realizing a lazy line-seq inside with-open

563 views
Skip to first unread message

Elango Cheran

unread,
May 27, 2013, 8:32:48 PM5/27/13
to clo...@googlegroups.com
Hi everyone,
I had a function that reads the contents of a file (in this case, it represents a license) and then verifies the contents.

As I started to expand the code for verifying, it made sense to break the function up into a function for file parsing and a function for verification.  The following is the function that I created to return the contents of the file parsing:

(defn- lic-file-msg-sigs
  "return a vector containing the original license string/message and a seq of each signature line generated. the input is the string of the entire license file"
  [lic-file-str]
  (let [result (promise)]
    (with-open [rdr (BufferedReader. (StringReader. lic-file-str))]
      (let [lines (line-seq rdr)
            line-sandwich-middle-fn (fn [lines line-before line-after]
                                         (->> lines
                                              (drop-while #(not (re-find (re-pattern line-before) %)))
                                              rest
                                              (take-while #(not (re-find (re-pattern line-after) %)))))
            msg-lines (line-sandwich-middle-fn lines LICENSE-BEGIN LICENSE-END)
            sig-strs (line-sandwich-middle-fn lines SIGNATURE-BEGIN SIGNATURE-END)
            msg (clojure.string/join \newline msg-lines)]
        (str msg sig-strs) ;; need to realize the values to force file
        ;; parsing before file is closed. couldn't figure out how to
        ;; force realization except for the str function
        (deliver result [msg sig-strs])))
    @result)) 


My question is related to the comments towards the end -- is there a better way to force the realization of the contents of the line-seq before I deliver it?

(If there is a better way to write this code, let me know....  In case you are wondering, I wanted to use line-seq for parsing the file so that I get the contents of the lines in between special sentinel lines.  line-seq requires a reader, and readers are best used with with-open.  But with-open closes the reader object at the end of its scope, so any code using the contents of the reader need to be realized before the reader is closed.  In order to return the contents outside of the with-open form, I used a promise & deliver.)

Thanks,
Elango

Sean Corfield

unread,
May 27, 2013, 8:44:53 PM5/27/13
to clo...@googlegroups.com
Just use doall:

(doall [msg sig-strs])

No need for the let / result / promise / deliver.
> --
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your
> first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

Elango Cheran

unread,
May 27, 2013, 9:10:43 PM5/27/13
to clo...@googlegroups.com
Much simpler, although I'm still seeing the following exception, unless I keep the form (str [msg sig-strs]):

IOException Stream closed  java.io.BufferedReader.ensureOpen (BufferedReader.java:115)

Any ideas why?

Kevin Downey

unread,
May 28, 2013, 12:50:37 AM5/28/13
to clo...@googlegroups.com
doall doesn't recurse, so you are not realizing the lazy-seq, you want something like [msg (doall sig-strs)]

if you are looking to play around with io stuff, I recommend looking in to using reducers for io, they allow you to sort of invert control, keeping the nice property of with-open always cleanly closing resources after use, but making it easier to break up io processing in functional steps with out needing to deal with the dynamic scoping issues of with-open and the lazy issues with line-seq
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Sean Corfield

unread,
May 28, 2013, 2:21:30 AM5/28/13
to clo...@googlegroups.com
On Mon, May 27, 2013 at 9:50 PM, Kevin Downey <red...@gmail.com> wrote:
> doall doesn't recurse, so you are not realizing the lazy-seq, you want
> something like [msg (doall sig-strs)]

Thank you Kevin! When Elango said my suggestion didn't work, I was
puzzled. Now it makes sense!

Elango Cheran

unread,
May 28, 2013, 2:32:49 AM5/28/13
to clo...@googlegroups.com
And yep, Kevin's change works.  Looking into reducers + I/O sounds interesting, I'll definitely check it out, thanks!


Reply all
Reply to author
Forward
0 new messages