Ruby

日本人が生んだコードを書く楽しさがある言語

Rubyは、日本人であるまつもとゆきひろ氏によって生まれた言語です。
C++/Javaのような言語が、パフォーマンスやオブジェクト指向的な機能性を目指して作られているのとは違い、「コードを書く楽しさ」のために作られています。
Rubyでは、動的スクリプト言語としてのオブジェクト指向の仕様と、ブロックやMix-inのような使いやすい記法から、美しく、機能的で、短いコードを簡素に書くことができます。
Perlを参考にした言語であり、「パール(真珠)ではなくルビー」という名前になっていますが、記法の過度な自由や美しくない記法の多いPerlに比べて、書き方が制限されている代わり自然で「このように書きたい」というニーズを満たした言語仕様になっています。
ライバルはPythonで、アメリカなどでPythonが流行っているのと逆に、日本ではRubyが流行っています。
また、最近ではRuby on Railsという革命的なWebフレームワークで採用されたことで、日本だけではなくグローバルに普及しました。ここまで流行っているのは、Railsの功績が大きいです。
ですが、ブロックの終わりに「end」というキーワードを使うとか、ブロック(無名関数)の引数を「|~|」で囲んだり、インスタンス変数を「@name」のようにアットマークで示すなど、独自のありえない記法がたくさんあります。ですが、その多くは自然で、使い慣れるとプログラミングの際にいつでもこの書き方をしたくなるほどシンプルかつ美しいです。
また、JavaC++と比べて「本当のプログラマの言語ではない」と言われることもあります。Rubyエンジニアは、いつまで経ってもRubyRailsしかできず、限界が来ると言われています。これは確かにそうかもしれません。型名や呼び出し規約をきちんと考えるJavaC++に比べて、動的であまり考えなくても適当に動くRubyは、一流のハッカーになるためには少し簡単すぎるのかもしれません。高水準・高レベルすぎて、実際のCPUやメモリなどを中心に動いているコンピュータ・アーキテクチャが見えづらくなっている、ということはあると思います。

Rubyは動的そのもの

Rubyの特徴として言えるのが、「動的」な言語ということです。
C++Javaなどが「型」の概念にとらわれるのに対して、(Rubyに型がないわけではありませんが)日常の利用で型という存在を別にしてコードを書くことができます。
C++Javaなどでは、親クラスの型や派生クラスの型、インターフェースの型などを考えて書かなければなりません。あるいは、たくさんの型に対応しようとするならば、テンプレートを使ってジェネリックで行わなければなりません。それに加えて、C++ではポインタの考え方が入ってきます。動的な配列やメモリ確保を実現したり、あるいはスコープ外のオブジェクトにアクセスするための参照型として、ポインタを使う必要があります。
Rubyは、動的なスクリプト言語であるため、そうした静的型付けの考え方から「解放」されて、スクリプトを動的に書けます。Rubyの型は、あえて指定しなくても、その場その場の状況に応じて動的に決定されます。
動的であることは必ずしも良いことではなく、厳密に型付けされている方が良いことは多々ありますが、手軽で簡単に処理を実行できる言語であると言えます。大規模なプログラムはJavaで書いて、個人で使うバッチ処理にはRubyを使う、といったやり方をすれば良いと思います。

Web用途に使うと何でもできる

Rubyは、Web用途に使うと何でもできます。
従来はPerl/CGIPHPのような言語で行われていたWeb業界は、最近は完全にRubyRails、あるいはそれと同等のWebフレームワークを使って作るようになりました。
Twitterのような高度な「掲示板のようなSNSのようなコミュニケーションサービス」は、RailsDjangoPython版のRails)で作ることができます。(最近はTwitterRailsからScalaに変更されたらしい。)
Railsを使えば、超簡単に、また何でもできるWebサービスを作れます。PHPでPDOなどを使ってごりごりSQLを書かなくても、最低限の記述で簡単に管理できます。
そのため、Webエンジニアになりたいのであれば、まずはRubyを習得しましょう。
Rubyは良い言語で、優れた言語仕様と何でも簡単にできるライブラリ関数がありますが、GUIアプリケーションを作るのには向いていません。もともとはPerlのようなシステム管理のために使われることの多い言語ですが、簡単なスクリプト処理とWeb以外の分野ではあまり使われていません。そのため、C/C++C#/VB/Javaなどと一緒に、Rubyを使って「Webサービスを作って何かやってやろう!」という気概を持って習得に励んでください。

バッチ処理の練習に最適

Rubyの大きな特徴は、「複雑で高度なことを小さな記述で簡単にできる」ということ。
標準のデータ構造やブロックなどを使うことで、C/C++では何十行・何百行におよぶコードを、数行で記述することができます。
また、日本発の言語であるため、日本語のマルチバイト文字などの対応も優れています。PerlPythonでは複雑になる日本語のテキストファイルの処理などを簡単に処理できます。
そのため、本当にバッチ処理の練習に向いています。練習だけではなく、Rubyを使うことで実用的なプログラミングを習得することができます。

自作の簡単なゲーム

Rubyによるちょっとしたゲーム

Rubyによるちょっとしたゲーム。自作ですが、作業所のみんなで開発したPerlのプログラムを参考にしています。

class Player
    def initialize(name, hp, atk)
        @name = name
        @hp = hp
        @atk = atk
    end
    
    def name()
        return @name
    end
    
    def damaged(power)
        puts "#{@name}#{power}ダメージを受けた。"
        @hp -= power
    end
    
    def attack(player)
        puts "#{@name}#{player.name()}を攻撃した。"
        player.damaged(@atk)
    end
    
    def print_hp()
        puts "#{@name}の残りHPは#{@hp}になった。"
    end
end

player1 = Player.new("戦士", 100, 10)
player2 = Player.new("魔法使い", 50, 15)
boss = Player.new("ボス", 1000, 20)

for i in 1..5 do
    puts "ターン#{i}"
    player1.attack(boss)
    player2.attack(boss)
    boss.attack(player1)
    boss.attack(player2)
    player1.print_hp()
    player2.print_hp()
    boss.print_hp()
    print "\n"
end

出力:

ターン1
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスを攻撃した。
ボスは15ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは80になった。
魔法使いの残りHPは30になった。
ボスの残りHPは975になった。

ターン2
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスを攻撃した。
ボスは15ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは60になった。
魔法使いの残りHPは10になった。
ボスの残りHPは950になった。

ターン3
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスを攻撃した。
ボスは15ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは40になった。
魔法使いの残りHPは-10になった。
ボスの残りHPは925になった。

ターン4
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスを攻撃した。
ボスは15ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは20になった。
魔法使いの残りHPは-30になった。
ボスの残りHPは900になった。

ターン5
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスを攻撃した。
ボスは15ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは0になった。
魔法使いの残りHPは-50になった。
ボスの残りHPは875になった。
ブラウザでRubyコンパイル・実行できるPaiza.io上で開発しました。

継承を使ったバージョン

継承を使って魔法を実装したバージョン。

class Player
    def initialize(name, hp, atk)
        @name = name
        @hp = hp
        @atk = atk
    end
    
    def name()
        return @name
    end
    
    def damaged(power)
        puts "#{@name}#{power}ダメージを受けた。"
        @hp -= power
    end
    
    def attack(player)
        puts "#{@name}#{player.name()}を攻撃した。"
        player.damaged(@atk)
    end
    
    def print_hp()
        puts "#{@name}の残りHPは#{@hp}になった。"
    end
end

class Mage < Player
    def initialize(name, hp, atk)
        super
    end
    
    def attack(player)
        puts "#{@name}#{player.name()}に大魔法エクスカリバーを唱えた。"
        player.damaged(@atk + 100)
    end
