diff --git a/lib/fhir/virtus/coercer.rb b/lib/fhir/virtus/coercer.rb index 0e8e9ed..c895a47 100644 --- a/lib/fhir/virtus/coercer.rb +++ b/lib/fhir/virtus/coercer.rb @@ -16,7 +16,7 @@ def call(value) klass.new(value) else coerced_value = coerce_according_to_types(value) - check_type!(coerced_value.class, value) + check_type!(coerced_value.class, coerced_value) coerced_value end end @@ -24,11 +24,17 @@ def call(value) private def virtus_coerce(type, value) - method = "to_#{type.name.downcase}" + method = "to_#{type.name.demodulize.downcase}" + coercer = Virtus.coercer[value.class] if coercer.respond_to?(method) - coercer.public_send(method, value) + begin + coercer.public_send(method, value) + rescue Coercible::UnsupportedCoercion + end + elsif is_boolean_type(type, value) + value end end @@ -43,7 +49,7 @@ def coerce_according_to_types(value) allowed_types.each do |type| result = virtus_coerce(type, value) - if !result.nil? && result.class <= type + if !result.nil? && (result.class <= type || is_boolean_type(type, result)) break end end @@ -57,9 +63,13 @@ def allowed_types end def check_type!(klass, value) - if klass != NilClass && !allowed_types.any? { |t| klass <= t } + if klass != NilClass && !allowed_types.any? { |t| klass <= t || is_boolean_type(t, value)} raise ArgumentError.new("Unexpected value with type #{klass.name}, expected one of: #{allowed_types.inspect}\n#{value.to_yaml}") end end + + def is_boolean_type(klass, value) + klass == Virtus::Attribute::Boolean && [TrueClass, FalseClass].include?(value.class) + end end end diff --git a/spec/multitype_attribute_spec.rb b/spec/multitype_attribute_spec.rb index 36cde2a..e873077 100644 --- a/spec/multitype_attribute_spec.rb +++ b/spec/multitype_attribute_spec.rb @@ -27,6 +27,11 @@ class Observation attribute :values, *Fhir::Collection[Float, Quantity, Coding] end + class Patient + include Virtus.model + attribute :multiple_birth, *Fhir::Type[Boolean, Integer] + end + it "hash in constructor" do obs = Observation.new(name: "BP", value: { @@ -74,4 +79,22 @@ class Observation obs.values.third.class.should == Coding obs.values.third.code.should == "34521" end + + it "should support multitype arrays that contain Booleans" do + pat_bool = Patient.new(multiple_birth: true) + pat_bool.multiple_birth.should == true + pat_bool.multiple_birth.class.should == TrueClass + + pat_bool.multiple_birth = "false" + pat_bool.multiple_birth.should == false + pat_bool.multiple_birth.class.should == FalseClass + + pat_int = Patient.new(multiple_birth: 2) + pat_int.multiple_birth.should == 2 + pat_int.multiple_birth.should be_an Integer + + pat_int.multiple_birth = "3" + pat_int.multiple_birth.should == 3 + pat_int.multiple_birth.should be_an Integer + end end