Thread View: pl.comp.lang.ruby
8 messages
8 total messages
Started by Jaroslaw Zabiello
Thu, 07 Sep 2006 10:43
Ruby i dekorator
Author: Jaroslaw Zabiello
Date: Thu, 07 Sep 2006 10:43
Date: Thu, 07 Sep 2006 10:43
6 lines
907 bytes
907 bytes
Jak w Ruby zaimplementować pythonowy dekorator? A może jest jakaś metoda która wyciąga całe ciało funkcji? Chcę coś dodać przed nim i po nim.. -- Jarosław Zabiełło http://blog.zabiello.com
Re: Ruby i dekorator
Author: Marcin Mielżyński
Date: Thu, 07 Sep 2006 11:42
Date: Thu, 07 Sep 2006 11:42
24 lines
1360 bytes
1360 bytes
Jaroslaw Zabiello wrote:
> Jak w Ruby zaimplementować pythonowy dekorator? A może jest jakaś metoda
> która wyciąga całe ciało funkcji? Chcę coś dodać przed nim i po nim..
>
można skorzystać np z method_added alias i define_method
domyślam się że chodzi o coś takiego w pythonie: ?
def around(fun):
def x(self):
print "pre"
fun(self)
print "post"
return x
class A:
@around
def m(self):
print "!"
A().m()
lopex
Re: Ruby i dekorator
Author: Jaroslaw Zabiello
Date: Thu, 07 Sep 2006 12:36
Date: Thu, 07 Sep 2006 12:36
36 lines
1886 bytes
1886 bytes
Dnia Thu, 07 Sep 2006 13:42:42 +0200, Marcin Mielżyński napisał(a): >> Jak w Ruby zaimplementować pythonowy dekorator? A może jest jakaś metoda >> która wyciąga całe ciało funkcji? Chcę coś dodać przed nim i po nim.. >> > > można skorzystać np z method_added alias i define_method method_added() wyłapuje fakt dodania metody, więc po co mi to? alias nie potrzebuję, bo chcę zachować tą samą nazwę. A define_method tworzy a nie odczytuje ciało metody. > domyślam się że chodzi o coś takiego w pythonie: ? > > def around(fun): > def x(self): > print "pre" > fun(self) > print "post" > return x > > class A: > @around > def m(self): > print "!" > > A().m() Tak. W RoR znalazlem blad i chcialem sobie poprawić (kurcze, ze dwa bite dni straciłem szukając błędu). (http://dev.rubyonrails.org/ticket/6073) Zanim jednak dodadza (o ile dodadza) to do kodu RoR, wole wykorzystac otwarte klasy i to sobie dodac w kontrolerze -- Jarosław Zabiełło http://blog.zabiello.com
Re: Ruby i dekorator
Author: Marcin Mielżyński
Date: Thu, 07 Sep 2006 12:59
Date: Thu, 07 Sep 2006 12:59
59 lines
2191 bytes
2191 bytes
Jaroslaw Zabiello wrote:
> Dnia Thu, 07 Sep 2006 13:42:42 +0200, Marcin Mielżyński napisał(a):
> method_added() wyłapuje fakt dodania metody, więc po co mi to? alias nie
> potrzebuję, bo chcę zachować tą samą nazwę. A define_method tworzy a nie
> odczytuje ciało metody.
method_added będzie bardzo przydatne dla zbliżenia do pythonowej wersji,
method_alias i define_method - koniecznie - no chyba chyba że przez
undef_method.
podstawy w bardzo prosty sposób można zrobić tak (dwie wersje):
class Class
def around meth,pre,post
alias_method :"old_#{meth}",meth.to_sym
define_method meth do
pre.call
send :"old_#{meth}"
post.call
end
end
def around2 meth
alias_method :"old_#{meth}",meth.to_sym
define_method meth do
yield method(:"old_#{meth}").to_proc
end
end
end
class A
def meth
p "meth"
end
def meth2
p "meth2"
end
end
A.around :meth, proc{p "pre"},proc{p "post"}
A.new.meth
A.around2 :meth2 do |m|
p "pre2"
m.call
p "post2"
end
A.new.meth2
łatwo przerobić na dużo wygodniejsze użycie...
lopex
Re: Ruby i dekorator
Author: Jaroslaw Zabiello
Date: Thu, 07 Sep 2006 16:35
Date: Thu, 07 Sep 2006 16:35
139 lines
4798 bytes
4798 bytes
Dnia Thu, 07 Sep 2006 14:59:22 +0200, Marcin Mielżyński napisał(a):
>> method_added() wyłapuje fakt dodania metody, więc po co mi to? alias nie
>> potrzebuję, bo chcę zachować tą samą nazwę. A define_method tworzy a nie
>> odczytuje ciało metody.
>
> method_added będzie bardzo przydatne dla zbliżenia do pythonowej wersji,
> method_alias i define_method - koniecznie - no chyba chyba że przez
> undef_method.
>
> podstawy w bardzo prosty sposób można zrobić tak (dwie wersje):
>
> class Class
>
> def around meth,pre,post
> alias_method :"old_#{meth}",meth.to_sym
> define_method meth do
> pre.call
> send :"old_#{meth}"
> post.call
> end
> end
>
> def around2 meth
> alias_method :"old_#{meth}",meth.to_sym
> define_method meth do
> yield method(:"old_#{meth}").to_proc
> end
> end
>
> end
>
> class A
> def meth
> p "meth"
> end
>
> def meth2
> p "meth2"
> end
> end
>
> A.around :meth, proc{p "pre"},proc{p "post"}
> A.new.meth
>
> A.around2 :meth2 do |m|
> p "pre2"
> m.call
> p "post2"
> end
>
> A.new.meth2
>
>
> łatwo przerobić na dużo wygodniejsze użycie...
Pogubiłem się trochę w tym kodzie. Chodzi mi o odpowiednik w Ruby czegoś
takiego jak tu w Pythonie:
>>> headers = {'Content-Type': 'text/html'}
>>> class Base:
... @classmethod
... def hello(cls, msg):
... headers['Content-Type'] = 'application/xml'
... return msg
...
>>> Base.hello('JA')
'JA'
>>> headers
{'Content-Type': 'application/xml'}
>>>
Jak widać metoda hello() zmieniła słownik headers. Moim celem jest tak
zmienić klasę Base aby tego NIE zrobiła. Np. tak:
>>> headers = {'Content-Type': 'text/html'}
>>> x = Base.hello
>>> class Base:
... @classmethod
... def hello(cls, msg):
... old = headers['Content-Type']
... result = x(msg)
... if old != headers['Content-Type']:
... headers['Content-Type'] = old
... return result
...
>>> Base.hello('JA')
'JA'
>>> headers
{'Content-Type': 'text/html'}
W Pythonie wyssałem cała metodę za pomocą prostego przypisania. Następnie
otworzyłem tą klasę, dodałem warunki chroniące i wywołałem z powrotem. W
tym ujęciu nie jest w ogóle ważne co sie dzieje w metodzie hello(). Z mego
pkt. widzenia może być "czarną skrzynką". Wiem tylko tyle, że modyfikowała
mi jeden klucz w zewn. słownik i przed tym chciałem się zabezpieczyć.
Wracając do Rubiego i do konretnego problemu jaki spotkałem w RoR. Chcę
poprawić metodę render_to_string() bo ona gdzieś modyfikuje nagłówek HTTP.
Pierwotnie definicja wygląda tak:
module ActionController
class Base
def render_to_string(options = nil, &block)
result = render(options, &block)
erase_render_results
forget_variables_added_to_assigns
reset_variables_added_to_assigns
result
end
end
end
Nie interesuje mnie co sie dzieje w środku. Chcę tylko dodać zabezpieczenie
przed zmianą klucza Content-Type w @headers. Zrobiłem to trochę siłowo,
kopiując wszystko jak leci i dodając swój warunek:
module ActionController
class Base
def render_to_string(options = nil, &block)
content_type = @headers['Content-Type']
result = render(options, &block)
erase_render_results
forget_variables_added_to_assigns
reset_variables_added_to_assigns
if content_type != @headers['Content-Type']
@headers['Content-Type'] = content_type
end
result
end
end
end
Interesowało mnie jednak, czy mógłbym to zrobić bardziej elegancko, bez
kopiowania środka metody. Tak jak w Pythonie.
--
Jarosław Zabiełło
http://blog.zabiello.com
Re: Ruby i dekorator
Author: Marcin Mielżyński
Date: Thu, 07 Sep 2006 17:36
Date: Thu, 07 Sep 2006 17:36
33 lines
1537 bytes
1537 bytes
to chyba najprościej tak:
class Base
def render_to_string(options = nil, &block)
# oryginalna czarna skrzynka
end
end
# powtórne otwarcie klasy
class Base
alias :orig_render_to_string render_to_string
def render_to_string(*args, &blk)
result = orig_render_to_string(*args,&blk)
# ...
result
end
end
A.new.render_to_string
myślałem że chodzi o bardziej 'generyczne' rozwiązanie ;)
W 2.0 będą kombinatory :pre :post i :around
lopex
Re: Ruby i dekorator
Author: Marcin Mielżyński
Date: Thu, 07 Sep 2006 17:37
Date: Thu, 07 Sep 2006 17:37
6 lines
1095 bytes
1095 bytes
Marcin Mielżyński wrote: Oops: > > Base.new.render_to_string >
Re: Ruby i dekorator
Author: Przemysław Kowalczyk
Date: Wed, 13 Sep 2006 21:22
Date: Wed, 13 Sep 2006 21:22
11 lines
1183 bytes
1183 bytes
On Thu, 07 Sep 2006 12:43:28 +0200, Jaroslaw Zabiello <hipertracker@gmail.com> wrote: > Jak w Ruby zaimplementować pythonowy dekorator? A może jest jakaś metoda > która wyciąga całe ciało funkcji? Chcę coś dodać przed nim i po nim.. moze to pomoze: http://swik.net/Ruby/Code+Snippets:+ruby/Partial+Mock+Object+or+mocking+an+instance+of+an+object./cimp pzdr szeryf
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads