モジュール

モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。

モジュールの定義

モジュールの定義とクラスの定義は似ています。 クラスの定義にはclassキーワードを使いますが、モジュール定義ではその代わりにmoduleキーワードを使います。

module Abc
  def abc
    print "abcdefg\n"
  end
end

モジュール名はAbcです。 モジュール名は定数で、最初の文字は大文字でなければいけません。 モジュールはクラスと違い、インスタンスを作ることはできません。 もし、Abc.newとしてインスタンスを作ろうとするとエラーになります。

インクルード

先程の例ではインスタンスメソッドabcをモジュールAbcの中で定義しました。 しかし、モジュールではインスタンスを作れないのですから、このメソッドは使いようがないように見えます。 メソッドを使うには、includeメソッドでモジュールを取り込む必要があります。

include Abc
abc

実行すると

abcdefg

と画面に現れます。 つまり、モジュールのメソッドabcを実行できたのです。

モジュールをインクルードすることにより、モジュールのメソッドを引き継ぐことができます。 通常はクラス定義の中でモジュールをインクルードしてメソッドを引き継ぎます。

class Xyz
  include Abc
  def xyz
    abc
  end
end

x = Xyz.new
x.abc
x.xyz

これを実行すると、クラスXyzでモジュールAbcがインクルードされることにより、モジュールのメソッドabcがクラスXyzのインスタンスをレシーバとして呼ぶことができるようになります。 プログラムを実行するとabcdefが2つ表示されます。

abcdef
abcdef
  • Xyzクラスのインスタンスxを生成
  • abcXyzのインスタンスメソッドになったから、x.abcによってabcdefが表示される
  • インスタンスメソッドxyzの中でインスタンスメソッドabcを呼び出せる。 def xyz〜endでは、selfが指すのはxyzが呼び出されたときのレシーバ(インスタンス)である。 そして、メソッド定義の中でメソッド呼び出し(abc)があり、そのレシーバが省略されたときは、selfをレシーバとする。 プログラムリストの最後の行で、x.xyzが呼び出されたとき、その中で呼び出されたabcのレシーバはxになる(selfはxになっている)

なお、includeはメソッド定義の中では使えません。 クラス定義の中で、メソッド定義の外でインクルードしてください。

ミックスイン

これまでのところをまとめておきましょう。

  • モジュールはインスタンスを生成できない
  • モジュールはインスタンスメソッドを定義できる
  • そのメソッドは、モジュールをインクルードしたクラスのインスタンスメソッドとして使うことができる

このことから、モジュールの目的(のひとつミックスイン)はクラスのインスタンスメソッドを提供することです。 しかしここで次のような疑問が浮かびます。 最初からクラス内でメソッドを定義すればインクルードなど必要ないのに、なぜわざわざモジュールのメソッドを取り込むのでしょうか?

モジュールは特定のクラスのためにメソッドを定義しているのではなく、複数のクラスに提供するためにメソッドを定義しているのです。 例えば、Comparableという組み込みのモジュールがあります。

  • Comparableは<=>メソッドをもとに、==>>=<<=between?clampというメソッドを定義している
  • Comparableをインクルードするクラスには<=>メソッドが定義されていなければならない

Comparableは比較可能なオブジェクトである整数、実数、文字列などに適用されています。 また、ユーザが比較可能なクラスを作るとき、<=>メソッドを定義し、Comparableをインクルードするだけで、==などの7つのメソッドが使えるようになります。

例として、江ノ電の駅のオブジェクトを作り、Comparableをインクルードしてみましょう。 駅には駅番号があり、藤沢のEN01から鎌倉のEN15までとなっています。 この駅番号の大小で駅の大小を決めることにします。

class Enoden
  include Comparable

  attr_reader :station_number, :name
  def initialize station_number, name
    @station_number = station_number
    @name = name
  end
  def <=>(other)
    self.station_number.slice(2..3).to_i <=> other.station_number.slice(2..3).to_i
  end
  def to_s
    "#{@station_number}: #{@name}"
  end
end

station_number = (1..15).map{|i| sprintf("EN%02d", i)}
name = "藤沢 石上 柳小路 鵠沼 湘南海岸公園 江ノ島 腰越 鎌倉高校前 七里ヶ浜 稲村ヶ崎 極楽寺 長谷 由比ヶ浜 和田塚 鎌倉".split(/ /)

enoshima = Enoden.new(station_number[5], name[5])
inamuragasaki = Enoden.new(station_number[9], name[9])
kamakura = Enoden.new(station_number[14], name[14])

print enoshima, "\n"
print inamuragasaki, "\n"
print enoshima < inamuragasaki, "\n"
print [kamakura, enoshima, inamuragasaki].sort.map{|a| a.to_s}, "\n"

これを実行すると次のようになります。

