Open matzryo opened 6 years ago
すでに P30
オブジェクトの一部がクラスの性質を持つ。 オブジェクトの一部がモジュールの性質を持つ。
モジュールにインスタンス生成機能、superclass関連を加えたのがクラス。
=> すべてのオブジェクトは#classを持つが、クラスオブジェクトしか#superclassは持たない、かな。ちょっと試す
irb(main):001:0> 1.class
=> Integer
irb(main):002:0> 1.superclass
Traceback (most recent call last):
2: from /home/matzryo/.anyenv/envs/rbenv/versions/2.5.1/bin/irb:11:in `<main>'
1: from (irb):2
NoMethodError (undefined method `superclass' for 1:Integer)
irb(main):003:0> 1.class.class
=> Class
irb(main):004:0> 1.class.superclass
=> Numeric
includeしたモジュールは、appendされる。継承チェーンで、include元クラスより上に位置づけられる。
Rubyのコードは常にオブジェクトの内部で実行されるらしい。なら、Object.ancestorsたちのメソッドは使えるのか?
irb(main):013:0> Object.ancestors
=> [Object, Kernel, BasicObject]
irb(main):014:0> Kernel.private_instance_methods.count
=> 68
irb(main):015:0> Kernel.private_instance_methods
=> [:sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :trap, :warn, :local_variables, :require, :autoload, :autoload?, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :require_relative, :eval, :iterator?, :block_given?, :catch, :throw, :loop, :gem_original_require, :URI, :binding, :trace_var, :untrace_var, :at_exit, :select, :Rational, :`, :Complex, :gem, :set_trace_func, :caller, :caller_locations, :test, :fork, :respond_to_missing?, :exit, :gets, :proc, :lambda, :sleep, :initialize_copy, :initialize_clone, :initialize_dup, :load, :syscall, :open, :printf, :print, :putc, :puts, :readline, :readlines, :p, :system, :exec, :exit!, :spawn, :abort, :rand, :srand]
irb(main):016:0> Object.private_instance_methods
=> [:DelegateClass, :irb_binding, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :trap, :warn, :local_variables, :require, :autoload, :autoload?, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :require_relative, :eval, :iterator?, :block_given?, :catch, :throw, :loop, :gem_original_require, :URI, :binding, :trace_var, :untrace_var, :at_exit, :select, :Rational, :`, :Complex, :gem, :set_trace_func, :caller, :caller_locations, :test, :fork, :respond_to_missing?, :exit, :gets, :proc, :lambda, :sleep, :initialize_copy, :initialize_clone, :initialize_dup, :load, :syscall, :open, :printf, :print, :putc, :puts, :readline, :readlines, :p, :system, :exec, :exit!, :spawn, :abort, :rand, :srand, :method_missing, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :initialize]
irb(main):017:0> BasicObject.private_instance_methods
=> [:method_missing, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :initialize]
irb(main):020:0> method_missing :hoge
Traceback (most recent call last):
2: from /home/matzryo/.anyenv/envs/rbenv/versions/2.5.1/bin/irb:11:in `<main>'
1: from (irb):20
NoMethodError (undefined method `hoge' for main:Object)
メソッドを呼び出すと、レシーバーがselfになる。 Rubyプログラム開始時は、mainオブジェクトがself。トップレベルコンテキストとも言う。
irb(main):001:0> self
=> main
irb(main):002:0> self.class
=> Object
クラス、モジュール定義内(メソッド除く)は、selfはクラス、モジュール。
3章 火曜日:メソッド
sendして、コード実行時に引数でメソッドを決める。動的ディスパッチ。 define_mothodでコード実行時にメソッドを定義する。動的メソッド。 イントロスペクション…オブジェクトの情報を取得する?
p57 コンポーネントの値を返すメソッドは動的メソッドで定義。 返り値は、オブジェクトをイントロスペクションして動的ディスパッチして得る。
Ghee
変更処理は、実装。参照処理はmethod_missingでキャッチして、@subjectに聞く。@subjectはGETリクエストのレスポンス。
ゴーストメソッド(呼び出し側からはふつうに処理されているように見えるが、静的なメソッド定義がないメソッド)を補足して、他のオブジェクトに転送するオブジェクトを動的プロキシと呼ぶ。
respond_to_missing?
const_missing
動的メソッドと動的ディスパッチのやり方のほうが、method_missingより影響範囲を小さくしやすそうで安心な雰囲気がする。
method_missingでは無限ループにならないように。通常ルートを用意する。 ふつうにメソッドを書いてみて、method_missingに移動してもいい。
method_missingでは、ancestorsにゴーストメソッドにしたいメソッド名が存在していると、そちらが適用されてしまう。
最小限のメソッドしかないクラスを使いたい。ブランクスレートを使うと安全。そのために使えるのがBasicObject。
undef_methodを使うこともできる
まとめ。
ゴーストメソッド、動的プロキシ、ブランクスレート
「可能であれば動的メソッドを使い、仕方がなければゴーストメソッドを使う」
第四章
Rubyには可視性の入れ子構造はない。スコープは区別されている。
グローバル変数はある。
トップレベルのインスタンス変数もある
class,module, defでスコープが変わる。メソッドは呼び出し時に実行される。ほかは実行時。定義時。
instance_evalを使えば、インスタンス変数にもアクセスできる。調査に便利。あと、テストのスタブ。
ブロックはオブジェクトではない。
~ $ irb
irb(main):001:0> inc = Proc.new { x }
=> #<Proc:0x000055e0b723dfc8@(irb):1>
irb(main):002:0> x = 100
=> 100
irb(main):003:0> inc2 = Proc.new { x }
=> #<Proc:0x000055e0b7268ca0@(irb):3>
irb(main):004:0> inc.call
Traceback (most recent call last):
3: from /home/matzryo/.anyenv/envs/rbenv/versions/2.5.1/bin/irb:11:in `<main>'
2: from (irb):4
1: from (irb):1:in `block in irb_binding'
NameError (undefined local variable or method `x' for main:Object)
irb(main):005:0> inc2.call
=> 100
メソッド定義時、引数最後、&をつけた引数は ブロックをProcにしたいこと意味する。 受け取ったブロックを、さらに渡したい場合に便利。
逆に、procを渡すときにブロックにしたいときは、メソッド実行時、引数最後に&をつける。 inject(&:+) とかは、Symbol#to_procからのブロックに変換、かな?
procとlambdaは微妙に違う。procは、明示的にreturnすると、定義されたスコープから戻ってしまう。
lambdaのほうが、引数チェックが厳しい。
Procより、lambdaのほうが直感的と言われるらしい。returnの挙動、引数チェック。
methodメソッドで、Methodオブジェクトを取れる。Metthodクラス。 Methodのスコープは所属するオブジェクト。変数のスコープが違う。
DSLの話…難しい。
あ、もっかい読んだら結構わかった
『メタプログラミングRuby 第二版』