PHPer向けのRuby入門

  • 96
    いいね
  • 5
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

  • この記事はRubyの書き方・読み方を最低限説明するために作成されたものである。
  • PHPがある程度普通に触れている人向けに、Rubyではどう書く?みたいなところが中心
  • Rubyの環境は既に整ってる前提

基本思想

PHPは関数が基本

  • 例えばある配列から先頭の要素を取り出す時
$a = array(1,2,3);
$first = array_shift($a);
var_dump($first);
var_dump($a);
  • array_shiftという関数に引数を渡すことで任意の処理を行う。

Rubyはオブジェクトが基本

  • 同様に配列から先頭の要素を取り出す時
a = [1,2,3]
first = a.shift
p first
p a

Arrayオブジェクトashiftメソッドで先頭の要素を取り出す。

これがPHPRubyの基本思想の違いである。

まず先に出力方法

  • 基本的な出力形式を押さえておく。
  • PHPでいう「困ったらダンプしてみる」というのはRubyでも通用するのでpメソッドを覚えておくと何かと便利。
  • コメント文は#
PHP Ruby
echo('hoge'); print 'hoge'
echo("hoge¥n"); puts 'hoge'
var_dump('hoge'); p 'hoge'
//コメント文 #コメント文

実際に出力してみよう

コンソールでirbと打つとインタラクティブシェルが起動する。まずはファイルを作成せずにシェルで挙動を確認しましょう。

PHP Ruby
php -a irb

演習問題1

インタラクティブシェルでprint, puts, pの出力を試してみましょう。

拡張子と実行方法

プログラムファイルの拡張子は.rb、実行はrubyコマンド

PHP Ruby
.php .rb
php hoge.php ruby hoge.rb
hoge.php
<?php
$a = 'hoge';
var_dump($a);
hoge.rb
a = 'hoge'
p a
  • <?php等の開始タブが不要
  • 変数に$不要
  • 行末にセミコロン不要(つけても良い)
  • カッコの省略可(つけても良い)

演習問題2

実際に上記ファイルを作って実行してみましょう。

ループ

loop.php
<?php
for($i=0; $i<10; $i++){
    echo($i."\n");
}
loop.rb
for i in 0...10 do
  p i
end

ここで覚えて欲しいのは0...10の範囲オブジェクト
0..10だと10を含む、0...10だと10を含まない。
またPHPで中括弧で囲んでいる部分はそのままRubyではdo ~ endで置き換えることができる。

ちなみに上記のfor文はほぼ使わない。
私も久しぶりに使うにあたってドキュメントを参照しながらでないと書けなかった(汗
上記の例でいうと範囲オブジェクトに対してeachメソッドを使って

loop2.rb
(0...10).each do |i|
  p i
end

こんな感じに書くのが自然である。
もっと言うと基本は配列等のオブジェクトに対してループを回すことが大半である(PHPでいうところのforeachと同義)
そのあたりは次の配列の項で触れる。

演習問題3

1から100までの偶数を出力して下さい。

配列

array.php
<?php
$a = array('Hello', 'new', 'world');
foreach($a as $value){
    var_dump($value);
}
array.rb
a = ['Hello', 'new', 'world']
a.each do |value|
  p value
end

これが前項で述べていたオブジェクト(この場合には配列)に対してeachでループを回している様子である。foreachだと思えば馴染みやすいかと思う。
Arrayオブジェクトに色々なメソッドがあるので適宜使って欲しい。

http://ref.xaio.jp/ruby/classes/array

PHP Ruby
sort($a) a.sort
empty($a) a.empty?
array_unique($a) a.uniq
count($a) a.count

ここで出てきたのでついでに紹介するがRubyではメソッド名に!?が使用できる。
自由に命名に使って良いが慣習として

  • true or falsebooleanを返すメソッドには末尾に?
  • 対象のオブジェクトに対して破壊的なメソッドには末尾に!を使う。

例えばarray.uniqarray.uniq!という元の配列を上書き(破壊)してしまうものも存在する。

演習問題4

次の処理のPHPRubyに書き換えてみましょう。

example4.php
<?php
// カンマ区切りの文字列を配列に格納
$string = 'Hello, new, world';
$array = explode(', ', $string);
print_r($array);

// 配列の各要素をカンマ区切りの文字列に変換
$convert_string = implode(', ', $array);
print_r($convert_string);

// カンマ区切りの文字列をコロン区切りの文字列にする
print_r(str_replace(',', ':', $convert_string));

条件分岐

if.php
<?php
$a = 'hoge';
if($a === 'hoge'){
    echo("true\n");
}
if.rb
a = 'hoge'
if a == 'hoge'
  p 'true'
end

特に難しいことはない。

  • カッコの省略
  • 中括弧がthen ~ end (thenは省略可)
  • ==PHP===と同じく厳密比較

Rubyならではの書き方を以下に記載する。

unless

unless.php
<?php
$a = 'hoge';
if($a !== 'moge'){
    echo('true');
}
unless.rb
a = 'hoge'
unless a == 'moge'
  p 'true'
end

unlessとは簡単に言えば!==と同義である。
簡単に否定の比較ができるので割と重宝する。
!よりも見落としにくい。

elsif

else.php
<?php
$a = 'hoge';
if($a === 'moge'){
    echo('moge');
} else if($a === 'hoge'){
    echo('hoge');
} else{
    echo('else');
}
else.rb
a = 'hoge'
if a == 'moge'
  p 'moge'
elsif a == 'hoge'
  p 'hoge'
else
  p 'else'
end

else ifでもelseifでもなくelsifなので注意

後置if

back_if.rb
a = 'hoge'
p 'true' if a == 'hoge'
p 'true' unless a == 'moge'

個人的にRubyが好きな理由の1つ
条件式を後ろに配置できる。
ものによっては1行でまとまって非常にスッキリするのでオススメ
英語の文法としても自然(と思う)
PHPにはないのでPHP版は割愛

演習問題5

1から30の間でFizzBuzzRubyで実装してみましょう。
FizzBuzzとは3の倍数でFizz, 5の倍数でBuzz, 15の倍数でFizzBuzz, それ以外の時は数値を出すプログラム問題のことである。

ハッシュ(連想配列)

hash.php
<?php
$a = array('key1' => 'value1', 'key2' => 'value2');
print_r($a);

foreach($a as $key => $value){
    echo("$key, $value\n");
}

echo($a['key2']."\n");
hash.rb
a = {'key1' => 'value1', 'key2' => 'value2'}
p a

a.each do |key, value|
  puts key + ', ' + value
end

puts a['key2']

ハッシュとは簡単に言うとPHPでいうところの連想配列である。
キーとそれに対応する値を保持する形
これも連想配列を理解していれば特に難しいことはない。
リテラルが中括弧を使用する点に注意

演習問題6

'key1' => 1この形で10まであるハッシュをループで生成して下さい。
生成したハッシュに対して、値が5以上であるもののkey値を出力して下さい。
Hint: キャスト

PHP Ruby
(int)'5' '5'.to_i
(string)5 5.to_s

関数

function.php
<?php
function add($a, $b){
    $sum = $a + $b;
    return $sum;
}

$result = add(1, 2);
var_dump($result);
function.rb
def add(a, b)
  sum = a + b
  return sum
end

sum = add(1, 2)
puts sum

PHPfunctiondefに置き換えればほぼそのまま流用できる。
ただRubyでは上記のような書き方は普通しない。
通常は以下のような書き方になる。

function2.rb
def add a, b
  a + b
end

puts add(1, 2)

Rubyではreturnを省略することができる。
省略した場合は関数内で最後に評価された値が自動で返る(この場合はa+bの結果)
ここはRubyのソースを読む上で勘違いしやすいところなので注意。

演習問題7

引数: array
戻値: hash
配列を渡したらその中に入っている数値を全て足した結果を返す関数を作成して下さい。
配列の中が全て整数でなければ加算できないのでsuccessにfalseを入れて返して下さい。
例:
[1,2,3,4,5,6,7,8,9,10] >> {'success' => true, 'value' => 55}
[1,2,3,'a',5,6,'b',8,9,10] >> {'success' => false, 'value' => nil}
Hint: nil
nilとはPHPでいうところのNULLと同義である。

PHP Ruby
NULL nil
is_null(NULL) nil.nil?

例外処理

exception.php
<?php
try {
    $a = 'moge';
    if($a === 'hoge'){
        echo("hoge\n");
    } else {
        throw new Exception('exception occur');
    }

    echo('finish');
} catch(Exception $e){
    var_dump($e->getMessage());
}
exception.rb
begin
  a = 'moge'
  if a == 'hoge'
    puts a
  else
    raise 'exception occur'
  end
rescue => message
  puts message
end

PHPtry-catchRubyではbegin-rescue-endに置き換わる。
また、例外を発生させる方法はthrowraiseに置き換える。

クラス

class.php
<?php
class ParentClass
{
    public function sayHello(){
        echo("Hello!\n");
    }
}

class ChildClass extends ParentClass
{
}

$a = new ParentClass();
$a->sayHello();

$b = new ChildClass();
$b->sayHello();
class.rb
class ParentClass
  public
  def sayHello
    puts 'Hello'
  end
end

class ChildClass < ParentClass
end

a = ParentClass.new
a.sayHello

b = ChildClass.new
b.sayHello

簡単に違いを表す

PHP Ruby
extends <
new Class Class.new
$a->hoge() a.hoge

また、PHPではメソッド1つ1つにpublic, protected, privateをつけるのに対し、Rubyでは宣言箇所以下ではそのアクセス権に絞られる。
以下の例で言うとa,b,cpublic, d,eprotected, fprivateとなる。

class hoge
public
a
b
c
protected
d
e
private
f
end

演習問題8

上記の例にChildClassを継承したGrandChildClassを追加して下さい。
GrandChildClassではsayHelloメソッドに引数で文字列を渡すとその人に対してHelloするようにメソッドを拡張して下さい。
例: c.sayHello('yamamoto') >> 'Hello! yamamoto!'

ブロック

ブロックに関してはPHPに置き換えるのが難しいため割愛
こちらの記事が大変参考になるので気になる人はこちら

http://qiita.com/kidach1/items/15cfee9ec66804c3afd2

おわりに

これでRubyの基本的な書き方は押さえられました。
次回はRailsにスポットを当てる予定です。

Appendix

演習問題の解答例を載せておきます。
解き方は1通りではないし私の解答がイケてない可能性もあるのであくまで例ということで。

演習問題3の解答例

example3.rb
(1..50).each do |i|
  p i * 2
end

# 条件文を使った方法はこっち
#(1..100).each do |i|
#  p i if i % 2 == 0
#end

演習問題4の解答例

example4.rb
string = 'Hello, new, world'
array = string.split(', ')
p array

convert_string = array.join(', ');
p convert_string

p convert_string.gsub(',', ':');

演習問題5の解答例

example5.rb
(1..30).each do |i|
  print 'Fizz' if i%3 == 0
  print 'Buzz' if i%5 == 0
  print i unless (i%3 == 0 || i%5 == 0)
  puts
end

演習問題6の解答例

example6.rb
a = {}
1.upto 10 do |i|
  a['key'+i.to_s] = i
end
p a

a.each do |key, value|
  p key if value >= 5
end

演習問題7の解答例

example7.rb
def add_all target_array
  # 全て数値かチェック
  success = number_check(target_array)
  result_hash = {'success' => success}
  if success
    result_hash['value'] = target_array.inject { |sum, n| sum + n }
  else
    result_hash['value'] = nil
  end
  result_hash

end

def number_check target_array
  target_array.each do |i|
    return false unless i.kind_of?(Numeric)
  end
  true
end

target_array = [1,2,3,4,5,6,7,8,9,10]
p add_all(target_array)

target_array = [1,2,3,'a',5,6,'b',8,9,10]
p add_all(target_array)

演習問題8の解答例

example8.rb
class ParentClass
  public
  def sayHello
    puts 'Hello'
  end
end

class ChildClass < ParentClass
end

class GrandChildClass < ChildClass
  public
  def sayHello(name)
    puts 'Hello! ' + name + '!'
  end
end

a = ParentClass.new
a.sayHello

b = ChildClass.new
b.sayHello

c = GrandChildClass.new
c.sayHello('yamamoto')