Laraval Bladeの機能で擬似Layout

知ってる人には当たり前の話。After Rais の世界の View の Layout という考え方はどれも同じようなものかと思っていたのだが、意外とそうでもなかったというメモ。

LaravelはController側でLayoutの制御を支援してない

Layout を Controller の property で指定する機能はあるが、Rails の view のように render の際に layout を指定する機能はないため、Action 側でコントロールするのはやや難しい。

abstract class Controller
{
  ..
  protected $layout;
  ..

  protected function setupLayout() {}
  ..

  public function callAction($method, $parameters)
  {
    $this->setupLayout();

    $response = call_user_func_array(array($this, $method), $parameters);
    ..
  }
}

こんな感じ。Action に渡ってくる際にはもう layout の解決は済んでしまっている。

むしろこの辺は Blade 自体が柔軟というか強力すぎる機能を提供している。

Bladeはdirectiveで@extendsする

@extends, @section, @yield を利用して特定の view の特定の領域にコンテンツを inject することを global に許可しているので、layout というか自身の container になる view を view の中から指定することができる。

例えば以下のような感じになる。

in layout.blade.php

@yield('content') // <-- ここに @extends した側の @section のコンテンツが入る

in contents.blade.php

@extends('path.to.layout') // <-- ここで container になる blade の名前を指定

@section('content')
  ..  <-- この中身が @yield に置換される
@stop

ポイントは以下の2つ。

  1. @extends で送る先の View を指定する
  2. @yield と @section のセットでコンテンツを送り込む

1 がめちゃくちゃ強力。

Controller や Renderer 側で View の階層、機能を管理するという考え方じゃなくて blade 自体が Blade 全体の管理しているものをすべて知ることができる という考え方。

まー確かに実に PHP っぽい。ちょっと怖いけど。

これを利用して「名前空間を整理すると」layout というか container となる view をまとめておくことができそうだ。

app/views/containers/

みたいな。

参考

Mechanizeで無茶をする

mechanize-0.9.3 Documentation

自分にとって Mechanize による自動化はたいがい無理を通す行為である。分かりやすく言えば API なんかない、あるいはあっても足りないみたいな状態で、それでもどうにか自動化したいから Mechanize を使う。

Mechanize が持っている標準的な機能だけで済んでいる場合はまだかなりマシで、実際のところ無理というか「無茶」なレベルに突入してしまうことが、なぜかそれなりにあったりする。具体的には HTML が壊れているのでパースに失敗して、あるはずの要素がなくなっていたりする場合などである。

今回はそんな無茶の一部をご紹介。

パーサを Hpricot に変える

ずばり基本でしょう。

Mechanize は 0.9 以降デフォルトパーサを Hpricot から Nokogiri に切り替えているが、そもそも Nokogiri は HTML 用にできていない。XML 用の道具に、 Hpricot によく似たインターフェイスを付けたものである。HTML は自由度の高い書式で、XML 用のノコギリでは歯こぼれを起こすことがよくある。

そこでこの設定(0.9.0 〜 0.9.2)。

require 'hpricot'
WWW::Mechanize.html_parser = Hpricot

cf.

0.9.3 (以降?)はサブクラスの利用に注意

html_parser がインスタンスのアクセッサとして定義されたのでインスタンスごとに parser をセットできるようになったのはいいんだけど、Mechanizeクラスオブジェクトのインスタンス変数を self.class で参照して自身に書き戻しているので、

サブクラスに反映されない

状態になっている。(少なくとも Ruby 1.8.7 では parser が nil になって動かなかった。)定義部分は以下のような感じ。

class Mechanize
  ...
  @html_parser = Nokogiri::HTML
  class << self; attr_accessor :html_parser, :log end
  def initialize
    ...
    @html_parser = self.class.html_parser
  end
  ...
end

動かすとこんな感じ。

$ cat sub_mechanize.rb
class SubMechanize < WWW::Mechanize
end
$ irb
irb(main):001:0> require 'mechanize'
=> true
irb(main):002:0> a = WWW::Mechanize.new
=> (snip)irb(main):003:0> a.html_parser
=> Nokogiri::HTML
irb(main):004:0> require './sub_mechanize'
=> true
irb(main):005:0> b = SubMechanize.new
=> (snip)
irb(main):006:0> b.html_parser
=> nil

恐らく Mechanize のインスタンスについては html_parser のセット方法に互換性をとりつつインスタンスごとに設定できるようにしたかったためにこうなったんだろうけど、いつもデバッグしやすいように独自のサブクラスを噛ましていた1ので、まったく parse できない現象にハマってしまった。仕方ないのでサブクラスの中で独自に定義することにした。

class SubMechanize < WWW::Mechanize
  def initialize
    super
    @html_parser = Hpricot
  end
end

こんなんでいいのかな。

cf. RubyのMechanizeの0.9.3が6月8日に出てたっぽい - きたももんががきたん。

Field を作る

これはまだ初級。

Form#add_field!( name, value )

