matzryo / mynotes

自分の学習メモ帳
0 stars 0 forks source link

メタプロ学習帳 #2

Open matzryo opened 6 years ago

matzryo commented 6 years ago

『メタプログラミングRuby 第二版』

matzryo commented 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
matzryo commented 6 years ago

includeしたモジュールは、appendされる。継承チェーンで、include元クラスより上に位置づけられる。

matzryo commented 6 years ago

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)
matzryo commented 6 years ago

メソッドを呼び出すと、レシーバーがselfになる。 Rubyプログラム開始時は、mainオブジェクトがself。トップレベルコンテキストとも言う。

irb(main):001:0> self
=> main
irb(main):002:0> self.class
=> Object

クラス、モジュール定義内(メソッド除く)は、selfはクラス、モジュール。

matzryo commented 6 years ago

3章 火曜日:メソッド

matzryo commented 6 years ago

sendして、コード実行時に引数でメソッドを決める。動的ディスパッチ。 define_mothodでコード実行時にメソッドを定義する。動的メソッド。 イントロスペクション…オブジェクトの情報を取得する?

matzryo commented 6 years ago

p57 コンポーネントの値を返すメソッドは動的メソッドで定義。 返り値は、オブジェクトをイントロスペクションして動的ディスパッチして得る。

matzryo commented 6 years ago

Ghee

変更処理は、実装。参照処理はmethod_missingでキャッチして、@subjectに聞く。@subjectはGETリクエストのレスポンス。

ゴーストメソッド(呼び出し側からはふつうに処理されているように見えるが、静的なメソッド定義がないメソッド)を補足して、他のオブジェクトに転送するオブジェクトを動的プロキシと呼ぶ。

matzryo commented 6 years ago

respond_to_missing?

matzryo commented 6 years ago

const_missing

matzryo commented 6 years ago

動的メソッドと動的ディスパッチのやり方のほうが、method_missingより影響範囲を小さくしやすそうで安心な雰囲気がする。

matzryo commented 6 years ago

method_missingでは無限ループにならないように。通常ルートを用意する。 ふつうにメソッドを書いてみて、method_missingに移動してもいい。

matzryo commented 6 years ago

method_missingでは、ancestorsにゴーストメソッドにしたいメソッド名が存在していると、そちらが適用されてしまう。

最小限のメソッドしかないクラスを使いたい。ブランクスレートを使うと安全。そのために使えるのがBasicObject。

undef_methodを使うこともできる

matzryo commented 6 years ago

まとめ。

ゴーストメソッド、動的プロキシ、ブランクスレート

matzryo commented 6 years ago

「可能であれば動的メソッドを使い、仕方がなければゴーストメソッドを使う」

matzryo commented 6 years ago

第四章

matzryo commented 6 years ago

Rubyには可視性の入れ子構造はない。スコープは区別されている。

matzryo commented 6 years ago

グローバル変数はある。

matzryo commented 6 years ago

トップレベルのインスタンス変数もある

matzryo commented 6 years ago

class,module, defでスコープが変わる。メソッドは呼び出し時に実行される。ほかは実行時。定義時。

matzryo commented 6 years ago

instance_evalを使えば、インスタンス変数にもアクセスできる。調査に便利。あと、テストのスタブ。

matzryo commented 6 years ago

ブロックはオブジェクトではない。

matzryo commented 6 years ago
~ $ 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
matzryo commented 6 years ago

メソッド定義時、引数最後、&をつけた引数は ブロックをProcにしたいこと意味する。 受け取ったブロックを、さらに渡したい場合に便利。

逆に、procを渡すときにブロックにしたいときは、メソッド実行時、引数最後に&をつける。 inject(&:+) とかは、Symbol#to_procからのブロックに変換、かな?

matzryo commented 6 years ago

procとlambdaは微妙に違う。procは、明示的にreturnすると、定義されたスコープから戻ってしまう。

matzryo commented 6 years ago

lambdaのほうが、引数チェックが厳しい。

matzryo commented 6 years ago

Procより、lambdaのほうが直感的と言われるらしい。returnの挙動、引数チェック。

matzryo commented 6 years ago

methodメソッドで、Methodオブジェクトを取れる。Metthodクラス。 Methodのスコープは所属するオブジェクト。変数のスコープが違う。

matzryo commented 6 years ago

DSLの話…難しい。

matzryo commented 6 years ago

あ、もっかい読んだら結構わかった