<?xml version="1.0" encoding="utf-8"?> 
<?xml-stylesheet href="stylesheet.xsl" type="text/xsl" media="screen"?>

<rdf:RDF 
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns="http://purl.org/rss/1.0/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:admin="http://webns.net/mvcb/"
  xml:lang="ja">

  <channel rdf:about="http://feed.feedforce.jp/f2892/index.rdf">
    <title>FFTT</title>
    <link>http://tech.feedforce.jp/</link>
    <image rdf:resource="http://feed.feedforce.jp/f2892/logo.gif" />
    <description>社内の勉強会資料やメンバーが適当に思ったことなどを公開をしています。</description>
    <admin:generatorAgent rdf:resource="www.rsssuite.jp" />
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_2346423_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_2254609_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_2200528_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1740085_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1670715_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1638902_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1590812_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1563962_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1203602_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1136619_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1088535_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_1068064_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_968514_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_928070_2892.html" />
        <rdf:li rdf:resource="http://feed.feedforce.jp/item_30880_885652_2892.html" />
      </rdf:Seq>
    </items>
  </channel>
  <image rdf:about="http://feed.feedforce.jp/f2892/logo.gif">
    <title>FFTT</title>
    <url>http://feed.feedforce.jp/f2892/logo.gif</url>
    <link>http://tech.feedforce.jp/</link>
  </image>
  <item rdf:about="http://feed.feedforce.jp/item_30880_2346423_2892.html">
    <title>Jasmineでテスティング</title>
    <link>http://feed.feedforce.jp/item_30880_2346423_2892.html</link>
    <dc:date>2010-10-08T18:39:37+09:00</dc:date>
    <description>今年のRubyKaigi 2010で、Sarah MeiさんによるJasmineというJavaScriptのテスティングフレームワークの紹介発表がありました(発表時はRCでしたが、先日(2010年9月14日)に無事バージョン1.0がリリースされています)。
