Dynamic define_method on class creation per module namespace

T

trans. (T. Onoma)

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.
 
T

trans. (T. Onoma)

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.
 
N

nobu.nokada

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
 
C

Christoph

trans. (T. Onoma) said:
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

trans. (T. Onoma)

On Sunday 14 November 2004 02:54 am, (e-mail address removed) 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
 
T

trans. (T. Onoma)

| >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

trans. (T. Onoma)

|
| 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.
 
J

Joel VanderWerf

trans. (T. Onoma) said:
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.org/12345

and going to http://ruby-talk.org/ gives the message:

The Ruby-talk.org domain is temporarily under maintenance. Please use
http://blade.nagaokaut.ac.jp/ruby/ruby-talk/index.shtml. 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-talk/12345

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 ;)
 
N

nobu.nokada

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
 
T

trans. (T. Onoma)

On Sunday 14 November 2004 07:22 pm, (e-mail address removed) wrote:
| 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

Right, that's one way to do it. Although that's manualizing things to the
point that I think might be just as easy to go ahead and write out each
method.

Funny thing though, this really gives one pause in consideration of 'class'
possibly being an actual method that one could tap into.

T.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,427
Latest member
HildredDic

Latest Threads

Top