やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

組込ライブラリ(Module)

 モジュールのクラス。

成果物

情報源

Module

特異メソッド

constants nesting new used_modules

インスタンスメソッド

< <= <=> === > >= alias_method ancestors 
attr attr_accessor attr_reader attr_writer 
autoload autoload? class_eval class_variable_defined? 
class_variables const_defined? const_get const_missing 
const_set const_source_location constants define_method 
freeze include include? included_modules inspect instance_method 
instance_methods method_defined? module_eval name 
prepend private_class_method private_instance_methods 
private_method_defined? protected_instance_methods 
protected_method_defined? public_class_method 
public_instance_method public_instance_methods 
public_method_defined? remove_class_variable 
remove_method to_s undef_method

privateメソッド

append_features class_exec class_variable_get class_variable_set 
deprecate_constant extend_object extended included method_added 
method_removed method_undefined module_exec module_function 
prepend_features prepended private private_constant protected 
public public_constant refine 
remove_const ruby2_keywords singleton_class? using

constants

このメソッドを呼び出した時点で参照可能な定数名の配列を返します。

class C
  FOO = 1
end
p C::FOO           #=> 1 FOOは参照可能
p Module.constants #=> [...] 内にFOOがない
p Module.constants.include? :FOO  #=> false
p Module::constants.include? :FOO #=> false

 いやいや、何でFOOがないんだよ。constantsメソッドを呼び出す前にちゃんと参照できているはずなのに。使えねー。

 と思って定義内でやってみたらFOOがあった。

class C
  FOO = 1
  p Module.constants.include? :FOO #=> true
end

 どゆこと? 特異メソッドだから?

nesting

このメソッドを呼び出した時点でのクラス/モジュールのネスト情報を配列に入れて返します。

module Foo
  module Bar
    module Baz
      p Module.nesting #=> [Foo::Bar::Baz, Foo::Bar, Foo]
    end
  end
end
p Module.nesting #=> []

 やはり定義外だと空になる。constantsと同じで定義内でのみ有効らしい。

new

名前の付いていないモジュールを新しく生成して返します。

ブロックが与えられると生成したモジュールをブロックに渡し、モジュールのコンテキストでブロックを実行します。

mod = Module.new
mod.module_eval {|m|
  # ...
}
mod

 そんなことができたのか。でも使わなそう。

最初に名前が必要になったときに名前が決定します。モジュールの名前は、そのモジュールが代入されている定数名のいずれかです。

m = Module.new
p m               # => #<Module 0lx40198a54>
p m.name          # => nil   # まだ名前は未定
Foo = m
# m.name          # ここで m.name を呼べば m の名前は "Foo" に確定する
Bar = m
p m.name          # "Foo" か "Bar" のどちらかに決まる

 私の環境ではFooになった。というか、なんでどちらかなの? 曖昧なので罠になりそう。

used_modules

現在のスコープで using されているすべてのモジュールを配列で返します。配列内のモジュールの順番は未定義です。

module A
  refine Object do
  end
end

module B
  refine Object do
  end
end

using A
using B
p Module.used_modules
#=> [B, A]

 まずusingってなんだよ。refineってなんだよ。

 さっぱりわからん。

 refineは以下の用途らしい。

既存の機能を局所的に修正したい場合などに用いる事ができます。

 でも、なんでそんなことをしたがるのかよくわからん。ややこしくなるばかりでは?

ancestors

クラス、モジュールのスーパークラスとインクルードしているモジュールを優先順位順に配列に格納して返します。

 継承リスト。同一名メソッドを呼び出すときのレシーバを決定する。先頭ほど優先度が高い。

attr, attr_accessor, attr_reader, attr_writer

メソッド ゲッター セッター
attr
attr_reader
attr_writer
attr_accessor

 attrの第二引数にtrueを渡してセッターも加えることができるが、非推奨。

class C
  attr :name, :age
end
class C
  attr_reader :name, :age
end
class C
  attr_writer :name, :age
end
class C
  attr_accessor :name, :age
end

 定義されるゲッターは以下。

def name
  @name
end

 定義されるセッターは以下。

def name=(val)
  @name = val
end

 これこそClassクラスのメソッドかと思っていたんだが。Moduleクラスのメソッドということは、module内でも同じように定義できるはず。でも、ModuleはClassと違ってインスタンス化できない。ほかのクラスにMixinしないと使えない。なので基本的にModuleでは使わずClassで使うのだろう。だったらなんでModuleクラスに定義されているのか疑問。ModuleクラスはClassクラスのスーパークラスらしいけど、どうせModuleで使わないならClassクラスで定義すればよかったのでは? なのにModuleクラスで定義されているということは、Moduleでもattrしたいときがあるってことだと思う。

 moduleでもattrできるはず。と思ってやってみたら、エラーになった。

module A
  attr_accessor :name
end
class B
  include A
end
b = B.new
p b.name #=> nil
b.name = 'ytyaru'
B.b.name #=> undefined method `b' for B:Class (NoMethodError)

 なんでや。

所感

 他にもメタいメソッドが色々あるが、今回はここまで。

対象環境

$ uname -a
Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux