Author Archives: 1000k - Page 2

var_dump()の結果をファイルに出力する

このエントリーをはてなブックマークに追加
はてなブックマーク - var_dump()の結果をファイルに出力する
Share on Facebook

file_put_contents()とvar_export()を組み合わせれば、1行で実現できます。

コード

/**
 * 変数のvar_dump()結果をログファイルに出力する。
 *
 * @param mixed $var ダンプしたい変数
 * @param string $path ログファイルのパス
 * @return int ファイルに書き込まれたバイト数。失敗した場合falseを返す。
 */
public function varExportToLog($var, $path) {
    return file_put_contents($path, $var_export($var, true), FILE_APPEND);
}

参考

XPのプラクティス一覧とチェック方法

このエントリーをはてなブックマークに追加
はてなブックマーク - XPのプラクティス一覧とチェック方法
Share on Facebook

アート・オブ・アジャイル デベロップメントでは、数々のXPプラクティスを以下の5カテゴリに分類しています。

  • 考えること
  • 協力すること
  • リリースすること
  • 計画すること
  • 開発すること

また、アジャイル開発においては、1イテレーション内で以下のプロセスを同時に進行します。

  • 計画づくり
  • 分析
  • 設計とコーディング
  • テスティング
  • 導入

各プロセスでどのようなプラクティスを実行すればいいのかは、以下の表を見ればわかります。

Read more »

XPプロジェクトの進め方概要

このエントリーをはてなブックマークに追加
はてなブックマーク - XPプロジェクトの進め方概要
Share on Facebook

アート・オブ・アジャイル デベロップメントの中身を実践するにあたり、XPのチームの組み方と、イテレーション毎にやることをまとめました。

XPチーム

役割の説明

  • オンサイト顧客(または単に「顧客」)
    • プロダクトマネージャー(別名プロダクトオーナー): プロダクトビジョンの維持、推進
    • ドメイン専門家: システムの対象領域に関する専門知識を有する
    • インタラクションデザイナ: UIの定義、レビュー
    • ビジネスアナリスト: 顧客と開発者の連絡係
  • プログラマー(=すべての開発者)
  • テスター
  • コーチ
    • プログラマーコーチ: プログラマーの技術的なプラクティスを手助けする
    • プロジェクトマネージャー: プログラミングとは無関係のプラクティスをコーチする
  • プロジェクトコミュニティ
    • ステークホルダー: エンドユーザー、購入者、経営者、経営幹部など
    • エグゼクティブスポンサー: プロジェクトにお金を出す、究極の顧客
  • メンター: 困ったときアドバイスをくれる人(チームにいる)

構成

ロール名 人数 備考
オンサイト顧客、顧客 1-2 オンサイト顧客1 + プロダクトマネージャー1が理想
プログラマー 4-10 ペアプロのため、偶数が望ましい
テスター 0- いない場合、顧客かPGで代用
プログラマコーチ 0-
プロジェクトマネージャー 0- 顧客が兼務することがある
メンター 0-
ステークホルダー 0-
エグゼクティブスポンサー 0-
  • プログラマー3名につき顧客2名が望ましい
  • プログラマー4名に付きテスター1名が良い
  • 最小のチームは5名
    • プログラマー4名(うち1名はコーチ)+顧客(プロダクトマネージャー)1名
    • 熟練プログラマー1 + プロダクトマネージャー1 のチームも可能だが、全面的にXPを採用するには無理がある
  • 最大でプログラマー10名、顧客6名、テスター3名、プロジェクトマネージャー1名(合計20名)
    • これ以上大きなXPチームは特別なプラクティスが必要
  • 掛け持ちアサイン(複数のプロジェクトに同時にアサイン)は効率を大幅に落とすので厳禁

Read more »

Phingが動作しない場合の対処

このエントリーをはてなブックマークに追加
はてなブックマーク - Phingが動作しない場合の対処
Share on Facebook

XAMPP 1.7.4でPhingを使おうとしましたが、エラーが出て使えませんでした。 結果として、Phingの再インストールで治りました。