EN06: 江ノ島
EN10: 稲村ヶ崎
true
["EN06: 江ノ島", "EN10: 稲村ヶ崎", "EN15: 鎌倉"]

プログラム中のattr_readerメソッドは読み出しのみサポートするインスタンス変数を定義します。 次のプログラムと同等です。

def station_number
  @station_number
end
def name
  @name
end

プログラムを説明します。

  • クラスEnodenはモジュールComparableをインクルードする
  • attr_readerメソッドによって、読み出しのみ可のインスタンス変数@station_number@nameを定義
  • オブジェクトを生成する時に、引数に駅番号、駅名を与える
  • 大小比較<=>は駅番号文字列の3〜4文字目を(sliceは0から数えるので2..3となっている)整数に直して比較
  • to_sメソッドは駅番号と駅名を文字列として返す
  • 駅番号の文字列の配列を作成
  • 駅名の文字列の配列を作成
  • 江ノ島、稲村ヶ崎、鎌倉のEnodenオブジェクトを作成
  • enoshimaとinamuragasakiを(to_sを使って)プリント
  • enoshimaとinamuragasakiの大小比較。稲村ヶ崎の駅番号の方が大きいのでtrueが返る
  • kamakura, enoshima, inamuragasakiの配列を作り、ソート。 <=>が定義してあるので、ソートが可能。 to_sで駅番号、駅名の文字列に直して表示

今回の例では江ノ電だけを対象にしましたが、一般に日本の駅には駅番号(駅ナンバリング)が用いられるようになってきました。 駅ナンバリングは3字以内の英字(路線)と番号でできています。 これから、Enodenクラスをより一般的な駅を表すStationクラスに格上げすることも可能だと思います。 駅の比較は(1)英字をアルファベットで大小をつけ(2)番号で大小をつけるという2段階で実現できます

さて、具体的にComparableモジュールがクラスにインクルードされ、その実態(オブジェクト)を手に入れるのを見てきました。 比較可能なクラスは様々あり、それらすべてにComparableモジュールが適用できます。 このように、クラス共通のメソッドを定義したモジュールを、各クラスに適用することをミックスインといいます。

Comparableは既存のモジュールですが、ユーザが独自にモジュールを作り、複数のクラスに適用することもできます。 また、Comparable以外にもEnumerableという非常に有用なモジュールがあります。 このモジュールはeachメソッドのあるクラスに適用できます。 eachメソッドを作るにはブロック付きメソッドの定義を知らなければならないので、今回は解説しませんでしたが、別の記事で取り上げられればと思っています。

2023

単項マイナスと構文解析

1 minute read

単項マイナスとは 単項マイナスと括弧 括弧なし単項マイナスを許容する場合のBNF calcの場合

Raccライブラリと構文解析

3 minute read

パーサ・ジェネレータとは 少し複雑な文法 四則(加減乗除)計算のBNF Racc で実装 クラス定義、BNFの記述部分 ヘッダー、インナー、フッター コンパイルと実行 演算子の優先順位と結合における左右の優先順位 まとめ

StrScanライブラリと字句解析

less than 1 minute read

StrScanライブラリのドキュメント 字句解析とは StrScanライブラリ StrScanライブラリを使った字句解析 実例

Gem

1 minute read

lbtというgemを作って公開してみた lbtはどんなgemか ファイルの配置 lbt.gemspec Rakefile gemのビルド RubyGems.orgへのアップロード 補足・・rake/gempackagetaskサブライブラリについて

Encoding

1 minute read

文字列のエンコーディングに頭を悩ませることはほとんどなくなりました。 なぜなら、どのアプリ、システムもUTF-8を使うようになったからです。 Rubyでもエンコーディングの問題が起こることはまず無いでしょう。 ですが、今回はエンコーディングの考え方を整理してみたいと思います。

Thread

less than 1 minute read

Fiberを書いたときから、次はスレッドを書こうと思っていましたが、時間がかかってしまいました。 その理由は、期待したとおりのスレッドの効果がなかったためです。 今回はそのことを書きますが、これはRubyのスレッドの抱えている問題なのか、自分のやり方が悪いのかははっきりしていません。

Fiber

1 minute read

Fiberは「ノンプリエンプティブな軽量スレッド」とRubyのマニュアルに記載されています。

RDoc

less than 1 minute read

今回はRubyプログラムから自動的にドキュメントを作成するRDocについて書きたいと思います。 私はこのことについて、エキスパートではありません。 この記事も、初心者の体験談だと考えてください。

Back to Top ↑

2022

Ruby/GTK4

5 minute read

Ruby/Gtkの記事を先日書いたときに、「これはかなり使える」という手応えを感じたので、WordBook(Railsで作った単語帳プログラム)のGTK 4版を作りました。 プログラムは「徒然なるままにRuby」のGitHubレポジトリに置いてあります。 レポジトリをダウンロードし、ディレクトリ_example/...

Shoes – Rubyとグラフィック

