cv1
Abril 29, 2008, 9:57am
#1
Tou tentando criar umas classes programaticamente pra embonitar uma DSL que eu quero fazer:
[code]module Products
end
def product(name)
Products.const_set name, Class.new do |c|
def to_s
"I am a #{name}"
end
end
end
product :Banana
puts Products::Banana.to_s, Products::Banana.new.to_s
[/code]
Isso imprime:
Products::Banana
#<Products::Banana:0x2815f4>
Quando na verdade eu esperava:
Products::Banana
I am a Banana
Onde eu vacilei?
Exatamente do jeito que você quer não vai aparecer não, tem que ter o Products:: na frente. Esse chega perto:
[code=ruby]module Products
end
def product(name)
Products.const_set name, Class.new
end
product :Banana
module DynamicModule
def to_s
"I am a #{self.class.name }"
end
end
Products::Banana.send( :include, DynamicModule )
puts Products::Banana.to_s, Products::Banana.new.to_s[/code]
Saída:
Products::Banana
I am a Products::Banana
Se você cortar os :: vai chegar no que você quer.
O Jay Fields tem mais a falar sobre definir métodos em instâncias -> http://blog.jayfields.com/2008/02/ruby-dynamically-define-method.html
Outra opção:
[code=ruby]class String
def constantize
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
end
Object.module_eval("::#{self}", __FILE__, __LINE__)
end
end
module Products
end
def product(name)
eval( “class #{name} ; end” )
new_class = name.to_s.constantize
Products.const_set name, new_class
end
product :Banana
module DynamicModule
def to_s
"I am a #{self.class.name }"
end
end
Products::Banana.send( :include, DynamicModule )
puts Products::Banana.to_s, Products::Banana.new.to_s[/code]
Imprime:
Banana
I am a Banana
Realmente ou é um ou é outro, não tem como ser os dois
cv1
Abril 29, 2008, 11:42am
#4
Valeu, Mauricio!
Achei outro jeito, tambem:
[code]def product(name, pricing_proc)
c = Class.new do
attr_reader :quantity
def initialize(quantity = 1)
@quantity = quantity
end
end
c.class_eval do
define_method :price, pricing_proc
define_method :to_s do
"I am a #{name}"
end
end
Products.const_set name, c
end
include Products
product :Banana
puts Banana.to_s, Banana.new.to_s[/code]
Ainda sobre o WTF, o problema não é que naquela primeira definição o método está sendo definido na instância de Class não?
cv1
Abril 30, 2008, 2:26pm
#6
Nao… na verdade, a versao inicial tem dois problemas:
o bloco tava sendo passado pro const_set ao inves do Class.new (o que eh um problema bem sutil, foi foda diagnosticar)
codigo dentro de def, class e module nao pode usar variaveis que estao fora dele, caso a coisa esteja acontecendo num bloco. O Ola me explicou, e eu juro que entendi na hora, mas nao consigo explicar direito (e tambem nao sei nem se eu entendi tao bem assim). Se alguem souber de um be-a-bá sobre isso, ia ser bem-vindo
Cara, quanto ao item “1)” do que você falou, juro que tinha pensado nisso assim que li a thread mas como tava sem tempo não fuxiquei pra ter certeza. Realmente é ruim de diagnosticar pois a tendência é achar que está sendo passado para o Class.new mesmo.
Quanto ao item “2)” eu não tenho a mínima ideia