object_attorney 3.0.0 → 3.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbfd04fe687681f1030ef93cbbf32c177bb67f98
4
- data.tar.gz: b2e7ff76d84de665db33f2275e082ad6dc24122c
3
+ metadata.gz: c4d890c47532df6465b42cf292cce79ea7547269
4
+ data.tar.gz: 53f487a5a4f3f6a8ef76e107fdb3ca5d3340af06
5
5
  SHA512:
6
- metadata.gz: 416ef86c1c665c0a20ef9a9efd78ed2ab21cacd7b254bbf5282e63cf54f214bb0757020f145a404730d0c63fd6fbd06a8457461d833f706c1a7a1c3e34e61ea8
7
- data.tar.gz: 878e0a1ce4a1fbcabf50ac95dd2e7090f6f21548bf19b559fca4b1dc49ce0c939d76ca28da737cc6414c384f972a13126935dc73e2f4c9f63256a8dd83d2f92f
6
+ metadata.gz: cc07794845c2f7370d4583e0ce75ea4918b4cf0de7644f69d35f2bb2c920b22e55989f311b5d5e76e35a004de6e38557caba229ef188c048afedb1540951d09b
7
+ data.tar.gz: b948a71214feb47355f3aca6caafa9970a3888a6c079e6bc3b1e09124ca3b7d6c81b3e30699059a86285085603a292d216adb8a16f3056d88d1efa91c26f2b7e
data/Gemfile.lock CHANGED
@@ -1,22 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- object_attorney (3.0.0)
4
+ object_attorney (3.0.1)
5
+ activemodel (~> 3)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
9
- activemodel (4.2.6)
10
- activesupport (= 4.2.6)
11
- builder (~> 3.1)
12
- activesupport (4.2.6)
13
- i18n (~> 0.7)
14
- json (~> 1.7, >= 1.7.7)
15
- minitest (~> 5.1)
16
- thread_safe (~> 0.3, >= 0.3.4)
17
- tzinfo (~> 1.1)
10
+ activemodel (3.2.22.2)
11
+ activesupport (= 3.2.22.2)
12
+ builder (~> 3.0.0)
13
+ activesupport (3.2.22.2)
14
+ i18n (~> 0.6, >= 0.6.4)
15
+ multi_json (~> 1.0)
18
16
  ast (2.3.0)
19
- builder (3.2.2)
17
+ builder (3.0.4)
20
18
  codeclimate-test-reporter (0.4.8)
21
19
  simplecov (>= 0.7.1, < 1.0.0)
22
20
  coderay (1.1.1)
@@ -25,7 +23,7 @@ GEM
25
23
  i18n (0.7.0)
26
24
  json (1.8.3)
27
25
  method_source (0.8.2)
28
- minitest (5.9.0)
26
+ multi_json (1.12.1)
29
27
  parser (2.3.1.2)
30
28
  ast (~> 2.2)
31
29
  powerpack (0.1.1)
@@ -61,16 +59,12 @@ GEM
61
59
  simplecov-html (~> 0.10.0)
62
60
  simplecov-html (0.10.0)
63
61
  slop (3.6.0)
64
- thread_safe (0.3.5)
65
- tzinfo (1.2.2)
66
- thread_safe (~> 0.1)
67
62
  unicode-display_width (0.3.1)
68
63
 
69
64
  PLATFORMS
70
65
  ruby
71
66
 
72
67
  DEPENDENCIES
73
- activemodel (= 4.2.6)
74
68
  codeclimate-test-reporter (= 0.4.8)
75
69
  object_attorney!
76
70
  pry (= 0.10.3)
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Object Attorney
2
-
2
+ This gem allows you to create use cases with ActiveModel validations and keep your model clean.
3
3
 
