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については今度ゆっくり調べることにしよう。

Rubyワンライナー入門

先日仕事中、一瞬の隙も見逃さずに情報収集できるRubyワンライナーとスクリプトというネタエントリを書いたのだが、その際Rubyワンライナーをもう少しまともに理解したいと思ったので入門してみた。手元のRubyは1.9.2

はじめに

Rubyワンライナーは、rubyコマンドに色々なオプション(-eや-nなど)をつけて実行する。各オプションの網羅的な解説が見たければ、コマンドラインでは$ man rubyで閲覧できるし、webではるりまサーチで参照できる。ただ、これらは網羅的すぎるので、以下よく使うオプションとその周辺情報についてまとめた。

-e

一番基本的なオプション。スクリプトを実行する。(ちなみに他のオプションと組み合わせる時は必ず最後に記載する)

例: hogeと表示

$ ruby -e 'puts "hoge"'

-n

プログラム全体がwhile gets ... endというループで囲まれているように動作する。ちょっとややこしい。

例: hoge.txtとfuge.txtの内容を表示

$ ruby -ne 'puts $_' hoge.txt fuge.txt
理解するには

Kernel.#gets、ARGF、$_について理解する必要がある

Kernel.#gets

ARGFから一行読み込んで、それを返します。...読み込んだ文字列は組み込み変数 $_ にもセットされます。...
http://rurema.clear-code.com/1.9.2/method/Kernel/m/gets.html

つまり、以下は同義

$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt

ざっくりいうと、以下のような流れになる

hoge.txtとfuge.txtを連結した仮想ファイル(ARGF)をセット

ARGFから1行読み込み、$_にセット。読み込めた場合は$_を出力してループ

ちなみに

上記では出力の部分をputs $_としているが、これはKernel.#printで代替できる。

Kernel.#print

引数を順に標準出力 $stdout に出力します。引数が与えられない時には変数 $_ の値を出力します。...
http://rurema.clear-code.com/1.9.2/method/Kernel/m/print.html

つまり、以下は全て同義

$ ruby -ne 'print' hoge.txt fuge.txt
$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt

-p

nオプションとほぼ同じ。nオプションと同じくプログラム全体をwhile gets...endループするが、さらに各ループの最後にprintする。つまり、printが省略できるということ。なので、以下は全て同義。

$ ruby -pe '' hoge.txt fuge.txt
$ ruby -ne 'print' hoge.txt fuge.txt
$ ruby -ne 'puts $_' hoge.txt fuge.txt
$ ruby -e 'while gets; puts $_; end' hoge.txt fuge.txt

$_を破壊的メソッドで変換して出力するような場合に便利

例: hoge.txtとfuge.txtの内容を全て大文字にして表示

$ ruby -pe '$_.upcase!' hoge.txt fuge.txt

-a

オートスプリット。nかpと一緒に使う。各ループの先頭で$F = $_.splitをを実行する。

例: カレントディレクトリの情報を配列に変換して表示

$ ls -laF | ruby -ane 'p $F'
-F

$;(入力フィールドセパレータ。splitのデフォルト区切り文字)を設定

例: 環境変数PATHを:で分割して改行表示

$ echo $PATH | ruby -F: -ane 'puts $F'

-r

ライブラリ読み込み。

例: yahooのhtmlを取得

$ ruby -r open-uri -e 'open("http://www.yahoo.co.jp") {|f| puts f.read}'

ちなみに、複数のライブラリを読み込みたい場合は-r を複数書く。

例: facebookapiからマークザッカーバーグJSONを取得しハッシュに変換

$ ruby -r open-uri -r json -e 'open("http://graph.facebook.com/zuck") {|f| p JSON.parse(f.read)}'

BEGIN, END

オプションでは無いのだが、普段あまり使わないRubyの構文BEGINとEND(begin...endとは全くの別物)がワンライナーだと結構使われるようだ。

例: 全行が整数のnumber.txtの合計値を表示

$ ruby -ne 'BEGIN{$sum = 0}; $sum += $_.to_i; END{puts $sum}' number.txt 

BEGINとENDをつけないと、毎行読み込むごとに$sum = 0; と puts $sumが実行されてしまうので意図した結果にならない

BEGIN

初期化ルーチンを登録します。BEGINブロックで指定した文は当該ファイルのどの文が実行されるより前に実行されます。...
http://doc.ruby-lang.org/ja/1.9.2/doc/spec=2fcontrol.html#BEGIN

END

「後始末」ルーチンを登録します。END ブロックで指定した文はインタプリタが終了する時に実行されます。Ruby の終了時処理について詳しくは 終了処理を参照してください。...
http://doc.ruby-lang.org/ja/1.9.2/doc/spec=2fcontrol.html#END

書籍プログラミング言語Rubyによると、この構文はawkを受け継いだものらしい。以下のサイトが参考になりそう。

Ruby one-liners
AWKのススメ « クックパッド開発者ブログ

終わり

とりあえずRubyワンライナー入門した!

仕事中、一瞬の隙も見逃さずに情報収集できるRubyワンライナーとスクリプト

情報収集はビジネスマンとしての基本である。しかし普段シェルで作業する者としては、毎回ブラウザを立ち上げる時間すら不毛である。よって、シェルから一瞬で情報収集できるRubyワンライナーを書いた。

上からYahoo, はてな, Naverまとめ, 2ちゃん

$ ruby -r open-uri -e 'open("http://www.yahoo.co.jp").read.scan(/topics.+?>([^<]+?)</) {|m| puts m}'
$ ruby -r open-uri -e 'open("http://b.hatena.ne.jp/hotentry").read.scan(/entry-link.+>(.+?)</) {|m| puts m}'
$ ruby -r open-uri -e 'open("http://matome.naver.jp/").read.scan(%r{matomename.+?-->(.+?)<!-}m) {|m| puts m}'
$ ruby -r open-uri -e 'open("http://uni.2ch.net/newsplus/").read.scan(/<a.+?>\d+?:\s(.+?)</) {|m| puts m}' | nkf -w

あれ?

普通にブラウザ開いた方が早いw

なので

コマンド一発で情報収集できるスクリプトを書いた

news
#!/usr/bin/env ruby
 
require 'open-uri'
require 'nkf'
 
defined_sites = {
  'yahoo' => {
    'url' => 'http://www.yahoo.co.jp',
    'regexp' => /topics.+?>([^<]+?)</
  },
  'hatena' => {
    'url' => 'http://b.hatena.ne.jp/hotentry',
    'regexp' => /entry-link.+>(.+?)</
  },
  'naver' => {
    'url' => 'http://matome.naver.jp/',
    'regexp' => /matomename.+?-->(.+?)<!--/m
  },
  '2ch' => {
    'url' => 'http://uni.2ch.net/newsplus/',
    'regexp' => /<a.+?>\d+?:\s(.+?)</
  }
}
 
class Site
  attr_accessor :url, :regexp
 
  def initialize
    yield self
  end
 
  def fetch
    open(@url) do |f|
      f.read.scan(@regexp) {|m| puts NKF.nkf('-w', m.join)}
    end
  end
end
 
site_names = ARGV.empty? ? defined_sites.keys : ARGV
sites = []
site_names.each do |site_name|
  raise 'not defined' unless defined_sites.keys.include? site_name
 
  sites << Site.new do |s|
    s.url = defined_sites[site_name]['url']
    s.regexp = defined_sites[site_name]['regexp']
  end
end
 
sites.map(&:fetch)

こいつに実行権限を与えて、pathを通して、newsコマンド

$ news

東電社長 時効主張せずと明言
鳩山元首相、招かれ訪中へ
高2自殺 前日に平手30-40発?
JTB 企業の体力測定事業参入
魔女狩りで禁固20年 ネパール
本田にミランがオファー準備
安藤美姫がトヨタ自動車退社
金爆・鬼龍院のNSC芸人時代
今日の話題(27件)
一番福へ全速力
...

キタ!


yahooとhatenaだけ表示したければ

$ news yahoo hatena


対象サイトを追加したければ、ハッシュ(defined_sites )に追加すればOK!
これで一瞬の隙も見逃さずに情報収集する「できるビジネスマン」になれる!

※注 ネタです

※追記 Rubyワンライナーについてまとめた
Rubyワンライナー入門