|
30 Jul 2009, 11:25
David Parry
(7 posts)
|
Hi, Dave Thomas, and all others. Thanks for the Ruby Metaprogramming screencasts… my colleague and I have been finding them invaluable.
We have a problem that we have been trying to solve using metaprogramming techniques, but have so far failed. It currently works as a recursive algorithm, but it “smells” like something that would be far better implemented using blocks and lambdas. Here it is:
We are using Ruport to generate reports. These reports use x number of the query-able fields (state, country, year, department etc..), do a sum on an amount field and group the results. We want to be able to arbitrarily nest the results, which has lead us to a recursive algorithm.
Here’s a simplified example:
department = %w(sales research production)
years = %w(2005 2006 2007 2008 2009)
months = %w(January February March April May June July August September October November December)
product_type = %w(big little skinny)
def output_line(args)
args = [args].flatten
a_string = ""
args.each {|a| a_string += "#{a} "}
puts "#{a_string} amount = #{rand(100)}"
end
def process(arr)
p2(arr.reverse, [])
end
def p2(arr, params = [])
arr_clone = arr.clone
top = arr_clone.pop
p = params.clone
if top.is_a?(Array)
top.each do |a|
new_params = [p, a].flatten
p2(arr_clone, new_params)
end
else
output_line(params)
end
end
process([department, years, months])
puts "************"
process([years, department])
puts "************"
process([months, department, years, product_type])
puts "************"
process([department])
puts "************"
As I said, this smells like something that could be done using lambdas or Procs, but it’s got us a tad confused. Of course, as a recursive algorithm, perhaps this may well be a perfectly good implementation, if a little confusing.
Does anyone have any suggestions about how to approach this?
|
|
30 Jul 2009, 11:29
David Parry
(7 posts)
|
Here’s some sample output, btw:
sales 2005 January amount = 70
sales 2005 April amount = 39
sales 2005 July amount = 13
sales 2005 October amount = 44
sales 2006 January amount = 57
sales 2006 April amount = 30
sales 2006 July amount = 55
sales 2006 October amount = 56
sales 2007 January amount = 54
sales 2007 April amount = 98
sales 2007 July amount = 14
sales 2007 October amount = 53
production 2005 January amount = 1
production 2005 April amount = 99
production 2005 July amount = 30
production 2005 October amount = 69
production 2006 January amount = 91
production 2006 April amount = 19
production 2006 July amount = 24
production 2006 October amount = 10
production 2007 January amount = 2
production 2007 April amount = 19
production 2007 July amount = 10
production 2007 October amount = 94
************
2005 sales amount = 17
2005 production amount = 72
2006 sales amount = 25
2006 production amount = 63
2007 sales amount = 16
2007 production amount = 73
************
January sales 2005 big amount = 94
January sales 2005 little amount = 35
January sales 2006 big amount = 14
January sales 2006 little amount = 39
January sales 2007 big amount = 57
January sales 2007 little amount = 72
January production 2005 big amount = 40
January production 2005 little amount = 58
January production 2006 big amount = 12
January production 2006 little amount = 87
January production 2007 big amount = 57
January production 2007 little amount = 7
April sales 2005 big amount = 60
April sales 2005 little amount = 34
April sales 2006 big amount = 80
April sales 2006 little amount = 25
April sales 2007 big amount = 20
April sales 2007 little amount = 81
April production 2005 big amount = 17
April production 2005 little amount = 94
April production 2006 big amount = 67
April production 2006 little amount = 86
April production 2007 big amount = 62
April production 2007 little amount = 76
July sales 2005 big amount = 55
July sales 2005 little amount = 52
July sales 2006 big amount = 79
July sales 2006 little amount = 4
July sales 2007 big amount = 60
July sales 2007 little amount = 79
July production 2005 big amount = 20
July production 2005 little amount = 26
July production 2006 big amount = 20
July production 2006 little amount = 14
July production 2007 big amount = 16
July production 2007 little amount = 47
October sales 2005 big amount = 6
October sales 2005 little amount = 86
October sales 2006 big amount = 55
October sales 2006 little amount = 7
October sales 2007 big amount = 4
October sales 2007 little amount = 48
October production 2005 big amount = 59
October production 2005 little amount = 76
October production 2006 big amount = 86
October production 2006 little amount = 6
October production 2007 big amount = 2
October production 2007 little amount = 64
************
sales amount = 43
production amount = 4
************
|
|
30 Jul 2009, 17:53
Dave Thomas
(233 posts)
|
I’m not sure it’s a metaprogramming issue, but you can use some Ruby method-passing semantics to tidy things up a bit:
department = %w(sales research production)
years = %w(2005 2006 2007 2008 2009)
months = %w(January February March April May June July August September October November December)
product_type = %w(big little skinny)
def really_process(result, first=[], *rest)
if first.empty?
puts result.join(" ")
else
first.each do |item|
result << item
really_process(result, *rest)
result.pop
end
end
end
def process(*categories)
really_process([], *categories)
end
process(department, years, months)
puts "************"
process(years, department)
puts "************"
process(months, department, years, product_type)
puts "************"
process(department)
puts "************"
<code></pre>
|
|
31 Jul 2009, 00:31
David Parry
(7 posts)
|
Nice! I will try and use this approach in my production code. Although, I’m still thinking this could be done with blocks or lambdas.
What I imagine is some how creating an “iterator” of some sort, for each of the arrays, then say “iterator this one with this one inside of it.”
I’m still experimenting, so if I come up with something I’ll post it…
|
| |
You must be logged in to comment
|