Lambda Smalltalk examples/ ディレクトリの実動サンプル。各ファイルはそのまま実行可能。

実行方法: lambda-st run examples/01_basics.st


01_basics.st

"
Lambda Smalltalk - Basics

Smalltalk is SVO: Subject Verb Object

  'hello' size
     S      V

  File read: 'config.txt'
   S    V        O

Just tell WHO to do WHAT.
"

"--- Print with newline ---"
'Hello, World!' printNl.

"--- Print without newline ---"
'No ' print.
'newline' print.
'' printNl.

"--- Variables ---"
| x y |
x := 10.
y := 20.
(x + y) printNl.

"--- String size ---"
'hello' size printNl.

"--- String uppercase ---"
'hello' asUppercase printNl.

"--- String lowercase ---"
'HELLO' asLowercase printNl.

"--- String trim ---"
'  hello  ' trim printNl.

"--- String concatenate ---"
('Hello' , ' ' , 'World') printNl.

"--- String repeat ---"
('-' * 10) printNl.

"--- String replace ---"
('hello' replaceAll: 'l' with: 'L') printNl.

"--- Number to string ---"
42 asString printNl.

"--- String to integer ---"
('123' asInteger + 10) printNl.

"--- String to number ---"
'3.14' asNumber printNl.

"--- Arithmetic ---"
(10 + 5) printNl.
(10 - 5) printNl.
(10 * 5) printNl.
(10 / 5) printNl.
(10 / 3) printNl.

"--- Exact Fraction ---"
((1 / 3) * 3) printNl.

"--- LargeInteger (overflow) ---"
(2147483647 + 1) printNl.
(1000000000 * 1000000000) printNl.

"--- Modulo ---"
(7 \\ 2) printNl.

