if I have an array-like class, is it possible to call the index with a
block?
class MyClass
def find(key)
return nil
end
def (key)
if (val = find(key))
return val
else
return yield(key) if block_given?
end
end
end
c = MyClass.new
c[:test] { "default" }
triggers a syntax error (Ruby 1.8.6).
Is there a way to accomplish this or do i need to do tricks like giving
the block to the constructor?
You can do:
c.(:text) { "default" }
but that's kind of ugly. I guess the whole point of c is to conceal
the fact that it's a method call, which means that it then doesn't try
to duplicate the full method call anatomy.
David
--
Upcoming training from Ruby Power and Light, LLC:
* Intro to Ruby on Rails, Edison, NJ, October 23-26
* Advancing with Rails, Edison, NJ, November 6-9
Both taught by David A. Black.
See http://www.rubypal.com for more info!
* David A. Black <dblack@rubypal.com> [09.10.2007]:
You can do:
c.(:text) { "default" }
ah, thanks, have not thought of that.
but that's kind of ugly. I guess the whole point of c is to conceal
the fact that it's a method call, which means that it then doesn't try
to duplicate the full method call anatomy.
at least its better than having a # and a #get(..) member where one
forwards to the other one. Will this change in 1.9 or later?
* Robert Dober <robert.dober@gmail.com> [09.10.2007]:
I agree with you that this is unfortunate for the general case.
In your case however -- unless it was only an example -- I would favor the
following idiom
c[:test] or "default"
nice! But in my case I will need the block because
a) in practice a simple literal will not suffice
b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)
Without these requirements I like your idea best...
* Robert Dober <robert.do...@gmail.com> [09.10.2007]:
> c[:test] or "default"
nice! But in my case I will need the block because
a) in practice a simple literal will not suffice
You're not limited to a simple literal.
b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)
Your example seems more hash-like than array-like to me, and it sounds
like using the same technique that Hash uses (passing a block to
Hash.new for default value computation) may work for you if the
computed value is a function of the object and/or the key.
class MyClass
def initialize obj=nil, &b
if block_given? @default_block = b
elsif obj @default_block = lambda {|h,k| obj }
end @h = Hash.new
end
def (key)
if !@h.has_key?(key) && @default_block @h[key] = @default_block.call(self, key)
puts "'#{@h[key]}' assigned to #{key}"
end @h[key]
end
def =(key, value) @h[key] = value
end
end
c = MyClass.new('default')
c[:foo] = 'foo'
puts c[:foo]
puts c[:test]
c = MyClass.new {|obj,key| "default for #{key}" }
puts c[:test]
···
On Oct 9, 10:40 am, Stephan Mueller <d4...@web.de> wrote:
* Brian Adkins <lojicdotcom@gmail.com> [10.10.2007]:
> This looks to me like you've just recreated features
> of Hash. Might as well just use Hash.
Presumably the OP had a reason for wanting an "array-like class"
instead of an actual Array or Hash. I only used a Hash in the example
for simplicity.
right! Thanks fpr your example, I decided to chose the variant where
the block is given to the constructor. If there wasn't the syntax-problem
with the block on # i would have chosen that as it seems to be more
intuitive.
Anyway, thanks for the interesting discussion. It's nice to see how
different people target the same problem with different solutions.
a) in practice a simple literal will not suffice
b) the result of the block should be assigned to the internal array at
the same step. (this was not part of my example code, sorry)
and
Anyway, thanks for the interesting discussion. It's nice to see how
different people target the same problem with different solutions.