今回はこの Jasmine を紹介したいと思います。</description>
    <content:encoded><![CDATA[<p>今年の<a href="http://rubykaigi.org/2010/">RubyKaigi 2010</a>で、<a href="http://www.sarahmei.com/blog/">Sarah Mei</a>さんによる<a href="http://pivotal.github.com/jasmine/">Jasmine</a>というJavaScriptのテスティングフレームワークの紹介発表がありました(発表時はRCでしたが、先日(2010年9月14日)に無事バージョン1.0がリリースされています)。</p>
<p>今回はこの Jasmine を紹介したいと思います。</p>
<h1>特徴</h1>
<p>Jasmineは以下のような特徴を持ったテスティングフレームワークです。</p>
<ul>
<li>JavaScript自身でJavaScriptをテスト可能</li>
<li><a href="http://rspec.info">RSpec</a>風の記述が行える</li>
<li>スタンドアローン版とRubyGem版</li>
</ul>
<h2>JavaScript自身でJavaScriptをテスト可能</h2>
<p>テスト用に専用の言語・フォーマットを使う必要はありません。</p>
<h2>RSpec風の記述が行える</h2>
<p>全体の構造は、RSpecのユーザーにはお馴染のdescribe や it という記法で記述します。<br />
Rubyのブロックほど簡潔には書けませんが、Functionオブジェクトを使ってそれらしく書くことが出来ます。</p>
<h3>例</h3>
<pre>describe("sprintf", function() {
  it("should return a string on success", function() {
  });
});</pre>
<h2>スタンドアローン版とRubyGem版</h2>
<p>スタンドアローン版は</p>
<ul>
<li>jasmine本体</li>
<li>テスト実行用のHTML(とその構成ファイル)</li>
<li>サンプルプログラムとテスト</li>
</ul>
<p>RubyGem版は加えて</p>
<ul>
<li>Rails2プロジェクト用ジェネレータ</li>
<li>Rails2プロジェクト以外への組み込み時に使用するコマンドラインツール(Rails3でも使用)</li>
<li>Rakeタスク</li>
<li>Selenium連携</li>
</ul>
<p>が含まれます。</p>
<h1>実行</h1>
<h2>スタンドアローン版の場合</h2>
<p>スタンドアローン版は付属するSpecRunner.html をブラウザで開くと実行できます。</p>
<p>付属のサンプルを実行した例</p>
<div><a href='http://tech.feedforce.jp/wp-content/uploads/2010/09/specrunner.png' title='SpecRunner.htmlをブラウザで開く'><img src='http://tech.feedforce.jp/wp-content/uploads/2010/09/specrunner.thumbnail.png' alt='SpecRunner.htmlをブラウザで開く' /></a></div>
<p>通常は結果のサマリー部分(5 specs, 0 failuresのところ)のみが表示されますが、<br />
上部の Show passed にチェックを入れてあるので、パスしたテストの内容も表示されています。</p>
<p>対象となる実装コード</p>
<pre> &lt;script type="text/javascript" src="src/sprintf.js"&gt;&lt;/script&gt;</pre>
<p>およびspecコード</p>
<pre>&lt;script type="text/javascript" src="spec/sprintf_spec.js"&gt;&lt;/script&gt;</pre>
<p>は、SpecRunner.html 内に直接追加します。</p>
<p>なお、日本語の出力をしたい場合は、meta要素によるcharset指定を使いましょう。</p>
<h2>gem版の場合</h2>
<h3>準備</h3>
<p>若干準備が必要です。</p>
<ul>
<li>script/generate jasmine (Rails 2の場合)</li>
<li>bundle exec jasmine init (Rails 3の場合)</li>
<li>jasmine init (その他の場合)</li>
</ul>
<p>いずれの場合でも</p>
<ul>
<li>サンプル(実装とspec)</li>
<li>Jasmine用設定ファイル(spec/javascripts/support/*)</li>
<li>Rakeタスク(lib/tasks/jasmine.rake)</li>
</ul>
<p>などが作られます。</p>
<p>テスト対象ファイルは spec/javascripts/support/jasmine.yml に書かれた</p>
<pre>src_files:
  - public/javascripts/**/*.js
spec_files:
  - **/*[sS]pec.js</pre>
<p>のようなファイル名パターンに従って自動的に集められます。</p>
<h3>サーバ経由での実行</h3>
<p>Rakeタスク</p>
<pre>rake jasmine</pre>
<p>を実行すると、ポート8888でテストサーバが起動します。<br />
この状態で http://localhost:8888/ にアクセスすると、スタンドアローン版と同様のテストページを表示できます。</p>
<h3>CIでの実行</h3>
<p>CI環境からRakeタスク jasmine:ci を実行します。ブラウザが開き、Selenium RCでテストが行われます。</p>
<div><a href='http://tech.feedforce.jp/wp-content/uploads/2010/09/selenium.png' title='RakeからSelenium RCを使って実行'><img src='http://tech.feedforce.jp/wp-content/uploads/2010/09/selenium.thumbnail.png' alt='RakeからSelenium RCを使って実行' /></a></div>
<h1>Jasmineの構成要素</h1>
<h2>describe, it</h2>
<p>前述の通り、describe と it が基本構造になります。</p>
<p>describeで作られる構造を Suite、it で作られる構造を Spec と呼びます(RSpecではそれぞれ ExampleGroup(Context) と Example)。</p>
<h2>expect</h2>
<p>RSpecの 式.should の代わりに expect(式) を使います。</p>
<h2>マッチャー</h2>
<p>expect(式) に対してマッチャーを呼び出してチェックを行います。</p>
<pre>expect("Name: %s Age: %d".sprintf("John Doe", 42).toEqual("Name: John Doe, Age: 42");</pre>
<h3>マッチャーの例</h3>
<ul>
<li>.toEqual 同値かどうか。</li>
<li>.toBe 同じオブジェクトかどうか。</li>
<li>.toMatch 正規表現に一致するか。</li>
<li>.toBeDefined undefinedでないか。</li>
<li>.toBeNull nullか。</li>
<li>.toBeTruthy / .toBeFalsy true / false か。</li>
<li>.toContain 配列や文字列に含むか。</li>
<li>.toBeLessThan / .toBeGreaterThan 大小比較。</li>
<li>.toThrow 例外を発生させるか。</li>
<li>.not expectとマッチャーの間に書き、条件を否定にします。</li>
</ul>
<p>あらたにマッチャーを追加することも可能です。</p>
<h2>スパイ</h2>
<p>オブジェクトのメソッドの呼び出しをスパイを使って監視することが出来ます。</p>
<pre>spyOn(x, 'method')</pre>
<p>とすると、x.method (Functionオブジェクト) に成り代わるスパイが作られます。</p>
<p>スパイが呼び出されたときの行動に関しては、いくつかのバリエーションがあります。</p>
<ul>
<li>spyOn(x, &#8216;method&#8217;).andReturn(arguments) 呼び出しに対して arguments を返す。</li>
<li>spyOn(x, &#8216;method&#8217;).andThrow(exception) 呼び出しに対して例外を発生させる。</li>
<li>spyOn(x, &#8216;method&#8217;).andCallFake(function) 呼び出しに対して、代わりに function を呼び出す。</li>
<li>spyOn(x, &#8216;method&#8217;).andCallThrough() x.method(&#8230;) そのまま本来のメソッド呼び出しを行わせる。</li>
</ul>
<p>テストコードを評価した後、スパイに対して</p>
<pre>expect(x.method)</pre>
<p>として、専用のマッチャーを使って結果を報告させることが出来ます。</p>
<ul>
<li>.toHaveBeenCalled() 呼ばれたか。</li>
<li>.toHaveBeenCalledWith(arguments) 引数 arguments を伴って呼ばれたか。</li>
<li>通常の expect 時と同じく、 .not で否定することも出来ます。</li>
</ul>
<p>スパイはされたメソッドは以下のプロパティを持ちます。</p>
<ul>
<li>.callCount 呼び出し回数</li>
<li>.mostRecentCall.args 直近の呼び出し時の引数</li>
<li>.argsForCall[i] i番目の呼び出し時の引数</li>
</ul>
<h2>非同期</h2>
<p>runsとwaitsForを使って非同期呼び出しを制御することが出来ます。<br />
AJAXコードの挙動を調べるために活用できます。</p>
<h3>runs(function)</h3>
<p>functionを実行します。</p>
<p>複数のrunsは順番に実行されます。</p>
<h3>waitsFor(function, message, timeout)</h3>
<p>functionがtrueを返す、またはtimeout(単位: ミリ秒)の時間経過を待ちます。(標準では10msec間隔)<br />
trueを返さずにtimeout経過してしまった場合はSpecの実行を中止し、messageを返します。</p>
<h3>例</h3>
<p>イメージしづらいので、スタンドアローン版でサンプルコードを書いてみました。</p>
<p>以下のファイル src/demo.js はTwitterのPublic Timelineを取得するものです。jQueryを使用しています。<br />
loadメソッドがTwitterのPublic Timeline APIを非同期で呼び出し、resultメソッドで結果の配列を取得することが出来ます。取得できるまではresultは長さゼロの配列。エラー処理はしていません。</p>
<pre>function PublicTL() {
  var url = 'http://api.twitter.com/1/statuses/public_timeline.json?callback=?';
  var tl = [];
  return {
    result: function result() {
      return tl;
    },
    load: function load() {
      tl = [];
      $.getJSON(url, {}, function(json) {
        tl = json;
      });
    },
  };
};</pre>
<p>Spec は、 spec/demo_spec.js に以下のように1つだけ書きました。Public Timelineは20件のデータが取れるはずなので、それをテストしています。</p>
<pre>describe('PublicTL', function() {
  var tl = new PublicTL();
  it('should get the public TL', function() {
    tl.load();
    waitsFor(function() {
      return tl.result().length &gt; 0;
    }, 'timeout', 1000);
    runs(function() {
      expect(tl.result().length).toEqual(20);
    });
  });
});</pre>
<p>SpecRunner.html に以下のようなscript要素を加えてブラウザで開きます。</p>
<p>Google Library APIを使用して jQuery をロード</p>
<pre>&lt;script type="text/javascript" src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;google.load("jquery", "1.4.2");&lt;/script&gt;</pre>
<p>実装ファイル</p>
<pre>&lt;script type="text/javascript" src="src/demo.js"&gt;&lt;/script&gt;</pre>
<p>Spec</p>
<pre>&lt;script type="text/javascript" src="spec/demo_spec.js"&gt;&lt;/script&gt;</pre>
<h2>その他</h2>
<h3>beforeEach, afterEach</h3>
<p>各Spec(it) ごとに毎回評価される関数を宣言します。RSpec の before(:each) / after(:each) に相当します。</p>
<p>RSpecの before(:all) / after(:all)に相当するものはありません。</p>
<h3>Suiteのネスト</h3>
<p>Suite(describe) はネストさせることができます。</p>
<h3>スキップ</h3>
<p>describe / it それぞれを xdescribe / xit と書き換えることで、<br />
その配下の Suite / Spec の実行をスキップすることが出来ます。<br />
RSpec の pending に類似した機能です。</p>
<h1>まとめ</h1>
<ul>
<li>Jasmineは、RSpecに似通った記法を使ってJavaScriptのテスティングを行うフレームワークです。</li>
<li>マッチャーにより、さまざまな条件をテストすることが出来ます。カスタマイズも可能です。</li>
<li>非同期な動作もテストすることが出来ます。</li>
<li>CIに統合することが可能です。</li>
</ul>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_2254609_2892.html">
    <title>Homebrew のご紹介</title>
    <link>http://feed.feedforce.jp/item_30880_2254609_2892.html</link>
    <dc:date>2010-09-10T17:51:31+09:00</dc:date>
    <description>9/3 の勉強会で Homebrew について発表したので、その内容を公開します。
man や公式ドキュメントの抜粋を和訳した程度の内容ですが、何かの助けになれば幸いです。
2011/02/23 追記: 草稿的に書いた私的なwiki ページを残してありますが、同一人(koshigoe)によるものです。</description>
    <content:encoded><![CDATA[<div>
<p>9/3 の勉強会で Homebrew について発表したので、その内容を公開します。</p>
<p>man や公式ドキュメントの抜粋を和訳した程度の内容ですが、何かの助けになれば幸いです。</p>
<p><b>2011/02/23 追記</b>: 草稿的に書いた私的な<a href="http://w.koshigoe.jp/study/?%5Bsystem%5D%5Bosx%5D+Homebrew+%BB%C8%A4%A4%CA%FD%A5%E1%A5%E2" target="_blank">wiki ページ</a>を残してありますが、同一人(koshigoe)によるものです。</p>
</div>
<p> <a href="http://tech.feedforce.jp/homebrew.html#more-126" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_2200528_2892.html">
    <title>おさらいRDoc</title>
    <link>http://feed.feedforce.jp/item_30880_2200528_2892.html</link>
    <dc:date>2010-08-24T18:15:17+09:00</dc:date>
    <description>Rubyエンジニアのみなさん、RDoc書いてますか？「人が書いたRDocは読むけど、自分ではあまり書かない&amp;#8230;」という方もいらっしゃるかもしれません。そこで今回はRDocを書くための要点について整理してみました。</description>
    <content:encoded><![CDATA[<p>Rubyエンジニアのみなさん、RDoc書いてますか？「人が書いたRDocは読むけど、自分ではあまり書かない&#8230;」という方もいらっしゃるかもしれません。そこで今回はRDocを書くための要点について整理してみました。</p>
<p> <a href="http://tech.feedforce.jp/review_rdoc.html#more-114" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1740085_2892.html">
    <title>Macアプリのパッケージ作成方法</title>
    <link>http://feed.feedforce.jp/item_30880_1740085_2892.html</link>
    <dc:date>2010-04-01T11:22:09+09:00</dc:date>
    <description>MacOSXのアプリケーションはコピーしてインストールが済んでしまうものも多いですが、動作するシステム条件があったり、複数の製品を一度にインストールしたい場合などはインストーラからのインストールが便利です。
今回はインストーラからインストールするために必要となるパッケージの作成方法について説明します。</description>
    <content:encoded><![CDATA[<p align="justify"><span class="Apple-style-span" style="font-family: Times; line-height: normal"> </span></p>
<p style="padding: 0.5em; background-color: #ffffff; font: 1em/1.3em Georgia,'Times New Roman',Times,serif" align="justify">MacOSXのアプリケーションはコピーしてインストールが済んでしまうものも多いですが、動作するシステム条件があったり、複数の製品を一度にインストールしたい場合などはインストーラからのインストールが便利です。<br />
今回はインストーラからインストールするために必要となるパッケージの作成方法について説明します。 <a href="http://tech.feedforce.jp/packagemaker.html#more-100" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1670715_2892.html">
    <title>ZABBIX 1.8でサーバ監視</title>
    <link>http://feed.feedforce.jp/item_30880_1670715_2892.html</link>
    <dc:date>2010-02-10T12:13:21+09:00</dc:date>
    <description>　一時期はサーバの死活監視・リソースチェックといえばNagios + Cacti/MRTGでしたが、最近はZABBIXが割と話題に上ることも多いので、昨年末に1.8がリリースされたこともあり、筆者自宅での事例を交えつつご紹介したいと思います。
?</description>
    <content:encoded><![CDATA[<p><span class="date"></span></p>
<p class="body">　一時期はサーバの死活監視・リソースチェックといえばNagios + Cacti/MRTGでしたが、最近はZABBIXが割と話題に上ることも多いので、昨年末に1.8がリリースされたこともあり、筆者自宅での事例を交えつつご紹介したいと思います。</p>
<p>? <a href="http://tech.feedforce.jp/zabbix-18.html#more-98" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1638902_2892.html">
    <title>Twitter の Streaming API について</title>
    <link>http://feed.feedforce.jp/item_30880_1638902_2892.html</link>
    <dc:date>2010-01-21T11:42:26+09:00</dc:date>
    <description>先日社内でおこなった勉強会で Twitter の Streaming API について紹介しましたので、以下にそのスライドを貼っておきます。
Streaming API はつい最近正式版となりました。ただ、全公開ステータスを取得できる firehose や Retweet に限定したステータスを取得できる retweet などのメソッドは、まだ特定のアプリケーションアカウントでしか利用できません。
しかし、Streaming API はコネクションをひとつ張れば切断されるまでリアルタイムにデー</description>
    <content:encoded><![CDATA[<p>先日社内でおこなった勉強会で Twitter の <a href="http://apiwiki.twitter.com/Streaming-API-Documentation" target="_blank">Streaming API</a> について紹介しましたので、以下にそのスライドを貼っておきます。</p>
<p><iframe src="http://docs.google.com/present/embed?id=dgbcz6cm_114gdx2mgf7" width="410" frameborder="0" height="342"></iframe></p>
<p>Streaming API はつい最近正式版となりました。ただ、全公開ステータスを取得できる firehose や Retweet に限定したステータスを取得できる retweet などのメソッドは、まだ特定のアプリケーションアカウントでしか利用できません。</p>
<p>しかし、Streaming API はコネクションをひとつ張れば切断されるまでリアルタイムにデータを取得することができます。従来の REST API では定期的にリクエストを投げてデータを取得する必要がありましたので、その分のコストが削減できます。</p>
<p>ですので、これから Twitter のデータを取得して新しいアプリケーションを構築しようとする場合は、Streaming API の利用を考慮に入れておくとよいかなと思います。</p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1590812_2892.html">
    <title>rvmの紹介</title>
    <link>http://feed.feedforce.jp/item_30880_1590812_2892.html</link>
    <dc:date>2009-12-11T17:39:28+09:00</dc:date>
    <description>複数のRubyをインストールし、切り替えて使用できるツール rvm(Ruby Version Manager) の紹介を行いました。</description>
    <content:encoded><![CDATA[<h2>rvmとは</h2>
<ul>
<li>Ruby Version Manager の略</li>
<li>複数のRubyをインストールして管理し、切り替えて使う仕組み。
<ul>
<li>MRI(Matz&#8217;s Ruby Implementation), JRuby, Rubinius, REE(Ruby Enterprise Edition), MacRubyに対応しています。</li>
</ul>
</li>
<li>2009年夏に登場しました。</li>
<li>ほとんどシェル関数で実装されています。</li>
</ul>
<h3>ご注意</h3>
<p>この記事の内容は2009年12月4日時点のものです。執筆時点で、rvmは活発に開発が進められているため、最新の状態とは挙動が異なる可能性があります。</p>
<h2>用途(例)</h2>
<ul>
<li>広く使われるライブラリを、異なるruby実装でテストしたい。</li>
<li>使用しているRubyが異なる古いプロダクトを保守したい。</li>
</ul>
<h2>情報源</h2>
<ul>
<li>本サイト: <a href="http://rvm.beginrescueend.com/" class="external">http://rvm.beginrescueend.com/</a></li>
<li>GitHub: <a href="http://github.com/wayneeseguin/rvm/" class="external">http://github.com/wayneeseguin/rvm/</a>
<ul>
<li>Clone URL: git://github.com/wayneeseguin/rvm.git</li>
</ul>
</li>
</ul>
<h2>インストール</h2>
<h3>gemで</h3>
<pre>
$ sudo gem install rvm
$ rvm-install
</pre>
<p>インストールが済んだらgemは削除して構いません。</p>
<pre>
$ sudo gem uninstall rvm
</pre>
<h3>gitで</h3>
<pre>
$ git clone git://github.com/wayneeseguin/rvm.git
$ cd rvm
$ ./install
</pre>
<p>どちらの場合も ~/.rvm 以下にファイルがコピーされ、rvmコマンドが使えるようになります。<br />
このとき ~/.bashrc・~/.bash_profile・~/.zshrc のすべてが書き換えられます。存在しない場合、作成されます。不要なら消しましょう。</p>
<h2>主なコマンド</h2>
<pre>
$ rvm info         - 現在の実行環境を表示
$ rvm list         - 管理しているrubyの一覧を表示
$ rvm install 名前 - 指定されたrubyをインストール
$ rvm use 名前     - 現在のシェルで使用するrubyを切り替える
$ rvm ruby ...     - rubyを一括実行
$ rvm gem ...      - gemを一括実行
$ rvm rake ...     - rakeを一括実行
$ rvm tests ...    - rake testを一括実行
$ rvm specs ...    - rake specを一括実行
</pre>
<h2>rubyのインストール</h2>
<p>インストールしていないものも含め、使える名前のリストを表示します。</p>
<pre>
$ rvm list --all
(ruby-)1.8.0-tv1_8_0
:
(ruby-)1.8.7(-p174)
:
macruby-head # Build from the macruby git repository
</pre>
<p>リストから名前を指定してインストールします。リスト内の名前の括弧内は省略できます。</p>
<pre>
$ rvm install 1.8.7
</pre>
<p>~/.rvm の下にインストールしたRubyの関連ファイル一式が置かれます。</p>
<h2>rubyの切り替え</h2>
<p>基本的な仕組みは、</p>
<ul>
<li>PATHの先頭部に .rvmの管轄下のものを前置。あれば入れ替え。</li>
<li>ラッパースクリプトでの環境変数(GEM_HOMEなど)の切り替え。</li>
</ul>
<pre>
で実現されています。
$ echo $PATH
$ rvm use 1.8.7
$ echo $PATH (先頭部分が変化する)
</pre>
<p>irb, rake, gemなども対応するものが使えるようになる。</p>
<h2>ディレクトリごとの自動切り替え</h2>
<p>カレントディレクトリに .rvmrc ファイルがあり、そこに</p>
<pre>
rvm ruby-1.8.7-p174
</pre>
<p>のように記述しておくと、このディレクトリおよびサブディレクトリに対するrubyを変更することが出来ます。</p>
<pre>
$ cd ~/project1; ruby -v
ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin9]
$ cd ~/project2; ruby -v
ruby 1.8.6 (2009-08-04 patchlevel 383) [i386-darwin9.8.0]
$ cd ~/project3; ruby -v
ruby 1.9.2dev (2009-12-02 trunk 25977) [i386-darwin9.8.0]
</pre>
<p>cdコマンドがシェル関数で再実装されており、ホームディレクトリや / に到達するまでディレクトリを遡って .rvmrc を探し、見つかったものを評価することで切り替えを実現しています。</p>
<h2>一括実行</h2>
<pre>
$ rvm ruby -v
$ rvm gem install rails
$ rvm specs
</pre>
<p>インストールされているrubyで該当処理を順次実行していきます。</p>
<p>複数のRubyに対して一括でgemをインストールしたり、テストを実行したりできます。</p>
<h2>gemセット</h2>
<p>使用するrubyの名前の後ろに%と任意のラベルを付けてgemセットを指定することができます。この仕組みにより、同じrubyを使用しつつ、異なるgem構成を使うことができます。</p>
<pre>
$ cd ~/project1; gem list
$ cd ~/project2; gem list
$ cd ~/project3; gem list
</pre>
<h2>質疑応答</h2>
<h3>Q: インストールにRubyは必要?</h3>
<p>A: gitで入れるなら不要。</p>
<h3>Q: Passengerで使うには?</h3>
<p>A: PassengerRubyには、passenger-install-apache2-module が表示するパスではなく、rvmのラッパースクリプトを指定する。ラッパーの中で必要な環境変数の設定を行ってから対象のRubyをexecしている。<br />
[<a href="http://rvm.beginrescueend.com/passenger/" class="external">http://rvm.beginrescueend.com/passenger/</a>]</p>
<p>ただし、発表者は未検証。</p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1563962_2892.html">
    <title>Resque 概要</title>
    <link>http://feed.feedforce.jp/item_30880_1563962_2892.html</link>
    <dc:date>2009-11-24T19:09:21+09:00</dc:date>
    <description>GitHub で使われているジョブキューの Resque の概要について、社内勉強会で発表しました。以下が発表に利用したスライドです。

    Introduction to Resque</description>
    <content:encoded><![CDATA[<div>
  GitHub で使われているジョブキューの Resque の概要について、社内勉強会で発表しました。以下が発表に利用したスライドです。</p>
<ul>
<li><a href="http://www.slideshare.net/koshigoe/introduction-to-resque">Introduction to Resque</a></li>
</ul>
</div>
<div>
  スライドの内容は大分省略しているので、以下に補足資料へのリンクを追記します。</p>
<ul>
<li><a href="http://w.koshigoe.jp/study/?%5BBackgroundJob%5D%5BRuby%5D+Resque+%A4%C8%A4%CF">KOSHIGOE学習帳 - [BackgroundJob][Ruby] Resque とは</a></li>
<li><a href="http://w.koshigoe.jp/study/?%5BBackgroundJob%5D%5BRuby%5D+Resque+%A4%CE+README+%A4%E8%A4%EA">KOSHIGOE学習帳 - [BackgroundJob][Ruby] Resque の README より</a></li>
<li><a href="http://w.koshigoe.jp/study/?%5BKVS%5D%5BRedis%5D+Redis+%B3%B5%CD%D7">KOSHIGOE学習帳 - [KVS][Redis] Redis 概要</a></li>
<li><a href="http://w.koshigoe.jp/study/?%5BKVS%5D%5BRedis%5D+Redis+%A5%D7%A5%ED%A5%C8%A5%B3%A5%EB%BB%C5%CD%CD">KOSHIGOE学習帳 - [KVS][Redis] Redis プロトコル仕様</a></li>
<li><a href="http://w.koshigoe.jp/study/?%5BKVS%5D%5BRedis%5D+Redis+%A5%B3%A5%DE%A5%F3%A5%C9%B0%EC%CD%F7">KOSHIGOE学習帳 - [KVS][Redis] Redis コマンド一覧</a></li>
</ul>
</div>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1203602_2892.html">
    <title>「えもにゅ」がAmazon EC2で動くまで</title>
    <link>http://feed.feedforce.jp/item_30880_1203602_2892.html</link>
    <dc:date>2009-02-17T19:26:04+09:00</dc:date>
    <description>先月末、「えもにゅ」というサービスをリリースしました。さらに12日には携帯から「えもにゅ」に投稿できる「えもにゅモバイル」もリリースしました。</description>
    <content:encoded><![CDATA[<p>先月末、「<a href="http://emonyu.jp/">えもにゅ</a>」というサービスをリリースしました。さらに12日には携帯から「えもにゅ」に投稿できる「えもにゅモバイル」もリリースしました。</p>
<ul>
<li><a href="http://www.feedforce.jp/entries/000854.html">感情を記録できるサービス 『えもにゅ』 をリリース！</a></li>
<li><a href="http://www.feedforce.jp/entries/000860.html">『えもにゅ』 にモバイル版登場！</a></li>
</ul>
<h3>えもにゅとは</h3>
<p>「<a href="http://emonyu.jp/">えもにゅ</a>」は自分の今の「気持ち」とその「度合い」を選んで投稿するサービスです。投稿した気持ちは「えもにゅくん」というキャラクターの表情によって表現され、ブログパーツを通してブログ上で公開することができます。</p>
<p>感情とブログパーツに特化している点が、これまでのライフログ系のサービスとは異なる点かと思います。</p>
<p>また、「人」と「時間」と「感情」のデータを結びつけて蓄積し、そのデータをAPI経由で公開することで、新たな相乗効果が生まれることを期待しています。(APIは今後公開予定です)</p>
<h3>えもにゅをEC2で動かす</h3>
<p>さて、その「えもにゅ」ですが、サーバーは <a href="http://aws.amazon.com/ec2/">Amazon EC2</a> を利用しています。「なぜ日本のサービスで EC2 なのか？」と思われるかもしれませんが、</p>
<ul>
<li>個人的に EC2 を使ってみたかった</li>
<li>日本で EC2 を利用してサービスを展開している事例が少ない</li>
<li>円高で料金が安くなっている</li>
<li>日本での利用が増えればEC2のサーバーが日本にもできるかもという淡い期待</li>
</ul>
<p>といった点が EC2 を利用しようと考えた理由です。</p>
<h3>えもにゅの構成</h3>
<p>えもにゅの構成は以下の図のようになっています。</p>
<p><img src="http://tech.feedforce.jp/wp-content/uploads/2009/02/emonyu-amazon-ec2.gif" alt="えもにゅの構成" /></p>
<p>EC2上にCentOSのインスタンスを起動、その上にPHP, Apache, MySQLなどをインストールしています。今のところインスタンスは1つです。画像やCSSといったスタティックなファイルは Amazon S3 に配備し、 static.emonyu.jp というサブドメインをCNAMEに割り当てています。</p>
<p>また、EC2とS3のみでは画像等のローディングが遅くて使い物にならなかったため、 Amazon CloudFront にキャッシュさせることで、日本からアクセスされても耐えられるようにしています。</p>
<h3>RightScale社のCentOSイメージを利用</h3>
<p>EC2のインスタンスで起動させているAMI(イメージ)は、<a href="http://www.rightscale.com/">RightScale</a>社が提供しているCentOSのイメージを利用しました。</p>
<p>このイメージを利用する際の注意点は、EC2のSmall Instanceで利用可能な160GBのうちの10GBしかルートにマウントされていない点です。</p>
<p>残りの150GBは /mnt に割り当てられています。MySQL を yum でインストールすると /var/lib/mysql にデータディレクトリが作成されますが、上記の通り /var 以下では 10GB までしか利用できないため、 /mnt の下に mysql用のディレクトリを作成して、シンボリックリンクを貼るといった対処が必要になります。</p>
<pre>$ cd /var/lib
$ rm mysql
$ ln -s /mnt/var/lib/mysql mysql
$ lllrwxrwxrwx 1 root   root      18  1月  8 22:30 mysql -&gt; /mnt/var/lib/mysql</pre>
<p>my.cnf の内容もそれにあわせて書き換えました。</p>
<pre>[mysqld]
datadir=/mnt/var/lib/mysql
socket=/mnt/var/lib/mysql/mysql.sock
[mysql.server]
basedir=/mnt/var/lib</pre>
<p>また、タイムゾーンが米国時間となっているため、最初に日本時間に変更しておく必要があります。</p>
<pre>lrwxrwxrwx 1 root root 30? 1月 16 11:16 /etc/localtime -&gt; /usr/share/zoneinfo/Asia/Tokyo</pre>
<h3>CloudFrontでスタティックファイルをホスティングする際の注意点</h3>
<p>CloudFrontのサーバは日本に置かれているためアクセスは速いのですが、キャッシュの有効時間を24時間未満に設定することができないため、キャッシュのコントロールがうまくいかないという問題があります。</p>
<p>ファイルの内容が更新されてもキャッシュは無効にならないため、キャッシュを無効にするにはファイル名を変更する必要があります。リリースのたびにファイル名を変更するのは面倒です。</p>
<p>そこで、スタティックファイルのディレクトリにバージョン番号を付与し、リリースのたびにそのバージョン番号を変更していくという、少々めんどくさい方法で対応することにしました。</p>
<p>イメージとしては、</p>
<pre>&lt;img src="/img/title.gif" alt="..." /&gt;</pre>
<p>という img タグがあったら、</p>
<pre>&lt;img src="http://static.emonyu.jp/24/img/title.gif" alt="..." /&gt;</pre>
<p>のようにテンプレートを書き換え、画像ファイル等はその番号のディレクトリに配備する、というものです。バージョン番号はデータベースで管理しています。</p>
<h3>S3にファイルを転送する際の注意点</h3>
<p>EC2からS3へファイルを転送するのに、<a href="http://undesigned.org.za/2007/10/22/amazon-s3-php-class">Amazon S3 PHP Class</a>というライブラリを利用しています。このライブラリは以下のようにして利用できるのですが、</p>
<pre>$s3-&gt;putObjectFile(
                   '/path/to/style.css',
                   'bucket-name',
                   's3/file/path/css/style.css',
                   S3::ACL_PUBLIC_READ);</pre>
<p>putObjectFile() の6番目の引数に適切に Content-Type を与えてあげる必要があります。たとえば上記のように Content-Type なしで転送してしまうと、ライブラリがデフォルトの Content-Type として text/plain を適用してしまうために、ブラウザでページを表示したときにCSSが適用されなくなります。そのため、</p>
<pre>$s3-&gt;putObjectFile(
                   '/path/to/style.css',
                   'bucket-name',
                   's3/file/path/css/style.css',
                   S3::ACL_PUBLIC_READ,
                   array(),
                   'text/css');</pre>
<p>のように、最後の引数で Content-Type を与える必要があります。もしくはファイルの拡張子から Content-Type を自動的に判別できるように、ライブラリ自身を修正してもよいと思います。</p>
<h3>まとめ</h3>
<p>以上のように少し手間と工夫が必要ですが、Amazon EC2, S3, CloudFrontを利用して日本向けのサービスを提供することができます。</p>
<p>今後は既存ユーザの利便性向上やAPIの公開、クラウドを生かした新機能の開発などをしていきたいと考えています。</p>
<p>というわけで、ぜひぜひ「<a href="http://emonyu.jp/" target="_blank">えもにゅ</a>」を使ってみてください。</p>
<p><a href="http://emonyu.jp/" target="_blank">http://emonyu.jp/ </a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1136619_2892.html">
    <title>Easy-Mmodeを使ってEmacsのマイナーモードを作る</title>
    <link>http://feed.feedforce.jp/item_30880_1136619_2892.html</link>
    <dc:date>2008-12-12T19:01:15+09:00</dc:date>
    <description>今回はEmacsのマイナーモードを作成する手順を紹介します。
説明では弊社が提供しているプロダクトのひとつ RSS Suite で利用している独自フレームワーク中で、対応するファイル間を移動できるようにするマイナーモードを作成していきます。</description>
    <content:encoded><![CDATA[<p align="justify">今回はEmacsのマイナーモードを作成する手順を紹介します。</p>
<p>説明では弊社が提供しているプロダクトのひとつ <a href="http://www.rsssuite.jp" title="RSS Suite" target="_blank">RSS Suite</a> で利用している独自フレームワーク中で、対応するファイル間を移動できるようにするマイナーモードを作成していきます。</p>
<h3>メジャーモードとマイナーモード</h3>
<p>Emacsにはカスタマイズする定義の集まりであるモードというものがあり、メジャーモードとマイナーモードの2種類があります。</p>
<h4>メジャーモード</h4>
<p>特定のテキスト編集向けに特化している。各バッファには、ある時点で1つのメジャーモードしかない。</p>
<h4>マイナーモード</h4>
<p>メジャーモードの選択とは独立にオン/オフできる機能を提供する。<br />
ここではマイナーモードを作成します。</p>
<h3>バッファとウィンドウ</h3>
<p>Emacs内でファイル間を移動するには、ウィンドウとバッファの操作が必要になります。</p>
<h4 align="justify">バッファ</h4>
<p>編集領域。Emacsの編集操作はすべてバッファを対象に行われます。</p>
<h4 align="justify">ウィンドウ</h4>
<p align="justify">?バッファの表示領域のこと。</p>
<h3>Easy-Mmode</h3>
<p>単純なマイナーモードであればEasy-Mmodeパッケージを利用すると便利です。<br />
以下のように書くと、test-modeというマイナーモードを定義できます。</p>
<pre> ;; マイナーモードの定義
 (easy-mmode-define-minor-mode test-mode
 ;; モード名は、-mode
 ;; ドキュメント
?  "This is Test Mode."
 ;; 初期値
 nil
 ;; on の時のモード行への表示
 " TestMode"
 ;; マイナーモード用キーマップの初期値
 '(("C-cf" . test-function))</pre>
<p>「M-x test-mode」でモードのオン/オフを切り替えることができ、test-modeがオンの時はキーバインド「C-c f」で関数test-functionを呼び出すことができるようになります。<br />
この設定の場合、test-modeがオンのときは&#8221;TestMode&#8221;がモード行に表示されます。</p>
<p><a href="http://tech.feedforce.jp/wp-content/uploads/2008/12/2008-12-09_1807.png" title="2008-12-09_1807.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/12/2008-12-09_1807.png" alt="2008-12-09_1807.png" /></a></p>
<h3 align="justify">実際にマイナーモードを作ってみる</h3>
<p>では、実際にマイナーモードを作成していきます。<br />
ここでは<a href="http://www.rsssuite.jp" title="RSS Suite" target="_blank">RSS Suite</a>の管理画面で利用するファイル間を移動できるようにすることを目標とします。</p>
<p align="justify">RSS Suiteの管理画面で必要となるファイルの構成は以下です。</p>
<ul>
<li>lib/FormProcess/FormProcessXxxYyyZzz.php(フォーム処理)</li>
<li>lib/PageContents/PageContentsXxxYyyZzz.php(コンテンツ表示)</li>
<li>lib/qfd/xxx.yyy.zzz.qfd(フォームの定義)</li>
<li>template/rss_admin/xxx.yyy.zzz.html(htmlテンプレート)</li>
</ul>
<p align="justify">命名規則からファイル名をうまく変換して、現在開いているファイルから対応するファイルへと移動できるようにします。</p>
<p> まず、Easy-Mmodeを利用して、RSS Suiteモードを定義します。</p>
<pre>?(easy-mmode-define-minor-mode rsssuite-mode
;; ドキュメント
 "This is RSS Suite Mode."
 ;; 初期値
 nil;; モード行への表示
 "RSSSuite"
 ;; マイナーモード用キーマップの初期値
 '(("C-cf" . suite-open-formprocess)
?  ("C-cp" . suite-open-pagecontents)
?  ("C-cq" . suite-open-qfd)
?  ("C-ct" . suite-open-template)))</pre>
<p>ここではそれぞれ4つの対応ファイルを開くためのキーマップを定義しています。<br />
次に、切り替えるファイルへのパスをそれぞれ定義しておきます。</p>
<pre> (defvar suite-qfd-path "lib/qfd/")
 (defvar suite-formprocess-path "lib/FormProcess/")
 (defvar suite-pagecontents-path "lib/PageContents/")
 (defvar suite-template-path "template/rss_admin/")
 (defvar suite-lib-path "lib/")</pre>
<p>関数defvarで変数に値を定義しています。<br />
次に関連ファイルを開いた時にrsssuite-modeをオンにするためhookを定義します。<br />
この設定は必須ではありませんが、rss_suiteディレクトリ以下のファイルを開いた時に自動でrsssuite-modeがオンになる方がラクなのでそのようにします。</p>
<pre>;; ファイルを開いた時のhook
(add-hook 'find-file-hooks
?         (function (lambda ()
?                     (suite-on-rsssuite-mode))))</pre>
<p>find-file-hooksはファイルを訪問後に呼び出されます。</p>
<p>ここで実行しているsuite-on-rsssuite-mode関数は以下のように定義してあります。</p>
<pre>;; RSS Suiteのディレクトリ配下であればrsssuite-modeにする
(defun suite-on-rsssuite-mode ()
? (if (string-match "rss_suite[^/]*/" default-directory)
?     (unless rsssuite-mode (rsssuite-mode))))</pre>
<p>変数rsssuite-modeはモードがオンになっていてばt, オフであればnilとなります。<br />
関数rsssuite-modeはオン・オフを切り替える関数で、ここではオフの時のみオンにする処理にしています。</p>
<p>次に、マイナーモードのキーマップで定義した関数suite-open-formprocessを見ていきます。</p>
<pre>;; 対応するFormProcessファイルを開く
(defun suite-open-formprocess ()
? (interactive)
? (setq suite-formprocess-file-path (concat (suite-get-top-dir)
?                                           suite-formprocess-path
?                                           "FormProcess"
?                                           (suite-get-capitalized-name)
?                                           ".php"))
? (set-window-buffer (selected-window) (find-file-noselect suite-formprocess-file-path))
? (suite-on-rsssuite-mode))</pre>
<p align="justify">defunで関数を定義しています。interactiveが含まれていると、 「M-x 関数名」で実行できるコマンドになります。<br />
変数suite-formprocess-file-pathに、対応するFormProcessファイルの絶対パスを格納しています。<br />
関数set-window-bufferは指定したウィンドウにバッファの内容を表示させます。ここでは選択されているウィンドウ(selected-windnow)に、確保したファイルsuite-formprocess-file-pathに対応するバッファを表示させています。</p>
<p>suite-formprocess-file-pathを求める部分では、関数concatで以下の文字列を連結しています。</p>
<ul>
<li>(suite-get-top-dir)</li>
<li>suite-formprocess-path</li>
<li>&#8220;FormProcess&#8221;</li>
<li>(suite-get-capitalized-name)</li>
<li>&#8220;.php&#8221;</li>
</ul>
<p>関数suite-get-top-dirの定義は以下です。</p>
<pre>?;; RSS Suiteのトップディレクトリの絶対パスを取得
 (defun suite-get-top-dir ()
   (string-match "rss_suite[^/]*/" default-directory)
   (substring default-directory 0 (match-end 0)))</pre>
<p>match-endには、string-matchの結果である終端のポイント位置が入ります。</p>
<p>関数suite-get-capitalized-nameの定義は以下です。</p>
<pre>?;; キャメルケースのファイル名を取得
(defun suite-get-capitalized-name ()
  (cond
   ((suite-formprocessp) (string-match "FormProcess(.+).php" (suite-get-file-name)) (suite-get-main-name))
   ((suite-pagecontentsp) (string-match "PageContents(.+).php" (suite-get-file-name)) (suite-get-main-name))
   ((suite-qfdp)  (string-match "(.+).qfd" (suite-get-file-name)) (suite-dot-to-capitalize-string (suite-get-main-name)))
   ((suite-templatep) (string-match "(.+).html" (suite-get-file-name)) (suite-dot-to-capitalize-string (suite-get-main-name)))
   (t nil)))</pre>
<p>現在開いているファイルがqfdファイル(xxx.yyy.zzz.qfd)やtemplateファイル(xxx.yyy.zzz.html)の場合、キャメルケースに変換して(XxxYyyZzz)返します。<br />
変換しているのは、関数suite-dot-to-capitalize-stringの部分です。</p>
<pre>?;; ファイル名からメインとなる部分の名前を切り出す
(defun suite-get-main-name ()
  (substring (suite-get-file-name) (match-beginning 1) (match-end 1))
  )</pre>
<p>match-beginningやmatch-endには直前に評価しているstring-matchの結果が入ります。</p>
<pre>;; ドットで連結されたファイル名をリストに変換
;; foo.bar.baz =&gt; (foo bar baz)
(defun suite-dot-to-capitalize-string (str)
  (suite-concat-capitalize-string-list (split-string str "."))
  )</pre>
<p>split-stringはドットで区切ってリストにしています。</p>
<pre>;; 文字列のリストをキャピタライズして連結する
;; (foo bar baz) -&gt; FooBarBaz
(defun suite-concat-capitalize-string-list (list)
  (cond
   ((= (length list) 1) (capitalize (car list)))
   (t (concat (capitalize (car list)) (suite-concat-capitalize-string-list (cdr list))))))</pre>
<p>listの長さが1であれば、carでlistの先頭要素をキャピタライズして返します。<br />
listの要素が2つ以上の場合は先頭要素をキャピタライズした文字列と、cdrで先頭要素を取り除いたlistを自身の関数suite-concat-capitalize-string-listに渡した結果の文字列と連結します。</p>
<p>逆に、ドットで区切られた名前から、キャピタライズした名前を取得する処理は以下です。</p>
<pre>;; ドットで連結されたファイル名を取得
(defun suite-get-concatenated-name ()
  (cond
   ((suite-formprocessp) (string-match "FormProcess(.+).php" (suite-get-file-name)) (suite-split-capitalize-string (suite-get-main-name )))
   ((suite-pagecontentsp) (string-match "PageContents(.+).php" (suite-get-file-name)) (suite-split-capitalize-string (suite-get-main-name )))
   ((suite-qfdp) (string-match "(.+).qfd" (suite-get-file-name)) (suite-get-main-name))
   ((suite-templatep)  (string-match "(.+).html" (suite-get-file-name)) (suite-get-main-name))
   (t nil))
  )

;; キャメルケースの文字をドット区切りに分解
;; FooBarBaz -&gt; foo.bar.baz
(defun suite-split-capitalize-string (str)
  (setq case-fold-search nil)
  (string-match "^[A-Z][a-z]+" str)
  (cond
   ((= (match-end 0) (length str)) (downcase str))
   (t  (concat
	(concat (downcase (substring str (match-beginning 0) (match-end 0))) ".")
	(suite-split-capitalize-string (substring str (match-end 0) (length str)))
	))))</pre>
<p>関数suite-split-capitalize-stringでは、受け取った文字列を先頭が大文字でそれ以降小文字が続く正規表現でマッチさせます。<br />
もしstring-matchの結果の終端ポイント位置とstrの長さが同じであれば、downcaseして返します。<br />
長さが異る場合は、downcaseした最初の単語に&#8217;.'を連結したものと、マッチ以降の文字を自身の関数suite-split-capitalize-stringに渡して返される文字列を連結します。</p>
<p align="justify">以上で対応したファイル間を移動できるマイナーモードができました。<br />
最後にソース全体を載せておきます。</p>
<pre>
 ;; RSS Suite モード
(easy-mmode-define-minor-mode rsssuite-mode
                              ;; ドキュメント
                              "This is RSS Suite Mode."
                              ;; 初期値
                              nil
                              ;; on の時のモード行への表示
                              " RSSSuite"
                              ;; マイナーモード用キーマップの初期値
                              '(("C-cf" . suite-open-formprocess)
                                ("C-cp" . suite-open-pagecontents)
                                ("C-cq" . suite-open-qfd)
                                ("C-ct" . suite-open-template)
                                ))

;; Suiteのトップからそれぞれのファイルへのパス
(defvar suite-qfd-path "lib/qfd/")
(defvar suite-formprocess-path "lib/FormProcess/")
(defvar suite-pagecontents-path "lib/PageContents/")
(defvar suite-template-path "template/rss_admin/")
(defvar suite-lib-path "lib/")

;; ファイルを開いた時のhook
(add-hook 'find-file-hooks
          (function (lambda ()
                      (suite-on-rsssuite-mode))))

;; Suiteのディレクトリ配下であればRSSSuite modeにする
(defun suite-on-rsssuite-mode ()
  (if (string-match "rss_suite[^/]*/" default-directory)
      (unless rsssuite-mode (rsssuite-mode))))

;; suiteのトップディレクトリの絶対パスを取得
(defun suite-get-top-dir ()
  (string-match "rss_suite[^/]*/" default-directory)
  (substring default-directory 0 (match-end 0)))

;; 対応するFormProcessファイルを開く
(defun suite-open-formprocess ()
  (interactive)
  (setq suite-formprocess-file-path (concat (suite-get-top-dir)
                                            suite-formprocess-path
                                            "FormProcess"
                                            (suite-get-capitalized-name)
                                            ".php"))
  (set-window-buffer (selected-window)
		     (find-file-noselect suite-formprocess-file-path))
  (suite-on-rsssuite-mode))

