読者です 読者をやめる 読者になる 読者になる

Ruby で使用できる単項演算子

Ruby で使用できる単項演算子を調べてみた。 Ruby では +, -, ~, ! が単項演算子と使用でき、さらに再定義することもできます。 [コード] class X def +@ p "+" end def -@ p "-" end def ~ p "~" end def ! p "!" end end def ` str p str end x = X.new +x…

Ubuntu で nokogiri をインストールする

nokogiri をインストールしようとしたらエラーになったので対処方法を覚書。 gem から nokogiri をインストールしようとしたら以下のようにエラーになりました。 $ sudo gem install nokogiri Building native extensions. This could take a while... ERROR…

Ruby で Object#instance_variable_set 等を使うときの注意

Ruby では Object#instance_variable_set を使用することで任意の名前のインスタンス変数に値を設定することができます。 class X attr_reader :name end x = X.new # @ + 変数名を渡す x.instance_variable_set(:@name, "homu") x.name # => name Object#in…

gem でインストールしようとしたら "Marshal data too short" とエラーになった

gem で mechanize をインストールしようとしたらエラーになった。 $ sudo gem install mechanize ERROR: While executing gem ... (ArgumentError) marshal data too short [解決] ~/.gem/ を削除したら解決した。 エラーになっていた理由はいまいちわからず…

Ruby 2.2 の Method#super_method

Ruby 2.2 で追加された Method#super_method を使用するとスーパークラスのメソッドを呼び出します。 class Super def homu "homu" end end class Sub < Super def homu "homuhomu" end end x = Sub.new # スーパークラスのメソッドを呼び出す x.method(:hom…

Ruby でサブクラスからスーパークラスのメソッドを明示的に呼び出す

Ruby でサブクラスで上書きしたスーパークラスのメソッドを super を使う以外で呼び出したい場合、Method#bind を使用します。 class Super def homu "homu" end end class Sub < Super def homu "homuhomu" end end x = Sub.new x.homu # => "homuhomu" # …

Ruby でクラスが継承したクラスや include したモジュールの優先順位を調べる

クラスが継承したクラスや include したモジュールの優先順位は Module#ancestors で調べることができます。 module IncludedModule end module PrependedModule end class Super end class X < Super include IncludedModule prepend PrependedModule end X…

Ruby でクラスが継承したクラスや include したモジュールの優先順位を調べる

クラスが継承したクラスや include したモジュールの優先順位は Module#ancestors で調べることができます。 module IncludedModule end module PrependedModule end class Super end class X < Super include IncludedModule prepend PrependedModule end X…

Ruby で include と継承した場合の super の優先順位

include と継承した場合、どちらが優先的に調べるのか試してみた。 [コード] module M def homu p "M#homu" end end class Base def homu p "Base#homu" end end class X < Base include M def homu p "X#homu" super end end X.new.homu [出力] "X#homu" "M…

Ruby で include した module のメソッドを呼ぶ

継承したクラスのメソッドと同じように super で呼び出すことができます。 [コード] module M def homu p "M#homu" end end class X include M def homu p "X#homu" # include した同名のメソッドを呼ぶ super end end X.new.homu [出力] "X#homu" "M#homu"

Ruby で #method_added が定義されてるモジュールを複数 mixin してみた。続き

Ruby で #method_added が定義されてるモジュールを複数 mixin してみた。続き Twitter で教えてもらって super を使えば元のメソッドを呼びだせるみたい。 [コード] module A def method_added name p "A#method_added: #{name}" end end module B def meth…

Ruby で #method_added が定義されてるモジュールを複数 mixin してみた

Ruby で #method_added が定義されてるモジュールを複数 mixin してみたらどうなるのか試してみた。 [コード] module A def method_added name p "A#method_added: #{name}" end end module B def method_added name p "B#method_added: #{name}" end end cl…

Ruby でメソッドを薄くラップする

みたいな機能が欲しかったので書いてみた。 [コード] module MethodWrapper def wrap name, &block prepend(Module.new do define_method name do super_ = proc { super() } Object.new.instance_eval do define_singleton_method :super_ do super_.() end…

Ruby の正規表現の比較で改行コードを配慮する

さて、次のようなコードの場合、改行コードを考慮せずに \n までしか返ってきません。 # マッチした文字列を取得したい "homu\nmami" =~ /^h(.*)/ && $1 # => "omu" こういう場合に改行コードも含めて欲しい場合は正規表現のリテラルに /m を追加します。 "h…

Ruby でメソッドが追加された時に呼び出されるメソッドのまとめ

大まかに .singleton_method_added、.method_added, #singleton_method_added の3つを使い分ければいい感じですかね。 [コード] class X # クラスメソッドを定義した時に呼び出される def self.singleton_method_added name p "class method : #{name}" end …

Ruby でクラスメソッドが定義された時に処理をフックする

Ruby でクラスメソッド、つまりクラスオブジェクトに対して特異メソッドが定義された時に処理をフックしたい場合は .singleton_method_added メソッドを『クラスメソッド』として定義します。 [コード] class X # インスタンスメソッドに singleton_method_a…

Ruby で特異メソッドを定義した際に処理をフックする

Ruby で特異メソッドを定義した際に処理をフックする場合、『インスタンスメソッド』に #singleton_method_added を定義します。 [コード] class X # インスタンスメソッドに singleton_method_added を追加する def singleton_method_added name p name end…

Ruby でインスタンスメソッドが定義された時に処理をフックする

インスタンスメソッドが定義された時に処理をフックしたい場合、『クラスメソッド』に #method_added を定義します。 [コード] class X # クラスメソッドに method_added を追加する def self.method_added name p name end # インスタンスメソッドを定義し…

Ruby で define_method で定義した中から super を呼び出す

次のようなコードで define_method 内から super を呼びだそうとしたらエラーになりました。 module M define_method :homu do p :superhomu # ここで元のメソッドを呼び出したかった super end end class X prepend M def homu p :homu end end X.new.homu …

Ruby のヒアドキュメントの識別子で記号を使う

ヒアドキュメントの識別子で記号を使用したい場合、文字列リテラルで定義することで記号を使用することができます。 str = <<"==EOS==" homu mami mado ==EOS== p str # => "homu\nmami\nmado\n" 便利そう。

Ruby でインスタンスメソッドを定義する手段

特定のクラスオブジェクトに対してインスタンスメソッドを定義したい場合にどういう手段があるのかまとめてみた。 クラス定義から定義する 多分普通のやり方。 単純にクラス定義時にメソッドを定義します。 class String def twice self + self end end "hom…

Ruby でトップレベルで定義したローカル変数は他のファイルからは参照されない

てっきりトップレベルで定義した変数はグローバル変数扱いで他のファイルからでも参照できるのかと思ったんですが、そういうことはないんですねー。 [a.rb] def a_func :a_func end @a = 42 a = 10 [b.rb] require_relative "./a" # メソッドやインスタンス…

今日教えてもらった Ruby の意味不明なコード

コード eval "a = 42" a = p a 出力 42 さて、これの動作が理解できる Rubyist はどれぐらいいるのだろうか。 なお、詳しい解説は某ももんが氏がしてくれるはず。

Ruby の eval でローカル変数に代入したかった

Ruby の #eval ではローカル変数を定義することはできませんが、インスタンス変数は定義する事ができるので、それを代替として使用することは可能です。 # ローカル変数定義はできない # eval "a = 42" # インスタンス変数は定義できる eval "@a = 42" p @a …

Ruby の eval メソッドでローカル変数定義はできない

次のように #eval メソッドでローカル変数を定義した場合、外からは参照することができない。 eval "a = 42" p a + a # => error: undefined local variable or method `a' for main:Object (NameError) これは expr 内のローカル変数の扱いがブロックと同じ…

