Make this code more Rubyish

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) 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/

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/

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

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 :slight_smile:

David

On Sun, 9 Jul 2006, [email protected] wrote:

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

David

On Jul 08, 2006, at 6:26 pm, [email protected] 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

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]] }

On 7/7/06, [email protected] [email protected] 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/