class Foo
attr_accessor :name, :age, :email, :gender, :height
def initalize params
@name = params[:name]
@age = params[:age]
@email = params[:email]
.
.
.
end
これは愚かなやり方のようです。 Rubyでオブジェクトを初期化するより良い/より慣用的な方法は何ですか?
Ruby 1.9.3
def initialize(params)
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
キーを繰り返し処理して、セッターを呼び出すだけです。これは、無効なキーを渡したときにキャッチされるため、こちらをお勧めします。
class Foo
attr_accessor :name, :age, :email, :gender, :height
def initialize params = {}
params.each { |key, value| send "#{key}=", value }
end
end
foo = Foo.new name: 'Josh', age: 456
foo.name # => "Josh"
foo.age # => 456
foo.email # => nil
ジョシュアチークの回答を少し一般化して活用する
module Initializable
def initialize(params = {})
params.each do |key, value|
setter = "#{key}="
send(setter, value) if respond_to?(setter.to_sym, false)
end
end
end
class Foo
include Initializable
attr_accessor :name, :age, :email, :gender, :height
end
Foo.new name: 'Josh', age: 456
=> #<Foo:0x007fdeac02ecb0 @name="Josh", @age=456>
[〜#〜] nb [〜#〜]初期化ミックスインが使用された場合およびカスタム初期化が必要、私たちは単にsuperと呼びます:
class Foo
include Initializable
attr_accessor :name, :age, :email, :gender, :height, :handler
def initialize(*)
super
self.handler = "#{self.name} #{self.age}"
end
end
Foo.new name: 'Josh', age: 45
=> #<Foo:0x007fe94c0446f0 @name="Josh", @age=45, @handler="Josh 45">
Foo = Struct.new(:name, :age, :email, :gender, :height)
これは、完全に機能するクラスには十分です。デモ:
p Foo.class # Class
employee = Foo.new("smith", 29, "[email protected]", "m", 1.75) #create an instance
p employee.class # Foo
p employee.methods.sort # huge list which includes name, name=, age, age= etc
引数の実際のリストを明示的に指定しないのはなぜですか?
class Foo
attr_accessor :name, :age, :email, :gender, :height
def initialize(name, age, email, gender, height)
@name = name
@age = age
@email = email
@gender = gender
@height = height
end
end
このバージョンは他のバージョンよりもコード行が多くなる場合がありますが、組み込みの言語機能を活用しやすくなります(たとえば、引数のデフォルト値や、initialize
が誤ったアリティで呼び出された場合にエラーが発生します)。
Paramsのすべてのキーを使用することは正しくありません。不本意な名前を定義できます。名前のホワイトリストだと思う
class Foo
@@attributes = [:name, :age, :email, :gender, :height]
@@attributes.each do |attr|
class_eval { attr_accessor "#{attr}" }
end
def initialize params
@@attributes.each do |attr|
instance_variable_set("@#{attr}", params[attr]) if params[attr]
end
end
end
Foo.new({:name => 'test'}).name #=> 'test'
唯一の引数としてハッシュを受け取っている場合、それをインスタンス変数として保持しないのはなぜですか?値が必要なときはいつでも、ハッシュから呼び出します。インスタンス変数名を短くして、簡単に呼び出せるようにすることができます。
_class Foo
attr_reader :p
def initalize p
@p = p
end
def foo
do_something_with(@p[:name])
...
end
end
_
_@p[:name]
_がまだ長すぎる場合は、プロシージャをインスタンス変数として保存し、@p.(:name)
のような関連する値を呼び出すことができます。
_class Foo
attr_reader :p
def initialize p
@p = ->x{p[x]}
end
def foo
do_something_with(@p.(:name))
...
end
end
_
または、別の方法として、ハッシュを呼び出してキーを適用するメソッドを定義することもできます。
_class Foo
def initalize p
@p = p
end
def get key
@p[key]
end
def foo
do_something_with(get(:name))
...
end
end
_
値を設定する場合は、setterメソッドを定義し、必要に応じて無効なキーをさらにチェックできます。
_class Foo
Keys = [:name, :age, :email, :gender, :height]
def initalize p
raise "Invalid key in argument" unless (p.keys - Keys).empty?
@p = p
end
def set key, value
raise "Invalid key" unless Keys.key?(key)
@p[key] = value
end
def get key
@p[key]
end
def foo
do_something_with(get(:name))
...
end
end
_