end

player1 = Player.new("戦士", 100, 10)
player2 = Mage.new("魔法使い", 50, 15)
boss = Player.new("ボス", 1000, 20)

for i in 1..5 do
    puts "ターン#{i}"
    player1.attack(boss)
    player2.attack(boss)
    boss.attack(player1)
    boss.attack(player2)
    player1.print_hp()
    player2.print_hp()
    boss.print_hp()
    print "\n"
end

出力:

ターン1
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスに大魔法エクスカリバーを唱えた。
ボスは115ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは80になった。
魔法使いの残りHPは30になった。
ボスの残りHPは875になった。

ターン2
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスに大魔法エクスカリバーを唱えた。
ボスは115ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは60になった。
魔法使いの残りHPは10になった。
ボスの残りHPは750になった。

ターン3
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスに大魔法エクスカリバーを唱えた。
ボスは115ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは40になった。
魔法使いの残りHPは-10になった。
ボスの残りHPは625になった。

ターン4
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスに大魔法エクスカリバーを唱えた。
ボスは115ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは20になった。
魔法使いの残りHPは-30になった。
ボスの残りHPは500になった。

ターン5
戦士はボスを攻撃した。
ボスは10ダメージを受けた。
魔法使いはボスに大魔法エクスカリバーを唱えた。
ボスは115ダメージを受けた。
ボスは戦士を攻撃した。
戦士は20ダメージを受けた。
ボスは魔法使いを攻撃した。
魔法使いは20ダメージを受けた。
戦士の残りHPは0になった。
魔法使いの残りHPは-50になった。
ボスの残りHPは375になった。

簡単な説明

Ruby

  • Ruby
    • Ruby
      • 演算子
      • データ構造
      • 制御フロー
      • メソッド
      • クラスとオブジェクト
      • ブロックとProcクラス
      • モジュールとMix-in
      • ライブラリ
      • gems

Ruby

演算子

基本は加減乗除。+, -, *, /, %などが使えるほかMathモジュールで数学関数を使える。

データ構造

ローカル変数はvalueグローバル変数は$valueインスタンス変数は@value、クラス変数は@@value
リストやハッシュもある

制御フロー

ifなどの制御ブロックや関数の終了はend
for文ではJavaの拡張for文のような記法(反復可能オブジェクトを1つ1つ操作する)も可能

メソッド

メソッドの定義はdef
returnは省略した場合最後の値を返す

クラスとオブジェクト

クラスの定義はclass
classの中にdefでメソッドを作り、@valueインスタンス変数を操作する
インスタンスの作成はnewメソッド
メソッドはレシーバ名.メソッド名()というように「.」をつけて呼び出す(ブロックを付加することも可能)
継承は「<」を使う。演算子オーバーロードが使えるため配列の[]を再定義することもできる。また特異メソッドを使ってインスタンスに直接メソッドを追加するなどの荒業も可能。

ブロックとProcクラス

ブロックはdo |x| 〜 endや波括弧も使える
ブロックは無名関数だが、ブロックがあるだけでRubyは極めて直観的で使いやすい

モジュールとMix-in

モジュールはクラスと似ているが、特定のメソッドをインクルードして使い回せる

EnumerableモジュールやComparableモジュール

これらのモジュールは、eachや<=>など最低限のメソッドを必要とし、最低限のメソッドだけ定義すれば、自分のクラスでもインクルードできる
eachだけを実装してEnumerableモジュールをインクルードすれば、mapやfindも使えて便利
Arrayクラスのメソッドに見えて、実際はEnumerableモジュールのメソッドという場合も多い
ダックタイピング(アヒルのように鳴き、アヒルのように歩くものは、アヒルに違いない)との相性も良い

ライブラリ

Rubyにはさまざまなライブラリが用意されている
特にArray, Hash, File, Dir, IO, String, Regexp, Procなどは不可欠