Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Stuart Halloway
 On Thu, Mar 3, 2011 at 9:15 PM, Stefan Rohlfing
 stefan.rohlf...@gmail.com wrote:
 I personally find Stuart's suggestion to be the most readable. The use of
 the - macro makes the workflow quite easy to follow.
 
 Yes, both the - and - macros are useful.  Unfortunately, about half
 of Clojure's functions put the object you're operating on first, and
 the other half put it last.  - works best with the former, and -
 with the latter.

This is hardly unfortunate! The API is carefully designed: object args come 
first, seq args come last.

 Stuart's code is readable because he found a way to structure it all
 in terms of functions that put the main object last.  I find that in
 most code, you end up with a mixture of the two types of functions,
 and then those macros aren't quite so useful.

I didn't have to find a way to structure the code. Knowing I was working with 
seqs, the use of - was automatic. The mixing happens when you are doing mixed 
things.

Stuart Halloway
Clojure/core
http://clojure.com

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Mark Engelberg
On Fri, Mar 4, 2011 at 4:50 AM, Stuart Halloway
stuart.hallo...@gmail.com wrote:
 This is hardly unfortunate! The API is carefully designed: object args come
 first, seq args come last.

I didn't mean to imply that the first/last choice is random or
arbitrary.  I understand that the seq functions trace their history to
languages in which order was chosen to ease currying, and the object
functions are derived more from the OO part of the programming world.
There's certainly a logic to it.

I still find it unfortunate in terms of being able to leverage - -
macros to maximize readability.  Perhaps I mix the styles more than
you.  Also, let's be honest -- it's not always clear whether something
is considered a seq or an object.  As a case in point, consider
strings.  There has been endless argument over what order the various
string library functions should be, precisely because there's a
tension between wanting the functions to mirror their seq
counterparts, and wanting them to mirror their Java OO counterparts.
Strings, in some sense, are both.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Ken Wesson
On Fri, Mar 4, 2011 at 7:50 AM, Stuart Halloway
stuart.hallo...@gmail.com wrote:
 This is hardly unfortunate! The API is carefully designed: object args come
 first, seq args come last.

Eh, not always: conj, nth, and several others put seq args first,
though cons can be used on seqs in place of conj and has the seq arg
last.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Ken Wesson
On Fri, Mar 4, 2011 at 12:34 PM, Stuart Halloway
stuart.hallo...@gmail.com wrote:
 This is hardly unfortunate! The API is carefully designed: object args come

 first, seq args come last.

 Eh, not always: conj, nth, and several others put seq args first,
 though cons can be used on seqs in place of conj and has the seq arg
 last.

 You may be right, but so far your chosen examples support my point:
 * conj is *not* a sequence fn -- it builds the type of thing passed in, not
 a seq
 * nth is *not* a sequence fn -- it knows about random access collections and
 navigates them appropriately

Oh, I'm sorry, I naturally interpreted sequence fn to mean fn that
can perform a sequence operation on a sequence arg rather than fn
that is *exclusive* to sequences and won't work on anything else.
Apparently you meant the latter? Which still doesn't matter since
someone operating on sequences might very well want to call nth or
similar at some point.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Stuart Halloway
 This is hardly unfortunate! The API is carefully designed: object args come
 
 first, seq args come last.
 
 Eh, not always: conj, nth, and several others put seq args first,
 though cons can be used on seqs in place of conj and has the seq arg
 last.
 
 You may be right, but so far your chosen examples support my point:
 * conj is *not* a sequence fn -- it builds the type of thing passed in, not
 a seq
 * nth is *not* a sequence fn -- it knows about random access collections and
 navigates them appropriately
 
 Oh, I'm sorry, I naturally interpreted sequence fn to mean fn that
 can perform a sequence operation on a sequence arg rather than fn
 that is *exclusive* to sequences and won't work on anything else.
 Apparently you meant the latter? Which still doesn't matter since
 someone operating on sequences might very well want to call nth or
 similar at some point.

In the context of chaining operators such as -, it is logical to consider 
both the input and output of the function. The functions listed under the Seq 
In, Seq Out section at http://clojure.org/sequences should all take their seq 
arg last.

There is a ticket in JIRA for making - and - more flexible, but I couldn't 
trivially find it because you can't search for punctuation. Feel free to 
respond with a link...

