diff --git a/README.md b/README.md index f2f508c..587a279 100644 --- a/README.md +++ b/README.md @@ -62,20 +62,32 @@ def name=(value) end ``` -### #attribute_provided? +### `#provided_attributes` and `#attribute_provided?` -Attribute is considered provided if its setter was explicitly invoked via a setter, `.new`, or `#attributes=` or it has a default value. +Attribute is considered provided if its setter was explicitly invoked via a setter, `.new`, or `#attributes=`. ``` ruby class Person include Tainbox - attribute :name, default: 'John' + attribute :name, default: 'Anonymous' attribute :age end -person = Person.new -person.attribute_provided?(:age) # => false +person = Person.new('age' => '24') + +person.provided_attributes # => [:age] +person.attribute_provided?(:name) # => false +person.attribute_provided?(:age) # => true + +person.name = 'John' +person.provided_attributes # => [:name, :age] person.attribute_provided?(:name) # => true +person.attribute_provided?(:age) # => true + +person.attributes = {} +person.provided_attributes # => [] +person.attribute_provided?(:name) # => false +person.attribute_provided?(:age) # => false ``` ### Disabling automatic attribute readers and writers diff --git a/lib/tainbox/attribute_definer.rb b/lib/tainbox/attribute_definer.rb index 0be57e5..fb1af12 100644 --- a/lib/tainbox/attribute_definer.rb +++ b/lib/tainbox/attribute_definer.rb @@ -41,14 +41,14 @@ def define_setter end define_method("tainbox_set_default_#{attribute}") do + tainbox_unregister_attribute_provided(attribute) + if args.has_key?(:default) - tainbox_register_attribute_provided(attribute) value = args[:default].deep_dup value = Tainbox::DeferredValue.new(value) if value.is_a?(Proc) instance_variable_set(:"@tainbox_#{attribute}", value) else - tainbox_unregister_attribute_provided(attribute) instance_variable_set(:"@tainbox_#{attribute}", nil) end end diff --git a/lib/tainbox/instance_methods.rb b/lib/tainbox/instance_methods.rb index ab86ac1..e93adf7 100644 --- a/lib/tainbox/instance_methods.rb +++ b/lib/tainbox/instance_methods.rb @@ -41,6 +41,10 @@ def attributes=(attributes) end end + def provided_attributes + self.class.tainbox_attributes & tainbox_provided_attributes + end + def attribute_provided?(attribute) tainbox_provided_attributes.include?(attribute.to_sym) end diff --git a/spec/tainbox_spec.rb b/spec/tainbox_spec.rb index df45762..3896346 100644 --- a/spec/tainbox_spec.rb +++ b/spec/tainbox_spec.rb @@ -19,19 +19,23 @@ def name expect(person.age).to eq(24) expect(person.attribute_provided?(:name)).to be_truthy expect(person.attribute_provided?(:age)).to be_truthy + expect(person.provided_attributes).to eq(%i[name age]) person.attributes = {} expect(person.name).to eq('Oliver') expect(person.age).to be_nil - expect(person.attribute_provided?(:name)).to be_truthy + expect(person.attribute_provided?(:name)).to be_falsey expect(person.attribute_provided?(:age)).to be_falsey expect(person.attributes).to eq(name: 'Oliver', age: nil) + expect(person.provided_attributes).to be_empty person.age = 10 expect(person.age).to eq(10) expect(person.attribute_provided?(:age)).to be_truthy + expect(person.provided_attributes).to eq(%i[age]) + expect(person.as_json).to eq('name' => 'Oliver', 'age' => 10) expect(person.as_json(only: :name)).to eq('name' => 'Oliver') expect(person.as_json(except: :name)).to eq('age' => 10)