Tech Racho エンジニアの「?」を「!」に。
  • 開発

Ruby: `new`を使わずにクラスのinitializeを実行してみる

やってみたらできました(Ruby 2.6.3)。業務では使う意味がないというか使わないでください。

class Foo
  def initialize
    @a = 1
    @b = 2
  end

  def inspect
    puts @a
    puts @b
  end
end

簡単のため、上のinitializeには引数もブロックも渡していません。

以下は普通にnewした場合です。

» a = Foo.new
1
2
» a.inspect
1
2

allocatetapsendでやる

  • Class#allocateを使うと、initializeを呼び出さずにインスタンスを生成できる
  • initializeメソッドはprivateなので、send(:initialize)で無理やり呼び出す
  • tapを使ってsend(:initialize)のブロックをねじ込む
» a = Foo.allocate.tap {|i| i.send(:initialize) }
1
2
#»
» a.class
#» Foo
» a.inspect
1
2

参考: instance method Class#allocate (Ruby 2.6.0)
参考: instance method Object#tap (Ruby 2.6.0)
参考: instance method Object#__send__ (Ruby 2.6.0)

Rubyのinitializeメソッドは特殊

Rubyのinitializeメソッドは、普通のインスタンスメソッドのような形をしていながら、例外的にprivateメソッドにされます。

» Foo.initialize
NoMethodError: private method `initialize' called for Foo:Class
from (pry):14:in `__pry__'

参考: instance method Object\#initialize (Ruby 2.6.0)

initialize という名前のメソッドは自動的に private に設定されます。
docs.ruby-lang.orgより

おたより発掘

Ruby: `new`を使わずにクラスのinitializeを実行してみる

Foo.allocate.instance_eval { initialize } と言う手もありますな

2019/07/04 19:09

ありがとうございます!pryではうまく動かなかったのですが、ファイルにしたら動きました。

ファイルの場合

# not_new.rb

#!/usr/bin/env ruby -
# encoding: UTF-8

class Foo
  def initialize
    @a = 1
    @b = 2
  end

  def inspect
    puts @a
    puts @b
  end
end

p a = Foo.new
p a.inspect
$ ruby not_new.rb
1
2

1
2

(参考)pryの場合

» class Foo
»   def initialize
»     @a = 1
»     @b = 2
»   end
»
»   def inspect
»     puts @a
»     puts @b
»   end
» end
#» :inspect
» foo = Foo.allocate.instance_eval { initialize }
#» 2
» foo.inspect
#» "2"

関連記事

Rubyのオブジェクト作成方法を改変する(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。