2012-03-19

Alpacaカワイイヨカワイイヨ

おとといからWebkit三昧です。

Packagistも最近登録したら直ぐに反映されるようになったので楽になりましたね!
ということでAlpacaとAlpaca-webkitをPackagistに追加したのでcomposerで簡単に楽しむことができます。

https://github.com/chobie/alpaca

AlpacaとAlpaca-webkitの設定方法

まず、composer.jsonにalpacaとalpaca-webkitを追加します。

  • composer.json
{
    "name": "my-project",
    "version": "1.0.0",
    "require": {
        "alpaca/alpaca": "master-dev",
        "alpaca/webkit": "master-dev"
    }
}
  • composer.pharを拾ってきてUPDATEします。
wget http://getcomposer.org/composer.phar
php -d detect_unicode=0 composer.phar update

※ 予めgem install capybara-webkitをして/Library/Ruby/Gems/1.8/gems/capybara-webkit-0.11.0/bin/にwebkit_serverがないと動きません><

  • 遊びます
<?php
require "vendor/.composer/autoload.php";

Alpaca\Alpaca::registerDriver('Alpaca\Driver\Webkit');
$session = new Alpaca\Session('Alpaca\Driver\Webkit');

$session->visit("http://www.yahoo.co.jp");
$session->fillIn("p","Hello World");
$session->clickButton("検索");

$session->render("/tmp/abc.png",array("width"=>1024,"height"=>100));
  • 出来上がり

f:id:chobi_e:20120319135011p:plain

今後のRoadmap

最近手広くやりすぎていて管理できていない感が満載ですが、僕の野望としてはSeleniumとGoutte Driverの追加と
Behat、PHPUnitとの統合をしたいなーと考えています。特にBehatとalpacaは相性が良いので優先度高めにやりたい感じ。

Contribute待ってます!

追記

とおもったらBehatにMinkという素晴らしい物があるじゃまいか!ちょっとMinkレビューしてみよっと
https://github.com/Behat/Mink

2012-03-18

BDD + Alpaca-Webkit = headless acceptance test framework for PHP web application.

Alpaca-webkitはcapybara-webkitwebkit_serverと通信を行ってPHPwebkitブラウザを動作させるためのツールキットです。まだまだ鋭意製作中なのでがんがん変わりますがどういったことができるか、ということの説明をかいておきましょう。

Capybara-webkit

Capybara-webkitはthoughtbot社が作成しているQtWebkitを利用してブラウザでのテストが行えるライブラリです。Capybara-webkit自体はrubyのライブラリとc++で書かれたQtWebkitのサーバーの二つが同梱されています。
このQtWebkitのサーバープログラムはソケット通信で内部のWebkitブラウザに指示を出しJavaScriptの実行や、HTMLの操作などなどが行えます。

普通、PHPでこういったブラウザ関連のテストをする場合は現状Seleniumオンリーだったのですが、Capybara-webkitのサーバー部分を流用してPHPでももっと自由に受け入れてストが行えるようにしてみようと試みているのがAlpaca-webkitです。

Alpaca-webkit

https://github.com/chobie/alpaca-webkit

