【ruby】include VS extend

include

定義

moduleで定義されたメソッドを追加

rubyは多重継承は出来ないため、includeで必要な機能を追加 通常、moduleはインスタンスメソッドを使用出来ない。 includeしたクラスのスーパークラスとして継承されるため、 moduleに定義されたインスタンスメソッドが使用出来る。

extend

定義

モジュールで定義されたメソッドをselfの特異メソッドとして追加。

例えば、class内でextendした場合はmodule内で定義したmethodは クラスメソッドとして追加される。

module ModuleTest
  def module_test
    puts "test"
  end
end

Class IncludeTest
  include ModuleTest
end

Class ExtendTest
  extend ModuleTest
end

IncludeTest.new.module_test #test
ExtendTest.module_test #test

python、ruby文字列変数展開、バッククオート

python文字列変数展開、バッククオート

pythonを使いはじめてます。 簡単ですが、自分のメモ代わりに最近調べた事 を書いておきます。(対比としてrubyのケースも書いておきます)

文字列の変数展開

# ruby
hoge = "hoge"
puts "hoge#{hoge}"  #hogehoge
#python
hoge = "hoge{}" #変数で置き換えは{}
print(hoge.format("hoge")) #hogehoge

バッククオート

#ruby
`touch hoge.txt`
#python
 import os
 cmd = "touch hoge.txt"
 os.system( cmd )

メタプログラミングRuby第五章 特異メソッド

特異メソッド

特異メソッドとは・・・特定のオブジェクトにメソッドを追加することです。

以下にコード例を示します。

hoge = "hoge"

def hoge.upcase?
    hoge.upcase #HOGE
end

モンキーバッチと違うことは?

モンキーバッチとはクラスにメソッドを追加及び修正が行えることです。

特異メソッドと同じようなコードを作成するには以下のような コードを記述することになります。

class String
  def upcase?
    if self == "monkey"
      self.upcase
    else
      self
    end
  end
end

p "monkey".upcase? #MONKEY
p "hoge".upcase? #hoge

しかし、このようなコードを記述すると 現在あるStringクラスに追加するので 間違いがあった際、String全域で間違ったコードが記述される可能性があります。

ダックタイピング

最初のコードに示した特異メソッドの対象となった hoge はStringクラスに属していますが オブジェクトとクラスは結びついていないため、 upcase? をいれたとしても元のStringクラスに 属しているメソッドを汚すことはない、

このようにRubyが用いることが出来るメソッドはその「オブジェクト」が決定します。

このような事象を 「ダックタイピング」と言います。

今回のケースで言えば、あるオブジェクトが Stringクラスのインスタンスかは気にする必要はないことです。 実際メソッドを使う際にはそのオブジェクトに紐付いているメソッドだけを着目すれば良いんです。

メタプログラミング ruby ローカル変数スコープ

ローカル変数のスコープ切り替え

ローカル変数を使う時にいつも気になるのがスコープの存在です。

一旦、スコープの切り替えタイミングは クラス定義 モジュール定義 メソッド定義 の3つです。 上記3つのことを「スコープゲート」と呼びます。

v1 = 1 #→v1

class MyClass
  v2 = 2 #→ v2
  p local_variables
  def my_method
    v3 = 3 #→ v3
    p local_variables
  end
  p local_variables #→ v2
end

obj = MyClass.new
obj.my_method.local_variables

スコープゲートを抜けるには?

クラス定義やメソッドを乗り越えて、ローカル変数を使いたい時があると思います。

クラス定義の場合

class.newを用いてインスタンスを作成して、クラス定義のスコープゲートを回避します。

v1 = 1

MyClass = Class.new do
  puts "クラス定義の中#{v1}"
end

メソッド

メソッドの際は動的メソッドを用います。

v1 = 1

MyClass = Class.new do
  puts "クラス定義の中#{v1}"
  define_method :my_method do
    "クラス定義の中#{v1}"
  end
end

フラットスコープ

スコープゲート(クラス定義・モジュール定義・メソッド)をメソッド呼び出しに変更すると スコープ変更せず、他の変数が見えることが出来ます。

これを スコープのフラット化 または フラットスコープ と呼びます。

メタプログラミング 第四章 ブロック

ブロック

ブロックは {} もしくは do endキーワードで定義出来ます。 具体例を説明します。

["1","2","3"].each do |i|
    puts i
end

# => ["1", "2", "3"]

文法書でよくある記述ですが、ブロックの前(do endキーワード) の前には 配列オブジェクト そして メソッド(eachメソッド) を用いて配列を標準出力しています。

処理の流れとしてはブロックをメソッドに渡してオブジェクトとメソッドで処理を行っています。

ここで注意したいのはブロックは単体では存在できず、メソッドの引数となることです。

またメソッドの引数を理解するには以下の例も参考になると思います。

def block_test
    yield
end

block_test do
    p  "block_test"
end
# "block_test"

これはblock_test でメソッドを定義して、 yieldキーワードで書かれたメソッドにブロックを実行した例です。

クロージャ

クロージャの定義はある関数が作られた時に状態(ローカル変数、インスタンス変数) が関数内で保持されることです。

そしてブロックはクロージャです。

次のコードを見て下さい。

def test_method
    x =  "hoge"
    yield
end

x = "hogehoge"

test_method do
    p x
end      #hogehoge

上記の例を見ると、出力されるのは “hoge"という気がしますが、 実行すると、"hogehoge"が出力されます。

これはどういうことかというと ブロックはメソッドの引数となり、 ブロックが定義された段階では xはローカル変数(hogehoge)と認識しているためです。

メタプログラミングRuby 第三章 method_missing

前回、動的メソッドを説明しました。今回は method_missingをまとめていきます。

mehod_missing

メソッド呼び出しの際に見つからなかった際に呼び出されるメソッドです。 以下にコード例を書いておきます。

class TestMethod
end

obj = TestMethod.new
obj.ghost(2) # undefined method `ghost' for #<TestMethod:0x007fab87884cc8> (NoMethodError)

method_objectは BasicObject(Objectクラスのメソッド kernelメソッドを持たない) で定義されているのでほぼ全てのオブジェクトに対応しています。

使い方

“ドキュメント”を確認すると、 ↓のように書くようです。

def method_missing(method_name [, *args [, &block]])

重要な箇所は以下の点です。 - 第一引数は method名 (method_name) - 第二引数は 引数 or block (*args blocks)

コード例を以下に記載します。

class TestMethod
  def method_missing(method,input)
    puts method
    puts input
  end
end

obj = TestMethod.new
obj.ghost(2) # ghost  2

method_missingメソッドは メソッド名を引数に持つのでメソッドに応じた処理を 記述することも可能です。

レシーバに対応するメソッドがなく、method_missingで対応した処理を ゴーストメソッド と呼ぶ。

ひとまず、三章ブログはここで一段落としておきます。

動的プロキシ等、残った重要トピックは気が向いた時に追記していきます。

次回は 第四章ブロック やります!

メタプログラミングRuby 第三章メソッド 動的メソッド

動的メソッド

前回は 「動的ディスパッチ」をメインに説明しました。

今回は本丸である動的メソッドの説明を行います。

動的メソッド定義

動的メソッドとは動的にclassとモジュールにメソッドを追加出来ます。

使い方は簡単で「define_method メソッド名」を定義してブロックの中身に 処理コードをつければOKです。

class Hello
    define_method "hello" do
        puts "hello"
    end
end

obj = Hello.new
obj.hello # "hello"

上のコード見ても何言ってるのって感じですよね。 define_methodが効力を発揮するのは同じような処理をまとめるのに 適しています。

例として、たいやきの価格を求めるコードを書いてみます。

メソッドでかく

class Taiyaki
  def anko_price
    puts 120
  end
  def cheese_price
    puts 200
  end
  def cream_price
    puts 220
  end
end

Taiyaki.new.anko_price

今回は例として「anko・cheese・cream」の3つの味の価格を求めるコードです。 味が何十種類もあったらメソッドを作るの面倒ですよね。

動的メソッド

class Taiyaki_dynamic
  def initialize
    hash = {"anko" => 120,"cheese" => 200,"cream" => 220} #①味と価格対応ハッシュ
    hash.each do |key,val|
      Taiyaki_dyanamic.price(key,val) #②メソッド作成
    end
  end

  def self.price(name,price) #クラス・メソッド
    define_method "#{name}_price" do
      puts price
    end
  end
end

Taiyaki_dynamic.new.anko_price #120
Taiyaki_dynamic.new.cheese_price #200

今回はmethod作成を self.priceというクラスメソッドにまとめています。 そして initializeメソッド(②)で、クラスをnewした際各味の価格を呼び出すメソッドを作成します。 たいやきの味が増えた場合はhash(①)を増やすだけで良いのでメソッド追加より見通しがよくなります。