Probably total sacrilege, but I was using this to have "nil" as a valid value in arithmetic and to treat numbers as if they were arrays (in a limited sense). The latter is easy to fix, by storing all numbers as 1 element arrays. This solves the iterator on "nil" too. All nil values will be in an array, so I just need to iterate on the array.
Using "nil" in arithmetic is to differentiate the no data state (nil), from having seen a data point, even a 0 value. Probably best to subclass Fixnum and build my own objects for arithmetic. Altering the numeric classes is definitely a tempting thing though.
I have XML definitions of the source log file and the resulting summary I want to get.
e.g.
a
<src>
...
<column id="sourceadjacentaddress">
<type>string</type>
</column>
<column id="destadjacentaddress">
<type>string</type>
</column>
...
</src>
<rslt>
...
<column id="link1">
<test exp="@src_sourceadjacentaddress == '00-D0-41-68-CF-56' || @src_destadjacentaddress == '00-D0-41-68-CF-56'"> </test>
<value exp= "+= @src_d_tooctets+src_d_fromoctets"> </value>
<type>int</type>
<scale exp="/@groupby_duration.megabyte"> </scale>
<format>%d</format>
</column>
...
</rslt>
This gets turned into ruby code that parses the log. It uses modified column name as variables. The test expression determines if the output column is modified, and the value expression is used to set or alter the value. If the values start as nil, then adding a value, will initialise them. Meeting further values, will result in them being added on.
If multiple results are required (e.g. for a histogram), then a value expression like
<value exp= "+= [@src_d_tooctets, @src_d_fromoctets]"> </value>
results in the to and from traffic being added to an array result called @rslt_link1, rather than a simple numeric result.
I did this by I adding "each" and "each_with_index" to every Object, thus allowing numbers and nil values to have an iterator.
I replaced the Fixnum + with one that would add arrays to numbers, giving an array result or Fixnum result, depending on the value being added.
Also the Arrays class was modified to add two arrays, by adding the elements at the same array index to each other, not concatenating the arrays.
I then committed the ultimate sin, and added a plus method to nil.
After all these hacks, I can
add a number to an array, and the first element will get altered.
add an array to a number, and get an Array with the first element altered
add a number or Array to nil, and get that number or the Array
i.e.
class Object
def each
if self != nil then yield(self) end
end
def each_with_index
if self != nil then yield(self,0) end
end
def length
if self == nil then 0 else 1 end
end
end
class Array
def +(value)
value.each_with_index { |x,i| self[i] += x }
self
end
end
class Fixnum
alias oldPlus +
def +(value)
if(value.length == 1)
self.oldPlus(value)
else
value.+(self)
end
end
end
class NilClass
def +(value)
value
end
end
a = [1,3]
a += [5,2]
a.each {|b| puts b }
puts
a = 1
a += 2
a.each {|b| puts b }
puts
a += [5,2]
a.each {|b| puts b }
puts
a = nil
a += 10
a.each {|b| puts b }
puts
a = nil
a += [3,8]
a.each {|b| puts b }
puts
a = ["hello","I"]
a += [" world"," repent"]
a.each {|b| print b, " " }
puts
···
On 20/05/2006, at 2:18 PM, Sam Roberts wrote:
Quoting rob@cs.auckland.ac.nz, on Sat, May 20, 2006 at 09:50:49AM +0900:
In the nil case, I wanted it to iterate and be printed as in the same
way as a non-nil value. In the plot data, a nil prints as '-'. I
hadn't thought of other code expecting to fail when the value was nil
or not an array. They probably wont want nil to have a to_s()
returning '-' either, not that anything has failed doing this, in
this instance.
The temptation to change the core classes to work a little more like you
want is almost overwhelming... at least I have found it so. I guess in
this case you could do:
def gnuplot_each(v, &proc)
if v.respond_to? :each
v.each &proc
else
yield v
end
end
then instead of doing
data.each {..}
you could do
gnuplot_each(data) {...}
cheers,
Sam