diff --git a/lib/primalize/single.rb b/lib/primalize/single.rb index 286f5ac..5b69c76 100644 --- a/lib/primalize/single.rb +++ b/lib/primalize/single.rb @@ -85,6 +85,10 @@ def primalize primalizer, &coerce Primalizer.new(primalizer, &coerce) end + def validate type, &validation + Validation.new(type, validation) + end + def type_mismatch_handler= handler @type_mismatch_handler = handler end @@ -400,5 +404,28 @@ def inspect "any#{@types.empty? ? nil : params}" end end + + class Validation + def initialize type, validation + @type = type + @validation = validation + end + + def coerce value + if @type.respond_to? :coerce + @type.coerce value + else + value + end + end + + def === value + @type === value && @validation.(coerce(value)) + end + + def inspect + "validate(#{@type.inspect})" + end + end end end diff --git a/spec/primalize/single_spec.rb b/spec/primalize/single_spec.rb index 6256b68..810a531 100644 --- a/spec/primalize/single_spec.rb +++ b/spec/primalize/single_spec.rb @@ -368,5 +368,18 @@ def order_serializer_class.inspect CSV end end + + it 'validates attributes' do + my_serializer = Class.new(Single) do + attributes( + number: validate(integer(&:to_i)) { |value| value.between? 0, 10 }, + ) + end + + expect(my_serializer.new(double(number: 10)).call).to eq(number: 10) + expect(my_serializer.new(double(number: nil)).call).to eq(number: 0) + expect(my_serializer.new(double(number: '0')).call).to eq(number: 0) + expect { my_serializer.new(double(number: 12)).call }.to raise_error TypeError + end end end