Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hashie::Extensions::IgnoreRequired mixin for ignoring required constraints #235

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/hashie.rb
Expand Up @@ -12,6 +12,7 @@ module Extensions
autoload :Coercion, 'hashie/extensions/coercion'
autoload :DeepMerge, 'hashie/extensions/deep_merge'
autoload :IgnoreUndeclared, 'hashie/extensions/ignore_undeclared'
autoload :IgnoreRequired, 'hashie/extensions/ignore_required'
autoload :IndifferentAccess, 'hashie/extensions/indifferent_access'
autoload :MergeInitializer, 'hashie/extensions/merge_initializer'
autoload :MethodAccess, 'hashie/extensions/method_access'
Expand Down
42 changes: 42 additions & 0 deletions lib/hashie/extensions/ignore_required.rb
@@ -0,0 +1,42 @@
module Hashie
module Extensions
# IgnoreRequired is a simple mixin that silently ignores
# required properties on initialization and assignment instead of
# raising an error. This is useful when using a building an object
# that will eventually be match a Dash but is temporarily incomplete.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"be match" is probably a typo :)

#
# @example
# class Person < Hashie::Dash
#
# property :first_name, required: true
# property :last_name, required: true
# property :email
# end
#
# class PartialPerson < Person
# include Hashie::Extensions::IgnoreRequired
# end
#
# user_data = {
# :first_name => 'Freddy',
# }
#
# p = Person.new(user_data) # ArgumentError: The property 'last_name' is required for Person.
#
# p = PartialPerson.new(user_data)
# p.last_name = 'Nostrils'
# p.first_name # => 'Freddy'
# p.first_name # => 'Nostrils'
# p.email # => nil
# p.foo # => NoMethodError
module IgnoreRequired
def assert_property_required!(_property, _value)
# do nothing
end

def assert_property_set!(_property)
# do nothing
end
end
end
end
65 changes: 65 additions & 0 deletions spec/hashie/extensions/ignore_required_spec.rb
@@ -0,0 +1,65 @@
require 'spec_helper'

describe Hashie::Extensions::IgnoreRequired do
context 'included in Dash' do
class ForgivingDash < Hashie::Dash
include Hashie::Extensions::IgnoreRequired
property :city, required: true
property :state, required: true, from: :province
property :zip, required: true
end

subject { ForgivingDash }

it 'silently ignores required properties on initialization' do
expect { subject.new(city: 'New York') }.to_not raise_error
end

it 'raises errors for undefined properties on initialization' do
expect { subject.new(city: 'Toronto', province: 'Ontario') }.to raise_error(NoMethodError, /property 'province' is not defined/)
end

it 'requires properties to be declared on assignment' do
hash = subject.new(city: 'Toronto')
expect { hash.country = 'Canada' }.to raise_error(NoMethodError)
end

it 'requires properties to be declared on access' do
hash = subject.new(city: 'Toronto')
expect { hash.country }.to raise_error(NoMethodError)
end
end

context 'combined with Coercion' do
class ForgivingDashWithCoercion < ForgivingDash
include Hashie::Extensions::Coercion
coerce_key :zip, ->(v) { format('%05d', v) }
end

subject { ForgivingDashWithCoercion }

it 'works with coerced properties' do
expect(subject.new(zip: 501).zip).to eq('00501')
end

context 'with nested, coerced Dashes' do
class Address < Hashie::Dash
property :number, required: true
property :street, required: true
property :apartment
end

class ForgivingDashWithAddress < ForgivingDashWithCoercion
property :address, required: true
coerce_key :address, Address
end

subject { ForgivingDashWithAddress }

it 'does not work propagate to nested, coercable properties' do
address = { street: 'Pennsylvania Avenue' }
expect { subject.new(address: address) }.to raise_error(ArgumentError, /property 'number' is required for Address/)
end
end
end
end