:pぴー.sendせんど(:pぴー, :pぴー)

mokoaki
mokoriso@gmail.com

2017/07/22

Module クラス

Ruby技術者認定試験の書籍写経メモ

機能をひとまとめにした モジュール の為のクラス

モジュールを使った機能の追加

Mix-in の辺りに書いてあります

定数に関するメソッド

Module.constants
レシーバ.constants
レシーバ.const_defined?
レシーバ.const_get
レシーバ.const_set
レシーバ.remove_const
レシーバ.const_missing

Module.constants メソッド

その時点で定義されている定数一覧を取得する

Module.constants
=> [:Integer, :Float] # 大量の配列

constants メソッド

特定のクラスやモジュールで定義されている定数の一覧を取得する

Regexp.constants
=> [:IGNORECASE, :EXTENDED, :MULTILINE, :FIXEDENCODING, :NOENCODING]

const_defined? メソッド

特定のクラスやモジュールで、指定した定数が定義されているかどうか

Regexp.const_defined?(:IGNORECASE)
=> true

Regexp.const_defined?(:HAGE)
=> false

const_get メソッド

特定のクラスやモジュールの定数の値を取り出す

Regexp.const_get(:IGNORECASE)
=> 1

Regexp::IGNORECASE
=> 1

const_set メソッド

特定のクラスやモジュールの定数の値を設定する

Regexp.const_get(:HAGE)
=> NameError: uninitialized constant Regexp::HAGE

Regexp::HAGE
=> NameError: uninitialized constant Regexp::HAGE

Regexp.const_set(:HAGE, true)

Regexp.const_get(:HAGE)
=> true

Regexp::HAGE
=> true

remove_const メソッド

クラスメソッドから自らの定数を消させる

class Moko
  HAGE = true

  class << self
    def remove
      remove_const(:HAGE)
    end
  end
end

Moko.const_get(:HAGE)
=> true

Moko::HAGE
=> true

Moko.remove
=> true

Moko.const_get(:HAGE)
=> NameError: uninitialized constant Moko::HAGE

Moko::HAGE
=> NameError: uninitialized constant Moko::HAGE

sendメソッドから無理やり定数を消す

class Moko
  HAGE = true
end

Moko.const_get(:HAGE)
=> true

Moko::HAGE
=> true

Moko.send(:remove_const, :HAGE)
=> true

Moko.const_get(:HAGE)
=> NameError: uninitialized constant Moko::HAGE

Moko::HAGE
=> NameError: uninitialized constant Moko::HAGE

const_missing メソッド

class Moko
  class << self
    def const_missing(const_name)
      p const_name
      return 'hage-!'
    end
  end
end

Moko::Hoge
:Hoge
=> "hage-!"

メソッドを設定する

インスタンスメソッドの一覧を取得

instance_methods
public_instance_methods
protected_instance_methods
private_instance_methods

オブジェクトが持つインスタンスメソッドインスタンス変数

メソッドの可視性の変更

public
protected
private

メソッドの可視性

アクセッサメソッド

attr_reader
attr_writer
attr_ccessor
attr

アクセッサメソッド

メソッドの別名を定義する

alias_method

正直、その違いだけならどっちでもいいや!と思う

class Moko1
  def zura
    p true
  end

  alias hage zura
  # alias :hage :zura #これでもいい
end

Moko1.new.hage
=> true
class Moko2
  def zura
    p true
  end

  alias_method :hage, :zura
  # alias_method 'hage', 'zura' # これでもいい
end

Moko2.new.hage
=> true

こんな風に使うんかねー?

class Oyaji
  def method1
    'oyaji'
  end
end

class Moko < Oyaji
  alias_method :original_method, :method1

  def method1
    'moko ' + original_method
  end
end

Moko.new.method1
=> "moko oyaji"

評価する

eval 現在のコンテキストで評価します
module_eval 指定したモジュールのコンテキストで評価します
class_eval 指定したクラスのコンテキストで評価します
instance_eval 指定したオブジェクトのコンテキストで評価します

module_evalメソッドはclass_evalの別名です

文字列をRubyコードとして評価する

eval('Regexp')
=> Regexp
end
Regexp.class_eval('IGNORECASE')
=> 1
a = /moko/i

a.instance_eval('inspect')
=> "/moko/i"

ブロックをクラス定義やモジュール定義の中のコードであるように実行する

例えばこの例はインスタンスメソッドになる

//.hage
=> NoMethodError: undefined method 'hage'

Regexp.class_eval do
  def hage
    'hage-!'
  end
end

//.hage
=> "hage-!"

例えばこの例は特異メソッドになる

a = //

a.instance_eval do
  def hage
    'hage-!'
  end
end

a.hage
=> "hage-!"

//.hage
=> NoMethodError: undefined method 'hage' for //:Regexp

引数を渡して評価したい

module_exec 指定したモジュールのコンテキストで評価します
class_exec 指定したクラスのコンテキストで評価します
instance_exec 指定したオブジェクトのコンテキストで評価します

module_execメソッドはclass_execの別名です

ブロックをクラス定義やモジュール定義の中のコードであるように実行する with 引数

こんな使い方はしないと思います、無理矢理な例でスンマセン

//.hage
=> NoMethodError: undefined method 'hage'

Regexp.class_exec(10) do |num|
  @@test = num

  def hage
    "hage#{@@test}"
  end
end

//.hage
=> "hage10"
a = //

a.instance_exec(10) do |num|
  @test = num

  def hage
    "hage#{@test}"
  end
end

a.hage
=> "hage10"

//.hage
=> NoMethodError: undefined method 'hage' for //:Regexp

クラス変数を扱う

class_variables
class_variable_defined?
class_variable_get
class_variable_set
remove_class_variable

class_variables メソッド

クラス変数の一覧を取得

class Moko
  @@homo = true
  @@hage = true
end

Moko.class_variables
=> [:@@homo, :@@hage]

class_variable_defined? メソッド

指定されたクラス変数が定義されているかどうか

class Moko
  @@homo = true
  @@hage = true
end

Moko.class_variable_defined?(:@@homo)
=> true

Moko.class_variable_defined?(:@@test)
=> false

class_variable_get メソッド

指定されたクラス変数を取得

class Moko
  @@homo = true
  @@hage = true
end

Moko.class_variable_get(:@@homo)
=> true

Moko.class_variable_get(:@@test)
=> NameError: uninitialized class variable @@test in Moko

class_variable_set メソッド

指定されたクラス変数を設定

class Moko
  @@homo = true
  @@hage = true
end

Moko.class_variable_get(:@@test)
=> NameError: uninitialized class variable @@test in Moko

Moko.class_variable_set(:@@test, true)

Moko.class_variable_get(:@@test)
=> true

Moko.class_variables
=> [:@@homo, :@@hage, :@@test]

remove_class_variable メソッド

指定されたクラス変数を取り除く

class Moko
  @@homo = true
  @@hage = true
end

Moko.class_variables
=> [:@@hage, :@@homo]

Moko.remove_class_variable(:@@homo)

Moko.class_variables
=> [:@@hage]

モジュールの機能を取り込む

include
extend
included
extended
include?
included_modules
autoload
autoload?

include メソッド

extend メソッド

included メソッド

module Module1
  class << self
    def included(object)
      p "#{object} #{object.class}"
    end
  end
end

class Moko
  include Module1
end
=> "Moko Class"

extended メソッド

モジュールがextendされた後に自動的に実行されるメソッド

module Module1
  class << self
    def extended(object)
      p "#{object} #{object.class}"
    end
  end
end

class Moko
  extend Module1
end
=> "Moko Class"

include? メソッド

モジュールがincludeされているかどうか

module Module1
end

class Moko
  include Module1
end

Moko.include?(Module1)
=> true

included_modules メソッド

module Module1
end

class Moko
  include Module1
end

Moko.included_modules
=> [Module1, Kernel]

autoload メソッド

未定義の定数が参照された時に移動的に特定のファイルをロードするように設定する

この段落は “./module.rb” が存在する、という前提で書かれています

module Module1
  def hage
    'hage-!'
  end
end
class Moko
  autoload(:Module1, './module.rb')
  include Module1
end

Moko.new.hage
=> "hage-!"

autoload? メソッド

指定した定数がオートロード対象でまだロードされていない場合はそのパスを、オートロード後やオートロード対象ではない時にはnilを返す

class Moko
  p autoload?(:Module1)
  autoload(:Module1, './module.rb')
  p autoload?(:Module1)
end
=> nil
=> "./module.rb"

Moko.new.hage
=> NoMethodError: undefined method 'hage'

class Moko
  p autoload?(:Module1)
  include Module1
  p autoload?(:Module1)
end
=> "./module.rb"
=> nil

Moko.new.hage
=> "hage-!"
class Moko
  def self.const_missing(const_name)
    p "const_missing #{const_name}"
  end

  autoload(:Module1, './module.rb')

  include Module1
  include Module2
end
=> "const_missing Module2"

Moko.new.hage
=> "hage-!"

モジュール関数

まずは、モジュール関数とはなんぞや?

組み込みライブラリのMathモジュールは、モジュールのメソッドを直接呼んでもいいし、includeしてメソッドを呼び出してもいい。こういうメソッドの事をモジュール関数といいます

Math.sqrt(2)
=> 1.4142135623730951

# sqrt(2)
# => NoMethodError: undefined method 'sqrt'

include Math
=> Object

sqrt(2)
=> 1.4142135623730951

モジュール関数はどうやって作る?

まずは、includeしてからmethod_nameを呼び出すには 普通にこうしますよね

module ModuleName
  def method_name
    true
  end
end

include ModuleName

method_name
=> true

ModuleName.method_name でモジュールのメソッドをインスタンス化することなく呼び出したいなら

module ModuleName
  class << self
    def method_name
      true
    end
  end
end

ModuleName.method_name
=> true

上記の2つを同時にやりたいなら こうですね

module ModuleName
  class << self
    def method_name
      true
    end
  end

  def method_name
    true
  end
end

ModuleName.method_name
=> true

# method_name
# => NameError: undefined local variable or method `method_name'

include ModuleName

method_name
=> true

DRYじゃねえ!これは絶対失敗だ

module_function メソッド

モジュール関数を作る

これだけ!

module ModuleName
  module_function

  def method_name
    true
  end
end

ModuleName.method_name
=> true

# method_name
# NameError: undefined local variable or method 'method_name'

include ModuleName

method_name
=> true

Module.ancestors メソッド

module OyajiModule1
end

module OyajiModule2
end

class Oyaji
  include OyajiModule1
  extend  OyajiModule2
end

module MokoModule1
end

module MokoModule2
end

class Moko < Oyaji
  include MokoModule1
  extend  MokoModule2
end

Moko.ancestors
=> [Moko, MokoModule1, Oyaji, OyajiModule1, Object, Kernel, BasicObject]