5 minute read

Rubyはグラフィックについて弱い印象があります。 しかし、グラフィックはデバイスに関することなので、言語そのものには直接の関係はないはずで、あるとすればライブラリです。 今後グラフィック関係のgemが開発されることに期待しましょう。

Rails7 テスト

5 minute read

前回作ったWordbook(リソースフル)のテストを書いてみます。 RailsのテストはminitestをRails用に拡張したものです。

Rails7 モデルとデータベース

2 minute read

今回はRailsにおけるデータの作成と保存、そして変更について説明します。 そのベースになるモデルとデータベースの話から始め、appendとchangeの動作について詳しく説明します。

Rails7とBootstrap

2 minute read

一般に、HTMLは文書の構造を表し、CSSはその体裁(見栄え)を表します。 Railsは最終的にCSSを含むHTML文書を出力するので、この2つについての理解が必須です。 この記事ではとくにCSSの人気ライブラリであるBootstrapを紹介します。 BootstrapはJavascriptも含んでいます。

Rails7のインストール

2 minute read

Rubyの最も人気のあるアプリケーションであるRuby on Railsを取り上げようと思い、書き始めました。 予想してはいましたが、相当な分量になってしまいました。 そのため、何回かに分けて記事にすることにします。 また、対象となる読者のレベルをどうしようかと考えましたが、「徒然Ruby」が基礎的な内容から始ま...

GemとBundler

1 minute read

Rubyのライブラリ管理システムのRubygemsとコマンドgemおよびbundlerについて説明します。

minitest(3)モックの詳細

2 minute read

minitestについて連続して2回書いてきました。 「minitestはドキュメントが少ない」という人がいますが、私も同感です。 例えば、モックとスタブの説明も少ないです。 そこで、今回はmock.rbのソースコードを参考に、モックの私的ドキュメントを書いてみました。 あくまで私個人の考えであり、minites...

minitest(1)テストとは

2 minute read

アプリ作成の記事でminitestを使いました。 今回はminitestについて、また一般にテストについて、私の考えを書こうと思います。

public、private、protected

2 minute read

今回はメソッドの呼び出し制限ついて説明します。 呼び出し制限にはpublic、private、protectedの3つがあります。

アプリ制作、インストール、テスト

1 minute read

2023/10/29 追記:この記事は新しく書き直しました。 古い記事で使っていたGitHubのCalcが大幅にアップデートされたためです。 そこで、この記事に合うようなプログラムsimple_calcを新たに作りました。 このプログラムは本レポジトリの_example/simple_calcにあります。

case文

2 minute read

if〜elsif〜・・・〜else〜endは皆さん良く使うでしょうか? これは場合分けで良く使われる方法です。 これと同様の制御構造にcase文があります。 Cのswitch文に似ていますが、より強力な機能を持っています。 if-else-endよりも高い能力があるといえます。

Lambda

1 minute read

Procオブジェクトを生成するメソッドlambdaについて説明します。

Proc オブジェクト

2 minute read

今回はブロックを一般化したオブジェクトProcを説明します。

モジュール

1 minute read

モジュールには名前空間とミックスイン(Mix-in)の2つの機能があります。 ここではミックスインについて説明します。

Kernelモジュール

less than 1 minute read

Kernelモジュールのメソッドはどこでも使うことができます。 そのメソッドの中には便利で有用なものが多いです。

便利なメソッド

1 minute read

ここでは私が便利だと思ったメソッドを紹介します。

文字列と正規表現

3 minute read

文字列は最も使うオブジェクトのひとつです。 特にウェブ・アプリケーションでは、コンテンツだけでなくHTMLのタグやCSSを含めすべてが文字列です。 Rubyは文字列オブジェクトのメソッドが充実しており、またパターンマッチのための正規表現も充実しています。

配列

2 minute read

配列は、どのプログラミング言語にもあると思います。 複数の要素を一括して扱うことができるのが配列です。 Rubyの配列はメソッドが充実しているので、プログラムを効率的、機能的に書くのに役立ちます。

トップレベルのメソッド

1 minute read

今回はメソッド定義です。 メソッド定義はRubyの核心ですが、今回はトップレベルに限って説明します。 この限定によって、内容はかなり易しくなっています。

ブロックとイテレータ

less than 1 minute read

ブロックはRubyの特長です。 ブロックのおかげで記述が非常にすっきりと分かりやすくなります。 今回はブロックをイテレータの本体として使う方法を説明します。

整数

less than 1 minute read

ここではRubyの最も基本的なオブジェクトである整数について説明します。

Hello world

less than 1 minute read

「徒然なるままに」をネットで調べてみると、「することもなく、手持無沙汰なのにまかせてという意味」とありました。 まさに、自分の現状を言い当てた言葉。 しかも、ブログに書くネタもなかなか思いつかない日々。

Back to Top ↑