capybara-webkitにinspiredされたライブラリ(というかwebkit_serverに依存)でPHPである程度自由にWebkitブラウザをheadlessで弄れます。
なぜアルパカ押しかというとσ(゜∀゜が高校生のころからアルパカが好きだったからです。capybara-webkitの実装を見つつ動作を調べている状況なのでまだまだAPIは洗練されていませんが、PHPwebkitブラウザを弄れるのはひじょーに面白いです。

もし試したい、という酔狂な方向け。

現在は/Library/Ruby/Gems/1.8/gems/capybara-webkit-0.11.0/bin/webkit_serverにwebkit_serverがあることを期待してるので、各自gemを使ってcapybara-webkitを前もってインストールして下さい。capybara-webkitはqtへの依存があるので前もってbrew install qt(前からbrewを使っている方は一旦brew updateしてFormuraを最新の状態にしておきましょう)でQtをインストールすればgem install capybara-webkitでOKです。

まともにQtをインストールすると数時間コースなのでbrewでインストールすることをオススメします。

Behat

試しにBehatでAlpaca-webkitを使って遊んでみます。

Feature: アルパカ
  アルパカちゃんを使ってGoogle検索をしてみます


Scenario: アルパカを使ってGoogleを開いて検索します
  Given アルパカで "http://www.google.com/" を開きます
  And 検索ボックスに "アルパカ" と入力します
  When 検索ボタンを押します
  Then I should get:
    """
    アルパカの検索結果
    """
  • FeatureContext.php
<?php

use Behat\Behat\Context\ClosuredContextInterface,
    Behat\Behat\Context\TranslatedContextInterface,
    Behat\Behat\Context\BehatContext,
    Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
    Behat\Gherkin\Node\TableNode;

require "/Users/chobie/src/alpaca/src/Alpaca/Driver/Webkit.php";
require "/Users/chobie/src/alpaca/src/Alpaca/Driver/Webkit/Browser.php";
require "/Users/chobie/src/alpaca/src/Alpaca/Driver/Webkit/Node.php";

/**
 * Features context.
 */
class FeatureContext extends BehatContext
{
    /**
     * Initializes context.
     * Every scenario gets it's own context object.
     *
     * @param   array   $parameters     context parameters (set them up through behat.yml)
     */
    public function __construct(array $parameters)
    {
        // Initialize your context here
        $this->browser = new Alpaca\Driver\Webkit(null);
    }

    /**
     * @Then /^I should get:$/
     */
    public function iShouldGet(PyStringNode $string)
    {
	$data = $this->browser->body();
    }


    /**
     * @Given /^アルパカで "([^"]*)" を開きます$/
     */
    public function nai($argument1)
    {
	$this->browser->visit($argument1);
    }

    /**
     * @Given /^検索ボックスに "([^"]*)" と入力します$/
     */
    public function meng($argument1)
    {
	$this->browser->fillIn("q", $argument1);
    }

    /**
     * @When /^検索ボタンを押します$/
     */
    public function mengV()
    {
	$this->browser->clickButton("Google 検索");
	$this->browser->render("/tmp/abc.png",array("width"=>1024,"height"=>100));
    }
}


今回は特にAssertなどはしておらず/tmp/abc.pngに検索結果の画面を保存しているだけです。
で、実際の出力がこんな感じ。

f:id:chobi_e:20120318215752p:plain

  • /tmp/abc.png

f:id:chobi_e:20120318215801p:plain

どう、おもしろそうでしょ?ヽ(´ー`)ノ

2012-02-29

Git2RepositoryBrowserBundleをふんわりリリースしました

こんばんは!ニート最後の日ということもありまして月曜日からつくり始めていた
Git2RepositoryBrowserBundleをGithub上に公開しました

Git2RepositoryBrowserBundle

f:id:chobi_e:20120229183058p:plain


php-git2とPECL Sundownを使ったWebベースのGitリポジトリブラウザで基本的なリポジトリブラウザの昨日+HTTP Smart Transportをサポートしています。勿論Vagrant+Chef-soloでSandboxが準備されているのでVagrantを普段利用している方ならば30分くらいでセットアップが出来るかと思います。

このBundleの狙い

もともとGithqというものをつくろうと思っていたのですが、正直Githubライクなものを一人で創り上げるのはかなり大変でして、自分の時間も限られていることからミニマムな機能だけ提供して自分は拡張開発のほうに専念しようかなー、という魂胆があります

求ム、Contributor

細かいHTMLの修正や、機能追加(ただしリポジトリブラウザの基本的な機能に限る)とかをやっていただける方を求めています。われこそはということはpull requestを!


https://github.com/chobie/Git2RepositoryBrowserBundle

https://github.com/chobie/Git2RepositoryBrowserBundleSandbox

2012-02-26

JSにコンパイルされたDartがPerlより速い件をPHPでやってみたら案外健闘していた件

表題のとおり

  • JSにコンパイルされたDartがPerlより速い件

http://d.hatena.ne.jp/gfx/20120226/1330260423

を試しにPHPでやってみた

  • SplFixedArray
<?php
$t0 = microtime(true);

$a = new SplFixedArray(1000000);
for ($i=0;$i<1000000;$i++) {
  $a[$i] = $i;
}

for ($i=0;$i<count($a);$i++) {
  $a[$i] = $a[$i]+1;
}

$sum = 0;
for ($i=0;$i<count($a);$i++) {
  $sum += $a[$i];
}

printf("%d\n",$sum);
printf("%6f\n",microtime(true)-$t0);
  • normal
<?php
$t0 = microtime(true);

$a = array();
for ($i=0;$i<1000000;$i++) {
  $a[] = $i;
}

for ($i=0;$i<count($a);$i++) {
  ++$a[$i];
}

$sum = 0;
for ($i=0;$i<count($a);$i++) {
  $sum += $a[$i];
}

printf("%d\n",$sum);
printf("%6f\n",microtime(true)-$t0);
# php5.4 SplFixedArray
500000500000
0.510691

# php5.4 (php -d memory_limit=256M benchmark.php)
500000500000
0.570727

# perl 5.12 (lion default)
500000500000
0.442306

# node v0.4.6
500000500000
0.058

# c (参考)
sum: 500000500000
0.011718


最初debug版でやって5秒ぐらいかかって涙目だったのはナイショ。

素のPHPのarrayでこのような演算をするとかなりメモリ使うのでこういうのは本当に向いていないよねぇ。因みにcount($a)を毎回forの判定条件で呼ばないようにするとだいたい倍ぐらい速くなります。

一応弁解しておくと、count自体の動作としては内部のカウントを見ているので高速なのですがPHPは関数のコールにどうしても時間がかかってしまうのでこのような感じになります。

#zend_hash.c
ZEND_API int zend_hash_num_elements(const HashTable *ht)
{
        IS_CONSISTENT(ht);

        return ht->nNumOfElements;
}


もう全部nodeで書けばいいんじゃないのというきがしている今日この頃

2012-02-26

hubotを使ってircのルームにしゃべらせてみる

最近fluent-phpの開発では#fluent-php@freenodeにてこまかいやりとりをするようにしました。
IRCなんて久しぶりにつかったので色々メモ。

irc proxy ZNC

perlの設定は面倒だったのでなるべくポータブルに動くものを探していたところzncというものに
出くわしました。インストールはaptitude install zncで簡単に。詳しくは下記参照で。

  • tiarraをやめてzncにしてみた

http://d.hatena.ne.jp/hideden/20110822/1314029426

ただ、なぜかうまく名前解決してくれない問題があったので直接IPアドレスを指定しときました。
c-aera関連でなにかおかしいのかしら。

webadminを有効にするとデフォルトではlistenしているポートで待機してくれます。
SSLを使っている場合はhttpsを使ってアクセスしなければいけません。
外部にport出していなければ非常に便利ですし、動的に設定を変更するのはwebadmin使え、
ということなので追加しておきましょう。

Hubot

http://d.hatena.ne.jp/anatoo/20120204/1328368042

今の時代botはHubotダヨネー、ということでHubotにも挑戦してみます。
基本的に@anatooの説明どおりインストールすればOK。
自分はHubotのためにnvmでnode.jsをセットアップしただけなのでcoffeeへのPATHが通ってなかったので

node_modules/.bin/coffee bin/hubot

で起動しましたとサ

HubotでIRCのルームにしゃべらせる

Hubotはデフォルトで8080でHttpもListenしているので、script/httpd.coffeeあたりに追記すれば自前の処理がかけるようです。
(もしくは別のところでもOK)。環境変数PORTを変更することでlistenするportを変えることができます。
それでは/hubot/say?message=hogeみたいなURLにアクセスされた場合に#fluent-phpに喋らすためにこんな感じで追記してみました。

package.jsonにqsのdependencyを追加

"qs":"0.4.2"

script/httpd.coffeeに追記

#先頭らへんに追加
url = require 'url'
qs = require 'qs'

~~~~~~~~~~~~~~~~~~~~~~

  robot.router.get "/hubot/say", (req, res) ->
    room = req.body.room
    parsedUrl = qs.parse(url.parse(req.url).query)
    message = parsedUrl.message
    user = robot.userForId "#fluent-php"
    user.room = room
    user.type = 'groupchat'
    robot.send user, "#{message}"
    res.writeHead 200, {'Content-Type': 'text/plain'}
    res.end 'OK'

チャットルームが固定、かつちょっと怪しいですがこれでHubotだけでIRCのチャットルームにも
喋らせることができるようになりました。もう少しちゃんと実装してgithubのhookからの通知に使ったりすることも簡単にできそうですねー。

githubのorganizationのリポジトリだとadmin的な権限を持っていないと細かいhook設定ができないので実際には使ってませんが、そのうちなんかしらで使いたいなーと思います。


いやはや、しかし自分の使わない言語で書くときはリファレンスなどの引き出しがまったくない状態で書くので難儀しますネ。誰かもっと素敵な感じで書いてくれないかなー(ちらっちらっ

2012-02-25

解説#61095 PHP can't add hex numbers

こんばんは!最近PHPのparserなどの処理まで終えるようになってきたのでこれはひどいと
噂のBug #61095についてみてみようと思います。

現象としては下記のようなコードを実行したときに一部の環境で意図しない計算結果が返ってくる、というものでした。

# chobie@macbook% php -r 'echo 0x00+2;'
4

0x00 + 2はどうやっても2なはずなんですが4が帰ってきています。おかしいですね。

それではr323394で修正された部分を見てみましょう

HNUM	"0x"[0-9a-fA-F]+

~~~~~~~

<ST_IN_SCRIPTING>{HNUM} {
	char *hex = yytext + 2; /* Skip "0x" */
	int len = yyleng - 2;
	0x00
	2

	/* Skip any leading 0s */
	while (*hex == '0') {
		hex++;
		len--;
	}

	if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= '7')) {
		zendlval->value.lval = strtol(hex, NULL, 16); # 問題があったコード
		zendlval->type = IS_LONG;
		return T_LNUMBER;
	} else {
		zendlval->value.dval = zend_hex_strtod(hex, NULL);
		zendlval->type = IS_DOUBLE;
		return T_DNUMBER;
	}
}

0x00が来た場合はまずはじめに先頭の0xをスキップして、その後に続く0を飛ばしていきます。この時点でhexのポインタが
期待していた0x00を過ぎてしまっていますね(´ー`)

SIZEOF_LONGはautoconfらへんのマクロで大体4ぐらいなのでこのif条件は最初のブロックが使われます。
strtol(hex, NULL, 16)は期待していた0x00の部分を過ぎて一部の環境ではうっかり2のほうまで行ってしまったので
0x00は16進の2と判断されて格納され結果的に0x00+2 => 0x2+2という計算になって4が帰ってきたのですね。


Cでの文字列処理でうっかり行き過ぎる、というのは他のOSSでもよく遭遇するので注意すべき所、でしょうか。

2012-02-22

Vagrantで作るSymfony2開発環境

みなさんこんにちは!ちょびえです。今日はVagrantで作るSymfony2の開発環境
について書いておこうかと思います。

Vagrant(ヴェイグラントゥッ)はVM開発環境を構築・配布するためのツールでOpscode Chef等と連携して簡単に開発環境の構築が行えるようになります。

最近私が開発するときは専らVagrantで開発環境用のcookbookを作ってから誰でも再現できるようにしています。と、いうのも実験的なPHP拡張などが含まれていると後々忘れたころに使おうと思って再構築するときにセットアップが面倒、とか既に頭の奥底からもキレイサッパリ忘れ去られているということが多々ありますし、ほかのContributorの方たちの環境構築の手間が省けるので敷居を下げるのにひじょーに良かったりします。

少し話は変わりますがTravis-CIの内部でもVagrantが使われており、いつでも再構築可能なVM環境というのはテストにも非常に役立つものです。因みにTravis-CIは今Donationを募集しているので普段よく使われている方は寄付してみてはどうでしょうか? https://love.travis-ci.org/
私は普段よく使っていることもありますし、今は円高なので$200寄付してみました(´ー`)

インストール方法

Vagrantを利用するためにはrubyVirtualBox、ProvisioningツールとしてChef-solo(他ももちろん使えますがChef-soloが便利)をインストールします。今回はMac OSX上での構築ということで少々解説したいとおもいます。

Oracls's VirtualBoxのインストール

https://www.virtualbox.org/wiki/Downloads

上記ページからOSX用のバイナリをダウンロードして普通どおりにインストールします。

vagrantのインストール

gem install vagrant

chef-soloのインストール

gem install chef-solo --no-rdoc --no-ri

rdoc,riの生成に時間がかかるのでみなさんオプションで外しているようです。

Symfony2環境のセットアップ

git clone https://github.com:chobie/Symfony2VagrantSandbox.git sandbox
cd sandbox
vagrant init
vagrant up

それ専用につくったわけではないんですが、ちょうどSymfony2で遊んでいたところなので流用。vagrant upをするとVMのダウンロードを行っていない場合はダウンロードから始まり、初回で役3~40分くらいでセットアップが終了します。
VMイメージがダウンロードされている場合は数分で開発環境が構築できるので便利!

このVMの設定では8081ポートがVMの80ポートと通信できるようになっているので、起動が終わったら段階でブラウザに http://localhost:8081/app_dev.php/demo/hello/chobien をたたけば同じみの表示画面になると思います。あとは煮るなり焼くなりお好きにどうぞ!

Chefのレシピはまだまだ勉強中なので今のところCentos向けのでしか動きませんが、とりあえず仲間内で開発するのには共通のVM,設定なので問題がないと思います。
そのうち時間があれば再利用可能なCookbookも書いてみたいですねー

よく使うtips

vagrant ssh
  • sshで接続するためのconfigを表示する
vagrant ssh-config
  • ホストマシン上のVagrantfileが置いてあるディレクトリの中身を参照する

vm上で

/vagrant

にアクセスすれば大体読み書きできます。自分はRake TaskにVMマシンにssh接続してファイルの転送をさせる、といったようなことを書いていたりします。

  • cookbookを追加する
cd cookbooks
knife cookbook create -o <CookBookName> .

cookbookを追加したら/recipes/default.rbにpackage "php"とか書いておけばDistributionにあったパッケージシステムを使ってインストールしてくれます。今回のCookbook集は練習がてらに書いてみたものなので、手始めに見てコピペして動かしてみて、覚えたら複雑なサンプルをみて繰り返す、というのが良いと思います。

そのほか

まだ1.0リリース前なのでちょくちょくVagrantfileの設定項目などがリファクタされていますが、それを差し引いても非常に便利なツールですし、トライしてみてはいかが?

参考リンク

http://www.ryuzee.com/contents/blog/4292

  • VagrantでローカルEC2 らくらく開発環境構築

http://www.slideshare.net/t9md/vagrant-intro