4
4
  [![Code Climate](https://codeclimate.com/github/goncalvesjoao/object_attorney/badges/gpa.svg)](https://codeclimate.com/github/goncalvesjoao/object_attorney)
5
5
  [![Test Coverage](https://codeclimate.com/github/goncalvesjoao/object_attorney/badges/coverage.svg)](https://codeclimate.com/github/goncalvesjoao/object_attorney/coverage)
@@ -12,25 +12,57 @@ end
12
12
  ```
13
13
 
14
14
  ```ruby
15
- class UserValidator < Struct.new(:user)
15
+ class UserValidator < ObjectAttorney::Base
16
+ validates_presence_of :first_name
17
+
18
+ validate :last_name_present
19
+
20
+ def last_name_present(user)
21
+ return if user.last_name.present?
22
+
23
+ user.errors.add(:last_name, :blank)
24
+ end
25
+ end
26
+ ```
27
+
28
+ ```ruby
29
+ @user = User.new
30
+
31
+ UserValidator.new(@user).valid? # false
32
+
33
+ @user.errors.messages # { first_name: ["can't be blank"], last_name: ["can't be blank"] }
34
+ ```
35
+
36
+ ## 2) Custom Usage
37
+ ```ruby
38
+ class User < ActiveRecord::Base
39
+ end
40
+ ```
41
+
42
+ ```ruby
43
+ class UserValidator
16
44
  include ObjectAttorney
17
45
 
18
46
  defend :user
19
47
 
20
- validates_presence_of :first_name
21
- end
48
+ validates_presence_of :first_name, if: :last_name_is_present
22
49
 
23
- # OR
50
+ attr_accessor :user
24
51
 
25
- class UserValidator < ObjectAttorney::Base
26
- validates_presence_of :first_name
52
+ def initialize(user)
53
+ @user = user
54
+ end
55
+
56
+ def last_name_is_present(user)
57
+ user.last_name.present?
58
+ end
27
59
  end
28
60
  ```
29
61
 
30
62
  ```ruby
31
- @user = User.new
63
+ @user = User.new(last_name: 'Snow')
32
64
 
33
- UserValidator.new(@user).valid?
65
+ UserValidator.new(@user).invalid? # true
34
66
 
35
67
  @user.errors.messages # { first_name: ["can't be blank"] }
36
68
  ```
@@ -9,9 +9,10 @@ module ObjectAttorney
9
9
  attribute
10
10
  end
11
11
 
12
- def lookup_ancestors
13
- [self]
14
- end
12
+ # Having doubts if this is really necessary
13
+ # def lookup_ancestors
14
+ # [self]
15
+ # end
15
16
  end
16
17
 
17
18
  def self.included(base_class)
@@ -16,14 +16,16 @@ module ObjectAttorney
16
16
  if proc_or_method.is_a?(Proc)
17
17
  base.instance_exec(object, &proc_or_method)
18
18
  else
19
- base.send(proc_or_method, object)
19
+ call_method!(base, proc_or_method, object)
20
20
  end
21
21
  end
22
22
 
23
- def safe_call_method(base, method)
24
- return nil unless base.respond_to?(method)
23
+ def call_method!(base, method, *args)
24
+ unless base.respond_to?(method)
25
+ raise NotImplementedError, "#{base} does not respond to #{method}"
26
+ end
25
27
 
26
- base.send(method)
28
+ base.send(method, *args)
27
29
  end
28
30
 
29
31
  def extend_errors_if_necessary(object)
@@ -14,7 +14,9 @@ module ObjectAttorney
14
14
  end
15
15
 
16
16
  def validate(defendant)
17
- [*@methods].map { |method| @attorney.send(method, defendant) }.all?
17
+ [*@methods].all? do |method|
18
+ Helpers.call_method!(@attorney, method, defendant)
19
+ end
18
20
  end
19
21
 
20
22
  end
@@ -1,5 +1,5 @@
1
1
  module ObjectAttorney
2
2
 
3
- VERSION = '3.0.0'.freeze
3
+ VERSION = '3.0.2'.freeze
4
4
 
5
5
  end
@@ -11,9 +11,9 @@ module ObjectAttorney
11
11
  end
12
12
 
13
13
  def defendant_is_innocent?
14
- proven_innocent = defendants.all? do |defendant|
14
+ proven_innocent = defendants.map do |defendant|
15
15
  innocent_of_all_accusations?(defendant)
16
- end
16
+ end.all?
17
17
 
18
18
  make_the_parent_guilty unless proven_innocent
19
19
 
@@ -29,13 +29,14 @@ module ObjectAttorney
29
29
  protected ######################### PROTECTED ################################
30
30
 
31
31
  def defendants
32
- defendant = Helpers.safe_call_method(self, defendant_options[:name])
33
-
34
- if parent_defendant
35
- Helpers.extend_errors_if_necessary(parent_defendant)
36
-
37
- defendant ||= parent_defendant.send(defendant_options[:name])
38
- end
32
+ defendant =
33
+ if parent_defendant
34
+ Helpers.extend_errors_if_necessary(parent_defendant)
35
+
36
+ Helpers.call_method!(parent_defendant, defendant_options[:name])
37
+ else
38
+ Helpers.call_method!(self, defendant_options[:name])
39
+ end
39
40
 
40
41
  [defendant].flatten.compact
41
42
  end
@@ -10,8 +10,8 @@ Gem::Specification.new do |gem|
10
10
  gem.license = 'MIT'
11
11
  gem.authors = ['João Gonçalves']
12
12
  gem.email = ['goncalves.joao@gmail.com']
13
- gem.summary = 'Ruby Form Object pattern implementation'
14
- gem.description = "This gem allows you to extract the code responsible for 'validations', 'nested objects' and 'strong parameters' from your model onto a specific class for a specific use case."
13
+ gem.summary = 'Allows you to keep your ActiveModel validations out of your objects'
14
+ gem.description = 'This gem allows you to create use cases with ActiveModel validations and keep your model clean'
15
15
  gem.homepage = 'https://github.com/streetbees/object_attorney'
16
16
 
17
17
  gem.files = `git ls-files`.split($/)
@@ -24,8 +24,7 @@ Gem::Specification.new do |gem|
24
24
  gem.add_development_dependency 'rspec', '3.4.0'
25
25
  gem.add_development_dependency 'rubocop', '0.37.2'
26
26
  gem.add_development_dependency 'simplecov', '0.11.2'
27
- gem.add_development_dependency 'activemodel', '4.2.6'
28
27
  gem.add_development_dependency 'codeclimate-test-reporter', '0.4.8'
29
28
 
30
- # gem.add_dependency 'i18n', '~> 0.7'
29
+ gem.add_dependency 'activemodel', '~> 3'
31
30
  end
@@ -25,7 +25,7 @@ describe ObjectAttorney do
25
25
 
26
26
  context "given a user with an invalid phone_number" do
27
27
  before do
28
- @user = User.new('jon', 'bad number')
28
+ @user = User.new(phone_number: 'bad number')
29
29
  @custom_validator.new(@user).valid?
30
30
  end
31
31
 
@@ -35,7 +35,7 @@ describe ObjectAttorney do
35
35
 
36
36
  context "and preventing the validation" do
37
37
  before do
38
- @user = User.new('jon', 'really bad number', true)
38
+ @user = User.new(phone_number: 'really bad number', dont_validate: true)
39
39
  @custom_validator.new(@user).valid?
40
40
  end
41
41
 
@@ -47,7 +47,7 @@ describe ObjectAttorney do
47
47
 
48
48
  context "given a user with a valid phone_number" do
49
49
  before do
50
- @user = User.new('jon', '123 123')
50
+ @user = User.new(phone_number: '123 123')
51
51
  @custom_validator.new(@user).valid?
52
52
  end
53
53
 
@@ -2,6 +2,77 @@ require 'spec_helper'
2
2
 
3
3
  describe ObjectAttorney do
4
4
 
5
+ context "When the defendant is nil" do
6
+ before do
7
+ @user_validator = Struct.new(:user) do
8
+ include ObjectAttorney
9
+
10
+ defend :user
11
+
12
+ validates_presence_of :first_name, unless: Proc.new { |user| user.dont_validate }
13
+ end
14
+ end
15
+
16
+ it "#valid? should be true" do
17
+ expect(@user_validator.new(nil).valid?).to be true
18
+ end
19
+ end
20
+
21
+ context "When the defendant is empty" do
22
+ before do
23
+ @user = User.new
24
+ @user.posts = []
25
+
26
+ @user_validator = Struct.new(:user) do
27
+ include ObjectAttorney
28
+
29
+ defend :posts, in: :user
30
+
31
+ validates_presence_of :first_name, unless: Proc.new { |user| user.dont_validate }
32
+ end
33
+ end
34
+
35
+ it "#valid? should be true" do
36
+ expect(@user_validator.new(@user).valid?).to be true
37
+ end
38
+ end
39
+
40
+ context "When the defendant is not defined" do
41
+ before do
42
+ @user = User.new
43
+
44
+ @user_validator = Struct.new(:user) do
45
+ include ObjectAttorney
46
+
47
+ defend :posts
48
+
49
+ validates_presence_of :first_name, unless: Proc.new { |user| user.dont_validate }
50
+ end
51
+ end
52
+
53
+ it "#valid? should raise an error" do
54
+ expect { @user_validator.new(@user).valid? }.to raise_error NotImplementedError
55
+ end
56
+ end
57
+
58
+ context "When the defendant is not defined on the parent" do
59
+ before do
60
+ @user = User.new
61
+
62
+ @user_validator = Struct.new(:user) do
63
+ include ObjectAttorney
64
+
65
+ defend :comments, in: :user
66
+
67
+ validates_presence_of :first_name, unless: Proc.new { |user| user.dont_validate }
68
+ end
69
+ end
70
+
71
+ it "#valid? should raise an error" do
72
+ expect { @user_validator.new(@user).valid? }.to raise_error NotImplementedError
73
+ end
74
+ end
75
+
5
76
  context "When the defendant is a single object" do
6
77
  before do
7
78
  @user = User.new
@@ -23,7 +94,7 @@ describe ObjectAttorney do
23
94
 
24
95
  context "and the unless validation is true" do
25
96
  before do
26
- @user = User.new('', '', true)
97
+ @user = User.new(dont_validate: true)
27
98
  end
28
99
 
29
100
  it "@user.errors should be empty" do
@@ -37,7 +108,7 @@ describe ObjectAttorney do
37
108
  context "When the defendant is an array nested inside another object" do
38
109
  before do
39
110
  @user = User.new
40
- @user.posts = [Post.new, Post.new(nil, true), Post.new('yada')]
111
+ @user.posts = [Post.new, Post.new(_destroy: true), nil, Post.new(title: 'yada')]
41
112
 
42
113
  @user_validator = Struct.new(:user) do
43
114
  include ObjectAttorney
@@ -57,8 +128,101 @@ describe ObjectAttorney do
57
128
  it "only the first @user.posts should have errors" do
58
129
  expect(@user.posts[0].errors.messages).to eq({ title: ["can't be blank"] })
59
130
  expect(@user.posts[1].errors.empty?).to be true
60
- expect(@user.posts[2].errors.empty?).to be true
131
+ expect(@user.posts[2]).to be_nil
132
+ expect(@user.posts[3].errors.empty?).to be true
61
133
  end
62
134
  end
63
135
 
136
+ describe "inheritance" do
137
+
138
+ context "when a use case inherits from another that has a dependant and a validation" do
139
+ before do
140
+ @user1 = User.new
141
+ @user2 = User.new
142
+ @user3 = User.new
143
+ @user4 = User.new
144
+
145
+ @user_validator1 = Class.new do
146
+ include ObjectAttorney
147
+
148
+ defend :user
149
+
150
+ validates_presence_of :first_name
151
+
152
+ attr_accessor :user
153
+
154
+ def initialize(user)
155
+ @user = user
156
+ end
157
+ end
158
+
159
+ @user_validator2 = Class.new(@user_validator1) do
160
+ validates_presence_of :phone_number
161
+ end
162
+
163
+ @user_validator3 = Class.new(@user_validator2) do
164
+ defend :users
165
+
166
+ attr_accessor :users
167
+
168
+ def initialize(users)
169
+ @users = users
170
+ end
171
+ end
172
+
173
+ @user_validator1.new(@user1).valid?
174
+ @user_validator2.new(@user2).valid?
175
+ @user_validator3.new([@user3, @user4]).valid?
176
+ end
177
+
178
+ it "@user_validator1.defendant_options should mention :user" do
179
+ expect(@user_validator1.defendant_options).to eq({ name: :user })
180
+ end
181
+
182
+ it "@user_validator2.defendant_options should mention :user" do
183
+ expect(@user_validator2.defendant_options).to eq({ name: :user })
184
+ end
185
+
186
+ it "@user_validator3.defendant_options should mention :users" do
187
+ expect(@user_validator3.defendant_options).to eq({ name: :users })
188
+ end
189
+
190
+ it "@user1.errors should ONLY mention first_name" do
191
+ expect(@user1.errors.count).to be 1
192
+
193
+ expect(@user1.errors.messages).to eq({
194
+ first_name: ["can't be blank"]
195
+ })
196
+ end
197
+
198
+ it "@user2.errors should mention first_name and phone_number" do
199
+ expect(@user2.errors.messages).to eq({
200
+ first_name: ["can't be blank"],
201
+ phone_number: ["can't be blank"]
202
+ })
203
+
204
+ expect(@user2.errors.count).to be 2
205
+ end
206
+
207
+ it "@user3.errors should mention first_name and phone_number" do
208
+ expect(@user3.errors.messages).to eq({
209
+ first_name: ["can't be blank"],
210
+ phone_number: ["can't be blank"]
211
+ })
212
+
213
+ expect(@user3.errors.count).to be 2
214
+ end
215
+
216
+ it "@user4.errors should mention first_name and phone_number" do
217
+ expect(@user4.errors.messages).to eq({
218
+ first_name: ["can't be blank"],
219
+ phone_number: ["can't be blank"]
220
+ })
221
+
222
+ expect(@user4.errors.count).to be 2
223
+ end
224
+ end
225
+
226
+ end
227
+
64
228
  end
data/spec/support/post.rb CHANGED
@@ -1,7 +1,13 @@
1
- class Post < Struct.new(:title, :marked_for_destruction)
1
+ class Post
2
+
3
+ attr_accessor :title, :_destroy
4
+
5
+ def initialize(attributes = {})
6
+ (attributes || {}).each { |name, value| send("#{name}=", value) }
7
+ end
2
8
 
3
9
  def marked_for_destruction?
4
- self.marked_for_destruction
10
+ _destroy
5
11
  end
6
12
 
7
13
  end
data/spec/support/user.rb CHANGED
@@ -1,5 +1,9 @@
1
- class User < Struct.new(:first_name, :phone_number, :dont_validate)
1
+ class User
2
2
 
3
- attr_accessor :posts
3
+ attr_accessor :first_name, :phone_number, :dont_validate, :posts
4
+
5
+ def initialize(attributes = {})
6
+ (attributes || {}).each { |name, value| send("#{name}=", value) }
7
+ end
4
8
 
5
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: object_attorney
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - João Gonçalves
@@ -81,36 +81,35 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.11.2
83
83
  - !ruby/object:Gem::Dependency
84
- name: activemodel
84
+ name: codeclimate-test-reporter
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 4.2.6
89
+ version: 0.4.8
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 4.2.6
96
+ version: 0.4.8
97
97
  - !ruby/object:Gem::Dependency
98
- name: codeclimate-test-reporter
98
+ name: activemodel
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '='
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.4.8
104
- type: :development
103
+ version: '3'
104
+ type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '='
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 0.4.8
111
- description: This gem allows you to extract the code responsible for 'validations',
112
- 'nested objects' and 'strong parameters' from your model onto a specific class for
113
- a specific use case.
110
+ version: '3'
111
+ description: This gem allows you to create use cases with ActiveModel validations
112
+ and keep your model clean
114
113
  email:
115
114
  - goncalves.joao@gmail.com
116
115
  executables: []
@@ -166,7 +165,7 @@ rubyforge_project:
166
165
  rubygems_version: 2.5.1
167
166
  signing_key:
168
167
  specification_version: 4
169
- summary: Ruby Form Object pattern implementation
168
+ summary: Allows you to keep your ActiveModel validations out of your objects
170
169
  test_files:
171
170
  - spec/object_attorney/base_spec.rb
172
171
  - spec/object_attorney/custom_validation_spec.rb