active_attr 0.13.1 → 0.14.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.

Potentially problematic release.


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

Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +0 -17
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile +4 -5
  6. data/README.md +140 -112
  7. data/active_attr.gemspec +8 -1
  8. data/gemfiles/rails_3_0.gemfile +0 -4
  9. data/gemfiles/rails_3_1.gemfile +0 -4
  10. data/gemfiles/rails_3_2.gemfile +0 -4
  11. data/gemfiles/rails_4_0.gemfile +1 -1
  12. data/gemfiles/rails_4_1.gemfile +1 -1
  13. data/gemfiles/rails_4_2.gemfile +1 -1
  14. data/gemfiles/rails_5_0.gemfile +1 -1
  15. data/gemfiles/rails_5_1.gemfile +1 -1
  16. data/gemfiles/rails_5_2.gemfile +1 -1
  17. data/gemfiles/rails_head.gemfile +1 -1
  18. data/lib/active_attr.rb +1 -1
  19. data/lib/active_attr/attributes.rb +62 -9
  20. data/lib/active_attr/chainable_initialization.rb +2 -6
  21. data/lib/active_attr/logger.rb +1 -1
  22. data/lib/active_attr/mass_assignment.rb +2 -2
  23. data/lib/active_attr/matchers/have_attribute_matcher.rb +1 -1
  24. data/lib/active_attr/model.rb +1 -0
  25. data/lib/active_attr/query_attributes.rb +1 -1
  26. data/lib/active_attr/railtie.rb +5 -0
  27. data/lib/active_attr/typecasting/boolean_typecaster.rb +8 -0
  28. data/lib/active_attr/version.rb +1 -1
  29. data/spec/functional/active_attr/attributes_spec.rb +8 -8
  30. data/spec/functional/active_attr/matchers/have_attribute_matcher_spec.rb +48 -0
  31. data/spec/functional/active_attr/model_spec.rb +47 -0
  32. data/spec/unit/active_attr/attribute_defaults_spec.rb +8 -0
  33. data/spec/unit/active_attr/attributes_spec.rb +91 -0
  34. data/spec/unit/active_attr/typecasting/big_decimal_typecaster_spec.rb +4 -0
  35. data/spec/unit/active_attr/typecasting/boolean_typecaster_spec.rb +3 -3
  36. metadata +27 -13
  37. data/.ruby-version +0 -1
@@ -120,5 +120,52 @@ module ActiveAttr
120
120
  end.end_date.should == Date.today
121
121
  end
122
122
  end
123
+
124
+ context "when define validation callbacks" do
125
+ let :model_class do
126
+ Class.new do
127
+ include Model
128
+
129
+ attribute :name
130
+ attribute :status
131
+
132
+ validates :name, :presence => true, :length => {:maximum => 6}
133
+
134
+ before_validation :remove_whitespaces
135
+ after_validation :set_status
136
+
137
+ def self.name
138
+ "Person"
139
+ end
140
+
141
+ private
142
+
143
+ def remove_whitespaces
144
+ name.strip!
145
+ end
146
+
147
+ def set_status
148
+ self.status = errors.empty?
149
+ end
150
+ end
151
+ end
152
+
153
+ it "can call before_validation" do
154
+ person = model_class.new(:name => " bob ")
155
+
156
+ expect(person.valid?).to be(true)
157
+ expect(person.name).to eq("bob")
158
+ end
159
+
160
+ it "can call after_validation" do
161
+ person = model_class.new(:name => "")
162
+ expect(person.valid?).to be(false)
163
+ expect(person.status).to be(false)
164
+
165
+ person = model_class.new(:name => "alice")
166
+ expect(person.valid?).to be(true)
167
+ expect(person.status).to be(true)
168
+ end
169
+ end
123
170
  end
124
171
  end
@@ -4,14 +4,18 @@ require "active_attr/attribute_defaults"
4
4
  module ActiveAttr
5
5
  describe AttributeDefaults do
6
6
  subject(:model) { model_class.new }
7
+ let(:non_duplicable) { double("non-duplicable", :duplicable? => false) }
7
8
 
8
9
  let :model_class do
10
+ non_duplicable_default = non_duplicable
11
+
9
12
  Class.new do
10
13
  include InitializationVerifier
11
14
  include AttributeDefaults
12
15
  attribute :first_name, :default => "John"
13
16
  attribute :age, :default => nil
14
17
  attribute :created_at, :default => lambda { Time.now }
18
+ attribute :non_duplicable, :default => non_duplicable_default
15
19
  end
16
20
  end