Ruby で無限ループする

無限ループというと while 1 みたいな構文で行うことが多いですが、Ruby では #loop メソッドを利用する事ができます。 # ループしたい処理をブロック内に記述する # 終了したい場合は break で抜ける loop { n = rand(0..10) puts n if n == 0 break end } …

Ruby の #freeze メソッドで凍結したオブジェクトを元に戻すことはできない

知らなかったので覚書。 Ruby では #freeze メソッドを使用して、破壊的なメソッドの呼び出しを抑制する事ができます。 s = "homu" s.freeze s.upcase! # error: `upcase!': can't modify frozen String (RuntimeError) この #freeze メソッドで不変にしたオ…

Ruby の r サフィックス

Ruby で 1/2r みたいな式を見かけたので調べてみた。 2r という風に数値に r サフィックスをつけることで Rational(2/1) という風な定義になるみたい。 なので最初の式は 1 / Rational(2/1) となる。 また、このサフィックスは Ruby 2.1 から導入された模様…

Ruby の Class.new で生成したオブジェクトを受け取る変数名によって挙動が変わる

どういうことかというと大文字から始まる変数名と小文字から始まる変数名では #class で返ってくる値が違いました。 X = Class.new X.new.class # => X x = Class.new x.new.class # => #<Class:0x000000016871c0> Ruby キモい(確信</class:0x000000016871c0>

