[ruby-list:40798] Re: nil以外のときメソッドを呼ぶ
From:
rubikitch <rubikitch@...>
Date:
2005-04-30 05:53:08 UTC
List:
ruby-list #40798
From: Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
Subject: [ruby-list:40794] Re: nil以外のときメソッドを呼ぶ
Date: Thu, 28 Apr 2005 06:12:42 +0900
るびきちです。
> るびきちさんの Struct からの継承を参考に
> まじめに書くことにしました。
自分も必要になったので自動型変換(など)をする構造体を書いてみました。
StructWithTypeクラスで、構造体宣言時に変換関数を指定できるます。
StructWithType.new(:x, :Float_non_nil,
:y, :Integer_non_nil,
:z, :strip_XX,
:a, :String)
構造体要素への代入時に指定された関数を通します。
#### コード
class StructWithType < Struct
def self.new(*args)
keys = []
types = []
args.each_with_index do |x,i|
if i%2 == 0
keys << x
else
types << x
end
end
unless keys.length > 0 &&
types.length > 0 &&
keys.length == types.length
raise ArgumentError, "#{self}: args.length must be even"
end
klass = super(*keys)
klass.instance_eval do
@@__type_dic__ = {}
@@__keys__ = keys
keys.each_with_index{|k,i| @@__type_dic__[k] = types[i]}
end
klass
end
def initialize(*args)
args.each_with_index do |x, i|
args[i] = __convert__(@@__keys__[i], x)
end
class << self
@@__keys__.each do |k|
define_method("#{k}="){|v| self[k]=v}
end
end
super *args
end
def __convert__(k,v)
__send__(@@__type_dic__[k.to_sym],v)
end
private :__convert__
def []=(k,v)
v = __convert__(k,v)
super(k,v)
end
end
#### テスト
class TestStructWithType < Test::Unit::TestCase
def common_test
aref_test(1,"s")
@x.i = 10
@x[:s] = "S"
aref_test(10,"S")
@x["s"] = "Str"
aref_test(10,"Str")
end
def aref_test(i,s)
assert_equal(i, @x.i)
assert_equal(s, @x.s)
assert_equal(i, @x[:i])
assert_equal(s, @x[:s])
assert_equal(i, @x["i"])
assert_equal(s, @x["s"])
assert_equal([i,s], @x.collect{|x| x})
a = []
@x.each_pair{|k,v| a << [k,v]}
assert_equal([[:i,i],[:s,s]], a)
end
def test_struct
struct_class = Struct.new(:i, :s)
@x = struct_class.new(1, "s")
common_test
end
def test_struct_with_type__normal
struct_class = StructWithType.new(:i,:Integer, :s,:String)
@x = struct_class.new(1, "s")
common_test
end
def test_struct_with_type__convert
struct_class = StructWithType.new(:i,:Integer, :s,:String)
@x = struct_class.new("1", "s")
common_test
end
def test_struct_with_type__aset
struct_class = StructWithType.new(:i,:Integer, :s,:String)
@x = struct_class.new("1", "s")
@x[:i] = "10"
aref_test(10,"s")
@x['i'] = "100"
aref_test(100,"s")
@x.i = "1000"
aref_test(1000,"s")
struct_class = StructWithType.new(:a,:String, :b,:Float, :c,:Integer)
@x = struct_class.new("a", "1.1", "2")
assert_equal("a", @x.a)
assert_equal(1.1, @x[:b])
assert_equal(2, @x["c"])
end
def test_error
assert_raises(ArgumentError) { StructWithType.new() }
assert_raises(ArgumentError) { StructWithType.new(:i) }
assert_raises(ArgumentError) { StructWithType.new(:i,:Ingteger, :s) }
assert_raises(ArgumentError) { StructWithType.new(1) }
assert_raises(ArgumentError) { StructWithType.new(1,2) }
assert_raises(ArgumentError) { StructWithType.new(1,2,3) }
end
class Field < StructWithType.new(:x, :Float_non_nil,
:y, :Integer_non_nil,
:z, :strip_XX,
:a, :String)
def self.[](line)
new(*line.split(/\t/))
end
def non_empty?(x)
x && !x.empty? || nil
end
def Float_non_nil(x)
non_empty?(x) && Float(x)
end
def Integer_non_nil(x)
non_empty?(x) && Integer(x)
end
def strip_XX(x)
non_empty?(x) && x.sub(/^XX/,'')
end
def String_non_nil(x)
non_empty?(x) && x
end
end
def field_compare(x,y,z,a)
assert_equal(x, @x.x)
assert_equal(y, @x.y)
assert_equal(z, @x.z)
assert_equal(a, @x.a)
end
def test_field
@x = Field["1\t2\tXX3\t4"]
field_compare 1.0, 2, "3", "4"
@x = Field["\t\t\t"]
field_compare nil, nil, nil, nil
@x = Field["1\t\t3\t"]
field_compare 1.0, nil, "3", nil
end
end
るびきち☆
http://www.rubyist.net/~rubikitch/ ←Ruby大衆化計画@移転