Stuart Halloway
Clojure/core
http://clojure.com

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-04 Thread Ken Wesson
On Fri, Mar 4, 2011 at 12:53 PM, Stuart Halloway
stuart.hallo...@gmail.com wrote:
 In the context of chaining operators such as -, it is logical to consider
 both the input and output of the function. The functions listed under the
 Seq In, Seq Out section at http://clojure.org/sequences should all take
 their seq arg last.

The conj function is listed in the seq in, seq out section of the
cheat-sheet and doesn't. ;)

But it seems to be the only one there, and cons can be used with - instead.

 There is a ticket in JIRA for making - and - more flexible, but I
 couldn't trivially find it because you can't search for punctuation. Feel
 free to respond with a link...

I hate broken search tools that made unwarranted assumptions about
what people would put in, or would search for.

Some code was posted here recently for more flexible - like macros. I
posted one such. Most of them would thread through a placeholder, e.g.
(-% 3 (- 1 %) (/ % 2)) threading through %s or (-- [x 3] (- 1 x) (/
x 2)) actually specifying a symbol to thread through and the initial
value in a binding-like syntax. (Both of those examples have -1 as the
desired output.)

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stefan Rohlfing
Dear Clojure Group,

I am currently reading the online book Pro 
Githttps://docs.google.com/document/d/1pms_fnr0m2xlYH_4CB3pMeWBdIBlly4CQGMWuogOntg/edit?hl=en.
 
In chapter 7.4 http://progit.org/book/ch7-4.html (section “Enforcing a 
User-Based ACL System”) there is a task of reading in an access control list 
(ACL) file, such as the following

# avail/unavail | users | path
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests

and printing out a map of the form { user1 [path 1, path 2], user2 
[path2, path3] ...}.

The author of the book provides a solution in Ruby, which I find relatively 
easy to follow, despite not having written any Ruby code before:

def get_acl_access_data(acl_file)
 # read in ACL data
 acl_file = File.read(acl_file).split(\n).reject { |line| line == '' }
 access = {}
 acl_file.each do |line|
   avail, users, path = line.split('|')
   next unless avail == 'avail'
   users.split(',').each do |user|
 access[user] ||= []
 access[user]  path
   end
 end
 access
end

I then tried the same in Clojure, but found my solution to be much less 
readable compared to the Ruby code:

