2011/06/16


タイトル長い!

言ったからには自分で書こう...
Twitter / mattn: 当たり前だと思うけど、PerlerならWeb::Sc ...

当たり前だと思うけど、PerlerならWeb::Scraperでアカウント名取ってNet::Twitter::Liteでfollowするよね? #perl http://d.hatena.ne.jp/...

https://twitter.com/mattn_jp/status/81320211634069504
所要時間、約10分
use strict;
use warnings;

use Config::Pit;
use Net::Twitter::Lite;
use URI;
use Web::Scraper;

my $uri = URI->new('http://d.hatena.ne.jp/sugyan/20110616/1308203734');

my $config = pit_get('api.twitter.com');
my $nt     = Net::Twitter::Lite->new(%$config);

my $helper = scraper {
    process '//div[@class="body"]//a[contains(@href,"http://twitter.com/")]',
      'link[]' => '@href';
};

$helper->user_agent->env_proxy;

my $res = $helper->scrape($uri);
for my $link (@{$res->{link}}) {
    print "$link\n";
    $link =~ s!.*/!!;
    #$nt->follow( $link ); # ココのコメント外してね
}

※ただし、動かした事がない。

Posted at by




Github
GithubのユーザページでJekyllが使われる様になりました。
GitHub Pages Upgraded to Jekyll 0.5.0 - GitHub

I just released Jekyll 0.5.0 which contains a huge overhaul that allows you to specify options in a _config.yml file. GitHub Pages will honor most of these settings, so if you want to have your Page rendered with RDiscount instead of Maruku, just put this in your config file: ...

http://github.com/blog/402-github-pages-upgraded-to-jekyll-0-5-0
Githubでは
username.github.com
というリポジトリを作成し、その中にHTMLファイルを作成すると
http://username.github.com
で表示出来るという使い方が出来るのですが、このコンテンツ管理にJekyllが使われる事になりました。
mojombo's jekyll at master - GitHub

Jekyll is a blog-aware, static site generator in Ruby

http://github.com/mojombo/jekyll/tree/master
Jekyllは制御構文処理にliquid、コンバータとしてredclothを使用し、Marukuもしくはrdiscountを使ったMarkdown記法が可能なブログジェネレータです。
起動方法によってはWEBrickを使ったWebサーバまで起動出来る便利なツールになっています。
今日はこのJekyllを使用した、簡単なブログの書き方をご紹介します。

設定ファイルとディレクトリを用意する

まず設定ファイルを用意します。ほぼデフォルトのままで十分ですが以下のファイルを用意します。

_config.yml
#destination: ./_site
#auto:        false
#lsi:         false
#server_port: 4000
pygments:    true
#markdown:    maruku
#permalink:   date
次に以下の様なディレクトリ構成を作成します。
※ルート
|   _config.yml
|  
+---_layouts
|       ※レイアウトファイルを格納するディレクトリ
|  
+---_posts
        ※記事を格納するディレクトリ

レイアウトファイルを用意する

Jekyllでブログを書く場合に機能するファイルは
  • デフォルトレイアウト(_layouts/default.html)
  • 記事データ用レイアウト(_layouts/post.html)
  • サイトページ(index.html)
  • 記事データ(_posts/yyyy-mm-dd-blog-title.html)
となります。記事データ以外はほぼテンプレート扱いのファイルになりますのでこの時点で作成します。
まずデフォルトレイアウト
_layouts/default.html
<!doctype html>
<head>
    <title>{{ page.title }}</title>
    <link rel="stylesheet" href="/css/site.css" type="text/css" />
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
</head>
<body>
    <div id="content">
    {{ content }}
    </div>
</body>
liquidの構文 {{ page.title }}
{{ content }}
があります。前者にはページのタイトルが、後者にはページのコンテンツが割り当てられます。

次に記事データ用テンプレート
_layouts/post.html
---
layout: default
---
<div class="post">
<h1>{{ page.title }}</h1>
Posted at <span>{{ page.date | date_to_string }}</span><br />
<br />
{{ content }}
</div>
<a href="/">もどる</a>
YAML形式になっています。このlayoutの値defaultを使用して上記defaultレイアウトが選択されている事になります。

