• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
 
 

インストール

   1  % gem install mongo_mapper

mongomapper (古いバージョンのgem)も存在するので注意

セットアップ

   1  require 'mongo_mapper'
   2  MongoMapper.database = "app1"  # DB名

  • 各モデル内で明示されない場合に利用されるデフォルトのDB名

モデル

   1  class Player
   2    include MongoMapper::Document
   3    key :name,   String, :required => true
   4    key :policy, Integer
   5    key :renkei, String
   6    key :note,   String
   7    timestamps!
   8  
   9    validates_uniqueness_of :name
  10  end

  • pkeyのidが勝手に定義される
  • 文字列は長さに制限がないので全てString

検索

   1  Player.count
   2  => 822
   3  
   4  Player.count(:renkei=>'萩原型')
   5  => 135
   6  
   7  Player.first
   8  => #<Player label: "萩原 忠志" ... >
   9  
  10  Player.all(:label=>/^河本/).map{|p| [p.pos, p.label]}
  11  => [["FW", "河本 鬼茂"], ["GK", "河本 龍将"]]

高度な設定

  • ARで言うテーブルをMongoDBではコレクションと呼ぶ
  • table を collection に変えるだけでAR風のAPIが使える

   1  class Pref
   2    include MongoMapper::Document
   3  
   4    set_database_name "usei"  # app1でなく usei DBを利用
   5    set_collection_name "zip" # prefs でなく zip コレクションを利用
   6  ...

長所

  • MongoDB自体の性能がよい
  • インタフェースが AR と DM のよい点を取り込み (CRUDはAR, SearchはDM)
  • バリデーションや関連もサポート
  • 正規表現による検索

短所

  • サーバ(MongoDB)への再接続などのコネクション機能が弱い(mongo_mapper でなく mongo の問題かも)
posted by Png maiha on Sun 21 Feb 2010 at 16:51

答え

"!=", "!==" を使う

詳細

文字列のHTMLエスケープはRailsやRack::Utilによって hヘルパメソッドとして提供されており、 ユーザはエスケープ処理を「hの有無」によって調整します。

例: hamlでのHTMLエスケープ
コード結果
= link_to(...)&lt;a href=...
=h link_to(...)&amp;lt;a href=...

自動エスケープモード

上記のようなユーザ駆動のエスケープ処理では100%の安全性を保証できないため、 hamlでは「デフォルトでエスケープする」というオプションが存在します。

   1  Haml::Template.options[:escape_html] = true

これにより常時エスケープされるようになるのですが、 今度はh の逆とも言うべき「エスケープしない」方法が必要になります。 これがずっとわからなくて困っていたのですが、 「ドキュメントを見る」という手段を思い出して解決しました。 "!=" を使えばよいようです。

例: escape_html: true
コード結果
!= link_to(...)&lt;a href=...
= link_to(...)&amp;lt;a href=...
=h link_to(...)&amp;amp;lt;a href=...

posted by Png maiha on Mon 8 Feb 2010 at 08:34 with 2 comments

link_to 等のヘルパメソッドは sinatra 本体には含まれていませんが、 sinatra_more という gem が用意されています。

install

   1  % gem install sinatra_more

standalone 利用の場合

直接 Sinatra::Base に register してしまいましょう。

   1  require 'sinatra'
   2  ...
   3  require 'sinatra_more/markup_plugin'
   4  Sinatra::Base.register SinatraMore::MarkupPlugin
   5  ...
   6  get '/' do
   7    ...

クラス利用の場合

該当クラスで register します。

   1  require 'sinatra_more/markup_plugin'
   2  
   3  class Application < Sinatra::Base
   4    register SinatraMore::MarkupPlugin
   5  end

MarkupPlugin

link_to だけでなく、全56種(ver 0.3.33 現在)ものヘルパメソッドが利用できるようになります。 以下に、よく使いそうなものを抜粋します。

   1  link_to(*args, &block)
   2  stylesheet_link_tag(*sources)
   3  javascript_include_tag(*sources)
   4  image_tag(url, options={})
   5  image_path(src)
   6  escape_html(text)
   7  h!(text, blank_text = '&nbsp;')
   8  content_tag(*args, &block)
   9  tag(name, options={})
  10  input_tag(type, options = {})
  11  form_for(object, url, settings={}, &block)
  12  text_field_tag(name, options={})

