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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +0 -17
- data/CHANGELOG.md +14 -0
- data/Gemfile +4 -5
- data/README.md +140 -112
- data/active_attr.gemspec +8 -1
- data/gemfiles/rails_3_0.gemfile +0 -4
- data/gemfiles/rails_3_1.gemfile +0 -4
- data/gemfiles/rails_3_2.gemfile +0 -4
- data/gemfiles/rails_4_0.gemfile +1 -1
- data/gemfiles/rails_4_1.gemfile +1 -1
- data/gemfiles/rails_4_2.gemfile +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -1
- data/gemfiles/rails_5_1.gemfile +1 -1
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/gemfiles/rails_head.gemfile +1 -1
- data/lib/active_attr.rb +1 -1
- data/lib/active_attr/attributes.rb +62 -9
- data/lib/active_attr/chainable_initialization.rb +2 -6
- data/lib/active_attr/logger.rb +1 -1
- data/lib/active_attr/mass_assignment.rb +2 -2
- data/lib/active_attr/matchers/have_attribute_matcher.rb +1 -1
- data/lib/active_attr/model.rb +1 -0
- data/lib/active_attr/query_attributes.rb +1 -1
- data/lib/active_attr/railtie.rb +5 -0
- data/lib/active_attr/typecasting/boolean_typecaster.rb +8 -0
- data/lib/active_attr/version.rb +1 -1
- data/spec/functional/active_attr/attributes_spec.rb +8 -8
- data/spec/functional/active_attr/matchers/have_attribute_matcher_spec.rb +48 -0
- data/spec/functional/active_attr/model_spec.rb +47 -0
- data/spec/unit/active_attr/attribute_defaults_spec.rb +8 -0
- data/spec/unit/active_attr/attributes_spec.rb +91 -0
- data/spec/unit/active_attr/typecasting/big_decimal_typecaster_spec.rb +4 -0
- data/spec/unit/active_attr/typecasting/boolean_typecaster_spec.rb +3 -3
- metadata +27 -13
- 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
|
20
|
-
typecaster.call(nil).should equal
|
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
|
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.
|
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-
|
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:
|
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:
|
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.
|
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
|