Ruby の class/module 定義式の戻り値

Ruby では class や module 定義も式なので戻り値があります。 class や module の定義式の戻り値は『最後に評価した式の結果』になります。 # 最後に評価式を返す # この場合は最後に定義したメソッドの戻り値を返す result = class X def method1 end def …

Ruby のメソッド定義式の戻り値

Ruby ではメソッドの定義(def)も式なので戻り値があります。 # メソッド定義の戻り値はメソッド名の Symbol name = def plus a, b a + b end p name # => :plus これって何かに利用できるのだろうか。 [おまけ] 式なので当然、以下のようなコードを記述す…

Ruby の break に引数を渡す

Ruby の break に引数を渡すと、そのループの戻り値になります。 data = [4, 2, 6, 7, 5, 3, 1, 8, 9] # 配列の中から最初に現れる奇数を探す result = for i in data if i % 2 != 0 break i end end result # => 7 # #each でも利用できる result = data.ea…

Ruby で #each_with_self を書いてみた

これを簡単に書けるようにしてみたくて書いてみた。 class Enumerator def with_self &block with_object self, &block end end module Enumerable def each_with_self &block each_with_object self, &block end end [1, 2, 3].each_with_self { |it, mysel…

Ruby で block 内からレシーバのオブジェクトを参照したかった

意図としては以下のように block 内で呼び出したレシーバを参照したい。 [1, 2, 3].map { |it| it + self.size # block 内でレシーバのオブジェクトを参照したい } # => [4, 5, 6] しかし、block 内のスコープでメソッドやオブジェクトを参照した場合、定義…

Ruby の Enumerable#each_with_index で index の初期値を指定する

Enumerable#each_with_index を利用すると index を付属してループする事ができます。 ["homu", "mami", "mado"].each_with_index { |it, i| puts "#{i} : #{it}" } # => 0 : homu # 1 : mami # 2 : mado index の初期値を指定してループする index の初期値…

Ruby では空白を間に挟んだ文字列リテラルは結合される

例えば、次のように空白を挟んだ文字列リテラルを連続で記述した場合、それは1つの文字列として結合されます。 # 空白を挟んで定義すると1つの文字列として結合される s = "homu" "mami" "mado" # => "homumamimado" # こういう風に書いても結合される ss = …

Ruby の Enumerable#each_with_index を自前で実装してみた

Enumerable#each_with_index の実装がどうなっているのか知りたかったんですが、どうやら C で書かれているようなので自分で Ruby を使った実装を書いてみた。 module Enumerable def each_with_index2 &block if block_given? index = 0 each { |it| block.…

Ruby で引数に配列を受け取る際の受け取り方いろいろ

Hash#map の引数の受け取り方で悩んでたんですが、つまりこういう事か。 # ブロックに配列を渡す def test &block block.call [1, 2, 3] end # 引数がひとつだけの場合はそのまま配列になる test { |a| p a # => [1, 2, 3] } # 配列の要素数よりも引数が少な…

Ruby の iolite を Hash#map に渡す場合の注意

さて、iolite を利用するとブロックを抽象的に記述する事ができるのですが、Hash#map に渡すときに注意する必要があります。 例えば、 homu = { "name" => "homu", "age" => "14"} # これを iolite を使って抽象化したい homu.map { |key, value| key + " : …

Ruby の Hash#map に渡すブロックは引数の数によって受け取り方が異なる

Hash#map は渡したブロックの引数の数によって受け取り方が異なります。 homu = { name: :homu, age: 14 } # 引数が2つの場合はキーと値が別々に渡される homu.map { |key, value| "#{key} : #{value}" } # => ["name : homu", "age : 14"] # 引数が1つの場…

Ruby の Array#* は Array#join と同等

知らなかった。 data = ["homu", "mami", "mado"] data * " + " # => "homu + mami + mado" 便利そうではあるのだけれど多用するのはなんか微妙な気もする。

Ruby で動的にメソッドを定義する

Ruby で動的にメソッドを定義したい場合、#define_method を利用する事ができます。 def create_method name define_method name do name end end create_method "homu" create_method "mami" homu # => "homu" mami # => "mami" Ruby でメタプログラミング…

Ruby でスペースや記号が含まれている名前でメソッドを定義する

Ruby でメソッドを定義する場合、名前には識別子(英数字+`)と再定義可能な演算子のみ使用する事ができます。 しかし、define_method` メソッドを使用するとスペースや記号を含んだ名前のメソッドを定義する事ができます。 class X # #define_method を使用し…

Ruby でメソッド名から Proc オブジェクトを生成する

#method を使うとレシーバのメソッドを Proc オブジェクトとして生成する事ができます。 class X def class_name "class X" end end x = X.new # メソッド名を渡すとそのメソッドを呼び出す Proc オブジェクトを返す class_name = x.method :class_name clas…

Ruby で可変長引数の Proc オブジェクトをカリー化する

可変長引数を受け取る Proc オブジェクトをカリー化する場合、#curry メソッドに対して任意の引数数を指定する事ができます。 sum = proc { |*args| args.inject :+ } # #curry に対して引数の数を渡す # 引数を2つ受け取ったら評価する p sum.curry(2).(1).…

Ruby でカリー化

Ruby では #curry で Proc オブジェクトをカリー化する事ができます。 plus = proc { |a, b, c| a + b + c } # 第一引数に 3 を渡した状態の Proc オブジェクトを返す plus3 = plus.curry.call 3 # 引数分の数が渡されたらブロックの結果が返ってくる plus3.…

Ruby でクラスのメソッドをあとから拡張する

例えば、任意のファイルのパーサをあとから実装して追加したい場合に Ruby だとどういう風に書くのがいいかなーと考えてみた。 class ParserFile def parse name "Failed" end end module ParserCPP def parse name if name =~ /\.cpp$/ "C++ file" else sup…

Ruby の #== と #=== の違い

Ruby には比較演算子 #== の他にも #=== という演算子を定義する事ができます。 ここから #=== について引用すると メソッド Object#== の別名です。 case 式で使用されます。このメソッドは case 式での振る舞いを考慮して、 各クラスの性質に合わせて再定…

Ruby の Proc オブジェクトの評価方法まとめ

Ruby の Proc オブジェクトを評価する場合、いくつかのメソッドが用意されているのでまとめてみました。 proc = Proc.new { |it| 42 + it } proc.call 1 # => 43 proc[2] # => 44 proc === 3 # => 45 proc.yield 4 # => 46 #call, #[], #===, #yield の4つの…

Ruby で複数のヒアドキュメントを記述する

次のようにして複数のヒアドキュメントを記述する事ができます。 def join *args p args args.join end p join(<<EOS1, <<EOS2, <<EOS3) homu mami EOS1 mado EOS2 saya an EOS3 # => ["homu\nmami\n", "mado\n", "saya\nan\n"] # "homu\nmami\nmado\nsaya\nan\n" 2個目のヒアドキュメントは1個目の終了ラベル以降が反映される</eos1,>…