"--- Floor division ---"
(-7 // 2) printNl.

"--- Power ---"
(2 raisedTo: 10) printNl.

"--- Absolute value ---"
(-5) abs printNl.

"--- Square root ---"
16 sqrt printNl.

"--- Min / Max ---"
(3 min: 7) printNl.
(3 max: 7) printNl.

'=== Done! ===' printNl.

02_collections.st

"
Lambda Smalltalk - Collections

Smalltalk is SVO: Subject Verb Object

  array size        - Array, tell me your size
  array first       - Array, give me your first element
  array select: []  - Array, select elements matching this

Just tell WHO to do WHAT.
"

"Load high-level collection methods"
FileStream fileIn: 'lib/Collections.st'.

"--- Array literal ---"
#(1 2 3) printNl.

"--- Array size ---"
#(10 20 30) size printNl.

"--- Array first ---"
#('a' 'b' 'c') first printNl.

"--- Array last ---"
#(1 2 3 4 5) last printNl.

"--- Array at index (1-based) ---"
| arr |
arr := #(10 20 30 40 50).
(arr at: 3) printNl.

"--- Create array of size N ---"
| a |
a := Array new: 3.
a at: 1 put: 'x'.
a at: 2 put: 'y'.
a at: 3 put: 'z'.
a printNl.

"--- Iterate: do ---"
| sum |
sum := 0.
#(1 2 3 4 5) do: [ :each | sum := sum + each ].
sum printNl.

"--- Transform: collect (map) ---"
(#(1 2 3) collect: [ :x | x * 2 ]) printNl.

"--- Filter: select ---"
(#(1 2 3 4 5 6) select: [ :x | x > 3 ]) printNl.

"--- Filter: reject ---"
(#(1 2 3 4 5 6) reject: [ :x | x > 3 ]) printNl.

"--- Find first match: detect ---"
(#(1 2 3 4 5) detect: [ :x | x > 3 ]) printNl.

"--- Find index: indexOf ---"
(#(1 2 3) indexOf: 2) printNl.

"--- Check contains: includes ---"
(#(1 2 3) includes: 2) printNl.

"--- Reduce: inject:into ---"
(#(1 2 3 4 5) inject: 0 into: [ :acc :x | acc + x ]) printNl.
(#(1 2 3 4 5) inject: 1 into: [ :acc :x | acc * x ]) printNl.

"--- Sum ---"
#(1 2 3 4 5) sum printNl.

"--- Sort ---"
#(3 1 4 1 5 9) sort printNl.

"--- Reverse ---"
#(1 2 3) reverse printNl.

"--- Sort by: sortBy ---"
(#(3 1 4 1 5) sortBy: [ :a :b | a < b ]) printNl.

"--- Unique ---"
#(1 2 2 3 3 3) unique printNl.

"--- Flatten ---"
#(#(1 2) #(3 4) #(5)) flatten printNl.

"--- Join ---"
(#('a' 'b' 'c') join: '-') printNl.

"--- Is empty ---"
#() isEmpty printNl.
#(1) isEmpty printNl.

"--- Max / Min ---"
#(3 1 4 1 5) max printNl.
#(3 1 4 1 5) min printNl.

"--- sumOf: / maxOf: / minOf: (block version) ---"
| people |
people := #(#('Alice' 30) #('Bob' 25) #('Carol' 35)).
(people sumOf: [:p | p at: 2]) printNl.  "=> 90"
(people maxOf: [:p | p at: 2]) printNl.  "=> 35"
(people minOf: [:p | p at: 2]) printNl.  "=> 25"

"--- Average ---"
#(10 20 30 40 50) average printNl.

"--- Iterate with index: doWithIndex ---"
#('a' 'b' 'c') doWithIndex: [ :elem :idx |
    (idx asString , ': ' , elem) printNl.
].

"--- Take first N: take ---"
(#(1 2 3 4 5) take: 3) printNl.

"--- Drop first N: drop ---"
(#(1 2 3 4 5) drop: 2) printNl.

"--- All but first: allButFirst ---"
#(1 2 3 4 5) allButFirst printNl.

"--- All but last: allButLast ---"
#(1 2 3 4 5) allButLast printNl.

"--- Copy with element: copyWith ---"
(#(1 2 3) copyWith: 4) printNl.

"--- Copy without element: copyWithout ---"
(#(1 2 3 2 4 2) copyWithout: 2) printNl.

"--- Partition by predicate: partition ---"
(#(1 2 3 4 5 6) partition: [ :x | x > 3 ]) printNl.

"--- Group by key: groupBy ---"
| grouped |
grouped := #(1 2 3 4 5 6) groupBy: [ :x | x \\ 2 ].
grouped keys printNl.
(grouped at: '0') printNl.
(grouped at: '1') printNl.

"--- Zip two arrays: zip ---"
(#(1 2 3) zip: #('a' 'b' 'c')) printNl.

"--- Split into chunks: chunks ---"
(#(1 2 3 4 5) chunks: 2) printNl.

"--- Iterate with separator: do:separatedBy ---"
#(1 2 3) do: [ :x | x print ] separatedBy: [ ', ' print ].
'' printNl.

"--- ifEmpty: / ifNotEmpty: ---"
#() ifEmpty: [ 'Empty array' printNl ].
#(1 2 3) ifNotEmpty: [ :arr | ('Size: ' , arr size asString) printNl ].

"Returns self if condition not met"
| result |
result := #(1 2 3) ifEmpty: [ 'was empty' ].
result printNl.  "=> #(1 2 3)"

"--- count: ---"
(#(1 2 3 4 5) count: [ :x | x > 2 ]) printNl.  "=> 3"

"--- String isBlank / ifBlank: / ifNotBlank: ---"
'' isBlank printNl.       "=> true"
'   ' isBlank printNl.    "=> true"
'hello' isBlank printNl.  "=> false"

| name |
name := ''.
name ifBlank: [ 'Using default name' printNl ].

name := 'Alice'.
name ifNotBlank: [ :n | ('Hello, ' , n) printNl ].

'=== Done! ===' printNl.

03_control_flow.st

"
Lambda Smalltalk - Control Flow

Smalltalk is SVO: Subject Verb Object

  (x > 0) ifTrue: [ ... ]
     S       V       O

  5 timesRepeat: [ ... ]
  S      V          O

Just tell WHO to do WHAT.
"

"--- If true ---"
(3 > 0) ifTrue: [ 'positive' printNl ].

"--- If false ---"
(3 < 0) ifFalse: [ 'not negative' printNl ].

"--- If-then-else ---"
| x |
x := 10.
(x > 5)
    ifTrue: [ 'big' printNl ]
    ifFalse: [ 'small' printNl ].

"--- Equality ---"
(5 = 5) printNl.
(5 ~= 3) printNl.

"--- Comparison ---"
(3 < 5) printNl.
(5 > 3) printNl.
(3 <= 3) printNl.
(5 >= 5) printNl.

"--- Logical AND / OR / NOT ---"
(true & true) printNl.
(true | false) printNl.
true not printNl.

"--- Repeat N times ---"
| count |
count := 0.
5 timesRepeat: [ count := count + 1 ].
count printNl.

"--- For loop: to:do ---"
| sum |
sum := 0.
1 to: 10 do: [ :i | sum := sum + i ].
sum printNl.

"--- For loop with step: to:by:do ---"
| evens |
evens := 0.
2 to: 10 by: 2 do: [ :i | evens := evens + i ].
evens printNl.

"--- While true ---"
| n |
n := 1.
[ n < 100 ] whileTrue: [ n := n * 2 ].
n printNl.

"--- While false ---"
| m |
m := 10.
[ m = 0 ] whileFalse: [ m := m - 1 ].
m printNl.

"--- If nil ---"
| val |
val := nil.
val ifNil: [ 'was nil' printNl ].

"--- If not nil ---"
val := 42.
val ifNotNil: [ 'not nil' printNl ].

"--- Nested if-else ---"
| score grade |
score := 85.
grade := (score >= 90)
    ifTrue: [ 'A' ]
    ifFalse: [
        (score >= 80)
            ifTrue: [ 'B' ]
            ifFalse: [ 'C' ]
    ].
grade printNl.

'=== Done! ===' printNl.

04_blocks.st

"
Lambda Smalltalk - Blocks and Closures

Blocks are Smalltalk's lambdas/closures.
They are first-class objects that hold code.

  block value           - Block, execute yourself
  block value: 5        - Block, execute with argument 5
  array collect: block  - Array, transform using this block

Just tell WHO to do WHAT.
"

"--- Create and execute a block ---"
| b |
b := [ 'Hello from block' printNl ].
b value.

"--- Block with one argument ---"
| add1 |
add1 := [ :x | x + 1 ].
(add1 value: 5) printNl.

"--- Block with two arguments ---"
| add |
add := [ :a :b | a + b ].
(add value: 3 value: 4) printNl.

"--- Closure: captures outer variable ---"
| counter block |
counter := 0.
block := [ counter := counter + 1. counter ].
(block value) printNl.
(block value) printNl.
(block value) printNl.

"--- Block as function ---"
| square |
square := [ :n | n * n ].
(square value: 7) printNl.

"--- Block as callback ---"
| nums doubled |
nums := #(1 2 3 4 5).
doubled := nums collect: [ :x | x * 2 ].
doubled printNl.

"--- Nested blocks ---"
| outer |
outer := [
    | inner |
    inner := [ 'inner' ].
    inner value
].
(outer value) printNl.

"--- Higher-order: block takes block ---"
| twice result |
twice := [ :f :x | f value: (f value: x) ].
result := twice value: [ :n | n + 1 ] value: 5.
result printNl.

'=== Done! ===' printNl.

05_classes.st

"
Lambda Smalltalk - Classes

Smalltalk is SVO: Subject Verb Object

  Object subclass: #Counter ...  - Object, create a subclass named Counter
  Counter new                    - Counter, create a new instance
  counter inc                    - Counter instance, increment yourself

Just tell WHO to do WHAT.
"

"--- Define a class ---"
Object subclass: #Counter instanceVariableNames: 'value'.

"--- Define methods ---"
Counter >> initialize
    value := 0.
!

Counter >> inc
    value := value + 1.
    ^ value
!

Counter >> value
    ^ value
!

"--- Create and use instance ---"
| c |
c := Counter new.
c inc printNl.
c inc printNl.
c inc printNl.
c value printNl.

"--- Built-in: Point ---"
| p |
p := 3 @ 4.
p x printNl.
p y printNl.
p printNl.

'=== Done! ===' printNl.

06_file_io.st

"
Lambda Smalltalk - File I/O

Smalltalk is SVO: Subject Verb Object

  File read: 'config.txt'                      - File, read this path (returns string)
  File write: 'out.txt' content: x             - File, write x to this path
  File exists: 'config.txt'                    - File, does this path exist?
  FileStream openRead: path do: [:stream|..]   - FileStream, open and auto-close (safe)

Just tell WHO to do WHAT.
"

"--- Read file ---"
| content |
content := File read: 'examples/06_file_io.st'.
(content size) printNl.

"--- Write file ---"
File write: 'examples/temp.txt' content: 'Hello, File!'.
(File read: 'examples/temp.txt') printNl.

"--- Check file exists ---"
(File exists: 'examples/temp.txt') printNl.
(File exists: 'examples/no_such_file.xyz') printNl.

"--- Glob pattern ---"
| files |
files := File glob: 'examples/*.st'.
files size printNl.

"--- Delete file ---"
(File delete: 'examples/temp.txt') printNl.
(File exists: 'examples/temp.txt') printNl.

"--- Safe file reading with openRead:do: ---"
"Auto-closes file even on error - no ensure: needed"
| lineCount |
lineCount := 0.
FileStream openRead: 'examples/06_file_io.st' do: [:stream |
    [stream atEnd] whileFalse: [
        stream nextLine.
        lineCount := lineCount + 1.
    ]
].
('Lines in this file: ' , lineCount asString) printNl.

'=== Done! ===' printNl.

07_file_in.st

"=== Lambda Smalltalk: FileStream fileIn: ==="

'=== Load library ===' printNl.

FileStream fileIn: 'examples/lib/math.st'.

'=== Use loaded class ===' printNl.

| calc |
calc := Calculator new.
calc setValue: 7.
calc square printNl.
calc value printNl.

'=== Done! ===' printNl.

08_plugins.st

"=== Lambda Smalltalk: Plugin System (FFI) ==="
"Load and call native plugins written in Rust/C (.dll/.so/.dylib)"

"=== Load plugin ==="
'Loading math plugin...' printNl.
| pluginName |
pluginName := Plugin load: 'examples/plugins/math_plugin/target/release/math_plugin.dll'.
'Loaded: ' print. pluginName printNl.

"=== List plugins and functions ==="
'Loaded plugins: ' print. (Plugin list) printNl.
'Available functions: ' print. (Plugin functions: 'math') printNl.

"=== Call plugin functions ==="
| r |

'factorial(5) = ' print.
r := Plugin call: 'math' function: 'factorial' args: #(5).
r printNl.

'factorial(10) = ' print.
r := Plugin call: 'math' function: 'factorial' args: #(10).
r printNl.

'fibonacci(10) = ' print.
r := Plugin call: 'math' function: 'fibonacci' args: #(10).
r printNl.

'gcd(48, 18) = ' print.
r := Plugin call: 'math' function: 'gcd' args: #(48 18).
r printNl.

'is_prime(17) = ' print.
r := Plugin call: 'math' function: 'is_prime' args: #(17).
r printNl.

'is_prime(15) = ' print.
r := Plugin call: 'math' function: 'is_prime' args: #(15).
r printNl.

'=== Done! ===' printNl.

09_modules.st

"=== Module System Example ==="
"Lambda Smalltalk supports a module system for namespace management."

"--- Basic Usage (without explicit modules) ---"
"When no module is declared, all classes are in the 'Core' module."
"This maintains backward compatibility with existing code."

Object subclass: #SimplePoint instanceVariableNames: 'x y'.

SimplePoint >> x
    ^x
!

SimplePoint >> y
    ^y
!

SimplePoint >> x: aValue
    x := aValue
!

SimplePoint >> y: aValue
    y := aValue
!

SimplePoint >> initialize
    x := 0. y := 0
!

|p|
p := SimplePoint new.
p x: 10.
p y: 20.
'SimplePoint x:' printNl.
p x printNl.
'SimplePoint y:' printNl.
p y printNl.

"--- Module Import ---"
"Import modules from lib/{ModuleName}/{ModuleName}.st"
"The module is auto-loaded on first import."

Module import: 'CodeGen'.

"Now we can use String extensions defined in CodeGen module"
'camelToSnake test:' printNl.
('myVariableName' camelToSnake) printNl.

'snakeToCamel test:' printNl.
('my_variable_name' snakeToCamel) printNl.

"--- Module Definition ---"
"In a module file (e.g., lib/MyLib/MyLib.st):"
"
Module name: 'MyLib'.
Module export: #(PublicClass1 PublicClass2).

Object subclass: #PublicClass1 instanceVariableNames: ''.
Object subclass: #PrivateHelper instanceVariableNames: ''.
"

'=== Module example done ===' printNl.

10_stream_fusion.st

"
Lambda Smalltalk - Streaming I/O Examples

Demonstrates efficient file processing using linesDo: with inline transformation.
This approach uses constant memory regardless of file size.
"

'=== Streaming I/O Examples ===' printNl.
'' printNl.

" ============================================ "
" Example 1: Basic linesDo: with transformation "
" ============================================ "

'--- Example 1: Filter and transform lines ---' printNl.

" Create test file "
File write: 'test_stream.txt' content: 'hello
world
lambda
smalltalk'.

" Process with inline transformation "
'Streaming (filter + uppercase):' printNl.
'test_stream.txt' linesDo: [:line |
    (line size > 4) ifTrue: [
        ('  ' , line asUppercase) printNl.
    ].
].
'' printNl.


" ============================================ "
" Example 2: Counting lines                   "
" ============================================ "

'--- Example 2: Count lines ---' printNl.

| count |
count := 0.
'test_stream.txt' linesDo: [:line |
    count := count + 1.
].
('Total lines: ' , count asString) printNl.
'' printNl.


" ============================================ "
" Example 3: Accumulating results             "
" ============================================ "

'--- Example 3: Sum line lengths ---' printNl.

| totalLength |
totalLength := 0.
'test_stream.txt' linesDo: [:line |
    totalLength := totalLength + line size.
].
('Total characters: ' , totalLength asString) printNl.
'' printNl.


" ============================================ "
" Example 4: Manual stream control            "
" ============================================ "

'--- Example 4: Manual iteration ---' printNl.

File write: 'mixed.txt' content: 'apple
banana
cherry
date
elderberry
fig
grape'.

| stream line |
stream := FileStream openRead: 'mixed.txt'.

'Lines longer than 4 characters (uppercase):' printNl.
[ stream atEnd ] whileFalse: [
    line := stream nextLine.
    (line size > 4) ifTrue: [
        ('  ' , line asUppercase) printNl.
    ].
].

stream close.
'' printNl.


" ============================================ "
" Example 5: Comparison with eager loading    "
" ============================================ "

'--- Example 5: Eager vs Streaming ---' printNl.

'Eager (loads entire file into memory):' printNl.
| lines |
lines := (File read: 'mixed.txt') lines.
lines := lines select: [:line | line size > 4].
lines := lines collect: [:line | line asUppercase].
lines do: [:line | ('  ' , line) printNl.].
'' printNl.

'Streaming (constant memory):' printNl.
'mixed.txt' linesDo: [:line |
    (line size > 4) ifTrue: [
        ('  ' , line asUppercase) printNl.
    ].
].
'' printNl.


'=== Streaming examples completed! ===' printNl.
'Use linesDo: with inline transformation for memory-efficient file processing.' printNl.

11_manual_gc.st

"======================================
 Manual Garbage Collection Examples
======================================"

'=== GC Basics ===' printNl.

"Test 1: Create objects without GC"
'Creating 1000 objects...' printNl.
1 to: 1000 do: [:i |
  arr := Array new: 10.
  arr at: 1 put: i.
].
'Done.' printNl.
'' printNl.

"Test 2: Check heap size"
'=== Heap Size ===' printNl.
'Current heap size: Still need System class methods' printNl.
'' printNl.

"Test 3: GC with live objects"
'=== GC Test ===' printNl.
'Creating some objects that stay alive...' printNl.
liveData := OrderedCollection new.
1 to: 100 do: [:i |
  liveData add: (Array new: 5).
].

'Creating temporary objects...' printNl.
1 to: 1000 do: [:i |
  temp := Array new: 10.
].

'Live objects: ' print. liveData size printNl.
'' printNl.

"Test 4: Memory usage pattern"
'=== Memory Pattern ===' printNl.
'This test creates and discards objects in a loop' printNl.
1 to: 10 do: [:round |
  ('Round ' , round asString) printNl.
  1 to: 100 do: [:i |
    temp := Array new: 20.
    temp at: 1 put: i.
  ].
].
'Done with 10 rounds (1000 temp objects created)' printNl.
'' printNl.

'=== All Tests Complete ===' printNl.

12_utilities.st

"============================================
 12_utilities.st - Utility Classes Demo
 ============================================
 Demonstrates: Json, Yaml, Toml, Csv, Env, Random, DateTime, Path, Sha2, Hmac, Base64,
               Directory, System, Http, Regex
"

'=== Json ===' printNl.

"Parse JSON string to Dictionary"
| json data |
json := '{"name": "Alice", "age": 30}'.
data := Json parse: json.
('Parsed: ' , (data at: 'name') , ', age=' , (data at: 'age') asString) printNl.

"Generate JSON from Dictionary"
| dict output |
dict := Dict new.
dict at: 'city' put: 'Tokyo'.
dict at: 'population' put: 14000000.
output := Json generate: dict.
('Generated: ' , output) printNl.


'=== Yaml ===' printNl.

"Parse YAML string to Dictionary"
| yaml yamlData |
yaml := 'name: Bob
age: 25
city: Osaka'.
yamlData := Yaml parse: yaml.
('Parsed YAML: name=' , (yamlData at: 'name') , ', age=' , (yamlData at: 'age') asString) printNl.


'=== Toml ===' printNl.

"Parse TOML string to Dictionary"
| toml tomlData |
toml := 'title = "Lambda Smalltalk"
version = "0.1.0"

[author]
name = "Developer"'.
tomlData := Toml parse: toml.
('Parsed TOML: title=' , (tomlData at: 'title')) printNl.


'=== Csv ===' printNl.

"Parse CSV string - returns array of dictionaries (header row becomes keys)"
| csv rows row |
csv := 'name,age,city
Alice,30,Tokyo
Bob,25,Osaka
Charlie,35,Kyoto'.
rows := Csv parse: csv.
('CSV data rows: ' , rows size asString) printNl.
"Each row is a Dictionary with header keys"
row := rows at: 1.
('Row 1: name=' , (row at: 'name') , ', age=' , (row at: 'age') asString , ', city=' , (row at: 'city')) printNl.
row := rows at: 2.
('Row 2: name=' , (row at: 'name') , ', age=' , (row at: 'age') asString , ', city=' , (row at: 'city')) printNl.

"Streaming CSV - memory efficient for large files"
| reader names |
reader := Csv reader: 'product,price
Apple,100
Banana,80
Orange,120'.
names := OrderedCollection new.
[reader atEnd] whileFalse: [
    | r |
    r := reader next.
    r ifNotNil: [names add: (r at: 'product')]
].
('Streamed products: ' , (names join: ', ')) printNl.


'=== Env (Environment Variables) ===' printNl.

"Get environment variable"
| path |
path := Env at: 'PATH'.
(path isNil)
    ifTrue: [ 'PATH not set' printNl ]
    ifFalse: [ ('PATH length: ' , path size asString) printNl ].

"Set and get environment variable"
Env at: 'LAMBDA_ST_TEST' put: 'hello'.
('LAMBDA_ST_TEST = ' , (Env at: 'LAMBDA_ST_TEST')) printNl.

"List all environment variable names"
| keys |
keys := Env keys.
('Total env vars: ' , keys size asString) printNl.


'=== Random ===' printNl.

"Generate random float [0.0, 1.0)"
| r |
r := Random next.
('Random float: ' , r asString) printNl.

"Generate random integer [0, max)"
| n |
n := Random nextInt: 100.
('Random int (0-99): ' , n asString) printNl.

"Generate 5 random numbers"
5 timesRepeat: [
    (Random nextInt: 10) print. ' ' print.
].
'' printNl.


'=== DateTime ===' printNl.

"Get current timestamp"
| now |
now := DateTime now.
('Now (epoch): ' , now asString) printNl.

"Format timestamp"
| formatted |
formatted := now format: '%Y-%m-%d %H:%M:%S'.
('Formatted: ' , formatted) printNl.

"Parse date string (RFC3339 format)"
| parsed |
parsed := DateTime parse: '2025-12-25T10:30:00+00:00'.
(parsed isNil)
    ifTrue: [ 'Failed to parse' printNl ]
    ifFalse: [ ('Parsed timestamp: ' , parsed asString) printNl ].


'=== Path ===' printNl.

"Extract basename"
| basename |
basename := Path basename: '/home/user/documents/report.pdf'.
('Basename: ' , basename) printNl.

"Extract dirname"
| dirname |
dirname := Path dirname: '/home/user/documents/report.pdf'.
('Dirname: ' , dirname) printNl.

"Extract extension"
| ext |
ext := Path extension: '/home/user/documents/report.pdf'.
('Extension: ' , ext) printNl.

"Join paths"
| joined |
joined := Path join: '/home/user' with: 'documents'.
('Joined: ' , joined) printNl.

"Get absolute path"
| abs |
abs := Path absolute: 'examples'.
('Absolute: ' , abs) printNl.

"Check if path exists"
| exists |
exists := Path exists: '.'.
('Current dir exists: ' , exists asString) printNl.

exists := Path exists: '/nonexistent/path/that/does/not/exist'.
('Nonexistent path exists: ' , exists asString) printNl.

"Check if path is directory"
| isDir |
isDir := Path isDirectory: '.'.
('Current dir is directory: ' , isDir asString) printNl.

isDir := Path isDirectory: 'examples/11_utilities.st'.
('This file is directory: ' , isDir asString) printNl.


'=== Sha2 (Hashing) ===' printNl.

"SHA256 hash"
| hash |
hash := Sha2 sha256: 'hello world'.
('SHA256: ' , hash) printNl.


'=== Hmac (Message Authentication) ===' printNl.

"HMAC-SHA256 for API signatures and webhook verification"
| signature |
signature := Hmac sha256: 'message to sign' key: 'secret-key'.
('HMAC-SHA256: ' , signature) printNl.

"AWS-style signature (simplified example)"
| awsSecret kDate |
awsSecret := 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'.
kDate := Hmac sha256: '20260110' key: ('AWS4' , awsSecret).
('AWS kDate: ' , kDate) printNl.


'=== Base64 ===' printNl.

"Encode to Base64"
| encoded decoded |
encoded := Base64 encode: 'Hello, Lambda Smalltalk!'.
('Encoded: ' , encoded) printNl.

"Decode from Base64"
decoded := Base64 decode: encoded.
('Decoded: ' , decoded) printNl.


'=== Directory ===' printNl.

"List directory entries"
| entries |
entries := Directory entries: 'examples'.
('Entries in examples/: ' , entries size asString , ' files') printNl.
entries do: [:entry | ('  - ' , entry) printNl ].


'=== System ===' printNl.

"Dynamic class lookup (DI pattern)"
| cls obj |
cls := System classNamed: 'OrderedCollection'.
cls printNl.  "=> OrderedCollection class"
obj := cls new.
obj add: 'dynamic'.
obj add: 'instantiation'.
('Created via classNamed: ' , obj asArray asString) printNl.

"Non-existent class returns nil"
(System classNamed: 'NonExistent') isNil ifTrue: [
    'NonExistent class not found (as expected)' printNl
].

"Platform detection"
('Platform: ' , System platform) printNl.


'=== Regex (String match:) ===' printNl.

"String match: uses regex patterns"
('abc123' match: '\d+') printNl.  "=> true (contains digits)"
('abc' match: '\d+') printNl.     "=> false (no digits)"

"Email validation"
| email |
email := 'test@example.com'.
(email match: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
    ifTrue: [ (email , ' is valid email') printNl ]
    ifFalse: [ (email , ' is invalid email') printNl ].

"Pattern matching examples"
('hello123world' match: '[0-9]+') printNl.  "=> true"
('no-numbers' match: '[0-9]+') printNl.     "=> false"


'=== Http (commented - requires network) ===' printNl.

"HTTP examples are commented out since they require network access.
Uncomment to test with actual endpoints.

--- Basic GET ---
| response |
response := Http get: 'https://httpbin.org/get'.
response printNl.

--- POST with body ---
| postResponse |
postResponse := Http post: 'https://httpbin.org/post' body: jsonBody.
postResponse printNl.

--- GET with custom headers ---
| headers authResponse |
headers := Dict new.
headers at: 'Authorization' put: 'Bearer your-token-here'.
headers at: 'User-Agent' put: 'Lambda-Smalltalk/1.0'.
authResponse := Http get: 'https://api.example.com/data' headers: headers.
authResponse printNl.

--- PUT and DELETE ---
Http put: url body: data headers: headers.
Http delete: url headers: headers.
"

'(Http examples are commented - uncomment to test with network)' printNl.


'=== Done! ===' printNl.

13_transformer.st

"
Transformer Example - Lark-style Source Code Surgery

This example demonstrates how to use the Transformer class for
source code manipulation with automatic gap preservation.
"

"Load the Transformer library"
Module import: 'Transform'.

'=== Transformer Example ===' printNl.
'' printNl.


"--- Example 1: Simple function renaming with Transformer ---"
'Example 1: Rename print() to console_log()' printNl.

| g t source result |

g := Grammar from: '
    call: FUNC "(" ARGS ")"
    FUNC: /[a-zA-Z_][a-zA-Z0-9_]*/
    ARGS: /[^)]*/
    %ignore /\s+/
'.

t := Transformer new grammar: g.

"Rule for call: items = [FUNC, '(', ARGS, ')']"
t rule: 'call' do: [:items |
    | func args |
    func := items at: 1.   "FUNC text"
    args := items at: 3.   "ARGS text (index 2 is '(')"
    (func = 'print')
        ifTrue: [ 'console_log(' , args , ')' ]
        ifFalse: [ func , '(' , args , ')' ]
].

source := 'x = print(hello); y = other(world); z = print(foo)'.
result := t transform: source.

('  Input:  ' , source) printNl.
('  Output: ' , result) printNl.
'' printNl.


"--- Example 2: Using Grammar replace:in:with: ---"
'Example 2: Using Grammar replace:in:with:' printNl.

| g2 source2 result2 |

g2 := Grammar from: '
    dotcall: RECV "." METHOD "()"
    RECV: /[a-z]+/
    METHOD: /[a-z]+/
    %ignore /./
'.

source2 := '/* comment */ obj.fetch() and client.send() /* end */'.
result2 := Grammar replace: g2 in: source2 with: [:m |
    | text |
    text := m at: 'text'.
    'await ' , text
].

('  Input:  ' , source2) printNl.
('  Output: ' , result2) printNl.
'' printNl.


"--- Example 3: Nested transformation ---"
'Example 3: Inspect tree structure' printNl.

| g3 matches |

g3 := Grammar from: '
    expr: IDENT "(" IDENT ")"
    IDENT: /[a-z]+/
    %ignore /\s+/
'.

matches := Grammar findAll: g3 in: 'foo(bar)'.
matches do: [:m |
    | tree |
    ('  text: ' , (m at: 'text')) printNl.
    tree := m at: 'tree'.
    tree isNil ifFalse: [
        ('  tree.name: ' , (tree at: 'name')) printNl.
        ('  tree.children count: ' , (tree at: 'children') size asString) printNl.
    ].
].
'' printNl.


'=== Done ===' printNl.

14_streaming_io.st

"
Lambda Smalltalk - Streaming I/O Examples

This file demonstrates memory-efficient file processing using FileStream.
Unlike File read: which loads entire files into memory, streaming APIs
process files line-by-line for better performance with large files.
"

'=== Streaming File I/O Examples ===' printNl.
'' printNl.

" ============================================ "
" Example 1: linesDo: - Simple line iteration "
" ============================================ "

'--- Example 1: linesDo: basic usage ---' printNl.

" Create a sample file "
File write: 'sample.txt' content: 'Apple
Banana
Cherry
Date
Elderberry'.

" Process each line without loading entire file "
'sample.txt' linesDo: [:line |
    ('  * ' , line) printNl.
].
'' printNl.


" ==================================================== "
" Example 2: Manual stream control for complex logic  "
" ==================================================== "

'--- Example 2: Manual stream control ---' printNl.

| stream line count |
stream := FileStream openRead: 'sample.txt'.
count := 0.

" Read lines manually with custom logic "
[ stream atEnd ] whileFalse: [
    line := stream nextLine.
    line ifNotNil: [
        count := count + 1.
        ('Line ' , count asString , ': ' , line) printNl.
    ].
].

stream close.
('Total lines: ' , count asString) printNl.
'' printNl.


" ============================================== "
" Example 3: Filter lines while streaming        "
" ============================================== "

'--- Example 3: Filter long lines ---' printNl.

" Create file with mixed line lengths "
File write: 'mixed.txt' content: 'Short
This is a longer line
Tiny
Another very long line here
OK'.

" Process only lines longer than 10 characters "
'mixed.txt' linesDo: [:line |
    (line size > 10) ifTrue: [
        ('  Long: ' , line) printNl.
    ].
].
'' printNl.


" ============================================== "
" Example 4: Count matching lines efficiently   "
" ============================================== "

'--- Example 4: Count lines containing letter ---' printNl.

| matchCount |
matchCount := 0.

'sample.txt' linesDo: [:line |
    " Count lines containing 'e' "
    (line includes: 'e') ifTrue: [
        matchCount := matchCount + 1.
    ].
].

('Lines containing "e": ' , matchCount asString) printNl.
'' printNl.


" ============================================== "
" Example 5: Early exit with manual stream      "
" ============================================== "

'--- Example 5: Find first match and stop ---' printNl.

stream := FileStream openRead: 'sample.txt'.
| found |
found := false.

[ stream atEnd not and: [ found not ] ] whileTrue: [
    line := stream nextLine.
    line ifNotNil: [
        (line startsWith: 'C') ifTrue: [
            ('Found line starting with C: ' , line) printNl.
            found := true.
        ].
    ].
].

stream close.
'' printNl.


" ============================================== "
" Example 6: Compare memory efficiency          "
" ============================================== "

'--- Example 6: Memory efficiency comparison ---' printNl.

" Create a larger file "
| content i |
content := ''.
i := 1.
[ i <= 100 ] whileTrue: [
    content := content , 'Line ' , i asString , '
'.
    i := i + 1.
].
File write: 'large.txt' content: content.

'Rich-man programming (loads entire file):' printNl.
| lines |
lines := (File read: 'large.txt') lines.
('  Loaded ' , lines size asString , ' lines into memory') printNl.

'Streaming approach (processes line-by-line):' printNl.
count := 0.
'large.txt' linesDo: [:ln | count := count + 1. ].
('  Processed ' , count asString , ' lines without loading all') printNl.
'' printNl.


" ============================================== "
" Example 7: Stream with error handling         "
" ============================================== "

'--- Example 7: Safe stream usage ---' printNl.

| safeStream |
safeStream := nil.
[
    safeStream := FileStream openRead: 'sample.txt'.

    " Process file "
    safeStream nextLine printNl.
    safeStream nextLine printNl.

] ensure: [
    " Always close stream even if error occurs "
    safeStream ifNotNil: [ safeStream close. ].
    'Stream closed safely' printNl.
].
'' printNl.


" ============================================== "
" Cleanup: Remove temporary files               "
" ============================================== "

File delete: 'sample.txt'.
File delete: 'mixed.txt'.
File delete: 'large.txt'.

'=== All streaming examples completed! ===' printNl.

15_argparser.st

"
ArgParser - command-line argument parsing

Build CLI tools with flags, options, and positional arguments.
"

Module import: 'CLI'.

| parser result |

"--- Create parser ---"
parser := ArgParser new.

"--- Set program name ---"
parser name: 'demo-tool'.

"--- Set description ---"
parser description: 'A demonstration CLI tool'.

"--- Add boolean flag (--verbose or -v) ---"
parser flag: 'verbose' short: 'v' description: 'Enable verbose output'.

"--- Add option with value (--output FILE or -o FILE) ---"
parser option: 'output' short: 'o' description: 'Output file path'.

"--- Add another option ---"
parser option: 'count' short: 'n' description: 'Number of iterations'.

"--- Add positional argument ---"
parser positional: 'input' description: 'Input file to process'.

"--- Parse command line args ---"
result := parser parse: System args.

"--- Check parse success ---"
result isSuccess ifTrue: [
    '=== Parsed Arguments ===' printNl.

    "--- Get positional value ---"
    'Input: ' print.
    ((result positional: 'input') ifNil: ['(not set)']) printNl.

    "--- Get option value ---"
    'Output: ' print.
    ((result option: 'output') ifNil: ['(not set)']) printNl.

    "--- Get flag value (boolean) ---"
    'Verbose: ' print.
    (result flag: 'verbose') printNl.

    'Count: ' print.
    ((result option: 'count') ifNil: ['(not set)']) printNl.

    "--- Get extra arguments ---"
    (result extras size > 0) ifTrue: [
        'Extra args: ' print.
        result extras printNl.
    ].
] ifFalse: [
    "--- Handle parse error ---"
    'Error: ' print.
    result errorMessage printNl.

    "--- Print help ---"
    parser printHelp.
].

'=== Done! ===' printNl.

16_parallel_process.st

"========================================
 Parallel Process Execution
 DevOps-style parallel command execution
========================================"

"Helper to get shell command based on OS"
| shell shellArg isWindows child exitCode pingCmd pollCount processes codes running maxConcurrency items results echoCmd exitCmd args |

isWindows := System platform = 'windows'.
shell := isWindows ifTrue: ['cmd'] ifFalse: ['sh'].
shellArg := isWindows ifTrue: ['/c'] ifFalse: ['-c'].

'=== 1. Basic ChildProcess ===' printNl.

"Spawn a process and wait for it"
args := Array new: 2.
args at: 1 put: shellArg.
args at: 2 put: 'echo Hello from child process'.
child := ChildProcess spawn: shell args: args.
'Spawned process: ' print. child printNl.

"Wait for completion (blocking)"
exitCode := child exitCode.
'Exit code: ' print. exitCode printNl.
'' printNl.


'=== 2. Non-blocking check ===' printNl.

"Spawn a longer-running process"
pingCmd := isWindows
    ifTrue: ['ping -n 1 127.0.0.1']
    ifFalse: ['ping -c 1 127.0.0.1'].
args := Array new: 2.
args at: 1 put: shellArg.
args at: 2 put: pingCmd.
child := ChildProcess spawn: shell args: args.
'Process spawned, polling...' printNl.

"Poll until finished"
pollCount := 0.
[child isFinished] whileFalse: [
    pollCount := pollCount + 1.
    (pollCount \\ 50000) = 0 ifTrue: ['..' print].
].
'' printNl.
'Finished after polling ' print. pollCount printNl.
'Exit code: ' print. child exitCode printNl.
'' printNl.


'=== 3. Multiple processes in sequence ===' printNl.

"Run multiple processes and collect results"
processes := OrderedCollection new.
args := Array new: 2. args at: 1 put: shellArg. args at: 2 put: 'echo Job 1'.
processes add: (ChildProcess spawn: shell args: args).
args := Array new: 2. args at: 1 put: shellArg. args at: 2 put: 'echo Job 2'.
processes add: (ChildProcess spawn: shell args: args).
args := Array new: 2. args at: 1 put: shellArg. args at: 2 put: 'echo Job 3'.
processes add: (ChildProcess spawn: shell args: args).

"Wait for all to complete"
codes := processes collect: [:p | p exitCode].
'All jobs completed. Exit codes: ' print. codes printNl.
'' printNl.


'=== 4. Parallel execution with manual pool ===' printNl.

"Run 4 jobs with max 2 concurrent"
maxConcurrency := 2.
running := OrderedCollection new.
results := OrderedCollection new.
items := #('A' 'B' 'C' 'D').

items do: [:item |
    "Wait if at max"
    [running size >= maxConcurrency] whileTrue: [
        running do: [:p |
            p isFinished ifTrue: [
                results add: p exitCode.
            ].
        ].
        running := running select: [:p | p isFinished not].
        1 to: 5000 do: [:i | ].  "brief busy wait"
    ].

    "Spawn new"
    echoCmd := 'echo ', item.
    args := Array new: 2. args at: 1 put: shellArg. args at: 2 put: echoCmd.
    running add: (ChildProcess spawn: shell args: args).
].

"Wait for remaining"
[running isEmpty not] whileTrue: [
    running do: [:p |
        p isFinished ifTrue: [results add: p exitCode].
    ].
    running := running select: [:p | p isFinished not].
    1 to: 5000 do: [:i | ].
].

'Parallel jobs (max 2 concurrent) completed. Exit codes: ' print. results asArray printNl.
'' printNl.


'=== 5. Error handling ===' printNl.

"Process that fails"
exitCmd := isWindows ifTrue: ['exit 42'] ifFalse: ['exit 42'].
args := Array new: 2. args at: 1 put: shellArg. args at: 2 put: exitCmd.
child := ChildProcess spawn: shell args: args.
exitCode := child exitCode.
'Process with exit 42, got: ' print. exitCode printNl.
'' printNl.


'=== All parallel process tests complete! ===' printNl.

16_tableprinter.st

"
TablePrinter Example - East Asian Width Support

Demonstrates TablePrinter with Japanese text.
Full-width characters (Japanese) are properly aligned.
"

'=== TablePrinter Example ===' printNl.
'' printNl.

"Import the Text module"
Module import: 'Text'.

"--- Example 1: Basic displayWidth test ---"
'Example 1: displayWidth test' printNl.
('  ''hello'' displayWidth = ', 'hello' displayWidth asString) printNl.
('  ''world'' displayWidth = ', 'world' displayWidth asString) printNl.
('  ''Running'' displayWidth = ', 'Running' displayWidth asString) printNl.
'' printNl.

"--- Example 2: Server status table (English only) ---"
'Example 2: English table' printNl.
| table |
table := TablePrinter new.
table headers: #('ID' 'Server Name' 'Status').
table addRow: #(1 'web-01' 'Running').
table addRow: #(2 'db-primary' 'Maintenance').
table addRow: #(105 'api-gateway' 'Error').
table printTable.
'' printNl.

"--- Example 3: Mixed table with Japanese ---"
'Example 3: Japanese table' printNl.
| table2 |
table2 := TablePrinter new.
table2 headers: #('ID' 'Server Name' 'Status' 'Memo').
table2 addRow: #(1 'web-01' 'Running' 'OK').
table2 addRow: #(2 'db-primary' 'Maintenance' 'Backup').
table2 addRow: #(105 'api-gateway' 'Error' 'Check').
table2 printTable.
'' printNl.

"--- Example 4: padRightDisplay test ---"
'Example 4: padRightDisplay test' printNl.
| s1 s2 s3 |
s1 := 'ABC'.
s2 := 'XYZ'.
s3 := 'Hello'.
('[', (s1 padRightDisplay: 10), ']') printNl.
('[', (s2 padRightDisplay: 10), ']') printNl.
('[', (s3 padRightDisplay: 10), ']') printNl.
'' printNl.

'=== Done ===' printNl.

16_mysql.st

"=== Lambda Smalltalk: MySQL Plugin Example ==="
"Demonstrates MySQL database connection and queries"

"NOTE: This example requires a running MySQL server."
"Adjust the connection string as needed."

"=== Load the MySQL plugin ==="
'Loading MySQL plugin...' printNl.
| pluginName |
pluginName := Plugin load: 'examples/plugins/mysql_plugin/target/release/mysql_plugin.dll'.
'Loaded: ' print. pluginName printNl.

'Available functions: ' print. (Plugin functions: 'mysql') printNl.

"=== Connect to database ==="
"Connection string format: mysql://user:password@host:port/database"
| db |
db := Plugin call: 'mysql' function: 'connect' args: #('mysql://root:password@localhost:3306/testdb').

db ifNil: [
    'Failed to connect to MySQL. Make sure the server is running.' printNl.
] ifNotNil: [
    'Connected! Handle: ' print. db printNl.

    "=== Create a test table ==="
    | result |
    result := Plugin call: 'mysql' function: 'execute' args: { db.
        'CREATE TABLE IF NOT EXISTS users (
            id INT AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(100) NOT NULL,
            age INT,
            email VARCHAR(100)
        )' }.
    'Create table: ' print. result printNl.

    "=== Insert data with parameters ==="
    result := Plugin call: 'mysql' function: 'execute_params'
        args: { db. 'INSERT INTO users (name, age, email) VALUES (?, ?, ?)'. #('Alice' 30 'alice@example.com') }.
    'Insert Alice: ' print. result printNl.

    result := Plugin call: 'mysql' function: 'execute_params'
        args: { db. 'INSERT INTO users (name, age, email) VALUES (?, ?, ?)'. #('Bob' 25 'bob@example.com') }.
    'Insert Bob: ' print. result printNl.

    result := Plugin call: 'mysql' function: 'execute_params'
        args: { db. 'INSERT INTO users (name, age, email) VALUES (?, ?, ?)'. #('Charlie' 35 'charlie@example.com') }.
    'Insert Charlie: ' print. result printNl.

    "=== Query all users ==="
    'All users:' printNl.
    | rows |
    rows := Plugin call: 'mysql' function: 'query' args: { db. 'SELECT * FROM users' }.
    rows do: [:row |
        '  ' print. row printNl.
    ].

    "=== Query with parameters ==="
    'Users older than 28:' printNl.
    rows := Plugin call: 'mysql' function: 'query_params'
        args: { db. 'SELECT name, age FROM users WHERE age > ?'. #(28) }.
    rows do: [:row |
        '  ' print. (row at: 'name') print. ' is ' print. (row at: 'age') print. ' years old' printNl.
    ].

    "=== Update data ==="
    result := Plugin call: 'mysql' function: 'execute_params'
        args: { db. 'UPDATE users SET age = ? WHERE name = ?'. #(31 'Alice') }.
    'Update Alice age: ' print. result printNl.

    "=== Delete data ==="
    result := Plugin call: 'mysql' function: 'execute_params'
        args: { db. 'DELETE FROM users WHERE name = ?'. #('Charlie') }.
    'Delete Charlie: ' print. result printNl.

    "=== Final state ==="
    'Final users:' printNl.
    rows := Plugin call: 'mysql' function: 'query' args: { db. 'SELECT * FROM users' }.
    rows do: [:row |
        '  ' print. row printNl.
    ].

    "=== Cleanup ==="
    result := Plugin call: 'mysql' function: 'execute' args: { db. 'DROP TABLE users' }.
    'Drop table: ' print. result printNl.

    "=== Close connection ==="
    result := Plugin call: 'mysql' function: 'close' args: { db }.
    'Connection closed: ' print. result printNl.
].

'=== Done! ===' printNl.

16_tcp.st

"
Lambda Smalltalk - TCP Networking Example
Demonstrates TCP client and server operations.
"

'=== TCP Client Example ===' printNl.

"Note: This example requires an actual server to connect to.
 For testing, you can use: nc -l 12345 (netcat) or similar.

 Basic usage:
   sock := Tcp connect: 'localhost' port: 12345.
   sock send: 'Hello, server!'.
   response := sock recvLine.
   response printNl.
   sock close.
"

'--- TCP API Overview ---' printNl.
'  Tcp connect: host port: port         - Connect to server' printNl.
'  Tcp connect: host port: port timeout: ms  - Connect with timeout' printNl.
'  stream send: data                    - Send string or ByteArray' printNl.
'  stream recv: maxBytes                - Receive up to maxBytes' printNl.
'  stream recv                          - Receive with default buffer' printNl.
'  stream recvLine                      - Receive a line (up to \n)' printNl.
'  stream close                         - Close the connection' printNl.
'' printNl.
'  TcpListener listen: port             - Start listening on port' printNl.
'  listener accept                      - Accept incoming connection' printNl.
'  listener close                       - Stop listening' printNl.
'' printNl.

"
=== Simple HTTP Client Example ===
This demonstrates making a raw HTTP request over TCP.
"

'--- Minimal HTTP Client ---' printNl.
"
sock := Tcp connect: 'httpbin.org' port: 80.
sock ifNotNil: [
    sock send: 'GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\n\r\n'.

    response := sock recv: 4096.
    response ifNotNil: [
        (response asString) printNl.
    ].
    sock close.
    'HTTP request complete.' printNl.
] ifNil: [
    'Connection failed.' printNl.
].
"

'--- TCP Server Example (pseudocode) ---' printNl.
"
server := TcpListener listen: 8080.
server ifNotNil: [
    'Listening on port 8080...' printNl.

    client := server accept.
    client ifNotNil: [
        request := client recvLine.
        'Received: ' print. request printNl.

        client send: 'Hello from Lambda Smalltalk!'.
        client close.
    ].

    server close.
].
"

'=== Redis Client Example (pseudocode) ===' printNl.
"
Redis uses a simple text protocol (RESP).
With TCP support, you can build a Redis client in pure Smalltalk.
"

"
Object subclass: #Redis instanceVariableNames: 'sock'.

Redis class >> connect: host port: port
    | r |
    r := self new.
    r sock: (Tcp connect: host port: port).
    ^ r
!

Redis >> ping
    sock send: '*1\r\n$4\r\nPING\r\n'.
    ^ sock recvLine  ''Should return +PONG''
!

Redis >> set: key value: value
    | keyLen valLen |
    keyLen := key size.
    valLen := value size.
    sock send: '*3\r\n$3\r\nSET\r\n$', keyLen asString, '\r\n', key, '\r\n$', valLen asString, '\r\n', value, '\r\n'.
    ^ sock recvLine
!

Redis >> get: key
    | keyLen |
    keyLen := key size.
    sock send: '*2\r\n$3\r\nGET\r\n$', keyLen asString, '\r\n', key, '\r\n'.
    ^ sock recvLine
!

''Usage:''
redis := Redis connect: 'localhost' port: 6379.
redis ping printNl.                    ''-> +PONG''
redis set: 'mykey' value: 'myvalue'.
redis get: 'mykey' printNl.            ''-> myvalue''
"

'TCP examples loaded.' printNl.

17_excel.st

"
Lambda Smalltalk - Excel Plugin Example
Demonstrates: Plugin loading, Excel read/write, multi-sheet support

Requires: excel_plugin (built automatically)
"

FileStream fileIn: 'examples/lib/excel.st'.

| excel rows sheets testFile |
testFile := '_test_excel_example.xlsx'.

"Build plugin if needed"
'--- Building Excel Plugin ---' printNl.
(Process run: 'cargo' args: #('build' '--release' '--manifest-path' 'examples/plugins/excel_plugin/Cargo.toml')) = 0
    ifFalse: [ self error: 'Build failed' ].

"Create Excel file with multiple sheets"
'--- Creating Excel File ---' printNl.
excel := Excel load.
excel newWorkbook.

"Sheet 1: Report"
excel addWorksheet: 'Report'.
excel writeString: 'Date' row: 0 col: 0 sheet: 'Report'.
excel writeString: 'Value' row: 0 col: 1 sheet: 'Report'.
excel writeString: '2026-01-10' row: 1 col: 0 sheet: 'Report'.
excel writeNumber: 123.45 row: 1 col: 1 sheet: 'Report'.
excel writeString: '2026-01-11' row: 2 col: 0 sheet: 'Report'.
excel writeNumber: 678.90 row: 2 col: 1 sheet: 'Report'.

"Sheet 2: Summary"
excel addWorksheet: 'Summary'.
excel writeString: 'Total' row: 0 col: 0 sheet: 'Summary'.
excel writeNumber: 802.35 row: 0 col: 1 sheet: 'Summary'.

('Saving to ' , testFile , '...') printNl.
excel save: testFile.

"Read back: sheet names"
'--- Reading Sheet Names ---' printNl.
excel := Excel load.
sheets := excel sheetNames: testFile.
'Sheets: ' print. sheets printNl.

"Read back: specific sheet"
'--- Reading Report Sheet ---' printNl.
rows := excel readSheet: 'Report' from: testFile.
rows do: [:row |
    row do: [:cell | cell print. '	' print].
    '' printNl.
].

"Read back: using read: (first sheet as dicts)"
'--- Reading as Dicts ---' printNl.
rows := excel read: testFile.
rows do: [:row |
    'Date: ' print. (row at: 'Date') print.
    ', Value: ' print. (row at: 'Value') printNl.
].

"Cleanup"
File delete: testFile.
('Cleaned up: ' , testFile) printNl.

'Done.' printNl.

18_postgres.st

"
Lambda Smalltalk - PostgreSQL Plugin Example
Requires: postgres_plugin.dll and a running PostgreSQL server

NOTE: This example requires a PostgreSQL server.
If you don't have one, install PostgreSQL or skip this example.

Connection string format:
  'host=localhost user=postgres password=yourpass dbname=testdb'
"

| db rows |

'--- Building PostgreSQL Plugin ---' printNl.
(Process run: 'cargo' args: #('build' '--release' '--manifest-path' 'examples/plugins/postgres_plugin/Cargo.toml')) = 0
    ifFalse: [ 'Build failed' printNl. ^ self ].

'--- Loading PostgreSQL Library ---' printNl.
FileStream fileIn: 'examples/lib/postgres.st'.

'--- Connecting to PostgreSQL ---' printNl.
"Change this connection string to match your PostgreSQL setup"
db := Postgres connect: 'host=localhost user=postgres password=postgres dbname=postgres'.
db = nil ifTrue: [
    'ERROR: Could not connect to PostgreSQL' printNl.
    'Make sure PostgreSQL is running and connection string is correct' printNl.
    ^ self
].
'Connected successfully' printNl.

'--- Creating Test Table ---' printNl.
(db execute: 'DROP TABLE IF EXISTS test_users') ifFalse: [
    'Failed to drop table' printNl. ^ self
].
(db execute: 'CREATE TABLE test_users (id SERIAL PRIMARY KEY, name VARCHAR(100), age INTEGER)') ifFalse: [
    'Failed to create table' printNl. ^ self
].
'Table created' printNl.

'--- Inserting Data ---' printNl.
(db execute: 'INSERT INTO test_users (name, age) VALUES (''Alice'', 30)') ifFalse: [
    'Failed to insert Alice' printNl. ^ self
].
(db execute: 'INSERT INTO test_users (name, age) VALUES (''Bob'', 25)') ifFalse: [
    'Failed to insert Bob' printNl. ^ self
].
'Data inserted' printNl.

'--- Inserting with Parameters ---' printNl.
(db execute: 'INSERT INTO test_users (name, age) VALUES ($1, $2)' params: #('Charlie' 35)) ifFalse: [
    'Failed to insert Charlie' printNl. ^ self
].
'Parameterized insert successful' printNl.

'--- Querying All Rows ---' printNl.
rows := db query: 'SELECT id, name, age FROM test_users ORDER BY id'.
rows = nil ifTrue: [
    'Query failed' printNl. ^ self
].

'Query results:' printNl.
rows do: [:row |
    "PostgreSQL plugin now returns proper Dicts!"
    'ID: ' print. (row at: 'id') print.
    ', Name: ' print. (row at: 'name') print.
    ', Age: ' print. (row at: 'age') printNl.
].

'--- Querying with Parameters ---' printNl.
rows := db queryWith: 'SELECT name, age FROM test_users WHERE age > $1' params: #(28).
rows = nil ifTrue: [
    'Parameterized query failed' printNl. ^ self
].

'Users older than 28:' printNl.
rows do: [:row |
    (row at: 'name') print. ' (age: ' print. (row at: 'age') print. ')' printNl.
].

'--- Cleanup ---' printNl.
(db execute: 'DROP TABLE test_users') ifFalse: [
    'Failed to drop table' printNl. ^ self
].
'Table dropped' printNl.

'--- PostgreSQL Plugin Test Complete ---' printNl.

19_template.st

"============================================
 19_template.st - Mustache Template Demo
 ============================================
 Demonstrates: Template rendering with data substitution
"

'=== Basic Template ===' printNl.

"Simple variable substitution"
| tmpl data result |
tmpl := 'Hello, {{name}}!'.
data := Dict new.
data at: 'name' put: 'Alice'.
result := Template render: tmpl with: data.
result printNl.


'=== Template with Multiple Variables ===' printNl.

"Multiple variables"
tmpl := 'Name: {{name}}, Age: {{age}}, City: {{city}}'.
data := Dict new.
data at: 'name' put: 'Bob'.
data at: 'age' put: 30.
data at: 'city' put: 'Tokyo'.
result := Template render: tmpl with: data.
result printNl.


'=== Template with Lists ===' printNl.

"Iterate over array items"
tmpl := 'Items:
{{#items}}
  - {{name}}: ${{price}}
{{/items}}'.
data := Dict new.
| items |
items := Array new: 3.
| item1 item2 item3 |
item1 := Dict new.
item1 at: 'name' put: 'Apple'.
item1 at: 'price' put: 100.
item2 := Dict new.
item2 at: 'name' put: 'Banana'.
item2 at: 'price' put: 80.
item3 := Dict new.
item3 at: 'name' put: 'Orange'.
item3 at: 'price' put: 120.
items at: 1 put: item1.
items at: 2 put: item2.
items at: 3 put: item3.
data at: 'items' put: items.
result := Template render: tmpl with: data.
result printNl.


'=== Template with Conditionals ===' printNl.

"Show/hide sections based on data"
tmpl := 'Hello{{#premium}}, Premium User{{/premium}}{{^premium}}, Guest{{/premium}}!'.
| data1 data2 |
data1 := Dict new.
data1 at: 'premium' put: true.
('Premium user: ' , (Template render: tmpl with: data1)) printNl.

data2 := Dict new.
data2 at: 'premium' put: false.
('Regular user: ' , (Template render: tmpl with: data2)) printNl.


'=== HTML Template ===' printNl.

"Generate HTML report"
tmpl := '<html>
<head><title>{{title}}</title></head>
<body>
  <h1>{{title}}</h1>
  <ul>
  {{#users}}
    <li>{{name}} - {{email}}</li>
  {{/users}}
  </ul>
</body>
</html>'.
data := Dict new.
data at: 'title' put: 'User List'.
| users |
users := Array new: 2.
| user1 user2 |
user1 := Dict new.
user1 at: 'name' put: 'Alice'.
user1 at: 'email' put: 'alice@example.com'.
user2 := Dict new.
user2 at: 'name' put: 'Bob'.
user2 at: 'email' put: 'bob@example.com'.
users at: 1 put: user1.
users at: 2 put: user2.
data at: 'users' put: users.
result := Template render: tmpl with: data.
result printNl.


'=== Done! ===' printNl.