<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Ulepszony String i sprawa parametr&#243;w</title>
    <link>http://blog.zabiello.com/articles/2007/06/29/improved-string</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Ulepszony String i sprawa parametr&#243;w</title>
      <description>&lt;p&gt;Ruby posiada bardzo bogate mo&#380;liwo&#347;ci przetwarzania tekstu. Zasugerowany sk&#322;adni&#261; Active Record i wcze&#347;niejszym do&#347;wiadczeniem z Pythonem troch&#281; si&#281; zdziwi&#322;em, &#380;e Matz nie zaimplementowa&#322; przekazywania hasza do operatora &lt;code&gt;%&lt;/code&gt;.&lt;/p&gt;


	&lt;h3&gt;Parametry w Active Record.&lt;/h3&gt;


	&lt;p&gt;Co prawda &lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt; nie mia&#322; mo&#380;e nigdy ambicji kompletnego pozbycia si&#281; j&#281;zyka &lt;span class="caps"&gt;SQL&lt;/span&gt;, ale na tle takiego &lt;a href="http://sqlalchemy.org"&gt;SQLAlchemy&lt;/a&gt; wypada znacznie mniej obiektowo&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Wida&#263; to po sposobie budowania warunk&#243;w. Active Record umo&#380;liwia przekazywanie parametr&#243;w do warunk&#243;w na trzy podstawowe&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; sposoby.&lt;/p&gt;


	&lt;h4&gt;&amp;#8220;Chamskie&amp;#8221; budowanie stringu &lt;span class="caps"&gt;SQL&lt;/span&gt;&lt;/h4&gt;


	&lt;p&gt;Ta metoda jest najbardziej popularna u wszelkiej ma&#347;ci lamer&#243;w i os&#243;b pocz&#261;tkuj&#261;cych. Jest bardzo powszechna w&#347;r&#243;d pehapowc&#243;w, kt&#243;rzy niedawno zacz&#281;li bawi&#263; si&#281; Railsami. Przyk&#322;adowy kod tego typu wygl&#261;da&#322;by mniej wi&#281;cej tak:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user='&lt;span class="expr"&gt;#{user}&lt;/span&gt;' AND login='&lt;span class="expr"&gt;#{passwd}&lt;/span&gt;'&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Taka &amp;#8220;radosna tfurczo&#347;&#263;&amp;#8221; jest z ca&#322;&#261; pewno&#347;ci&#261; zaproszeniem do klasycznego ataku &lt;a href="http://pl.wikipedia.org/wiki/SQL_Injection"&gt;&lt;span class="caps"&gt;SQL&lt;/span&gt; Injection&lt;/a&gt;. Rails posiada co prawda funkcj&#281; &lt;code&gt;sanitize_sql()&lt;/code&gt; kt&#243;ra pacyfikuje niebezpieczne znaki w kwerendzie &lt;span class="caps"&gt;SQL&lt;/span&gt;, ale mo&#380;na o niej zapomnie&#263;, a kod staje si&#281; po prostu brzydki. Zatem tego typu praktyce m&#243;wimy stanowcze: fuj!&lt;/p&gt;


	&lt;p&gt;Prawie wszystkie relacyjne bazy pozwalaj&#261; na budowanie parametryzowanego &lt;span class="caps"&gt;SQL&lt;/span&gt;&amp;#8217;a. Na tym bazuj&#261; dwie kolejne metody.&lt;/p&gt;


	&lt;h4&gt;Przekazywanie listy.&lt;/h4&gt;


	&lt;p&gt;Warunek &lt;code&gt;:conditions&lt;/code&gt; mo&#380;e przyjmowa&#263; zar&#243;wno String jak i Array. W tym drugim wypadku dostajemy za darmo kod uodporniony na atak &lt;span class="caps"&gt;SQL&lt;/span&gt; Injection. Nie trzeba pami&#281;ta&#263; o tym czy dane zawieraj&#261; jakie&#347; niebezpieczne znaki. Nie trzeba te&#380; zastanawia&#263; si&#281; czy przekazywny parametr jest liczb&#261;, czy stringiem (wymagaj&#261;cym apostrof&#243;w w kodzie &lt;span class="caps"&gt;SQL&lt;/span&gt;). Kod jest wi&#281;c i prostszy i bezpieczniejszy.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=? AND login=?&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h4&gt;Przekazywanie hasza.&lt;/h4&gt;


	&lt;p&gt;Przekazywanie listy ma pewn&#261; wad&#281;: trzeba pami&#281;ta&#263; o kolejno&#347;ci parametr&#243;w. Tak&#380;e zawiera niepotrzebn&#261; redundancj&#281; w wypadku kiedy jaki&#347; parametr musi si&#281; powtarza&#263;. Dlatego Active Record umo&#380;liwia korzystanie ze sk&#322;adni inspirowanej baz&#261; Oracle.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;'],&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=:user AND login=:login&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:user&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;user&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:passwd&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;passwd&lt;/span&gt;&lt;span class="punct"&gt;}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;lub jeszcze kr&#243;cej:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Model&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="symbol"&gt;:all&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:conditions&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;user=:user AND login=:login&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;h3&gt;Parametry do stringa.&lt;/h3&gt;


	&lt;p&gt;Po tym wst&#281;pie, pora na (niemi&#322;&#261;) niespodziank&#281; jak&#261; spotka&#322;em w implementacji Rubiego. Generalnie Ruby posiada bardzo bogate mo&#380;liwo&#347;ci przetwarzania tekstu. Podobnie jak Python, posiada te&#380; skr&#243;con&#261; form&#281; funkcji &lt;code&gt;sprintf&lt;/code&gt; realizowan&#261; za pomoc&#261;  operatora &lt;code&gt;%&lt;/code&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s can use %s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;Ruby&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;list of parameters&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Ruby can use list of parameters.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Python jednak&#380;e pozwala tak&#380;e na u&#380;ywanie s&#322;ownik&#243;w.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;params&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{'&lt;/span&gt;&lt;span class="string"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:'&lt;/span&gt;&lt;span class="symbol"&gt;Python&lt;/span&gt;&lt;span class="symbol"&gt;'&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;what&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="symbol"&gt;:'&lt;/span&gt;&lt;span class="symbol"&gt;a dictionary&lt;/span&gt;&lt;span class="symbol"&gt;'&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%(lang)s can also use %(what)s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;params&lt;/span&gt;
