🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.ruby
Article #187

Re: Ruby i dekorator

#187
From: Jaroslaw Zabiello
Date: Thu, 07 Sep 2006 16:35
139 lines
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
Technical Details
Message-ID: <1x2rocd4cjsfx.1pa1f7xfso7pe.dlg@40tude.net>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail
References: <re7vnvdwaxef.1xsf47isecttl$.dlg@40tude.net> <edp0jp$ph2$1@news.onet.pl> <1b5oye9z0x1aq.n67fdxozbl7i.dlg@40tude.net> <edp53n$b6v$1@news.onet.pl>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!not-for-mail
From: Jaroslaw Zabiello <hipertracker@gmail.com>
Newsgroups: pl.comp.lang.ruby
Subject: Re: Ruby i dekorator
Date: Thu, 7 Sep 2006 17:35:49 +0100
Organization: "Portal Gazeta.pl -> http://www.gazeta.pl"
Lines: 139
Message-ID: <1x2rocd4cjsfx.1pa1f7xfso7pe.dlg@40tude.net>
References: <re7vnvdwaxef.1xsf47isecttl$.dlg@40tude.net> <edp0jp$ph2$1@news.onet.pl> <1b5oye9z0x1aq.n67fdxozbl7i.dlg@40tude.net> <edp53n$b6v$1@news.onet.pl>
NNTP-Posting-Host: 82.195.148.233
Mime-Version: 1.0
X-Trace: inews.gazeta.pl 1157646954 7769 82.195.148.233 (7 Sep 2006 16:35:54 GMT)
X-Complaints-To: usenet@agora.pl
NNTP-Posting-Date: Thu, 7 Sep 2006 16:35:54 +0000 (UTC)
X-User: newsgate2006
User-Agent: 40tude_Dialog/2.0.15.1pl
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit