Sinatra触ってると出てくるRackって何?

Sinatraを触ってると、Rackがいろんなところで出てくるが、いまいちわからないので調べた。

以下のページを参考。

Rackとは、

ミドルウェアである。

別なアプリケーションをラップして、リクエストやレスポンスの加工、処理を切り替える。

WSGIに影響された。

WSGIとは,PythonのためのWebサーバとWebアプリケーション/フレームワーク間の標準インターフェースを定める「仕様」です。(中略)
両者間の標準インターフェースが提唱され,WSGIに対応しているフレームワークと,WSGIを介して連携できるWebサーバとをユーザが好みの組み合わせで使えるようになったのです。(中略)
RackはこのWSGIに影響されて開発された,Rubyにおけるサーバとアプリケーション/フレームワーク間のインターフェースの役割を果たすライブラリです。

「インターフェースが統一されていれば,サーバやフレームワークの組み合わせは自由である」
Ruby Freaks Lounge:第23回 Rackとは何か(1)Rackの生まれた背景|gihyo.jp … 技術評論社

rackupによって起動される。

app.rb等、ファイルの末尾に以下のコードを書き加えることで、app.rb単体でアプリケーションを起動できる。

if __FILE__ == $0
  require 'rack/handler/webrick'
  Rack::Handler::WEBrick.run SimpleApp.new, :Port => 9292
end

問題は、サーバ依存のコードが残ってしまうこと。
サーバとアプリケーションの間に、Rackが入ることによって、自由に組み合わせられるのメリットが失われてしまう。
だから、rackupによって、起動させる。

「基本的にはconfig.ruに色々書いて,アプリケーション側にはサーバ依存のコードは書かない」


以下のものが最低限必要。
  • callというメソッドを持っていること
  • callメソッドの引数としてWebサーバからのリクエストを受けること
  • callメソッドは,次の要素を含むレスポンスを返すること

Lokkaプラグインlokka-twitter_urlを作ってみた

大したものじゃないけど、Lokkaプラグイン作ってみた。

[twitter:meganii]

って、やると、http://twitter.com/meganiiへのリンクに置換するよ。


以下、参考にさせてもらいましたー!!
URLを自動でリンク先のタイトルで展開するLokkaプラグイン - a newcomer!


lokka-twitter_url.rb
module Lokka
  module TwitterUrl
    def self.registered(app)
      %w(posts posts/* pages pages/*).each do |suburl|
        app.before("/admin/#{suburl}") do
          if @request.env['REQUEST_METHOD'] =~ /POST|PUT/ && 
             (body = (params[:post] && params[:post][:body]))
            body.force_encoding("utf-8").gsub!(/\[twitter:(.*?)\]/u){ TwitterUrl::Util.link($1) }
          end
        end
      end
    end

    module Util
      def self.link(id)
        "<a href=\"http://twitter.com/#{id}\" target=\"_blank\">@#{id}</a>"
      end
    end
  end
end

gsub!

gsub!メソッドは、パターンにマッチした部分をすべて指定の文字列に置換します。レシーバ自身を変更するメソッドです。戻り値は、置換が行われたときはレシーバ自身、変更がなかったときはnilです。
gsub, gsub! (String) - Rubyリファレンス

お名前.comで取得したドメインでHeroku×Lokkaを動かすまで

最近、Heroku上でLokkaを動かして遊んでいます。せっかく、勢いで独自ドメインを取ったので、独自ドメインで運用してみようと思ったときの備忘録です。

参考にさせてもらったページ

基本的に、ここのページを参考にさせてもらいました。

heroku側で、クレジットカードの番号を有効にして、設定を完了したあと、
お名前.comのレンタルDNSレコード設定を変更。

Herokuアプリに独自ドメインを割り当てる(ムームードメインの場合) - アインシュタインの電話番号☎

あとは、DNSの反映が完了するのを待つだけ

完全に切り替わるまで、1日以上かかった気がします。
ギークなひみつきち

次にやりたいこと

GoogleAppEngineでRSS配信したい

twitterのリストから取得した情報をRSSとして配信したい。

参考にしたページ

from django.utils import feedgenerator
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext import db
from google.appengine.ext.webapp import template

class Rss(webapp.RequestHandler):
    def get(self):
        # フィード作成
        feed = feedgenerator.Rss201rev2Feed(
            title = "extweet",
            link = "RSSのURL",
            description = "RSSの説明",
            language = u"ja")

        tweets = db.GqlQuery("SELECT * FROM Tweet ORDER BY date DESC")
        for tweet in tweets:
            feed.add_item(
                title = tweet.content,
                link = tweet.urls[0],
                description = tweet.content,
                pubdate = tweet.date)
    
        # RSS 文字列にする
        rss = feed.writeString("utf-8")
        self.response.headers['Content-Type']='text/xml; charset=utf-8'
        self.response.out.write(rss)

def main():
    application = webapp.WSGIApplication([('/rss',Rss)],
                                         debug=True)
    util.run_wsgi_app(application)


if __name__ == '__main__':
    main()
(中略)
        if lasttweet != None:
            cursor = tweepy.Cursor(api.list_timeline,owner=OWNER,slug=SLUG,since_id=lasttweet.id,include_entities='true').items(100)
        else:
            cursor = tweepy.Cursor(api.list_timeline,owner=OWNER,slug=SLUG,include_entities='true').items(100)

        for tweets in cursor:
            tweeturls = []
            for e in tweets.entities['urls']:
                tweeturls.append(e['expanded_url'])

            if len(tweeturls) > 0:
                if lasttweet != None:
                    if tweets.id > lasttweet.id:
                        tweet = Tweet()
                        tweet.id = tweets.id
                        tweet.urls = tweeturls
                        tweet.title = tweets.text
                        tweet.content = tweets.text
                        tweet.save()
                        self.response.out.write(tweets.text)

なぜかこれだと、Bylineで読み込んだときに、空白のページになってしまった。
RSSの仕様を見ると、エンティティエンコードされたHTMLが使えますとのこと。もしかして、これかと思って、CDATAタグを加えてみると、なんだかうまく行ったみたい。。。

んー、何が原因だったんだろう?

RSS 2.0 Specification 日本語訳 - futomi's CGI Cafe
description がテキスト(エンティティーエンコードされた HTML が使えます。例をご覧下さい。)を含んでいるなら、その item はそれ自身で完結するかもしれません。 ...


Encoding & item-level descriptions (RSS 2.0 at Harvard Law)


CDATAタグを埋め込んだ

  tweet = Tweet()
  tweet.id = tweets.id
  tweet.urls = tweeturls
  tweet.title = tweets.text
  content = "<![CDATA[" + tweets.text + "<a href=\"" + tweeturls[0] + "\">" + tweeturls[0] + "</a>" + "]]>"
  tweet.content = content
  tweet.save()

次実装したい機能

  • 自分に必要なURLだけを、抽出したい。(foursquereとか, 写真とか省きたい)
  • 一日のURLをまとめて, Evernoteに送りたい
  • 誰が共有したのかをわかるようにしたい
  • 同じURLが共有されている場合、その共有数と名前がわかるようにしたい