attrio 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,18 +8,11 @@ module Attrio
8
8
 
9
9
  module ClassMethods
10
10
  def define_attrio_new(as)
11
- # define_singleton_method(:new) do |*args, &block|
12
- # obj = self.allocate
13
- # obj.send "reset_#{as}!"
14
- # obj.send :initialize, *args, &block
15
- # obj
16
- # end
17
-
18
11
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
19
12
  def self.new(*args, &block)
20
- obj = self.allocate
21
- obj.send "reset_#{as}!"
13
+ obj = self.allocate
22
14
  obj.send :initialize, *args, &block
15
+ obj.send "set_#{as}_defaults"
23
16
  obj
24
17
  end
25
18
  EOS
data/lib/attrio/reset.rb CHANGED
@@ -8,13 +8,24 @@ module Attrio
8
8
 
9
9
  module ClassMethods
10
10
  def define_attrio_reset(as)
11
- define_method "reset_#{as.to_s}" do
12
- self.send(as.to_s).values.each do |attribute|
13
- self.send(attribute.writer_method_name, attribute.default_value)
14
- end
11
+ define_method "reset_#{as.to_s}" do |attributes = []|
12
+ self.send(as.to_s, attributes).values.each{ |attribute| self.send(attribute.writer_method_name, nil) }
13
+ self.send("set_#{as.to_s}_defaults", attributes)
14
+ end
15
+
16
+ define_method "reset_#{as.to_s}_defaults" do |attributes = []|
17
+ self.send(as.to_s, attributes).values.select{ |attribute| !attribute.default_value.nil? }.each { |attribute| self.send(attribute.writer_method_name, nil) }
18
+ self.send("set_#{as.to_s}_defaults", attributes)
15
19
  end
16
20
 
17
- self.send(:alias_method, "reset_#{as.to_s}!", "reset_#{as.to_s}")
21
+ define_method "set_#{as.to_s}_defaults" do |attributes = []|
22
+ self.send(as.to_s, attributes).values.select{ |attribute| !attribute.default_value.nil? }.each do |attribute|
23
+ next if self.send(attribute.reader_method_name).present?
24
+
25
+ default_value = attribute.default_value.is_a?(Attrio::DefaultValue::Base) ? attribute.default_value.call(self) : attribute.default_value
26
+ self.send(attribute.writer_method_name, default_value)
27
+ end
28
+ end
18
29
  end
19
30
  end
20
31
  end
@@ -9,10 +9,6 @@ module Attrio
9
9
  raise NotImplementedError
10
10
  end
11
11
 
12
- def self._typecast(value, options = {})
13
- self.typecasted?(value) ? value : self.typecast(value, options)
14
- end
15
-
16
12
  def self.typecasted?(value)
17
13
  false
18
14
  end
@@ -3,9 +3,9 @@
3
3
  module Attrio
4
4
  module Types
5
5
  class Date < Base
6
- def self.typecast(value, options = {})
6
+ def self.typecast(value, options = {})
7
7
  begin
8
- options[:format].present? ? ::Date.strptime(value, options[:format]) : ::Date.parse(value)
8
+ options[:format].present? ? ::Date.strptime(value.to_s, options[:format]) : ::Date.parse(value.to_s)
9
9
  rescue ArgumentError => e
10
10
  nil
11
11
  end
@@ -5,7 +5,7 @@ module Attrio
5
5
  class DateTime < Base
6
6
  def self.typecast(value, options = {})
7
7
  begin
8
- options[:format].present? ? ::DateTime.strptime(value, options[:format]) : ::DateTime.parse(value)
8
+ options[:format].present? ? ::DateTime.strptime(value.to_s, options[:format]) : ::DateTime.parse(value.to_s)
9
9
  rescue ArgumentError => e
10
10
  nil
11
11
  end
@@ -5,7 +5,7 @@ module Attrio
5
5
  class Time < Base
6
6
  def self.typecast(value, options = {})
7
7
  begin
8
- options[:format].present? ? ::Time.strptime(value, options[:format]) : ::Time.parse(value)
8
+ options[:format].present? ? ::Time.strptime(value.to_s, options[:format]) : ::Time.parse(value.to_s)
9
9
  rescue ArgumentError => e
10
10
  nil
11
11
  end
@@ -3,8 +3,8 @@
3
3
  module Attrio
4
4
  module Version
5
5
  MAJOR = 0
6
- MINOR = 1
7
- PATCH = 1
6
+ MINOR = 2
7
+ PATCH = 0
8
8
  BUILD = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -24,16 +24,11 @@ describe Attrio do
24
24
  model.respond_to?(:attributes).should be_true
25
25
  end
26
26
 
27
- it 'should respond_to attributes=' do
28
- model.respond_to?(:attributes=).should be_true
29
- end
30
-
31
27
  describe 'object' do
32
28
  let(:object) { model.new }
33
29
 
34
30
  it 'should respond_to reset_attributes' do
35
31
  object.respond_to?(:reset_attributes).should be_true
36
- object.respond_to?(:reset_attributes!).should be_true
37
32
  end
38
33
  end
39
34
  end
