hallo,
eine kleine herausforderung -
nehmen wir an, ich möchte während der laufzeit einer Applikation ein
Module im Objectspace verankern:
bspw. mit:
class Foobar
end
my_mod = ‘Foo’
eval(“module #{my_mod}; end”)
if defined?(Foo) # returns ‘constant’
dann möchte ich dem module etwas funktion beibringen:
eval(my_mod).send(:define_method, ‘bar’) { puts "static function ‘bar’
called "}
und letztlich der class Foobar ein paar statische methoden mittels
my_mod beibringen:
Foobar.extend(eval(my_mod))
end
wie aber parametrisiere ich die zu definierende funktion?
also im sinne von :define_method, ‘bar(*args)’ …
gruesse
rene
On Thu, 4 Sep 2008 01:46:41 +0200
Rene P. [email protected] wrote:
hallo,
eine kleine herausforderung -
eine kleine loesung:
meth = %q{def bar(*args) puts “static function bar with args:
#{args.inspect}” end}
eval(my_mod).module_eval(meth)
comments?
On Thursday 04 September 2008, Rene P. wrote:
comments?
Ja: Bist du sicher, dass das sinnvoll ist, was du da machst? Du könntest
erklären, was überhaupt das Ziel ist, wahrscheinlich lässt sich dann
ein eleganterer Weg finden, als der über eval-Tricksereien.
Michael
Hallo,
Mal die Frage, was du damit machen willst beiseite gelassen: Das ganze
geht auch recht elegant ohne eval(String).
Ich versuche mal das gleiche Ergebnis zu erzielen, nur eben so, wie
ich es geschrieben hätte.
class Foobar
end
my_mod = Object.const_set(:Foo, Module.new)
if defined?(Foo) # returns ‘constant’
my_mod.module_eval do
define_method :bar do
puts “static function ‘bar’ called”
end
end
Foobar.extend(my_mod)
end
wie aber parametrisiere ich die zu definierende funktion?
also im sinne von :define_method, ‘bar(*args)’ …
Die Antwort ist verhältnismäßig einfach: Gibt dem Block, den du an
define_method übergibst einfach Parameter, also z.B.
my_mod.module_eval do
define_method :bar do |*args|
puts "static function 'bar' called with '#{args.join(', ')}'"
end
end
comments?
Das eval von Strings hat immer einen faden Beigeschmack, das sich zu
leicht Userinput in diesen Strings wiederfindet. Das kann leicht
eskalieren. Außerdem funktionieren Code-Analyse und
Syntax-Highlighting in solchen Blöcken nicht.
Es gibt aber auch Fälle in denen man nicht drumherum kommt. In 1.8
z.B. können Blöcke keine anderen Blöcke als Parameter annehmen. Damit
könnte man also keine dynamischen Methoden definieren, die Blöcke
erwarten. Hier kommt man um eval(String) oder module_eval(String)
nicht herum.
Auch die Ausführungszeit von den String-eval-definierten Methoden kann
kürzer sein, als die der dynamisch definierten, da sie keinen Scope
mehr mit sich rumschleppen müssen.
Aber das ist ein weites Feld.
Viele
Grüße
Gregor
On Thu, 4 Sep 2008 10:30:51 +0200
“Gregor Schmidt” [email protected] wrote:
Hallo,
Mal die Frage, was du damit machen willst beiseite gelassen: Das ganze
geht auch recht elegant ohne eval(String).
hallo gregor,
das hoffte ich. dein lösungsansatz sieht trez chic aus.
und damit sich michael nicht länger fragt wozu das gut sein soll:
ich spiele gerade mit einer verteilten answendung, in der es ein
rails-basiertes frontend geben soll, welches mittels json-rpc eine
middleware kontaktet. von dort wird logik, bzw. funktion exportiert, die
ich in meine unbedarften model-classes injektiere.
der ansatz dabei ist die zusätzlichen (remote) funktionen beim
hochfahren der anwendung bereitzustellen.
vorhandene ruby-basierte json-rpc client-implementierungen gehen den
m.e. uneleganten weg, jeden methodenaufruf durch ‘method-missing’ zu
schleusen, um dort dann einen rpc-aufruf abzusetzen, der nach rfc im
negativen falle ein 404 generiert, bzw. zu generieren hat…
und: natürlich gibt es auch die möglichkeit, die schnittstelle im
frontend fest zu verdrahten, bzw. die (remote)funktionen im model
auszuformulieren, das macht das ganze lesbarer - aber es ist weniger
lustig.
viele grüsse
rene
puts "static function 'bar' called"
end
end
Foobar.extend(my_mod)
end