feat: transparent MEMO read/write + documentation update

DBFArea auto-manages FPT memo files:
- Create/Open: auto-creates/opens FPT when memo fields exist
- PutValue: string on MEMO field auto-writes to FPT
- GetValue: MEMO field auto-reads from FPT, returns string
- Close: auto-closes FPT

Documentation: Value methods, MEMVAR, SET, ErrorBlock, MEMO
added to five-syntax-ko.md and five-syntax-en.md (+480 lines)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 17:32:07 +09:00
parent 827adeeb99
commit 08c0ef13d4
4 changed files with 681 additions and 74 deletions

View File

@@ -394,6 +394,248 @@ PROCEDURE Main()
| 삼각함수 | 없음 | Sin, Cos, Tan, ... |
| 상수 | 없음 | Pi, E, Phi, ... |
## Value 타입 메서드 (Five 확장)
Five는 기본 타입에 52개의 내장 메서드를 지원합니다. 체이닝 가능:
### String 메서드 (20개)
```prg
LOCAL cStr := " Hello World "
? cStr:Trim() // "Hello World"
? cStr:Upper() // " HELLO WORLD "
? cStr:Lower() // " hello world "
? cStr:Left(7) // " Hello"
? cStr:Right(7) // "orld "
? cStr:SubStr(3, 5) // "Hello"
? cStr:At("World") // 9
? cStr:Len() // 15
? cStr:Replicate(2) // " Hello World Hello World "
? cStr:Reverse() // " dlroW olleH "
? cStr:IsAlpha() // .F. (starts with space)
? cStr:IsDigit() // .F.
? cStr:IsEmpty() // .F.
? cStr:Trim():Upper():Left(5) // "HELLO" — chaining
```
### Array 메서드 (14개)
```prg
LOCAL aList := {3, 1, 4, 1, 5}
? aList:Len() // 5
? aList:Sort() // {1, 1, 3, 4, 5}
? aList:Find(4) // 3 (1-based)
? aList:Push(9) // {1,1,3,4,5,9}
? aList:Pop() // 9
? aList:First() // 1
? aList:Last() // 5
? aList:Join(",") // "1,1,3,4,5"
? aList:Reverse() // {5,4,3,1,1}
? aList:Unique() // {5,4,3,1}
? aList:Slice(2, 4) // {4,3}
// Map/Filter/Each with code blocks
LOCAL aDoubled := {1,2,3}:Map({|x| x * 2}) // {2,4,6}
LOCAL aEven := {1,2,3,4}:Filter({|x| x % 2 == 0}) // {2,4}
{1,2,3}:Each({|x| QOut(x)}) // prints each
```
### Numeric 메서드 (6개)
```prg
LOCAL nVal := 3.14159
? nVal:Round(2) // 3.14
? nVal:Abs() // 3.14159
? nVal:Int() // 3
? nVal:Str(10, 4) // " 3.1416"
? nVal:IsZero() // .F.
? (-5):Abs() // 5
```
### Hash 메서드 (7개)
```prg
LOCAL hData := {"name" => "Charles", "age" => 30}
? hData:Keys() // {"name","age"}
? hData:Values() // {"Charles",30}
? hData:Len() // 2
? hData:HasKey("name") // .T.
? hData:Remove("age") // {"name" => "Charles"}
? hData:Merge({"city" => "Seoul"})
```
### Any 타입 메서드 (5개)
```prg
LOCAL xVal := "hello"
? xVal:Type() // "C"
? xVal:Clone() // deep copy
? xVal:IsNil() // .F.
? xVal:ToString() // "hello"
? xVal:ValType() // "C"
```
## MEMVAR — PUBLIC/PRIVATE 변수
Harbour 호환 메모리 변수 시스템. PUBLIC은 전역, PRIVATE은 함수 스코프.
```prg
// PUBLIC — 프로그램 전체에서 접근
PUBLIC gAppName
gAppName := "Five Application"
PROCEDURE Main()
LOCAL cLocal := "local only"
// PRIVATE — 현재 함수 + 하위 함수에서 접근, 리턴 시 복원
PRIVATE nTemp := 100
SubFunc()
? nTemp // 100 (SubFunc의 PRIVATE이 복원됨)
? gAppName // "Five Application" (PUBLIC)
RETURN
PROCEDURE SubFunc()
PRIVATE nTemp := 999 // shadows caller's nTemp
? nTemp // 999
RETURN // nTemp restored to 100
```
### MEMVAR 스코프 규칙
| 종류 | 수명 | 가시성 | 섀도잉 |
|------|------|--------|--------|
| PUBLIC | 프로그램 종료까지 | 전체 | PRIVATE이 숨길 수 있음 |
| PRIVATE | 선언 함수 리턴까지 | 선언 함수 + 하위 | 중첩 PRIVATE 가능 |
| LOCAL | 선언 함수 리턴까지 | 선언 함수만 | MEMVAR와 독립 |
| STATIC | 프로그램 종료까지 | 선언 함수만 | MEMVAR와 독립 |
### 매크로에서 MEMVAR 접근
```prg
PUBLIC cName := "Charles"
LOCAL cVar := "cName"
? &cVar // "Charles" — 매크로가 MEMVAR 검색
```
## SET 명령어 시스템
Harbour 호환 SET 설정. 47+ 설정 지원:
```prg
// Boolean 토글
SET EXACT ON // 문자열 완전 일치 비교
SET DELETED ON // 삭제 레코드 숨김
SET SOFTSEEK ON // SEEK 실패 시 가장 가까운 레코드
SET EXCLUSIVE OFF // 공유 모드
SET CONFIRM ON // GET 입력 시 확인 필요
// 값 설정
SET DATE FORMAT "yyyy-mm-dd" // 날짜 형식
SET DECIMALS TO 4 // 소수점 자릿수
SET EPOCH TO 2000 // 2자리 년도 해석 기준
// SET() 함수로 프로그래밍 방식 접근
LOCAL lOld := SET(_SET_EXACT, .T.) // 설정하고 이전 값 반환
? SET(_SET_EXACT) // .T.
```
### SET 상수
```prg
_SET_EXACT // 1 문자열 정확 비교
_SET_FIXED // 2 고정 소수점
_SET_DECIMALS // 3 소수점 자릿수
_SET_DATEFORMAT // 4 날짜 형식
_SET_EPOCH // 5 년도 기준
_SET_DELETED // 8 삭제 레코드 필터
_SET_EXCLUSIVE // 11 독점 모드
_SET_SOFTSEEK // 12 소프트 검색
```
## ErrorBlock / Break — 에러 처리
Harbour 호환 구조적 에러 처리:
### BEGIN SEQUENCE / RECOVER
```prg
LOCAL bOldError
LOCAL oErr
// 에러 핸들러 설정
bOldError := ErrorBlock({|e| Break(e)})
BEGIN SEQUENCE
// 에러가 발생할 수 있는 코드
USE "nonexistent.dbf"
RECOVER USING oErr
// oErr는 에러 객체 (Hash)
? oErr["DESCRIPTION"] // 에러 설명
? oErr["OPERATION"] // 실패한 연산
? oErr["SUBSYSTEM"] // 서브시스템 이름
? oErr["GENCODE"] // 일반 에러 코드
END SEQUENCE
// 이전 핸들러 복원
ErrorBlock(bOldError)
```
### ErrorBlock
```prg
// 현재 에러 핸들러 가져오기
LOCAL bHandler := ErrorBlock()
// 새 핸들러 설정 (이전 핸들러 반환)
LOCAL bOld := ErrorBlock({|e| MyErrorHandler(e)})
FUNCTION MyErrorHandler(oErr)
? "Error:", oErr["DESCRIPTION"]
? "Operation:", oErr["OPERATION"]
BREAK oErr // BEGIN SEQUENCE의 RECOVER로 전달
RETURN NIL
```
### ErrorNew
```prg
LOCAL oErr := ErrorNew()
oErr["SUBSYSTEM"] := "MYAPP"
oErr["DESCRIPTION"] := "Custom error"
oErr["OPERATION"] := "MyFunc"
oErr["GENCODE"] := 1001
oErr["SEVERITY"] := 2 // ES_ERROR
```
## MEMO 필드 — 투명한 읽기/쓰기
Five는 DBF의 MEMO 필드를 투명하게 처리합니다.
FPT 파일이 자동으로 생성/열림:
```prg
// MEMO 필드가 있는 테이블 생성 — FPT 자동 생성
USE "notes" NEW
APPEND BLANK
REPLACE NAME WITH "Charles"
REPLACE NOTES WITH "This is a long memo text..." // FPT에 자동 저장
? NOTES // "This is a long memo text..." — FPT에서 자동 읽기
// 큰 메모도 문제없음
REPLACE NOTES WITH REPLICATE("Large data. ", 1000) // ~12KB
? LEN(NOTES) // 12000
```
### MEMO 내부 동작
| 동작 | 자동 처리 |
|------|-----------|
| DBF 생성 (M 필드 포함) | FPT 파일 자동 생성 |
| DBF 열기 (M 필드 포함) | FPT 파일 자동 열기 |
| REPLACE memo WITH text | FPT에 쓰기 → 블록 번호 DBF에 저장 |
| ? memo | 블록 번호로 FPT 읽기 → 문자열 반환 |
| DBF 닫기 | FPT 자동 닫기 |
## 예제 파일
| 파일 | 설명 |