def something; end
class SomeClass
def method_missing( sym, *args ) .... do magic; end
end
SomeClass.new.something # I'd like this to go to
SomeClass#method_missing, not Kernel#something
I can manage this other ways, but I'd love to use something like send,
if possible.
Francis Hwang
http://fhwang.net/
Am Sonntag, 29. Mai 2005, 00:42:46 +0900 schrieb Francis Hwang:
> Is there a way to prevent Object#send from dispatching to a global
> method? By which I mean:
>
> def something; end
>
> class SomeClass
> def method_missing( sym, *args ) .... do magic; end
> end
>
> SomeClass.new.something # I'd like this to go to
> SomeClass#method_missing, not Kernel#something
class SomeClass
undef something
end
Probably you thought of no specific method, so one should
remove them all. This causes an error:
class SomeClass
Kernel.methods.each { |x| undef_method x.to_sym }
end
Is there a way to un-include?
Bertram
--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de
"Francis Hwang" <se...@fhwang.net> wrote in message
Francis Hwang
http://fhwang.net/
> Is there a way to prevent Object#send from dispatching to a global
> method? By which I mean:
>
You could look at how Builder::BlankSlate handles it. It uses method
defined hooks to undefine any methods added to any ancestors. You
can find BlankSlate in the builder gem.
For example
traken$ irb --simple-prompt
>> require 'builder/blankslate'
=> false
>> class Empty < Builder::BlankSlate
>> def inspect
>> "<empty>"
>> end
>> def method_missing(sym, *args)
>> puts "Calling #{sym}(#{args.join(',')})"
>> end
>> end
=> nil
>> e = Empty.new
=> <empty>
>> e.hi
Calling hi()
=> nil
>> def hi() "HI" end
=> nil
>> e.hi
Calling hi()
=> nil
def fname; "here's an unfortunate coincidence"; end
class User < Lafcadio::DomainObject
text 'fname'
text 'lname'
end
I wanted to trigger some methods to undefine instance methods of
'fname' in User, but I can't do that with Class.inherited -- because at
the time that the User class is being defined, I don't know that I'm
looking for global methods named 'fname' and 'lname'.
It feels like, from perusing the archives, there is currently no way to
be notified when a class definition is finished. Correct?
Francis Hwang
http://fhwang.net/
I don't know of any ... however, would this help?
class User < Lafcadio::DomainObject
fields do
text 'fname'
text 'lname'
end
end
You can have fields perform actions at the end of the block. I don't know if
this is good enough, or if you really need it at the end of the class def.
--
-- Jim Weirich j...@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
Not that I could find, and I've mentioned this as an annoying limitation
of Ruby myself.
--
Glenn Parker | glenn.parker-AT-comcast.net | <http://www.tetrafoil.com/>
> On Saturday 28 May 2005 11:05 pm, Francis Hwang wrote:
>> I wanted to trigger some methods to undefine instance methods of
>> 'fname' in User, but I can't do that with Class.inherited -- because
>> at
>> the time that the User class is being defined, I don't know that I'm
>> looking for global methods named 'fname' and 'lname'.
>>
>> It feels like, from perusing the archives, there is currently no way
>> to
>> be notified when a class definition is finished. Correct?
>
> I don't know of any ... however, would this help?
>
> class User < Lafcadio::DomainObject
> fields do
> text 'fname'
> text 'lname'
> end
> end
>
> You can have fields perform actions at the end of the block. I don't
> know if
> this is good enough, or if you really need it at the end of the class
> def.
Thanks for the suggestion, but that's probably too cumbersome. For the
time being I suppose I'll just have to warn users of the lib not to
have global methods named the same as the auto-methods. It's probably
not a common problem, anyway.
Francis Hwang
http://fhwang.net/
>
> Thanks for the suggestion, but that's probably too cumbersome. For the
> time being I suppose I'll just have to warn users of the lib not to
> have global methods named the same as the auto-methods. It's probably
> not a common problem, anyway.
>
> Francis Hwang
> http://fhwang.net/
>
Perhaps Jamis Buck's BlankSlate might be what you're looking for?
See here: http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc
Feel free to echo this to the list if it's the correct answer.
IMPOSSIBLE, adj:
(1) I wouldn't like it and when it happens I won't approve;
(2) I can't be bothered;
(3) God can't be bothered.
- The Hipcrime Vocab by Chad C. Mulligan
> Francis Hwang wrote:
>
>>
>> Thanks for the suggestion, but that's probably too cumbersome. For
>> the time being I suppose I'll just have to warn users of the lib not
>> to have global methods named the same as the auto-methods. It's
>> probably not a common problem, anyway.
>>
>> Francis Hwang
>> http://fhwang.net/
>>
>
> Perhaps Jamis Buck's BlankSlate might be what you're looking for?
>
> See here: http://onestepback.org/index.cgi/Tech/Ruby/BlankSlate.rdoc
>
> Feel free to echo this to the list if it's the correct answer.
Don't you mean Jim's BlankSlate? Seeing as http://onestepback.org is
Jim's blog and all.
Anyway, as I said before, that doesn't work in my odd case because
Lafcadio uses class methods within the class definition, and my code
would need to know that stuff, but it's invoked after the class
definition begins, so it wouldn't work in this case.
Francis Hwang
http://fhwang.net/
> Francis Hwang wrote:
>> It feels like, from perusing the archives, there is currently no way
>> to be notified when a class definition is finished. Correct?
>
> Not that I could find, and I've mentioned this as an annoying
> limitation of Ruby myself.
Should I submit an RCR? Haven't done one before. Would it be called?
Class#inherited_finished ?
Francis Hwang
http://fhwang.net/
>
> Don't you mean Jim's BlankSlate? Seeing as http://onestepback.org is
> Jim's blog and all.
>
*cough* That would make sense. My apologies to the related parties...
I would say it's worth an RCR, but a class definition is never really
finished, so a different name is needed. Maybe Module#end_update would
make more sense. This would be a callback that is invoked when the
interpreter gets to the final "end" of a Module/Class block. Extra
points if it passed a list of constants that were added, removed, or
redefined.
Can you accomplish your original goal with Module#method_added? If
Lafcadio::DomainObject#text defines new methods, that seems like a
sufficiently solid hook.
In message "Re: preventing Object#send from dispatching to a global method?"
on Sun, 29 May 2005 00:42:46 +0900, Francis Hwang <se...@fhwang.net> writes:
|Is there a way to prevent Object#send from dispatching to a global
|method?
How about undef'ing global methods from the class? See delegate.rb in
the distribution.
matz.
On Jun 2, 2005, at 8:57 AM, Glenn Parker wrote:
> Francis Hwang wrote:
>> On May 30, 2005, at 9:02 PM, Glenn Parker wrote:
>>> Francis Hwang wrote:
>>>
>>>> It feels like, from perusing the archives, there is currently no
>>>> way to be notified when a class definition is finished. Correct?
>>>
>>> Not that I could find, and I've mentioned this as an annoying
>>> limitation of Ruby myself.
>> Should I submit an RCR? Haven't done one before. Would it be called?
>> Class#inherited_finished ?
>
> I would say it's worth an RCR, but a class definition is never really
> finished, so a different name is needed. Maybe Module#end_update
> would make more sense. This would be a callback that is invoked when
> the interpreter gets to the final "end" of a Module/Class block.
> Extra points if it passed a list of constants that were added,
> removed, or redefined.
>
> Can you accomplish your original goal with Module#method_added? If
> Lafcadio::DomainObject#text defines new methods, that seems like a
> sufficiently solid hook.
>
I can't; DomainObject#text doesn't actually define a new method, it
just adds to a class-level array of fields that are accessed in
method_missing. I actually solved part of the problem by using
undef_method, as Matz suggested. Another part of the problem is still
unsolved, so I'll be responding to Matz' email in a few seconds,
explaining it in more detail ...
Francis Hwang
http://fhwang.net/
Part of the problem is solved, part is not.
Part 1, the solved part:
Children of Lafcadio::DomainObject. This is normally subclassed by
somebody using the library, and then fields are set using one-line
directives:
def name; "global name method"; end
class Client < Lafcadio::DomainObject
text :name
integer :standard_rate
datetime :created
end
c = Client.new( 'name' => 'My first client', 'standard_rate' => 100,
'created' => Time.now )
puts c.name # was returning 'global name method', I fixed it to return
'My first client'
I fixed this by finding the spot in a class method where all the class
fields are being collated for the first time:
class Lafcadio::DomainObject
def self.class_fields #:nodoc:
class_fields = @@class_fields[self]
unless class_fields
@@class_fields[self] = self.get_class_fields
class_fields = @@class_fields[self]
class_fields.each do |class_field|
begin
undef_method class_field.name.to_sym
rescue NameError
# not defined globally or in an included Module, skip it
end
end
end
class_fields
end
end
that solved it, though I'm not crazy about that begin..rescue..end
block, I couldn't think of a less cumbersome way to do it.
Part 2, the much worse, as-of-yet-unsolved part:
Lafcadio has a query inference facility, inspired mostly by Criteria,
that is useful for expressing queries in ways that can be either turned
into SQL or run against an in-memory store. Here's an example:
one_year = 60 * 60 * 24 * 365
fave_clients = object_store.get_clients { |cli|
Query.And( cli.standard_rate.gte( 100 ), cli.created.gte( Time.now -
one_year ) )
}
What actually happens is, inside that block, Lafcadio pushes through an
object of class DomainObjectImpostor, which uses method_missing to
create query clauses when it receives calls like #standard_rate and
#created. (It actually spits out ObjectFieldImpostors, which then
listen to methods like #gte.)
But here's the problem:
def name; "global name method"; end
first_client = object_store.get_clients { |cli|
cli.send( :name ).equals( 'My first client' )
}[0]
This won't work, because #name will get dispatched to the global
method. And I can't use undef_method in this case, because I shouldn't
undef the global #name method to _every_ instance of
DomainObjectImpostor, because only some DomainObjectImpostors will be
pretending to be Clients. Others will be pretending to be Users,
Invoices, Projects, etc., etc., and they should be able to dispatch
calls to the global #name method.
Is there a way to undef a method for just one instance? Or maybe I
should consider instantiating new classes for every "instance", in the
same way that you can call DelegateClass( some_class ) when using
delegate.rb?
Or maybe I'm just making the whole thing overly complicated and there's
some simple answer right in front of my nose ...
Francis Hwang
http://fhwang.net/