;; 対応するPageContentsファイルを開く
(defun suite-open-pagecontents ()
  (interactive)
  (setq suite-pagecontents-file-path (concat (suite-get-top-dir)
                                             suite-pagecontents-path
                                             "PageContents"
                                             (suite-get-capitalized-name)
                                             ".php"))
  (set-window-buffer (selected-window)
		     (find-file-noselect suite-pagecontents-file-path))
  (suite-on-rsssuite-mode))

;; 対応するqfdファイルを開く
(defun suite-open-qfd ()
  (interactive)
  (setq suite-qfd-file-path (concat (suite-get-top-dir)
                                    suite-qfd-path
                                    (suite-get-concatenated-name)
                                    ".qfd"))
  (set-window-buffer (selected-window)
		     (find-file-noselect suite-qfd-file-path))
  (suite-on-rsssuite-mode))

;; 対応するテンプレートファイルを開く
(defun suite-open-template ()
  (interactive)
  (setq suite-template-file-path
	(concat (suite-get-top-dir)
		suite-template-path
		(suite-get-concatenated-name)
		".html"))
  (set-window-buffer (selected-window)
		     (find-file-noselect suite-template-file-path))
  (suite-on-rsssuite-mode))

;; ファイル名からメインとなる部分の名前を切り出す
(defun suite-get-main-name ()
  (substring (suite-get-file-name) (match-beginning 1) (match-end 1)))