@@ -52,16 +47,11 @@ describe Attrio do
52
47
  model.respond_to?(:model_attributes).should be_true
53
48
  end
54
49
 
55
- it 'should respond_to model_attributes=' do
56
- model.respond_to?(:model_attributes=).should be_true
57
- end
58
-
59
50
  describe 'object' do
60
51
  let(:object) { model.new }
61
52
 
62
53
  it 'should respond_to reset_model_attributes' do
63
- object.respond_to?(:reset_model_attributes).should be_true
64
- object.respond_to?(:reset_model_attributes!).should be_true
54
+ object.respond_to?(:reset_model_attributes).should be_true
65
55
  end
66
56
  end
67
57
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Attrio::DefaultValue::Callable do
4
+ subject { described_class.new(object, attribute, default_value) }
5
+
6
+ let(:model) do
7
+ Class.new do
8
+ include Attrio
9
+
10
+ define_attributes do
11
+ attr :attribute, DateTime, :default => proc{ DateTime.now }
12
+ end
13
+ end
14
+ end
15
+
16
+ let(:object){ model.new }
17
+
18
+ let(:attribute){ mock('attribute')}
19
+ let(:default_value){ mock('default_value')}
20
+ let(:response) { stub('response') }
21
+
22
+ before { default_value.stub(:call => response) }
23
+ it 'should call the value with the object and attribute' do
24
+ default_value.should_receive(:call).with(object, attribute).and_return(response)
25
+ subject.call(object)
26
+ end
27
+
28
+ it "should set attribute value to appropriate type" do
29
+ object.attribute.should be_instance_of(DateTime)
30
+ end
31
+
32
+ it "should be evaluate attribute value every time" do
33
+ another_object = model.new
34
+
35
+ object.attribute.should_not be_equal(another_object.attribute)
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe Attrio::DefaultValue::Clonable do
4
+ subject { described_class.new(object, attribute, default_value) }
5
+
6
+ let(:model) do
7
+ Class.new do
8
+ include Attrio
9
+
10
+ define_attributes do
11
+ attr :attribute, Date, :default => Date.today
12
+ end
13
+ end
14
+ end
15
+
16
+ let(:object){ model.new }
17
+
18
+ let(:attribute){ mock('attribute')}
19
+ let(:default_value){ mock('default_value')}
20
+ let(:instance) { mock('instance') }
21
+ let(:clone) { mock('clone') }
22
+
23
+ before { default_value.stub(:clone => clone) }
24
+
25
+ it 'should clone the value' do
26
+ default_value.should_receive(:clone).with(no_args)
27
+ subject.call(instance)
28
+ end
29
+
30
+ it 'should be an instance of a cloned value' do
31
+ subject.call(instance).should be(clone)
32
+ end
33
+
34
+ it "should set attribute value to appropriate type" do
35
+ object.attribute.should be_instance_of(Date)
36
+ end
37
+
38
+ it "should not be equal to clonable object" do
39
+ object.attribute.should_not be_equal(Date.today)
40
+ end
41
+
42
+ it "should have the same value as clonable object" do
43
+ object.attribute.should == Date.today
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Attrio::DefaultValue::Base, '.handle' do
4
+ subject { described_class.handle(mock('object'), mock('attribute'), default) }
5
+
6
+ context 'when default is a symbol' do
7
+ let(:default) { :symbol }
8
+
9
+ it { should be_instance_of(Attrio::DefaultValue::Symbol) }
10
+ end
11
+
12
+ context 'when default is a callable' do
13
+ let(:default) { Proc.new {} }
14
+
15
+ it { should be_instance_of(Attrio::DefaultValue::Callable) }
16
+ end
17
+
18
+ context 'when default is a clonable' do
19
+ let(:default) { "I can be cloned" }
20
+
21
+ it { should be_instance_of(Attrio::DefaultValue::Clonable) }
22
+ end
23
+
24
+ context 'when default is not clonable' do
25
+ let(:default) { 1 }
26
+
27
+ it { should be_nil }
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Attrio::DefaultValue::Symbol do
4
+ subject { described_class.new(object, attribute, default_value) }
5
+
6
+ let(:model) do
7
+ Class.new do
8
+ include Attrio
9
+
10
+ define_attributes do
11
+ attr :attribute, Date, :default => :today
12
+ attr :attribute_with_non_existing_method, Symbol, :default => :non_existing_method
13
+ end
14
+
15
+ def today
16
+ Date.today
17
+ end
18
+ end
19
+ end
20
+
21
+ let(:object){ model.new }
22
+
23
+ let(:attribute){ mock('attribute')}
24
+ let(:default_value){ mock('default_value')}
25
+
26
+ it "should set attribute value to appropriate type" do
27
+ object.attribute.should be_instance_of(Date)
28
+ end
29
+
30
+ it "should have value that is returned by method in class" do
31
+ object.attribute.should == Date.today
32
+ end
33
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe Attrio::DefaultValue do
4
+ let(:model) do
5
+ Class.new do
6
+ include Attrio
7
+
8
+ define_attributes do
9
+ attr :attribute_without_default_value, Date
10
+ attr :attribute_with_default_value, Integer, :default => 1
11
+ # attr :attribute_with_callable_default_value, DateTime, :default => lambda{ DateTime.now }
12
+ # attr :attribute_with_clonable_default_value, Date, :default => Date.today
13
+ # attr :attribute_with_symbol_default_value, Date, :default => :today
14
+ # attr :attribute_with_non_existing_method_default_value, Symbol, :default => :non_existing_method
15
+ end
16
+
17
+ def today
18
+ Date.today
19
+ end
20
+ end
21
+ end
22
+
23
+ let(:object){ model.new }
24
+
25
+ context 'default value is not set' do
26
+ it "should set attribute to nil" do
27
+ object.attribute_without_default_value.should be_nil
28
+ end
29
+ end
30
+
31
+ context 'default value is set as a not clonable object' do
32
+ it "should set attribute value to appropriate type" do
33
+ object.attribute_with_default_value.should be_instance_of(Fixnum)
34
+ end
35
+
36
+ it "should be equal to attribute value" do
37
+ object.attribute_with_default_value.should be_equal(1)
38
+ end
39
+ end
40
+
41
+ # context 'default value is set as a callable' do
42
+ # it "should set attribute value to appropriate type" do
43
+ # object.attribute_with_callable_default_value.should be_instance_of(DateTime)
44
+ # end
45
+
46
+ # it "should be evaluate attribute value every time" do
47
+ # object.attribute_with_callable_default_value.should < another_object.attribute_with_callable_default_value
48
+ # end
49
+ # end
50
+
51
+ # context 'default value is set as a clonable object' do
52
+ # it "should set attribute value to appropriate type" do
53
+ # object.attribute_with_clonable_default_value.should be_instance_of(Date)
54
+ # end
55
+
56
+ # it "should not be equal to clonable object" do
57
+ # object.attribute_with_clonable_default_value.should_not be_equal(Date.today)
58
+ # end
59
+
60
+ # it "should have the same value as clonable object" do
61
+ # object.attribute_with_clonable_default_value.should == Date.today
62
+ # end
63
+ # end
64
+
65
+ # context 'default value is set as a symbol' do
66
+ # it "should set attribute value to appropriate type" do
67
+ # object.attribute_with_clonable_default_value.should be_instance_of(Date)
68
+ # end
69
+
70
+ # it "should have value that is returned by method in class" do
71
+ # object.attribute_with_clonable_default_value.should == Date.today
72
+ # end
73
+ # end
74
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Embedded Value' do
4
+ before do
5
+ module MassAssignment
6
+ def initialize(attributes = {})
7
+ self.attributes = attributes
8
+ end
9
+
10
+ def attributes=(attributes = {})
11
+ attributes.each do |attr,value|
12
+ self.send("#{attr}=", value) if self.respond_to?("#{attr}=")
13
+ end
14
+ end
15
+ end
16
+
17
+ class City
18
+ include Attrio
19
+ include MassAssignment
20
+
21
+ define_attributes do
22
+ attr :name, String
23
+ end
24
+ end
25
+
26
+ class Address
27
+ include Attrio
28
+ include MassAssignment
29
+
30
+ define_attributes do
31
+ attr :street, String
32
+ attr :zipcode, String
33
+ attr :city, City
34
+ end
35
+ end
36
+
37
+ class User
38
+ include Attrio
39
+ include MassAssignment
40
+
41
+ define_attributes do
42
+ attr :name, String
43
+ attr :address, Address
44
+ end
45
+ end
46
+ end
47
+
48
+ let(:address_attributes) do
49
+ { :street => 'Sklizkova 6A', :zipcode => '170000', :city => { :name => 'Tver' } }
50
+ end
51
+
52
+ it 'should allow to pass a hash for the embedded value' do
53
+ user = User.new
54
+ user.address = address_attributes
55
+ user.address.street.should == 'Sklizkova 6A'
56
+ user.address.zipcode.should == '170000'
57
+ user.address.city.name.should == 'Tver'
58
+ end
59
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Attrio::Inspect do
4
- context '' do
4
+ context 'without options' do
5
5
  let(:model) do
6
6
  Class.new do
7
7
  include Attrio
@@ -13,12 +13,12 @@ describe Attrio::Inspect do
13
13
 
14
14
  let(:object) { model.new }
15
15
 
16
- it 'should' do
16
+ it 'should have inspect defined by attrio' do
17
17
  object.method(:inspect).source_location.first.should match(/lib\/attrio\/inspect.rb/)
18
18
  end
19
19
  end
20
20
 
21
- context '' do
21
+ context ':inspect option passed' do
22
22
  let(:model) do
23
23
  Class.new do
24
24
  include Attrio
@@ -30,7 +30,7 @@ describe Attrio::Inspect do
30
30
 
31
31
  let(:object) { model.new }
32
32
 
33
- it 'should' do
33
+ it 'should not have inspect defined by attrio' do
34
34
  if RUBY_ENGINE == 'rbx'
35
35
  object.method(:inspect).source_location.first.should_not match(/attrio/)
36
36
  else