返ってくる値を真偽値に変換する
例えば、match
を使用して、正しいかどうかの確認だけをしたいと思います。
REG_EXP = /foo/ x = 'foo' x.match(REG_EXP) => #<MatchData "foo"> x.match('bar') => nil
通常だと判定した結果が返ってきます。
これを真偽値に変換します。
!!(x.match(REG_EXP)) => true !!(x.match('bar')) => false
以上です。
rspecでprivate methodを呼び出したい時の方法
privateメソッドを実行したいけど、できないよ!って場合の方法です。
send
を使えばできます。
class Foo private def foo puts 'hoge' end end x = Foo.new x.send(:foo) hoge => nil x.foo NoMethodError: private method `foo' called for #<Foo:0x007fa279135010>
こうなるので、send
を使ってメソッドを呼び出せば、private methodもテストできます。
これは便利だ。
オブジェクトのインスタンス変数名とメソッド一覧の取得方法
タイトルの通りです。
オブジェクトのインスタンス変数名とメソッド一覧の取得方法を探っていきます。
まずはインスタンス変数名からです。
インスタンス変数名の取得方法
instance_variables
class Foo def initialize @foo = 1 @bar = 2 end end x = Foo.new x.instance_variables => [:@foo, :@bar]
このメソッドはインスタンス変数を配列で返してくれます。
メソッド一覧の取得
メソッド名 | 取得できるメソッド |
---|---|
Object#methods | オブジェクトの持つプライベートメソッド以外 |
Object#public_methods | オブジェクトの持つパブリックメソッド |
Object#private_methods | オブジェクトの持つプライベートメソッド |
Object#protected_methods | オブジェクトの持つプロテクテッドメソッド |
Object#singleton_methods | オブジェクトの持つ特異メソッド |
class Foo def foo; end private def bar; end protected def baz; end end class Bar < Foo def foo_b; end private def bar_f; end protected def baz_f; end end x = Foo.new y = Bar.new def x.foo; end x.methods => [:foo, :baz, :to_yaml, :to_yaml_properties, ... x.public_methods => [:foo, :to_yaml, :to_yaml_properties, :pry, x.private_methods => [:bar, :DelegateClass, :default_src_encoding, :sprintf, x.protected_methods => [:baz] y.methods => [:foo_f, :baz_f, :foo, :baz, y.public_methods => [:foo_f, :foo, :to_yaml, :to_yaml_properties, y.private_methods => [:bar_f, :bar, :DelegateClass, :default_src_encoding, y.protected_methods => [:baz_f, :baz] x.singleton_methods => [:foo]
ちなみに特異メソッドのみを呼び出すのは、methods
からでも呼び出せます。
その場合は、引数にfalse
を渡せばいいです。
参考
instance method Object#methods (Ruby 2.3.0)
x.methods(false) => [:foo]
まとめ
メソッド呼び出し方法を知っておけば、デバック時に役立つ可能性が生まれます。
以上です。
rubyのthreadについて
スレッドは同じプロセス上でメモリを共有しつつ、処理を並列に実行することができます。
スレッドを用いることで、単独で時間がかかる処理を早くすることができる可能性があります。
スレッドの生成
スレッドを作成し、処理を実行するには、Thread.fork/Thread.new/Thread.startを使用します。
下記は複数ファイルの行数を出力する例です。
files = %w(ruby.rb test.rb) threads = files.map do |file| Thread.fork do num = File.readlines(file).length "#{file}: #{num}" end end p threads.map(&:value)
変数の扱い
スレッドは同じプロセス上のスレッドとメモリを共有します。
for item in %w(foo bar baz) Thread.fork do sleep 1 puts item end end (Thread.list - [Thread.current]).each &:join =>baz =>baz =>baz
メモリが共有されているので、最後に当たったものを参照しています。
他のスレッドと共有したくない値は、ブロックの仮引数として受け取るようにしましょう。
for item in %w(foo bar baz) Thread.fork item do |value| sleep 1 puts value end end (Thread.list - [Thread.current]).each &:join =>foo =>baz =>bar
以上です。
eval族
evalについてです。
|メソッド名|動作| |Kernel.#eval|selfが呼び出された式を評価する| |Module#class_eval|レシーバのクラスをselfとして式を評価する| |Module#module_eval|レシーバのモジュールをselfとして式を評価する| |Basic#Object#instace_eval|レシーバのオブジェクトをselfとして式を評価する|
Kernel.#eval
foo = 'bar' eval 'foo' => "bar"
evalとBindingオブジェクト
Bindingオブジェクトを使うことで、コンテキストに名前がないものでも評価されるようになります。
class Foo def initialize @foo = 'foo' end def bar local_val = 'bar' binding end end x = Foo.new y = x.bar eval "@foo", y => 'foo' eval "local_val", y => 'bar'
ただし、initializeにbindingをさしてもうまくいきませんでした。
eval "@foo", y TypeError: wrong argument type String (expected binding)
以上です。
参考
includeとprependで読み込む順番の確認
includeとprependで読み込む順番を確認していきたい思います。
moduleの複数読み込みをした場合に、どのような順番で読み込まれるのかを確認していきます。
includeの順番に依存
何も考えないでincludeしていく場合は、読み込む順番に依存していることがわかります。
module Foo def foo puts 'foo' end end module Bar def foo puts 'foo bar' end end class Baz include Foo include Bar end Baz.ancestors => [Baz, Bar, Foo, Object, Kernel, BasicObject] x = Baz.new x.foo =>foo bar
ancestorsで確認しても、[Baz, Bar, Foo, Object, Kernel, BasicObject]
下から読み込みされていることがわかります。
prependで優先的に読む
prependで試してみます。
module Foo def foo puts 'foo' end end module Bar def foo puts 'foo bar' end end class Baz prepend Foo include Bar end Baz.ancestors => [Foo, Baz, Bar, Object, Kernel, BasicObject] x = Baz.new x.foo =>foo
これを見るとBazより先に読み込まれていることがわかります。
ということは、同じメソッドを用意したらどうなるか確認してみます。
module Foo def foo puts 'foo' end end module Bar def foo puts 'foo bar' end end class Baz prepend Foo include Bar def foo puts 'foo baz' end end Baz.ancestors => [Foo, Baz, Bar, Object, Kernel, BasicObject] x = Baz.new x.foo =>foo
Fooの方が先にあるので、当然moduleのFooのmethodが読まれます。
まとめ
既存のメソッドをオーバーライドする・優先的に読む必要があるのなら、prependを使うのがいいでしょう。
lambdaについて
lambaはProcオブジェクトの別の書き方です。
Procオブジェクトやブロックに関してはこちらの記事をみてください。
ブロックについて - mikami's engineer diary
x = lambda { 'foo' } x.call =>foo
lambdaは->
でも書けるので上はこのように書き直せます。
x = -> { 'foo' } x.call => "foo"
railsだとこっちの方が見かけると思います。
ブロックを渡していたんですね。
引数も渡せます。
x = -> (x) { x + 100 } x.call(5) => "105"
Procオブジェクトとの挙動の違いはあります。
詳細はこちらをご覧ください。
クラスメソッドについて
クラスメソッドの定義を見ていきます。
class Hoge def self.hello puts 'hoge' end end Hoge.hello =>hoge
これは標準的な書き方だと思います。
この時のself
はクラス自身(ここではHoge)を見ています。
class Hoge def Hoge.hello puts 'hoge' end end Hoge.hello =>hoge
Hoge
に対しての特異メソッド
になります。
これが成り立つのならば下も成り立ちます。
class Hoge end def Hoge.hello puts 'hello' end Hoge.hello
クラスメソッドは、クラスオブジェクトに対しての特異メソッド
ということです。
classを動的に作成する
こんなやり方をすると可読性がなくて、よくないと思うのですが、紹介します。
klass = nil FooClass = Class.new do |f|←ブロック内で定義する klass = f f == self def hello puts 'hello' end end←ここで定義終了 => FooClass x = klass.new => #<FooClass:0x007ff5330a89c8> x.hello => :hello
以上。