alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})
The implementation I came up with is this:
class Object
def self.duck(*name_proc)
duck = self.new
duckclass = (class << duck;self;end)
while not name_proc.empty?
name,proc = name_proc.slice!(0,2)
duckclass.send(:define_method,name,&proc)
end
duck
end
end
Is there another way to do this? With all of the talk about
duck-typing, there would already be something out there to do
this.
__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html
Well, my way isn't really different, and I actually wouldn't use
either "my" way or yours, but in the spirit of ruby I propose this
revision:
class Object
def self.duck(methods = {})
duck = self.new
duckclass = (class << duck; self; end)
methods.each do |name,proc|
duckclass.send(:define_method, name, &proc)
end
duck
end
end
alphabet = Object.duck(
:[] => proc{ |i| ?a+i },
:size => proc{ 26 }
)
I simply replaced the array with a hash. Looks a bit cleaner to me.
Jacob Fugal
> Is there another way to do this? With all of the talk about
> duck-typing, there would already be something out there to do
> this.
There was some talk in the past about Object.new taking a block, which
imho would be useful for this. Meanwhile what about using Struct.new
with a block to define methods?
On Tue, 7 Jun 2005, Eric Mahurin wrote:
> Regarding duck-typing... Is there an easy way make a "duck"?
> i.e. an object that responds to enough methods to be an
> acceptable argument to a certain methods. For example, if I
> have a method that takes aString and uses the #size and #[i]
> methods, I could pass it something that looked just enough like
> a String to work:
>
> alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})
>
> The implementation I came up with is this:
>
> class Object
> def self.duck(*name_proc)
> duck = self.new
> duckclass = (class << duck;self;end)
> while not name_proc.empty?
> name,proc = name_proc.slice!(0,2)
> duckclass.send(:define_method,name,&proc)
> end
> duck
> end
> end
>
>
> Is there another way to do this? With all of the talk about
> duck-typing, there would already be something out there to do
> this.
I've always understood "duck typing" to refer to a particular approach
to the handling of method calls on objects, so I personally wouldn't
expect a to see a correlation between the amount of talk about duck
typing and this kind of technique. Your technique looks to me like it
has more to do with the opposite end of the process: the preparation
and priming of an object, as a way of creating a situation favorable
to subsequent duck typing. I don't think what you've got here stands
in any unique or special relation to duck typing; after all, from the
duck typing perspective, a method that an object got from its original
Class is just as much part of the object's behavior as a method the
object got extended with later.
In fact... your technique actually calls to mind Module#extend. Do
you have a case where you'd prefer to do it the way you've done it
above, rather than defining the methods in a module and then extending
your object with it?
David
--
David A. Black
dbl...@wobblini.net
Why aren't you satisfied with
class Alpha
def [](i) ?a+i end
def size() 26 end
end
alphabet = Alpha.new
or
alphabet = Object.new
def alphabet.[](i) ?a+i end
def alphabet.size() 26 end
You can even squeeze that on one line if you feel the need for it. I
mean, you don't generate those methods dynamically or get them from
somewhere else so why not just use the std approach?
Kind regards
robert
> Hi --
>
> On Tue, 7 Jun 2005, Eric Mahurin wrote:
>
> > Regarding duck-typing... Is there an easy way make a
> "duck"?
> > i.e. an object that responds to enough methods to be an
> > acceptable argument to a certain method. For example, if
> I
> > have a method that takes aString and uses the #size and
> #[i]
> > methods, I could pass it something that looked just enough
> like
> > a String to work:
> >
> > alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})
> >
> > The implementation I came up with is this:
> >
> > class Object
> > def self.duck(*name_proc)
> > duck = self.new
> > duckclass = (class << duck;self;end)
> > while not name_proc.empty?
> > name,proc = name_proc.slice!(0,2)
> > duckclass.send(:define_method,name,&proc)
> > end
> > duck
> > end
> > end
> >
> >
> > Is there another way to do this? With all of the talk
> about
> > duck-typing, it seems like there would already be something
out there to
> do
> > this.
>
> I've always understood "duck typing" to refer to a particular
> approach
> to the handling of method calls on objects, so I personally
> wouldn't
> expect a to see a correlation between the amount of talk
> about duck
> typing and this kind of technique. Your technique looks to
> me like it
> has more to do with the opposite end of the process: the
> preparation
> and priming of an object, as a way of creating a situation
> favorable
> to subsequent duck typing. I don't think what you've got
> here stands
> in any unique or special relation to duck typing; after all,
> from the
> duck typing perspective, a method that an object got from its
> original
> Class is just as much part of the object's behavior as a
> method the
> object got extended with later.
Correct. I'm looking at the other side - making an object (a
"duck") that works well with a method using duck-typing.
> In fact... your technique actually calls to mind
> Module#extend. Do
> you have a case where you'd prefer to do it the way you've
> done it
> above, rather than defining the methods in a module and then
> extending
> your object with it?
I was wanting to define the duck in-line with arbitrary procs
for the methods. I'll give you a more concrete example using a
duck-typed method. Take enum.include?(obj) for example. It
searchs in enum something that matches obj using obj==element.
Let's say I wanted to match with obj===element or
obj.include?(element), etc. I could do these:
enum.include?(Object.duck(:==,range.method(:===)))
enum.include?(Object.duck(:==,set.method(:include?)))
enum.include?(Object.duck(:==,hash.method(:[])))
enum.include?(Object.duck(:==,proc{|element|...}))
A special case that is very easily handled right now is if your
duck typing method takes an argument that only needs to respond
to []. For example:
def scan_while(aHash)
loop {
...
aHash[element] or break
...
}
end
scan_while(hash)
scan_while(proc{|element|...})
scan_while(set.method(:include?))
scan_while(range.method(:===))
scan_while(obj.method(:==))
__________________________________
Discover Yahoo!
Get on-the-go sports scores, stock quotes, news and more. Check it out!
http://discover.yahoo.com/mobile.html
For the example I gave above, I think you are correct. The
examples I gave in response to David Black are probably better
ones. With those, a simple "def" won't cut it. You need
define_method. But, using define_method is cumbersome from an
object because you first need to make it have a singleton
class, then use "send" to access it from that class because it
it a private method. Another solution to the problem of
"making a duck" would be to have a
Object#define_singleton_method:
class Object
def define_singleton_method(name,&block)
klass = (class << self;self;end)
klass.send(:define_method,name,&block)
self
end
end
Then, for example, you could do this to make a set be useful
for a method that uses == for comparison:
seteq = Object.new.
define_singleton_method(:==,&set.method(:include?))
I'm not sure why this isn't in Object right now. It seems like
the rest of the *singleton_method* methods are there.
__________________________________
Discover Yahoo!
Find restaurants, movies, travel and more fun for the weekend. Check it out!
http://discover.yahoo.com/weekend.html
At Tue, 7 Jun 2005 01:00:23 +0900,
Eric Mahurin wrote in [ruby-talk:144691]:
> Regarding duck-typing... Is there an easy way make a "duck"?
> i.e. an object that responds to enough methods to be an
> acceptable argument to a certain methods. For example, if I
> have a method that takes aString and uses the #size and #[i]
> methods, I could pass it something that looked just enough like
> a String to work:
>
> alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})
I'd posted a feature called `behavior' in [ruby-dev:25772].
alphabet = Object.behaving(:[]) {|i|(?a+i).chr}
p alphabet[20] #=> "u"
--
Nobu Nakada
Looks like 2 approaches to doing the same thing. I do like the
hash interface a little better. From your code that I read, it
looks like you can do this:
alphabet = Object.new.behaving(:[] => proc{|i|?a+i}, size:
proc{26})
I didn't know about the ":symbol => value" shortcut of "symbol:
value". Or forgot about it. Very nice in this situation.
Is there an advantage to having a separate Behavior class as
opposed the solution I had: making a singleton Object directly?
I think having something like this readily available would
promote more (interesting) uses of duck-typing.
__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html
Btw, you can also use class eval:
class Object
def define_singleton_method(name,&block)
klass = (class << self;self;end).class_eval do
define_method(name,&block)
end
self
end
end
and also
o=Object.new
class <<o;self;end.class_eval do
def bax() "bar" end
end
o.bax
> Then, for example, you could do this to make a set be useful
> for a method that uses == for comparison:
>
> seteq = Object.new.
> define_singleton_method(:==,&set.method(:include?))
This does not work. You cannot transfer a method from one class to
another:
09:14:01 [ruby]: cat define.rb
class Foo
def test() bar() end
def bar() "FOO::BAR" end
end
class Bar
def bar() "BAR::BAR" end
end
bar = Bar.new
bar_kl = (class<<bar;self;end)
bar_kl.send(:define_method, :xxx, Foo.new.method(:test))
bar_kl.send(:public, :xxx)
bar.xxx()
09:15:33 [ruby]: ruby define.rb
define.rb:16:in `xxx': bind argument must be an instance of Foo
(TypeError)
from define.rb:16
> I'm not sure why this isn't in Object right now. It seems like
> the rest of the *singleton_method* methods are there.
Probably because it doesn't work - at least not completely the way you
like to have it. Btw, and if you're borrowing implementations from other
classes then you can directly use an instance of that class...
Kind regards
robert
At Tue, 7 Jun 2005 11:59:47 +0900,
Eric Mahurin wrote in [ruby-talk:144750]:
> Is there an advantage to having a separate Behavior class as
> opposed the solution I had: making a singleton Object directly?
To allow sharing same behavior.
--
Nobu Nakada
If you put an & in front of your "Foo.new.method(:test)" (like
what I did), or .to_proc it will work fine.
__________________________________
Discover Yahoo!
Use Yahoo! to plan a weekend, have fun online and more. Check it out!
http://discover.yahoo.com/
I'm not sure how much application this would have over the
conventional class definition approach.
At first I didn't think this would work because I thought you
wouldn't be able to create any instance variables using
define_method. I thought any @ variables in a proc would refer
to the @ variable in the original context, but define_method
apparently rebinds them to the object.
I always remind myself that the binding of "self" changes - even for each
method invocation. This explains pretty good why this works as it should.
16:31:18 [ruby]: ruby x.rb
4
666
666
16:38:10 [ruby]: cat x.rb
o=Object.new
def o.size() 666 end
x="test"
class<<o;self;end.class_eval do
define_method(:test) do
puts x.size
puts self.size
puts size
end
end
o.test
16:38:14 [ruby]:
Kind regards
robert
Darn, though I had the & in there. However, there's another problem which
I originally wanted to demonstrate with this setup: methods might not
behave as one would expect:
16:31:16 [ruby]: cat define.rb
class Foo
def test() bar() end
def bar() "FOO::BAR" end
end
class Bar
def bar() "BAR::BAR" end
end
bar = Bar.new
bar_kl = (class<<bar;self;end)
bar_kl.send(:define_method, :xxx, &Foo.new.method(:test))
bar_kl.send(:public, :xxx)
p bar.xxx()
16:31:16 [ruby]: ruby define.rb
"FOO::BAR"
Foo::test is still bound to Foo::bar and you probably would rather see
Bar::bar being called.
Kind regards
robert
define_method, instance_eval, class_eval, module_eval, and
maybe others seem to have this special ability - rebind the
meaning of self (but not locals) for a Proc. This brings us
back to the topic I talked about earlier - unbind/rebind procs.
It would be nice if we could do the same thing to a Proc that
these methods can do internally:
aProc.rebind_self(obj) -> aNewProc # rebind what self is
With this, "obj.instance_eval(&proc)" would be equivalent to
"proc.rebind_self(obj).call". Other useful rebindings may be:
aProc.rebind_locals(binding) -> aNewProc
aProc.rebind_all(binding) -> aNewProc
# replace local variables with their current values
aProc.unbind_locals -> aNewProc
BTW, I don't see the value that class_eval and module_eval
provide over instance_eval. classes and modules can be treated
like instances just like any other object.
__________________________________
Discover Yahoo!
Get on-the-go sports scores, stock quotes, news and more. Check it out!
http://discover.yahoo.com/mobile.html
Wow, this is nice... but where is it documented?
I used to use code like this until now:
class Foo < Struct.new(:all, :my, :fields)
def mymethod
# ...
end
end
--
Christian Neukirchen <chneuk...@gmail.com> http://chneukirchen.org
So is Struct.new(&block) equivalent to:
StructClass = Struct.new
StructClass.instance_eval(&block)
StructClass
So you could do this to make an object using == to map to ===
of a range.
alpha = ('a'..'z')
alphaeq =
Struct.new(:dummy){define_method(:==,&alpha.method(:===))}.new
Actually it looks like you can do the same thing with Class:
alpha = ('a'..'z')
alphaeq = Class.new{define_method(:==,&alpha.method(:===))}.new
This is still pretty verbose, but it seems like a descent
solution. I'll use this until something better comes along.
__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html
Why do you want rebind if the other approach is much simpler?
#instance_eval *always* rebinds self (and only self).
> Other useful rebindings may be:
>
> aProc.rebind_locals(binding) -> aNewProc
> aProc.rebind_all(binding) -> aNewProc
> # replace local variables with their current values
> aProc.unbind_locals -> aNewProc
When do you think will unbind_locals be useful? A proc typically needs some
of the variables bound. As for the rebindings, I would prefer a general
mechanism to transfer state from one binding to another. Then one could
implement all your rebind* methods in terms of that general mechanism plus
do more. Alternatively one could think about conversion methods Binding <->
Hash.
> BTW, I don't see the value that class_eval and module_eval
> provide over instance_eval. classes and modules can be treated
> like instances just like any other object.
class_eval and instance_eval are not equivalent:
>> class Foo;end
=> nil
>> Foo.class_eval do
?> def bar() "bar" end
>> end
=> nil
>> Foo.new.bar
=> "bar"
>> Foo.instance_eval do
?> def bax() "bax" end
>> end
=> nil
>> Foo.new.bax
NoMethodError: undefined method `bax' for #<Foo:0x10179ee0>
from (irb):12
>>
Kind regards
robert
> > define_method, instance_eval, class_eval, module_eval, and
> > maybe others seem to have this special ability - rebind the
> > meaning of self (but not locals) for a Proc. This brings
> us
> > back to the topic I talked about earlier - unbind/rebind
> procs.
> > It would be nice if we could do the same thing to a Proc
> that
> > these methods can do internally:
> >
> > aProc.rebind_self(obj) -> aNewProc # rebind what self is
> >
> > With this, "obj.instance_eval(&proc)" would be equivalent
> to
> > "proc.rebind_self(obj).call".
>
> Why do you want rebind if the other approach is much simpler?
>
> #instance_eval *always* rebinds self (and only self).
because you can get a handle on that rebound Proc. You might
want to pass it around or whatever.
> > Other useful rebindings may be:
> >
> > aProc.rebind_locals(binding) -> aNewProc
> > aProc.rebind_all(binding) -> aNewProc
> > # replace local variables with their current values
> > aProc.unbind_locals -> aNewProc
>
> When do you think will unbind_locals be useful?
As a replacement for many string evals - which are ugly,
inefficient, and possibly dangerous. Many (most?) times that
you need to eval a string it is because you need to pull in
some local variables to help define the string to be evaled.
Here is the first example of a string eval in the 1.8 library I
found:
for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
LI OPTION tr th td ]
methods += <<-BEGIN + nO_element_def(element) + <<-END
def #{element.downcase}(attributes = {})
BEGIN
end
END
end
eval(methods)
This could be replaced by:
for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
LI OPTION tr th td ]
define_method(element.downcase.to_sym ,
proc { |attributes={}|
nO_element_def(element)
}.unbind_locals # replace element with constant
)
end
Much cleaner, huh?
> A proc
> typically needs some
> of the variables bound. As for the rebindings, I would
> prefer a general
> mechanism to transfer state from one binding to another.
> Then one could
> implement all your rebind* methods in terms of that general
> mechanism plus
> do more. Alternatively one could think about conversion
> methods Binding <->
> Hash.
Transferring locals might be pretty easy, but transferring the
meaning of self would be more difficult, I think. At least
without making a new Binding (and then you'd still need a way
to rebind it to the original proc).
> > BTW, I don't see the value that class_eval and module_eval
> > provide over instance_eval. classes and modules can be
> treated
> > like instances just like any other object.
>
> class_eval and instance_eval are not equivalent:
>
> >> class Foo;end
> => nil
> >> Foo.class_eval do
> ?> def bar() "bar" end
> >> end
> => nil
> >> Foo.new.bar
> => "bar"
> >> Foo.instance_eval do
> ?> def bax() "bax" end
> >> end
> => nil
> >> Foo.new.bax
> NoMethodError: undefined method `bax' for #<Foo:0x10179ee0>
> from (irb):12
Interesting. I assumed that since
class_eval/instance_eval/module_eval all returned the same
"self" that they did the same thing. The only difference I see
is in "def <method> ...". With class_eval, it defines instance
methods and with instance_eval, it defines class methods.
That's kind of strange. Some kind of magic is going on here
other than the changing of self.
I was hoping that instance_eval could be used to define class
methods using #define_method, but #define_method does the same
with both - defines instance methods. Anybody know of an
equivalent to #define_method for making class methods? I
couldn't figure out any way to define a class method from a
proc - just out of curiosity.
__________________________________
Do you Yahoo!?
Yahoo! Mail - Helps protect you from nasty viruses.
http://promotions.yahoo.com/new_mail
nowhere, it seem. But I remebered it was discussed on ruby-core and
tried it :)
<snip>
> So is Struct.new(&block) equivalent to:
>
> StructClass = Struct.new
> StructClass.instance_eval(&block)
> StructClass
no, class_eval, and you have to submit at least one arg to Struct.new :/
I think of self as a dynamic variable, outside of lexical scope
and that makes me think..
> This brings us
> back to the topic I talked about earlier - unbind/rebind procs.
> It would be nice if we could do the same thing to a Proc that
> these methods can do internally
.. would dynamic variables be enough? Christian Neukirchen has a nifty
implementation of them on his blog.
<snip>
> BTW, I don't see the value that class_eval and module_eval
> provide over instance_eval. classes and modules can be treated
> like instances just like any other object.
if you define a method in a class_eval/module_eval block on object X
ruby will define it in instances of X while if you use instance_eval
you'd define the method on the object X
> Eric Mahurin ha scritto:
> > This brings us
> > back to the topic I talked about earlier - unbind/rebind
> procs.
> > It would be nice if we could do the same thing to a Proc
> that
> > these methods can do internally
>
> ... would dynamic variables be enough? Christian Neukirchen
> has a nifty
> implementation of them on his blog.
From what I saw, this didn't seem much different than another
space for global variables. The main ability I was wanting was
to be able to replace local variables with their current value
in a proc. I think this would make the ugly *eval(string)
methods rarely needed. I just looked through the stdlib and
found almost every occurence of *eval(string) and found almost
every one looks kind of like this:
name = ...
var = ...
eval("def #{name} .... #{var} .... end")
This would work:
name = ...
var = ...
define_method(name.to_sym,proc{.... var ....}.unbind)
assuming that Proc#unbind replaced "var" with its current
value.
A define_class_method method would also be useful. Otherwise
there would be no equivalent to the above when doing eval("def
self.#{name} .... end").
I see. Although I don't have a use case for this at hand and in fact
never missed that. But that might be just my personal experience.
Not really (at least to my eyes). Also, there are some issues:
- I don't know what nO_element_def does exactly, but it will have to be
rewritten to not create a string with ruby code
- Your version might be less efficient.
- There might be subtle differences because "element" is pulled into the
closure
- Also, unbind_locals will remove "element" from the procs bindings
>> A proc
>> typically needs some
>> of the variables bound. As for the rebindings, I would
>> prefer a general
>> mechanism to transfer state from one binding to another.
>> Then one could
>> implement all your rebind* methods in terms of that general
>> mechanism plus
>> do more. Alternatively one could think about conversion
>> methods Binding <->
>> Hash.
>
> Transferring locals might be pretty easy, but transferring the
> meaning of self would be more difficult, I think. At least
> without making a new Binding (and then you'd still need a way
> to rebind it to the original proc).
Why do you think that self is special? If there is a general mechanism to
transfer state (i.e. bindings) into a binding, any variable can be
rebound. I imagine something like
proc.binding.bind(:self => whatever, :foo => "bar")
eval("self", proc.binding) # -> whatever
eval("foo", proc.binding) # -> "bar"
<snip/>
> Interesting. I assumed that since
> class_eval/instance_eval/module_eval all returned the same
> "self" that they did the same thing. The only difference I see
> is in "def <method> ...". With class_eval, it defines instance
> methods and with instance_eval, it defines class methods.
> That's kind of strange. Some kind of magic is going on here
> other than the changing of self.
Definitely.
> I was hoping that instance_eval could be used to define class
> methods using #define_method, but #define_method does the same
> with both - defines instance methods. Anybody know of an
> equivalent to #define_method for making class methods? I
> couldn't figure out any way to define a class method from a
> proc - just out of curiosity.
Since a class method is just an instance method of the class:
>> class Foo;end
=> nil
>> class <<Foo
>> define_method(:bar) {"bar"}
>> end
=> #<Proc:0x10185860@(irb):7>
>>
?> Foo.bar
=> "bar"
>>
Thanks for the interesting exchange!
Kind regards
robert
Yep. I wasn't paying attention very well. Here is its
definition (this is from cgi.rb, BTW):
def nOE_element_def(element, append = nil)
s = <<-END
"<#{element.upcase}" + attributes.collect{|name, value|
next unless value
" " + CGI::escapeHTML(name) +
if true == value
""
else
'="' + CGI::escapeHTML(value) + '"'
end
}.to_s + ">"
END
s.sub!(/\Z/, " +") << append if append
s
end
def nO_element_def(element)
nOE_element_def(element, <<-END)
if block_given?
yield.to_s + "</#{element.upcase}>"
else
""
end
END
end
Here would be the evaluating (instead of generating) version:
def nOE_element_def(element,attributes)
"<#{element.upcase}" + attributes.collect{|name, value|
next unless value
" " + CGI::escapeHTML(name) +
if true == value
""
else
'="' + CGI::escapeHTML(value) + '"'
end
}.to_s + ">"
end
def nO_element_def(element,attributes)
nOE_element_def(element,attributes) +
if block_given?
yield.to_s + "<#{element.upcase}>"
else
""
end
end
> - Your version might be less efficient.
If you flatten the hierarchy, you should be able to get the
same efficiency:
for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
LI OPTION tr th td ]
define_method(element.downcase.to_sym ,
proc { |attributes={}|
"<#{element.upcase}" + attributes.collect{|name, value|
next unless value
" " + CGI::escapeHTML(name) +
if true == value
""
else
'="' + CGI::escapeHTML(value) + '"'
end
}.to_s + ">" +
if block_given?
yield.to_s + "<#{element.upcase}>"
else
""
end
}.unbind_locals # replace element with constant
)
end
> - There might be subtle differences because "element" is
> pulled into the
> closure
>
> - Also, unbind_locals will remove "element" from the procs
> bindings
I'm assuming that unbind_locals will simply replace any local
variables (external to the proc) with what their current value
is: element will become "HTML", "HEAD", "BODY", etc.
I was assuming that with local variables, you just be moving
the value from one binding to another - not aliasing. The
problem is that you can't assign to "self". If you really
could do the above, then this:
binding.bind(:self => whatever)
would be equivalent to:
self = whatever
I don't that would be a trivial thing to implement. But, if
this "bind" created a new binding (i.e. non-destructive instead
of destructive), it would seem more feasible:
whateverBinding = binding.bind(:self => whatever)
whateverBinding.self.object_id==whatever.object_id
But then you are back to where you started - you still have a
bind the proc to a different binding (probably returning a new
proc).
> > Anybody know of an
> > equivalent to #define_method for making class methods? I
> > couldn't figure out any way to define a class method from a
> > proc - just out of curiosity.
>
> Since a class method is just an instance method of the class:
>
> >> class Foo;end
> => nil
> >> class <<Foo
> >> define_method(:bar) {"bar"}
> >> end
Thanks! That works, but I wanted the proc to have visibility
to the local variables. I think this would be more useful:
class Foo;end
(class<<Foo;self;end).send(:define_method,:bar) {"bar"}
> Thanks for the interesting exchange!
and thanks for your ideas.
.. back to my original topic - making a duck. For my stuff, I
think I've decided to have 2 ways of doing it:
# make a duck using methods from obj
myDuck = obj.duck(newSym, oldSym, ...)
# make a duck using arbitrary procs
myDuck = duck(methSym => methProc, ...)
One of the applications I'm looking at now is for a method that
looks like this:
Cursor#scan(value)
where value is String/Array like. All it needs is to respond
to #[int] which should return an object that responds to #==.
Although this #scan may look like it just matches to a verbatim
String/Array, you could also do something like this to match to
some digits:
# make == look like ===
digit = (?0..?9).duck(:==,:===)
# match to a string of 4 digits
# Proc responds to [] like a String/Array
cursor.scan(proc{|i|(i<4)? digit : nil})
Do people do things like this with duck-typing? Or are most
just all talk. Doing something like the above is where I see
the power.
__________________________________
Discover Yahoo!
Use Yahoo! to plan a weekend, have fun online and more. Check it out!
http://discover.yahoo.com/
At Thu, 9 Jun 2005 01:30:53 +0900,
Eric Mahurin wrote in [ruby-talk:144892]:
> # make == look like ===
> digit = (?0..?9).duck(:==,:===)
> # match to a string of 4 digits
> # Proc responds to [] like a String/Array
> cursor.scan(proc{|i|(i<4)? digit : nil})
It would be called as `alias', I guess.
--
Nobu Nakada
I don't care too much what the method names are. Below is the
implementation I was thinking. This gives you 3 ways to make a
"duck" (a minimal object for a duck-typed argument of a
method):
digit = (?0..?9).duck(:==,:include?,:to_s,:inspect)
alpha = Object.duck(size: proc{26}, :== =>
(?a..?z).method(:===) )
test = Object.duck(:hi) {puts "hello world!"}
Any chance of getting something like this in the standard lib?
Your "Behavior" implementation is fine too.
class Object
def duck(*new_old)
obj = Object.new
klass = (class<<obj;self;end)
until new_old.empty?
new,old = new_old.slice!(0,2)
klass.send(:define_method,new,&self.method(old))
end
obj
end
def self.duck(methods,&block)
obj = self.new
klass = (class<<obj;self;end)
if block
klass.send(:define_method,methods,&block)
else
methods.each { |name,proc|
klass.send(:define_method,name,&proc)
}
end
obj
end
end