以下に経緯を残しておきます。

環境

  • Windows XP SP3
  • XAMPP 1.7.4
  • PHP 5.3.5
  • Phing 2.3.3 (恐らくXAMPPにデフォルトで入っていたもの)

症状

下記のように、ただ”uhouho”とechoするだけの簡単なビルドファイルを実行しようとして、エラーが出ました。

<!-- C:\temp\build.xml -->
<?xml version="1.0" encoding="UTF-8"?>

<project name="FooBar" default="dist">
  <target name="dist">
    <echo msg="uhouho"></echo>
  </target>
</project>

実行結果

$ phing -f C:\temp\build.xml
Buildfile: C:\temp\build.xml

BUILD FAILED
Can't load default task list
Total time: 0.0030 seconds

また、バージョン表示でもエラーが出ました。

$ phing -v
No VERSION.TXT file found; try setting phing.home environment variable.

対処方法

Setting up your workstation for extension development – Joomla! Documentation > No VERSION.TXT Error を参考に、Phingを再インストールしました。

# アンインストール
$ pear uninstall phing/phing
uninstall ok: channel://pear.phing.info/phing-2.3.3

# チャンネルの設定
$ pear channel-discover pear.phing.info
Channel "pear.phing.info" is already initialized

# インストール
$ pear install phing/phing
WARNING: "pear/PEAR_PackageFileManager" is deprecated in favor of "pear/PEAR_PackageFileManager2"
Did not download optional dependencies: phing/phingdocs, pear/VersionControl_Git, phpunit/PHPUnit, pecl/Xdebug, pear/Services_Amazon_S3, pear/HTTP_Request2, channel://pear.pdepend.org/PHP_Depend, channel://pear.phpmd.org/PHP_PMD, phpunit/phpcpd, channel://pear.docblox-project.org/DocBlox, pear/PHP_CodeSniffer, use --alldeps to download automatically
phing/phing requires PEAR Installer (version >= 1.8.0), installed version is 1.7.2
phing/phing can optionally use package "phing/phingdocs" (version >= 2.4.7.1)
phing/phing requires package "pear/VersionControl_SVN" (version >= 0.3.4), installed version is 0.3.1
phing/phing can optionally use package "pear/VersionControl_Git" (version >= 0.4.3)
phing/phing can optionally use package "phpunit/PHPUnit" (version >= 3.4.0)
phing/phing can optionally use package "pecl/Xdebug" (version >= 2.0.5)
phing/phing can optionally use package "pear/Services_Amazon_S3" (version >= 0.3.1)
phing/phing can optionally use package "pear/HTTP_Request2" (version >= 0.5.2)
phing/phing can optionally use package "channel://pear.pdepend.org/PHP_Depend" (version >= 0.10.0)
phing/phing can optionally use package "channel://pear.phpmd.org/PHP_PMD" (version >= 1.1.0)
phing/phing can optionally use package "phpunit/phpcpd" (version >= 1.3.2)
phing/phing can optionally use package "channel://pear.docblox-project.org/DocBlox" (version >= 0.11.0)
phing/phing can optionally use package "pear/PHP_CodeSniffer" (version >= 1.3.0)
No valid packages found
install failed