(use '[clojure.string :only (split)])

(defn get-acl-access-data [file]
 (let [acl (split (slurp file) #\n)]
   (apply merge-with #(into %1 %2)
 (map (fn [[avail users path]]
 (let [users (split users #,)]
(reduce (fn [acc user]
(when (= avail avail)
  (assoc acc user [path])))
   {} users)))
   (map #(split % #\|) acl)

;; Output:
;; {schacon [lib tests], 
;;  usinclair [doc], 
;;  cdickens [doc], 
;;  ebronte [doc], 
;;  tpw [nil], 
;;  defunkt [nil], 
;;  pjhyett [nil], 
;; nickh [nil]}

Maybe it is just because I am still a beginner, but I am afraid I won’t be 
able to figure out immediately what this code is doing a few weeks from now.

However, I am sure there must be a better way of translating the Ruby 
version into Clojure. My main goal is on clarity, as I often struggle 
organizing my code in a way I would consider readable.

I therefore would be glad for any ideas of improvement. Any suggestions are 
highly welcome!

Best regards,

Stefan

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stefan Rohlfing
Dear Clojure Group,

I am currently reading the online book Pro Git http://progit.org/book/. In 
chapter 7.4 http://progit.org/book/ch7-4.html (section “Enforcing a 
User-Based ACL System”) there is a task of reading in an access control list 
(ACL) file, such as the following

# avail/unavail | users | path
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests

and printing out a map of the form { user1 [path 1, path 2], user2 
[path2, path3] ...}.

The author of the book provides a solution in Ruby, which I find relatively 
easy to follow, despite not having written any Ruby code before:

def get_acl_access_data(acl_file)
 # read in ACL data
 acl_file = File.read(acl_file).split(\n).reject { |line| line == '' }
 access = {}
 acl_file.each do |line|
   avail, users, path = line.split('|')
   next unless avail == 'avail'
   users.split(',').each do |user|
 access[user] ||= []
 access[user]  path
   end
 end
 access
end

I then tried the same in Clojure, but found my solution to be much less 
readable compared to the Ruby code:

(use '[clojure.string :only (split)])

(defn get-acl-access-data [file]
 (let [acl (split (slurp file) #\n)]
   (apply merge-with #(into %1 %2)
 (map (fn [[avail users path]]
 (let [users (split users #,)]
(reduce (fn [acc user]
(when (= avail avail)
  (assoc acc user [path])))
   {} users)))
   (map #(split % #\|) acl)

;; Output:
;; {schacon [lib tests], 
;;  usinclair [doc], 
;;  cdickens [doc], 
;;  ebronte [doc], 
;;  tpw [nil], 
;;  defunkt [nil], 
;;  pjhyett [nil], 
;; nickh [nil]}

Maybe it is just because I am an ambitious beginner at best, but I am afraid 
I won’t be able to figure out immediately what this code is doing in a few 
weeks.

However, there probably is a better way of translating the Ruby version into 
Clojure. With better I mean easier to follow. My main goal is on clarity, 
as I often struggle organizing my code in a way I would consider readable.

I therefore would be glad for any ideas of improvement. Any suggestions are 
highly welcome!

Best regards,

Stefan

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stuart Halloway
 Dear Clojure Group,
 
 I am currently reading the online book Pro Git. In chapter 7.4 (section 
 “Enforcing a User-Based ACL System”) there is a task of reading in an access 
 control list (ACL) file, such as the following
 
 # avail/unavail | users | path
 avail|nickh,pjhyett,defunkt,tpw
 avail|usinclair,cdickens,ebronte|doc
 avail|schacon|lib
 avail|schacon|tests
 
 and printing out a map of the form { user1 [path 1, path 2], user2 
 [path2, path3] ...}.
 
 The author of the book provides a solution in Ruby, which I find relatively 
 easy to follow, despite not having written any Ruby code before:
 
 def get_acl_access_data(acl_file)
   # read in ACL data
   acl_file = File.read(acl_file).split(\n).reject { |line| line == '' }
   access = {}
   acl_file.each do |line|
 avail, users, path = line.split('|')
 next unless avail == 'avail'
 users.split(',').each do |user|
   access[user] ||= []
   access[user]  path
 end
   end
   access
 end
 
 I then tried the same in Clojure, but found my solution to be much less 
 readable compared to the Ruby code:
 
 (use '[clojure.string :only (split)])
 
 (defn get-acl-access-data [file]
   (let [acl (split (slurp file) #\n)]
 (apply merge-with #(into %1 %2)
   (map (fn [[avail users path]]
   (let [users (split users #,)]
  (reduce (fn [acc user]
  (when (= avail avail)
(assoc acc user [path])))
 {} users)))
 (map #(split % #\|) acl)
 
 ;; Output:
 ;; {schacon [lib tests], 
 ;;  usinclair [doc], 
 ;;  cdickens [doc], 
 ;;  ebronte [doc], 
 ;;  tpw [nil], 
 ;;  defunkt [nil], 
 ;;  pjhyett [nil], 
 ;; nickh [nil]}
 
 Maybe it is just because I am still a beginner, but I am afraid I won’t be 
 able to figure out immediately what this code is doing a few weeks from now.
 
 However, I am sure there must be a better way of translating the Ruby version 
 into Clojure. My main goal is on clarity, as I often struggle organizing my 
 code in a way I would consider readable.
 
 I therefore would be glad for any ideas of improvement. Any suggestions are 
 highly welcome!
 
 Best regards,
 
 Stefan

Both the approaches above have the weakness that the steps are commingled, 
making it difficult to test (or reuse) part of the work done by the fn. Here is 
a Clojure version that makes the steps more distinct:

(require '[clojure.string :as str])
(require '[clojure.java.io :as io])

(with-open [r (io/reader somefile)]
  (- (line-seq r)
   (map #(str/split % #\|))
   (filter #(= avail (first %)))
   (mapcat (fn [[_ users path]] (map hash-map (str/split users #,) 
(repeat [path]
   (apply merge-with into)))

From this it is easy to see that the fn:

1. splits the lines on |
2. filters on avail
3. builds a list of user|path pairs
4. merges the user|path pairs into a map


Stuart Halloway
Clojure/core
http://clojure.com

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread gaz jones
i was gonna suggest this:

(let [users (- (split (slurp acl) #\n)
 (map #(split % #\|))
 (map (fn [[a u p]] [a (split u #,) p]))
 (filter (fn [[a _ _]] (= avail a)))
 (mapcat (fn [[_ users path]]
   (map #(hash-map % [path]) users)))
 (apply merge-with into))]
  users)

then i read the bit about readable... :P

On Thu, Mar 3, 2011 at 8:51 PM, Stuart Halloway
stuart.hallo...@gmail.com wrote:
 Dear Clojure Group,

 I am currently reading the online book Pro Git. In chapter 7.4 (section
 “Enforcing a User-Based ACL System”) there is a task of reading in an access
 control list (ACL) file, such as the following

 # avail/unavail | users | path
 avail|nickh,pjhyett,defunkt,tpw
 avail|usinclair,cdickens,ebronte|doc
 avail|schacon|lib
 avail|schacon|tests

 and printing out a map of the form { user1 [path 1, path 2], user2
 [path2, path3] ...}.

 The author of the book provides a solution in Ruby, which I find relatively
 easy to follow, despite not having written any Ruby code before:

 def get_acl_access_data(acl_file)
  # read in ACL data
  acl_file = File.read(acl_file).split(\n).reject { |line| line == '' }
  access = {}
  acl_file.each do |line|
    avail, users, path = line.split('|')
    next unless avail == 'avail'
    users.split(',').each do |user|
  access[user] ||= []
  access[user]  path
    end
  end
  access
 end

 I then tried the same in Clojure, but found my solution to be much less
 readable compared to the Ruby code:

 (use '[clojure.string :only (split)])

 (defn get-acl-access-data [file]
  (let [acl (split (slurp file) #\n)]
    (apply merge-with #(into %1 %2)
  (map (fn [[avail users path]]
  (let [users (split users #,)]
 (reduce (fn [acc user]
 (when (= avail avail)
   (assoc acc user [path])))
    {} users)))
    (map #(split % #\|) acl)

 ;; Output:
 ;; {schacon [lib tests],
 ;;  usinclair [doc],
 ;;  cdickens [doc],
 ;;  ebronte [doc],
 ;;  tpw [nil],
 ;;  defunkt [nil],
 ;;  pjhyett [nil],
 ;; nickh [nil]}

 Maybe it is just because I am still a beginner, but I am afraid I won’t be
 able to figure out immediately what this code is doing a few weeks from now.

 However, I am sure there must be a better way of translating the Ruby
 version into Clojure. My main goal is on clarity, as I often struggle
 organizing my code in a way I would consider readable.

 I therefore would be glad for any ideas of improvement. Any suggestions are
 highly welcome!

 Best regards,

 Stefan

 Both the approaches above have the weakness that the steps are commingled,
 making it difficult to test (or reuse) part of the work done by the fn. Here
 is a Clojure version that makes the steps more distinct:
 (require '[clojure.string :as str])
 (require '[clojure.java.io :as io])
 (with-open [r (io/reader somefile)]
   (- (line-seq r)
        (map #(str/split % #\|))
        (filter #(= avail (first %)))
        (mapcat (fn [[_ users path]] (map hash-map (str/split users #,)
 (repeat [path]
        (apply merge-with into)))
 From this it is easy to see that the fn:
 1. splits the lines on |
 2. filters on avail
 3. builds a list of user|path pairs
 4. merges the user|path pairs into a map

 Stuart Halloway
 Clojure/core
 http://clojure.com

 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@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+unsubscr...@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 post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Mark Engelberg
Don't be afraid to split your work across multiple functions.  Not
only is this clearer, but you can then test the functions
independently.  So something like this:

(defn access-map-add-users [access-map users path]
  (apply merge-with into access-map
 (for [user users] {user [path]})))

(defn access-map-add-line [access-map line]
  (let [[avail user-string path] (split line #\|),
users (split user-string #\,)]
(cond
 (not= avail avail) access-map  ; no change to access-map
 :else (access-map-add-users access-map users path

(defn get-acl-access-data [file]
  (let [acl-lines (split (slurp file) #\n)]
(reduce access-map-add-line {} acl-lines)))

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Mark Engelberg
It's also worth noting that you can translate the Ruby code almost
line for line if you make use of Clojure's atoms to adopt a more
imperative approach.  In general, it's more satisfying to find a
pure functional way to solve a problem, but while you're transitioning
from Ruby, it's not unreasonable to copy Ruby's style in localized
contexts.

For example (untested),

(defn get-acl-access-data [file]
  (let [acl (split (slurp file) #\n),
access (atom {})]
(doseq [line acl]
  (let [[avail user-string path] (split line #\|)]
(when (not= avail avail)
  (doseq [user (split user-string #\,)]
(swap! access update user conj path)
@access))

Note that this makes use of an update function that really should be
in the core, but isn't:
; This should be in core
(defn update [m k f  args]
  (apply update-in m [k] f args))

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Mark Engelberg
On Thu, Mar 3, 2011 at 7:35 PM, Mark Engelberg mark.engelb...@gmail.com wrote:
        (when (not= avail avail)

Whoops, should be:
(when (= avail avail)

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stefan Rohlfing
Thank you all so much for helping me improve my code!

I personally find Stuart's suggestion to be the most readable. The use of 
the - macro makes the workflow quite easy to follow. 

I hope that with some more experience I will be able to see these patterns 
myself and adapt my code accordingly.

Best regards,

Stefan  

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Mark Engelberg
On Thu, Mar 3, 2011 at 9:15 PM, Stefan Rohlfing
stefan.rohlf...@gmail.com wrote:
 I personally find Stuart's suggestion to be the most readable. The use of
 the - macro makes the workflow quite easy to follow.

Yes, both the - and - macros are useful.  Unfortunately, about half
of Clojure's functions put the object you're operating on first, and
the other half put it last.  - works best with the former, and -
with the latter.

Stuart's code is readable because he found a way to structure it all
in terms of functions that put the main object last.  I find that in
most code, you end up with a mixture of the two types of functions,
and then those macros aren't quite so useful.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stefan Rohlfing
You are perfectly right. Organizing the code so that - or - an be applied 
is key here. 
Unfortunately, only if all functions to be composed follow the same pattern 
of either 'insert first' or 'insert last' can these macros be used.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Justin Kramer
'for' can be handy when unpacking compound lines:

(ns foobar
  (:require [clojure.java.io :as io]))

(defn parse-acl [acl-file]
  (with-open [r (io/reader acl-file)]
(apply
 merge-with into
 (for [[status users path] (map #(.split % \\|) (line-seq r))
   :when (= avail status)
   user (.split users ,)]
   {user [path]}

Justin

On Mar 3, 9:15 pm, Stefan Rohlfing stefan.rohlf...@gmail.com wrote:
 Dear Clojure Group,

 I am currently reading the online book Pro Git http://progit.org/book/. In
 chapter 7.4 http://progit.org/book/ch7-4.html (section “Enforcing a
 User-Based ACL System”) there is a task of reading in an access control list
 (ACL) file, such as the following

 # avail/unavail | users | path
 avail|nickh,pjhyett,defunkt,tpw
 avail|usinclair,cdickens,ebronte|doc
 avail|schacon|lib
 avail|schacon|tests

 and printing out a map of the form { user1 [path 1, path 2], user2
 [path2, path3] ...}.

 The author of the book provides a solution in Ruby, which I find relatively
 easy to follow, despite not having written any Ruby code before:

 def get_acl_access_data(acl_file)
  # read in ACL data
  acl_file = File.read(acl_file).split(\n).reject { |line| line == '' }
  access = {}
  acl_file.each do |line|
    avail, users, path = line.split('|')
    next unless avail == 'avail'
    users.split(',').each do |user|
      access[user] ||= []
      access[user]  path
    end
  end
  access
 end

 I then tried the same in Clojure, but found my solution to be much less
 readable compared to the Ruby code:

 (use '[clojure.string :only (split)])

 (defn get-acl-access-data [file]
  (let [acl (split (slurp file) #\n)]
    (apply merge-with #(into %1 %2)
              (map (fn [[avail users path]]
                          (let [users (split users #,)]
                             (reduce (fn [acc user]
                                             (when (= avail avail)
                                               (assoc acc user [path])))
                                            {} users)))
                        (map #(split % #\|) acl)

 ;; Output:
 ;; {schacon [lib tests],
 ;;  usinclair [doc],
 ;;  cdickens [doc],
 ;;  ebronte [doc],
 ;;  tpw [nil],
 ;;  defunkt [nil],
 ;;  pjhyett [nil],
 ;; nickh [nil]}

 Maybe it is just because I am an ambitious beginner at best, but I am afraid
 I won’t be able to figure out immediately what this code is doing in a few
 weeks.

 However, there probably is a better way of translating the Ruby version into
 Clojure. With better I mean easier to follow. My main goal is on clarity,
 as I often struggle organizing my code in a way I would consider readable.

 I therefore would be glad for any ideas of improvement. Any suggestions are
 highly welcome!

 Best regards,

 Stefan

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Tranforming an ACL file: Comparing Clojure with Ruby

2011-03-03 Thread Stefan Rohlfing
Thanks for your suggestion. 
Using the 'for' macro here makes the main part of the parse function much 
clearer.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en