そしてサイトページ
サイトページには一般的なブログと同じく、記事の一覧を表示したいと思います。
liquidのfor構文を使用して以下の様に書きます。
index.html
---
layout: default
title: つけ麺旅行記
---

<div class="posts">
<h1>{{ page.title }}</h1>
<ul>
{% for post in site.posts limit:3 %}
    <li><span>{{ post.date | date_to_string }}</span>&nbsp;&raquo;&nbsp;<a href="{{ post.url }}">{{ post.title }}</a></li>
{% endfor %}
</ul>
</div>
デフォルトレイアウトを使用し、titleの値が指定されています。つまりこのサイトのタイトルは「つけ麺旅行記」になるのです。
またfor構文で記事データの内3件のタイトルと日付が表示されます。
出来上がった構造は以下の様になります。
|   index.html
|   _config.yml
|  
+---_layouts
|       default.html
|       post.html
|      
+---_posts
       ※記事を格納するディレクトリ

記事データを書く

この時点で既にブログとして機能しています。試しに以下の様にサーバを実行してみましょう。
# jekyll --server --auto
--serverオプションでWEBrickを使用したサーバを起動します。起動すると_siteというディレクトリが作成され変換されたHTMLが格納されます。またバイナリファイルやCSSファイル等はルートから_siteディレクトリにコピーされる様になっています。
また--autoオプションを指定する事でディレクトリ変更を監視させます。ローカルでファイルが変更された場合、自動的に_siteディレクトリへの変換が行われます。引数で与える事が出来るパラメータは_config.ymlでも設定可能ですので詳しくはマニュアルを参照下さい。

記事データは_postsディレクトリに保存します。この時ファイル名に一定の規則がありファイル名の先頭がYYYY-MM-DDによる日付表現、その後続く名称(ハイフンやアンダースコアは空白と見なされる)が記事タイトルとなります。但しYAML記述でtitleを指定した場合にはそちらが優先されます。
今回は例えば、2009年4月16日に「つけ麺」に関する記事を書いたというデータとして以下の様に記事ファイルを作成しました。
なお、拡張子を.mdにする事でMarkdown記法しています。

_posts/2009-04-16-greeting.md
---
layout: post
title: つけ麺の美味しい店 その3
---
京都にあるらしい。
-----------------

