Hatena::ブログ(Diary)

高尾宏治日記 on はてな このページをアンテナに追加 RSSフィード

2013年05月24日

Railsのカスタムgeneratorの、specを記述する

先日はRailsのカスタムgeneratorの作成方法を説明しました (http://d.hatena.ne.jp/kouji0625/20130523/p1) が、今日はそのspecの記述方法を説明します。generator自体の作成はちょろいのですが、generatorのspecとなると面倒そうですね。実際、rspec-railsはgeneratorのspecをサポートしていません。spec/generators/foo_spec.rbを作成しても、「それで何!?」って感じになるだけです。

じゃあ、rspec-railsが提供しているgeneratorには、specがないのかというとそうではありません。ammeter (https://github.com/alexrothenberg/ammeter) というgemを使って次のような感じでspecを記述しています。

https://github.com/rspec/rspec-rails/blob/master/spec/generators/rspec/helper/helper_generator_spec.rb より

require 'spec_helper'

# Generators are not automatically loaded by Rails
require 'generators/rspec/helper/helper_generator'

describe Rspec::Generators::HelperGenerator do
  # Tell the generator where to put its output (what it thinks of as Rails.root)
  destination File.expand_path("../../../../../tmp", __FILE__)

  before { prepare_destination }

  subject { file('spec/helpers/posts_helper_spec.rb') }
  describe 'generated by default' do
    before do
      run_generator %w(posts)
    end

    describe 'the spec' do
      it { should exist }
      it { should contain(/require 'spec_helper'/) }
      it { should contain(/describe PostsHelper/) }
    end
  end
  describe 'skipped with a flag' do
    before do
      run_generator %w(posts --no-helper_specs)
    end
    it { should_not exist }
  end
end

これまたよくできていますね。

APIの詳しい説明はありませんが、以下のような感じでしょうかね。

  • Gemfile
    • group :test { gem 'ammeter' }
  • spec/spec_helper.rb
    • require 'ammeter/init'
  • spec/generators/xxx/xxx_generator_spec.rb
    • require 'generators/xxx/xxx_generator'
    • describe XxxGenerator do
    • destination <生成したファイルの一時保存先>
    • before { prepare_destination }: 決まり文句
    • run_generator <引数>: generatorを実行

これで、generatorもspecの対象の仲間入りです。

なお、テストフレームワークとしてtest-unitを使っている場合は、Rails本体で使っている Rails::Generators::TestCase が使えます。Rails本体のgeneratorのテストコードがとても参考になります。正直なところ、generatorのテストについては、test-unitに乗り換えたくなりましたwww

--- 参考情報(別名:人力合わせて読みたい♪)

--- PR広告

記事を読んでくださり、ありがとうございます。もしよろしければ、この記事の著者が提供している無料のサービス「かくってる?」をお試しください。

2013年05月23日

いまさら聞けないRailsのカスタムgeneratorの作成方法

はじめに

Railsのアプリケーションを作成していると、同じようなモデル(STIを使っているとよくありますよね)、同じようなコントローラ(RESTfulにすればするほど、コントローラは似てきますよね)が増えてきます。新しいモデルやコントローラを作るときに、コピー&ペーストしたあと、エディタでクラス名を置換し始めたら、カスタムgeneratorを作成するチャンスです。

カスタムgeneratorはめっちゃ簡単に作成できます。しかも、特定のアプリケーションの開発ノウハウ(アクションの作り方やRSpecの記述内容)を動作するプログラムとして記述することができます。

というわけで、カスタムgeneratorの作成方法を説明します...とおもいきや、Rails Guide (http://guides.rubyonrails.org/generators.html) に詳細な説明がありますので、細かい話はおいといて私の興味があるところだけを説明します。

generatorでできること

まずはgeneratorでできることを挙げます。(最後の失言は別として)あなたがほしいものとマッチしたならば、ぜひ、generatorを作成してみてください。

  • テンプレートから適切な名前のファイルを生成して適切なディレクトリに配置できます。
  • Railsのgeneratorで生成されるファイルの一部だけを修正して特定のアプリケーション向けのものにできます。
  • gitのコマンドを簡単に実行できます。
  • アプリケーション自体(rails new AppName -m </path/to/template.rb>)のテンプレートを作成できます。
  • (結局Rubyスクリプトなので、なんでもできるんじゃい!!)

最初にやること

generatorの名前を決めたら、Rails.rootディレクトリで次のコマンドを実行します。あとはどんどん記述するだけです。

$ rails generate generator <名前>

Railsのgeneratorはどこにあるの?

せっかくgeneratorを作成するのですから、よりよいコードを書きたいものですね。そのときに参考になるコードといえば、Railsに含まれているgeneratorです。ここにはノウハウがたっぷりつまっています。

Railsのgeneratorは、/path/to/gems/railties-<version>/lib/rails/generators/rails/ にあります。RVMを使っている場合は ~/.rvm/gems/<ruby@gemset>/gems/railties-<version>/lib/rails/generators/rails/ です。

scaffoldのgeneratorなんかはいいですね。hook_forをうまく使って、DRYになってます。参考にしたいものです。

require 'rails/generators/rails/resource/resource_generator'

module Rails
  module Generators
    class ScaffoldGenerator < ResourceGenerator #metagenerator
      remove_hook_for :resource_controller
      remove_class_option :actions

      hook_for :scaffold_controller, :required => true
      hook_for :stylesheets
    end
  end
end

テンプレートはどこにどうやって記述するの?

Rails Guide (http://guides.rubyonrails.org/generators.html#lib) には、lib以下やlib/tasks以下に特定の文字列に含む特定のRubyスクリプトを配置するメソッドの説明があります。

lib("special.rb", 'p Rails.root')
rakefile("test.rake", 'hello there')

でも、本当に知りたいのは lib/generators/<名前>/template.rb から lib/<アプリケーションの名前空間:name_space>/foo.rb を生成するやり方ですよね。

まずは、「lib/<name_space>/foo.rb」、つまり、ディレクトリを作成してから適切な名前のファイルを配置する方法です。以下のようにlibメソッドの第1引数にディレクトリを追加して、適切なところに「#{file_name}」を記述するだけです。ちょろいですね。

lib("name_space/#{file_name}.rb", 'p Rails.root')

次にerbのテンプレートファイルからRubyスクリプトを生成する方法です。それには Thor の template メソッド (http://rdoc.info/github/wycats/thor/master/Thor/Actions#template-instance_method) を使います。

dest = "lib/name_space/#{file_name}"
log :lib, dest
template("template.rb", dest)

おわりに

まだまだ説明したいことがありますが、ここらあたりで今日は失礼しますw

--- 参考情報

--- PR広告

記事を読んでくださり、ありがとうございます。もしよろしければ、この記事の著者が提供している無料のサービス「かくってる?」をお試しください。

2013年05月22日

OpenID ConnectとSCIM、メモメモ

OpenID Connect は、認証結果と属性情報(クレーム)の受け渡しを行うための共通仕様です。

各クラウドサービスが OpenID Connect に対応する事で、利用者がサービスごとの ID・パスワードを覚えたり、サービスにアクセスする度にログイン情報を入力する必要が無くなります。

(省略)

SCIM は ID 情報の連携(ユーザー・プロビジョニング)の共通仕様で、フォーマット(JSON)とプロトコル(RESTful API)を定義しています。

各クラウドサービスが対応する事で、利用企業は各クラウドサービスに対して、共通の仕様で ID 情報の連携を行う事が可能となります。

クラウドサービスにおけるID管理の理想と現実 | Cybozu Inside Out | サイボウズエンジニアのブログ

これはおもしろい。OAuthもすげーって思ったけど、これはもっとすげー。日本発で、世界で通用する標準フォーマットになるといいですね。

--- 参考情報

--- PR広告

記事を読んでくださり、ありがとうございます。もしよろしければ、この記事の著者が提供している無料のサービス「かくってる?」をお試しください。