Hi,
In message "Re: preventing Object#send from dispatching to a global
method?"
on Sun, 29 May 2005 00:42:46 +0900, Francis Hwang
|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.
Part of the problem is solved, part is not.
Part 1, the solved part:
Children of Lafcadio:
omainObject. 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:
omainObject
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:
omainObject
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/