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:
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user