詳細は lib/sinatra_more/markup_plugin/*.rb を確認して下さい。

その他のPlugin

sinatra_more gem には、 MarkupPlugin 以外にも RenderPlugin、WardenPlugin、MailerPlugin、RoutingPlugin といったプラグインが用意されています。 利用方法は MarkupPlugin の場合と同じで、 利用したいプラグイン名を列挙していきます。

   1  require 'sinatra_more/markup_plugin'
   2  require 'sinatra_more/render_plugin'
   3  Sinatra::Base.register SinatraMore::MarkupPlugin
   4  Sinatra::Base.register SinatraMore::RenderPlugin
   5  ...

各プラグインの代表的なメソッドを記載します。 例えば、RenderPlugin にはみんな大好きな "partial" が入ってたりしますので、しっかりチェック&register しましょう。

RenderPlugin

描画系プラグイン

   1  partial(template, options={})
   2  erb_template(template_path, options={})
   3  haml_template(template_path, options={})
   4  render_template(template_path, options={})

WardenPlugin

認証系プラグイン

   1  current_user
   2  authenticate_user!
   3  logged_in?
   4  authenticated?(&block)

MailerPlugin

メール関係?(使わないので未調査)

RoutingPlugin

ルーティング系プラグイン (named route?)

   1  map(*args, &block)
   2    # map(:accounts).to('/accounts/url')
   3    # map(:admin, :show).to('/admin/show/:id')
   4    # map(:admin) { |namespace| namespace.map(:show).to('/admin/show/:id') }

posted by Png maiha on Thu 4 Feb 2010 at 01:10

Rails + Cucumber で Culerity を使うと、 以下のような WARNING が大量に発生する。 これでは、いくらテストがgreenでも精神はredになってしまう。

   1  % cucumber features/foo.feature
   2  Using the default profile...
   3  2010/01/20 18:43:57 com.gargoylesoftware.htmlunit.IncorrectnessListenerImpl notify
   4  警告: Obsolete content type encountered: 'text/javascript'.
   5  2010/01/20 18:43:58 com.gargoylesoftware.htmlunit.IncorrectnessListenerImpl notify
   6  警告: Expected content type of 'application/javascript' or 'application/ecmascript' for remotely loaded JavaScript element at 'http://z-ecx.images-amazon.com/images/G/01/nav2/gamma/amazonJQ/amazonJQ-combined-core-5113._V228305908_.js', but got 'application/x-javascript'.
   7  (...)
   8  .
   9  
  10  1 scenario (1 passed)
  11  1 step (1 passed)

この警告メッセージは、 HtmlUnit が吐いているものであるが、 Culerity::RemoteBrowserProxy のオプション(log_level) で制御することができる。 具体的には、 "script/generate culerity" を利用した場合、 以下の step ファイル内で定義されている。

   1  % vi features/step_definitions/culerity_steps.rb
   2  -  $browser.log_level = :warning
   3  +  $browser.log_level = :severe

(celerity の default は :off だが、culerity が :warning にしている)

上記の修正によって、WARNING の表示が抑制される。

   1  % cucumber features/foo.feature
   2  Using the default profile...
   3  .
   4  
   5  1 scenario (1 passed)
   6  1 step (1 passed)

新規プロジェクトの度に毎回変更するのが面倒であれば、 generator の template を直接変更するのもいいかもしれない。

   1  % vi $GEM_PATH/gems/culerity-0.2.7/rails_generators/culerity/templates/features/step_definitions/culerity_steps.rb

指定可能な log_level は、 (高) :all, :severe, :warning, :info, :config, :fine, :finer, :finest, :off (低) であり、実際に以下のコードで確認することができる。(JRuby)

   1  % irb
   2  irb(main):001:0> java.util.logging.Level.constants
   3  => ["FINE", "CONFIG", "FINEST", "FINER", "WARNING", "SEVERE", "OFF", "INFO", "ALL"]

log level に関するさらなる詳細は java.util.logging.Level を参照のこと。

http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/logging/Level.html

posted by Png maiha on Wed 20 Jan 2010 at 10:39

(以下は PostgreSQL を例にしてますが、他のドライバでも通用すると思います)

install

まずは JRuby 用のドライバをインストールします。

   1  % gem install activerecord-jdbcpostgresql-adapter

設定

通常は database.yml に "adapter: jdbcpostgresql" と記述して利用するのですが、ここでは別の方法を紹介します。 内容は簡単で以下のコードを評価するだけです。

   1  if RUBY_PLATFORM == "java"
   2    require "active_record/connection_adapters/jdbcpostgresql_adapter"
   3  end

(Railsであれば "config/initializers/jruby_compat.rb" などに記述しておくとよいでしょう)

メリット

  • MRI と同じアダプタ名 "postgresql" を利用できる
  • 変更なしで MRI, JRuby のどちらでも動作する

実行例

   1  % rvm use system
   2  % ./script/console
   3  >> User.count
   4  => 6
   5  >> User.connection.class
   6  => ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
   7  
   8  % rvm use jruby
   9  % ./script/console
  10  >> User.count
  11  => 6
  12  >> User.connection.class
  13  => ActiveRecord::ConnectionAdapters::JdbcAdapter

JRuby はまだ発展途上ですので、 開発や挙動確認で MRI を利用する局面が多々あります。 そんな折、この方法であればいちいち database.yml の内容を変更する必要がないため、非常にシームレス&快適に利用できると思います。

posted by Png maiha on Mon 18 Jan 2010 at 23:44

chasen を久々に使ってみたところ以下のエラーが出ました。 (chasen-2.4.4-2 @ Ubuntu)

   1  % chasen foo.txt
   2  chasen: /var/lib/chasen/dic/debian/cforms.cha:9-21: no basic form

調べてみたところ、naist-jdic-utf8 パッケージの不具合で、 以下のコードを設定ファイルに追加することで解決するようです。 (場所はどこでもいいと思うのでとりあえず一番下に追加)

   1  # vi /usr/share/chasen/chasenrc-utf8
   2  ...
   3  (ENCODE "w")

(http://groups.google.co.jp/group/linux.debian.bugs.dist/browse_thread/thread/4fb69cc926bf8bc1?pli=1)

   1  % chasen foo.txt
   2  あ      ア      あ      感動詞
   3  いう    イウ    いう    動詞-自立   ...
   4  え      エ      え      感動詞
   5  お      オ      お      感動詞
   6  EOS

次のリリースでは治る予定のようです。

posted by Png maiha on Sat 2 Jan 2010 at 16:47

haml は構造化文章をシンプルかつ強力に記述することができるが、 複数行のデータの扱いには以下の理由で不向きである。

  • 行指向であるため適切なインデントの記述が強要される
  • 頑張って埋め込んでも可読性が落ちて全体の構造が把握し辛くなる

これを改善するには、コード(構造情報)とデータの分離が必要になる。

inline filter module

   1  module Inline
   2    include Haml::Filters::Base
   3   
   4    def self.[](key)
   5      @@data[key.to_s] rescue nil
   6    end
   7   
   8    def render(str)
   9      @@data = Hash[*str.split(/^\s*@@\s*(\w+)\s*\n/m)[1..-1]]
  10      return nil
  11    end
  12  end

上記を評価することで、 sinatra の in file template のようにデータ群を管理できるようになる。

入力(haml)

   1  %h1 Inline Filter
   2  .describe= Inline[:describe]
   3  .author created by #{Inline[:author]}
   4   
   5  :inline
   6   @@ describe
   7   This filter easily separates structure and data.
   8   You can use in-file-templates like sinatra.
   9   
  10   @@ author
  11   maiha@wota.jp

出力(html)

   1  <h1>Inline Filter</h1>
   2  <div class='describe'>
   3    This filter easily separates structure and data.
   4    You can use in-file-templates like sinatra.
   5  </div>
   6  <div class='author'>created by maiha@wota.jp</div>

posted by Png maiha on Tue 20 Oct 2009 at 20:59

Gears を使うには

  1. gears_init.js の読み込み
  2. 低レベルAPIを駆使

という面倒な作業が必要になる。

具体的には

   1  <script type="text/javascript" src="gears_init.js"></script>

   1  var db = google.gears.factory.create('beta.database');
   2  db.open("database-demo");
   3  var rs = db.execute("select name from users");
   4  while(rs.isValidRow()) {
   5    name = rs.fieldByName('name');
   6    rs.next();
   7  }
   8  rs.close();
   9  db.close();

のようなコードが必要になり、今日日こういうのは書きたくない。 そこで、

active_record.js を使う

Aptana が提供してる activejs プロジェクトの ActiveRecord ライブラリを利用すると、以下のようにすっきりする。

   1  <script type="text/javascript" src="active_record.js"></script>

   1  ActiveRecord.connect(ActiveRecord.Adapters.Gears,'database-demo');
   2  var User = ActiveRecord.create('users', {name:''});
   3  User.create({name:'maiha'});

RailsのARを忠実にJavaScriptへ移植してあるため、 ARに慣れていればほぼドキュメントなしで使えるのが嬉しい。

   1  maiha = User.findByName('maiha');  // Dynamic Finder
   2  name  = maiha.name; // Accessor methods
   3  maiha.name = 'foo';
   4  maiha.save();
   5  
   6  User.count();
   7  User.find({all: true, order: 'name'});

他にも

  • Validation
  • Callback
  • Relation (hasOne, hasMany, belongsTo)
  • Migration

といった機能が実装されており、 ARの移植物としてみても完成度が非常に高い。 ちなみに、js のサイズは compaction なしで200KB程度。

参考

  • http://activerecordjs.org/
posted by Png maiha on Mon 19 Oct 2009 at 05:51

S-IDE では操作対象の要素を xpath で指定することができる。

例:xpathの明示
コマンド対象
clickxpath=//h2/a

対象要素を特定するこの機能は Element Locator と呼ばれ、 Selenium Core で提供されている。

   1  BrowserBot.prototype.findElement = function(locator, win) {
   2      var element = this.findElementOrNull(locator, win);
   3      if (element == null) throw new SeleniumError("Element " + locator + " not found");
   4      return element;
   5  }
(selenium-core-1.0.1/core/scripts/selenium-browserbot.js)

従って、S-IDE の対象指定以外での場所、 例えば自作関数内や getEval の中などで使いたい場合には、 上記の findElement を直接呼び出すとよい。

HP2703/2842
MP1413/1413

   1  function isHpFull(percent) {
   2    var path = '//tr[0]/td[1]';
   3    var hp   = selenium.browserbot.findElement(path).split('/');
   4    var hp1  = parseInt(hp[0]);
   5    var hp2  = parseInt(hp[1]);
   6    return ((hp1 * 100 / hp2) > percent);
   7  }

例:HPが90%以上ある場合は宿屋に入らない
コマンド対象
gotoIfisHpFull(90)skip_inn
clicklabel=宿屋
labelskip_inn

関連として、Selenium 環境ではない状態の Mozilla で xpath を扱うには、 document.evaluate が便利である。

   1  function xpath2text(path) {
   2    var result = document.evaluate(path, doc, null, 7, null);
   3    var item = result.snapshotItem(0);
   4    return item.innerHTML;
   5  }

参考

  • https://developer.mozilla.org/ja/Introduction_to_using_XPath_in_JavaScript
posted by Png maiha on Fri 25 Sep 2009 at 21:50

S-IDE でループや条件分岐といったフローコントロールを行うためのメモ

下策:TRをコピペ

[ユースケース] 無限でなくていいから適度にいますぐ

例:好きなだけコピペ
コマンド対象
open/users/new
typenamemaiha
typepassxxxxx
open/users/new
...

1,000オペレーションは全然大丈夫だったけど、 10,000ぐらい書いたら色々重くなったので注意

中策:flowControl extension を使う

[ユースケース] ループだけでなく条件分岐もできる

インストール

Andrey が作った flowControl は Selenium 用であるが、 それを Darren が S-IDE に移植した(goto_sel_ide.js) ので Selenium Core 拡張として読み込ませる。

  • http://51elliot.blogspot.com/2008/02/selenium-ide-goto.html

例:華麗に goto
コマンド対象
labelcreate_user
open/users/new
typenamemaiha
typepassxxxxx
gotocreate_user

上策:while で攻める

[ユースケース] goto はリアルで無限なので while で回数指定する

例:while で500ループ指定
コマンド対象
store0i
whilestoredVars.i++ < 500
open/users/new
typenamemaiha
typepassxxxxx
endWhile

flowControlのその他の命令及び詳細な使い方は

  • http://wiki.openqa.org/display/SEL/flowControl
posted by Png maiha on Mon 21 Sep 2009 at 17:40