attrio 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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