Tenjinテンプレートエンジンで快適Web制作4

IWDD41で発表したTenjinテンプレートエンジンで快適Web制作3の続きエントリーです。

画像ファイルが沢山あるページの場合、srcやaltをそのままhtmlの中に書いても良いですが、yamlファイルで管理したりすると便利かも。

apple:
  src:        apple.jpg
  alt:        りんごの写真
  width:      300
grape:
  src:        grape.jpg
  alt:        ぶどうの写真
  width:      400
lemon:
  src:        lemon.jpg
  alt:        レモンの写真
  width:      500

data.yaml

それぞれの画像ファイルに対するメタデータを、このようなYAML形式で作っておきます。

そして、以下のようなテンプレートを作ると、YAMLファイルからデータを読み込んで、それぞれの項目名を元に、imgタグを返すことができます。

<?rb
@title='YAMLファイルからページを作る'

# YAMLファイルを読み込んで、指定されたハッシュのimgタグを返す
require 'yaml'
def yaml2img(key)
  hash   = YAML.load(File.read('data.yaml'))
  ysrc   = hash[key]['src']
  yalt   = hash[key]['alt']
  ywidth = hash[key]['width']
  @_buf << '<img src="/images/'+ysrc+'" alt="'+yalt+'" width="'+ywidth+'">'
end
?>

<?rb import 'header.html' ?>
  <div>
    <?rb yaml2img('apple') ?>
    <?rb yaml2img('grape') ?>
    <?rb yaml2img('lemon') ?>
  </div>
<?rb import 'footer.html' ?>

yaml.html

imgタグを返すyaml2imgメソッドをテンプレート内で定義して、テンプレート内で<?rb yaml2img() ?>で呼ぶと、その場所にimgタグが出力されます。

http://localhost/yaml.html にアクセスすると、

<html>
  <head>
    <title>YAMLファイルからページを作る</title>
  </head>
  <body>
  <div>
    <img src="/images/apple.jpg" alt="りんごの写真" width="300">
    <img src="/images/grape.jpg" alt="ぶどうの写真" width="400">
    <img src="/images/lemon.jpg" alt="レモンの写真" width="500">
  </div>
  <div>ここがフッター</div>
  </body>
</html>

という結果が得られると思います。


Tenjinテンプレートエンジンで快適Web制作3

IWDD41で発表したTenjinテンプレートエンジンで快適Web制作2の続きエントリーです。

Webサイトの原稿をもらうときに、ワードだったり、エクセルだったりすることがあるかと思いますが(><)、今回はエクセルファイルから直接ページを作ってみます。

まず、エクセルでこんなシートを作ります。シート名は「page1」、ファイル名は「data.xls」にしておきます。これがページの原稿になります。

エクセルで原稿を作る data.xls

RubyのSpreadSheetライブラリを使って、エクセルのデータを直接読み込んでテンプレートの中に展開します。

<?rb
@title='エクセルファイルからページを作る'

require 'rubygems'
require 'spreadsheet'
book  = Spreadsheet.open('data.xls', 'rb')          # エクセルファイルを指定する
sheet = book.worksheet('page1')                     # シート名を指定する

xls_title  = sheet[2,1]                             # ページタイトル(B3)
xls_body   = sheet[3,1].gsub(/\n/, '<br>')          # 本文。改行をbrタグに置換(B4)
xls_alt    = sheet[4,1]                             # 写真の説明(B5)
xls_src    = '/images/' + sheet[5,1]                # 写真のファイル名(B6)
?>

<?rb import 'header.html' ?>
  <div>
    <h1>${xls_title}</h1>
    <p>#{xls_body}</p>
    <img src="${xls_src}" alt="${xls_alt}">
  </div>
<?rb import 'footer.html' ?>

excel.html

こんな感じでexcel.htmlテンプレートを作ります。xls_body変数にはbrタグが入ってくるので、${xls_body}ではなくて#{xls_body}(エスケープ無し)を使っておきます。

http://localhost/excel.html にアクセスすると

<html>
  <head>
    <title>エクセルファイルからページを作る</title>
  </head>
  <body>
  <div>
    <h1>ここがページのH1になる場所</h1>
    <p>ここにページの内容を書く。<br><br>複数行の内容を入れ込んでもOK...</p>
    <img src="/images/apple.jpg" alt="赤く実ったリンゴ">
  </div>
  <div>ここがフッター</div>
  </body>
</html>

という出力が得られると思います。


Tenjinテンプレートエンジンで快適Web制作2

IWDD41で発表したTenjinテンプレートエンジンで快適Web制作の続きエントリーです。

TenjinをCGIから使う基本的な環境が出来たら、「header.html/body.html/footer.html」のパーツごとに分けてみます。

