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

@@ -423,6 +423,248 @@ PROCEDURE Main()
| Constants | No | Pi, E, Phi, Ln2, Sqrt2 |
| Special values | No | NaN, Inf, MaxFloat64 |
## Value Type Methods (Five Extension)
Five provides 52 built-in methods on basic types. All support chaining:
### String Methods (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 Methods (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 element
```
### Numeric Methods (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 Methods (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 Type Methods (5)
```prg
LOCAL xVal := "hello"
? xVal:Type() // "C"
? xVal:Clone() // deep copy
? xVal:IsNil() // .F.
? xVal:ToString() // "hello"
? xVal:ValType() // "C"
```
## MEMVAR — PUBLIC/PRIVATE Variables
Harbour-compatible memory variable system. PUBLIC is global, PRIVATE is function-scoped with shadowing:
```prg
// PUBLIC — accessible throughout the entire program
PUBLIC gAppName
gAppName := "Five Application"
PROCEDURE Main()
LOCAL cLocal := "local only"
// PRIVATE — accessible in current function + callees, restored on return
PRIVATE nTemp := 100
SubFunc()
? nTemp // 100 (SubFunc's PRIVATE restored)
? gAppName // "Five Application" (PUBLIC)
RETURN
PROCEDURE SubFunc()
PRIVATE nTemp := 999 // shadows caller's nTemp
? nTemp // 999
RETURN // nTemp restored to 100
```
### MEMVAR Scope Rules
| Type | Lifetime | Visibility | Shadowing |
|------|----------|------------|-----------|
| PUBLIC | Until program exit | Everywhere | Can be shadowed by PRIVATE |
| PRIVATE | Until declaring function returns | Declaring function + callees | Nested PRIVATE supported |
| LOCAL | Until declaring function returns | Declaring function only | Independent of MEMVAR |
| STATIC | Until program exit | Declaring function only | Independent of MEMVAR |
### MEMVAR Access via Macro
```prg
PUBLIC cName := "Charles"
LOCAL cVar := "cName"
? &cVar // "Charles" — macro searches MEMVAR
```
## SET Command System
Harbour-compatible SET settings. 47+ settings supported:
```prg
// Boolean toggles
SET EXACT ON // exact string comparison
SET DELETED ON // hide deleted records
SET SOFTSEEK ON // nearest record on failed SEEK
SET EXCLUSIVE OFF // shared mode
SET CONFIRM ON // require confirmation on GET
// Value settings
SET DATE FORMAT "yyyy-mm-dd" // date format
SET DECIMALS TO 4 // decimal places
SET EPOCH TO 2000 // 2-digit year interpretation base
// Programmatic access via SET() function
LOCAL lOld := SET(_SET_EXACT, .T.) // set and return previous value
? SET(_SET_EXACT) // .T.
```
### SET Constants
```prg
_SET_EXACT // 1 exact string comparison
_SET_FIXED // 2 fixed decimal point
_SET_DECIMALS // 3 decimal places
_SET_DATEFORMAT // 4 date format
_SET_EPOCH // 5 epoch year
_SET_DELETED // 8 deleted record filter
_SET_EXCLUSIVE // 11 exclusive mode
_SET_SOFTSEEK // 12 soft seek
```
## ErrorBlock / Break — Error Handling
Harbour-compatible structured error handling:
### BEGIN SEQUENCE / RECOVER
```prg
LOCAL bOldError
LOCAL oErr
// Set error handler
bOldError := ErrorBlock({|e| Break(e)})
BEGIN SEQUENCE
// Code that may generate an error
USE "nonexistent.dbf"
RECOVER USING oErr
// oErr is an error object (Hash)
? oErr["DESCRIPTION"] // error description
? oErr["OPERATION"] // failed operation
? oErr["SUBSYSTEM"] // subsystem name
? oErr["GENCODE"] // generic error code
END SEQUENCE
// Restore previous handler
ErrorBlock(bOldError)
```
### ErrorBlock
```prg
// Get current error handler
LOCAL bHandler := ErrorBlock()
// Set new handler (returns previous)
LOCAL bOld := ErrorBlock({|e| MyErrorHandler(e)})
FUNCTION MyErrorHandler(oErr)
? "Error:", oErr["DESCRIPTION"]
? "Operation:", oErr["OPERATION"]
BREAK oErr // pass to RECOVER in BEGIN SEQUENCE
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 Fields — Transparent Read/Write
Five handles DBF MEMO fields transparently.
FPT files are automatically created and opened:
```prg
// Create table with MEMO field — FPT auto-created
USE "notes" NEW
APPEND BLANK
REPLACE NAME WITH "Charles"
REPLACE NOTES WITH "This is a long memo text..." // auto-writes to FPT
? NOTES // "This is a long memo text..." — auto-reads from FPT
// Large memos work seamlessly
REPLACE NOTES WITH REPLICATE("Large data. ", 1000) // ~12KB
? LEN(NOTES) // 12000
```
### MEMO Internal Behavior
| Action | Automatic Handling |
|--------|-------------------|
| Create DBF (with M field) | FPT file auto-created |
| Open DBF (with M field) | FPT file auto-opened |
| REPLACE memo WITH text | Write to FPT, store block number in DBF |
| ? memo | Read FPT by block number, return string |
| Close DBF | FPT auto-closed |
## Example Files
| File | Description |