guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] branch main updated: New line or field iteration procedu


From: Mikael Djurfeldt
Subject: [Guile-commits] branch main updated: New line or field iteration procedures in (ice-9 rdelim)
Date: Thu, 19 Dec 2024 16:45:50 -0500

This is an automated email from the git hooks/post-receive script.

mdj pushed a commit to branch main
in repository guile.

The following commit(s) were added to refs/heads/main by this push:
     new c2829e4a8 New line or field iteration procedures in (ice-9 rdelim)
c2829e4a8 is described below

commit c2829e4a86d6fc72520930825bd44900d876db1d
Author: Adam Faiz <adam.faiz@disroot.org>
AuthorDate: Thu Dec 19 22:36:38 2024 +0100

    New line or field iteration procedures in (ice-9 rdelim)
    
    * NEWS: Update
    * module/ice-9/rdelim (for-rdelim-from-port, for-delimited-from-port,
      for-line-in-file): New procedures.
    * doc/ref/api-io.texi: Documentation of `for-rdelim-for-port`-related
      procedures.
    * test-suite/tests/rdelim.test: Tests for `for-rdelim-for-port`-related
      procedures.
    
    Signed-off-by: Mikael Djurfeldt <mikael@djurfeldt.com>
---
 NEWS                         |  7 +++++++
 doc/ref/api-io.texi          | 22 ++++++++++++++++++++++
 module/ice-9/rdelim.scm      | 35 ++++++++++++++++++++++++++++++++++-
 test-suite/tests/rdelim.test | 34 +++++++++++++++++++++++++++++++++-
 4 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index f14e6c93c..3328a03cf 100644
--- a/NEWS
+++ b/NEWS
@@ -38,6 +38,13 @@ advanced argument handling such as optional and keyword 
arguments. The
 implementation fully supports (next-method) calls, also for keyword
 arguments. The new syntax is documented in the Guile Reference manual.
 
+** New line or field iteration procedures in (ice-9 rdelim)
+
+(ice-9 rdelim) has three new procedures: for-rdelim-from-port,
+for-delimited-from-port and for-line-in-file. Of these, for-line-in-file
+is helpful in the common situation where you want a procedure applied to
+every line in a file.
+
 * Changes to the distribution
 
 * Bug fixes
diff --git a/doc/ref/api-io.texi b/doc/ref/api-io.texi
index 79bc9e9d6..0a9773f62 100644
--- a/doc/ref/api-io.texi
+++ b/doc/ref/api-io.texi
@@ -984,6 +984,28 @@ used.  This procedure is equivalent to:
 @end lisp
 @end deffn
 
+@deffn {Scheme Procedure} for-rdelim-from-port port proc rdelim-proc @
+        [#:stop-pred=eof-object?]
+For every unit provided by @code{(rdelim-proc port)}, provide
+this unit(rdelim) to @var{proc} to be processed. This will continue throughout
+@var{port} until @var{stop-pred} returns @code{#t}.
+@var{stop-pred} is @code{eof-object?} by default.
+@var{rdelim-proc} has to advance through @var{port} with every call made to it.
+@end deffn
+
+@deffn {Scheme Procedure} for-delimited-from-port port proc @
+        [#:delims=''\n''] [#:handle-delim='trim]
+Call @var{proc} for every line delimited by @var{delims} from @var{port}.
+@end deffn
+
+@deffn {Scheme Procedure} for-line-in-file file proc @
+        [#:encoding=#f] [#:guess-encoding=#f]
+Call @var{proc} for every line in @var{file}.
+@var{file} must be a filename string.
+
+The line provided to @var{proc} is guaranteed to be a string.
+@end deffn
+
 @node Default Ports
 @subsection Default Ports for Input, Output and Errors
 @cindex Default ports
diff --git a/module/ice-9/rdelim.scm b/module/ice-9/rdelim.scm
index d2cd081d7..65d1932fc 100644
--- a/module/ice-9/rdelim.scm
+++ b/module/ice-9/rdelim.scm
@@ -23,7 +23,10 @@
 ;;; similar to (scsh rdelim) but somewhat incompatible.
 
 (define-module (ice-9 rdelim)
-  #:export (read-line
+  #:export (for-delimited-from-port
+            for-line-in-file
+            for-rdelim-from-port
+            read-line
             read-line!
             read-delimited
             read-delimited!
@@ -206,3 +209,33 @@ characters to read.  By default, there is no limit."
              line)
       (else
        (error "unexpected handle-delim value: " handle-delim)))))
+
+(define* (for-rdelim-from-port port proc rdelim-proc
+                               #:key (stop-pred eof-object?))
+  "Call PROC for every (RDELIM-PROC PORT) from PORT until STOP-PRED returns #t.
+RDELIM-PROC has to advance through PORT with every call."
+  (let loop ((rdelim (rdelim-proc port)))
+    (cond ((stop-pred rdelim)
+           (close-port port))
+          (else
+           (proc rdelim)
+           (loop (rdelim-proc port))))))
+
+(define* (for-delimited-from-port port proc
+                                  #:key (delims "\n") (handle-delim 'trim))
+  "Call PROC for every delimited line from PORT until the eof-object is 
reached."
+  (for-rdelim-from-port port proc
+                        (lambda (port)
+                          (read-delimited delims port handle-delim))))
+
+(define* (for-line-in-file file proc
+                           #:key (encoding #f) (guess-encoding #f))
+  "Call PROC for every line in FILE until the eof-object is reached.
+FILE must be a filename string.
+
+The line provided to PROC is guaranteed to be a string."
+  (call-with-input-file
+      file
+    (lambda (port)
+      (for-delimited-from-port port proc))
+    #:encoding encoding #:guess-encoding guess-encoding))
diff --git a/test-suite/tests/rdelim.test b/test-suite/tests/rdelim.test
index 3aaa0b253..ad44278d2 100644
--- a/test-suite/tests/rdelim.test
+++ b/test-suite/tests/rdelim.test
@@ -20,7 +20,8 @@
 (define-module (test-suite test-rdelim)
   #:use-module (ice-9 rdelim)
   #:use-module ((rnrs io ports) #:select (open-bytevector-input-port get-u8))
-  #:use-module (test-suite lib))
+  #:use-module (test-suite lib)
+  #:use-module (test-suite guile-test))
 
 (with-test-prefix "read-line"
 
@@ -247,6 +248,37 @@
            (string=? (substring buf 0 len) s)
            (string=? (substring buf len) ".")))))
 
+
+(with-test-prefix "for-line-in-file"
+
+  (define (test-file)
+    (data-file-name "ports-test.tmp"))
+
+  (let ((lst '())
+        (lines '())
+        (string "line1\nline2\nline3")
+        (filename (test-file)))
+    (call-with-input-string
+        "A\0B\0C"
+      (lambda (port)
+        (pass-if "for-delimited-from-port parses stream correctly"
+          (for-delimited-from-port port
+                                   (lambda (entry)
+                                     (set! lst (cons entry lst)))
+                                   #:delims "\0")
+          (equal? lst '("C" "B" "A")))))
+    (let ((port (open-output-file filename)))
+      (display string port)
+      (close-port port))
+    (pass-if "for-line-in-file parses file correctly"
+      (for-line-in-file filename
+                        (lambda (line)
+                          (set! lines (cons line lines))))
+      (equal? lines '("line3" "line2" "line1"))))
+
+  (delete-file (test-file))
+  )
+
 ;;; Local Variables:
 ;;; eval: (put 'with-test-prefix 'scheme-indent-function 1)
 ;;; eval: (put 'pass-if 'scheme-indent-function 1)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]