Integrityのコードにあったaタグの書き方。

%Q(<a href="#{page_data.last}">#{page_data.first}</a>)

"が書けるから楽なんですね。ちょっと嬉しい。

lib/integrity/helpers/breadcrumbs.rb at master from integrity's integrity - GitHub

'unk'.to_sym

って

:'unk'

こうも書けるんですね。知らなかった…orz

HashWithIndifferentAccessとかMashに慣れ過ぎてシンボルを疎かにしてると裏世界でひっそり幕を閉じる。(@ブロントさん)

:"u#{n}k"

こういう時便利。

CMS作成一人合宿最終日。

cssを書いてないので全然出来てないように見えるが機能的には最低限の機能が出来つつある。あと2日ぐらい作業すればこのブログを移行することが出来そうだ。

検索機能、ページング機能とWordPressでいうところのコンディショナルタグ機能を作った。 コンディショナルタグとは、テンプレート中で今どのページにいるのかを判断するために使う関数。

PyhaもWordPressの影響を受けて、複数のコンテキストを持つが全てに対応するテンプレートを用意する必要は無い。(対応するテンプレートが存在すればそちらを使う)

コンテキストとは、トップページだとかカテゴリーアーカイブとか個別ページとかそいう文脈のこと。

それぞれにテンプレートを用意するのは大変なので、最低限のテンプレートは、インデックスやアーカイブのように、複数のテキストを表示するdocumentsと、個別エントリーのように一つのテキストを表示するdocumentの2つだけだ。

  • documents.erb --- 複数のテキストを表示するテンプレート
  • document.erb --- 一つのテキストを表示するテンプレート

テンプレートをまるごと切り替える必要はないが、例えば一つのテンプレート内でタイトルだけはコンテキストに応じて変更したいという場合にコンディショナルタグを使う。

<% if category? %>
  <h2>カテゴリーページ</h2>
<% else %>
  <h2>トップページ</h2>
<% end %>

のように使う。

現状あるコンテキストにあわせて下記のコンディショナルタグを用意した。

  • index?
  • search?
  • category?
  • yearly?
  • monthly?
  • dialy?
  • document?
  • documents?

最後の2つはコンテキストではなく、テンプレートの種類を表すものなので、どれか一つのみがtrueを返すわけではない。例えばindex?とdocuments?は両立する。

(もちろんリリース後に書くドキュメントはこんな小難しい書き方はしない。今は自分の考えをまとめるためにメモする)

現状、例えばWebから投稿するインターフェースは無い。それはすぐ作れるが、テーマ作成者向けAPIが固まらないうちに細部をつくりはじめると、管理画面の実装上の都合などが無意識にAPIに影響を与えてしまうので、先にWordPressのブログを移行するのに十分なAPIを固めた上で作りたい。

先が見えてきたので残りタスクをリストアップしてみた。最初のバージョンは少ない機能でリリースしたい。

5日間一人合宿の感想

5日間かけた割には平均的なRubyistに比べて進みが遅いと思うが、正直、予想以上でも以下でもなく、まあこのぐらい進むだろうなと思っていた通りな感じだった。プログラムを作る方法としては結構はかどるやり方だと感じた。でも途中で@jishihaさんと作っているものについて話したのが非常に良かった。丸5日誰とも合わずに作っていたら機能は増えたかもしれないが、ソフトが良くない方向に進んでいたように思う。勉強会やカンファレンスも楽しいが、自分の作っているプロダクトに関するディスカッション程有益なプログラマー同士のコミュニケーションは無いと強く感じました。

タスク:Issues - komagata/pyha - GitHub

ソース:komagata's pyha at master - GitHub

DataMapperパターンのRuby実装。RDB、KVS、NoSQL系DBをサポートしてて、1.0.0なので結構枯れてる。

調べる必要があったヤツだけをメモ。

スラッグ型(URLの中で使える文字列)

String型のサブクラスだから安心。

require 'dm-types'

Class Post
  include DataMapper::Resource

  property :slug, Slug
end

デフォルトスコープ

Class Post
  include DataMapper::Resource

  property :id, Serial

  default_scope(:default).update(:order => [:id.desc])
end

手抜き全文検索

Class Post
  include DataMapper::Resource

  property :id, Serial
  property :title, String
  property :body, Text

  def self.search(str)         
    all(:title.like => "%#{str}%") |
    all(:body.like => "%#{str}%")   
  end
end
Post.search('unk').all(:limit => 5)

「でたー!クラウザーさんのLIKE '%foo%'だー!」

真面目にやるならdm-is-searchableでインデックスを別のストレージ(DM用語ではrepository)に保存する。

サインアップとログインを作った。

Admin Loginからuser:pass = test1:testで入れる。

ユーザー認証にはsinatara-authenticationというgemがあるが、100行足らずで実装できる部分だし、DataMapperの時点であらゆるDBに対応してるのにそのORM自体を差し替えられるというのはCMSにはオーバースペックなので外した。

sinatra自身もそうだが、ライブラリやフレームワークの癖が強すぎるとCMSとして一貫したAPIを作るのにどうしても思想的な偏りが出来てしまって良くないように思う。(例えばRailsをベースにCMSを作るとRails流儀に合わせようという心的姿勢が無意識に出来てしまう。)

sinatraはそういった癖がかなり少ない方だが、極限までミニマルなCMSを作りたくなる衝動を抑えるのは難しい。

何度かsinatraアプリを作った経験とミニマルになりすぎて実用的でないアプリを量産した苦い思いがなければまた同じ過ちを犯したに違いない・・・。

sinatraも1.0.0が出て、そろそろコミッタもユーザーもクールダウンしているのであくまで裏方として使う良い頃合いなのかもしれない。

管理画面をちょこっと作ってみて、イケそうなので細部はほっておいて、表側のテーマ作成者向けのAPIをきちんとつくっていきたい。

WordPressのデザイナーから見た利点は@machidaさんに事あるごとに質問して来たんだが、下記のサイトを見て、「WordPressでイケル!」と確信を持ったそうです。

WordPressテーマ(テンプレート)カスタマイズのまとめ(日本語訳) - TRANS

これを参考に、「クラウド対応の一貫したテンプレートAPIを持つCMS」というコンセプトが達成できるように作って行こうと思います。

今日は一人合宿ではありませんでした。@jishihaさんからアカデミーヒルズで作業してるので来ませんかというメッセージをもらったので行ってきました。(アカデミーヒルズは会員の同伴者として行くと安く使える)

以前も使わせていただいて快適だったので行くと、土日は同伴者駄目らしい。

ということで、Twitterでの@milkcocoaさん情報により、六本木地下鉄出口付近のルノアールに移動。無茶苦茶空いてるし、電源は使えるしで最高。

というか、お盆で、今日は花火という時に誰も仕事などしないのでルノアールはすいていた。

皆がお盆休みを満喫している間に僕らはモクモクとプログラミングした・・・。

CMSの進捗

昨日、面倒だったユーザー認証を終わらせたので、次に面倒だと思っていたツリー構造を持つカテゴリー機能を作った。幸いdm-is-treeというdatamapperのプラグインが殆どの面倒な部分を片付けてくれた。(DOMのように、parent, children, siblings, ancestorsなどのメソッドがある。特にancestorsがあればパンくずリストが簡単に出来る)

ついでに年別アーカイブ、月別アーカイブ、日別アーカイブも作った。group byなどのSQLを使ったらKVSにも対応してる意味が無くなるのでちょっと面倒。

デザイナーに使ってもらう工夫について

WordPressにある機能の実装にはさして問題なさそうだが、@jishihaさんとどうやったらエンジニア以外に使ってもらえるかについて色々話した。

WordPressのテーマをこのCMSを用に変換できるようにしたらどうか、とか、GUIインストーラーを作ったらどうかなど。

尖ったプログラマーがやらない地味なサイトやドキュメント整備が大事だという点は頑張ろうと思いました。

テストサイト:http://pyha.heroku.com/

ソース:komagata's pyha at master - GitHub

標準ライブラリのDateで月の加減計算が出来るって知ってました?

Ruby、3年以上はやってるはずなのに知りませんでした…orz

+, -で日の加減が出来るのは直感的にわかるけど、月に対しても出来るとはびっくりしました。

% irb -r date
>> (Date.today).to_s
=> "2010-08-15"
>> (Date.today << 2).to_s
=> "2010-06-15"
>> (Date.today >> 5).to_s
=> "2011-01-15"

サブクラスのDateTimeでもモチロン出来ます。

オーマイガッ!

とりあえずHerokuで動かしてみた。

Test Site

Herokuのbundlerが1.0.0.rc.2に上がってて糞ハマる。

CMS本体のコードよりも、テーマ作成者向けのAPIを慎重に吟味する。

テーマファイルは下記のような構成にした。

  • posts.erb --- 複数の投稿を表示するページ。(トップページ、アーカイブ、検索結果など)
  • post.erb --- ひとつの投稿を表示するページ。(個別ページ)
  • index.erb(必須でない)--- トップページ。このファイルが無い場合はposts.erbが使われる。
  • layout.erb(必須でない)--- レイアウトファイル。このファイルが無い場合はレイアウト機能は使われない。
  • style.css(必須でない)--- CSS。

本棚戦略

僕は「読んだ本全ては売る」という本棚戦略を取っている。(ブックオフの宅本便に送る)

この戦略で盲点だったのは、家に残るのは「超分厚い本」や「難解な本」ばかりになってしまうことだ。

本棚のタネンバウムのオペレーティングシステムを苦々しい思いで睨みつけていた。

そこで本を裁断してPDF化してくれるサービスを利用することにした。

読書観

読めれば良い。最悪真っ白なPDFが送られてきてもネタになる。それよりも狭い部屋を圧迫する本棚が問題だ。

スキャポンの対応

裁断サービスは軒並み申し込みが殺到していたので、複数申し込み、最初に使えるようになったスキャポンに申し込んだ。めったに頼まないだろうし、値段は1冊100円だろうが200円だろうがどうでもいい。面倒が少ないサービスを使いたいと思っていました。

6月21日:

PayPalで66冊分の料金を支払った。本を送ってから2〜3週間でPDFが送られてくるらしい。本が詰まったダンボール数箱は運ぶのが大変なのでヤマト運輸の集配サービスを使った。便利。

8月3日:

本を郵送してから1ヶ月以上経つのに何の音沙汰も無い。PayPal前払いのみなので詐欺だとしても何の不思議も無いのでメールで問い合わせた。

駒形様

スキャポン運営事務局です。
このたびは弊社サービスの遅れ誠に申し訳ございません。

駒形様の書籍は、昨日データ化をおこないまして、本日から明日にかけて
検品とOCRを予定しております。

今しばらくお待ちいただけますよう何卒よろしくお願い申し上げます。

1ヶ月以上経つのにちょうど今日やってたってそれ、蕎麦屋の「今出ました」的な?

8月4日:

次の日あっさり納品された。DropBoxが遅いため、指定のURLからダウンロードして欲しいとのこと。フリーのDynamicDNSサービスのドメインでBasic認証フォルダ直置きかあ・・・。

PDFをダウンロードしてみると、読めない部分はまず無いという品質でとても満足。オプションで頼んだOCRも良好なようだった。しかし明らかにファイル数が少ない。簡単なコマンドでファイル数を調べると39冊しかない。66冊頼んだのに半分強しかない。メールで問い合わせると、

駒形様

スキャポン運営事務局です。
下記の件、大変失礼いたしました。

只今、残りのデータをアップロードしておりますので、8分ほどお待ちいただけますよう
なにとぞよろしくお願い申し上げます。

とのこと。

その後、無事69冊のPDFがダウンロードできた。冊数は少ない方でも多い方でもいい加減なのね…。

ファイル名を本のタイトルにするという有料オプションを申し込んでいたが、何冊かは間違っていた。

感想

PDFの品質やOCRの精度にはとても満足しています。でもそれって全部SnapScanの性能なんじゃ…。応募が殺到して忙しいのは理解できますが、SnapScanの性能以外のサービスはとても低いように思いました。

次頼む時は他のサービスの体験談も出揃ってると思うのでそれを参考に決めたいと思います。

関連:本棚オーバーフロー問題 - komagata [p0t]

RubyでJavaScriptみたいにアクセサが自動定義されてるHashみたいのって何を使えばいいのかなと思ってたんですが、標準ライブラリにOpenStructなんてのがあるんですね。

% irb -r ostruct
>> hash = {:foo => 1, :bar => 2}
=> {:foo=>1, :bar=>2}
>> hash.foo
NoMethodError: undefined method `foo' for {:foo=>1, :bar=>2}:Hash
        from (irb):2
>> ostruct = OpenStruct.new(hash)
=> #<OpenStruct foo=1, bar=2>
>> ostruct.foo
=> 1

便利ー!

参照:ostruct - Rubyリファレンスマニュアル