active_attr 0.4.1 → 0.5.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of active_attr might be problematic. Click here for more details.

Files changed (53) hide show
  1. data/.travis.yml +7 -0
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +57 -25
  4. data/Rakefile +2 -0
  5. data/active_attr.gemspec +3 -2
  6. data/gemfiles/rails_3_1.gemfile +6 -0
  7. data/lib/active_attr.rb +3 -2
  8. data/lib/active_attr/attribute_defaults.rb +120 -0
  9. data/lib/active_attr/attribute_definition.rb +25 -2
  10. data/lib/active_attr/attributes.rb +44 -33
  11. data/lib/active_attr/logger.rb +8 -8
  12. data/lib/active_attr/mass_assignment.rb +2 -1
  13. data/lib/active_attr/matchers/have_attribute_matcher.rb +28 -10
  14. data/lib/active_attr/model.rb +2 -0
  15. data/lib/active_attr/query_attributes.rb +2 -5
  16. data/lib/active_attr/typecasted_attributes.rb +77 -0
  17. data/lib/active_attr/typecasting.rb +60 -0
  18. data/lib/active_attr/typecasting/boolean.rb +6 -0
  19. data/lib/active_attr/typecasting/boolean_typecaster.rb +21 -0
  20. data/lib/active_attr/typecasting/date_time_typecaster.rb +14 -0
  21. data/lib/active_attr/typecasting/date_typecaster.rb +14 -0
  22. data/lib/active_attr/typecasting/float_typecaster.rb +11 -0
  23. data/lib/active_attr/typecasting/integer_typecaster.rb +12 -0
  24. data/lib/active_attr/typecasting/object_typecaster.rb +9 -0
  25. data/lib/active_attr/typecasting/string_typecaster.rb +11 -0
  26. data/lib/active_attr/version.rb +1 -1
  27. data/spec/functional/active_attr/attribute_defaults_spec.rb +136 -0
  28. data/spec/functional/active_attr/attributes_spec.rb +19 -5
  29. data/spec/functional/active_attr/model_spec.rb +34 -4
  30. data/spec/functional/active_attr/typecasted_attributes_spec.rb +116 -0
  31. data/spec/support/mass_assignment_shared_examples.rb +1 -1
  32. data/spec/unit/active_attr/attribute_defaults_spec.rb +43 -0
  33. data/spec/unit/active_attr/attribute_definition_spec.rb +12 -8
  34. data/spec/unit/active_attr/attributes_spec.rb +22 -10
  35. data/spec/unit/active_attr/mass_assignment_spec.rb +1 -0
  36. data/spec/unit/active_attr/matchers/have_attribute_matcher_spec.rb +94 -15
  37. data/spec/unit/active_attr/query_attributes_spec.rb +1 -1
  38. data/spec/unit/active_attr/typecasted_attributes_spec.rb +76 -0
  39. data/spec/unit/active_attr/typecasting/boolean_spec.rb +10 -0
  40. data/spec/unit/active_attr/typecasting/boolean_typecaster_spec.rb +147 -0
  41. data/spec/unit/active_attr/typecasting/date_time_typecaster_spec.rb +67 -0
  42. data/spec/unit/active_attr/typecasting/date_typecaster_spec.rb +55 -0
  43. data/spec/unit/active_attr/typecasting/float_typecaster_spec.rb +27 -0
  44. data/spec/unit/active_attr/typecasting/integer_typecaster_spec.rb +35 -0
  45. data/spec/unit/active_attr/typecasting/object_typecaster_spec.rb +15 -0
  46. data/spec/unit/active_attr/typecasting/string_typecaster_spec.rb +24 -0
  47. data/spec/unit/active_attr/typecasting_spec.rb +87 -0
  48. data/spec/unit/active_attr/version_spec.rb +11 -2
  49. metadata +75 -29
  50. data/lib/active_attr/strict_mass_assignment.rb +0 -44
  51. data/lib/active_attr/unknown_attributes_error.rb +0 -18
  52. data/spec/unit/active_attr/strict_mass_assignment_spec.rb +0 -38
  53. data/spec/unit/active_attr/unknown_attributes_error_spec.rb +0 -9
@@ -53,7 +53,7 @@ module ActiveAttr
53
53
  end
54
54
 
55
55
  it "calls the predicate method if defined" do
56
- subject.query_attribute(:true).should == true
56
+ subject.query_attribute(:true).should eq true
57
57
  subject.query_attribute(:false).should == false
58
58
  end
59
59
 
