今日から組込ライブラリを学習してゆく。
成果物
情報源
BasicObject
特殊な用途のために意図的にほとんど何も定義されていないクラスです。
知らなくてもよさそう。
基本的にはほぼすべてのクラスの親は Object と考えて差し支えありません。しかし、ある種のクラスを定義する際には Object クラスは持っているメソッドが多すぎる場合があります。
はあ。
例えば、 BasicObject#method_missingを利用して Proxy パターンを実装する場合にはObject クラスに定義済みのメソッドはプロクシできないという問題が発生します。このような場合に Object ではなく BasicObject から派生して問題を解決できます。
わからん! デザインパターンも学習せねば理解できない。
Object
全てのクラスのスーパークラス。オブジェクトの一般的な振舞いを定義します。
class C; end C.ancestors #=> [C, Object, PP::ObjectMixin, Kernel, BasicObject]
必ず以下が親になっているっぽい。
Object ↑ PP::ObjectMixin ↑ Kernel ↑ BasicObject
このクラスのメソッドは上書きしたり未定義にしない限り、すべてのオブジェクトで使用することができます。
いくつか抜き出す。
clone
/dup
freeze
,frozen?
instance_of?(klass)
/is_a?(mod)
,kind_of?(mod)
ni?
tap
,then
ARGF
,ARGV
,ENV
- メタ
clone
/dup
オブジェクトを複製する。
メソッド | 概要 | taint | freeze | 特異メソッド等 |
---|---|---|---|---|
dup |
浅いコピー(shallow copy ) |
⭕ | ❌ | ❌ |
clone |
深いコピー(deep copy ) |
⭕ | ⭕ | ⭕ |
taint
はself
を返す。Ruby3.2で削除予定。
class C; end c1 = C.new c2 = c1.clone
class C; end c1 = C.new c2 = c1.dup
freeze
, frozen?
オブジェクトを凍結(内容の変更を禁止)します。
もしやオブジェクトに定義を追加することを禁止できる?
いったん凍結されたオブジェクトを元に戻す方法はありません。
マジか。
凍結されるのはオブジェクトであり、変数ではありません。代入などで変数の指すオブジェクトが変化してしまうことは freeze では防げません。 freeze が防ぐのは、 `破壊的な操作' と呼ばれるもの一般です。変数への参照自体を凍結したい場合は、グローバル変数なら Kernel.#trace_var が使えます。
つまりfreeze
は値を不変(イミュータブル)にできるってこと?
s = 'ABC' s.replace('xyz') p s #=> "xyz" s.freeze s.replace('abc') #=> can't modify frozen String: "xyz" (FrozenError)
freeze
は破壊的操作を防げる。でも、代入による変更は防げない。
s = 'ABC' s.freeze s = 'xyz' p s #=> "xyz"
クラス定義の追加とかも禁止できるっぽい。
class C; end C.freeze class C def m; :m; end #=> can't modify frozen class: C (FrozenError) end
freeze
をデフォルトにしたかった。コードすべてを読まないとどこで改ざんされるかわからなくなってしまう。ダッグタイピング的には改ざんできたほうが嬉しいのかもしれないけれど、大規模なコードになるとバグる可能性が常にある。デフォルトでfreeze
にするコマンド引数とかあればよかったのに。シバンに引数セットすれば安全なコードが書ける。ダッグタイピングしたければその引数を外すだけ。とかだったらよかったのになぁ。
frozen?
は凍結されていたら真を返す。
class C; end p C.frozen? #=> false C.freeze p C.frozen? #=> true
instance_of?(klass)
/is_a?(mod)
,kind_of?(mod)
instance_of?
はオブジェクトがklass
のインスタンスであるなら真を返す。
class C; end class D; end C.new.instance_of?(C) #=> true C.new.instance_of?(D) #=> false class E < D; end E.new.instance_of?(D) #=> false
is_a?
, kind_of?
はオブジェクトが指定されたmod
かそのサブクラスのとき真を返す。また、オブジェクトがmod
をMixinしていたら真を返す。
class C; end class D; end C.new.is_a?(C) #=> true C.new.is_a?(D) #=> false class E < D; end E.new.is_a?(D) #=> true
module M; end class C include M end class D; end C.new.is_a?(M) #=> true D.new.is_a?(M) #=> false
ni?
レシーバがnil
なら真を返す。
class C; end c = C.new c.nil? #=> false c = nil c.nil? #= true
tap
, then
self
を引数としてブロックを評価する。メソッドチェーンを作る。tap
はself
を返す。then
はブロックの結果を返す。
(1..10) .tap {|x| puts "original: #{x}" } .to_a .tap {|x| puts "array: #{x}" } .select {|x| x.even? } .tap {|x| puts "evens: #{x}" } .map {|x| x*x } .tap {|x| puts "squares: #{x}" }
3.next.then {|x| x**x }.to_s # => "256" "my string".yield_self {|s| s.upcase } # => "MY STRING"
require 'open-uri' require 'json' construct_url(arguments). yield_self {|url| URI(url).read }. yield_self {|response| JSON.parse(response) }
ブロックなしで呼び出されたときは Enumerator を返します。例えば条件によって値を捨てるのに使えます。
# 条件にあうので何もしない 1.yield_self.detect(&:odd?) # => 1 # 条件に合わないので値を捨てる 2.yield_self.detect(&:odd?) # => nil
&:odd?
はたぶんodd?
が奇数なら真を返すメソッドなのだろう。そして&
はブロック引数をあらわし、:
はシンボルか。見慣れない指定の仕方。
ARGF
, ARGV
, ENV
定数 | 概要 |
---|---|
ARGF |
引数 (なければ標準入力) で構成される仮想ファイル。(詳細は ARGF、ARGF.class を参照)。 |
ARGV |
Ruby スクリプトに与えられた引数を表す配列。 |
ENV |
環境変数を表す (擬似) 連想配列 (詳細は ENV を参照)。 |
メタ
実装の確認に使える。たとえばextend
したときどのオブジェクトに追加されたのかを確認できる。
- public_method[s]
- protected_method[s]
- private_method[s]
class C def m; end end C.new.public_mehods #=> すべて C.new.public_mehods false #=> 自分で定義したものだけ
特異クラス/特異メソッド。
- singleton_class
- singleton_method[s]
所感
ほかにも有用なメソッドや定数はあるが、ひとまずこれだけ。
対象環境
- Raspbierry pi 4 Model B
- Raspberry Pi OS buster 10.0 2020-08-20 ※
- bash 5.0.3(1)-release
- Ruby 3.0.2
$ uname -a Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux