Radiant の Extension を書いみる。 チュートリアルが存在するので、それにならって手を動かすことにする。
使用している Radiant のバージョンは、0.7.1 になる。
Table of Contents
Open Table of Contents
カスタム Radius Tags を作成する
Radiant には、コンテンツの編集に使用する Radius Tags と言われるパワフルなタグが存在する。 まずは、そのカスタムタグを作ってみよう!というチュートリアル。
ここで記載している内容は、以下のチュートリアルになる。
Radiant Tags の詳細については、以下のサイトを参照。
generator を使用して Extension の雛形を作成
Extension 用の generator が備わっているので、それを利用してまずは Extension の雛形を作成する。
$ cd radiant_project_home
$ ruby script/generate extension custom_tags
create vendor/extensions/custom_tags/app/controllers
create vendor/extensions/custom_tags/app/helpers
create vendor/extensions/custom_tags/app/models
create vendor/extensions/custom_tags/app/views
create vendor/extensions/custom_tags/db/migrate
create vendor/extensions/custom_tags/lib/tasks
create vendor/extensions/custom_tags/README
create vendor/extensions/custom_tags/custom_tags_extension.rb
create vendor/extensions/custom_tags/lib/tasks/custom_tags_extension_tasks.rake
create vendor/extensions/custom_tags/spec/controllers
create vendor/extensions/custom_tags/spec/models
create vendor/extensions/custom_tags/spec/views
create vendor/extensions/custom_tags/spec/helpers
create vendor/extensions/custom_tags/Rakefile
create vendor/extensions/custom_tags/spec/spec_helper.rb
create vendor/extensions/custom_tags/spec/spec.opts
generator によって雛形となるファイルが作成される。
まずは spec を書く
何はともあれ、まずは spec を書く。
vendor/extensions/custom_tags/spec/lib/cutom_tags_extension.rb
上記ファイルを作成し以下を記載。
require File.dirname(__FILE__) + '/../spec_helper'
describe 'CustomTag' do
scenario :pages # need to replace with `dataset :pages'
describe '<r:box>' do
it 'should render the crrect HTML' do
tag = '<r:box icon="happyface" title="Test Title">Content</r:box>'
expected = %{<div class="box">
<h2>
<img src="/images/icons/happyface.png" />
Test Title
</h2>
<div class="content">
Content
</div>
</div>}
pages(:home).should render(tag).as(expected)
end
end
end
Radiant によって拡張されているクラス(デコレータ)メソッド、マッチャーなどが登場している。
-
scenario :pages
Radiant によって定義されている RSpec scenario(
Senarios Plugin
)。 Page オブジェクトへの参照を提供してくれる。 Page オブジェクトは tag のレンダリングを行ってくれる。後述するが、現在この
Senarios Plugin
は使用されていない。 aiwilliams’s scenarios at master - GitHub にも書いてあるが、既に Deprecate されており、Dataset Plugin
(aiwilliams’s dataset at master - GitHub)を使うようにアナウンスされている。 そのため、ここでの記載は、dataset :pages
とする必要がある。 -
pages(:home).should render(tag).as(expected)
tag を page オブジェクトでレンダリングし、as(expected) でその結果を検証している。
spec を実行する。
もし、test 環境をまだ整えていない場合は、
$ cd radiant_project_home
$ rake db:test:prepare
を実行しておく。改めて spec を実行する。
$ cd vendor/extensions/custom_tags/
$ rake spec
実行時に、以下のエラーに遭遇する。
/opt/local/lib/ruby/gems/1.8/gems/radiant-0.7.1/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:276:in `load_missing_constant': uninitialized constant Spec::Rails::Example::RailsExampleGroup (NameError)
現状、Gem の状態は
- radiant (0.7.1)
- rspec (1.2.6, 1.1.12)
- rspec-rails (1.2.6, 1.1.12)
となっている。
上記に同様の事象にひっかかっている方がいたが、
Radiant 0.7.1 requires RSpec 1.1.11 or 1.1.12, but the version is not “locked” properly in the gemspec. Edge runs properly on RSpec 1.2.x.
ということらしい。
gem では 1.1.12 も入っているのだが、1.2.6 の方を見てしまうので、うまく動作しない。
- v.1.1.12 だけを残して、それ以外のバージョンの rspec、rspec-rails gem は削除
- チュートリアルで
scenario :pages
となっているところをdataset :pages
と変更する- Developer Tips: Scenarios and Datasets
Senarios Plugin
からDataset Plugin
に変更がされているため。
- Developer Tips: Scenarios and Datasets
の 2 つの変更により動作するようになる。
しかし・・・ Radiant v.0.7.1 の RSpec のバージョンは、v.1.2.6 を必要要件としていなかったかな?? まぁ、今のところ Radiant 自体を触る余裕はまだないので、、とりあえず Extension のテストができる v.1.1.12 を使うことにする。
他の Rails アプリでもそうだったが、RSpec はまだまだ進化中のものであるため、バージョンの依存性が強い。 そのため、これまでは vender 配下に rspec と rspec-rails をインストールし使用する方法をとっていたのだが、Radiant の環境ではうまくやることができなかった。 きっと何らかのやり方があるのだろうが、残念ながら手が回っていない。。
と、気を取り直して再度 spec を実行。
$ rake spec
(in /Users/hoge/work/radiant_test/vendor/extensions/custom_tags)
/opt/local/lib/ruby/gems/1.8/gems/radiant-0.7.1/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:493:in `const_missing': uninitialized constant CustomTagsExtension::CustomTags (NameError)
.....
OK。まだ CustomTags なんてものは書いていないので、この NameError のエラーで正しい。
Radius Tag を定義する
タグを記載する CustomTags module を用意する。
vendor/extensions/custom_tags/lib/custom_tags.rb
を作成し、Custom Radius Tag を定義する。
module CustomTags
include Radiant::Taggable
desc %{
タイトル、アイコン、本文を持った HTML box コンテンツを作成する。
*使い方:*
<pre><code><r:box title="title" icon="icon">...</r:box></code></pre>
}
tag "box" do |tag|
""
end
end
単純に空文字を返すだけの box Radius Tag の完成だ。。
Radiant::Taggable
を継承するtag
メソッドで今回作成する Radius Tag を定義するdesc
メソッドでは、rake task のように、その tag の説明を記載する
テストする。
$ rake spec
(in /Users/hoge/work/radiant_test/vendor/extensions/custom_tags)
F
1)
'CustomTag <r:box> should render the correct HTML' FAILED
expected "<r:box icon=\"happyface\" title=\"Test Title\">Content</r:box>" to render as "<div class=\"box\">\n <h2>\n <img src=\"/images/icons/happyface.png\" />\n Test Title\n </h2>\n <div class=\"content\">\n Content\n </div>\n</div>", but got ""
./spec/lib/custom_tags_spec.rb:20:
Finished in 0.708661 seconds
1 example, 1 failure
また失敗するが、これで OK。
期待する結果に対して、but got ""。
それはそうだ。box
Radius Tag の実装は、まだ空文字しかまだ返さないので。。
Radius Tag を使用可能とする
上記までで Radius Tag は定義できたが、Radiant はまだその存在を認知していない。 定義した Radius Tag を Radiant に認知させる。
vendor/extensions/custom_tags/custom_tags_extension.rb
が初期化処理を記載するファイルになるので、ここに記載する。
activate
メソッドの中に以下を記載する。
Page.send :include, CustomTags
Page クラスに先程作成した Radius Tag を定義した CustomTags
module を include させる。
これで Radiant もbox
タグを Radius Tag として認知したことになる。<r:box>
タグが使用可能となっている。
tag メソッドのブロックの記載方法
先の tag
の定義は暫定的に空文字のみを返すようにしていたので、ちゃんとしたものを返すようにする。
tag "box" do |tag|
%{<div class="box">
<h2>
<img src="/images/icons/#{tag.attr['icon']}.png" />
#{tag.attr['title']}
</h2>
<div class="content">
#{tag.expand}
</div>
</div>}
end
yield されているブロック引数の tag オブジェクトは、レンダリングされるタグになる。
また、今作成している <r:box>
を使用するコンテンツの作成者によって定義されるその全てのコンテンツと属性を保持しているものになる。
2 つの役に立つメソッドをもっている。
-
tag.attr['attribute_name']
タグに与えられる属性の値に対して hash によるアクセスを提供する
-
tag.expand
開始タグと終了タグの間のコンテンツを描画する。
ここでのケースでは文字列ではあるが、Radiant は存在する他の Radius Tag のレンダリングも行える。
きちんと tag
メソッドを実装したので、テストが通るようになっているはずだ。spec を再度実行する。
$ rake spec
(in /Users/taka/work/radiant_test/vendor/extensions/custom_tags)
.
Finished in 0.703412 seconds
1 example, 0 failures
OK。これで一応の完成となる。
追加したカスタム Radius Tags を確認する
サーバを再起動して本当に使えるようになっているか確認してみる。
Page を追加し、Edit Page でまずはAvailable Tagsを確認してみる。
desc
に書いた内容がちゃんと追加されている。
使用可能になった <r:box>
タグを実際に書いてみる。
保存して、画面で表示を確認する。
スタイルシートをちゃんと定義していないので、ハズカシイ表示にはなっているが、ちゃんと box Radius タグが利用できた。
<div class="box">
<h2>
<img src="/images/icons/movie_thumbnail.png" />
This is the custom tag!
</h2>
<div class="content">This is the custom tag body.</div>
</div>
HTML も問題ない。
オプショナル属性
アイコンやタイトルをいつも指定しないかもしれない。 アイコンはいつも使用するデフォルトのものがあり、タイトルはブランクとすることができるようにしたい。 この要件も簡単に追加できる。
お約束でまずは spec から。
code example を追加する。
it 'should have a default icon and allow a blank title' do
tag = '<r:box>Content</r:box>'
expected = %{<div class="box">
<h2>
<img src="/images/icons/sadface.png" />
</h2>
<div class="content">
Content
</div>
</div>}
pages(:home).should render(tag).as(expected)
end
テストする。
$ rake spec
(in /Users/taka/work/radiant_test/vendor/extensions/custom_tags)
F.
1)
'CustomTag <r:box> should have a default icon and allow a blank title' FAILED
expected "<r:box>Content</r:box>" to render as "<div class=\"box\">\n <h2>\n <img src=\"/images/icons/sadface.png\" />\n \n </h2>\n <div class=\"content\">\n Content\n </div>\n</div>", but got "<div class=\"box\">\n <h2>\n <img src=\"/images/icons/.png\" />\n \n </h2>\n <div class=\"content\">\n Content\n </div>\n</div>"
./spec/lib/custom_tags_spec.rb:36:
Finished in 0.714863 seconds
2 examples, 1 failure
ちゃんと失敗する。
"<div class=\"box\">\n <h2>\n <img src=\"/images/icons/sadface.png\" />\n \n </h2>\n <div class=\"content\">\n Content\n </div>\n</div>"
とレンダリングされるのを期待したのだが、
"<div class=\"box\">\n <h2>\n <img src=\"/images/icons/.png\" />\n \n </h2>\n <div class=\"content\">\n Content\n </div>\n</div>"
がレンダリングされているよ!という内容の失敗だ。確かにそれは RSpec のおっしゃる通りだ。
vendor/extensions/custom_tags/lib/custom_tags.rb
に変更を入れる。
<img src="/images/icons/#{tag.attr['icon']}.png" />
となっている箇所を
<img src="/images/icons/#{tag.attr['icon'] || 'sadface'}.png" />
とする。||
オペレータで icon の属性が指定されなかった場合に、‘sadface’ を返すように変更している。
再度実行。
$ rake spec
(in /Users/taka/work/radiant_test/vendor/extensions/custom_tags)
..
Finished in 0.738969 seconds
2 examples, 0 failures
OK。
参考サイト
-
Developer Tips: Scenarios and Datasets
Scenarios Plugin
からDataset Plugin
への変更をアナウンスしている Radiant Blog の記事。 -
Wiseheart Design - Meet Dataset: The Fixture-Killing, Data-Loading Framework
John W. Long 氏による Dataset の説明。
-
aiwilliams’s dataset at master - GitHub
Dataset Plugin
の GitHub