Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions lib/values.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
# p.y
# #=> 0
#
module Values
class FieldError < ::ArgumentError
attr_reader :missing_fields, :unexpected_fields

def initialize(message, missing_fields=[], unexpected_fields=[])
@missing_fields, @unexpected_fields = missing_fields, unexpected_fields
super(message)
end
end
end

class Value
# Create a new value class.
#
Expand All @@ -24,7 +35,9 @@ def self.new(*fields, &block)
attr_reader(:hash, *fields)

define_method(:initialize) do |*values|
raise ArgumentError.new("wrong number of arguments, #{values.size} for #{fields.size}") if fields.size != values.size
if (fields.size != values.size)
raise Values::FieldError.new("wrong number of arguments, #{values.size} for #{fields.size}", fields[values.size..-1])
end

fields.zip(values) do |field, value|
instance_variable_set(:"@#{field}", value)
Expand All @@ -38,14 +51,13 @@ def self.new(*fields, &block)
const_set :VALUE_ATTRS, fields

def self.with(hash)
unexpected_keys = hash.keys - self::VALUE_ATTRS
if unexpected_keys.any?
raise ArgumentError.new("Unexpected hash keys: #{unexpected_keys}")
end
unexpected_fields = hash.keys - self::VALUE_ATTRS
missing_fields = self::VALUE_ATTRS - hash.keys

missing_keys = self::VALUE_ATTRS - hash.keys
if missing_keys.any?
raise ArgumentError.new("Missing hash keys: #{missing_keys} (got keys #{hash.keys})")
if unexpected_fields.any?
raise Values::FieldError.new("Unexpected hash keys: #{unexpected_fields}", missing_fields, unexpected_fields)
elsif missing_fields.any?
raise Values::FieldError.new("Missing hash keys: #{missing_fields} (got keys #{hash.keys})", missing_fields, unexpected_fields)
end

new(*hash.values_at(*self::VALUE_ATTRS))
Expand Down
25 changes: 21 additions & 4 deletions spec/values_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@
end

it 'raises argument errors if not given the right number of arguments' do
expect { Point.new }.to raise_error(ArgumentError, 'wrong number of arguments, 0 for 2')
expect { Point.new }.to raise_error do |error|
expect(error).to be_a(Values::FieldError)
expect(error.message).to eq('wrong number of arguments, 0 for 2')
expect(error.missing_fields).to contain_exactly(:x, :y)
expect(error.unexpected_fields).to be_empty
end
end
end

Expand Down Expand Up @@ -100,11 +105,19 @@ def change_color(new_color)
end

it 'errors if you instantiate it from a hash with unrecognised fields' do
expect { Money.with(:unrecognized_field => 1, :amount => 2, :denomination => 'USD') }.to raise_error(ArgumentError)
expect { Money.with(:unrecognized_field => 1, :amount => 2, :denomination => 'USD') }.to raise_error do |error|
expect(error).to be_a(Values::FieldError)
expect(error.missing_fields).to be_empty
expect(error.unexpected_fields).to contain_exactly(:unrecognized_field)
end
end

it 'errors if you instantiate it from a hash with missing fields' do
expect { Money.with({}) }.to raise_error(ArgumentError)
expect { Money.with({}) }.to raise_error do |error|
expect(error).to be_a(Values::FieldError)
expect(error.missing_fields).to contain_exactly(:amount, :denomination)
expect(error.unexpected_fields).to be_empty
end
end

it 'does not error when fields are explicitly nil' do
Expand Down Expand Up @@ -200,7 +213,11 @@ def change_color(new_color)
end

it 'raises argument error if unknown field' do
expect { p.with({ :foo => 3 }) }.to raise_error(ArgumentError)
expect { p.with({ :foo => 3 , :bar => "baz" }) }.to raise_error do |error|
expect(error).to be_a(Values::FieldError)
expect(error.unexpected_fields).to contain_exactly(:foo, :bar)
expect(error.missing_fields).to be_empty
end
end
end
end
Expand Down