Skip to content

Commit 2cdb42e

Browse files
dbrattliclaude
andauthored
feat(builtins): make TextIOWrapper enumerable and readline arg optional (#331)
Resolves #131. - Add `inherit IEnumerable<string>` to TextIOWrapper so file objects can be iterated line-by-line in a type-safe `for line in reader` loop without a cast. Maps to Python's iterator protocol; a file object is its own iterator. - Add zero-arg `readline` / `readlines` overloads on TextIOBase so the size argument is optional (Python's `readline(size=-1)`), matching the existing two-overload pattern used by `read`. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 896b760 commit 2cdb42e

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/stdlib/Builtins.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ type TextIOBase =
1212
abstract read: __size: int -> string
1313
abstract write: __s: string -> int
1414
abstract writelines: __lines: string seq -> unit
15+
abstract readline: unit -> string
1516
abstract readline: __size: int -> string
17+
abstract readlines: unit -> string list
1618
abstract readlines: __hint: int -> string list
1719
abstract tell: unit -> int
1820

1921
type TextIOWrapper =
2022
inherit IDisposable
2123
inherit TextIOBase
24+
inherit IEnumerable<string>
2225

2326
module OpenTextMode =
2427
[<Literal>]

test/TestBuiltins.fs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,38 @@ let ``test write works`` () =
2020
result.Dispose()
2121
os.remove tempFile
2222

23+
[<Fact>]
24+
let ``test TextIOWrapper can be enumerated`` () =
25+
let tempFile = os.path.join (os.path.expanduser "~", ".fable_test_iter.txt")
26+
let writer = builtins.``open`` (tempFile, OpenTextMode.Write)
27+
writer.write "a\nb\nc\n" |> ignore
28+
writer.Dispose()
29+
30+
let lines = ResizeArray<string>()
31+
let reader = builtins.``open`` (tempFile, OpenTextMode.Read)
32+
33+
for line in reader do
34+
lines.Add(line.Trim())
35+
36+
reader.Dispose()
37+
os.remove tempFile
38+
39+
lines |> List.ofSeq |> equal [ "a"; "b"; "c" ]
40+
41+
[<Fact>]
42+
let ``test readline without argument works`` () =
43+
let tempFile = os.path.join (os.path.expanduser "~", ".fable_test_readline.txt")
44+
let writer = builtins.``open`` (tempFile, OpenTextMode.Write)
45+
writer.write "first\nsecond\n" |> ignore
46+
writer.Dispose()
47+
48+
let reader = builtins.``open`` (tempFile, OpenTextMode.Read)
49+
let line = reader.readline ()
50+
reader.Dispose()
51+
os.remove tempFile
52+
53+
line.Trim() |> equal "first"
54+
2355
[<Fact>]
2456
let ``test max with two arguments works`` () =
2557
builtins.max (3, 5) |> equal 5

0 commit comments

Comments
 (0)