分割されたテンプレートファイルを読み込むには

<?rb import 'filename' ?>

を使います。

<html>
  <head>
    <title>${@title}</title>
  </head>
  <body>

header.html

<?rb @title='タイトルを設定する' ?>
<?rb import 'header.html' ?>
  <div>メイン</div>
<?rb import 'footer.html' ?>

main.html

  <div>ここがフッター</div>
  </body>
</html>

footer.html

このように3つのファイルを用意して http://localhost/main.html にアクセスすると、header.htmlとfooter.htmlがインポートされて評価されます。 また、main.htmlで@title変数に設定された内容が、header.htmlの${@title}で評価されていると思います。

結果として

<html>
  <head>
    <title>タイトルを設定する</title>
  </head>
  <body>
  <div>メイン</div>
  <div>ここがフッター</div>
  </body>
</html>

というHTMLが返ってくると思います。


Tenjinテンプレートエンジンで快適Web制作

IWDD41で「Tenjinテンプレートエンジンで快適Web制作」として発表してきました。

VGAアダプタを忘れてプロジェクタに映せなかったので(><)、blogにコードを貼ってみます。

素のHTMLを何ページも手書きしたくない、CMSを入れる程でもない、DreamWeaverテンプレートでは物足りない。 デザイナーでもテンプレートエンジンを使いこなしたい。Rubyを使いたい。そんな人にお勧めです。

今年はもっとRubyを勉強しようと思っているので、Ruby用のrbTenjinを使ってデモを書きました。

IWDDで発表した内容は

  • 基本的なTenjinの使い方
  • ヘッダ、本文、フッタの3ファイルに分ける方法
  • エクセルファイルからデータを読み込んでHTMLページ生成
  • YAMLファイルからデータを読み込んでHTMLページ生成
  • CGIのパラメータを受け取ってページの内容を変える

基本的なTenjinの使い方

テンプレートファイルの中で

  • ${...}と書けばrubyの式を評価した結果が入る(HTMLエスケープ有り)
  • #{...}と書けばrubyの式を評価した結果が入る(HTMLエスケープ無し)
  • <?rb ... ?>でrubyの文を埋め込める

Apacheで使うための設定

今回はCGIとして動かして、そのCGIの中でTenjinを使っていきます。

  1. Tenjinを動かすためのパーサとしてのCGI
  2. apacheで動かすための.htaccessファイル
  3. テンプレートファイル

まず、1.Tenjinを動かすためのCGIを http://dekstop.de/weblog/2006/01/rhtml_on_osx_with_apache_and_erb/ を参考にして書いてみます。これを「tenjin.cgi」とかの名前で保存しておきます。CGIがテンプレートファイルを受け取って、Tenjinに渡してレンダリングした結果を表示しています。

#!/usr/bin/ruby
$KCODE = 'utf-8'
require 'time'
# require 'rubygems'                          # 必要ならば
require 'tenjin'

time = Time.now.httpdate

HEADERS = <<EOF
Date: #{ time }
Server: #{ ENV['SERVER_SOFTWARE'] }
Last-Modified: #{ time }
Content-Type: text/html

EOF

begin

  path = nil
  if (ENV['PATH_TRANSLATED'])
    path = ENV['PATH_TRANSLATED']
  else
    file_path = ENV['REDIRECT_URL'].include?(File.basename(__FILE__)) ? ENV['SCRIPT_URL'] : ENV['REDIRECT_URL']
    path = File.expand_path(ENV['DOCUMENT_ROOT'] + '/' + file_path)
    raise "Attempt to access invalid path: #{path}" unless path.index(ENV['DOCUMENT_ROOT']) == 0
  end

  tenjin = Tenjin::Engine.new(:cache => false)  # キャッシュ機能は今は外しておく
  output = tenjin.render(path)                  # テンプレートをレンダリングする

  print HEADERS + output                        # レンダリング結果を出力

rescue Exception
  # エラーが発生した場合
  print "Content-Type: text/html\n\n"

  # error message
  print "<h1>Script Error</h1>"
  print "<pre>#{ $! }</pre>"

  # debug info
  print "<h2>Backtrace</h2>"
  print "<pre>#{$!.backtrace.join("\n")}</pre>"

  print "<h2>Environment</h2>"
  print "<pre>#{ENV.keys.map { |key| key + ' = ' + ENV[key] + "\n"} }</pre>"

  print "<hr>"
  print "<i>#{__FILE__} -- #{time}</i>"

end

tenjin.cgi

apacheで動かすための.htaccessファイル