;; キャメルケースのファイル名を取得
(defun suite-get-capitalized-name ()
  (cond
   ((suite-formprocessp)
    (string-match "FormProcess(.+).php" (suite-get-file-name))
    (suite-get-main-name ))
   ((suite-pagecontentsp)
    (string-match "PageContents(.+).php"
		  (suite-get-file-name)) (suite-get-main-name ))
   ((suite-qfdp)
    (string-match "(.+).qfd" (suite-get-file-name))
    (suite-dot-to-capitalize-string (suite-get-main-name )))
   ((suite-templatep)
    (string-match "(.+).html" (suite-get-file-name))
    (suite-dot-to-capitalize-string (suite-get-main-name )))
   (t nil)))

;; ドットで連結されたファイル名を取得
(defun suite-get-concatenated-name ()
  (cond
   ((suite-formprocessp)
    (string-match "FormProcess(.+).php" (suite-get-file-name))
    (suite-split-capitalize-string (suite-get-main-name )))
   ((suite-pagecontentsp)
    (string-match "PageContents(.+).php" (suite-get-file-name))
    (suite-split-capitalize-string (suite-get-main-name )))
   ((suite-qfdp)
    (string-match "(.+).qfd" (suite-get-file-name))
    (suite-get-main-name))
   ((suite-templatep)
    (string-match "(.+).html" (suite-get-file-name))
    (suite-get-main-name))
   (t nil)))

;; 文字列のリストをキャピタライズして連結する
;; (foo bar baz) -&gt; FooBarBaz
(defun suite-concat-capitalize-string-list (list)
  (cond
   ((= (length list) 1) (capitalize (car list)))
   (t (concat (capitalize (car list))
	      (suite-concat-capitalize-string-list (cdr list))))))

;; ドットで連結されたファイル名をリストに変換
;; foo.bar.baz =&gt; (foo bar baz)
(defun suite-dot-to-capitalize-string (str)
  (suite-concat-capitalize-string-list (split-string str "."))
  )

;; キャメルケースの文字をドット区切りに分解
;; FooBarBaz -&gt; foo.bar.baz
(defun suite-split-capitalize-string (str)
  (setq case-fold-search nil)
  (string-match "^[A-Z][a-z]+" str)
  (cond
   ((= (match-end 0) (length str)) (downcase str))
   (t  (concat
	(concat (downcase
		 (substring str (match-beginning 0) (match-end 0))) ".")
	(suite-split-capitalize-string (substring str
						  (match-end 0)
						  (length str)))))))

;; FormProcessかどうか
(defun suite-formprocessp ()
  (string-match "FormProcess" (suite-get-file-name)))

;; PageContentsかどうか
(defun suite-pagecontentsp ()
  (string-match "PageContents" (suite-get-file-name)))

;; qfdかどうか
(defun suite-qfdp ()
  (string-match ".*.qfd" (suite-get-file-name)))

;; テンプレートかどうか
(defun suite-templatep ()
  (string-match ".*.html" (suite-get-file-name)))

;; ファイル名取得
(defun suite-get-file-name ()
  (if buffer-file-name
      (file-name-nondirectory buffer-file-name)
    (error "there are not respond file")))</pre>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1088535_2892.html">
    <title>ShindigとPartuzaでOpenSocialガジェットのテスト環境を構築(その2)</title>
    <link>http://feed.feedforce.jp/item_30880_1088535_2892.html</link>
    <dc:date>2008-10-27T11:07:36+09:00</dc:date>
    <description>前回はOpenSocialガジェットのホスティング環境を構築できる Shindig について説明しました。