# ↑では依存性のエラーでインストールできなかったので、--alldepsオプションを付けてやり直す
$ pear install --alldeps phing/phing
Failed to download pear/VersionControl_SVN within preferred state "stable", latest release is version 0.3.4, stability "alpha", use "channel://pear.php.net/VersionControl_SVN-0.3.4" to install
Failed to download pear/VersionControl_Git within preferred state "stable", latest release is version 0.4.4, stability "alpha", use "channel://pear.php.net/VersionControl_Git-0.4.4" to install
WARNING: "pear/PEAR_PackageFileManager" is deprecated in favor of "pear/PEAR_PackageFileManager2"
Failed to download pear/Services_Amazon_S3 within preferred state "stable", latest release is version 0.3.5, stability "alpha", use "channel://pear.php.net/Services_Amazon_S3-0.3.5" to install
Failed to download pear/HTTP_Request2 within preferred state "stable", latest release is version 2.0.0RC2, stability "beta", use "channel://pear.php.net/HTTP_Request2-2.0.0RC2" to install
phing/phing requires PEAR Installer (version >= 1.8.0), installed version is 1.7.2
phing/phing requires package "pear/VersionControl_SVN" (version >= 0.3.4), installed version is 0.3.1
phing/phing can optionally use package "pear/VersionControl_Git" (version >= 0.4.3)
phing/phing can optionally use package "pear/Services_Amazon_S3" (version >= 0.3.1)
phing/phing can optionally use package "pear/HTTP_Request2" (version >= 0.5.2)
phing/phing can optionally use package "channel://pear.pdepend.org/PHP_Depend" (version >= 0.10.0)
phing/phing can optionally use package "channel://pear.phpmd.org/PHP_PMD" (version >= 1.1.0)
phing/phing can optionally use package "channel://pear.docblox-project.org/DocBlox" (version >= 0.11.0)
phing/phingdocs requires PEAR Installer (version >= 1.8.0), installed version is 1.7.2
phpunit/PHPUnit requires PEAR Installer (version >= 1.9.3), installed version is 1.7.2
phpunit/PHPUnit requires package "channel://pear.symfony-project.com/YAML" (version >= 1.0.2)
phpunit/PHPUnit can optionally use PHP extension "curl"
phpunit/PHPUnit can optionally use PHP extension "dbus"
phpunit/phpcpd requires PEAR Installer (version >= 1.9.0), installed version is 1.7.2
phpunit/phpcpd requires package "channel://components.ez.no/ConsoleTools" (version >= 1.6)
phpunit/DbUnit requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/DbUnit requires package "channel://pear.symfony-project.com/YAML" (version >= 1.0.2)
phpunit/File_Iterator requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/Text_Template requires PEAR Installer (version >= 1.8.1), installed version is 1.7.2
phpunit/PHP_CodeCoverage requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/PHP_CodeCoverage requires package "channel://components.ez.no/ConsoleTools" (version >= 1.6)
phpunit/PHP_CodeCoverage requires package "phpunit/File_Iterator" (version >= 1.2.2)
phpunit/PHP_CodeCoverage requires package "phpunit/Text_Template" (version >= 1.0.0)
phpunit/PHP_Timer requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/PHPUnit_MockObject requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/PHPUnit_MockObject requires package "phpunit/Text_Template" (version >= 1.0.0)
phpunit/PHPUnit_Selenium requires PEAR Installer (version >= 1.9.2), installed version is 1.7.2
phpunit/PHP_TokenStream requires PEAR Installer (version >= 1.9.1), installed version is 1.7.2
phpunit/PHP_TokenStream requires package "channel://components.ez.no/ConsoleTools" (version >= 1.6)
downloading xdebug-2.1.2.tgz ...
Starting to download xdebug-2.1.2.tgz (304,229 bytes)
..............................................................done: 304,229 bytes
downloading PHP_CodeSniffer-1.3.0.tgz ...
Starting to download PHP_CodeSniffer-1.3.0.tgz (327,201 bytes)
...done: 327,201 bytes
66 source files, building
ERROR: The DSP xdebug.dsp does not exist.
ERROR: unable to unpack C:\DOCUME~1\SCI01310\LOCALS~1\Temp\pear\download\PHP_CodeSniffer-1.3.0.tgz

# またよくわからないエラーで失敗。
# Googleで検索しても「XAMPPのせい」と一蹴されていたので、依存性を無視してインストールする。
$ pear install -n phing/phing
warning: phing/phing requires package "pear/VersionControl_SVN" (version >= 0.3.4), installed version is 0.3.1
phing/phing can optionally use package "pear/VersionControl_Git" (version >= 0.4.3)
phing/phing can optionally use package "phpunit/PHPUnit" (version >= 3.4.0)
phing/phing can optionally use package "pecl/Xdebug" (version >= 2.0.5)
phing/phing can optionally use package "pear/Services_Amazon_S3" (version >= 0.3.1)
phing/phing can optionally use package "pear/HTTP_Request2" (version >= 0.5.2)
phing/phing can optionally use package "phpunit/phpcpd" (version >= 1.3.2)
phing/phing can optionally use package "docblox/DocBlox" (version >= 0.11.0)
downloading phing-2.4.7.1.tgz ...
Starting to download phing-2.4.7.1.tgz (421,828 bytes)
.....................................................................................done: 421,828 bytes
install ok: channel://pear.phing.info/phing-2.4.7.1

ようやくインストールできました。

動作確認

バージョンが表示できるか確認します。

$ phing -v
Phing 2.4.7.1

バージョン表示はOK。 ビルドはどうでしょうか?

$ phing -f C:\temp\build.xml
** ERROR *****************************************************************
* Sorry, can't find the php.exe file.
* You must edit this file (C:\xampp\php\phing.bat) to point to your php.exe (CLI)
*    [Currently set to .\php.exe]
**************************************************************************

Phingの再インストールで php.exe が見つけられなくなってしまったようです。 c:\xampp\php\phing.bat を編集し、「SET phpCli」の行を以下のように編集します。

SET phpCli=C:\xampp\php\phing.bat

これでリトライ。

$ phing -f C:\temp\build.xml
Buildfile: C:\temp\build.xml

FooBar > dist:

     [echo] uhouho

BUILD FINISHED

Total time: 0.5076 seconds

無事動きました。

参考

XAMPP環境にJenkinsをインストールする方法

このエントリーをはてなブックマークに追加
はてなブックマーク - XAMPP環境にJenkinsをインストールする方法
Share on Facebook

アジャイル開発のスキルを少しずつ磨いています。そろそろ継続的インテグレーションを試してみようと思い、XAMPP環境にJenkinsをインストールしてみました。

環境

  • Windows XP SP3
  • XAMPP 1.7.4

導入手順

本当に、setup.exeを動かすだけで済みました。

Welcome to Jenkins CI! | Jenkins CIからWindows版のパッケージをダウンロード。 執筆時点(2011/10/06時点)では jenkins-1.433.zip。

ダウンロード後、解凍してsetup.exeを実行してインストール。 インストール先はデフォルトの “C:\Program Files\Jenkins” とします。

インストール完了後、勝手にブラウザが立ち上がって http://localhost:8080 にアクセスしますが、Jenkinsのロードが完了するまではエラーが出るようです。 時間をおいてリロードすれば、トップ画面が表示されるはずです。

軽くはまったこと

Windowsインストーラーは頻繁にアップデートされているようで、半年前のインストール方法より簡単になっているようです。 最初、古いインストール記事を見ながらApacheとjenkins.xmlの設定をやったら起動せず、途方に暮れました。

参考

vmstatの値をロギングする

このエントリーをはてなブックマークに追加
はてなブックマーク - vmstatの値をロギングする
Share on Facebook

vmstatの値をファイルに出力したいとき、次のコマンドが使えます。

nohup vmstat -n -S M 1 | awk '{ print strftime("%Y/%m/%d %H:%M:%S"), $0 } { system(":") }' >> /path/to/log &

出力は下記のようになります。

2011/09/28 15:51:07 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------
2011/09/28 15:51:07  r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
2011/09/28 15:51:07  1  0      0    251    153    358    0    0     0     9    1    0  0  0 99  0  0
2011/09/28 15:51:08  0  0      0    251    153    358    0    0     0     0 1012   40  0  1 99  0  0
2011/09/28 15:51:09  0  0      0    251    153    358    0    0     0     0 1004   37  0  0 100  0  0

このプロセスを終了したい場合は、下記のようにkillしてやればOKです。

$ pgrep vmstat      # vmstatのprocess idを取得する
29248

