From b8d6008646b44e6196dacb03043e0c92526de889 Mon Sep 17 00:00:00 2001 From: Vladimir Sazhin Date: Mon, 10 Jun 2019 13:42:46 +0300 Subject: [PATCH] New boolean attribute syntax --- lib/tainbox/attribute_definer.rb | 10 ++++ lib/tainbox/class_methods.rb | 12 +++-- spec/tainbox_spec.rb | 78 ++++++++++++++++++++++++++++---- 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/lib/tainbox/attribute_definer.rb b/lib/tainbox/attribute_definer.rb index 0be57e5..b5e16b3 100644 --- a/lib/tainbox/attribute_definer.rb +++ b/lib/tainbox/attribute_definer.rb @@ -16,12 +16,15 @@ def initialize(klass, attribute_name, requested_type, requested_args) def define_getter klass.tainbox_register_attribute(attribute_name) attribute = attribute_name + type = requested_type klass.tainbox_layer.instance_eval do define_method(attribute) do value = instance_variable_get(:"@tainbox_#{attribute}") value.is_a?(Tainbox::DeferredValue) ? instance_exec(&value.proc) : value end + + alias_method("#{attribute}?", attribute) if type == :Boolean end end @@ -40,6 +43,13 @@ def define_setter instance_variable_set(:"@tainbox_#{attribute}", value) end + if type == :Boolean + define_method("#{attribute}!") do + send("#{attribute}=", true) + self + end + end + define_method("tainbox_set_default_#{attribute}") do if args.has_key?(:default) tainbox_register_attribute_provided(attribute) diff --git a/lib/tainbox/class_methods.rb b/lib/tainbox/class_methods.rb index 41dc00a..490b92c 100644 --- a/lib/tainbox/class_methods.rb +++ b/lib/tainbox/class_methods.rb @@ -21,13 +21,17 @@ def tainbox_initializer_suppressed? attr_reader :tainbox_initializer_suppressed def attribute(name, type = nil, **args) + name = name.to_s args = args.dup - define_reader = args.fetch(:reader, true) - define_writer = args.fetch(:writer, true) + + if name.end_with?('?') + name.chop! + type = :Boolean + end definer = Tainbox::AttributeDefiner.new(self, name, type, args) - definer.define_getter if define_reader - definer.define_setter if define_writer + definer.define_getter if args.fetch(:reader, true) + definer.define_setter if args.fetch(:writer, true) end def suppress_tainbox_initializer! diff --git a/spec/tainbox_spec.rb b/spec/tainbox_spec.rb index df45762..56b2246 100644 --- a/spec/tainbox_spec.rb +++ b/spec/tainbox_spec.rb @@ -6,35 +6,95 @@ person = Class.new do include Tainbox - attribute :name, default: 'Oliver' + + attribute :name, default: 'Anonymous' attribute :age, Integer + attribute :admin?, default: false def name super.strip end end - person = person.new(name: ' John ', 'age' => '24') + person = person.new(name: ' John ', 'age' => '24', 'admin' => '1') + expect(person.name).to eq('John') - expect(person.age).to eq(24) expect(person.attribute_provided?(:name)).to be_truthy + + expect(person.age).to eq(24) expect(person.attribute_provided?(:age)).to be_truthy + expect(person.admin).to eq(true) + expect(person.admin?).to eq(true) + expect(person.attribute_provided?(:admin)).to be_truthy + + expect(person.attributes).to eq(name: 'John', age: 24, admin: true) + expect(person.as_json).to eq('name' => 'John', 'age' => 24, 'admin' => true) + person.attributes = {} - expect(person.name).to eq('Oliver') - expect(person.age).to be_nil + + expect(person.name).to eq('Anonymous') expect(person.attribute_provided?(:name)).to be_truthy + + expect(person.age).to be_nil expect(person.attribute_provided?(:age)).to be_falsey - expect(person.attributes).to eq(name: 'Oliver', age: nil) + expect(person.admin).to eq(false) + expect(person.admin?).to eq(false) + expect(person.attribute_provided?(:admin)).to be_truthy + + expect(person.attributes).to eq(name: 'Anonymous', age: nil, admin: false) + expect(person.as_json).to eq('name' => 'Anonymous', 'age' => nil, 'admin' => false) person.age = 10 + expect(person.age).to eq(10) expect(person.attribute_provided?(:age)).to be_truthy - 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) + expect(person.admin!).to eq(person) + + expect(person.admin).to eq(true) + expect(person.admin?).to eq(true) + expect(person.attribute_provided?(:admin)).to be_truthy + + person.name = ' John ' + + expect(person.name).to eq('John') + expect(person.attribute_provided?(:name)).to be_truthy + + expect(person.as_json).to eq('name' => 'John', 'age' => 10, 'admin' => true) + expect(person.as_json(only: :name)).to eq('name' => 'John') + expect(person.as_json(except: :name)).to eq('age' => 10, 'admin' => true) + end + + it 'supports old syntax' do + person = Class.new do + include Tainbox + + attribute :admin, :Boolean + end + + person = person.new('admin' => '1') + + expect(person.admin).to eq(true) + expect(person.attribute_provided?(:admin)).to be_truthy + + expect(person.attributes).to eq(admin: true) + expect(person.as_json).to eq('admin' => true) + + person.attributes = {} + + expect(person.admin).to eq(nil) + expect(person.attribute_provided?(:admin)).to be_falsey + + expect(person.attributes).to eq(admin: nil) + expect(person.as_json).to eq('admin' => nil) + + person.admin = true + + expect(person.admin).to eq(true) + expect(person.admin?).to eq(true) + expect(person.attribute_provided?(:admin)).to be_truthy end it 'accepts objects which respond to #to_h as attributes' do