&amp;#187; FFTT : ShindigとPartuzaでOpenSocialガジェットのテスト環境を構築(その1)
今回は、その Shindig を利用して OpenSocial 機能を実装している Partuza を紹介します。</description>
    <content:encoded><![CDATA[<p>前回はOpenSocialガジェットのホスティング環境を構築できる <a href="http://incubator.apache.org/shindig/">Shindig</a> について説明しました。</p>
<p>? <a href="http://tech.feedforce.jp/shindig-partuza-opensocial-1.html">FFTT : ShindigとPartuzaでOpenSocialガジェットのテスト環境を構築(その1)</a></p>
<p>今回は、その Shindig を利用して OpenSocial 機能を実装している <a href="http://www.partuza.nl/">Partuza</a> を紹介します。</p>
<h2>Partuza</h2>
<p><a href="http://www.partuza.nl/">Partuza</a> はオープンソースのSNSです。PHPで書かれています。読み方はよくわかりません。ソースをダウンロードして個人の環境に設置することで使えるようになります。ライセンスは Apache License 2.0 です。</p>
<h3>こんなとき参考になります</h3>
<ul>
<li>Apache Shindigを利用してOpen Social対応SNSを作りたい</li>
<li>すでにあるSNSにApache Shindigを利用したOpen Social機能を実装したい</li>
</ul>
<p>というわけで、早速 Partuza をインストールしてみます。ソースコードは <a href="http://code.google.com/p/partuza/">partuza - Google Code</a> から入手できます。</p>
<h3>Partuza のインストール</h3>
<h4>checkout</h4>
<pre>$ mkdir /var/www/partuza
$ cd /var/www/partuza
$ svn co http://partuza.googlecode.com/svn/trunk .</pre>
<h4>バーチャルホストを設定</h4>
<pre>&lt;VirtualHost 192.168.1.142:80&gt;
    DocumentRoot /var/www/partuza/html
    ServerName dev.partuza.jp
    ErrorLog /var/log/httpd/partuza_error_log
    CustomLog /var/log/httpd/partuza_access_log combined

    AddDefaultCharset UTF-8

    &lt;Directory /var/www/partuza/html&gt;
        AllowOverride All
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre>
<h4>必要であれば</h4>
<p>/etc/php.ini に以下の記述があるか。</p>
<pre>short_open_tag = On</pre>
<p><a href="http://www.libgd.org/Main_Page">gd</a>をインストールしていなければインストール。</p>
<h4>パーミッション変更</h4>
<pre>$ chmod 777 /var/www/partuza/images/people</pre>
<h4>SQL実行(MySQL)</h4>
<pre>$ cd /var/www/partuza
$ mysqladmin -u root -p create partuza
$ mysql -u root -p -D partuza &lt; partuza.sql</pre>
<p>ここまで設定すれば、Partuza が動きます。</p>
<p>しかし、まだ Shindig が組み込まれていませんので、Shindig を Partuza に組み込む設定をします。</p>
<h4>Shindig に local.php を作成</h4>
<pre>$ vi /var/www/shindig/config/local.php</pre>
<p>local.phpファイルの中身は次のようにする。</p>
<pre>&lt;?php

$shindigConfig = array(
                       'people_service' =&gt; 'PartuzaPeopleService',
                       'activity_service' =&gt; 'PartuzaActivitiesService',
                       'app_data_service' =&gt; 'PartuzaAppDataService',
                       'extension_class_paths' =&gt; '/var/www/partuza/Shindig',);</pre>
<h4>Partuza の config.php を編集</h4>
<p>Shindig が動く環境のホスト名を設定します。</p>
<pre>$ vi /var/www/partuza/html/config.php</pre>
<pre>- 'gadget_server'    =&gt; 'http://shindig',
+ 'gadget_server'    =&gt; 'http://dev.shindig.jp',</pre>
<p>ここまで設定できれば、PartuzaでOpenSocialガジェットが動くようになります。</p>
<p><img src="http://tech.feedforce.jp/wp-content/uploads/2008/10/partuza-home.gif" alt="Partuza" /></p>
<p>↑ テストで<a href="http://www.google.co.jp/ig/directory?hl=ja&amp;url=map.fkoji.com/kusayakyu/search.xml">このガジェット</a>を追加してみました。(※ このガジェットにOpenSocialの機能はありません。)</p>
<h2>まとめ</h2>
<p>このように、 Shindig と Partuza を利用すると、OpenSocial対応のガジェットおよびSNSの開発環境を簡単に構築することができます。興味のある方はぜひ利用してみてください。</p>
<p>? <a href="http://tech.feedforce.jp/shindig-partuza-opensocial-1.html">FFTT : ShindigとPartuzaでOpenSocialガジェットのテスト環境を構築(その1)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_1068064_2892.html">
    <title>ShindigとPartuzaでOpenSocialガジェットのテスト環境を構築(その1)</title>
    <link>http://feed.feedforce.jp/item_30880_1068064_2892.html</link>
    <dc:date>2008-10-06T10:59:23+09:00</dc:date>
    <description>OpenSocial対応のガジェットを構築するうえでの悩みどころは、「テスト環境どうするの？」というところではないでしょうか。
まだ公開していないガジェットアプリケーションをOrkutのsandboxでテストするのはちょっとなぁ・・・と思ったことがある人は、ここで紹介するShindigとPartuzaを使ってみるといいかもしれません。
今回はまず Shindig について説明します。</description>
    <content:encoded><![CDATA[<p><a href="http://code.google.com/apis/opensocial/">OpenSocial</a>対応のガジェットを構築するうえでの悩みどころは、「テスト環境どうするの？」というところではないでしょうか。</p>
<p>まだ公開していないガジェットアプリケーションを<a href="http://www.orkut.com/">Orkut</a>のsandboxでテストするのはちょっとなぁ・・・と思ったことがある人は、ここで紹介するShindigとPartuzaを使ってみるといいかもしれません。</p>
<p>今回はまず Shindig について説明します。</p>
<h2>Shindig</h2>
<p><a href="http://incubator.apache.org/shindig/">Shindig</a>は<a href="http://code.google.com/apis/opensocial/docs/0.8/spec.html">OpenSocial API Specification</a>と<a href="http://code.google.com/apis/gadgets/docs/spec.html">Gadgets Specification</a>を実装したオープンソースのプロジェクトです。<a href="http://incubator.apache.org/">Apache incubator</a>にて開発が進められています。</p>
<p>Shindigを使うと誰でも自由にOpenSocialガジェットをホストするサイトを構築することができます。ローカル環境に立てればテスト環境が作れるというわけです。</p>
<p>※ iGoogleのガジェットをいくつか試してみましたが、すべてのガジェットが実行できるわけではありませんでした。iGoogle独自のメソッドの多くは実装されていないようです。</p>
<h3>Shindigの構成要素</h3>
<ul>
<li>Gadget Container JavaScript</li>
<li>Gadget Server</li>
<li>OpenSocial Container JavaScript</li>
<li>OpenSocial Data Server</li>
</ul>
<h3>導入</h3>
<p><a href="http://incubator.apache.org/shindig/#php" class="external">http://incubator.apache.org/shindig/#php</a></p>
<p>Java版もありますが、ここではPHP版で。</p>
<h4>必要環境</h4>
<ul>
<li>Subversion</li>
<li>mod_rewrite</li>
<li>PHP 5.2.x (json, simplexml, mcrypt, curl)</li>
</ul>
<h4>ソースをチェックアウト</h4>
<pre>$ mkdir /var/www/shindig
$ cd /var/www/shindig
$ svn co http://svn.apache.org/repos/asf/incubator/shindig/trunk/ .</pre>
<h4>バーチャルホストを立てる</h4>
<p>ここでは dev.shindig.jp というドメインとします。</p>
<pre>&lt;VirtualHost 192.168.1.142:80&gt;
    DocumentRoot /var/www/shindig/php
    DirectoryIndex index.html index.php
    ServerName dev.shindig.jp
    AddDefaultCharset UTF-8 

    &lt;Directory /var/www/shindig/php&gt;
        AllowOverride All
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;</pre>
<h4>PECL json インストール</h4>
<p>個人の環境にPECL jsonが入っていなかったのでインストールしました。</p>
<pre>$ sudo pecl install json</pre>
<h3>ガジェットを実行してみる</h3>
<p>ここまでできれば、すぐにガジェットを実行することができます。エンドポイントは、</p>
<pre>http://dev.shindig.jp/gadgets/ifr?</pre>
<p>です。urlパラメータを与えてガジェットを実行します。</p>
<pre>http://dev.shindig.jp/gadgets/ifr?url=[ガジェットのXMLファイルのURL]</pre>
<p><img src='http://tech.feedforce.jp/wp-content/uploads/2008/09/shindig-example.gif' alt='shindig-example.gif' /></p>
<p>↑ ドキュメントに<a href="http://www.labpixies.com/campaigns/todo/todo.xml">サンプルとして記載されているガジェット</a>を実行したところ。</p>
<p>このように、Shindigを使うと簡単にOpenSocial対応ガジェットをホスティングする環境を作ることができます。</p>
<p>というわけで、次回はPartuzaについて。</p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_968514_2892.html">
    <title>RubyCocoaを1杯</title>
    <link>http://feed.feedforce.jp/item_30880_968514_2892.html</link>
    <dc:date>2008-07-02T18:43:33+09:00</dc:date>
    <description>今回はRubyCocoaを使ってMacOSXの簡単なアプリケーションを作ってみようと思います。</description>
    <content:encoded><![CDATA[<p><span class="Apple-style-span" style="font-family: Times; line-height: normal"> </span></p>
<p style="padding: 0.5em; background-color: #ffffff; font-family: Georgia,'Times New Roman',Times,serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 1em; line-height: 1.3em; font-size-adjust: none; font-stretch: normal" align="justify">今回はRubyCocoaを使ってMacOSXの簡単なアプリケーションを作ってみようと思います。<span id="more-75"></span></p>
<h2><span class="Apple-style-span" style="font-size: 16px; font-weight: normal"><span class="Apple-style-span" style="font-size: 24px; font-weight: bold">RubyCocoaとは</span></span></h2>
<ul>
<li>Rubyを使ってMacOSXのアプリケーションフレームワークであるCocoaを操作できる</li>
<li>対話的にCocoaを開発できる</li>
<li>Leopardから標準搭載</li>
<li>バージョン 0.13.2(2008/2/16)</li>
</ul>
<h2><span class="Apple-style-span" style="font-size: 16px; font-weight: normal"><span class="Apple-style-span" style="font-size: 24px; font-weight: bold">代表的なアプリケーション</span></span></h2>
<p align="justify">RubyCocoaを使って開発されたアプリケーションには以下のようなものがあります。</p>
<ul>
<li><a href="http://limechat.sourceforge.net/index_ja.html">LimeChat for OSX</a></li>
<li><a href="http://coderepos.org/share/wiki/Chemr">Chemr</a></li>
<li><a href="http://blog.deadbeaf.org/2008/03/01/qstwitter-14/">QSTwitter<br />
</a></li>
</ul>
<p align="justify">特にQuickSilverからTwitterに投げれるQSTwitterはとても便利に使わせてもらっています。</p>
<h2>作ってみよう</h2>
<p align="justify">Twitterにポストするだけの簡単なアプリケーションを作ってみます。</p>
<h2><font class="Apple-style-span" size="6"><span class="Apple-style-span" style="font-size: 19px">準備</span></font></h2>
<p align="justify">Xcodeを使うので、あらかじめインストールしておく必要があります。MacOSXのインストールDVDに含まれているのでそこからインストールするか、もしくは<a href="http://developer.apple.com/">ADC</a>(Apple Developer Connection)のサイトからダウンロードすることもできます。また、RubyからTwitterにポストする部分でRuby Twitter Gemを使いましたので、それもインストールしておきます。 ターミナルを開いて、</p>
<pre style="font-family: 'Courier New',fixed; font-size: 11px; line-height: 13px">$ sudo gem install twitter</pre>
<p>でインストールします。</p>
<h2><font class="Apple-style-span" size="6"><span class="Apple-style-span" style="font-size: 19px">プロジェクト作成</span></font></h2>
<p align="justify">まず、プロジェクトを作成します。/Developer/Applications/Xcode.appを開きます。 File-&gt;New Projectを選択し、 Cocoa-Ruby Applicationを選択します(1)。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0029.png" title="new project"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0029.thumbnail.png" alt="new project" /></a> (1)</p>
<p>プロジェクト名を入力して次に進むと、プロジェクトウィンドウが立ちあがります(2)。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0031.png" title="プロジェクトウィンドウ"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0031.thumbnail.png" alt="プロジェクトウィンドウ" /></a> (2)</p>
<p>次にコントローラを作成します。 Classes-&gt;Add-&gt;Ruby NSObject subclass を選択します(3)。</p>
<p align="justify"> <a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0032.png" title="Ruby NSObject subclass"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/2008-06-26_0032.thumbnail.png" alt="Ruby NSObject subclass" /></a> (3)<br />
ここではAppController.rbというファイル名で保存します。 今回は次のようなコードにしました。</p>
<pre>require 'osx/cocoa'
require 'rubygems'
require 'twitter'

class AppController &lt; OSX::NSObject
  include OSX
  ib_outlet :window, :name, :password, :message
  ib_action :post
  def post
    twit = Twitter::Base.new(@name.stringValue.to_s, @password.stringValue.to_s)
    twit.update(@message.stringValue.to_s)
    @message.setStringValue ''
  end
end</pre>
<p align="justify"> ib_outletで、コントローラからウィンドウへの参照を定義しています。 ib_actionで、アクションを定義します。</p>
<p>ボタンがクリックされたときにここで定義したアクシ ョンが呼ばれるように後で設定します。<br />
def post … end にアクションpostの処理内容を書きます。 Twitterクラスのインスタンスを生成し、ウィンドウに入力してあるメッセージをポストします。@nameで参照しているオブジェクトを取得し、stringValueメソッドでそのオブジェクトの文字列を取得します。 stringValueで取得した文字列はCocoaの文字列クラスのオブジェクトなので、to_sメソッドで Rubyの文字列に変換しています。</p>
<p align="justify"> setStringValueメソッドで、参照しているオブジェクトの文字列に文字を設定しています。</p>
<p align="justify">このコードを保存し、次にInterfaceBuilderを使ってUIとコントローラを結びつけていきます。 プロジェクトウィンドウのMainMenu.nibをダブルクリックする(4)とInterfaceBuilderが立ち上がります。</p>
<p> <a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/mainmenunib.png" title="mainmenunib.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/mainmenunib.thumbnail.png" alt="mainmenunib.png" /></a> (4)<br />
LibraryパレットからNSObjectをドラッグし、メインウィンドウにドロップします(5)。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/movensobject.png" title="movensobject.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/movensobject.thumbnail.png" alt="movensobject.png" /></a> (5)<br />
このオブジェクトを選択した状態で、クラスパレットのClassに先程作成したAppControllerを選択します(6)。</p>
<p align="justify"> <a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/selectappcontroller.png" title="selectappcontroller.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/selectappcontroller.thumbnail.png" alt="selectappcontroller.png" /></a> (6)<br />
次にWindowとコントローラを結びつけていきます。今回は元々あるWindowは使わないので、メインウィンドウにあるWindowを削除します。<br />
LibraryパレットからHUD Windowをドラッグ&amp;ドロップでメインウィンドウに移動します(7)。</p>
<p><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/hudwindow.png" title="hudwindow.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/hudwindow.thumbnail.png" alt="hudwindow.png" /></a> (7)</p>
<p>このウィンドウとコントローラを結びつけるために、メインウィンドウのAppControllerをCtrlキーを押したままマウスを押し、Windowにドラッグして離します。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-5.png" title="picture-5.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-5.thumbnail.png" alt="picture-5.png" /></a> (8)</p>
<p align="justify"> Outletsというウィンドウが表示されるので、AppController.rbのib_outletに定義した windowを選択します(8)。次に、Twitterにポストするために必要なボタンやテキストフィールドを追加していきます。<br />
メインウィンドウのPanel(Window)をダブルクリックするとそのウィンドウが表示されるので、そこにパネルウィンドウから必要なオブジェクトをドラッグ&amp;ドロップで配置していきます(9)。今回は、PushButtonとTextField,Secure TextField, Labelを使いました。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/windowbottun.png" title="windowbottun.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/windowbottun.thumbnail.png" alt="windowbottun.png" /></a> (9)<br />
配置したテキストフィールドやボタンとコントローラを結びつけていきます。<br />
メインウィンドウのAppControllerを選択し、Ctrlキーを押したままマウスを押してウィンドウのオブジェクトにドラッグして離します。すると、選択肢にAppController.rbで定義したアウトレットが表示されるので、対応するものを選択します(10)。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-6.png" title="picture-6.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-6.thumbnail.png" alt="picture-6.png" /></a> (10)<br />
messageやname,passwordの部分をこのように設定していきます。<br />
次はTwitterにポストする時に押すボタンとコントローラを結びつけます。<br />
アウトレットの時とは逆に、ボタンを選択しCtrlキーを押したままマウスを押してメインウィンドウのAppControllerにドラッグして離します(11)。<br />
このとき、AppController.rbのib_actionに定義した「post」が表示されるので、選択します。</p>
<p align="justify"><a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-7.png" title="picture-7.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/picture-7.thumbnail.png" alt="picture-7.png" /></a> (11)<br />
ウィンドウのオブジェクトをすべてコントローラと結びつけたら、実行してみます。<br />
Xcodeのメニューにある、Build -&gt; Build and Go で実行するとアプリケーションが立ち上がります(12)。</p>
<p align="justify"> <a href="http://tech.feedforce.jp/wp-content/uploads/2008/06/rctwitter.png" title="rctwitter.png"><img src="http://tech.feedforce.jp/wp-content/uploads/2008/06/rctwitter.thumbnail.png" alt="rctwitter.png" /></a> (12)</p>
<p align="justify"> Twitterのアカウント情報を入力し、Postボタンを押してMessageを投げることができれば成功です。</p>
<h2>おわりに</h2>
<p align="justify"> 細かな処理は省略しましたが、RubyCocoaを使ってアプリケーションを作る大まかな流れはつかめたと思います。<br />
アカウント情報が間違っていた場合の例外処理や、そもそも設定部分は環境設定画面に置くなど、まだまだやることはたくさんありそうです。</p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_928070_2892.html">
    <title>Mercurial はじめの一歩</title>
    <link>http://feed.feedforce.jp/item_30880_928070_2892.html</link>
    <dc:date>2008-05-30T16:11:35+09:00</dc:date>
    <description>弊社ではソースコードの管理にSubversionを使用していますが、個人的に興味があるので、分散バージョン管理システムの一つであるMercurialを触ってみました。</description>
    <content:encoded><![CDATA[<p>弊社ではソースコードの管理に<a href="http://subversion.tigris.org/">Subversion</a>を使用していますが、個人的に興味があるので、分散バージョン管理システムの一つである<a href="http://www.selenic.com/mercurial/wiki/">Mercurial</a>を触ってみました。</p>
<p> <a href="http://tech.feedforce.jp/mercurial.html#more-59" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
  <item rdf:about="http://feed.feedforce.jp/item_30880_885652_2892.html">
    <title>OpenVZ - OSレベルの仮想化について</title>
    <link>http://feed.feedforce.jp/item_30880_885652_2892.html</link>
    <dc:date>2008-04-25T18:18:11+09:00</dc:date>
    <description>OpenVZは、Linuxで動作するコンテナベースの仮想化ソフトです。</description>
    <content:encoded><![CDATA[<p>OpenVZは、Linuxで動作するコンテナベースの仮想化ソフトです。</p>
<p>本家URL<br />
<a href="http://openvz.org/">http://openvz.org/</a><br />
wiki<br />
<a href="http://wiki.openvz.org/">http://wiki.openvz.org/</a></p>
<p> <a href="http://tech.feedforce.jp/open-vz.html#more-58" class="more-link">(more&#8230;)</a></p>]]></content:encoded>
  </item>
</rdf:RDF>
