S2CGI Webフレームワークは、Apache上でCGIスクリプトとし実行されるRubyアプリケーションを作成するための小さなフレームワークです。
次のURLからsvn exportして下さい。
次のディレクトリが作成されます。
- https://www.seasar.org/svn/sandbox/s2container.ruby/trunk/s2cgi/
project/ config/ # 設定ファイルディレクトリ lib/ # サービスやロジッククラスの保存ディレクトリ public/ # WEB公開ディレクトリ test/ # UnitTestディレクトリ tpl/ # erbテンプレートファイル保存ディレクトリ var/ # データやログ保存ディレクトリ vendor/ # 依存ライブラリ保存ディレクトリ
インストールドキュメントにしたがって S2Container.Ruby をインストールして下さい。
Rackを使用する場合は、Rackをインストールして下さい。
拡張子cgiをcgiスクリプトとして登録します。
public ディレクトリを公開する設定とします。AddHandler cgi-script .cgi Alias /s2cgi/ "/path/to/project/public/" <Directory "/path/to/project/public"> Options ExecCGI AllowOverride None Order allow,deny Allow from localhost </Directory>
Base URLを適切に設定します。Base URLの設定は config ディレクトリの environment.rb で行います。% cat config/environment.rb | grep BASE_URL BASE_URL = '/s2cgi' %publicディレクトリのcgiスクリプトの所有者と実行権を確認してください。cgiスクリプトのシェバングを適切に設定します。% ls -l public/cgi/quick1.cgi -rwxr--r-- 1 apache apache 1250 Feb 1 00:00 public/cgi/quick1.cgi % head -1 public/cgi/quick1.cgi #!/usr/bin/env ruby %varディレクトリの所有者と実行権を確認してください。% ls -ld var drwxr-xr-x 6 apache apache 4096 Feb 1 00:00 var %
CGI フレームワークの起動は、Seasar::CGI.run メソッドを呼びます。 public/cgiディレクトリに次のような quick1.cgiを作成します。
% cat public/cgi/quick1.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/cgi.rb' Seasar::CGI.run %次に、tpl/cgi ディレクトリに quick1.cgiのerbテンプレートファイルを「quick1.html」として作成します。
% cat tpl/cgi/quick1.html Hello World %ブラウザで、http://localhost/s2cgi/cgi/quick1.cgi にアクセスすると、「Hello World」 と表示されます。
Seasar::CGI.run メソッドには、引数でSeasar::CGI::Pageクラスのインスタンスを渡すことができます。 public/cgiディレクトリに次のような quick2.cgi を作成します。
% cat public/cgi/quick2.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/cgi.rb' class Page < Seasar::CGI::Page; end Seasar::CGI.run(Page.new) %次に、tpl/cgi ディレクトリに quick2.cgiのerbテンプレートファイルを「quick2.html」として作成します。
% cat tpl/cgi/quick2.html Hello World 2 %ブラウザで、http://localhost/s2cgi/cgi/quick2.cgi にアクセスすると、「Hello World 2」 と表示されます。
Seasar::CGI.run メソッドは、引数が nil の場合、S2ContainerからSeasar::CGI::Pageクラスのコンポーネントを取得します。 コンテナにSeasar::CGI::Pageクラスのコンポーネントが存在しない場合は、Seasar::CGI::Pageクラスのインスタンスを自動生成して使用します。 (上述の「フレームワークの起動」の例になります。)
Seasar::CGI::Pageクラスは、デフォルト処理として、tpl ディレクトリ以下のerbテンプレートファイルからコンテンツを生成します。 erbテンプレートファイルへのパスは、SCRIPT_NAMEのBASE_URL以下のパスが使用されます。「/s2cgi/cgi/quick2.cgi」の場合は、 「tpl/cgi/quick2.html」がerbテンプレートファイルとなります。
S2ContainerからPageコンポーネントを取得する場合は、次のようなCGIスクリプトになります。
% cat public/cgi/quick3.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/cgi.rb' class Page < Seasar::CGI::Page s2comp end Seasar::CGI.run %
Seasar::CGI::Pageクラスのクラス変数を次に示します。
@@fatal.
フレームワーク起動後にエラーが発生した場合に、実行される手続きオブジェクトを設定します。手続きオブジェクトには、 キャッチされたエラーインスタンスとSeasar::CGI::Pageクラスのインスタンスが渡されます。
デフォルトでは、config/cgi.rb内で次のように設定されています。
Seasar::CGI::Page.fatal {|e, page| s2logger.fatal() {"#{e.message} #{e.backtrace}"} print "Location: #{BASE_URL}fatal.html\n\n"; }
@@tpl_dir.
erbテンプレートファイルを保存するディレクトリへのパスを設定します。デフォルトではプロジェクトディレクトリの tplディレクトリが設定されています。
@@tpl_ext.
erbテンプレートファイルの拡張子を設定します。デフォルトは「html」です。
Seasar::CGI::Pageクラスのインスタンス変数を次に示します。get/postメソッドの処理において使用できます。
@cgi.
Ruby添付ライブラリのCGIインスタンスを保持します。
@contents.
レスポンスコンテンツを保持する変数です。puts, p, renderメソッドの結果文字列が追記されます。
@auto_render.
get/postメソッドの呼び出し後に、@contentsのサイズが0の場合に、自動的にrenderメソッドを呼ぶかどうかを Booleanで設定します。
@auto_response.
get/postメソッドの呼び出し後に、@contentsを、@cgi.outで出力するかどうかをBooleanで設定します。
@headers.
auto_response時に、@cgi.outで出力するHTTPヘッダをHashで保持します。
Pageクラスでは、WEB層に関する次の処理を行います。
Pageクラスにgetメソッドを定義すると、リクエストメソッドがGETの場合に呼ばれます。postメソッドも同様に、リクエストメソッドが POSTの場合に実行されます。次のようなCGIスクリプトを作成します。
% cat public/cgi/quick5.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/cgi.rb' class Page < Seasar::CGI::Page s2comp def get puts 'Hello World 5' end end Seasar::CGI.run %
ブラウザで、http://localhost/s2cgi/cgi/quick5.cgi にアクセスすると、「Hello World 5」 と表示されます。 putsメソッドとpメソッドは、Seasar::CGI::Pageクラスでオーバーライドされています。それぞれ、引数で渡されたオブジェクトの 文字列表現とinspect結果をレスポンスコンテンツに追加します。レスポンスコンテンツのサイズが0でない場合は、erbテンプレートファイルの 自動読み込みは行われないため、上記サンプルでは、erbテンプレートファイルを用意する必要はありません。
Seasar::CGI::Page#paramメソッドは、引数で指定されたキー名のリクエストパラメータを返します。リクエストパラメータに キーが存在しない場合はnilを返します。キーが複数存在する場合は配列を返します。
param(name)
paramメソッドは、 リクエストパラメータの検証を行う場合にも使用します。検証設定についてはこちらを参照下さい。
Seasar::CGI::Page#renderメソッドはerbテンプレートファイルを処理し、結果文字列を@contentsに追記します。引数でerbテンプレートファイルを指定することができます。 erbテンプレートファイルの指定は、@@tpl_dirで指定されるディレクトリ以下の相対パスで指定します。「@@tpl_dir/cgi/quick6.html」 テンプレートファイルを指定する場合は、次のようになります。
render 'cgi/quick6'
引数を省略した場合は、SCRIPT_NAMEからBASE_URLを除いた相対パスが使用されます。SCRIPT_NAMEが「/s2cgi/cgi/quick6.cgi」、BASE_URLが「/s2cgi」の場合は、 テンプレートファイルは「cgi/quick6」となります。テンプレートファイルの拡張子には、@@tpl_ext値が使用されます。
renderメソッドは、レイアウトファイルを自動検索します。レイアウトファイルが見つかった場合は、テンプレートファイルの処理を行いません。 レイアウトファイルがテンプレートファイルとして処理されます。レイアウトファイルの検索は、テンプレートファイルに「_layout」を付加したファイルが 存在するかを確認します。存在しない場合は、テンプレートファイルと同じディレクトリに「layout」というファイルが存在するかを確認します。 テンプレートファイルが「cgi/quick6」の場合は、まず「cgi/quick6_layout」が存在するかを確認し、存在しない場合は、「cgi/layout」 が存在するかを確認します。
Seasar::CGI::Page#partialメソッドは、テンプレートファイルを処理し、文字列を返します。引数でerbテンプレートファイルを指定できます。レイアウトファイル内でメインコンテンツの テンプレートを読み込んだり、テンプレートファイルを部分的に分割したりする場合に使用します。レイアウトファイル内でメインコンテンツのテンプレートファイルを指定 する場合は、@templateを引数に指定して下さい。
<!-- レイアウトファイル --> <%= partial(@template) %> # メインコンテンツの読み込み
Seasar::CGI::Page#redirectメソッドは、引数で指定されたURLをHTTPヘッダのLocationに設定し、リダイレクトを実施します。 リダイレクトを実施後、exitを実行しCGIスクリプトを終了します。第二引数でリダイレクトする際のリクエストパラメータを Hashで設定できます。
redirect('http://xxx.com/index.cgi', :year => 2009)
Seasar::CGI::Page#validateメソッドは、リクエストパラメータの検証を行う処理を含むブロックを受け取ります。第一引数では、 :all、:get、:postを指定し、どのリクエストメソッドのアクセス時に検証を行うかを指定することができます。 戻り値としてBooleanを返します。戻り値がFalseの場合は、リクエストメソッドに対応するget/postメソッドの呼び出しが行われません。
class Page < Seasar::CGI::Page validate { # :allと同じ。 GET、POST リクエストの場合に実行される param :year, :numeric valid? } validate(:get) { # GET リクエストの場合に実行される param :year, :numeric valid? } validate(:post) { # POST リクエストの場合に実行される param :year, :numeric valid? } end
validateメソッドに渡されるブロック内では、リクエストパラメータを検証するために次のメソッドが使用できます。
param(name, type = nil, options = nil)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 第3引数: 検証メソッドに渡されるオプション
リクエストパラメータを nameで指定し、適用する検証メソッドを typeで指定します。一つのリクエストパラメータに複数の バリデーションタイプを登録することができます。
valid? メソッド.
valid?(name = nil, type = nil)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 戻り値: Boolean
引数の name と type に合致する登録エントリがすべてValidな場合にTrueを返します。1つでもErrorが ある場合は、Falseとなります。引数 name がnilの場合は、typeに合致する検証エントリが対象となります。 引数typeがnilの場合は、nameに合致する検証エントリが対象となります。nameおよびtypeが共にnilの場合は、 すべての登録エントリが対象となります。
valids メソッド.
valids(name = nil, type = nil)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 戻り値: Seasar::Validate::Entryインスタンスの配列
引数の name と type に合致する登録エントリのうち、検証結果がValidなエントリを配列で返します。
error? メソッド.
error?(name = nil, type = nil)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 戻り値: Boolean
引数の name と type に合致する登録エントリのうち、1つでもErrorがある場合にTrueを返します。 すべてのエントリがValidな場合はFalseを返します。
次のように、erbテンプレートファイル内で使用することができます。
username : <input type="text" name="username" value=""/> <% if error?(:username) %><span class="err_msg">ユーザ名を4~8文字で入力して下さい。</span><% end %>
errors メソッド.
errors(name = nil, type = nil)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 戻り値: Seasar::Validate::Entryインスタンスの配列
引数の name と type に合致する登録エントリのうち、検証結果がErrorのエントリを配列で返します。
if_errors メソッド.
if_errors(name = nil, type = nil, &procedure)
- 第1引数: リクエストパラメータのキー名
- 第2引数: バリデーションタイプ
- 第3引数: ブロック
引数の name と type に合致する登録エントリのうち、1つでもErrorがある場合に、ブロック引数にすべてのエラーエントリ配列を 渡して呼び出します。
次のように、erbテンプレートファイル内で使用することができます。
<% if_errors do |errors| %> <%=h errors.size %>件の問題が発生しました。 <% end %>
バリデーションタイプごとに使用されるメソッドは、Seasar::Validate::Utilsモジュールに定義されているメソッドが 使用されます。その際、メソッド名は、バリデーションタイプに"?"を付加した名前になります。バリデーションタイプが「:int」の 場合は、メソッド名は「int?」とになります。
また、Seasar::Validate::Utils::Validators Hashに登録されている手続きオブジェクトも使用されます。 バリデーションタイプで指定されるSymbolがHashキーとして使用されます。
:int.
Integerかどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.int? です。
オプションはHashで指定します。(省略可)paramメソッドの例は次になります。
- :min => 最小値
- :max => 最大値
- :include => :min、:maxで指定される数値を含むかどうか。デフォルトはTrueです。
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :year, :int, :min => 2000, :max => 2050
:numeric.
数値文字列かどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.numeric? です。
オプションはHashで指定します。(省略可)paramメソッドの例は次になります。
- :min => 最小値
- :max => 最大値
- :include => :min、:maxで指定される数値を含むかどうか。デフォルトはTrueです。
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :year, :int, :min => 2000, :max => 2050
:string.
Stringかどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.string? です。
オプションはHashで指定します。(省略可)paramメソッドの例は次になります。
- :min => 最短文字数
- :max => 最長文字数
- :include => :min、:maxで指定される数値を含むかどうか。デフォルトはTrueです。
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :name, :string, :min => 6, :max => 8
:array.
配列かどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.array? です。
オプションはHashで指定します。(省略可)paramメソッドの例は次になります。
- :min => 最小メンバ数
- :max => 最大メンバ数
- :include => :min、:maxで指定される数値を含むかどうか。デフォルトはTrueです。
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :names, :array, :min => 6, :max => 8
:member, :in.
オプションで指定する配列のメンバかどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.member? です。
オプションはHashまたはArrayで指定します。paramメソッドの例は次になります。
- :items => メンバ配列
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :names, :member, %w[foo bar hoge huga]
:regexp.
オプションで指定するRegexpにマッチするかどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.regexp? です。
オプションはHashまたはRegexpで指定します。paramメソッドの例は次になります。
- :regexp => Regexp
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :name, :regexp, /^abc/
:alpha.
アルファベット文字列かどうかを検証します。
使用されるメソッドは、Seasar::Validate::Utils.alpha? です。
オプションはHashで指定します。(省略可)paramメソッドの例は次になります。
- :case => :down または、:up
- :required => リクエストパラメータが存在するかどうか。デフォルトはTrueです。
param :name, :alpha, :case => :down
Validationメソッドで検証ブロックを登録する代わりに、GETアクセスに対してはvalidate_getメソッド、 POSTアクセスに対してはvalidate_postメソッドを定義して、バリデーションを実施することもできます。
class Page < Seasar::CGI::Page def validate_get # GET リクエストの場合に実行される param :year, :numeric valid? end def validate_post # POST リクエストの場合に実行される param :year, :numeric valid? end end
S2CGIのセッションは、Ruby添付ライブラリのCGI::Session を使用します。newメソッドの引数で渡すオプションは、Seasar::CGI::Session.optionsに設定されているHash値が使用されます。 デフォルトでは、config/cgi.rb内で次のように設定されています。
Seasar::CGI::Session.options = {'tmpdir' => SESSION_DIR, 'database_manager' => CGI::Session::PStore}
Seasar::CGI::Page#get_session メソッド.
CGI::Sessionを生成して返します。セッションが開始されていない場合は、nilを返します。
Seasar::CGI::Page#start_session メソッド.
CGI::Sessionの新規インスタンスを返します。
CGIスクリプト内で定義するPageクラスをコンポーネント登録すると、Seasar::CGI.runメソッドは、登録されたPageコンポーネントを S2Containerから取得して実行します。Pageコンポーネントに依存するコンポーネントのインジェクション設定を行うことで、DIを実施できます。
lib/exampleディレクトリに次のようなサービスクラスを作成します。
% cat lib/example/some-service.rb module Example class SomeService s2comp def add(a, b) return a + b end end end
次のようなCGIスクリプトを作成します。Pageクラスでは、SomeServiceインスタンスを受け取る「:some_service」 アクセッサメソッドを定義します。
% cat public/cgi/quick6.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/cgi.rb' require 'example/some-service' class Page < Seasar::CGI::Page s2comp attr_accessor :some_service def get puts '1 + 2 = ' + @some_service.add(1, 2).to_s end end Seasar::CGI.run %
ブラウザで、http://localhost/s2cgi/cgi/quick6.cgi にアクセスすると、「1 + 2 = 3」 と表示されます。
libディレクトリに作成するサービスやロジッククラスのUnitTestはtestディレクトリに作成します。
testディレクトリに作成したUnitTestは、test-suite.rbで実行できます。
% ruby test/test-suite.rb Loaded suite . Started ... Finished in 0.001 seconds. 3 tests, 8 assertions, 0 failures, 0 errors %
Rack CGI フレームワークの起動は、Seasar::Rack::CGI.run メソッドを呼びます。 public/rackディレクトリに次のような quick1.cgiを作成します。
% cat public/rack/quick1.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/rack.rb' Seasar::Rack::CGI.run %次に、tpl/rack ディレクトリに quick1.cgiのerbテンプレートファイルを「quick1.html」として作成します。% cat tpl/rack/quick1.html Hello World %ブラウザで、http://localhost/s2cgi/rack/quick1.cgi にアクセスすると、「Hello World」 と表示されます。
Seasar::Rack::CGI.run メソッドには、引数でSeasar::Rack::CGI::Pageクラスのインスタンスを渡すことができます。 public/rackディレクトリに次のような quick2.cgi を作成します。
% cat public/rack/quick2.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/rack.rb' class Page < Seasar::Rack::CGI::Page; end Seasar::Rack::CGI.run(Page.new) %次に、tpl/rackディレクトリに quick2.cgiのerbテンプレートファイルを「quick2.html」として作成します。% cat tpl/cgi/quick2.html Hello World 2 %ブラウザで、http://localhost/s2cgi/rack/quick2.cgi にアクセスすると、「Hello World 2」 と表示されます。Seasar::Rack::CGI.run メソッドは、引数が nil の場合、S2ContainerからSeasar::Rack::CGI::Pageクラスのコンポーネントを取得します。 コンテナにSeasar::Rack::CGI::Pageクラスのコンポーネントが存在しない場合は、Seasar::Rack::CGI::Pageクラスのインスタンスを自動生成して使用します。
@env.
Seasar::Rack::CGI::Page#callに渡されるRack環境引数
@request.
Rack::Requestのインスタンスを保持します。
@response.
Rack::Responseのインスタンスを保持します。@response.finishメソッドは、get/postメソッドの呼び出し後に自動的に実行されます。
@auto_render.
get/postメソッドの呼び出し後に、@response.body.size が 0、 @response.status が 200 の場合に、 自動的にrenderメソッドを呼ぶかどうかをBooleanで設定します。
Rack Up を行う手続きオブジェクトをSeasar::Rack::CGI::Page.rack クラス変数に設定します。デフォルト値として、config/rack.rbで 次のように設定されています。Seasar::Rack::CGI::Page.rack {|page| Rack::Builder.app do use Seasar::Rack::CGI::Stdin2StringIO use Rack::ShowStatus use Rack::ShowExceptions use Rack::MethodOverride use Rack::ContentLength use Rack::Session::Cookie run page end }Rack Up 手続きオブジェクトは、Seasar::Rack::CGI.runメソッド内で実行されます。 その際、S2Containerから取得されたPageインスタンスや新規生成されたPageインスタンスが引数として渡されます。
また、Rack Up 手続きオブジェクトは、Seasar::Rack::CGI.runメソッドのブロック引数としても設定できます。% cat public/rack/quick3.cgi #!/usr/bin/env ruby # -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../../config/rack.rb' class Page < Seasar::Rack::CGI::Page s2comp def get puts 'Hello World 3' end end Seasar::Rack::CGI.run {|page| Rack::Builder.app do use Seasar::Rack::CGI::Stdin2StringIO run page end } %
© Copyright The Seasar Foundation and the others 2008-2009, all rights reserved. |