LoginSignup
0
0

More than 5 years have passed since last update.

Ruby版automatic field initialization?

Last updated at Posted at 2018-09-27

Rubyのinitialize

init.rb
class User
  attr_reader :name, :income
  def initialize(name, income)
    @name = name
    @income = income
  end

  def real_user?
    @income > 10_000_000
  end
end

これを

init2.rb
class User
  attr_reader :name, :income
  def initialize(@name, @income)

  def real_user?
    @income > 10_000_000
  end
end

こんなふうに書きたいというのはRuby(に限りませんが)を書いていると考えたことがあるかと思います

参考:http://melborne.github.io/2013/09/27/auto-attr-set-in-ruby/

やりました

ご存知の通りRubyの自由度は高いです
なので、なんとかできないかと試してみたところ ……

auto_init.rb

class Hoge
  extend AutoInit
  def_initialize :arg1, :arg2

  def show
    p [@arg1, @arg2]
  end
end

hoge = Hoge.new 1, 2
hoge.show # => [1, 2]

できました

…… はい、見ての通りクラスマクロ的ななにかです
def initialize ではなく def_initialize という名前のクラスメソッドですね

せっかくなのでさらについでに

auto_init2.rb
class Fuga
  extend AutoInit
  def_initialize :arg1, :arg2 do |arg3|
    @arg3 = arg3.upcase
  end

  def show
    p [@arg1, @arg2, @arg3]
  end
end

fuga = Fuga.new 'hoge', 'fuga', 'piyo'
fuga.show # => ["hoge", "fuga", "PIYO"]

こんなふうにただの代入以外にもなにかしたい場合にも対応

実装

auto_init_module.rb
module AutoInit
  def def_initialize(*names)
    class_eval do
      define_method :initialize do |*args|
        names.each { |name| instance_variable_set("@#{name}", args.shift) }
        instance_exec(*args, &proc) if block_given?
      end
    end
  end
end

こんな感じです、これだけです
def_initialize実行時点でinitializeをdefine_methodで定義しています

試してみたらできたといった感じかつやや黒魔術風味なので、変なバグがありそうな気もします
今の所わかっているのは、ベースがProcであるため、変数が足りないor多い場合もエラーにならず通ってしまうことくらいですか

なんやかんやすればなんとかなるとは思いますが、ちょっとした思いつきにそこまでする気力がありませんでした …… なのでgemにしたり等の予定はないです

お付き合い、ありがとうございました

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0