$ kill {上で出てきたpid}

参考

デコード/エンコードを1ファイルで行うPHP

このエントリーをはてなブックマークに追加
はてなブックマーク - デコード/エンコードを1ファイルで行うPHP
Share on Facebook

URLエンコード/デコード、HTMLエンティティエンコード/デコードを行うとき便利なフォームを作成しました。 PHP+jQueryで実装されており、このファイルをPHPの動くWebサーバーに置けばすぐに使えます。

できること

  • URLエンコード/デコード
  • HTMLエンティティエンコード/デコード
  • PHPの配列のシリアライズ/アンシリアライズ

必要な環境

  • PHPの動作するWebサーバー

Read more »

svnでdiffの行数を取得する

このエントリーをはてなブックマークに追加
はてなブックマーク - svnでdiffの行数を取得する
Share on Facebook

どれだけコーディングしたかチェックするため、svnのdiffの行数を取得するコマンドを考えました。 下のコマンドを叩くと、変更された行の総数が表示されます。

(2011-08-17修正) 以前のコードはdiffのヘッダ行まで取得してしまっていたので、正しい数値が得られるよう修正しました。

svn diff -r {before}[:{after}] -x -b {path} | grep -E '^[+\-][[:blank:]]' | wc -l

例えば「チェンジセット301~310で uso.php に発生した差分の総行数」は、下のようになります。

# svn diff -r 301:310 -x -b ./uso.php | grep -E '^[+\-][[:blank:]]' | wc -l
500

ロジックは、

  1. 空白文字の差分(インデントや空行の削除)を無視してdiffを取る
  2. 差分行だけ(「+ 」「- 」どちらかから始まっている行)を取得する
  3. 行数をカウントする

となっています。

参考

fixtureがテスト用データベースに反映されない?

このエントリーをはてなブックマークに追加
はてなブックマーク - fixtureがテスト用データベースに反映されない?
Share on Facebook

CakePHPでフィクスチャを作成したけど、テスト実行時にフィクスチャではなくDBのデータをロードしてしまう。ちゃんとテストケース内で $fixtures に設定しているはずなのに。

そんな症状に長らく悩んでいましたが、結論から言うと、$fixturesで指定しているフィクスチャ名を書き間違えていたせいでした。ファイル名を間違えている時、テストケースはエラーを吐かず、DBを読みに行ってしまうようです。

ずいぶん悩みましたが、初歩的なミスでした。

確かめた記事

Mark Story「1.2のNightlyリビジョンで直ってるよ」

→解決してない

「フィクスチャがDBに入らないんだけど」

「テスト動かせば自動で入るよ」

「知ってるよ。そのはずなのに入らないから聞いてるんだ」

返事無し

fixtureをディレクトリに分けて管理する

このエントリーをはてなブックマークに追加
はてなブックマーク - fixtureをディレクトリに分けて管理する
Share on Facebook

(2011/07/15 Update) 7/13以前のコードに誤りがあり、正しく動作しなかったので修正しました。

やりたいこと

CakePHPの規則に従うと、フィクスチャは /app/test/fixtures/ ディレクトリにすべて入れなければなりません。この場合、「同じモデルを使うけど、テストケース毎に異なるフィクスチャを代入したい」という要望をかなえるのが難しいです。

例えば、

  • Hige コントローラー
  • Moja コントローラー

どちらも同じ Uso モデルを使う場合を考えます。それぞれで違うフィクスチャを使いたくても、Uso モデルのフィクスチャは uso_fixture.php の1個です。フィクスチャの値を両方のテストケースで使えるようにするのは難しく、まして複数人でテスト設計するのは困難です。

そこで、それぞれのコントローラーから呼び出すフィクスチャを

  • /app/test/fixtures/hige/uso_fixture.php
  • /app/test/fixtures/moja/uso_fixture.php

と使い分けられるようにする方法を考えました。

やり方

CakeTestCase を拡張した MyCakeTestCase を作成し、その中で _loadFixtures をオーバーライドします。 なお、参考にしたバージョンは CakePHP 1.3.10 です。