Apacheのmod_actionを使って、htmlファイルへのアクセスを、tenjin.cgiに渡すようにします。テンプレートファイルの拡張子は.rhtmlとかでも良いのですが、.htmlにしておくと、URLの見た目的にも、エディタでの扱いやすさ的にも良いと思います。

Options +ExecCGI

AddHandler tenjinpage .html
Action tenjinpage /tenjin.cgi

.htaccess

ここまで出来たら準備完了です。テンプレートファイルを作って、動作確認してみます。

<?rb aaa = 'こんにちはー' ?>
<html>
  <head>
    <title>${aaa}</title>
  </head>
  <body>
    ${aaa}
  </body>
</html>

test.html

こんなHTMLファイルを作って、 http://localhost/test.html にアクセスしてみると、変数aaaの内容が${aaa}で評価されて、ブラウザには

<html>
  <head>
    <title>こんにちはー</title>
  </head>
  <body>
    こんにちはー
  </body>
</html>

という内容が返ってくると思います。

毎回CGIを呼び出しているので、スピードが気になる場合は、レンダリング結果を静的ページとして保存してしまうのも良いと思います。


仙台Ruby会議01

仙台Ruby会議に参加してきました!私も一応実行委員としてUstreamでの生中継の担当をしていました。

当日の様子はUstreamで生中継され、録画映像は公開されています。ピークで最大同時接続数40人くらいがUstを見ていただいていたようです。

また、Ustとは別にバックアップ用に撮影しておいたHDVの編集が終わりましたので、こちらもUPしておきます。.mp4形式のファイルでサイズが大きいです。ローカルにダウンロードしてお楽しみ下さい。


GAINERと加速度センサとFunnelでKeynoteのスライドをめくる

1000speakers:7@仙台#1ではコミュニティー枠で東北のコミュニティーの紹介を話したんですが、それだけでは技術的な話がないので、GAINER加速度センサFunnelとRubyで、Keynote.appのスライドをめくるというのをデモしました。

GAINERのボタンを押すときに、加速度センサが載っているブレッドボードを

  • 向こうに傾けると:スライドがスタート
  • 手前に傾けると :スライドがストップ
  • 右に傾けると  :スライドが次へ
  • 左に傾けると  :スライドが戻る

という仕組みです。

Gainerと加速度センサーをブレッドボードを使って組みました。加速度センサーの説明書や「+GAINER」のP.110を参考にしました。

Gainer

もっと長さのちょうど良いジャンプワイヤーを使えば、見栄の良い回路を組むこともできます。もちろんブレッドボードが無ければ、直接半田付けをすれば良いのですが、次回の使い回しが大変になりますね。

Gainer

加速度センサーのアップ写真。このセンサーがX軸Y軸Z軸の加速度を出力してくれます。かわいいですね♪

そしてFunnel Serverを立ち上げて、Gainerを認識していることを確認します。

Keynoteでプレゼンしたいスライドを開いておいて、以下のプログラムをターミナル等から実行すると動作すると思います。

#!/usr/bin/ruby

$LOAD_PATH.push('lib')
require 'funnel'
include Funnel

gio = Gainer.new
gio.button.on RISING_EDGE do
  ain0 = gio.ain(0).value
  ain1 = gio.ain(1).value  
  if ain1 > 0.7
    slide('show next')
  elsif ain1 < 0.3
    slide('show previous')
  elsif ain0 < 0.3
    slide('start')
  elsif ain0 > 0.7
    slide('stop slideshow')
  end
end

def slide(appscript)
    <<-`EOC`
    osascript -e '
    tell application "Keynote"
        #{appscript}
    end tell'
    EOC
end
sleep(60*15)

まず、FunnelのRuby用ライブラリを読み込みます。今回はプログラムファイルと同階層にlibフォルダを作って置きました。

次にGAINERの基板に付いているボタンが押された事(RISING_EDGE)をトリガーにして、アナログ入力の値を読み込みます。Funnelを使うことによって、すごく簡単に書くことができます。

今回使ったのは3軸加速度センサなのでX軸Y軸Z軸の3つの出力があります。アナログ入力0、アナログ入力1、アナログ入力2にそれぞれのピンが接続されているのですが、今回はX軸とY軸だけを見ればよいので、X軸が接続されているain(0)と、Y軸が接続されているain(1)の値を得ています。

そして、それぞれの値によって、スライドをnext/prev/start/stopしています。

Keynote.appを動かすにはAppleScriptを作ってMacのosascriptコマンドを実行しています。

次のスライドに進む時は

tell application "Keynote"
    show next
end tell'

というAppleEventをosascriptコマンドでKeynoteに送ってあげると、スライドが1枚めくれます。

osascriptは、シェル等からAppleScriptを実行するためのコマンドです。詳しくは
$man osascript にて。