GitHub Pages を使い始めたこと

ブログが増え(て)ました。

Hi - Hibariya

http://hibariya.github.com/index.html

理由:いつも使っているエディタ(自分の場合はVim)で日記が書きたかった。

あまりにもテキストエリアでの文章編集(とはてな記法)が身につかないので、いかに日記を楽に書くかを追求する予定。まずは、ターミナルから簡単に記事を書くためのツールをつくった。$EDITORを使ってターミナル上で記事を編集・プレビュー・公開までできるCUI向けツール。

GitHub - hibariya/retter: A diary workflow for shell users

さて、ご存知の方も多いと思いますが、世の中には Octopress という素晴らしいツールがあります。僕はRetterの開発途中でOctopressの存在に気づいてしまった。*1

作ってしまったものは仕方がないし、どこまでのものを作ることができるかも試したいので、しばらくは黙々と開発を続けようと思います。パッチなどは小さなものから大きなものまで受け付けております。

*1:もちろんRetterにも優れている点があります。このツールはretterというコマンドで操作するのですが、コマンド自体は片手だけで打ててしまうため、とても指にやさしいです。

Rails勉強会@東京第63回でセッションオーナーというのをやったこと

ここ数ヶ月間、行こう行こうと思いつつ中々いけなかった Rails' Wiki - Rails勉強会@東京第63回 に行ってきた。今回は RubyKaigi Advent Calendar 2011 | 日本Ruby会議2011(7月16日〜18日) のイベントのひとつでもあるのでした。

久々の参加で遅刻したんですが、着いて早々に [twitter:@takkanm] さんに「Rails3.1のセッションもって」と指名された。こういうイベントで長時間話した経験は無いし、何をやるべきなのかぼんやりとしか分かっていなかったので、結構困惑した。その時点で最新のRailsすらマシンに入れて無かったし、話せることは全くない気がしていたのでした。
だけど心配はいらなかった! 今回は状況がよかった(みんな割と詳しかった、他)のもあると思うけど、事前に入念な準備が必要なわけではないし(あるに越したことはないけど)、知らないことがあるとむしろそれをトピックにできたりして、セッションオーナーというのはとても好都合な立ち位置なのでした。周りの人とだいたい同じような立ち位置のままで、ききたいことがすぐきけるし話に入りやすい。そうやって周りの人に身を任せてお喋りするのは割と楽しい。
セッションオーナーという名目があるとお喋りするのが当然になって、イベントに参加している感がとても出てくるようなので、寂しがり屋でシャイでものぐさな人にはとても合っているのではないかと思いました。

決してうまくやれた訳ではないけど好い経験になった。
あと、そのとき教えてもらった ‎RailsCasts on Apple Podcasts はとても便利そうだと思いました。

Mongoid::Paranoiaで論理削除したドキュメントも一緒くたに問い合わせる

hatena.vimの動作確認も兼ねて。

unscoped で論理削除されたものも引っ張ってこれるかと思ったら違った。

    # mongoid-2.0.2/lib/mongoid/paranoia.rb
    <中略...>
    module ClassMethods #:nodoc:
                                                                                                                                                                                                                
      # Override the default +Criteria+ accessor to only get existing
      # documents. Passes all arguments up to +NamedScope.criteria+
      #
      # Returns:
      #
      # A +Criteria+ for deleted_at not existing.
      def criteria(*args)
        super.where(:deleted_at.exists => false)
      end
      # Find deleted documents
      #
      # Examples:
      #
      #   <tt>Person.deleted</tt>  # all deleted employees
      #   <tt>Company.first.employees.deleted</tt>  # works with a join
      #   <tt>Person.deleted.find("4c188dea7b17235a2a000001").first</tt>
      def deleted
        where(:deleted_at.exists => true)
      end
    end
    <中略...>

Mongoid::Paranoiaを使うとcriteriaが上書きされるんですね。だから unscoped とかしてもだめだったのか。
削除されたものは deleted で取れるけど、論理削除関係なく問い合せたいときはどうするんだろう。

module Mongoid::Paranoia::ClassMethods
  def with_deleted
    c = criteria
    c.selector.clear
    c
  end
end

足してその場をしのいだ。

はっとしたこと

ruby-1.9.2-p0 > 10.times.map{ 'foo' }.map{|v| puts v.object_id }
2152510320
2152510280
2152510200
2152510160
2152510120
2152510060
2152510020
2152509980
2152509920
2152509780
 => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] 
ruby-1.9.2-p0 > (['foo']*10).map{|v| puts v.object_id }
2151828140
2151828140
2151828140
2151828140
2151828140
2151828140
2151828140
2151828140
2151828140
2151828140
 => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] 

あまり意識してなかった。
http://doc.ruby-lang.org/ja/1.9.2/class/Array.html

数値とかSymbolはどちらも同じでobject_idは変わらない。少し前にRHGをさらっとだけ読んだのでこれは想像できた。

ruby-1.9.2-p0 > 10.times.map{ :urryyyy }.map{|v| puts v.object_id }
498728
498728
498728
498728
498728
498728
498728
498728
498728
498728
 => [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] 

予想があたってよかった。

Fabricationを使ってみた

※2011/11/08 コメント欄で指摘を頂いた箇所を加筆修正しました。また、割と古い記事ですので最新の情報は Fabrication を参照することをお奨めします。

これを作ってるとき、machinistとmachinist_mongoを使っていたんですが、試しに前々から気になっていたFabricationで書き換えてみました。README書いてあることをいくつか実際にやってみたのでメモしておきます。割と使いやすかったです。

何に使えるの

下記をサポートしてるそうですので、Mongoid使えます。やった!

使ったもの

  • Fabrication…本日のメイン
  • Faker…嘘データをどんどこ作ってくれるやつ

QuickStart & 使い方

Gemfile

Rails/Mongoid/RSpec/Fabricationで↓のような組み合わせで使ってます。

group :development, :test do
  gem 'rspec-rails', '>= 2.0.0.beta.22'
  gem 'mongoid-rspec'
  gem 'faker'
  gem 'fabrication'  # <= これ
  gem 'wirble'
  gem 'spork'
end
記述する場所

spec/fabricators.rbに書くか、spec/fabricators/*.rbに複数ファイルにして書いてもいいみたいです。ここに置いておけば、必要になったら勝手に呼ばれます。最初から自分で読み込んでおきたいときはspec/spec_helper.rbなどに書きます。

Fabricatorを書いて使ってみる

spec/fabricators.rbなどにfabricatorを書いていきます。blueprintみたいな感じで。

# Userモデルはこんな感じだとします
class User
  include Mongoid::Document
  field :screen_name, :type=>String
  field :description, :type=>String
  field :site, :type=>String
  field :gender, :type=>String
end

# Userモデルのfabricatorを作ります
Fabricator(:user) do
  screen_name { Faker::Internet.user_name }
  description { Faker::Lorem.paragraph[0..190] }
  site { ['http://', Faker::Internet.domain_name].join }
  gender { ['male', 'female'].sort_by{ rand }.first }
end

作ったFabricatorをspecの中で好きなときに呼び出します。factorygirlやmachinistと同じように、3通りの呼び出し方があります。

# インスタンスを保存して返す
Fabricate(:user)
# => #<User _id: 4cb18e0c011c0e5a2c000001, screen_name: "aidan", description: "Vel iste illo beatae maxime earum accusantium. Facilis doloremque nemo dolores perspiciatis. Eum et nisi sunt qui soluta facilis consequatur quasi. Qui sunt omnis beatae sit. Quisquam earum d", site: "http://wintheiserwunsch.com", gender: "female">

# インスタンスを保存せずに返す
Fabricate.build(:user)
# => #<User _id: 4cb18e32011c0e5a2c000002, screen_name: "darlene", description: "Exercitationem voluptatem voluptatibus officia saepe labore earum. Voluptas ut ipsam soluta. Libero possimus eius illo soluta quo blanditiis quod. Similique ea qui reprehenderit nihil ut cons", site: "http://schiller.uk", gender: "female">

# 属性だけを生成してHashで返す
Fabricate.attributes_for(:user)
# => {"screen_name"=>"jaylon", "description"=>"Et vitae nobis enim non. Quia sunt ipsum laboriosam. Maxime ut neque voluptatum velit est aliquam sequi qui. Eius dolorem id ut assumenda.", "site"=>"http://wuckert.uk", "gender"=>"male"}
Fabricatorの継承とか

すでに作ったのとはちょっと違うのがほしいときは、すでにあるfabricatorを継承することができます。:fromパラメータに継承元の名前を入れて、変更したいフィールドの定義を記述します。

# 必ずfemaleなひとがほしい
Fabricator(:female, :from=>:user) do
  gender 'female'
end

もちろん、継承は使わず呼び出すときに直接指定することもできます。

# いまだけfemaleなひとがほしい
Fabricate(:user, :gender=>'female')
# => {"screen_name"=>"daron", "description"=>"Aut dolor reprehenderit consequuntur nihil magni odit eveniet. A est magni nam vero praesentium. Praesentium quae perferendis mollitia. Voluptatem harum ex aperiam tempora ab nihil voluptas. ", "site"=>"http://huel.com", "gender"=>"female"}
クラスの明示的な指定

:class_nameパラメータで明示的にクラス名を指定することもできます。色々なパターンでFabricatorをつくりたいときなどはこれで。クラス名はシンボルやklass、文字列で指定できます。

# :class_name は :user, User, 'User' などで指定可
Fabricator(:invalid_user, :class_name=>:user) do
  screen_name 'hibariya'
  description 'i have no gender'
end
Sequenceで一意にする

MachinistのShamのようなものも用意されています。*1Fabricate.sequenceを使うと、呼び出すたびにインクリメントする数値が得られます。ブロックも渡せるので数値以外の一意な何かもつくることができます。Fakerには大量の単語とかがコード中にドカっと入ってるんですが、普通に重複しますので、データが一意でないといけないときなどはこれを使います。
大きく分けると3つの書き方になるようです。

Fabricate.sequence(:foo_id) # 呼び出すたびに0から始まる連番を返す
Fabricate.sequence(:bar_id, 1000) # 呼び出すたびに1000から始まる連番を返す
Fabricate.sequence(:future){|n| n.days.since } # 呼び出すたびに1日ずつ未来の日付を返す

さっきのUserモデルの例だとこんな感じになります。

# uriもscreen_nameも重複させたくない!
Fabricator(:user) do
  screen_name { Fabricate.sequence(:screen_name){|i| [Faker::Internet.user_name, i.to_s].join } } # <= ここ
  description { Faker::Lorem.paragraph[0..190] }
  site { Fabricate.sequence(:uri){|i| ['http://', i.to_s, Faker::Internet.domain_name].join } } # <= ここ
  gender { %w(male female).sort_by{ rand }.first }
end
on_init, init_with でnewに引数を渡す

newするのに引数が必要なクラスのfabricatorを作るときなどに使えます

class Site
  def initialize(uri) @uri = uri end
end

# on_initとinit_withで、initializeに渡す引数を指定できる
Fabricator(:site) do
  on_init{ init_with(['http://', Faker::Internet.domain_name].join) }
end
after_build, after_create コールバック

保存する前、保存したあとのコールバック。さっきまで勘違いしていたんですが、Fabricate.buildでもafter_createは呼ばれるようです(でもsaveはされない)これはバグだったそうです(https://github.com/paulelliott/fabrication/pull/36
)。

# User#fetch_recent_entries!がsave前のステップで呼び出される
Fabricator(:foo_user, :from=>:user) do
  after_build {|user| user.fetch_recent_entries! }
end

# User#fetch_recent_entries!がsave後のステップで呼び出される
Fabricator(:bar_user, :from=>:user) do
  after_create {|user| user.fetch_recent_entries! }
end
belongs_to, references_oneな関連を!で表現

belongs_to, references_oneな関係にあるものは!を付けると自動的に作ってくれるらしい。べんり!というのは間違いで、!を付けるか否かで関連が作られるタイミングが変えられるようです(!を付けなければ参照されるまで作られない)。

Fabricator(:umbrella) do
  color { %w(red green blue pink violet purple).sort_by{ rand }.last }
end

Fabricator(:girl) do
  name 'unknown'
  umbrella! # !を付けると即座に関連が生成される
end

Machinist <=> Fabrication 比較表

Machinistとの違いを、よく使う項目だけ表にしてみるとこんな感じでしょうか。*2

Machinist Fabrication
Model.blueprint do ~ end Fabricator(:model) do ~ end
Model.blueprint(:named_blueprint) do ~ end Fabricator(:named_fabricator, :from=>:model) do ~ end
Model.make Fabricate(:model)
Model.make_unsaved Fabricate.build(:model)
Model.plan Fabricate.attribues_for(:model)

*1:Shamを使うと呼び出すデータの順番や一意性が保証されるのでした

*2:注) Model, :modelは何かのモデルクラスに読み替えます

よく更新してるブログを上の方に表示する「RSSS」を作ったこと

詳しくは: http://rsss.be。使うと↓のような感じになります。
http://rsss.be/hibariya

これはなに

  • 使っているブログをまとめて登録できるプロフィールのようなもの
  • 最近よく更新しているブログを大きく上の方に表示する
  • 最近どのブログをよく更新していたかの推移を表示する
  • 使っているブログのフィードをまとめて吐く
  • フィードを吐くサービスならブログでなくても可
  • Twitter OAuth(Read権限)でログインする必要あり

自分に関連してるURLをがーっと並べるタイプのプロフィールとかで、あまり使わなくなったサイトを一覧から消したりして管理するのが面倒だなーと思ってたのが作るきっかけです。最近あのミニブログ使ってないなとか、最近リブログしかしてないなーとかそういうのがぱっと見で分かるようなページが欲しかったので、HerokuとRails3とMongoDBの勉強を兼ねて作ってみた*1。最近Herokuがどうのこうのというエントリが多かった原因はこれでした。

しばらくここで開発中 GitHub - hibariya/rsss: 最近使っているサービスを可視化

*1:環境がなくてIE未確認。多分崩れているのでいつかなおす

HerokuでRuby1.9.2が使えるようになってる

今更ですが、使えるようになってましたの記録。

% heroku stack
  aspen-mri-1.8.6
* bamboo-ree-1.8.7
  bamboo-mri-1.9.1 (beta)
  bamboo-mri-1.9.2 (beta)

% heroku stack:migrate bamboo-mri-1.9.2

試しに使ってみたところ、Herokuで使うRubyを1.9.1から1.8.7に戻した - のどをRubyでいっぱいにしてで悩んでいたいくつかの悩ましい事象も起こらず、普通に使えています。ところで(beta)なのはいつまでなんでしょうね。