17
21
 
@@ -32,6 +36,10 @@ module ActiveAttr
32
36
  it "includes declared dynamic attribute defaults" do
33
37
  attribute_defaults["created_at"].should be_a_kind_of Time
34
38
  end
39
+
40
+ it "includes non-duplicable attribute defaults" do
41
+ attribute_defaults["non_duplicable"].should == non_duplicable
42
+ end
35
43
  end
36
44
 
37
45
  describe "#initialize" do
@@ -9,6 +9,7 @@ module ActiveAttr
9
9
  let :model_class do
10
10
  Class.new do
11
11
  include Attributes
12
+
12
13
  attribute :first_name
13
14
  attribute :last_name
14
15
  attribute :amount
@@ -133,6 +134,11 @@ module ActiveAttr
133
134
  model.should_receive(:attribute=).with("first_name", "Ben")
134
135
  model.first_name = "Ben"
135
136
  end
137
+
138
+ it "returns the new attribute definition" do
139
+ result = attributeless.attribute! :first_name
140
+ result.should == AttributeDefinition.new(:first_name)
141
+ end
136
142
  end
137
143
 
138
144
  describe ".attributes" do
@@ -151,6 +157,38 @@ module ActiveAttr
151
157
  end
152
158
  end
153
159
 
160
+ describe "#{described_class}.filter_attributes" do
161
+ after { described_class.send(:remove_instance_variable, "@filter_attributes") }
162
+
163
+ it "defaults to an empty array" do
164
+ described_class.filter_attributes.should == []
165
+ end
166
+
167
+ it "can be mutated" do
168
+ described_class.filter_attributes << :password
169
+ described_class.filter_attributes.should == [:password]
170
+ end
171
+
172
+ it "can be assigned" do
173
+ described_class.filter_attributes += [:password]
174
+ described_class.filter_attributes.should == [:password]
175
+ end
176
+
177
+ it "initiailizes new classes using the module config" do
178
+ described_class.filter_attributes += [:password]
179
+ model_class.filter_attributes.should == [:password]
180
+ end
181
+
182
+ it "subclasses should inherit from the parent class" do
183
+ model_class.filter_attributes = [:password]
184
+ Class.new(model_class).filter_attributes.should == [:password]
185
+ end
186
+
187
+ it "cannot be overridden on instances" do
188
+ model_class.new.should_not respond_to(:filter_attributes=)
189
+ end
190
+ end
191
+
154
192
  describe ".inspect" do
155
193
  it "renders the class name" do
156
194
  model_class.inspect.should match(/^Foo\(.*\)$/)
