フィールドが設定または読み取られたときに、フィールドのセットを指定されたRubyタイプに自動的に変換する単純なクラスを作成しようとしています。
これが私がこれまでに持っているものであり、それは機能します。ただし、これはDRYではなく、私のメタプログラミングは初歩的なものです。
これを実装するためのより良い、よりクリーンな方法はありますか?
class BasicModel
def self.fields(params)
params.each do |name, type|
# Define field writers
define_method("#{name}=") {|v| @fields[name] = v}
# Define field readers
case type.name
when 'String'
define_method(name) { @fields[name].to_s }
when 'Integer'
define_method(name) { @fields[name].to_i }
when 'Float'
define_method(name) { @fields[name].to_f }
else raise 'invalid field type'
end
end
end
fields(
name: String,
qty: Integer,
weight: Float
)
def initialize
@fields = {}
end
end
# specification
m = BasicModel.new
m.name => ""
m.name = 2 => 2
m.name => "2"
m.qty => 0
m.qty = "1" => "1"
m.qty => 1
m.weight => 0.0
m.weight = 10 => 10
m.weight => 10.0
リーダーとライターの型キャストのデメリット/デメリットは何ですか?たとえば、次のコードは、リーダー(上記)ではなく、ライターでタイプキャストされます。中にも入れましcase
たdefine_method
。
class BasicModel
def self.fields(params)
params.each do |name, type|
define_method(name) { @fields[name] }
define_method("#{name}=") do |val|
@fields[name] = case type.name
when 'Integer' then val.to_i
when 'Float' then val.to_f
when 'String' then val.to_s
else raise 'invalid field type'
end
end
end
end
考えられる懸念は、決定木(例:caseステートメント)をブロックから除外する必要があることだと考えていましたdefine_method
。フィールドが設定/読み取られるたびに、ステートメントが無意味に評価されると思います。これは正しいです?