gitignoreまとめ

Gitで無視ファイルを細かく設定する際にはまったので、メモ

ヘルプ

こまったら、これで

$ man gitignore

web版

前提

まずは前提を抑えておかないと、はまる

既にトラックされたファイルはgitignoreが効かない
$ git init
$ touch hoge.txt
$ git add hoge.txt # トラックされた後に
$ vim .gitignore # 無視設定しても 
hoge.txt
$ git status # 効かない

既にトラックされたファイルを無視対象にしたければ、git rm --cached

$ git rm --cached hoge.txt # 上記のトラックされたファイルをインデックスから削除すれば(ワークツリーはそのまま)
$ git status #gitignoreが効く

# もしhoge.txtをcommit済みの場合
$ git commit -m 'delete hoge.txt' # コミットしてリポジトリからも消す
空のディレクトリは管理されない
$ git init
$ mkdir aaa # 空のディレクトリを作成
$ git add . 
$ git status # git管理下にならない

Git管理下にしたければ空ファイルを置けばよい。名前は何でもよいが.gitkeepとするのが慣習

$ touch aaa/.gitkeep # 空のディレクトリに.gitkeepという名前の空ファイルを作成
$ git add . 
$ git status # git管理下になる

.gitignore vs .gitkeep
http://stackoverflow.com/questions/7229885/gitignore-vs-gitkeep

優先順位

gitignoreは以下4つの方法で設定できて、それぞれ優先順位がある

↑優先度「高」

(1) コマンドラインからの指定

・git ls-filesなどのコマンドがコマンドラインから無視パターンを指定できる。

<例 >
untrackedなファイルから*.txtにマッチするファイルを除いて表示

$ git ls-files -o --exclude-standard -x '*.txt'
(2) .gitignoreファイル

・プロジェクトのメンバー全員で共通して無視したいパターンに使う。
・通常、バージョンコントロール内に入れてプロジェクトメンバー間でシェアする。
複数の.gitignoreファイルがある場合、階層が深い方が優先される

<例>
.gitignore

*.txt

100/.gitignore

!*.txt

結果

.
├── .gitignore
├── 100/
│   ├── .gitignore
│   └── hoge.txt # 無視しない(100/.gitignoreが適用)
├── 200/
│   └── hoge.txt # 無視する
└── hoge.txt # 無視する
(3) $GIT_DIR/info/excludeファイル

・自分だけの設定。自分がこのプロジェクトにおいてだけ無視したいパターンに使う。
・例えば、自分だけがこのプロジェクトで使っているデバッグ用の俺俺スクリプトなどに。
・$GIT_DIRは、特に設定していなければワークツリーのトップにある.gitディレクトリを指す

<例>

# このプロジェクトに特有な自分だけのスクリプトmy_script.rbをバージョン管理外に
$ vim .git/info/exclude
# git ls-files --others --exclude-from=.git/info/exclude                                                                                                                          
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
my_script.rb
(4) core.excludesfile(設定用変数)で指定されたファイル

・自分だけの設定。自分がどのようなプロジェクトであっても常に無視したいパターンに使う。
・例えば、vimの.swpやmacの.DS_Storeなど

<例>

# git configコマンドで設定(ファイル名は.gitignoreでなくてもよい)
$ git config --global core.excludesfile ~/.gitignore

# すると~/.gitconfigに以下のような記載が追加される
[core]
  excludesfile = /Users/hidenorimaehara/.gitignore

# 対象ファイルに無視パターンを設定
$ vim ~/.gitignore
.DS_Store

↓優先度「低」

無視パターンの書き方

無視パターンの書き方は以下。適用される階層に注意

どこにも/なし

・shell glob pattern(※1)として扱う
・.gitignoreファイルにおいては、その.gitignoreファイルを基準とした相対パスでパターン解析
・つまり、同階層以下全てに適用される(上位階層には適用されない)。
・.gitignoreファイル以外(※2)では、ワークツリーのトップレベル(※3)を基準とした相対パスでパターン解析

<例>
100/.gitignore

*.txt

結果

.
├── 100/
│   ├── .gitignore
│   ├── 110/
│   │   └── hoge.txt #無視する
│   └── hoge.txt #無視する
└── hoge.txt #無視しない(100/.gitignoreの上位階層のため)

