[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Dynamic define_method on class creation per module namespace

T. Onoma

11/14/2004 7:23:00 AM

Here's a wee challenge for Rubyists at large. Consider:

module M

class A
def initialize ; puts "A" ; end
end

def a
A.new
end

class B
def initialize ; puts "B" ; end
end

def b
B.new
end

# etc

end

I would like to create a mixin of some sort that automatically creates the
module methods as needed. So,

module M

include ClassMethods

class A
def initialize ; puts "A" ; end
end

class B
def initialize ; puts "B" ; end
end

# etc

end

would give same effect as above. Possible?

Thanks,
T.


13 Answers

T. Onoma

11/14/2004 7:31:00 AM

0

Sorry, slight correction. I intended those to be module methods (albeit it
probably doesn't matter much either way) So the example should be:

module M

class A
def initialize ; puts "A" ; end
end

def self.a
A.new
end

class B
def initialize ; puts "B" ; end
end

def self.b
B.new
end

# etc

end

Thanks,
T.


nobu.nokada

11/14/2004 7:54:00 AM

0

Hi,

At Sun, 14 Nov 2004 16:22:41 +0900,
trans. (T. Onoma) wrote in [ruby-talk:120248]:
> I would like to create a mixin of some sort that automatically creates the
> module methods as needed. So,

One method is to use method_missing.

module ClassMethods
def method_missing(id, *args, &block)
if /\A[a-z][A-Za-z_0-9]*\z/ =~ name = id.to_s
classes = []
constants.each do |n|
if name.casecmp(n).zero? and Class === (c = const_get(n))
classes << c
end
end
if classes.size == 1
return classes.first.new(*args, &block)
end
end
super
end
end

--
Nobu Nakada


Christoph R.

11/14/2004 11:37:00 AM

0

trans. (T. Onoma) schrieb:

>Sorry, slight correction. I intended those to be module methods (albeit it
>probably doesn't matter much either way) So the example should be:
>
>
I don't see how you could cleanly implement this (disregarding
Nobu's missing method magic) with out a const_addded hook.
See [ruby-talk:44258]


/Christoph



T. Onoma

11/14/2004 8:46:00 PM

0

On Sunday 14 November 2004 02:54 am, nobu.nokada@softhome.net wrote:
| One method is to use method_missing.
|
| module ClassMethods
| def method_missing(id, *args, &block)
| if /\A[a-z][A-Za-z_0-9]*\z/ =~ name = id.to_s
| classes = []
| constants.each do |n|
| if name.casecmp(n).zero? and Class === (c = const_get(n))
| classes << c
| end
| end
| if classes.size == 1
| return classes.first.new(*args, &block)
| end
| end
| super
| end
| end

I don't like using missing method usually, but I guess that's the only way to
currently do it.

Thanks,
T


Its Me

11/14/2004 9:06:00 PM

0


"trans. (T. Onoma)" <transami@runbox.com> wrote
> module M
>
> include ClassMethods
>
> class A
> def initialize ; puts "A" ; end
> end
>
> class B
> def initialize ; puts "B" ; end
> end
>
> # etc
>
> end

I think you can hook into Class#inherited at the Object level, thusly:

class Object
def self.inherited(child)
for m in all_modules_that_have_included_ClassMethods
if m.const_defined(child.name) && m.const_get(child.name)==child
generated = "
def #{child.name.downcase}(*args, &b)
#{child.name).new(*args, &b)
end"
m.module_eval generated
end
end
end
end

I'm curious what you are trying to do with this. I am doing something
similar to allow easy creation of tree structures, but I need instance (not
module) methods to grab hold of the constructed objects, plus some 'typed'
attribute macros to know what to instantiate.

car 'A' {
engine '8-cylinder' {
valve { ...}
valve { ...}
valve { ...}
}
}

I plan to allow some conveinent cross-tree references as well.


T. Onoma

11/14/2004 9:18:00 PM

0

On Sunday 14 November 2004 06:36 am, Christoph wrote:
| trans. (T. Onoma) schrieb:
| >Sorry, slight correction. I intended those to be module methods (albeit it
| >probably doesn't matter much either way) So the example should be:
|
| I don't see how you could cleanly implement this (disregarding
| Nobu's missing method magic) with out a const_addded hook.
| See [ruby-talk:44258]

Ah yes, that would be perfect. One day, one day....

Thanks,
T.

P.S. I recall long ago someone mentioned a real quick way to access ruby-talk
messages (like the above ruby-talk:44258). Anyone know how?


T. Onoma

11/14/2004 9:37:00 PM

0

On Sunday 14 November 2004 04:08 pm, itsme213 wrote:
| I think you can hook into Class#inherited at the Object level, thusly:
|
| class Object
| def self.inherited(child)
| for m in all_modules_that_have_included_ClassMethods
| if m.const_defined(child.name) &&
| m.const_get(child.name)==child generated = "
| def #{child.name.downcase}(*args, &b)
| #{child.name).new(*args, &b)
| end"
| m.module_eval generated
| end
| end
| end
| end

Thanks, I may be able to work with that. If I can just get
all_modules_that_have_included_ClassMethods :)

| I'm curious what you are trying to do with this. I am doing something
| similar to allow easy creation of tree structures, but I need instance (not
| module) methods to grab hold of the constructed objects, plus some 'typed'
| attribute macros to know what to instantiate.
|
| car 'A' {
| engine '8-cylinder' {
| valve { ...}
| valve { ...}
| valve { ...}
| }
| }
|
| I plan to allow some conveinent cross-tree references as well.

I am doing something very similar with a markup parser (made-up example):

tr = token_registry {
block :literal, '"""', '"""'
line :strong, '*', '*'
line :italic, '_', '_'
}

One of things that made the methods even better was not having to worry about
the namespace for the classes themselves --in other words, the classes Block
and Line themselves are, in a way, private.

T.


Joel VanderWerf

11/14/2004 10:17:00 PM

0

trans. (T. Onoma) wrote:
> P.S. I recall long ago someone mentioned a real quick way to access ruby-talk
> messages (like the above ruby-talk:44258). Anyone know how?

This used to work, IIRC, but doesn't now:

http://ruby-talk...

and going to http://ruby... gives the message:

The Ruby-talk.org domain is temporarily under maintenance. Please use
http://blade.nagaokaut.ac.jp/ruby/ruby-talk/i.... Thanks, Ruby
Central, Inc.

Anyway, it possible to configure many browsers to recognize

ruby-talk:12345

as a shortcut in the url bar for the url

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-...

In konqueror, this feature is called Web Shortcuts.

OT: ironically message 12345 is from matz, reluctantly agreeing to
remove the [ruby-talk:12345] tag that was automatically added to
beginning of the subject line on messages from the ML. If you remember
*that* discussion, you're getting to be an old timer here. (And if you
were on the list, but don't remember the discussion you are really an
old timer ;)


Its Me

11/14/2004 11:41:00 PM

0

"trans. (T. Onoma)" <transami@runbox.com> wrote

> Thanks, I may be able to work with that. If I can just get
> all_modules_that_have_included_ClassMethods :)

Worst case:
ObjectSpace.each_object(Module) { |m|
m.included_modules.include?(ClassMethods) }

Better: hook into ClassMethods#included(module) to mark all modules that
include ClassMethods.


nobu.nokada

11/15/2004 12:22:00 AM

0

Hi,

At Mon, 15 Nov 2004 06:37:11 +0900,
trans. (T. Onoma) wrote in [ruby-talk:120320]:
> I am doing something very similar with a markup parser (made-up example):
>
> tr = token_registry {
> block :literal, '"""', '"""'
> line :strong, '*', '*'
> line :italic, '_', '_'
> }
>
> One of things that made the methods even better was not having to worry about
> the namespace for the classes themselves --in other words, the classes Block
> and Line themselves are, in a way, private.

What about this way? Though I don't think the name
class_method is proper...


module ClassMethods
def class_method(name, superclass = ::Object, method = name.to_s.downcase,
&definition)
c = Class.new(superclass, &definition)
define_method(method, &c.method(:new))
module_function method
const_set(name, c)
end
end

if $0 == __FILE__

module M
extend ClassMethods

class_method(:A) do
def initialize ; puts "A" ; end
end

class_method(:B) do
def initialize ; puts "B" ; end
end
end

p M.a, M.b
end


--
Nobu Nakada