@@ -214,6 +252,59 @@ module ActiveAttr
214
252
  model.inspect.should == %{#<Foo amount: nil, first_name: "Ben", last_name: "#{last_name}">}
215
253
  end
216
254
 
255
+ context "filtering attributes with a Symbol" do
256
+ before { model_class.filter_attributes = [:amount] }
257
+
258
+ it "does not filter an attribute with a nil value" do
259
+ model.inspect.should == %{#<Foo amount: nil, first_name: "Ben", last_name: "#{last_name}">}
260
+ end
261
+
262
+ it "filters filtered attributes that have a value" do
263
+ model.amount = 100
264
+ model.inspect.should == %{#<Foo amount: [FILTERED], first_name: "Ben", last_name: "#{last_name}">}
265
+ end
266
+ end
267
+
268
+ context "filtering attributes with a String" do
269
+ before { model_class.filter_attributes = ["amount"] }
270
+
271
+ it "does not filter an attribute with a nil value" do
272
+ model.inspect.should == %{#<Foo amount: nil, first_name: "Ben", last_name: "#{last_name}">}
273
+ end
274
+
275
+ it "filters filtered attributes that have a value" do
276
+ model.amount = 100
277
+ model.inspect.should == %{#<Foo amount: [FILTERED], first_name: "Ben", last_name: "#{last_name}">}
278
+ end
279
+ end
280
+
281
+ context "filtering attributes with a partial attribute name" do
282
+ before { model_class.filter_attributes = [:name] }
283
+
284
+ it "filters filtered attributes that have a value and whose attribute contains the filtered attribute name" do
285
+ model.inspect.should == %{#<Foo amount: nil, first_name: [FILTERED], last_name: [FILTERED]>}
286
+ end
287
+ end
288
+
289
+ context "filtering attributes with a Regexp" do
290
+ before { model_class.filter_attributes = [/name/i] }
291
+
292
+ it "filters filtered attributes that have a value and whose attribute matches the Regexp" do
293
+ model.inspect.should == %{#<Foo amount: nil, first_name: [FILTERED], last_name: [FILTERED]>}
294
+ end
295
+ end
296
+
297
+ context "filtering attributes with a Proc with 2 arguments" do
298
+ before do
299
+ model.amount = 100
300
+ model_class.filter_attributes = [->(key, value) { value.reverse! if key =~ /name/ }]
301
+ end
302
+
303
+ it "filters filtered attributes that have a value by mutating the attributes" do
304
+ model.inspect.should == %{#<Foo amount: 100, first_name: "neB", last_name: "iksewoP">}
305
+ end
306
+ end
307
+
217
308
  it "doesn't format the inspection string for attributes if the model does not have any" do
218
309
  attributeless.new.inspect.should == %{#<Foo>}
219
310
  end
@@ -24,6 +24,10 @@ module ActiveAttr
24
24
  typecaster.call("bob").should eql BigDecimal("0.0")
25
25
  end
26
26
 
27
+ it "casts an alpha string coercable object to a zero BigDecimal" do
28
+ typecaster.call(double(to_s: "bob")).should eql BigDecimal("0.0")
29
+ end
30
+
27
31
  it "casts a Rational to a BigDecimal" do
28
32
  typecaster.call(Rational(1, 2)).should eql BigDecimal("0.5")
29
33
  end
@@ -16,8 +16,8 @@ module ActiveAttr
16
16
  typecaster.call(false).should equal false
17
17
  end
18
18
 
19
- it "casts nil to false" do
20
- typecaster.call(nil).should equal false
19
+ it "casts nil to nil" do
20
+ typecaster.call(nil).should equal nil
21
21
  end
22
22
 
23
23
  it "casts an Object to true" do
@@ -26,7 +26,7 @@ module ActiveAttr
26
26
 
27
27
  context "when the value is a String" do
28
28
  it "casts an empty String to false" do
29
- typecaster.call("").should equal false
29
+ typecaster.call("").should equal nil
30
30
  end
31
31
 
32
32
  it "casts a non-empty String to true" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_attr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Griego
@@ -9,8 +9,28 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-04-25 00:00:00.000000000 Z
12
+ date: 2019-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: actionpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 3.0.2
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '6.1'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: 3.0.2
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '6.1'
14
34
  - !ruby/object:Gem::Dependency
15
35
  name: activemodel
16
36
  requirement: !ruby/object:Gem::Requirement
@@ -66,12 +86,9 @@ dependencies:
66
86
  - !ruby/object:Gem::Version
67
87
  version: '1.0'
68
88
  - !ruby/object:Gem::Dependency
69
- name: factory_girl
89
+ name: factory_bot
70
90
  requirement: !ruby/object:Gem::Requirement
71
91
  requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: '2.2'
75
92
  - - "<"
76
93
  - !ruby/object:Gem::Version
77
94
  version: '5.0'
@@ -79,9 +96,6 @@ dependencies:
79
96
  prerelease: false
80
97
  version_requirements: !ruby/object:Gem::Requirement
81
98
  requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- version: '2.2'
85
99
  - - "<"
86
100
  - !ruby/object:Gem::Version
87
101
  version: '5.0'
@@ -157,7 +171,6 @@ extra_rdoc_files: []
157
171
  files:
158
172
  - ".gitignore"
159
173
  - ".rspec"
160
- - ".ruby-version"
161
174
  - ".travis.yml"
162
175
  - ".yardopts"
163
176
  - CHANGELOG.md
@@ -252,7 +265,8 @@ files:
252
265
  homepage: https://github.com/cgriego/active_attr
253
266
  licenses:
254
267
  - MIT
255
- metadata: {}
268
+ metadata:
269
+ changelog_uri: https://github.com/cgriego/active_attr/blob/master/CHANGELOG.md
256
270
  post_install_message:
257
271
  rdoc_options: []
258
272
  require_paths:
@@ -261,7 +275,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
261
275
  requirements:
262
276
  - - ">="
263
277
  - !ruby/object:Gem::Version
264
- version: '0'
278
+ version: 1.9.2
265
279
  required_rubygems_version: !ruby/object:Gem::Requirement
266
280
  requirements:
267
281
  - - ">="
@@ -269,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
283
  version: '0'
270
284
  requirements: []
271
285
  rubyforge_project:
272
- rubygems_version: 2.6.12
286
+ rubygems_version: 2.7.9
273
287
  signing_key:
274
288
  specification_version: 4
275
289
  summary: What ActiveModel left out
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.4.1