tag:www.stefanwienert.net,2008:/rubyRuby - Stefan Wienert's Blog2011-09-01T18:13:03ZEnkiStefan Wienertstwienert@gmail.comtag:www.stefanwienert.net,2008:Post/702011-06-08T04:40:00Z2011-06-08T06:40:54ZRails for Zombies - Braaainz<p>Wer schon immer mal Ruby on Rails lernen wollte, aber nie den Einstieg oder die Zeit gefunden hatte, für den gibt es jetzt <strong>Rails for Zombies</strong>.</p>
<p>Didaktik mal total anders. Statt drögen nie endenden Tutorials, gibt es eine mit vielen Videos angereichtere “Lern-Experience”. Dabei haben die Macher neben den Lektionen direkt jeweils eine Aufgabe, die es in einer Ruby-artigen Live-<br />
Console zu lösen gibt!</p>
<p>Achja, umsonst ist das auch noch! Geld verdienen wollen die Macher envylabs mit Folgetutorials in derselben Güte, die in der selben Qualität ausfallen dürften.</p>
<p>Free from <span class="caps">PHP</span> now! Let’s go ;)</p>
<p><a href="http://railsforzombies.org/">railsforzombies.org</a></p>tag:www.stefanwienert.net,2008:Post/472010-05-26T13:42:00Z2010-05-26T15:42:42ZRuby on Rails Screencast - Implementation einer User Anmeldung<p>Für eine kommende Vorlesung über Test Driven Development habe ich einen Screencast angefertigt.</p>
<p>Das ganze natürlich in Rails mit Test::Unit und Vim (wegen der Sparsamkeit mit dem Screenplatz).</p>
<p>Das Auditorium kennt Rails größtenteils nicht, weshalb es ein einfach gewähltes Beispiel ist:<br />
Die Implementierung eines simplen Authentifizierungsmechanismus, der einen Nutzer am System anmeldet.</p>
<p><object width="400" height="300"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=12044362&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=12044362&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"></embed></object><p><a href="http://vimeo.com/12044362">Screencast Rails Session Authentication</a> from <a href="http://vimeo.com/user3902285">Stefan Wienert</a> on <a href="http://vimeo.com">Vimeo</a>.</p></p>
<p>Das genutzte Programm zur Aufnahme war Xvidcap. Sehr genial.</p>tag:www.stefanwienert.net,2008:Post/422010-04-07T02:48:00Z2010-04-07T04:48:15ZMal wieder ein paar Links zum Thema Rails und Vim<p>Vim:</p>
<ul>
<li><a href="http://robots.thoughtbot.com/post/166073596/intro-rails-vim">Rails.vim</a></li>
<li><a href="http://vimcasts.org/">Qualitativ hochwertiger Screencast für <span class="caps">VIM</span></a></li>
</ul>
<p>Rails:</p>
<ul>
<li><a href="http://blog.siverti.com.br/gmate/">Gmate – Ein Gedit Plugin Kompendium</a> sehr genial auch für nicht-Rails Projekte</li>
<li><a href="http://www.youtube.com/rhomobile#p/a/f/0/T2pztOky_L0">plattformübergreifend Android, iPhone, WinMob Anwendungein in einem Rails ähnlichen Framework bauen</a></li>
<li><a href="http://eggsonbread.com/2010/03/28/my-rspec-best-practices-and-tips/">Rspec Best Practices</a></li>
<li><a href="http://rubybestpractices.com/">Kostenloses Beta Buch: Ruby Best Practices</a></li>
<li><a href="http://www.ruby-toolbox.com/">Rubytoolbox – Auswahl und Kategorisierung der beliebtesten Gems</a></li>
<li><a href="http://www.rubyflow.com/">Rubyflow – <span class="caps">DER</span> Rubyticker</a> Dazu hier von <a href="http://site.stefanwienert.net/rss/rubyflow.rss">mir der komplette Feed inklusive der nicht-approved Beiträge</a></li>
</ul>tag:www.stefanwienert.net,2008:Post/372010-03-02T06:31:00Z2011-09-01T18:13:03ZRails/Passenger im Parallels Plesk zum Laufen bekommen EDIT mit SSL<p>Wer auch Parallels Plesk Panel für seine Serveradministration verwendet, und sich schonmal gefragt hat, ob es was besseres als die Build-in Fast <span class="caps">CGI</span> Unterstützung oder Mongrel/Webrick gibt, dem will ich hier mal einen kleinen Guide geben, wie das ganze mit Passenger zu bewerkstelligen ist.<br />
Wir verwenden für die Administration unserer Server auch Plesk, da es echt stupid simple ist.</p>
<p>Ich gehe davon aus, dass Ruby und Rubygems bereits installiert sind! (Sollte man z.B. Debian verwenden, auf keinen Fall die Pakete aus dem apt-get installieren, sondern <a href="http://rubyonrails.org/download">manuell wie hier beschreiben</a>.) Auch ein Root-Zugang zum Server wird benötigt.</p>
<p>Also:</p>
<ol>
<li>im Plesk eine neue Domain/Subdomain anlegen</li>
<li>Unser Rails-Projekt nach <tt>/var/www/vhosts/<span class="caps">DOMAIN</span>/httpdocs</tt> bzw. <tt>/var/www/vhosts/<span class="caps">DOMAIN</span>/subdomains/<span class="caps">SUBDOMAIN</span>/httpdocs</tt> kopieren. Also genau dort rein, kein weiteres Unterverzeichnis (nach httpdocs kommen dann gleich app db config public …)</li>
<li>Schauen, dass die Lese/Schreibrechte hinhauen: z.B. <tt>chgrp psaserv log db tmp -R && chmod g+w * -R</tt>. Im einzelnen mal schauen.</li>
<li>Root Konsole: Gems installieren und Datenbank migrieren:</li>
</ol><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">rake gems<span class="sy">:install</span><tt>
</tt>rake db<span class="sy">:migrate</span> <span class="co">RAILS_ENV</span>=<span class="s"><span class="dl">"</span><span class="k">production</span><span class="dl">"</span></span><tt>
</tt>gem install passenger<tt>
</tt><span class="c"># laengere Anleitung befolgen. Im Endeffekt muss man ein paar Zeilen in die apache2.conf kopieren. </span><tt>
</tt><span class="c"># Den zweiten Teil mit mit der Vserver Konfiguration interessiert uns im Moment nicht</span><tt>
</tt></pre></td>
</tr></table>
<ol>
<li>Im Ordner <tt><span class="caps">DOMAIN</span>/conf</tt> also von unserem httpdocs Verzeichnis <tt>../conf/vhost.conf</tt> nun die Datei vhost.conf anlegen und folgendes reinkopieren (jeweils das richtige Verzeichnis als Ziel nehmen, je nachdem ob wir eine Subdomain oder Domain benutzen möchten):</li>
</ol><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"> <span class="co">DocumentRoot</span> <span class="rx"><span class="dl">/</span><span class="k">var</span><span class="dl">/</span></span>www/vhosts/<span class="co">DOMAIN</span>/httpdocs/public<tt>
</tt><span class="c"># bzw. /var/www/vhosts/DOMAIN/subdomains/SUBDOMAIN/httpdocs/public</span><tt>
</tt> <<span class="co">Directory</span> <span class="rx"><span class="dl">/</span><span class="k">var</span><span class="dl">/</span></span>www/vhosts/pludoni.de/subdomains/tasks/httpdocs/public ><tt>
</tt> <span class="co">AllowOverride</span> all<tt>
</tt> <span class="co">Options</span> -<span class="co">MultiViews</span><tt>
</tt> <<span class="rx"><span class="dl">/</span><span class="k">Directory><tt>
</tt></span></span></pre></td>
</tr></table>
<ol>
<li>plesk Vhost reloaden:</li>
</ol><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">/usr/local/psa/admin/sbin/websrvmng -u --vhost-name=DOMAIN.de<tt>
</tt></pre></td>
</tr></table>
<p>hierbei jeweils immer nur die Domain angeben, auch wenn wir nur einen Subdomain anlegen.</p>
<p>Nun sollte unsere Rails App unter der Domain bzw. Subdomain verfügbar sein. Neustarten können wir Passenger indem wir ein <tt>touch tmp/restart.txt</tt> oder die Datei sonst irgendwie im Timestamp verändern.</p>
<p><strong>Edit</strong>: Möchte man Plesk, Rails und Passenger mit <span class="caps">SSL</span> verwenden (also https://…domain), muss man noch etwas tun:</p>
<ul>
<li>die Datei “conf/vhost.conf” nach “conf/vhost_ssl.conf” kopieren</li>
<li>Plesk reloaden</li>
</ul>
<p>Ansonsten erhält man ein 403 “Forbidden You don’t have permission to access / on this server.”, da Apache das ganze als statische <span class="caps">HTML</span>-Seite betrachtet, und die index.html sucht.</p>tag:www.stefanwienert.net,2008:Post/362010-02-28T19:13:00Z2010-02-28T20:13:44ZKurzes Gem Showcase - Delicious, actsasarchive, menu borwsercms css sprite<p>Ich schaue gerade meine kürzlich gebookmarkten Sites an, und will hier mal ein paar coole Ruby Ressourcen zeigen.</p>
<ul>
<li>Delicious-<span class="caps">API</span>: http://github.com/weppos/www-delicious für den beliebten Bookmarkdienst</li>
<li>Acts as archive, destroy und delete Aktionen eines Objektes führen nicht zur Löschung, sondern Archivierung http://github.com/winton/acts_as_archive</li>
<li>MMMenu http://github.com/snitko/mmmenu eine kleine Menü <acronym title="(Domain Specific Language"><span class="caps">DSL</span></acronym>)</li>
<li>Automatische, transparente <span class="caps">CSS</span> Sprite Transformation http://github.com/reevoo/spriter</li>
<li>BrowserCMS, meine Basis <span class="caps">CMS</span> für meine nächsten Projekte http://www.browsercms.org/ <br />
Schaut <a href="http://aac2009.confreaks.com/07-feb-2009-10-00-browsercms-patrick-peak-and-paul-barry.html">euch das Video dazu an</a></li>
</ul>
<p>und sowieso:<br />
http://www.ruby-toolbox.com/ und http://www.rubyflow.com/ zur Ideenfindung.</p>
<p>I love that community :)</p>tag:www.stefanwienert.net,2008:Post/352010-02-28T19:06:00Z2010-02-28T20:06:14ZMinibot für Erstellung eines iCals und RSS-Feeds von einer Web1.0 Site<p>In Dresden gibt es die Hochschule für Musik “Carl Maria von Weber”, welche <a href="http://www.hfmdd.de/index.php?id=4">auf ihrer Website</a> auch ihr aktuelles Programm kundtun. Wer etwas Interesse an klassischer Musik hat, hat durch diese Art der Konzerte die Gelegenheit, sehr gute Pianisten sehr preiswert (umsonst…) zu hören.</p>
<p>Leider bieten sie weder einen Feed noch einen Kalender an, deshalb dachte ich mir, das wär wieder ein guter Einsatz für das hpricot-Gem, ich will hier mal kurz den Ablauf skizzieren.</p>
<h3>Rien ne va plus … ohne Gems!</h3><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="s"><span class="dl">%w[</span><span class="k">rubygems hpricot curl active_support icalendar</span><span class="dl">]</span></span>.each { |x| require x}<tt>
</tt></pre></td>
</tr></table>
<p>Im ersten Fall hatte ich Probleme mit den <strong>Umlauten</strong>, also erst einmal alles nach <span class="caps">UTF</span>-8 transformieren/encodieren:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">cal = <span class="co">Calendar</span>.new <span class="c"># by the way: wir machen gleich mal einen ical draus, siehe icalendar gem.</span><tt>
</tt><tt>
</tt>curl_object = <span class="co">Curl</span>::<span class="co">Easy</span>.perform(<span class="s"><span class="dl">"</span><span class="k">http://www.hfmdd.de/veranstaltungen/</span><span class="dl">"</span></span>)<tt>
</tt>body = <span class="co">Iconv</span>.conv(<span class="s"><span class="dl">"</span><span class="k">UTF-8//IGNORE</span><span class="dl">"</span></span>,<span class="s"><span class="dl">"</span><span class="k">ISO-8859-1</span><span class="dl">"</span></span>, curl_object.body_str)<tt>
</tt>doc = Hpricot(body)<tt>
</tt></pre></td>
</tr></table>
<p>Im nächsten Schritt mit <a href="http://www.selectorgadget.com/">Selector Gadget</a> und Firebug herausfinden, welcher <span class="caps">CSS</span>-Selektor uns Zeiger auf die Contentbereiche liefert, hier z.B. “#contentbereich div” mit der Eigenschaft, dass deren margin 35em ist… Leider haben die Webdesigner bei der Site der Musikhochschule wenig Gebraucht von Klassen oder IDs gemacht.</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">elements = doc.search(<span class="s"><span class="dl">"</span><span class="k">#contentbereich div</span><span class="dl">"</span></span>).select{ <tt>
</tt> |it| it[<span class="sy">:style</span>].include? <span class="s"><span class="dl">"</span><span class="k">35em</span><span class="dl">"</span></span> <span class="r">if</span> it[<span class="sy">:style</span>].present?<tt>
</tt>}<tt>
</tt><span class="c"># present? ist das Gegenteil von .blank?</span><tt>
</tt><tt>
</tt><span class="c"># Jetzt traversieren wir die Elemente die uebrig bleiben</span><tt>
</tt>elements.each <span class="r">do</span> |item|<tt>
</tt> [...]<tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p>Jetzt zum langweiligeren […] Teil, dem lokalen Extrahieren der Daten…<br />
Das passiert leider etwas unsauber, da, wie man auf der Seite sehen kann, recht willkürliche Formate in den Datumsangaben gemacht wurden, hier mein bester Versuch:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"> text = item.search(<span class="s"><span class="dl">"</span><span class="k">div[2]</span><span class="dl">"</span></span>).inner_html <span class="r">rescue</span> text = <span class="s"><span class="dl">"</span><span class="k">???</span><span class="dl">"</span></span><tt>
</tt> date = item.search(<span class="s"><span class="dl">"</span><span class="k">>div>b</span><span class="dl">"</span></span>).first.inner_text.split(<span class="s"><span class="dl">"</span><span class="k">.</span><span class="dl">"</span></span>)<tt>
</tt> time = item.search(<span class="s"><span class="dl">"</span><span class="k">>div[1]>*</span><span class="dl">"</span></span>)[<span class="i">4</span>].to_s[<span class="i">0</span>..<span class="i">4</span>].split(<span class="s"><span class="dl">"</span><span class="k">:</span><span class="dl">"</span></span>) <span class="r">rescue</span> time = <span class="s"><span class="dl">"</span><span class="k">00:00</span><span class="dl">"</span></span><tt>
</tt> <span class="r">begin</span><tt>
</tt> new_date = <span class="co">DateTime</span>.strptime(<span class="s"><span class="dl">"</span><span class="k">20</span><span class="il"><span class="idl">#{</span>date[<span class="i">2</span>]<span class="idl">}</span></span><span class="k">-</span><span class="il"><span class="idl">#{</span>date[<span class="i">1</span>]<span class="idl">}</span></span><span class="k">-</span><span class="il"><span class="idl">#{</span>date[<span class="i">0</span>]<span class="idl">}</span></span><span class="k">T</span><span class="il"><span class="idl">#{</span>time[<span class="i">0</span>]<span class="idl">}</span></span><span class="k">:</span><span class="il"><span class="idl">#{</span>time[<span class="i">1</span>]<span class="idl">}</span></span><span class="k">:00+0100</span><span class="dl">"</span></span>) <tt>
</tt> <span class="r">next</span> <span class="r">if</span> new_date < <span class="co">Date</span>.today<tt>
</tt> event = cal.event<tt>
</tt> event.start = new_date<tt>
</tt> event.summary = text.split(<span class="s"><span class="dl">"</span><span class="k"><br</span><span class="dl">"</span></span>).first[<span class="i">0</span>..<span class="i">150</span>]<tt>
</tt> event.description = text <tt>
</tt> <span class="r">rescue</span><tt>
</tt> puts <span class="s"><span class="dl">"</span><span class="k">INVALID: 20</span><span class="il"><span class="idl">#{</span>date[<span class="i">2</span>]<span class="idl">}</span></span><span class="k">-</span><span class="il"><span class="idl">#{</span>date[<span class="i">1</span>]<span class="idl">}</span></span><span class="k">-</span><span class="il"><span class="idl">#{</span>date[<span class="i">0</span>]<span class="idl">}</span></span><span class="k">T</span><span class="il"><span class="idl">#{</span>time[<span class="i">0</span>]<span class="idl">}</span></span><span class="k">:</span><span class="il"><span class="idl">#{</span>time[<span class="i">1</span>]<span class="idl">}</span></span><span class="k">:00+0100</span><span class="dl">"</span></span><tt>
</tt> <span class="c"># spaeter ein logger</span><tt>
</tt> <span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p>Jetzt koennen wir den Kalendar direkt ausgeben, oder sonstwas damit machen</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">cal.to_ical<tt>
</tt></pre></td>
</tr></table>
<p>Das Ganze war eher ein Proof-of-Concept, denn wie immer, wenn man ScreenScraping betreibt, sollte man eine Art Einverständnis des Inhabers der gescrapten Seite haben (oder sie bieten wie Google und Twitter eine <span class="caps">API</span> an)</p>tag:www.stefanwienert.net,2008:Post/342010-02-16T08:09:00Z2010-02-16T09:09:23ZYakuake mit Startskripts versehen - Automatische Einrichtung der Arbeitsumgebung<p>Diejenigen von euch, die eine <span class="caps">KDE</span> Umgebung unter Linux verwenden, kennen vielleicht yakuake, ein Terminalprogramm mit etwas EyeCandy, welches bei Druck von F12 aus dem oberen Bildschirmrand herausfährt.<br />
Ich selbst nutze zwar Gnome, nehme aber als priorisiertes Terminalprogramm trotzdem yakuake, da ich finde, dass das Farbschema “Dunkle Pasteltöne” einfach gut aussieht, und man die Shell, egal auf welchem Virtuellem Desktop man sich befindet, nie aus den Augen verliert (F12 und sie ist wieder da).</p>
<p>Die Dokumentation der Skriptfähigkeit ist etwas dürftig, außer einem <a href="http://88.191.25.234/wordpress/2009/05/09/yakuake-launch-on-start/">Blogeintrag</a> habe ich nicht sehr viel gefunden. Das dort abgebildete Beispielshellskript hab ich bei mir nicht zum Laufen bekommen, darum hab ich ein Ruby Programm dafür geschrieben…. (Ehrlich gesagt, find ich Shell Skript hässlich, keine Parameterliste, hässliche Conditional-Syntax… ja wann kommt denn endlich eine Ruby Shell?? :D)</p>
<h3>kurze Einführung</h3>
<p>Ersteinmal muss yakuake laufen, vornehmlich in einem initialen Zustand.<br />
Das Ganze läuft über qbus und man ruft prinzipiell nur ein paar recht einfache Shellkommandos auf:</p>
<p>Ein Aufruf von</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">qdbus org.kde.yakuake /yakuake/sessions <tt>
</tt><tt>
</tt># und<tt>
</tt><tt>
</tt>qdbus org.kde.yakuake /yakuake/tabs <tt>
</tt></pre></td>
</tr></table>
<p>Gibt uns alle möglichen Kommandos auf. Hier meine Favoriten:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">qdbus org.kde.yakuake <span class="rx"><span class="dl">/</span><span class="k">yakuake</span><span class="dl">/</span><span class="mod">sessions</span></span> addSession<tt>
</tt>qdbus org.kde.yakuake <span class="rx"><span class="dl">/</span><span class="k">yakuake</span><span class="dl">/</span><span class="mod">sessions</span></span> addSessionTwoHorizontal<tt>
</tt>qdbus org.kde.yakuake <span class="rx"><span class="dl">/</span><span class="k">yakuake</span><span class="dl">/</span><span class="mod">sessions</span></span> addSessionTwoVertical<tt>
</tt><span class="c"># Macht ein neues Tab (mit zwei, horizontal/vertikal geteilten Sessions sprich Terminals)</span><tt>
</tt><tt>
</tt>qdbus org.kde.yakuake <span class="rx"><span class="dl">/</span><span class="k">yakuake</span><span class="dl">/</span></span>tabs setTabTitle <span class="gv">$tabid</span> <span class="s"><span class="dl">'</span><span class="k">name</span><span class="dl">'</span></span><tt>
</tt><span class="c"># Setzt den Tab auf ein neues Label</span><tt>
</tt><tt>
</tt>qdbus org.kde.yakuake <span class="rx"><span class="dl">/</span><span class="k">yakuake</span><span class="dl">/</span><span class="mod">sessions</span></span> runCommandInTerminal <span class="gv">$sessionid</span> <span class="s"><span class="dl">'</span><span class="k">command</span><span class="dl">'</span></span><tt>
</tt><span class="c"># Führt ein Shell-Kommando in Terminal Nr X aus</span><tt>
</tt><tt>
</tt>qdbus org.kde.yakuake | grep <span class="co">Sessions</span> | cut --fields <span class="s"><span class="dl">"</span><span class="k">3</span><span class="dl">"</span></span> --delim=<span class="s"><span class="dl">"</span><span class="k">/</span><span class="dl">"</span></span> | sort -n | tail -n <span class="i">1</span><tt>
</tt><span class="c"># Gibt uns die letzte vergebene SessionID aus</span><tt>
</tt><tt>
</tt></pre></td>
</tr></table>
<p>Wie man sieht, besteht das eigentliche Problem, den Überblick über die Sessions (Terminals) und Tabs zu behalten. Wenn man keine geteilten Fenstern nutzt, sollten die beiden identisch sein.</p>
<h3>Ein Ruby-Wrapper</h3>
<p>Um den IDs herr zu werden, habe ich das Ganze in ein Rubyprogramm, eine Klasse, geflochten:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>23<tt>
</tt>24<tt>
</tt>25<tt>
</tt>26<tt>
</tt>27<tt>
</tt>28<tt>
</tt>29<tt>
</tt><strong>30</strong><tt>
</tt>31<tt>
</tt>32<tt>
</tt>33<tt>
</tt>34<tt>
</tt>35<tt>
</tt>36<tt>
</tt>37<tt>
</tt>38<tt>
</tt>39<tt>
</tt><strong>40</strong><tt>
</tt>41<tt>
</tt>42<tt>
</tt>43<tt>
</tt>44<tt>
</tt>45<tt>
</tt>46<tt>
</tt>47<tt>
</tt>48<tt>
</tt>49<tt>
</tt><strong>50</strong><tt>
</tt>51<tt>
</tt>52<tt>
</tt>53<tt>
</tt>54<tt>
</tt>55<tt>
</tt>56<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">class</span> <span class="cl">Yakuake</span><tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">initialize</span><tt>
</tt> <span class="iv">@cid</span>=<span class="i">0</span> <tt>
</tt> <span class="iv">@tabid</span>=<span class="i">0</span> <tt>
</tt> <span class="r">end</span> <tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">exec</span>(cmd)<tt>
</tt> puts cmd <tt>
</tt> system cmd <tt>
</tt> <span class="r">end</span> <tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">add_splitted_tab</span>(title1,command1,command2)<tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/sessions addSessionTwoHorizontal</span><span class="dl">"</span></span><tt>
</tt> <span class="iv">@tabid</span>+=<span class="i">1</span> <tt>
</tt> cid = last <tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/tabs setTabTitle </span><span class="il"><span class="idl">#{</span><span class="iv">@tabid</span><span class="idl">}</span></span><span class="k"> '</span><span class="il"><span class="idl">#{</span>title1<span class="idl">}</span></span><span class="k">'</span><span class="dl">"</span></span><tt>
</tt> [command1, command2].each_with_index <span class="r">do</span> |command,index| <tt>
</tt> <span class="r">if</span> command <tt>
</tt> ccid = cid <span class="i">-1</span> + index <tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/sessions runCommandInTerminal </span><span class="il"><span class="idl">#{</span>ccid-<span class="i">1</span><span class="idl">}</span></span><span class="k"> '</span><span class="il"><span class="idl">#{</span>command<span class="idl">}</span></span><span class="k">'</span><span class="dl">"</span></span> <tt>
</tt> <span class="r">end</span> <tt>
</tt> <span class="r">end</span> <tt>
</tt> <span class="r">end</span> <tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">add_tab</span>(name, command=<span class="pc">false</span>)<tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/sessions addSession</span><span class="dl">"</span></span><tt>
</tt> <span class="iv">@tabid</span>+=<span class="i">1</span> <tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/tabs setTabTitle </span><span class="il"><span class="idl">#{</span><span class="iv">@tabid</span><span class="idl">}</span></span><span class="k"> '</span><span class="il"><span class="idl">#{</span>name<span class="idl">}</span></span><span class="k">'</span><span class="dl">"</span></span><tt>
</tt> <span class="r">if</span> command <span class="r">and</span> !command.empty? <tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/sessions runCommandInTerminal </span><span class="il"><span class="idl">#{</span>last - <span class="i">1</span><span class="idl">}</span></span><span class="k"> '</span><span class="il"><span class="idl">#{</span>command<span class="idl">}</span></span><span class="k">'</span><span class="dl">"</span></span> <tt>
</tt> <span class="r">end</span> <tt>
</tt> <span class="r">end</span> <tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">execute</span>(terminal_id, command)<tt>
</tt> exec <span class="s"><span class="dl">"</span><span class="k">qdbus org.kde.yakuake /yakuake/sessions runCommandInTerminal </span><span class="il"><span class="idl">#{</span>terminal_id<span class="idl">}</span></span><span class="k"> '</span><span class="il"><span class="idl">#{</span>command<span class="idl">}</span></span><span class="k">'</span><span class="dl">"</span></span> <tt>
</tt> <span class="r">end</span> <tt>
</tt><tt>
</tt> <span class="r">def</span> <span class="fu">last</span><tt>
</tt> <span class="sh"><span class="dl">`</span><span class="k">qdbus org.kde.yakuake | grep Sessions | cut --fields "3" --delim="/" | sort -n | tail -n 1</span><span class="dl">`</span></span>.strip.to_i <tt>
</tt> <span class="r">end</span> <tt>
</tt><span class="r">end</span> <tt>
</tt><tt>
</tt><span class="c"># Aufruf/Einrichtung des Workspace:</span><tt>
</tt>y=<span class="co">Yakuake</span>.new<tt>
</tt>y.add_splitted_tab(<span class="s"><span class="dl">"</span><span class="k">sshs</span><span class="dl">"</span></span>,<span class="s"><span class="dl">"</span><span class="k">ssh username@server.de</span><span class="dl">"</span></span>,<span class="s"><span class="dl">"</span><span class="k">ssh username@server2.de</span><span class="dl">"</span></span>)<tt>
</tt><span class="c"># jeweils in den Arbeitsordner navigieren und svn up</span><tt>
</tt>y.execute(y.last-<span class="i">2</span>,<span class="s"><span class="dl">"</span><span class="k">cd public_html/modules</span><span class="dl">"</span></span>)<tt>
</tt>y.execute(y.last-<span class="i">2</span>,<span class="s"><span class="dl">"</span><span class="k">svn up</span><span class="dl">"</span></span>)<tt>
</tt>y.execute(y.last-<span class="i">1</span>,<span class="s"><span class="dl">"</span><span class="k">cd ~username/public_html/modules</span><span class="dl">"</span></span>)<tt>
</tt>y.execute(y.last-<span class="i">1</span>,<span class="s"><span class="dl">"</span><span class="k">svn up</span><span class="dl">"</span></span>)<tt>
</tt><span class="c"># ein paar irbs zum "rumprobieren"</span><tt>
</tt>y.add_splitted_tab(<span class="s"><span class="dl">"</span><span class="k">Irbs</span><span class="dl">"</span></span>, <span class="s"><span class="dl">"</span><span class="k">irb</span><span class="dl">"</span></span>,<span class="s"><span class="dl">"</span><span class="k">irb</span><span class="dl">"</span></span>)<tt>
</tt><span class="c"># Ein Programmstarter</span><tt>
</tt>y.add_tab(<span class="s"><span class="dl">"</span><span class="k">Progs</span><span class="dl">"</span></span>,<span class="s"><span class="dl">"</span><span class="k">ruby ~zealot64/rubyqt/tray.rb&</span><span class="dl">"</span></span>)<tt>
</tt><tt>
</tt></pre></td>
</tr></table>
tag:www.stefanwienert.net,2008:Post/322010-02-07T19:33:00Z2010-02-07T20:33:33ZAutomatische Silbentrennung / Hyphenation ist online<p>Ich habe heute <a href="/special/hyphen">ein kleines Interface zu einem Silbentrenner</a> geproggt, welches auf zwei Gems (tex/hyphen und text/hyphen) basiert.<br />
Weiter Informationen zu den Quellen auf der Seite. Das Tool ist jetzt jederzeit im Menü verfügbar.<br />
Solange mein Server nicht den Bach runter geht, ist die Nutzung erstmal, auf für automatisierte <span class="caps">GET</span> und <span class="caps">POST</span> Anfragen frei. Um genau zu sein ist genau diese Skriptingmöglichkeit für mich der Anlass gewesen, diese Funktion bereitzustellen.<br />
Damit justify ausgerichtete Blocksätze auch dank automatisierter Silbentrennung wieder hübsch aussehen. :)</p>tag:www.stefanwienert.net,2008:Post/292010-01-20T17:17:00Z2010-01-20T18:17:51ZAktuelle Projekte und Ideen<p>Wenn ich zur Zeit während meines Praktikums etwas Zeit habe, arbeite ich an ein paar Hobbyprojekten, die mir so in letzter so eingefallen sind:</p>
<ul>
<li>Ein (hübsches) (openSource) <strong><acronym title="Dokumenten Management System"><span class="caps">DMS</span></acronym></strong> basierend auf Rails, welches <strong>doc, pdf, odf, text</strong> archiviert, taggt und indexiert, um die Dokumente leichter wiederzufinden
<ul>
<li>mit Paperclip, Ferret als Indexierungsdienst, Verwendung von pdftotext, antiword, odf2text und eventuell tesseract zum <span class="caps">OCR</span> (auch für Bilder und pdfs), rspec <acronym title="Behavior Driven Development"><span class="caps">BDD</span></acronym> Tests für die Modelle</li>
</ul></li>
<li>Einen “Bot”, der die eigene Website abgrast um interne <strong>Linkverbindungen als Graphen</strong> darzustellen, um so lange Wege zu finden und zu eliminieren (Webdesignregel: Redundanz und kurze Wege)
<ul>
<li>Ruby mit mechanize oder evtl. auch einfach “wget -spider” nehmen, graphviz</li>
</ul></li>
<li><strong>Drupal Scaffold</strong> Ein Ruby Skript, welches mir, ähnlich dem scaffold von Rails, ein Datenmodell in ein (MySQL) Schema gießt, und auch gleich einen (einfachen) Adminsetter dazu liefert (eine Seite unter admin/settings/%name mit der Option, ein neues Objekt anzulegen und alte anzuschauen.</li>
</ul>tag:www.stefanwienert.net,2008:Post/262010-01-13T22:09:00Z2010-01-13T23:09:53ZUmgang und Mapping einer Legacy Datenbank mit Ruby (ohne Rails) mit abweichenenden Namenskonventionen mit Active Support<h3>Einleitung/Motivation</h3>
<p>Zur Zeit moechte ich verschiedene <span class="caps">XML</span>-Dialekte aus einem <strong>vorhandenen Datenbankschema</strong> gewinnen, und brauchte dazu ein ordentliches <strong>Objektrelationales Mapping,</strong> wie man es aus <strong>Rails</strong> ja kennt. (Ausprobieren! keine Zeile <span class="caps">SQL</span> mehr notwendig :D). <br />
Allerdings <strong>ohne Rails</strong> sondern in einem einfachen Rubyscript.<br />
Was es dort alles gibt, will ich hier mal kurz exemplarisch vorfuehren.</p>
<h3>Voraussetzung und Datenbankverbindung</h3>
<p>Um ein Legacy relationales Datenmodell mit Ruby schoen zu mappen, ging ich letztens wie folgt vor:</p>
<p>Zu erst Rails (<strong>active_record</strong> ist aber auch ausreichend) installieren, falls noch nicht gemacht (fuer active_record) und <strong>composite primary keys</strong>, das uns wie der Name schon sagt, <strong>zusammengesetzte Primärschlüssel</strong>, welches unser Legacy-Schema mitunter mit sich bringt, bereitstellt.</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">sudo gem install rails composite_primary_keys <tt>
</tt></pre></td>
</tr></table>
<p>Nun können wir uns im ersten Schritt <strong>mit unserer Datenbank verbinden</strong>:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">"</span><span class="k">rubygems</span><span class="dl">"</span></span><tt>
</tt>require <span class="s"><span class="dl">"</span><span class="k">active_record</span><span class="dl">"</span></span><tt>
</tt>require <span class="s"><span class="dl">"</span><span class="k">composite_primary_keys</span><span class="dl">"</span></span><tt>
</tt><tt>
</tt>options = {<span class="sy">:adapter</span> => <span class="s"><span class="dl">'</span><span class="k">mysql</span><span class="dl">'</span></span>,<tt>
</tt> <span class="sy">:database</span> => <span class="s"><span class="dl">'</span><span class="k">databasename</span><span class="dl">'</span></span>,<tt>
</tt> <span class="sy">:username</span> => <span class="s"><span class="dl">'</span><span class="k">username</span><span class="dl">'</span></span>,<tt>
</tt> <span class="sy">:password</span> => <span class="s"><span class="dl">'</span><span class="k">******</span><span class="dl">'</span></span>,<tt>
</tt> <span class="sy">:host</span> => <span class="s"><span class="dl">'</span><span class="k">localhost</span><span class="dl">'</span></span> ,<tt>
</tt> <span class="sy">:encoding</span> => <span class="s"><span class="dl">'</span><span class="k">utf8</span><span class="dl">'</span></span>}<tt>
</tt><span class="co">ActiveRecord</span>::<span class="co">Base</span>.establish_connection(options)<tt>
</tt></pre></td>
</tr></table>
<h3>Definition der Modelle</h3>
<p>Nun kommt dort drunter die Konstruktion der <strong>Modell-Klassen</strong>, die die Tabellen abbilden.</p>
<p>Angenommen wir haben eine <b>Tags</b>, <b>Posts</b>, <b>Posts_Tags</b> und <b>Users</b> Tabelle (in freier Ruby Namenskonvention) mit den folgenden Beziehungen:<br />
Post : Tag = n : m (Jobs_Tags)<br />
Post : User = n : 1</p>
<p>Also ein Post hat eine Anzahl Tags (über “jobs_tags”) und genau einen User.</p>
<p>Da das aber zu leicht wäre, gibt es folgende <strong>Handicaps</strong> :):</p>
<ul>
<li>“Posts” Tabelle heißt “entries_import”, Primaerschluessel (PK) postid, Fremdschlüssel “uid” heißt “nutzer”</li>
<li>“Tags” Tabelle heißt “clouds_import”, PK tagid</li>
<li>“Posts_Tags” Tabelle heisst “clouds_import_lnk”, PK (postid,tagid) <strong>zusammengesetzter Primaerschluessel!</strong></li>
<li>“Users”-Tabelle heißt “users”, mit PK uid</li>
</ul>
<p>(leicht abgeändertes RealWorld Beispiel!)</p>
<p>Tja sieht schon recht messy aus. Aber alles machbar:</p>
<h3>Der Code</h3><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>23<tt>
</tt>24<tt>
</tt>25<tt>
</tt>26<tt>
</tt>27<tt>
</tt>28<tt>
</tt>29<tt>
</tt><strong>30</strong><tt>
</tt>31<tt>
</tt>32<tt>
</tt>33<tt>
</tt>34<tt>
</tt>35<tt>
</tt>36<tt>
</tt>37<tt>
</tt>38<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">class</span> <span class="cl">Post</span> < <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt> set_table_name <span class="s"><span class="dl">"</span><span class="k">entries_import</span><span class="dl">"</span></span> <span class="c"># posts Tabelle</span><tt>
</tt> set_primary_key <span class="s"><span class="dl">"</span><span class="k">postid</span><span class="dl">"</span></span><tt>
</tt> has_many <span class="sy">:tags</span>, <span class="sy">:through</span> => <span class="sy">:taggings</span><tt>
</tt> has_many <span class="sy">:taggings</span>, <span class="sy">:primary_key</span> => <span class="s"><span class="dl">"</span><span class="k">postid</span><span class="dl">"</span></span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">postid</span><span class="dl">"</span></span><tt>
</tt> belongs_to <span class="sy">:user</span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">nutzer</span><span class="dl">"</span></span><tt>
</tt><tt>
</tt><span class="c"># Extra Points! Unser 'Post' hat ein "visible" Attribut, welches </span><tt>
</tt><span class="c"># geradezu nach einem named scope schreit! :)</span><tt>
</tt> named_scope <span class="sy">:visible</span>, <span class="sy">:conditions</span> => {<span class="sy">:visible</span> => <span class="i">1</span>}, <span class="sy">:order</span> => <span class="s"><span class="dl">"</span><span class="k">pubDate desc</span><span class="dl">"</span></span><tt>
</tt><tt>
</tt><tt>
</tt><span class="c">#Extra Points! Tags direkt als (Komma)getrennte Liste zurueckgeben lassen, und </span><tt>
</tt><span class="c"># noch den Tag "Blog" auf jeden Fall ans Ende der Tags haengen</span><tt>
</tt> <span class="r">def</span> <span class="fu">tag_list</span>(sep = <span class="s"><span class="dl">"</span><span class="k">,</span><span class="dl">"</span></span>)<tt>
</tt> (tags.map(&<span class="sy">:name</span>) << <span class="s"><span class="dl">"</span><span class="k">Blog</span><span class="dl">"</span></span>).uniq.join(sep)<tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="r">class</span> <span class="cl">Tag</span> < <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt> set_table_name <span class="s"><span class="dl">"</span><span class="k">clouds_import</span><span class="dl">"</span></span><tt>
</tt> set_primary_key <span class="s"><span class="dl">"</span><span class="k">tagid</span><span class="dl">"</span></span><tt>
</tt> has_many <span class="sy">:jobs</span>, <span class="sy">:through</span> => <span class="sy">:taggings</span><tt>
</tt> has_many <span class="sy">:taggings</span>, <span class="sy">:primary_key</span> => <span class="s"><span class="dl">"</span><span class="k">tagid</span><span class="dl">"</span></span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">tagid</span><span class="dl">"</span></span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="r">class</span> <span class="cl">Tagging</span> < <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt> set_table_name <span class="s"><span class="dl">"</span><span class="k">clouds_import_lnk</span><span class="dl">"</span></span><tt>
</tt> set_primary_keys <span class="sy">:jobid</span>, <span class="sy">:tagid</span> <span class="c"># Zusammengesetzter Primaerschluessel</span><tt>
</tt> belongs_to <span class="sy">:job</span>, <span class="sy">:primary_key</span> => <span class="s"><span class="dl">"</span><span class="k">postid</span><span class="dl">"</span></span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">postid</span><span class="dl">"</span></span><tt>
</tt> belongs_to <span class="sy">:tag</span>, <span class="sy">:primary_key</span> => <span class="s"><span class="dl">"</span><span class="k">tagid</span><span class="dl">"</span></span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">tagid</span><span class="dl">"</span></span><tt>
</tt><span class="r">end</span><tt>
</tt><tt>
</tt><span class="r">class</span> <span class="cl">User</span> < <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt>
</tt> set_primary_key <span class="s"><span class="dl">"</span><span class="k">uid</span><span class="dl">"</span></span><tt>
</tt> set_table_name <span class="s"><span class="dl">'</span><span class="k">users</span><span class="dl">'</span></span><tt>
</tt> has_many <span class="sy">:jobs</span>, <span class="sy">:foreign_key</span> => <span class="s"><span class="dl">"</span><span class="k">nutzer</span><span class="dl">"</span></span>, <span class="sy">:primary_key</span> => <span class="s"><span class="dl">"</span><span class="k">uid</span><span class="dl">"</span></span><tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
<p>Fertig!<br />
Nun können wir in althergebrachter Rails Manier extrem bequem auf unsere Modelle wie folgt zugreifen:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><tt>
</tt>posts = <span class="co">Post</span>.all<tt>
</tt>posts.first.tags <span class="c"># gibt uns die tags zurück</span><tt>
</tt>post = <span class="co">Post</span>.find(<span class="sy">:first</span>, <span class="sy">:order</span> => <span class="s"><span class="dl">"</span><span class="k">...</span><span class="dl">"</span></span>)<tt>
</tt>post.user.name<tt>
</tt><tt>
</tt><span class="c"># oder auch named scopes (siehe oben)</span><tt>
</tt><span class="co">Post</span>.visible.first.tag_list<tt>
</tt></pre></td>
</tr></table>
<p>usw. Wirklich eine Wohltat ;)</p>
<p>Natürlich kann man in seinen Modellen noch Methoden definieren, die uns den Zugriff noch erleichtern und unser Modell um Funktionalität erweitert und damit unsere Controller und Views nicht zumuellt.</p>
<h3>Bonus: <span class="caps">XML</span> Builder</h3>
<p>Wie man jetzt damit einen <span class="caps">XML</span>-Dialekt (z.B. auch <span class="caps">RSS</span>) baut, ist recht einfach, dank des <span class="caps">XML</span> Builder Gems (Das bei Rails eigentlich auch schon dabei sein sollte).<br />
Ich will hier nur ganz kurz teasern, ansonsten.. Google ist dein Freund:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt>5<tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt>15<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">"</span><span class="k">rubygems</span><span class="dl">"</span></span><tt>
</tt>require <span class="s"><span class="dl">"</span><span class="k">builder</span><span class="dl">"</span></span><tt>
</tt><tt>
</tt>xml = <span class="co">Builder</span>::<span class="co">XmlMarkup</span>.new( <span class="sy">:target</span> => <span class="gv">$stdout</span> , <span class="sy">:indent</span> => <span class="i">1</span> )<tt>
</tt>xml.instruct!<tt>
</tt>xml.rss <span class="r">do</span> <tt>
</tt><span class="c"># oder: xml.tag!("rss") do sinnvoll falls unser Tag nicht nur aus Kleinbuchstaben besteht</span><tt>
</tt> xml.channel <span class="r">do</span><tt>
</tt> <span class="r">for</span> item <span class="r">in</span> <span class="co">Post</span>.visible<tt>
</tt> ...<tt>
</tt> ... item.title ...<tt>
</tt><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt></pre></td>
</tr></table>
tag:www.stefanwienert.net,2008:Post/242009-12-30T18:48:00Z2009-12-30T19:48:54ZTool fuer externe/interne Link-Analyse mit rel=nofollow<p>Fuer ein aktuelles Projekt wurde eine <b>Linkanalyse</b>, insbesondere der ausgehenden Links gewuenscht. Insbesondere die Verwendung des <span class="caps">SEO</span> Buzzwords “rel=nofollow” sollte dabei aufgezeigt werden. Was lag naeher als schnell in Ruby mit Zuhilfenahme des hpricot Gems ein kleines Skript dafuer zu bauen?</p>
<p>Das Skript gruppiert die Links in die drei Kategorien “Internal, External with nofollow, External without nofollow”. Hintergrund ist hierbei, dass das nofollow Attribut Suchmaschinen anweist, den verlinkten Seiten bei der Berechnung ihres Pagerankes diesen Link zu ignorieren. Mehr Infos in der <a href="http://de.wikipedia.org/wiki/Nofollow">Wikipedia</a>. Anmerken moechte ich noch, dass die Verwendung des Attributes umstritten ist, ich persoenlich finde es relativ ueberfluessig; Warum verlinkt man eine Seite, nur um den Suchmaschinen zu sagen, “hey, ich hab jetzt aber nicht auf die Seite verlinkt”.</p>
<p>Dank <span class="caps">XML</span> Builder ist dann auch ein ordentlicher <span class="caps">XML</span> Export kein Problem, und laesst sich so mit z.B. Firefox bequem navigieren.</p>
<p>Unter <a href="/linkcheck/link_check_form">linkcheck/link_check_form</a> findet ihr ein minimalistisches Eingabeformular. Das Ganze laesst sich natuerlich auch bequem mit <span class="caps">GET</span> ansteuern :).</p>tag:www.stefanwienert.net,2008:Post/202009-12-18T16:13:00Z2009-12-18T17:13:05ZCode Katas - Training für den Software-Entwickler<p>Unter <a href="http://katas.softwarecraftsmanship.org/">http://katas.softwarecraftsmanship.org/</a> habe ich ein paar interessante Kata-Screencasts, vornehmlich in Ruby, aber auch in “Exoten” wir Erlang oder Lua gefunden.</p>
<p>Was ist ein Kata? Schonmal einen “Speedrun” von einem Computerspiel gesehen?</p>
<p>Hierbei geht es darum, ein bestimmtes (meist akademisches) Softwareproblem, unter Zeitdruck zu schaffen, und sich durch Wiederholung zu verbessern. Bei softwarecraftsmannship habe ich bisher nur Test-driven-development gesehen, d.h. es wird immer erst der Test geschrieben, und dann der minimale Code, der den Test erfüllt. Nachdem der Test erfolgreich war, wird refaktorisiert. Das ganze wird iterativ solange wiederholt, bis alle Features erfüllt sind.</p>
<p>Sehr interessant sind “String Calculator” in Ruby und Erlang unter vim mit rspec als Testframework :>.</p>tag:www.stefanwienert.net,2008:Post/192009-12-16T21:37:00Z2009-12-16T22:37:31ZPHP - Die beste Wahl für's Web?<p>Eines vorneweg: <span class="caps">PHP</span> war mein Einstieg in die Webprogrammierung. Die ersten Schritte haben, aufgrund der C-ähnlichen und mir damit bekannten Syntax, sogar sehr Spaß gemacht.</p>
<p>Nicht ganz ausschweigen sollte man den Fakt, dass eine Skriptsprache ganz gleich welcher Rubrik natürlich nicht das Allheilmittel jeglicher Softwareprojekte ist, weshalb ich mich hier ganz klar auf Sprachen für (private und kleinkommerzielle) Webentwicklung beschränken möchte.</p>
<h3>Story</h3>
<p>Wenn man wie ich von <span class="caps">PHP</span> kommt, ist bei Ruby und Rails vieles am Anfang ungewöhnlich, und es braucht seine Zeit, bis man sich an den Fakt, das <b>alles</b> ein Objekt ist, gewöhnen muss. Dies schafft aber auch erstklassige Möglichkeiten, Programmtext effizient und damit übersichtlich zu gestalten.</p>
<p>Im Gegensatz zu <span class="caps">PHP</span> wo ich bei trivialsten Dingen jedesmal das Rad neu erfinden muss (Ich denke nur an DateTime Handling, fortgeschrittene Stringfunktionen) hat Rails und Ruby eine sehr ausdrucksstarke Bibliothek dabei.<br />
Schön finde ich <a href="http://www.feld.com/wp/archives/2006/10/php-vs-ruby.html">diese Grafiken</a>. Hiernach wurden für <span class="caps">PHP</span>-Projekte deutlich mehr Line of Codes am Gesamtkuchen gezählt, die meiste Zunahme an Projekten überhaupt gegeben hat. Also man für eigentlich alle Projekte unter <span class="caps">PHP</span> eine Wagenladung Code mitbringen muss. <acronym title="Don't repeat yourself -- ALLES was man wiederverwenden könnte, wird ausgelagert"><span class="caps">DRY</span></acronym> <span class="caps">FTW</span>.<br />
Auch die extrem bunte Bibliothek von <span class="caps">PHP</span>, die scheinbar über die Jahre aus C-Sprachen zusammengeklaut wurde, mit total uneinheitlichen Verhalten von Funktionen: usort verändert sein Argument und gibt nichts zurück, str_replace belässt es und gibt das Ergebnis zurück.</p>
<h3>Die Syntax — Showdown</h3>
<p>Der Fakt der C-Abstammung ist für mich einer der größten Kritikpunkte, denn intuitiv ist was anderes (strstr zum Finden eines Strings…, bei Ruby: find).<br />
Wenn ich mal wieder ein etwas größeres Modul in Drupal beginn, vergesse ich so manches mal ein “;”. <br />
Das nervt und ist absolut unnötigt. Mehr als eine Anweisung ist nur für Obfascuation-Wettbewerbe geeignet. Desweiteren ist das “;” trotzdem unter Ruby <b>optional</b> nutzbar.</p>
<p>Warum diese extreme Anlehnung der Syntax an den C-Sprachen? Ist sie für betriebssystemnahe Anwendungsfälle recht angebracht, da minimal abstrakt, führt sie beim Anwendungsfallszenario “Webentwicklung” doch mehr Hürden denn Erleichterungen.</p>
<p>Warum wie ein Computer denken? Wenn ich doch wie ein Mensch denken kann? Für ein kleines µ mehr an Performance? Dafür mit einer deutlich angestiegenen Fehleranfälligkeit, teilweise unüberschaubaren Programmfluss und einer grottigen Wartbarkeit?</p>
<p>Klar ist es toll, wenn man vorher C, C++, Java oder was auch immer programmiert hat, kurz mal <span class="caps">PHP</span> sieht, und denkt “Hey, das ist ja genau das gleiche!”. Auch ich hatte diesen Aha-Effekt (Im Rückblick nichts, gegen den Aha-Effekt, den ich z.B. bei der ersten Nutzung der <acronym title="Eine Live-Shell mit Autocomplete im Kontext der Anwendung. Das heißt, man kann dort schön seine Abfragen ausprobieren, neue Nutzer anlegen usw.">script/console</acronym>, dem ersten <acronym title="Automatisches Erstellen von Formularen, DB-Tabellen und Programmlogik">scaffold</acronym> oder der Validate <—> Formularfehlermeldung hatte :D)</p>
<p><span class="caps">PHP</span> ist in meinen Augen als Websprache absolut ungeeignet.</p>
<p>Viele gute <span class="caps">PHP</span>-Frameworks wie CakePHP, Zend oder auch auch in erweiterter Bedeutung Drupal, können meiner Ansicht nach nicht über diesen Aspekt hinwegtäuschen.</p>
<p>Hier ein paar Auszüge meiner Lieblingshassobjekte:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">htmlspecialchars <---> h<tt>
</tt>$this-> <---> Warum muss man diese <tt>
</tt>Redundanz innerhalb einer Klasse mit sich herumschleppen? <tt>
</tt>Warum "weiß" die Klasse nicht direkt über ihre Methoden?<tt>
</tt></pre></td>
</tr></table>
<p>Weitere Vorteile ergeben sich aus der kompletten Objektorientierung:</p><table class="CodeRay"><tr>
<td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt>
</tt>2<tt>
</tt></pre></td>
<td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">str_replace("a","b","Hallo"); <---> "Hallo".gsub("a","b")<tt>
</tt>preg_match("/../",$source,$target); <---> target = /.../.match(source)<tt>
</tt></pre></td>
</tr></table>
<p>Im Endeffekt ist <span class="caps">PHP</span> sowas von laberlastig und ausdrucksschwach, dass ich z.B. bei der Entwicklung von Drupal-Modulen ohne Snippets überhaupt nicht mehr klarkommen würde. Klar liegt es vielleicht auch ein stückweit an Drupal, nichsdestotrotz bietet die aufgepfropfte Objektorientierung auch hier keine Erleichtung.</p>
<blockquote>
<p>But it’s a complex language that contains a lot of advanced idioms which will be very hard for <span class="caps">PHP</span> and Visual Basic programmers to absorb.</p>
</blockquote>
<blockquote>
<p>Sometimes, too much magic is too much magic, and it can definitely be the case that the flow of code is too direct or too clever to be understandable by regular developers. Developers were able to do the jump from imperative to object-oriented programming, but it was a hard fight.</p>
</blockquote>
<a href="http://beust.com/weblog/archives/000382.html">Quelle</a>
<p>Die vielerorts kritisierte scheinbar komfortable Konvertierung von <span class="caps">PHP</span> hat auch bei mir schon zu so manchen erstaunlichen Programmverhalten geführt.</p>
<p>Durch Rails habe ich aber auch die korrekte Benennung meiner Modelle und Datenbanktabellen gelernt. Also wenn ich eine Nutzer-Tabelle habe, dann heißt sie “users”, der Primärschlüssel “id”, ein Nutzerfremdschlüssel einer anderen Tabelle würde “user_id” heißen.<br />
Warum? Bei Rails wird man für die korrekte Benennung “belohnt”, indem einige Dinge komplett automatisch passieren, sollte man sich an die Konventionen gehalten haben. Dazu zählt: Benutzung von “partials” (Also eines View-Code-Schnipsels, dass für jedes Item eines Objekts einmal ausgeführt wird),</p>
<p>Manch einer mag anführen, dass Syntax Geschmackssache ist, und bei der Bewertung einer Sprache nur einen Teilaspekt darstellen sollte. Dem stimme absolut nicht zu. Je mehr Sonderzeichen ( “{ } ; $”) im Textfluss sind, desto schwerer lässt es sich lesen.</p>
<h3>Rails Fanboy for life?</h3>
<p>Auch bei Ruby oder Rails ist (natürlich wie immer in meinen Augen) nicht alles perfekt: neidisch blicke ich auf die Einrücksemantik von Python, spart sie mir doch die Blockschlüsselwörter. Oder das von Haus aus installierte “erb” finde ich durch “haml” erst erträglich gemacht :).</p>
<p>Auch habe ich ständig das Gefühl, dass ich erst einen Bruchteil der Sprache voll ausschöpfe. Insbesondere die funktionalen Aspekte wie procs habe ich bisher nur selten verwendet.<br />
Auch die sehr mächtigen Testmöglichkeiten durch gems wie rspec, cucumber oder silenium habe ich bisher eher akademisch benutzt.</p>
<p>In vielen Foren habe ich auch von einem fast schon spürbaren Hass auf Rails-Nutzer bemerkt; da wird von “Latte-Machiatto schlürfende” “Fanboys” geredet, die nur “oberflächliche” Anwendungen programmieren [können]. Kein Vergleich mit JavaEE, C, whatsoever. Das mag sein, dass ein Railsprojekt nicht unbedingt als System für eine Forbes 100 Firma geeignet ist, aber für sehr viele Anwendungsfälle, insbesondere bei überschaubaren Websites, mit nicht ganz 100% mainstreammäßigen also individuell Anforderungen (“Blog”, also Wordpress, Mini social Community Drupal, usw) ist es in vielerlei Hinsicht eine bessere Wahl als… <span class="caps">PHP</span>. <br />
Schön gesagt von xaviershay auf github:</p>
<blockquote>
<p>No ugly <span class="caps">PHP</span> Stylings burning your eyeballs.</p>
</blockquote>
<a href="http://github.com/xaviershay/enki">Quelle</a>
<p>Ganz ausgelassen habe ich hierbei Django/Python, dass ganz oben auf meiner Liste der zu begutachtenden Frameworks steht.</p>
<h3>Fazit?</h3>
<p>Ja ich bin subjektiv. <br />
Vielleicht liegt es an dem gut gemachten Screencast von Ryan Bates und teach-me-code? Oder der per Plugins (wirble, hirb) aufgemöbelten Liveshell irb bzw. script/generate, die mir so manchen “Ausprobier”-Lauf erspart hat (Kein Vergleich mit php -a )? Oder an dem teils humorig geschrieben Buch von O’Reilly? Oder an der Wahl der Namen? (“god” das Monitoring Tool, “sass:Syntactically awesome Stylesheets”, “<span class="caps">YAML</span>”: Yet another markup language", hpricot also wie Aprikose…)? <br />
<b>Ruby/Rails verbreitet einfach eine andere Grundstimmung</b> – Die Leute haben Spaß beim Programmieren!</p>tag:www.stefanwienert.net,2008:Post/132009-11-24T15:59:00Z2009-11-24T16:59:28ZRuby/ScrAPI-RSS-Interface für 4players.de<p>In den letzten Tagen wollte ich mal die <a href="http://www.4players.de/4players.php/tests/PC-CDROM/Alle/Alle/datum/0/1.html">PC-Tests von 4players.de</a> als <span class="caps">RSS</span>-Feed abonnieren, musste aber leider feststellen, dass man nur PC-Artikel als ganzes abonnieren kann (Also inklusive aller Previews und was weiß ich alles), die mir zu umfangreich sind.<br />
Um einen guten Überblick über aktuelle (gute) Spiele zu erhalten, und vielleicht sogar gleich Wertung + Genre im Blick zu haben, lag es für mich also nahe, ein kleines <span class="caps">RSS</span>-Interface dafür zu bauen, was letztlich in einem Crawler/Parser + <span class="caps">RSS</span> Ausgabe resultiert.</p>
<p>Motiviert dazu hat mich eine <a href="http://railscasts.com/episodes/173-screen-scraping-with-scrapi">halbwegs aktuelle Railscast-Episode zum Gem ScrAPI</a>, welches es stark erleichtert, per <span class="caps">CSS</span>-Pfad Daten einer Website abzufragen.<br />
Dazu sinnvoll ist das Firefox-Addon-Addon FireQuark für Firebug, welches sich mit <span class="caps">CSS</span>-Pfad als Alternative zu <span class="caps">XPATH</span> beschäftigt.</p>
<p>Das eigentliche Problem nach dem Herausfinden der expliziten <span class="caps">CSS</span>-Pfade war, das ganze für Umlaute, also <span class="caps">UTF</span>-8 kompatibel zu gestalten.<br />
4players zeichnet seine Website zwar als <span class="caps">UTF</span>-8 aus, und mit einem normalen Browser gibt es keine Probleme, aber wenn ich z.B. mit wget (oder halt scrAPI) die Website manuell hole, erhalte ich LATIN1 kodierten Text. Da ScrAPI mir ersichtlich leider keine direkte Unterstützung von Kodierungskonvertierungen besitzt, musste ich dieses also händisch tun.</p>
<p>Den gesamten Quelltext gibt es unter <a href="http://stefanwienert.net/~zealot128/dokuwiki/doku.php?id=tutorial:4players-ruby-feedinterface">http://stefanwienert.net/~zealot128/dokuwiki/doku.php?id=tutorial:4players-ruby-feedinterface</a>. Falls jemand direktes Interesse an dem Feed hat, kann <a href="http://site.stefanwienert.net/rss/fourplayers.rss">ihn hier abonnieren</a>.</p>
<p><strong>Anmerung zu <span class="caps">CURB</span></strong>, Curb ist das Ruby-Binding für <span class="caps">CURL</span>, zur Installation des Gems wird also eine libcurl benöntigt. <br />
Unter Ubuntu also eines der libcurl Pakete installieren. Leider kann ich nicht mehr genau sagen welche, ich glaube es war eine der “libcurl-dev” oder “libcurl4-dev” Pakete :).</p>tag:www.stefanwienert.net,2008:Post/72009-10-22T15:04:00Z2009-10-22T17:04:01ZGedit Syntax Erweiterungen - YAML, SASS, Moinmoin-Wiki, HAML<p><a href="http://groups.google.com/group/haml/msg/b5100d80d9182c71">hier</a> gibts eine Anleitung, wie man gedit dazu bringt, <span class="caps">SASS</span>, <span class="caps">HAML</span> und <span class="caps">YAML</span> zu unterstützen.</p>
<p><a href="http://forum.ubuntuusers.de/topic/moinmoin:-syntax-highlighting-fuer-gedit/">dort</a> das gleiche für MoinMoin Wiki-Syntax, am Besten zusammen mit der Firefox Erweiterung “It’s all Text”, welche ein kleines “Edit” – Feld unter jeder Textarea macht, um diese bequem im externen Editor seiner Wahl zu bearbeiten.</p>