diff --git a/lib/simple_form_object.rb b/lib/simple_form_object.rb index 54eea04..0f4c8f4 100644 --- a/lib/simple_form_object.rb +++ b/lib/simple_form_object.rb @@ -1,4 +1,5 @@ require "simple_form_object/version" +require "simple_form_object/attribute" require "active_model" require "active_support" @@ -14,8 +15,20 @@ def attribute(name, type = :string, options = {}) _attributes << Attribute.new(name, type, options) end + def route_as(model_name) + @model_name = model_name.to_s.camelize + end + def _attributes - @_attributes ||= [] + inherited_attributes = [] + + ancestors.drop(1).each do |ancestor| + if ancestor.respond_to?(:_attributes) + inherited_attributes.concat(ancestor._attributes) + end + end + + @_attributes ||= inherited_attributes end def _attribute(attribute_name) @@ -23,7 +36,13 @@ def _attribute(attribute_name) end def model_name - ActiveModel::Name.new(self, nil, self.to_s.gsub(/Form$/, '')) + ActiveModel::Name.new(self, nil, model_name_for_routing) + end + + private + + def model_name_for_routing + @model_name || to_s.gsub(/Form$/, "") end end @@ -46,34 +65,7 @@ def attributes attribs end - class Attribute - def initialize(name, type = nil, options) - @name = name - @type = type || :string - @options = options - - extract_options - end - - attr_accessor :name, :type, :options - - def fake_column - self - end - - def apply_default_to(form) - if form.send(@name).nil? - form.send("#{@name}=", @default) if @apply_default - end - end - - private - - def extract_options - @apply_default = true - @default = options.fetch(:default) { @apply_default = false; nil } - @skip_validations = options.fetch(:skip_validations, false) - end + def has_attribute?(attribute) + attributes.key?(attribute) end - end diff --git a/lib/simple_form_object/attribute.rb b/lib/simple_form_object/attribute.rb new file mode 100644 index 0000000..382a02a --- /dev/null +++ b/lib/simple_form_object/attribute.rb @@ -0,0 +1,40 @@ +module SimpleFormObject + class Attribute + def initialize(name, type = nil, options) + @name = name + @type = type || :string + @options = options + + extract_options + end + + attr_accessor :name, :type, :options + + def fake_column + self + end + + def apply_default_to(form) + if form.send(@name).nil? + default_value = @default.respond_to?(:call) ? @default.call : @default + form.send("#{@name}=", default_value) if @apply_default + end + end + + def number? + %i(integer float decimal).include?(type) + end + + def limit + nil + end + + private + + def extract_options + @apply_default = true + @default = options.fetch(:default) { @apply_default = false; nil } + @skip_validations = options.fetch(:skip_validations, false) + end + end +end diff --git a/spec/attribute_spec.rb b/spec/attribute_spec.rb index a4966bb..2434ad9 100644 --- a/spec/attribute_spec.rb +++ b/spec/attribute_spec.rb @@ -53,6 +53,47 @@ expect(form.foo).to eq false end end + end + + describe '#limit' do + subject(:attribute) { SimpleFormObject::Attribute.new(:name, :string, {}) } + + it 'returns nil' do + expect(subject.limit).to be_nil + end + end + + describe '#number?' do + context 'when attribute is an integer' do + subject(:attribute) { SimpleFormObject::Attribute.new(:name, :integer, {}) } + + it 'returns true' do + expect(subject).to be_number + end + end + + context 'when attribute is a float' do + subject(:attribute) { SimpleFormObject::Attribute.new(:name, :float, {}) } + it 'returns true' do + expect(subject).to be_number + end + end + + context 'when attribute is a decimal' do + subject(:attribute) { SimpleFormObject::Attribute.new(:name, :decimal, {}) } + + it 'returns true' do + expect(subject).to be_number + end + end + + context 'when attribute is a string' do + subject(:attribute) { SimpleFormObject::Attribute.new(:name, :string, {}) } + + it 'returns false' do + expect(subject).not_to be_number + end + end end end diff --git a/spec/model_spec.rb b/spec/model_spec.rb index 374c05a..8fd88e3 100644 --- a/spec/model_spec.rb +++ b/spec/model_spec.rb @@ -67,20 +67,56 @@ end describe '.model_name' do - let(:klass) do - class KlassForm - include SimpleFormObject + context 'by convention' do + let(:klass) do + class KlassForm + include SimpleFormObject + end + + KlassForm + end + + it 'should return an ActiveModel::Name' do + expect(klass.model_name).to be_a_kind_of ActiveModel::Name + end + + it 'should remove Form from the name of the class' do + expect(klass.model_name.name).to eq 'Klass' + end + end + + context 'by declaration' do + let(:klass) do + class KlassForm + include SimpleFormObject + + route_as :custom + end + + KlassForm + end + + it 'should return an ActiveModel::Name' do + expect(klass.model_name).to be_a_kind_of ActiveModel::Name + end + + it 'should remove Form from the name of the class' do + expect(klass.model_name.name).to eq 'Custom' end + end + end - KlassForm + describe '#has_attribute?' do + before do + klass.attribute :foo end - it 'should return an ActiveModel::Name' do - expect(klass.model_name).to be_a_kind_of ActiveModel::Name + it 'returns true for a declared attribute' do + expect(instance.has_attribute?(:foo)).to be(true) end - it 'should remove Form from the name of the class' do - expect(klass.model_name.name).to eq "Klass" + it 'returns false for a declared attribute' do + expect(instance.has_attribute?(:bar)).to be(false) end end end