/app/libs/my_cake_test_case.php

<?php
/**
 * Extension of CakeTestCase Class
 *
 * @author  $Author: senge.keiyo $
 * @version $id$
 */
class MyCakeTestCase extends CakeTestCase {

    /**
     * Load fixtures specified in var $fixtures.
     *
     * fixtureディレクトリ配下の任意のディレクトリにフィクスチャを配置できるよう拡張。
     *
     * 例えば $fixtures に 'app.unit_test.uso' と指定すると、
     * /app/tests/fixtures/unit_test/uso_fixture.php をロードできる。
     *
     * @author senda.keijiro
     * @return void
     * @access protected
     */
    function _loadFixtures() {
        if (!isset($this->fixtures) || empty($this->fixtures)) {
            return;
        }

        if (!is_array($this->fixtures)) {
            $this->fixtures = array_map('trim', explode(',', $this->fixtures));
        }

        $this->_fixtures = array();

        foreach ($this->fixtures as $index => $fixture) {
            $fixtureFile = null;
            $fixturePaths = null;

            if (strpos($fixture, 'core.') === 0) {
                $fixture = substr($fixture, strlen('core.'));
                foreach (App::core('cake') as $key => $path) {
                    $fixturePaths[] = $path . 'tests' . DS . 'fixtures';
                }
            } elseif (strpos($fixture, 'app.') === 0) {
                // MODIFIED
                // app.unittest.plan が来たら /fixtures/unittest/plan_fixtures.php
                // をロードするようにする
                $parts = explode('.', $fixture);
                $fixture = $parts[count($parts) - 1];

                array_shift($parts);
                array_pop($parts);
                $path = implode(DS, $parts);

                $fixturePaths = array(
                    TESTS . 'fixtures' . DS . $path,
                    TESTS . 'fixtures',
                    VENDORS . 'tests' . DS . 'fixtures'
                );
            } elseif (strpos($fixture, 'plugin.') === 0) {
                $parts = explode('.', $fixture, 3);
                $pluginName = $parts[1];
                $fixture = $parts[2];
                $fixturePaths = array(
                    App::pluginPath($pluginName) . 'tests' . DS . 'fixtures',
                    TESTS . 'fixtures',
                    VENDORS . 'tests' . DS . 'fixtures'
                );
            } else {
                $fixturePaths = array(
                    TESTS . 'fixtures',
                    VENDORS . 'tests' . DS . 'fixtures',
                    TEST_CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'tests' . DS . 'fixtures'
                );
            }

            foreach ($fixturePaths as $path) {
                if (is_readable($path . DS . $fixture . '_fixture.php')) {
                    $fixtureFile = $path . DS . $fixture . '_fixture.php';
                    break;
                }
            }

            if (isset($fixtureFile)) {
                require_once($fixtureFile);
                $fixtureClass = Inflector::camelize($fixture) . 'Fixture';
                $this->_fixtures[$this->fixtures[$index]] =& new $fixtureClass($this->db);
                $this->_fixtureClassMap[Inflector::camelize($fixture)] = $this->fixtures[$index];
            }
        }

        if (empty($this->_fixtures)) {
            unset($this->_fixtures);
        }
    }
}
あとはテストケースでこのクラスを呼び出してやればOKです。 **/app/tests/cases/controllers/higes_controller.test.php**
<?php
App::import('Model', 'Uso');
App::import('Lib', 'MyCakeTestCase');

class HigesControllerTestCase extends MyCakeTestCase {
    var $fixtures = array(
        'app.hige.uso'      // /app/test/fixtures/hige/uso_fixture.php がロードされる
    );
?>

副作用

テストケースで「App::import(‘Lib’, ‘MyCakeTestCase’);」すると、なぜかMyCakeTestCaseもテスト対象になるらしく、テスト結果の「n/n test cases complete」の値が1増えます。 テスト結果のGreen/Redには影響しないので、無視してください。

参考