From: "Ara.T.Howard" Date: 2004-04-26T00:34:14+09:00 Subject: Re: Great answers! A few more questions On Sat, 24 Apr 2004, Richard Lionheart wrote: > The Thomas/Hunt book says 'update' is a method in Hash and CGI::Session, but > not in Array. sorry - i meant Array#replace > > def initialize(*args, &block) > Could (must?) be invoked as MyArrayType['x','y']{|i| dostuff(i)} so that > block(element) could be executed which in turn would invoke > dostuff(elemement) for selected elements in the array(s) in args. ~ > cat a.rb class A def initialize(*args, &block) puts '---' p "args <#{ args.inspect }>" block.call if block end end A.new A.new{ p 'forty-two'} A.new 42 A.new(42){ p 'forty-two'} ~ > ruby a.rb --- "args <[]>" --- "args <[]>" "forty-two" --- "args <[42]>" --- "args <[42]>" "forty-two" if you look at the docs for Array#new you'll see it comes in three of the flavors above, since i needed the same method signature as Array#new this was a fast dirty way to do it without really needing to know the exact methed signature. if you program C this is about like saying int method() { } or in C++ int method(...) { } execpt it's __much__ easier to get at whatever args the methods has been called with! > > if Array === args.first > My guess is that this statement is equivalent to "if 'Array' is the type of > the first item in the 'args' array." That doesn't comport with "Programming > Ruby", Thomas et al, 2001, page 283, which seems to indicate "element by > element comparison of two arrays." But I can't see how you could intend to > compare Array's elements, because I don't think Array HAS any elements when > 'initialize' is invoked. note the '===' vs '=='. the method being invoked is the __class__ method '==='. in this case Array inherits this method from Class - one of it's parents. so check out the class method of Class named '==='. ;-) eg. ~ > cat b.rb array = [42] hash = {4 => 2} file = open __FILE__ [array, hash, file].each do |obj| [Array, Hash, File].each do |klass| printf "<%s> %s <%s>\n", obj.inspect, (klass === obj ? "is a" : "is not a"), klass end end ~ > ruby b.rb <[42]> is a <[42]> is not a <[42]> is not a <{4=>2}> is not a <{4=>2}> is a <{4=>2}> is not a <#> is not a <#> is not a <#> is a case uses '===' by default, so you can also ~ > cat c.rb array = [42] hash = {4 => 2} file = open __FILE__ [array, hash, file].each do |obj| case obj when Array puts "<#{ obj.inspect }> is a Array" when Hash puts "<#{ obj.inspect }> is a Hash" when File puts "<#{ obj.inspect }> is a File" end end ~ > ruby c.rb <[42]> is a Array <{4=>2}> is a Hash <#> is a File this is a bit more rubyish i think - but both peices of code are asking if an object is of a certain __type__ > > ary = args.shift > Equivalent to "ary = args[0]" in this instance, since 'args' is not modified > (no "!" after "shift"). you can always play and find out: ~ > irb irb(main):001:0> a = [0,1,2] => [0, 1, 2] irb(main):002:0> a.shift => 0 irb(main):003:0> a => [1, 2] shift is a method that DOES modify it's reciever. not all such methods end in '!', such as Array#delete. there is no hard and fast rule about this in ruby, but in general one can say that methods for which it is non-intuitive that the method would modify the reciever have a bang, and methods for which there are two versions (modifying and non-modifying) have a bang version. essentially it's up to the designer of the class to decide which methods are 'dangerous'. eg. ~ > irb irb(main):001:0> a = [0,1,2] => [0, 1, 2] irb(main):002:0> a.map{|elem| elem ** 2} => [0, 1, 4] irb(main):003:0> a => [0, 1, 2] irb(main):004:0> a.map!{|elem| elem ** 2} => [0, 1, 4] irb(main):005:0> a => [0, 1, 4] irb(main):006:0> a.delete 0 => 0 irb(main):007:0> a => [1, 4] > > super > Invokes Array#initialze with the original arguments that 'initialize' got, > but I don't see what this accomplishes. that's sort of the point - who knows what Array#initialize does, but we are trying to 'be an Array' so we had better do it. we could look into the sources for Array and find out, or let ruby do it for us. consider: ~ > cat d.rb class Base def initialize val @val = val end def meth p(@val + 2) end end class Derived0 < Base def initialize(*args, &block) super end end class Derived1 < Base def initialize(*args, &block) # nothing end end d0 = Derived0.new 40 d1 = Derived1.new 40 d0.meth d1.meth ~ > ruby d.rb 42 d.rb:7:in `meth': undefined method `+' for nil:NilClass (NoMethodError) from d.rb:26 > > an aggregate class is often safer and less frustrating to debug... > I assume you're talking about using a Module and including it into a class > or classes. > > As before, I appreciate your tutoring. well - don't take my word for it, play around and read the group - lot's of way to skin a cat. ;-) cheers. -a -- =============================================================================== | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov | PHONE :: 303.497.6469 | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328 | URL :: http://www.ngdc.noaa.gov/stp/ | TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done ===============================================================================