※1 http://hgbook.red-bean.com/read/file-names-and-pattern-matching.html#id381291
※2 $GIT_DIR/info/excludeファイルなど
※3 git rev-parse --show-toplevelで確認できる

末尾に/

ディレクトリだけに適用される(ファイルには適用されない)

<例>
100/.gitignore

[0-9][0-9][0-9]/

結果

├── 100/
│   ├── .gitignore
│   ├── 110/ #無視する
│   │   └── hoge.txt
│   ├── 120 #無視しない(120はファイルであり、ディレクトリでないため)
│   └── hoge.txt
└── hoge.txt
先頭に/

・その.gitignoreファイルと同階層にだけ適用される
・「/」はその.gitignoreファイルを基点としたパスのことであり、ファイルシステムのルートではない

<例>
100/.gitignore

/hoge.txt

結果

├── 100/
│   ├── .gitignore
│   ├── 110/
│   │   └── hoge.txt #無視しない(100/.gitignoreの直下ではないため)
│   └── hoge.txt #無視する
└── hoge.txt #無視しない
途中に/

ワイルドカード(*など)が「/」にマッチしないshell glob patternとして解析する
・これは例を見た方がはやい

<例>
100/.gitignore

*/hoge.txt 

結果

├── 100/
│   ├── .gitignore
│   ├── 110/
│   │   ├── 111/
│   │   │   └── hoge.txt #無視しない(100/.gitignoreを基準とした*/hoge.txtに合致しないため)
│   │   └── hoge.txt #無視する
│   └── hoge.txt #無視しない(100/.gitignoreを基準とした*/hoge.txtに合致しないため)
└── hoge.txt #無視しない
!

・逆の意味になる(無視しない)
・これを用いることで、ホワイトリスト方式が実現できる

<例>
.gitignore

# まず直下のファイルとディレクトリを全て無視する                                                                                                                                 
/*

# ただし、以下は無視しない
!/.gitignore
!/100

結果

├── .gitignore #無視しない
├── 100/ #無視しない
│   └── hoge.txt
├── 200/ #無視する
│   └── hoge.txt
├── fuge.txt #無視する
└── hoge.txt #無視する

終わり

Githubには各フレームワークや環境におけるデフォルトのgitignoreが集まっており便利
https://github.com/github/gitignore

PHPを愛する試み 〜self:: parent:: static:: および遅延静的束縛〜

PHPを愛する試みというものを個人的にやっている

PHPを愛する試み
PHPを愛する試み 〜調教編〜

今回は、self:: parent:: static:: 遅延静的束縛について図で整理してみた。

スコープ定義演算子 (::)

まず「::」について。これはスコープ定義演算子という。マニュアルには以下のようにある。

スコープ定義演算子 (::)

スコープ定義演算子 (またの名を Paamayim Nekudotayim)、 平たく言うと「ダブルコロン」は、トークンのひとつです。 static, 定数 およびオーバーライドされたクラスのプロパティやメソッドにアクセスすることができます。これらの要素をクラス定義の外から参照する際には、 クラスの名前を使用してください。PHP 5.3.0 以降では、変数を用いてクラスを参照することも可能です。 変数の値に (self や parent、 static といった) キーワードを指定することはできません。
...
http://www.php.net/manual/ja/language.oop5.paamayim-nekudotayim.php

分かりづらいので、自分流に解釈する。例えば、以下の図ように沢山のfoo()があるとして、どのfoo()なのかを決定するための演算子が::である。「::の右側にあるメソッドやプロパティが、::の左側のスコープに属すると決定する演算子」と考えればしっくりくる。

self::やparent::というのは、このスコープを表す方法の1つ。全部で以下の4つがある。

方法 スコープ 使える場所
クラス名:: 明示したクラス クラス定義の外or中
self:: self::が記載されたクラス クラス定義の中
parent:: parent::が記載されたクラスの親クラス クラス定義の中
static:: 直近の "非転送コール" のクラス クラス定義の中

1つずつみていく

クラス名::

クラス名::とすると、スコープは「明示したクラス」となる。
クラス定義の外でも中でも使える。

<?php
class C
{
  public static function foo() {
    D::foo(); //foo()のスコープはD
  }
}

class D
{
  public static function foo() {
    echo 'D_foo' . PHP_EOL;
  }
}

C::foo(); //foo()のスコープはC。結果:D_foo 


self::

self::とすると、スコープは「self::が記載されたクラス」となる。
クラス定義の中でしか使えない。

<?php

class C
{
  public static function foo () {
    self::bar(); //bar()のスコープはself::が記載されたクラス(C)
  }
                                                                                                                                  
  public static function bar () {
    echo 'C_foo' . PHP_EOL;
  }
}

class CC extends C
{
  public static function bar () {
    echo 'CC_foo' . PHP_EOL;
  }
}

C::foo(); //C_foo
CC::foo(); //C_foo


parent::

parent::とすると、スコープは「parent::が記載されたクラスの親クラス」となる。
クラス定義の中でしか使えない。

<?php                                                                                                                             

class C
{
  public static function bar () {
    echo 'C_bar' . PHP_EOL;
  }
}

class CC extends C
{
  public static function foo () {
    parent::bar(); //bar()のスコープはparent::が記載されたクラス(CC)の親クラス(C)
  }

  public static function bar () {
    echo 'CC_bar' . PHP_EOL;
  }  
}

CC::foo(); //C_bar


static::

これが本題。static::とすると、スコープは「直近の "非転送コール" のクラス」となる。
クラス定義の中でしか使えない。

ややこしいのが「直近の "非転送コール" のクラス」というもの。マニュアルにはこう書いてある。

遅延静的束縛 (Late Static Bindings)
...
より正確に言うと、遅延静的束縛は直近の "非転送コール" のクラス名を保存します。 静的メソッドの場合、これは明示的に指定されたクラス (通常は :: 演算子の左側に書かれたもの) となります。静的メソッド以外の場合は、そのオブジェクトのクラスとなります。 "転送コール" とは、self:: や parent::、static:: による静的なコール、 あるいはクラス階層の中での forward_static_call() によるコールのことです。 get_called_class() 関数を使うとコール元のクラス名を文字列で取得できます。 static:: はこのクラスのスコープとなります。
...
http://php.net/manual/ja/language.oop5.late-static-bindings.php

整理すると、

非転送コール: C::foo()や$c->foo()といったクラス名(もしくはオブジェクト)を明示した呼び出し
転送コール: self:: parent:: static::もしくはクラス階層の中での forward_static_call() での呼び出し
遅延静的束縛 非転送コール時に、明示されたクラス名(もしくはオブジェクトのクラス名)を保持する機能

となる。
これらをふまえて、static::を使ったコードを書いてみる

<?php
class C
{
  public static function foo() {
    static::bar(); // bar()のスコープは直近の "非転送コール" のクラス(C::foo()ならC。CC::foo()ならCC)
  }

  public static function bar() {
    echo 'C_bar' . PHP_EOL;
  }
}

class CC extends C
{
  public static function bar() {
    echo 'CC_bar' . PHP_EOL;
  }
}

C::foo(); //C_bar
CC::foo(); //CC_bar       

C::foo()と呼び出した時とCC::foo()で呼び出した時の動きが変わった!
絵にすると以下のようになる


「直近の非転送コール」とは? 〜例1〜

「直近の非転送コール」が何を表すのか、もう少し詳しくみてみる。
例えば、以下のように途中で転送コール(self::など)をはさんだ場合はどうなるか

<?php
class C
{
  public static function foo() {
    self::hoge(); //self::は転送コール
  }

  public static function hoge() {
    static::bar(); // bar()のスコープは直近の "非転送コール" のクラス(この場合CC)
  }

  public static function bar() {
    echo 'C_bar' . PHP_EOL;
  }
}

class CC extends C
{
  public static function bar() {
    echo 'CC_bar' . PHP_EOL;
  }
}

CC::foo(); //CC_bar  

転送コールは無視して直近の非転送コールまで遡っていることがわかる
絵にするとこうなる


「直近の非転送コール」とは? 〜例2〜

非転送コールが複数存在する場合はどうか

<?php
class C
{
  public static function foo() {
    C::hoge(); //非転送コール
  }

  public static function hoge() {
    static::bar(); // bar()のスコープは直近の "非転送コール" のクラス(この場合、C)
  }

  public static function bar() {                                                                                                                                                                            
    echo 'C_bar' . PHP_EOL;
  }
}

class CC extends C
{
  public static function bar() {
    echo 'CC_bar' . PHP_EOL;
  }
}

CC::foo(); //C_bar

非転送コールが複数存在する場合は、直近の非転送コールに解決されている
絵にするとこうなる

いずれにおいてもstatic::からコールスタックを遡って、一番近い非転送コール(転送コールは除く)で明示されたクラスに解決されていることがわかる。

静的メソッドの呼び出しではない場合

これまで静的メソッドの呼び出しを例としてきたが、さきほど引用したマニュアルにあるように、「静的メソッド以外の場合は、そのオブジェクトのクラス」となる

<?php                                                                                                                        
class C
{
  public function foo() {
    static::bar();
  }

  public static function bar() {
    echo 'C_bar' . PHP_EOL;
  }
}

class CC extends C
{
  public static function bar() {
    echo 'CC_bar' . PHP_EOL;
  }
}

$cc = new CC();
$cc->foo(); //CC_bar

静的メソッドでなくても直近の非転送コールまで遡って行く仕組みは同じだ。
これを絵にするとこうなる

注意:「メソッド・プロパティ定義のstatic」「静的変数static」とは違う

static::について混乱するのは、staticが遅延静的束縛以外の意味でも使われるからだ。マニュアルには以下のように書いてある

static キーワード

このページでは、static キーワードを使って静的なメソッドやプロパティを定義する方法を説明します。 static は、 静的な変数の定義 や 静的遅延束縛 にも使えます。これらの場合の static の使い方は、 それぞれのページを参照ください。
http://php.net/manual/ja/language.oop5.static.php

つまり、staticはこれまで見てきたように遅延静的束縛以外に、以下2つの意味で使われる。

・静的なメソッド・プロパティを定義するためのstatic

<?php
class C
{
  public static $v = 'hoge';                                                                                                 

  public static function foo() {
    echo 'foo' . PHP_EOL;
  }
}

var_dump(C::$v); //hoge
C::foo(); //foo

・ 静的変数のstatic

<?php
class C
{
  public function countup() {
    static $count; //静的変数
    $count++;
    var_dump($count); 
  }
}

$c = new C();
$c->countup(); //1
$c->countup(); //2
$c->countup(); //3 

同じキーワードが色々な意味で使われるところがややこしい。。。

以上

長かったがstaticについては大分整理できた。

余談

self::は__CLASS__。static::はget_called_class()で参照できる
<?php
class C
{
  public static function foo() {
    var_dump(__CLASS__); //常にC
    self::bar(); //常にC::foo()

    var_dump(get_called_class()); //CかCC
    static::bar(); //C::foo()かCC::foo()
  }

  public static function bar() {
    echo 'C_bar' . PHP_EOL;                                                                                                  
  }
}

class CC extends C
{
  public static function bar() {
    echo 'CC_bar' . PHP_EOL;
  }
}

C::foo();
CC::foo();
new self() new parent() new static()

self, parent, staticキーワードはオブジェクト生成にも使える。

<?php
class C
{
  public static function foo() {
    var_dump(new self());
  }

  public static function hoge() {
    var_dump(new static());
  }
}

class CC extends C
{
  public static function bar() {
    var_dump(new parent());
  }
}

C::foo(); //object(C)
CC::bar(); //object(C)                                                                                                            
C::hoge(); //object(C)
CC::hoge(); //object(CC)

終わり

絵にして整理したら理解が進んだ!
フレームワークソースコードを読んでいるとstatic::やself::はガンガン出てくるので自分の中ではよい整理になった!

PHPを愛する試み 〜調教編〜

PHPを愛する試みというのを個人的にやっている。

最近仕事でPHPをガリガリ使わなければならない状況になってしまった。そのため可及的速やかにPHPを愛する必要がある。

tap

ときに、Rubyにはtapという素敵なメソッドがある。

tapかわいいよtap

PHPでも$obj->tap(...)みたいに書きたい!

p

ときに、Rubyにはpという素敵なメソッドがある。

p (Kernel)

PHPでも$obj->p()みたいに書きたい!

ということで

今回はPHPを無理矢理Rubyっぽく使うという調教プレイでたわむれることにした。

どうやるか

ざっと調べたところ、

・どんなオブジェクトでもtapとpを使いたい。
・けどPHPにはRubyのように基底クラスを簡単に書き換えるような仕組みはなさそう
・かといって全てのクラスにメソッド実装するのはダルイ
C言語で拡張とか僕には無理だお

という感じだった。しかし、さらに調べるとrubyactivesupportっぽいことをPHPでやってる洋モノの変態さんを発見した。

ActiveSupport for PHP - Ruby style

なんかよさそう。ということで、ここから発想を得て以下のような仕組みを考えてみた。

・任意のオブジェクト$objをruby()に食わせると、->tap()と->p()が使えるようになる
・->tap()と->p()はメソッドチェインで->tap()->p()のように繋げることができる
ruby()に食わせたオブジェクトは->php()で元のオブジェクトに戻せる

Rubyっぽいメソッドを叩き込むドSファイル

ruby.php

<?php
class Ruby
{
    public function __construct($origin) {
        $this->origin = $origin;
    }

    public function tap($callback) {
        $callback($this->origin);
        return $this;
    }

    public function p() {
        var_dump($this->origin);
        return $this;
    }

    public function php() {
        return $this->origin;
    }
}

function ruby($origin) {
    return new Ruby($origin);
}

使ってみる

rubynize.php

<?php                                                                                                                                                             
require 'ruby.php';

class C
{
    public function __construct() {
        $this->name = 'hoge';
    }   
}

// オブジェクトをvar_dump
$c = new C();
ruby($c)->p();

// オブジェクトのnameプロパティにfugeをセット
$c = new C();
ruby($c)->tap(function ($x) {$x->name = 'fuge';});                                                                                                            
var_dump($c);

// オブジェクトのnameプロパティにfugeをセットし、オブジェクトをvar_dump
$c = new C();
ruby($c)->tap(function ($x) {$x->name = 'fuge';})->p();

// 上記の返り値をRubynizeする前のものにする
$c = new C();
$new_c = ruby($c)->tap(function ($x) {$x->name = 'fuge';})->p()->php();
var_dump($new_c);

チェイン(鎖)ー!

さらに使ってみる

rubynize2.php

<?php
require 'ruby.php';
 
class C
{
  public function setName($name) {
    $this->name = $name;
    return $this;
  }
 
  public function setSex($sex) {
    $this->sex = $sex;
    return $this;
  }
}
 
 
// 普通のメソッドチェイン
$c = new C();
$c->setName('hoge')->setSex('man');
var_dump($c);
 
// tapでnameをhoge->fugeに
$c = new C();
ruby($c->setName('hoge'))
  ->tap(function ($x) {$x->name = 'fuge';})
  ->php()
  ->setSex('man');
var_dump($c);
 
// tapでnameをhoge->fugeに。sexをman->womanに。さらにチェーンでvar_dump
$c = new C();
ruby(
  ruby(
    ruby($c->setName('hoge'))
    ->tap(function ($x) {$x->name = 'fuge';})
    ->php()
    ->setSex('man')
  )   
  ->tap(function ($x) {$x->sex = 'woman';})
)->p();

チェインチェイン(鎖鎖)ー!

終わり

ruby()が必要だったり->php()しなきゃだったりで、もっとすっきり出来そう。
だけど自分の能力ではこの辺が限界だお...
もっとPHPのことを知らなきゃですな...

※ 個人的にPHPとたわむれる試みなので、実用性とか(ry

※シリーズもので頑張ってる
PHPを愛する試み
PHPを愛する試み 〜調教編〜
PHPを愛する試み 〜self:: parent:: static:: および遅延静的束縛〜

unshift, shift, pop, pushが混乱するので、絵で整理した

配列の追加・取り出しに関する4つのメソッド(unshift, shift, pop, push)がいつも混乱するので絵で整理した。

絵にすれば覚えられそう!いちお練習のため、自分がよく使うRuby, PHP, JavaScriptでコードも書いた。

・いずれの言語においても上記4つのメソッドは似たような名前で存在しており、用途も同じ。
・いずれの言語のいずれのメソッドも破壊的メソッド
・言語、バージョンによってメソッドの返り値は異なる。

という具合だった。

Ruby

ruby 1.9.2

# unshift
a = [1, 2, 3]
b = a.unshift 0
p a #[0, 1, 2, 3]
p b #[0, 1, 2, 3]

# shift
a = [1, 2, 3]
b = a.shift
p a #[2, 3]
p b #1

# pop
a = [1, 2, 3]
b = a.pop
p a #[1, 2]
p b #3

# push
a = [1, 2, 3]
b = a.push 4
p a #[1, 2, 3, 4]
p b #[1, 2, 3, 4]

# <<
a = [1, 2, 3]
b = a << 4
p a #[1, 2, 3, 4]
p b #[1, 2, 3, 4]

PHP

PHP 5.3.10

<?php
// unshift
$a = array(1, 2, 3);
$b = array_unshift($a, 0);
var_dump($a); //array(0, 1, 2, 3)                                                                                                                             
var_dump($b); //4(結果配列の要素数)

// shift
$a = array(1, 2, 3);
$b = array_shift($a);
var_dump($a); //array(2, 3)
var_dump($b); //1

// pop
$a = array(1, 2, 3);
$b = array_pop($a);
var_dump($a); // array(1, 2)
var_dump($b); // 3

// push
$a = array(1, 2, 3); 
$b = array_push($a, 4); 
var_dump($a); //array(1, 2, 3, 4)
var_dump($b); //4 (結果配列の要素数)

// [] =
$a = array(1, 2, 3);
$b = $a[] = 4;
var_dump($a); //array(1, 2, 3, 4)
var_dump($b); //4(追加した値)

JavaScript

node 0.6.12

var a = [1, 2, 3];                                                                                                                                                                                          
var b = a.unshift(0);
console.log(a); //[0, 1, 2, 3]
console.log(b); //4(結果配列の要素数)

var a = [1, 2, 3];
var b = a.shift();
console.log(a); //[2, 3]
console.log(b); //1

var a = [1, 2, 3];
var b = a.pop();
console.log(a); //[1, 2]
console.log(b); //3

var a = [1, 2, 3];
var b = a.push(4);
console.log(a); //[1, 2, 3, 4]
console.log(b); //4(結果配列の要素数)

一瞬で「今日のディレクトリ」を作成・移動できるRuby/Bashスクリプト


ちょっとしたファイルを作成・保存しておきたい時、自分にとっては「今日の日付のディレクトリ」にまとめておくのが丁度よい。これまでは毎日手作業で「今日の日付のディレクトリ」を作成・移動していたのだけど、これを毎回やるのが面倒臭い。ということでスクリプトで自動化した。ちなみに環境はruby1.9.2。bash 3.2.48。

※追記
ブコメでご指摘いただいた通り、Ruby使わないでBashだけでできます...なぜわざわざRubyを使ったのか...そこにRubyがあったからです...

機能

・シェルで「. today」と入力すると「~/daily/今日の日付(yyyy_mm_dd)」ディレクトリを作成し移動する

実装にあたって

Rubyでディレクトリを作るのは簡単なのだが、現在のシェルを移動するのに一工夫必要だった。RubyでDir.chdirするだけでは、現在のシェルのディレクトリは移動しない(あくまでもrubyコマンドを実行したシェルの子プロセスとして動くから)。そこで「Rubyはディレクトリ作成後、移動コマンド(cd ...)を標準出力に吐き出す→吐き出されたコマンドを現在のシェルで実行する」という処理にした。

標準出力に吐き出された文字列をBashのコマンドとして実行するには「コマンド置換($()か``)」を使う

コマンド置換

コマンド置換 (command substitution) を用いると、 コマンド名をコマンドの出力で置き換えられます。...
http://linuxjm.sourceforge.jp/html/GNU_bash/man1/bash.1.html

コマンドを現在のシェルで実行するには「.かsource」を使う

. filename [arguments]
source filename [arguments]

filename からコマンドを読み込み、現在のシェル環境の下で実行します。...
http://linuxjm.sourceforge.jp/html/GNU_bash/man1/bash.1.html

コードを書く

Ruby

~/script/today.rb

today = Time.now.strftime "%Y_%m_%d"                                                                                                                                              
today_dir = File.expand_path("~/daily/#{today}")
Dir.mkdir(today_dir) unless File.exist? today_dir
puts "cd #{today_dir}"
Bash

today

#!/usr/bin/env bash                                                                                                                                                                                         

$(ruby ~/script/today.rb)

※「$()」は「``」でもOK

このBashコードに実行権限をつけてパスを通せば、準備完了。

実行

※追記
ご指摘いただいたので、lsの表示結果を掲載しました

例えば、今日の日付が2013年1月20日で、この状態から

$ pwd
/Users/hidenorimaehara
$ ls ~/daily
2013_01_18 2013_01_19

シェルで以下のコマンドを打つと

$ . today

※「.」は「source」でもOK

今日の日付のディレクトリが作成され移動できる。

$ pwd
/Users/hidenorimaehara/daily/2013_01_20
$ ls ../
2013_01_18 2013_01_19 2013_01_20

となる

Macなら、こうすれば、ディレクトリ移動後にそのディレクトリをFinderを開けて便利。

$ . today
$ open .

終わり

ちょっとしたスクリプトだけど、自分にとっては結構便利だった!

PHPを愛する試み

僕はRubyが好きだ。プライベートではRubyばっかり使っている。でも、仕事ではPHPを使わなければならない。これまでPHPは書きにくいーと思い込んでいてあまり好きではなかったのだけど、仕事で使う以上PHPを好きになった方がきっと幸せになれる。何かを好きになるにはどうすればよいか。そう、相手のことを知る努力をすればいいんだ!ということで、PHPについて知る努力をしてみた。

PHP The Right Wayを読む

http://ja.phptherightway.com/

PHPへの愛が100上がった☆

これは...

PHP好きになれるかも!

普段Rubyで書いてるコードをPHPで書いてみる

折角なので自分が普段Rubyを使っていて便利だなーと感じていることをPHPではどう書くのか(厳密では無いにしても大体同じ内容はどう書くか)試してみた。Rubyは1.9.2、PHPは5.3.10。

多重代入っぽいもの

Ruby

a, b = [1, 2]
puts a
puts b

PHP

<?php
list($a, $b) = array(1, 2);
echo "$a\n";
echo "$b\n"; 

ほう!

可変長引数

Ruby

def foo(*args)                                                                                                                                 
  p args
end

foo 1, 2
foo 1, 2, 3

PHP

<?php
function foo() {
  var_dump(func_get_args());
}

foo(1, 2);                                                                                                                                
foo(1, 2, 3);

ほほう!

無名関数・クロージャ

Ruby

a = [1, 2, 3]
b = 10
r = a.map {|v| v * b}
p r

PHP

<?php                                                                                                                                     
$a = array(1, 2, 3);
$b = 10;
$r = array_map(function($v) use ($b) {return $v * $b;}, $a);
var_dump($r);

キモカワイイ

名前空間

Ruby

module A
  class C
    def self.foo; puts 'A_foo'; end
  end
end

module B
  class C
    def self.foo; puts 'B_foo'; end
  end                                                                                                                                     
end

A::C.foo
B::C.foo

PHP

<?php
namespace A{
  class C
  {
    static function foo() {echo "A_foo\n";}
  }
}

namespace B{
  class C
  {
    static function foo() {echo "B_foo\n";}
  }
}

namespace {
  \A\C::foo();
  \B\C::foo();
}

キモい!けど、きっと慣れる!

呼び出し元を一覧表示

Ruby

def foo1; foo2; end
def foo2; foo3; end
def foo3; puts caller; end
foo1

PHP

<?php
function foo1() {foo2();}
function foo2() {foo3();}
function foo3() {debug_print_backtrace();}
foo1();

これできるんだ!

オブジェクトの情報をいろいろ表示

Ruby

class C;
  def foo1; end
end                                                                                                                                   
class CC < C;
  def foo2; end
end
class CCC < CC;
  def foo3; end
end

ccc = CCC.new
puts ccc.class.ancestors
puts ccc.methods

PHP

<?php                                                                                                                                     
class C
{
  function foo1() {}
}
class CC extends C
{
  function foo2() {}
}
class CCC extends CC
{
  function foo3() {}
}

$ccc = new CCC();
var_dump(get_class($ccc));
var_dump(class_parents($ccc));
var_dump(get_class_methods($ccc));
//さらにReflectionObject::exportを使うと、メソッドの定義場所やインスタンス変数まで表示してくれる
ReflectionObject::export($ccc);

ソースコード読むとき助かる!

メソッドチェイン

Ruby

class C                                                                                                                                                                             
  def foo1; self; end
  def foo2; self; end
  def foo3; puts 'done'; end
end

C.new.foo1.foo2.foo3

PHP

<?php
class C
{
  function foo1() {return $this;}
  function foo2() {return $this;}
  function foo3() {echo 'done';}
}

$c = new C();                                                                                                                                                                       
$c->foo1()->foo2()->foo3();

流れてる...

メタプログラミング(動的な関数定義と呼び出し)

Ruby

class C                                                                                                                                   
  def method_missing(method_name, *args)
    puts method_name
  end
end

c = C.new
[:foo1, :foo2].each {|m| c.__send__(m)}

PHP

<?php
class C
{                                                                                                                                              
  function __call($method_name, $args) {
    echo "$method_name\n";
  }
}

$c = new C();
foreach(array("foo1", "foo2") as $m) {$c->$m();}

こいつ・・・動くぞ!

さらにPHP5.4にすると

スゴイらしい...

http://php.net/manual/ja/migration54.new-features.php

配列のリテラルとして[]が使えたり、ビルトインサーバが使えたりするらしいですお...

PHP

好きになれるかも!今度はフレームワークとかも触ってみよう!

※シリーズもので頑張ってる
PHPを愛する試み
PHPを愛する試み 〜調教編〜
PHPを愛する試み 〜self:: parent:: static:: および遅延静的束縛〜

Rubyで内部DSLっぽいのやってみる

少し前に仕事中、一瞬の隙も見逃さずに情報収集できるRubyワンライナーとスクリプトというRubyスクリプトを書いたのだが、スクレイピング対象サイトをハッシュで持ってるあたりが使いづらい。良い機会なので内部DSLってのに挑戦してみた。

しかし、内部DSLについてざっと調べたものの、まだ租借しきれていない。とりあえず、Sinatraっぽい構文でスクレイピング対象サイトを指定できるようにした。

sites.rb(ユーザー側)

fetch 'yahoo' do
    url 'http://www.yahoo.co.jp'
    regexp /topics.+?>([^<]+?)</
end

fetch 'hatena' do
    url 'http://b.hatena.ne.jp/hotentry'
    regexp /entry-link.+>(.+?)</
end

fetch 'naver' do
    url 'http://matome.naver.jp/'
    regexp /matomename.+?-->(.+?)<!--/m
end

fetch '2ch' do
    url 'http://uni.2ch.net/newsplus/'
    regexp /<a.+?>\d+?:\s(.+?)</
end

news(定義側)

#!/usr/bin/env ruby
 
require 'open-uri'
require 'nkf'
 
class Site
  attr_accessor :name, :url, :regexp

  def initialize(n)
    @name = n
  end

  def url(u)
    @url = u
  end

  def regexp(r)
    @regexp = r
  end
 
  def get
    open(@url) do |f|
      f.read.scan(@regexp) {|m| puts NKF.nkf('-w', m.join)}
    end
  end
end

@defined_sites = []

def fetch(name, &block)
  s = Site.new(name)
  s.instance_eval &block
  @defined_sites << s
end

load File.expand_path('../sites.rb', __FILE__)

defined_site_names = @defined_sites.map(&:name)
site_names = ARGV.empty? ? defined_site_names : ARGV

sites = []
site_names.each do |site_name|
  raise 'not defined' unless defined_site_names.include? site_name
  @defined_sites.map {|s| sites << s if s.name === site_name}
end

sites.map(&:get)

実行

上記2ファイルを同じディレクトリに配置し、newsに実行権限を与え、パスを通せば前回と同様に動く。

けど

これが内部DSLと呼べるかはよく分からない。内部DSLについては今度ゆっくり調べることにしよう。