![麺や高倉二条](http://www.hotpepper.jp/IMGDB_MP/95/19/M000009519/M000009519_368.jpg)

って[どこかのブログ](http://d.hatena.ne.jp/naoya/20090405/aho_corasick)に書いてあった。
ほんとに旨いらしい。
このファイルを作成した瞬間にサーバが更新を検知し、_siteへHTML変換してくれます。

ブラウザで閲覧する

デフォルトのポート番号は4000になっています。「http://localhost:4000/」でルートを表示すると以下の様に表示されます。
今回は例として「つけ麺」の記事を3件書いた事にしています。
jekyll1
そして記事本体へのリンク(16日の記事)をクリックすると以下の様に表示されます。
jekyll2
見事に記事が表示されました。レンタルサーバ等では上記の様にサーバとして起動するのではなく # jekyll
と単体起動させて_siteディレクトリにHTMLを出力させ、出来上がった_siteディレクトリ配下をFTPでアップロードするという流れになるかと思います。

一度ここまでの環境を作成しておけば
  1. 記事を書く
  2. jekyllでHTMLファイルを出力する
  3. サーバへアップロードする
という手順だけでブログを更新出来ます。

なお、jekyllは発展途上のプロジェクトなので要望があればgithub上でclone/push requestして欲しいと作者も書いています。ぜひcontribute authorになってみて下さい。
少しギーク仕様ぽいですが、慣れると使いやすそうな気がします。一度試してみては如何でしょうか?
Posted at by



2011/06/09


Google App EngineへのGo言語アップロード権(Trusted Tester for the golang runtime for appengine)を得たので、Webアプリを作り始めたら皆が必ず作るという「おうっふー」をGo言語に移植してみた。
なお、「おうっふー」とはログイン画面のみを持ち、ログインすると有無を言わさず「おうっふー」という単語をログインアカウントにポストするWebアプリケーションの事。知ってない奴はWeb界のモグリだ!って隣の人が言ってた。
以下、Go言語のコードを解説してみる。 ログイン画面からログインハンドラに要求が行われると、OAuth1.0でリクエストトークンがTwitterに要求され、得たテンポラリトークンで認証画面に遷移します。 http.HandleFunc("/login"func(w http.ResponseWriter, r *http.Request) {
    client := urlfetch.Client(appengine.NewContext(r))
    tmp, err := creds.request(client)
    if err != nil {
        http.Error(w, err.String(), 500)
        return
    }
    url := fmt.Sprintf("%s?oauth_token=%s&oauth_callback=%s", authURI, http.URLEscape(tmp.Key), http.URLEscape(callbackURI))
    w.Header().Set("Set-Cookie""tmp="+http.URLEscape(tmp.Key)+"/"+http.URLEscape(tmp.Secret))
    http.Redirect(w, r, url, 302)
})
この時、注意しなければならないのがurlfetchにリクエストから作成したコンテキストが必要である事。urlfechを使いたい関数までhttp.Requestを引きずり回さないといけないという、なんとも煩わしい仕様ですがキマリはキマリ。
また認証画面から戻って来た時に再び照合が行える様に、テンポラリトークンをクッキーに保持しておきます。

認証画面から戻ってくると登録していたコールバックURLが呼び出されます。 client := urlfetch.Client(appengine.NewContext(r))
v := r.FormValue("oauth_verifier")
a := strings.Split(r.Header.Get("Cookie"), "=", -1)
w.Header().Set("Set-Cookie""tmp=")
if len(a) != 2 || a[0] != "tmp" {
    http.Error(w, "invalid request"500)
    return
}
a = strings.Split(a[1], "/", -1)
if len(a) != 2 {
    http.Error(w, "invalid request"500)
    return
}
ak, _ := http.URLUnescape(a[0])
as, _ := http.URLUnescape(a[1])
tmp := &Token{ak, as}
token, err := creds.verify(client, tmp, v)
if err != nil {
    http.Error(w, err.String(), 500)
    return
}
クッキーを読み取り得たテンポラリトークンと、認証画面から戻されたベリファイアを合わせて照合を行います。Twitter APIを使ったアプリをバシバシ書いてる諸君なら、鼻くそほじるより簡単ですね。
後は得られたアクセストークンを使ってTwitterにポストする。 gouffu := []string{"ごうっふ~""おうっふ~""もうっふ~""とうっふ~""もふもっふ~""わっふ~""きゃっふ~"}
data := map[string]string{"status": gouffu[rand.Int()%len(gouffu)]}
creds.sign(token, data, resURI, "POST")
resp, err := client.PostForm(resURI, data)
if err != nil {
    http.Error(w, err.String(), 500)
    return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
    http.Error(w, resp.Status, 500)
    return
}
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
    http.Error(w, err.String(), 500)
    return
}
var m map[string]interface{}
err = json.Unmarshal(b, &m)
if err != nil {
    http.Error(w, err.String(), 500)
    return
}
screen_name := m["user"].(map[string]interface{})["screen_name"].(string)
id_str := m["id_str"].(string)
url := fmt.Sprintf("https://twitter.com/%s/status/%s", screen_name, id_str)
http.Redirect(w, r, url, 302)
単語1つでは遊び心が無いので、何個か用意した。ポストが完了したらパーマリンクへリダイレクトする様にした。
なお、このサーバではクッキーは一時的に保存する事はしてもデータストア等には何も残していません。

ごうっふ~

...

http://go-ouffu.appspot.com/
良かったら遊んでみて下さい。
ソースはこの辺に置いときます。
mattn/go-ouffu - GitHub

ごうっふ~

https://github.com/mattn/go-ouffu
Posted at by