&lt;span class="constant"&gt;Python&lt;/span&gt; &lt;span class="ident"&gt;can&lt;/span&gt; &lt;span class="ident"&gt;also&lt;/span&gt; &lt;span class="ident"&gt;use&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;dictionary&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Troch&#281; mnie zdziwi&#322;o, &#380;e Ruby nie posiada odpowiednika tej funkcjonalno&#347;ci&amp;#8230;. Na szcz&#281;&#347;cie, dzi&#281;ki otwartym klasom, &lt;a href="http://en.wikipedia.org/wiki/Monkey_patch"&gt;monkey patching&lt;/a&gt; w przypadku Rubiego nabiera zupe&#322;nie innego wymiaru. Nic nie stoi na przeszkodzie aby ulepszy&#263; standardowy obiekt String.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;String&lt;/span&gt;  
  &lt;span class="ident"&gt;alias_method&lt;/span&gt; &lt;span class="symbol"&gt;:old_percent&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;:%&lt;/span&gt;
  &lt;span class="comment"&gt;# Template strings. &lt;/span&gt;
  &lt;span class="comment"&gt;# Inspired by Python %(key)s and $key syntax.&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;Hash&lt;/span&gt;
      &lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each_pair&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
        &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^[a-z]+$&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
          &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;$(&lt;span class="expr"&gt;#{key}&lt;/span&gt;)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;
          &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;$&lt;span class="expr"&gt;#{key}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;
        &lt;span class="keyword"&gt;end&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;    
    &lt;span class="ident"&gt;old_percent&lt;/span&gt; &lt;span class="ident"&gt;var&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;hash&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="symbol"&gt;:lang&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Ruby&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="symbol"&gt;:what&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;a hash&lt;/span&gt;&lt;span class="punct"&gt;'}&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Now $lang can also use $what :)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;hash&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Now Ruby can also use a hash :)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I jak tu nie powiedzie&#263;, &#380;e Ruby jest pi&#281;kny? :)&lt;/p&gt;


&lt;hr size="1" width="30%" align="left" /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Active Record jest te&#380; mniej zaawansowany ni&#380; np. SQLAlchemy. Funkcjonalno&#347;&#263; Active Record jest mo&#380;e i &#347;wietna, ale jego implementacja w wielu punktach jest z pewno&#347;ci&#261; niedojrza&#322;a. Np. nie mam poj&#281;cia dlaczego Active Record zwraca list&#281; obiekt&#243;w zamiast generator, to pozwoli&#322;oby na wi&#281;ksze oszcz&#281;dno&#347;ci pami&#281;ci.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Bardziej obiektowe budowanie warunk&#243;w zapewniaj&#261; pluginy &lt;a href="http://agilewebdevelopment.com/plugins/ez_where"&gt;ez_where&lt;/a&gt; i &lt;a href="http://agilewebdevelopment.com/plugins/condition_builder"&gt;Condition Builder&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 29 Jun 2007 02:42:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:fbba7197-20e9-4c68-ba9b-f30633f57374</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string</link>
      <category>ruby</category>
      <category>rails</category>
      <category>activerecord</category>
      <category>monkeypatching</category>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by Jaros&#322;aw Zabie&#322;&#322;o</title>
      <description>&lt;p&gt;climbus: Python te&#380; pozwala na modyfikacj&#281; klas poza tym, &#380;e nie da si&#281; tego zrobi&#263; bezpo&#347;rednio na obiektach typu &lt;code&gt;str&lt;/code&gt; czy &lt;code&gt;int&lt;/code&gt;. Ruby jest tylko bardziej konsekwentny.&lt;/p&gt;</description>
      <pubDate>Tue, 03 Jul 2007 11:06:52 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f52d1685-8758-452e-b126-cccdbb86e89a</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-853</link>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by climbus</title>
      <description>&lt;p&gt;Nie przekonam si&#281; do zmiany klasy bez zmiany jej nazwy (dziedziczenie). Przynajmniej wiadomo z czym mam do czynienia.&lt;/p&gt;


	&lt;p&gt;Co si&#281; stanie gdy kto&#347; na pocz&#261;tku pliku zaimportuje plik zmieniaj&#261;cy klas&#281; u&#380;ywan&#261;  cz&#281;sto poni&#380;ej?&lt;/p&gt;</description>
      <pubDate>Tue, 03 Jul 2007 08:58:21 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:9503fa75-aa92-4419-8962-369b413ce290</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-852</link>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by sztywny</title>
      <description>&lt;p&gt;Conditions podawane do ActiveRecord::Base.find mog&#261; by&#263; hashem, wi&#281;c mo&#380;na te&#380; pisa&#263; po prostu tak:&lt;/p&gt;


	&lt;p&gt;user, passwd = params[&amp;#8216;user&amp;#8217;], params[&amp;#8216;passwd&amp;#8217;]
Model.find(:all, :conditions =&amp;gt; {:user =&amp;gt; user, :passwd =&amp;gt; passwd})&lt;/p&gt;</description>
      <pubDate>Fri, 29 Jun 2007 20:48:35 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:dc1b202d-2b07-409a-8388-bf3d5105b557</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-847</link>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by lopex</title>
      <description>&lt;p&gt;Jest te&#380; bardzo wygodny idiom to robienia templat&#243;w (rozszerzy&#263; wedle uznania):
s = &amp;#8220;some template $a $b&amp;#8221; 
h = { &amp;#8220;a&amp;#8221; =&amp;gt; &amp;#8220;A&amp;#8221;, &amp;#8220;b&amp;#8221; =&amp;gt; &amp;#8220;B&amp;#8221; }
s.gsub(/(?:\$(\w+))/){h[$1]}&lt;/p&gt;


	&lt;p&gt;Btw, xalan nie jest parserem tylko procesorem ;)&lt;/p&gt;</description>
      <pubDate>Fri, 29 Jun 2007 18:10:32 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:e7b22e36-2ca3-46dc-a35e-c3d1cc0eedc6</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-846</link>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by Jaros&#322;aw Zabie&#322;&#322;o</title>
      <description>&lt;p&gt;Co&#347; podobnego ma &lt;a href="http://pyana.sourceforge.net/" rel="nofollow"&gt;Pyana&lt;/a&gt;, gdzie bardzo &lt;a href="http://pyana.sourceforge.net/examples/simple_callbacks.py" rel="nofollow"&gt;&#322;atwo mo&#380;na dodawa&#263; funkcje Pythona&lt;/a&gt; do jej (bardzo szybkiego) parsera XSLT&lt;/p&gt;</description>
      <pubDate>Fri, 29 Jun 2007 11:59:27 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:43b5743a-1a2b-41cd-aa16-288680972ec1</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-845</link>
    </item>
    <item>
      <title>"Ulepszony String i sprawa parametr&#243;w" by hosiawak</title>
      <description>&lt;p&gt;Otwarte klasy Rubiego to najlepsza rzecz od czasu krojonego chleba :) Do innych nale&#380;&#261; jeszcze np. funkcje jako obiekty (lambda/Proc). Przyk&#322;ad zastosowania ? Wyobra&#378;my sobie, &#380;e budujemy parser HTML&amp;#8217;a kt&#243;ry za pomoc&#261; XPath wyci&#261;ga potrzebne nam informacje ze strony WWW, np.&lt;/p&gt;


&lt;pre&gt;
require 'hpricot'
def extract(options = {})
  val = @doc.at(options[:xpath])
end
&lt;/pre&gt;
Sam XPath jednak nie wystarcza, bardzo cz&#281;sto b&#281;dziemy musieli podda&#263; nasze dane obr&#243;bce. Jakiej obr&#243;bce ? Np. gsub, strip, join itp. Jak zmodyfikowa&#263; metod&#281; extract aby zapewni&#322;a nam tak&#261; elastyczno&#347;&#263; ? Z pomoc&#261; przychodzi przekazywanie funkcji jako obiekt&#243;w, np:

&lt;pre&gt;
require 'hpricot'

def extract(options = {})
  val = @doc.at(options[:xpath])
  val = options[:filter].call(val)
end
&lt;/pre&gt;

	&lt;p&gt;Teraz mo&#380;emy zrobi&#263; co&#347; takiego:&lt;/p&gt;


&lt;pre&gt;
data.extract(:xpath =&amp;gt; '/nasz/xpath',
             :filter =&amp;gt; lambda {|x| x.gsub(/,.*$/, '') } )
&lt;/pre&gt;
Pot&#281;&#380;na koncepcja zapo&#380;yczona z Lisp&amp;#8217;a  kt&#243;ra okazuje si&#281; bardzo u&#380;yteczna w np. w budowaniu elastycznych DSL&amp;#8217;i. 

	&lt;p&gt;albo powiedzmy:&lt;/p&gt;


&lt;pre&gt;
data.extract(:xpath =&amp;gt; '/nasz/xpath',
             :filter =&amp;gt; lambda {|x| x.split(',')[1].strip } )
&lt;/pre&gt;</description>
      <pubDate>Fri, 29 Jun 2007 10:39:52 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:5e590e66-d02d-4016-850c-156d11a56ce6</guid>
      <link>http://blog.zabiello.com/articles/2007/06/29/improved-string#comment-844</link>
    </item>
  </channel>
</rss>
