Metaprogramming

Volevo approfondire qualche nozione base di ruby prima di iniziare un
nuovo progetto con tema DSL. Ruby è sicuramente di grande aiuto ma
alcune cose non me le spiego o devo capirle meglio:

Questione 1.

Mi chiedevo il motivo per cui instance_eval e class_eval agiscono al
contrario:

class Test; end
actions = %w(say think make)
actions.each do |action|
Test.instance_eval “def #{action}; "What do i have to #{action}?";
end”
end
Test.say

viceversa class_eval ha effetto solo sull’istanza ma li confondo sempre

Spesso la sintassi ruby offre diversi modi per fare la stessa cosa ma a
volte mi chiedo se ci possono essere anche piccole differenze:

Questione 2.

Differenza tra send e send
A parte il warning del secondo mi sembrano uguali

class Test; end
actions = %w(say think make send send)
actions.each do |action|
Test.instance_eval “def #{action}; "What do i have to #{action}?";
end”
end
(eval):1: warning: redefining `send’ may cause serious problems
=> [“say”, “think”, “make”, “send”, “send”]

irb(main):008:0> Test.singleton_methods
=> [:say, :think, :make, :send, :send]

Questione 3.

Mi chiedevo la differenza tra il definire i metodi nella metaclass o
intrinseci alla classe (self):

#metaclass
class Test
class << self
def name
“Ambrogio”
end
name
end
end
Test.class

#self
class Test
def self.name
“Ambrogio”
end
name
end
Test.class

Questione 4.

Differenza tra yield e &block.
Questa è più sui concetti base che sulla metaprogrammazione ma sono
curioso di sapere qualche opinione.

#yield
class A
def go(*attrs)
p “Before block”
attrs.each do |attr|
p yield(attr)
end if block_given?
p “After block”
end
end
a=A.new
a.go “1”,“2” do |i|
“ciao#{i}”
end

#&block
class B
def go(*attrs, &block)
p “Before block”
attrs.each do |attr|
p block.call(attr)
end if block_given?
p “After block”
end
end
b=B.new
b.go “1”,“2” do |i|
“ciao#{i}”
end

#alternativa con accesso diretto
class C
attr_reader :attr
def initialize
@attr = “”
end
def go(*attrs, &block)
p “Before block”
attrs.each do |attr|
@attr = attr
p instance_eval(&block)
end if block_given?
p “After block”
C.name
end
end
c=C.new
c.go “1”,“2” do
“ciao#{attr}”
end

On Mar 6, 2012, at 6:30 PM, Marco M. wrote:

Volevo approfondire qualche nozione base di ruby prima di iniziare un
nuovo progetto con tema DSL. Ruby sicuramente di grande aiuto ma
alcune cose non me le spiego o devo capirle meglio:

Questione 1.

Mi chiedevo il motivo per cui instance_eval e class_eval agiscono al
contrario:

Non agiscono al contrario, anche se in effetti il wording e’ francamente
molto discutibile.
instance_eval agisce nel contesto in cui Test e’ una istanza di Class,
mentre class_eval agisce nel contesto della classe - cioe’ come una
istanza.
Tricky a dir poco.

Questione 2.

Differenza tra send e send
A parte il warning del secondo mi sembrano uguali

AFAIK molte classi sovrascrivono send. Dove sovrascrivere e’ inteso come
overwrite. Sono in condizioni pietose, penso in inglese ma con un
inglese di merda, quindi magari sbaglio qualche termine in italiano.

Questione 3.

Mi chiedevo la differenza tra il definire i metodi nella metaclass o
intrinseci alla classe (self):

AFAIK nessuna, solo syntax sugar. Ma non sono stupito se qualcuno mi
corregge.

Questione 4.

Differenza tra yield e &block.
Questa pi sui concetti base che sulla metaprogrammazione ma sono
curioso di sapere qualche opinione.

Example 4 · GitHub

E’ tutto documentato qui:
http://innig.net/software/ruby/closures-in-ruby
&block lo puoi salvare in una variabile e ci sono differenze nell’error
handling piu’ che altro.

ngw

p.s. Ma com’e’ che comp.lang.ruby sembra semimorto?

On Mar 6, 2012, at 6:49 PM, Nicholas W. wrote:

Mi chiedevo il motivo per cui instance_eval e class_eval agiscono al
contrario:

Non agiscono al contrario, anche se in effetti il wording e’ francamente molto
discutibile.
instance_eval agisce nel contesto in cui Test e’ una istanza di Class, mentre
class_eval agisce nel contesto della classe - cioe’ come una istanza.
Tricky a dir poco.

instance_eval modifica il self mentre class_eval modifica sia il self
sia il current_class. Usando class_eval puoi per esempio riaprire una
class basandoti su una variabile che rappresenta la classe.
Es:

module MyModule

def self.included base
base.class_eval do

qui stai riaprendo la classe base

    # class_eval modifica il current_class mentre il blocco viene 

eseguito
end
end

end

Mi chiedevo la differenza tra il definire i metodi nella metaclass o
Example 4 · GitHub
http://lists.ruby-it.org/mailman/listinfo/ml
Andrea C.
[email protected]

Grazie Andrea per lo spunto, guarda questi esempi:

class Test; end
Test.class_eval {def say; “hello”; end}
Test.say
#NoMethodError: undefined method `say’ for Test:Class
Test.new.say
#=> “hello”

class Test; end
Test.instance_eval {def say; “hello”; end}
Test.say
#=> “hello”
Test.new.say
#NoMethodError: undefined method `say’ for #Test:0x2cafb88

Questo il motivo per cui genera un pò di confusione.

Ho elaborato il tuo esempio:

class Test
def included
self.class.class_eval do
# riapro la classe base
yield
end
end
end
Test.class_eval {def say; “hello”; end}
Test.say
#NoMethodError: undefined method `say’ for Test:Class

test=Test.new
test.say
#=> “hello”

#Aggiungo alla classe base col tuo spunto
test.included {def say; “hello”; end}
Test.say
#=> “hello”
Test.new.say
#=> “hello”

Così ci siamo ma è stato necessario il metodo included

On Mar 7, 2012, at 12:59 PM, Marco M. wrote:

Grazie Andrea per lo spunto, guarda questi esempi:

class Test; end
Test.class_eval {def say; “hello”; end}
Test.say
#NoMethodError: undefined method `say’ for Test:Class
Test.new.say
#=> “hello”

Qui aggiungi un metodo di instanza on di classe.
Se vuoi aggiungere un metodo di istanza lo devi aggiungere alla classe
quando viene riaperta e quindi al self.

class Test; end
Test.class_eval do
class << self
def say
“hi”
end
end
end
Test.say

Ho elaborato il tuo esempio:
Test.say
Test.new.say
#=> “hello”

Cos ci siamo ma stato necessario il metodo included


Posted via http://www.ruby-forum.com/.


Ml mailing list
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml

Andrea C.
[email protected]

Grazie Nicholas per l’intervento e per quel link che è finito nei
preferiti. Sono argomenti che purtroppo uso poco e dimentico in fretta.
Ad esempio questo è un appunto che ho scritto nel 2009:
http://marco.mastrodonato.info/2009/06/distruttori-di-classe-in-ruby.html

e neanche mi ricordavo di aver mai approfondito qualcosa di così
tecnico, in genere per lavoro riesco ad occuparmi solo della parte
funzionale.

Comunque ruby è fenomenale, con un pò di creatività non si hanno limiti