active_attr 0.4.1 → 0.5.0.alpha1

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.

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