@@ -0,0 +1,76 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasted_attributes"
3
+
4
+ module ActiveAttr
5
+ describe TypecastedAttributes do
6
+ subject { model_class.new }
7
+
8
+ let :model_class do
9
+ Class.new do
10
+ include TypecastedAttributes
11
+
12
+ attribute :amount, :type => String
13
+ attribute :first_name
14
+ attribute :last_name
15
+
16
+ def last_name_before_type_cast
17
+ super
18
+ end
19
+
20
+ def self.name
21
+ "Foo"
22
+ end
23
+ end
24
+ end
25
+
26
+ let :attributeless do
27
+ Class.new do
28
+ include TypecastedAttributes
29
+
30
+ def self.name
31
+ "Foo"
32
+ end
33
+ end
34
+ end
35
+
36
+ describe ".attribute" do
37
+ it "defines an attribute pre-typecasting reader that calls #attribute_before_type_cast" do
38
+ subject.should_receive(:attribute_before_type_cast).with("first_name")
39
+ subject.first_name_before_type_cast
40
+ end
41
+
42
+ it "defines an attribute reader that can be called via super" do
43
+ subject.should_receive(:attribute_before_type_cast).with("last_name")
44
+ subject.last_name_before_type_cast
45
+ end
46
+ end
47
+
48
+ describe ".inspect" do
49
+ it "renders the class name" do
50
+ model_class.inspect.should match(/^Foo\(.*\)$/)
51
+ end
52
+
53
+ it "renders the attribute names and types in alphabetical order, using Object for undeclared types" do
54
+ model_class.inspect.should match "(amount: String, first_name: Object, last_name: Object)"
55
+ end
56
+
57
+ it "doesn't format the inspection string for attributes if the model does not have any" do
58
+ attributeless.inspect.should == "Foo"
59
+ end
60
+ end
61
+
62
+ describe "#attribute_before_type_cast" do
63
+ it "returns the assigned attribute value, without typecasting, when given an attribute name as a Symbol" do
64
+ value = :value
65
+ subject.amount = value
66
+ subject.attribute_before_type_cast(:amount).should equal value
67
+ end
68
+
69
+ it "returns the assigned attribute value, without typecasting, when given an attribute name as a String" do
70
+ value = :value
71
+ subject.amount = value
72
+ subject.attribute_before_type_cast('amount').should equal value
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/boolean"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe Boolean do
7
+ it { described_class.should be_a Class }
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,147 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/boolean_typecaster"
3
+ require "bigdecimal"
4
+
5
+ module ActiveAttr
6
+ module Typecasting
7
+ describe BooleanTypecaster do
8
+ describe "#call" do
9
+ it "returns true for true" do
10
+ subject.call(true).should equal true
11
+ end
12
+
13
+ it "returns false for false" do
14
+ subject.call(false).should equal false
15
+ end
16
+
17
+ it "casts nil to false" do
18
+ subject.call(nil).should equal false
19
+ end
20
+
21
+ it "casts an Object to true" do
22
+ subject.call(Object.new).should equal true
23
+ end
24
+
25
+ context "when the value is a String" do
26
+ it "casts an empty String to false" do
27
+ subject.call("").should equal false
28
+ end
29
+
30
+ it "casts a non-empty String to true" do
31
+ subject.call("abc").should equal true
32
+ end
33
+
34
+ {
35
+ "t" => true,
36
+ "f" => false,
37
+ "T" => true,
38
+ "F" => false,
39
+ # http://yaml.org/type/bool.html
40
+ "y" => true,
41
+ "Y" => true,
42
+ "yes" => true,
43
+ "Yes" => true,
44
+ "YES" => true,
45
+ "n" => false,
46
+ "N" => false,
47
+ "no" => false,
48
+ "No" => false,
49
+ "NO" => false,
50
+ "true" => true,
51
+ "True" => true,
52
+ "TRUE" => true,
53
+ "false" => false,
54
+ "False" => false,
55
+ "FALSE" => false,
56
+ "on" => true,
57
+ "On" => true,
58
+ "ON" => true,
59
+ "off" => false,
60
+ "Off" => false,
61
+ "OFF" => false,
62
+ }.each_pair do |value, result|
63
+ it "casts #{value.inspect} to #{result.inspect}" do
64
+ subject.call(value).should equal result
65
+ end
66
+ end
67
+ end
68
+
69
+ context "when the value is Numeric" do
70
+ it "casts 0 to false" do
71
+ subject.call(0).should equal false
72
+ end
73
+
74
+ it "casts 1 to true" do
75
+ subject.call(1).should equal true
76
+ end
77
+
78
+ it "casts 0.0 to false" do
79
+ subject.call(0.0).should equal false
80
+ end
81
+
82
+ it "casts 0.1 to true" do
83
+ subject.call(0.1).should equal true
84
+ end
85
+
86
+ it "casts a zero BigDecimal to false" do
87
+ subject.call(BigDecimal.new("0.0")).should equal false
88
+ end
89
+
90
+ it "casts a non-zero BigDecimal to true" do
91
+ subject.call(BigDecimal.new("0.1")).should equal true
92
+ end
93
+
94
+ it "casts -1 to true" do
95
+ subject.call(-1).should equal true
96
+ end
97
+
98
+ it "casts -0.0 to false" do
99
+ subject.call(-0.0).should equal false
100
+ end
101
+
102
+ it "casts -0.1 to true" do
103
+ subject.call(-0.1).should equal true
104
+ end
105
+
106
+ it "casts a negative zero BigDecimal to false" do
107
+ subject.call(BigDecimal.new("-0.0")).should equal false
108
+ end
109
+
110
+ it "casts a negative BigDecimal to true" do
111
+ subject.call(BigDecimal.new("-0.1")).should equal true
112
+ end
113
+ end
114
+
115
+ context "when the value is the String version of a Numeric" do
116
+ it "casts '0' to false" do
117
+ subject.call("0").should equal false
118
+ end
119
+
120
+ it "casts '1' to true" do
121
+ subject.call("1").should equal true
122
+ end
123
+
124
+ it "casts '0.0' to false" do
125
+ subject.call("0.0").should equal false
126
+ end
127
+
128
+ it "casts '0.1' to true" do
129
+ subject.call("0.1").should equal true
130
+ end
131
+
132
+ it "casts '-1' to true" do
133
+ subject.call("-1").should equal true
134
+ end
135
+
136
+ it "casts '-0.0' to false" do
137
+ subject.call("-0.0").should equal false
138
+ end
139
+
140
+ it "casts '-0.1' to true" do
141
+ subject.call("-0.1").should equal true
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,67 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/date_time_typecaster"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe DateTimeTypecaster do
7
+ describe "#call" do
8
+ it "returns the original DateTime for a DateTime" do
9
+ value = DateTime.now
10
+ subject.call(value).should equal value
11
+ end
12
+
13
+ it "returns nil for nil" do
14
+ subject.call(nil).should equal nil
15
+ end
16
+
17
+ it "casts a Date to a DateTime at the beginning of the day with no offset" do
18
+ result = subject.call(Date.new(2012, 1, 1))
19
+ result.should eql DateTime.new(2012, 1, 1)
20
+ result.should be_instance_of DateTime
21
+ end
22
+
23
+ it "casts a UTC Time to a DateTime with no offset" do
24
+ result = subject.call(Time.utc(2012, 1, 1, 12, 0, 0))
25
+ result.should eql DateTime.new(2012, 1, 1, 12, 0, 0, 0)
26
+ result.should be_instance_of DateTime
27
+ end
28
+
29
+ it "casts a local Time to a DateTime with a matching offset" do
30
+ result = subject.call(Time.local(2012, 1, 1, 12, 0, 0))
31
+ result.should eql DateTime.new(2012, 1, 1, 12, 0, 0, Rational(Time.now.utc_offset, 86400))
32
+ result.should be_instance_of DateTime
33
+ end
34
+
35
+ it "casts an ISO8601 date String to a Date" do
36
+ result = subject.call("2012-01-01")
37
+ result.should eql DateTime.new(2012, 1, 1)
38
+ result.should be_instance_of DateTime
39
+ end
40
+
41
+ it "casts an RFC2616 date and GMT time String to a DateTime" do
42
+ result = subject.call("Sat, 03 Feb 2001 00:00:00 GMT")
43
+ result.should eql DateTime.new(2001, 2, 3)
44
+ result.should be_instance_of DateTime
45
+ end
46
+
47
+ it "casts an RFC3339 date and offset time String to a DateTime" do
48
+ result = subject.call("2001-02-03T04:05:06+07:00")
49
+ result.should eql DateTime.new(2001, 2, 3, 4, 5, 6, "+07:00")
50
+ result.should be_instance_of DateTime
51
+ end
52
+
53
+ it "casts a UTC ActiveSupport::TimeWithZone to a DateTime" do
54
+ result = subject.call(Time.utc(2012, 1, 1, 1, 1, 1).in_time_zone("UTC"))
55
+ result.should eql DateTime.new(2012, 1, 1, 1, 1, 1, 0)
56
+ result.should be_instance_of DateTime
57
+ end
58
+
59
+ it "casts an Alaska ActiveSupport::TimeWithZone to a Date representing the date portion" do
60
+ result = subject.call(Time.utc(2012, 1, 1, 0, 0, 0).in_time_zone("Alaska"))
61
+ result.should eql DateTime.new(2011, 12, 31, 15, 0, 0, "-09:00")
62
+ result.should be_instance_of DateTime
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/date_typecaster"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe DateTypecaster do
7
+ describe "#call" do
8
+ it "returns the original date for a Date" do
9
+ value = Date.today
10
+ subject.call(value).should equal value
11
+ end
12
+
13
+ it "returns nil for nil" do
14
+ subject.call(nil).should equal nil
15
+ end
16
+
17
+ it "casts a UTC Time to a Date representing the date portion" do
18
+ subject.call(Time.utc(2012, 1, 1, 0, 0, 0)).should eql Date.new(2012, 1, 1)
19
+ end
20
+
21
+ it "casts a local Time to a Date representing the date portion" do
22
+ subject.call(Time.local(2012, 1, 1, 0, 0, 0)).should eql Date.new(2012, 1, 1)
23
+ end
24
+
25
+ it "casts a UTC DateTime to a Date representing the date portion" do
26
+ subject.call(DateTime.new(2012, 1, 1, 0, 0, 0)).should eql Date.new(2012, 1, 1)
27
+ end
28
+
29
+ it "casts an offset DateTime to a Date representing the date portion" do
30
+ subject.call(DateTime.new(2012, 1, 1, 0, 0, 0, "-12:00")).should eql Date.new(2012, 1, 1)
31
+ end
32
+
33
+ it "casts an ISO8601 date String to a Date" do
34
+ subject.call("2012-01-01").should eql Date.new(2012, 1, 1)
35
+ end
36
+
37
+ it "casts an RFC2616 date and GMT time String to a Date representing the date portion" do
38
+ subject.call("Sat, 03 Feb 2001 00:00:00 GMT").should eql Date.new(2001, 2, 3)
39
+ end
40
+
41
+ it "casts an RFC3339 date and offset time String to a Date representing the date portion" do
42
+ subject.call("2001-02-03T04:05:06+07:00").should eql Date.new(2001, 2, 3)
43
+ end
44
+
45
+ it "casts a UTC ActiveSupport::TimeWithZone to a Date representing the date portion" do
46
+ subject.call(Time.utc(2012, 1, 1, 0, 0, 0).in_time_zone("UTC")).should eql Date.new(2012, 1, 1)
47
+ end
48
+
49
+ it "casts an Alaska ActiveSupport::TimeWithZone to a Date representing the date portion" do
50
+ subject.call(Time.utc(2012, 1, 1, 0, 0, 0).in_time_zone("Alaska")).should eql Date.new(2011, 12, 31)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/float_typecaster"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe FloatTypecaster do
7
+ describe "#call" do
8
+ it "returns the original float for a Float" do
9
+ value = 2.0
10
+ subject.call(value).should equal value
11
+ end
12
+
13
+ it "casts nil to 0.0" do
14
+ subject.call(nil).should eql 0.0
15
+ end
16
+
17
+ it "returns the float version of a String" do
18
+ subject.call("2").should eql 2.0
19
+ end
20
+
21
+ it "returns nil for an object that does not respond to #to_f" do
22
+ subject.call(Object.new).should be_nil
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/integer_typecaster"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe IntegerTypecaster do
7
+ describe "#call" do
8
+ it "returns the original integer for a FixNum" do
9
+ value = 2
10
+ subject.call(value).should equal value
11
+ end
12
+
13
+ it "casts nil to 0" do
14
+ subject.call(nil).should eql 0
15
+ end
16
+
17
+ it "returns the integer version of a String" do
18
+ subject.call("2").should eql 2
19
+ end
20
+
21
+ it "returns nil for an object that does not respond to #to_i" do
22
+ subject.call(Object.new).should be_nil
23
+ end
24
+
25
+ it "returns nil for Float::INFINITY" do
26
+ subject.call(1.0 / 0.0).should be_nil
27
+ end
28
+
29
+ it "returns nil for Float::NAN" do
30
+ subject.call(0.0 / 0.0).should be_nil
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+ require "active_attr/typecasting/object_typecaster"
3
+
4
+ module ActiveAttr
5
+ module Typecasting
6
+ describe ObjectTypecaster do
7
+ describe "#call" do
8
+ it "returns the original object for any object" do
9
+ value = mock
10
+ subject.call(value).should equal value
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end