無駄に JavaScript に分離したフォームの場合、必要な field が HTML 上に存在しないことがよくある。その値を無理矢理 form 上に反映するために使う。

FileUpload を作る

これに気づいたときにはけっこう嬉しかった。add_field! では Field は作れても FileUpload は作れないから。

どうやるかというと、Form オブジェクトに対して instance_eval を使う。

Form#enctype = 'multipart/form-data'
Form#instance_eval {
  @file_uploads << WWW::Mechanize::Form::FileUpload.new( name[, filename] )
}

もともと file_upload が存在しない form として解釈した場合は enctype が違うことがある(というか指定してないかも)ので手で変更してあげると吉。

Form を作る

instance_eval() を思い出してしまえば簡単。もう form そのものを解釈できませんでしたという凶悪な HTML 向け。

Page#instance_eval {
  @forms << WWW::Mechanize::Form.new( node[, mech, page] )
}

node には Hpricot::Elem オブジェクトを入れてあげれば ok.

このとき、Hpricot::Elem になれば元の文字列はなんでもよいので、

Form.new( Hpricot( String#scan( /<form.*?>.*?<\/form>/m ).to_s ).at( 'form' ) )

みたいなこともできる。HTML が壊れているので正規表現でいったん form だけ引っこ抜いて、それを Hpricot オブジェクトに戻してやって Form を作る。途中の整形も思いのまま。

Page を作る

Page を作るのはちょっと手が掛かる。以前作ったものを gist に置いてあるので参考になれば嬉しい。

  1. http://gist.github.com/76140 

git では空ディレクトリは add できない

少なくとも git 1.6.0.2 時点では。

いや、知ってたんだ。知ってたんだよ。知っててもやっぱハマるね。ハマらないと覚えないわコレは。

というかね。

空ディレクトリは add できないって制限なんだから、そういうメッセージをちゃんと出せよ!

できないことが悪いとは言わないけど、インターフェイスとしてなってないと思うぞ。

風邪引いたやつはマスクしろ

義務としてマスクしろ。それか出てくんな。

ちぃっくしょー

ばーか

※ やばいと思って予防目的でマスク買ってきたが手遅れだった。

Firefox でスタイルシートじゃない指定も外れる

メニューから [ 表示 ] → [ スタイルシート ] → [ スタイルシートを使用しない ] を選ぶと、CSS で書いていないデコレーション1も外れるのね。知らなかった。こりゃ便利だ。

※ Firefox 1.0.7 @ MacOSX で確認しているので、他の環境のことは知らない。

  1. body の bgcolor 属性とかタグで書いてある font とか 

ブックマークを捨てた道のり 〜 あるいは情報整理の話 〜

ブックマークはもう長いことあまりまともに使っていない。ブックマークを使わなくなった理由は以下の通り。(あ、ちなみに Google があるからという理由ではありません。念のため。)

  • 検索できない
  • ブックマークしたマシンでしか使えない

検索については Firefox では Phoenix という名前の時代から可能だし、ずいぶん改善されてきている。ほとんど触ったことのない IE コンポーネントタブブラウザでもたぶんできるだろう。できなきゃ何百何千なんてブックマークは管理できっこない。

しかし検索にはある程度冗長な情報が大事だと自分は思っているので、実は既存のブックマークの検索には不満が多い。ブックマークするというアクションはとても楽だが、その簡単なアクションで登録できるのはそのページのタイトルだけ、というのが普通だ。Firefox のブックマークには キーワードや説明というプロパティがあるが、meta タグの keyword や description を自動で拾ってくれるわけではない。ページタイトルという情報だけで検索できることなんてたかが知れている。それとも手で「説明」や「キーワード」を入力する? ばかばかしいよね。IE コンポーネントタブブラウザではもっといろんな情報から検索できるのだろうか?

ブックマークしたマシンでしか使えないかどうかはちょっと微妙なところで、LAN 内であれば素の IE でも共有することは可能だし、最近のアプリは比較的エクスポート/インポートの機能が充実している。んだけど。エクスポート/インポートが面倒くさい。ネットワーク的に離れたマシンにデータを移すには何らかのストレージを用意しなくちゃいけない。メンドイ。

そこでどうしていたかというと以前は

  • 手書きでリンク集を作って Web に上げていた

はるかに面倒くさいじゃないか。でもこれには理由があって、その頃はいろんな人によく便利なサイトがないか聞かれたりしていたので、「自分のマシンが目の前になくても使える自分用のブックマーク」がほしかったし、「共有ブックマークなどのサービスも Google もまだなかった」。そこで原始的に手で作っていたのだ。この段階ではまだブックマークは捨てきれていなかった。吐き出しに恐ろしく労力が掛かるから。

しばらくして

  • Wiki に吐き出すようにした

これは快適。じゃんじゃか吐き出して手元のブックマークはほぼなくなった。しかし問題もあった。

  • 整理がメンドイ

Wiki は油断するととても使いにくいサイトができあがる。見ための意味が分からなくなる。検索すればいいんだけど、ぱっと見の印象も大事だ。見にくいサイトは例え有用な情報があっても使わない。これは自分の行動を振り返って断言できる。だから見やすくしたい。でも整理はメンドイ。でも面白いとかすごいと思ったサイトはすぐにどこかにその情報を保存したい。そこで今は

  • 日記に書く

ことにした。別に超整理法はまったく興味ないんだけど、時系列メモはとにかく吐き出しが楽。ChangeLog Memo も同じだけど、吐き出すときにどこに整理しようとか考える必要がない。1(最低限の目安としてカテゴリはつけるようにしてるけど。)ある程度の情報量がまとまってきたら時間を取って、検索しながら情報を吸い出して Wiki や静的な HTML などに起こして整理するという作業をする。

つまり整理を先延ばしにしてるわけだ。これは整理を先延ばしにしたまま検索で使い勝手を確保するというデジタルデータの恩恵に預かりまくりな戦法である。これをアナログというか物理的なモノで再現すると自分だけが配置を理解しているゴミの山を身の周りに築き上げるという恰好になるので注意が必要だ。やるならデジタルデータだけでやる。目に見えてしまうとただのだらしない人。

このサイクルは結城さんが日記でやっていることや ishinao さんが 日記ツールで下書き、blogツールで清書 で述べていることとまったく同じだし、実は全然ブックマークに限らない話だったりする。2

ただし「書く」という行為はそれなりにコストが高い。忙しいときはそのまま URI を貼るだけになりがちだがあまりそれはやりたくない。3そこでコストと「この情報をどこかに残したい」という欲求を天秤に掛ける。コストが勝てばその情報は自分にとってその程度なのだと思ってほぼ間違いない。

それでも「時間が足りないんだ、そんなまどろっこしいことできるか」という場合は、ほんとに急場しのぎのためと割り切ってメモツールを援用するとよいと思う。自分も Firefox 用 Extension の QuickNote を一応入れてある。しかしほとんど使わないし極力使わないようにしている。これは以前デスクトップ用の付箋をまったく整理できずに破綻させたことがあるからであって、他の人はその心配はないかもしれない。また高機能な付箋ソフトはたぶん時間情報も扱えて検索もできるんだろうけど、自分の場合はそもそもブックマークを捨てる出発点に「特定のクライアントマシンに依存したくない4」という要求があるので付箋などのメモツールの方向には力は入れていない。

参考までに今自分の向かっているマシンのブックマークには Wiki が 3個、テスト環境の URI が 3個、Namazu につっこんだ各種言語のマニュアル、ローカルに立てた Another HTML-lint、ローカルの ViewCVS、コードから自動生成したドキュメントくらい。簡単に言うと「ホームページ」の数を増やしてくれる程度のものでしかない。フォルダは Sage 用に掘ったものしかないのでえーとあれはどこだっけと探すこともない。とても快適だ。

身の回りの情報をもっとうまく扱いたいと思ったら、まずブックマークを捨てることを試みるといいかもしれない。

  1. ならテキストファイルとメモ帳でいいじゃんと思うかもしれないが、それはとてもとても面倒くさい。自分が Wiki に頼るようになったのはひとえに面倒くさいからなんだけど、この話は気が向いたらまた別の機会に。 

  2. ちなみに二人とも情報整理用に独自に Web アプリを開発してしまうところも似ている。 

  3. 理由は前述の通り。URI とページタイトルしかないのであればその検索性はブックマークと何も変わらない。 

  4. OS も縛られたくない 

RSS Reader のシェアに驚く

ちょっと旧聞なのだけれど。

えむもじら RSS リーダのシェア

で Live Bookmark と Sage の差ってこんなにあるのか!ってことと NewsFire(旧MacNewsWire)がこんなにシェアが高いなんて!ということに驚いている。

これのどこが驚きかというと、まず Mac アプリのシェアが高いことに対する単純な驚き。Mac のシェアが伸びたって話は聞かないので単純に Mac な人が新しもん好きということなのだろうか。1

Live Bookmark は「ブックマークなんて使いにくいものをよく使うなぁ」というのが正直な感想。まぁ自分の使っている Sage もブックマークなんだけど、これはアプリが統一されていてなおかつ標準のブックマークとは異なるナイスな操作性が気に入っているのでブックマークにデータを入れるということについては我慢している。

ブックマークについてはなんか書いているうちに想像以上に長くなったので別セクションで。

  1. Mac なアプリに選択肢がないから結果的にシェアが高くなるということはありそうだけど。 

雪ですね

雪なんですよ。

なんか、あんまりニュースになっていないような気がしないでもないのは自分がちゃんとニュースチェックしてないからですか。峠は越えたみたいな気がしますが。でも油断ならんのよね。

気になるロゴ

これをデザインした T シャツほしいなぁ。勝手に作ったらまずいのかなぁ。売らずに着てる分にはいいんだよね?

About

例によって個人のなんちゃらです