5分でわかるWatir
以下の文章はŽeljko Filipinによる"Watir in five minutes"の翻訳です。*1
(中略)
僕が初めてWatirを仕事で使った時、すごく驚いたことを今でも覚えている。インストールしてから数時間で、僕はテスト中のWebアプリケーション用のスクリプトを書けるようになっていた。この本を読めば、数時間もかからずにWebサイトをテストできるようになるはずだ。
もしRubyに親しんでいるのなら、IRBがRubyライブラリを勉強するための最良のツールの1つだってことがわかっているだろう。
もしRubyを知らないのなら、こう思うかもしれない。IRBって何?
IRB(この場合)はInternational Ruby BoardでもImmigration or Refugee Board (of Canada)のことでもない。Interactive Ruby Sehllのことだ。読んで字の如く、Ruby用のシェルことだと思ってくれ。
IRBをスタートするためには、コマンドライン上で'irb'と打てばいい。このように表示されるはずだ。
$ irb >
これで、Rubyコマンドを打ち込めば、即座に結果が得られるようになった。'require "watir-webdriver"と入力してwatir-webdriver gemを使用することをRubyに伝えてみよう。
このように表示されるはずだ。
> require "watir-webdriver" => true
こうなっても、パニクるな。
> require "watir-webdriver" LoadError: no such file to load -- watir-webdriver from (irb):1:in `require' from (irb):1
これは最初にRubyGemsをrequireしなければならないことを意味している。この場合は、このようにする。
> require "rubygems" => true > require "watir-webdriver" => true
すべてのRubyコマンドは何らかの値を返す。`require "rubygems"`は、Rubyのインストール状況に応じて'true'または'false'を返す。今のところは気にしなくていい。`require "watir-webdriver"`の返り値は`=> true`となるはずだ。返り値には2つの部分がある。最初のは'=>'。矢印みたいなこれは、'Rubyがこれを返した'ということを意味している。2つめの部分は'true'。'true'が返ってきた場合、すべてが上手く行っている。
こうは言ったけれども、とりあえず返り値のことは無視してくれてかまわない。
さてこれからが魔法の始まりだ。この1つのコマンドでFirefoxが立ち上がる。
browser = Watir::Browser.new :ff
watir-webdriver driving Firefox 6 on Mac OS 10.6
(中略)
立ち上げるブラウザは1つだけにしておこう。それで十分だ。他のブラウザとは後で遊ぼう。出力はこうなるはずだ。
> browser = Watir::Browser.new :ff => #<Watir::Browser:0x2ed1f1cd5b186306 url="about:blank" title="">
前にも言ったように、`#
ただブラウザを立ち上げただけでもカッコいいけど、まだ便利ではない。Watirはそれ以上のことができる。例えば、ブラウザをどんなサイトへも誘導することができる。今回の例として、google.comを使用する。この例を終えてから、他のサイトへも自分自身で試してもらいたい。
さて、google.comへ行こう。
> browser.goto "http://www.google.com/" => "http://www.google.hr/"
google.comが開かれたね。魔法みたいじゃないかい?
ブラウザをコントロールすることはとても便利だ。だけどもちろん、テストをするためにはアクションを実行するだけでは足りない。アクションの後に何が起きたのか確認しなければいけないんだ。ブラウザのアドレスバーにURLを入力した後に何が起きるか、リンクボタンをクリックし後に何が起きるか、テキストフィールドに何か入力したりセレクトボックスで何かを選択した場合に何が起こるのか・・・?
これから初めて確認を行う。同じように、初めてコマンドの後にRubyが何を返したのかについても調べて見る。ブラウザがgoogle.comを実際に開いたか確認してみよう。
> browser.url => "http://www.google.hr/"
ちゃんと動いてたね!Rubyはブラウザのアドレスバーの文字列を返した。僕はクロアチアに住んでいるから、*google.hr*が開いた。もし君がアメリカ以外の国に住んでいるなら、別のGoogleサイトを開いているだろう。
リンクをクリックするときがきた。どのリンクをクリックするのか、簡単に明示することができる。今は、Google.com in Englishというテキストのリンクをクリックしてみる。同じテキストのリンクが同一ページ内に複数あると少し複雑になるけど、これに関しては後で扱う。もし既にgoogle.comを開いているなら、このステップは無視してくれ。
> browser.link(:text => "Google.com in English").click => []
さて、google.comが開いた。
別のリンクをクリックする前に、Watirのすごい特徴をお見せしよう。それはフラッシュという。現実のWebアプリケーションは複雑だ。時には既存のもののテストやデバッグを行わければいけない。正しい要素をやり取りしているのか、確認しないといけない。試してみよう(google.comの左上にあるImagesリンクを見て)。
> browser.link(:text => "Images").flash => 10
リンクがフラッシュしたのが確認できた?バックグラウンドカラーが赤に数回変わった。クールじゃない?僕はWatirを使うときは何時もこの機能を利用する(例えばカンファレンスで)。Watirはプレゼン向きだと思う。とても視覚的だ。
もしフラッシュが確認できなかったら(フラッシュするのは短い間だ)、同じコマンドを数回実行してもらいたい。同じコマンドを実行するために上向きの矢印キーをクリックすればいい。
リンクをクリックしてみよう。
> browser.link(:text => "Images").click => []
今回はページのタイトルを確認してみよう。
> browser.title => "Google Images"
ページのタイトルが文字列で返ってきた。
なにか検索してみよう。これは検索のテキストフィールドにbookの入力を行う。
> browser.text_field(:name => "q").set "book" => ["book"]
どうやって僕がテキストフィールドのname属性がqだとわかったのか不思議かもしれない(':name => "q"'のこと)。もし君がページ内を調査する方法を知らなくても、このまま読み進めてくれ。後で説明する。
さて、Search Imageボタンをクリックしよう。
> browser.button(:value => "Search Images").click => []
検索結果ページが表示された。ページ内に何枚画象があるのか確認してみよう。
(違う結果になる可能性もあって、常に250というわけではない)
> browser.images.size => 250 ||< 最後に、ブラウザを閉じてみよう。 >|| > browser.close => true
さて、楽しめたね。だけど常にIRBに入力したくはないだろう。テストを実行している間に、何か他のことをやりたいでしょ。RubyとWatirの他のほとんどすべてと同じく、単純な解決策がある。IRBに入力したコードをすべてテキストファイルに貼りつけて、拡張子を*rb*にして保存するんだ。IRBは開発やデバックの時にしか使わない。だから、'irb'をファイルの最初の行に貼り付けなくていい。ファイルはこのようになるはずだ。
require "watir-webdriver" browser = Watir::Browser.new :ff browser.goto "http://www.google.com/" browser.url browser.link(:text => "Google.com in English").click browser.link(:text => "Images").click browser.title browser.text_field(:name => "q").set "book" browser.button(:value => "Search Images").click browser.images.size browser.close
IRBに`require "rubygems"`と入力していた場合は、 ファイルの先頭にこれを付け加えておこう。
どんなテキストエディターを使用してもかまわない。僕は [RubyMine](http://www.jetbrains.com/ruby/)か[NetBeans](http://netbeans.org/)を使っている。
スクリプトを実行する。出力はこのようになるはずだ。
$ ruby watir5.rb http://www.google.hr/ Google Images 246
後でクールな見た目のレポートの作り方を教えよう。
これまでのところで良い印象を受けなかったら、多分もう無理だ。もし気に入ってくれたのなら、どでかい大砲を持ってくる時がきた。深いところへ行こう。
*1:This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
PILでHalftonみたいなの
こんな感じですか?わかりません><。
After
# -*- coding: utf-8 -*- from PIL import Image, ImageDraw def collect(img, h, w, y, x, interval): y2 = (y + interval) if (y + interval) < h else h - 1 x2 = (x + interval) if (x + interval) < w else w - 1 r = 0 g = 0 b = 0 c = 0 for i in range(y, y2 + 1): for j in range(x , x2 + 1): p = img.getpixel((j, i)) r += p[0] g += p[1] b += p[2] c += 1 return (r / c , g / c , b / c) if c > 0 else (255, 255, 255) def halftone(img): size = img.size w = size[0] h = size[1] interval = 4 r = interval / 2 output = Image.new('RGB', (w, h), 'white') draw = ImageDraw.Draw(output) for y in range(0, h + r, interval): for x in range(0, w + r, interval): p = collect(img, h, w, y, x, interval) draw.ellipse((x - r, y - r, x + r, y + r), fill = p) return output if __name__ == '__main__': img = Image.open("src.jpg") output = halftone(img) output.save("dst.jpg")
Javascriptで画象をグリッチ
Canvasの勉強がてらにJavascriptで画象をグリッチするアプリをつくってみた。
http://glitched-canvas.heroku.com/
ソースコード: https://github.com/ninoseki/glitched-canvas
Canvas要素にはピクセル単位でアクセスできるので、何でもできそうですね。
Javascript・CSSを圧縮・結合するCodeIgniterライブラリ「Simple assets」
CodeIgniterでJavascript・CSSを圧縮・結合するライブラリ「Simple assets」が便利だったので紹介してみる。
https://github.com/bstrahija/assets
導入
GitHubからダウンロードし、config、helpers、librariesをapplication配下に配置する。
※すでにapplication/config/autocload.phpが初期状態でない場合は上書きせず、追記すること。
設定
デフォルトの設定では以下のようなディレクトリ配置になっている。
/application /assets /cache /css /images /js /sparks /system
この設定を変えたい場合は、application/config/assets.phpを変更すればいい。
<?php $config['assets']['assets_dir'] = 'assets'; $config['assets']['js_dir'] = 'js'; $config['assets']['css_dir'] = 'css'; $config['assets']['cache_dir'] = 'cache';
使用方法
<?php display_css(array('init.css', 'style.css')); ?> // 引数にとったCSSを圧縮・結合し、linkタグを出力 <?php display_js(array('libs/modernizr-1.6.js', 'libs/jquery-1.4.4.js', 'plugins.js', 'script.js')); ?> // 引数にとったJavascriptを圧縮結合し、scriptタグを出力
※圧縮・結合されたファイルはassets/cache_dirに格納される。
うーん簡単で便利ですね。
コントローラー経由でファイルを出力する
すごく単純なことだけど、これまでやったことがなかったのでメモ。
ファイル名はContent-Dispositionヘッダーを使って指定するんすね。今まで知らんかった。
<?php class Test extends CI_Controller { public function files($name) { $this->load->helper('file'); $this->load->library('upload'); // ファイルを読み込んで出力 $path = $this->upload->upload_path . $name; $data = readfile($path); $mime = get_mime_by_extension($path); $this->output ->set_content_type($mime) ->set_header("Content-Disposition: attachment; filename=\"{$name}\"") ->set_output($data); } } ?>
アップロード不可能な拡張子を指定してファイルアップロードする
CodeIgniterのファイルアップロードクラスはアップロード可能な拡張子を指定することができるけど、逆にアップロード不可能な拡張子を指定できない。
そこでCI_Uploadクラスを拡張して、アップロード不可能な拡張子を指定できるようにしてみる。
MY_Upload.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class MY_Upload extends CI_Upload { public $disallowed_types = ""; // -------------------------------------------------------------------- /** * Initialize preferences * * @param array * @return void */ public function initialize($config = array()) { $defaults = array( 'max_size' => 0, 'max_width' => 0, 'max_height' => 0, 'max_filename' => 0, 'allowed_types' => "", 'disallowed_types' => "", 'file_temp' => "", 'file_name' => "", 'orig_name' => "", 'file_type' => "", 'file_size' => "", 'file_ext' => "", 'upload_path' => "", 'overwrite' => FALSE, 'encrypt_name' => FALSE, 'is_image' => FALSE, 'image_width' => '', 'image_height' => '', 'image_type' => '', 'image_size_str' => '', 'error_msg' => array(), 'mimes' => array(), 'remove_spaces' => TRUE, 'xss_clean' => FALSE, 'temp_prefix' => "temp_file_", 'client_name' => '' ); foreach ($defaults as $key => $val) { if (isset($config[$key])) { $method = 'set_'.$key; if (method_exists($this, $method)) { $this->$method($config[$key]); } else { $this->$key = $config[$key]; } } else { $this->$key = $val; } } // if a file_name was provided in the config, use it instead of the user input // supplied file name for all uploads until initialized again $this->_file_name_override = $this->file_name; } // -------------------------------------------------------------------- /** * Verify that the filetype is allowed * * @return bool */ public function is_allowed_filetype($ignore_mime = FALSE) { // if allowed file type list is not defined if (count($this->allowed_types) == 0 OR ! is_array($this->allowed_types)) { // if disallowed file type list is not defined if (count($this->disallowed_types) == 0 OR ! is_array($this->disallowed_types)) { return TRUE; } // check for disallowed file types and return // negated because is_disallowed_filetype returns opposite result as this function return ! $this->is_disallowed_filetype(); } // proceed as usual with allowed file type list check return parent::is_allowed_filetype($ignore_mime); } // -------------------------------------------------------------------- /** * Set Allowed File Types * * @param string * @return void */ public function set_disallowed_types($types) { if ( ! is_array($types) && $types == '*') { $this->disallowed_types = '*'; return; } $this->disallowed_types = explode('|', $types); } // -------------------------------------------------------------------- /** * Verify that the filetype is disallowed * * @return bool */ public function is_disallowed_filetype($ignore_mime = FALSE) { if ($this->disallowed_types == '*') { return TRUE; } if (count($this->disallowed_types) == 0 OR ! is_array($this->disallowed_types)) { return FALSE; } $ext = strtolower(ltrim($this->file_ext, '.')); if ( in_array($ext, $this->disallowed_types)) { return TRUE; } return FALSE; } }
以上のファイルとapplication/librariesに配置すればOK。
設定ファイルは以下のようにアップロード不可能な拡張子のみ記述するようにしておく。
<?php $config['upload_path'] = APPPATH . '../uploads/'; $config['disallowed_types'] = 'gif|jpg|png'; $config['max_size'] = '100'; $config['max_width'] = '1024'; $config['max_height'] = '768';
こんな感じっすかね?
Backbone.jsを使ってアプリを作ったよ
http://hitorigoto.heroku.com/
Wrenライクにタイムラインを見ずにツイートだけができるアプリを、Backbone.jsを使って作ってみた。
ソースはGithubで公開してある。
Backbone.jsのチュートリアルはHello Backbone.js(英語)がとてもわかりやすく参考になった。
今回程度のものだと普通にJavascriptで直書きしてもいいんだけど、Backbone.jsを使うと一貫性/保守性が向上するってことを実感。
Backbone.js面白い!