# Make this code more Rubyish

**URL:** <https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573>\
**Category:** Ruby\
**Created:** [July 8, 2006, 1:40am UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573 "2006-07-08T01:40:03Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [July 8, 2006, 1:40am UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/1 "2006-07-08T01:40:03Z")

</div>

I have the following code I pounded out today. It works, but it feels  
more like Perl than Ruby to me. Can anyone offer some suggestions for  
how to improve the readability of it?

dev = /^SLOC._(?=^Totals grouped by)/im.match(`sloccount --addlangall . 2>/dev/null`)  
prd = /^SLOC._(?=^Totals grouped by)/im.match(`sloccount --addlangall $(cat .prod_dir) 2>/dev/null`)

dh = {}; ph = {}  
dev.to\_s.scan(/^(\d+)\s+(\w+)/).each { |p| dh[p[1]] = p[0] if p[0].to\_i

> 0 }  
> prd.to\_s.scan(/^(\d+)\s+(\w+)/).each { |p| ph[p[1]] = p[0] if p[0].to\_i  
> 0 }

df = {}; dfa = []  
ph.each\_pair do |k,v|  
dfa \<\< diff = dh[k].to\_i-v.to\_i  
df[diff] = “#{k}\t#{v}\t#{dh[k]}\t#{diff}”  
end  
dfa.sort! {|x,y| y \<=\> x }

puts “Dir\tProd\tDev\tDiff”  
dfa.each { |k| puts df[k] }

The code shells out to the program sloccount  
([SLOCCount](http://www.dwheeler.com/sloccount/)) which produces some output which  
looks like this (there is more, but the chunk I am interested in is  
contained in this sample):

Categorizing files.  
Computing results.

SLOC Directory SLOC-by-Language (Sorted)  
2606 tests php=2598,sh=8  
1462 models php=1462  
325 views php=325  
257 actions php=257  
227 top\_dir php=227  
84 sql sh=84  
0 CVS (none)  
0 img (none)  
0 templates (none)  
0 tutorials (none)

Totals grouped by language (dominant language first):  
php: 4869 (98.15%)  
sh: 92 (1.85%)

Total Physical Source Lines of Code (SLOC) = 4,961

The output my Ruby script produces looks like this:  
$ sloc\_comp.rb  
Dir Prod Dev Diff  
sql 3474 4858 1384  
top\_dir 81 81 0  
actions 244 241 -3  
views 430 424 -6  
tests 437 416 -21  
models 735 618 -117

Regards,  
Jason  
[http://blog.casey-sweat.us/](http://blog.casey-sweat.us/)

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [July 8, 2006, 7:21am UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/2 "2006-07-08T07:21:45Z")

</div>

Jason Sweat wrote:

> dev.to\_s.scan(/^(\d+)\s+(\w+)/).each { |p| dh[p[1]] = p[0] if p[0].to\_i \> 0 }  
> dfa.each { |k| puts df[k] }  
> SLOC Directory SLOC-by-Language (Sorted)
> 
> Regards,  
> Jason  
> [http://blog.casey-sweat.us/](http://blog.casey-sweat.us/)

dev = \<\<EOM  
2606 tests php=2598,sh=8  
1462 models php=1462  
325 views php=325  
257 actions php=257  
227 top\_dir php=227  
84 sql sh=84  
0 CVS (none)  
0 img (none)  
0 templates (none)  
0 tutorials (none)  
EOM

prod = \<\<EOM  
2609 tests php=2598,sh=8  
1460 models php=1462  
321 views php=325  
1257 actions php=257  
327 top\_dir php=227  
84 sql sh=84  
0 CVS (none)  
0 img (none)  
0 templates (none)  
0 tutorials (none)  
EOM

puts “Dir\tProd\tDev\tDiff”,  
[prod, dev].map{|x| x.split(/\s+\S+\n/).map{|s| s.split} }.  
transpose.map{|x| x.transpose}.map{|n,s|  
[s[0], n[0], n[1], n[1].to\_i - n[0].to\_i]}.select{|x|  
x[1,2]!=[“0”,“0”]}.sort\_by{|x| x[-1]}.map{|x| x.join(“\t”)}.reverse

Dir Prod Dev Diff  
views 321 325 4  
models 1460 1462 2  
sql 84 84 0  
tests 2609 2606 -3  
top\_dir 327 227 -100  
actions 1257 257 -1000

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [July 8, 2006, 7:24pm UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/3 "2006-07-08T19:24:10Z")

</div>

Hi –

On Sat, 8 Jul 2006, William J. wrote:

> puts “Dir\tProd\tDev\tDiff”,  
> [prod, dev].map{|x| x.split(/\s+\S+\n/).map{|s| s.split} }.  
> transpose.map{|x| x.transpose}.map{|n,s|  
> [s[0], n[0], n[1], n[1].to\_i - n[0].to\_i]}.select{|x|  
> x[1,2]!=[“0”,“0”]}.sort\_by{|x| x[-1]}.map{|x| x.join("\t")}.reverse

He’s done it in Perl already – he said more Rubyish 🙂

David

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [July 8, 2006, 7:29pm UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/4 "2006-07-08T19:29:43Z")

</div>

On Sun, 9 Jul 2006, removed\_email\_address@domain.invalid wrote:

> He’s done it in Perl already – he said more Rubyish 🙂  
> Whoops, my witty repartee was factually inaccurate.  
> s/in Perl/in Ruby but in a more typically Perlish style/ 🙂

David

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [July 8, 2006, 9:17pm UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/5 "2006-07-08T21:17:49Z")

</div>

On Jul 08, 2006, at 6:26 pm, removed\_email\_address@domain.invalid wrote:

> David

I actually thought you were being metaphorical with that… that code  
is the most Perlish Ruby I’ve ever seen.

It’s been said a million times that you can write FORTRAN in any  
language; judging by the snippet above I think it’s fair to say you  
can write any language in Ruby!

Ashley

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [August 3, 2006, 11:57am UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/6 "2006-08-03T11:57:54Z")

</div>

Hi –

On Sat, 8 Jul 2006, Jason Sweat wrote:

> dev.to\_s.scan(/^(\d+)\s+(\w+)/).each { |p| dh[p[1]] = p[0] if p[0].to\_i \> 0 }  
> prd.to\_s.scan(/^(\d+)\s+(\w+)/).each { |p| ph[p[1]] = p[0] if p[0].to\_i \> 0 }
> 
> df = {}; dfa = []  
> ph.each\_pair do |k,v|  
> dfa \<\< diff = dh[k].to\_i-v.to\_i  
> df[diff] = “#{k}\t#{v}\t#{dh[k]}\t#{diff}”

I think there’s a logic flaw there. If you have two directories with  
the same diff count, the second one will clobber the hash entry from  
the first one.

> 84 sql sh=84
> 
> actions 244 241 -3  
> views 430 424 -6  
> tests 437 416 -21  
> models 735 618 -117

Here’s a little rewrite, which uses scanf to get the necessary data  
from the lines, and does the hashing and sorting a little differently.  
See if anything here is of use to you.

dev = \<\<EOM  
2606 tests php=2598,sh=8  
1462 models php=1462  
325 views php=325  
257 actions php=257  
227 top\_dir php=227  
84 sql sh=84  
0 CVS (none)  
0 img (none)  
0 templates (none)  
0 tutorials (none)  
EOM

prod = \<\<EOM  
2609 tests php=2598,sh=8  
1460 models php=1462  
321 views php=325  
1257 actions php=257  
327 top\_dir php=227  
84 sql sh=84  
0 CVS (none)  
0 img (none)  
0 templates (none)  
0 tutorials (none)  
EOM

require ‘scanf’

def get\_counts(lines)  
res = {}  
lines.scanf("%i%s%s") do |count, thing|  
next unless count \> 0  
res[thing] = count  
end  
res  
end

dh = get\_counts(dev)  
ph = get\_counts(prod)

dfa = []  
df = {}  
dh.each\_pair do |k,v|  
diff = v - ph[k]  
dfa \<\< [diff,k]  
df[k] = [k, ph[k], v, diff].join("\t")  
end

puts “Dir\tProd\tDev\tDiff”  
dfa.sort.reverse.each { |k| puts df[k[1]] }

---

<div class="post-metadata">

**Author:** ![sweatje](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ad7895/32.png) [@sweatje](https://www.ruby-forum.com/u/sweatje)\
**Post date:** [August 3, 2006, 2:24pm UTC](https://www.ruby-forum.com/t/make-this-code-more-rubyish/97573/7 "2006-08-03T14:24:13Z")

</div>

On 7/7/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I think there’s a logic flaw there. If you have two directories with  
> the same diff count, the second one will clobber the hash entry from  
> the first one.

Yes, I actually noticed that as I was running it on some other  
projects. Amazing how your first sample can taint your perspective.

Does this iteration look a bit less like line noise?

require ‘scanf’

def sloc\_scandir(dir)  
/^SLOC._?$(._(?=^Totals grouped by))/im.match(  
%x{sloccount --addlangall #{dir} 2\>/dev/null}  
)[1].to\_s  
end

def get\_counts(lines)  
res = {}  
lines.scanf(“%i%s%s”) do |count, thing|  
next unless count \> 0  
res[thing] = count  
end  
res  
end

class SlocDir  
attr\_accessor :name, :dev, :prd  
def initialize(name, dev)  
@name = name  
@dev = dev  
end  
def diff  
@dev - @prd  
end  
def render  
“#{@name}\t#{@prd}\t#{@dev}\t#{diff}”  
end  
end

dirs = {}  
get\_counts(sloc\_scandir(‘.’)).each\_pair { |k,v| dirs[k] =  
SlocDir.new(k,v) }  
get\_counts(sloc\_scandir(`cat .prod_dir`)).each\_pair { |k,v| dirs[k].prd  
= v }

puts “Dir\tProd\tDev\tDiff”  
dirs.values.sort{ |x,y| y.diff \<=\> x.diff }.each { |d| puts d.render }

Regards,  
Jason  
[http://blog.casey-sweat.us/](http://blog.casey-sweat.us/)
