rails-patterns 0.4.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,260 @@
1
+ RSpec.describe Ruleset do
2
+ context 'when empty ruleset is initialized' do
3
+ it 'raises an error' do
4
+ empty_ruleset_klass = Class.new(Ruleset)
5
+ custom_ruleset_klass = Class.new(Ruleset)
6
+ subject = double
7
+
8
+ with_mocked_rules do |rules|
9
+ rules << mock_rule(:rule_1)
10
+ custom_ruleset_klass.add_rule(:rule_1)
11
+
12
+ expect { custom_ruleset_klass.new(subject) }.not_to raise_error
13
+ end
14
+
15
+ expect { empty_ruleset_klass.new(subject) }.to raise_error Ruleset::EmptyRuleset
16
+ end
17
+ end
18
+
19
+ describe '#forceable?' do
20
+ context 'all rules are forceable' do
21
+ it 'returns true' do
22
+ with_mocked_rules do |rules|
23
+ subject = double
24
+ rules << mock_rule(:rule_1, is_forceable: true)
25
+ rules << mock_rule(:rule_2, is_forceable: true)
26
+
27
+ custom_ruleset_klass = Class.new(Ruleset)
28
+ custom_ruleset_klass.add_rule(:rule_1)
29
+ custom_ruleset_klass.add_rule(:rule_2)
30
+
31
+ expect(custom_ruleset_klass.new(subject).forceable?).to eq true
32
+ end
33
+ end
34
+ end
35
+
36
+ context 'at least one rule is not forceable' do
37
+ it 'returns false' do
38
+ with_mocked_rules do |rules|
39
+ subject = double
40
+ rules << mock_rule(:rule_1, is_forceable: false, is_satisfied: false, is_applicable: true)
41
+ rules << mock_rule(:rule_2, is_forceable: true)
42
+
43
+ custom_ruleset_klass = Class.new(Ruleset)
44
+ custom_ruleset_klass.add_rule(:rule_1)
45
+ custom_ruleset_klass.add_rule(:rule_2)
46
+
47
+ expect(custom_ruleset_klass.new(subject).forceable?).to eq false
48
+ end
49
+ end
50
+
51
+ context 'and rule is satisfied' do
52
+ it 'returns true' do
53
+ with_mocked_rules do |rules|
54
+ subject = double
55
+ rules << mock_rule(
56
+ :rule_1,
57
+ is_forceable: false,
58
+ is_satisfied: true,
59
+ is_applicable: true
60
+ )
61
+ rules << mock_rule(:rule_2, is_forceable: true)
62
+
63
+ custom_ruleset_klass = Class.new(Ruleset)
64
+ custom_ruleset_klass.add_rule(:rule_1)
65
+ custom_ruleset_klass.add_rule(:rule_2)
66
+
67
+ expect(custom_ruleset_klass.new(subject).forceable?).to eq true
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'and rule is not applicable' do
73
+ it 'returns true' do
74
+ with_mocked_rules do |rules|
75
+ subject = double
76
+ rules << mock_rule(
77
+ :rule_1,
78
+ is_forceable: false,
79
+ is_satisfied: false,
80
+ is_applicable: false
81
+ )
82
+ rules << mock_rule(:rule_2, is_forceable: true)
83
+
84
+ custom_ruleset_klass = Class.new(Ruleset)
85
+ custom_ruleset_klass.add_rule(:rule_1)
86
+ custom_ruleset_klass.add_rule(:rule_2)
87
+
88
+ expect(custom_ruleset_klass.new(subject).forceable?).to eq true
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ describe '#not_applicable?' do
96
+ context 'all rules are not applicable' do
97
+ it 'returns true' do
98
+ with_mocked_rules do |rules|
99
+ subject = double
100
+ rules << mock_rule(:rule_1, is_applicable: false)
101
+ rules << mock_rule(:rule_2, is_applicable: false)
102
+
103
+ custom_ruleset_klass = Class.new(Ruleset)
104
+ custom_ruleset_klass.add_rule(:rule_1)
105
+ custom_ruleset_klass.add_rule(:rule_2)
106
+
107
+ expect(custom_ruleset_klass.new(subject).not_applicable?).to eq true
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'at least one rule is applicable' do
113
+ it 'returns false' do
114
+ with_mocked_rules do |rules|
115
+ subject = double
116
+ rules << mock_rule(:rule_1, is_applicable: false)
117
+ rules << mock_rule(:rule_2, is_applicable: true)
118
+
119
+ custom_ruleset_klass = Class.new(Ruleset)
120
+ custom_ruleset_klass.add_rule(:rule_1)
121
+ custom_ruleset_klass.add_rule(:rule_2)
122
+
123
+ expect(custom_ruleset_klass.new(subject).not_applicable?).to eq false
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ describe '#satisfied?' do
130
+ context 'all rules are satisfied' do
131
+ it 'returns true' do
132
+ with_mocked_rules do |rules|
133
+ subject = double
134
+ rules << mock_rule(:rule_1)
135
+ rules << mock_rule(:rule_2)
136
+
137
+ custom_ruleset_klass = Class.new(Ruleset)
138
+ custom_ruleset_klass.add_rule(:rule_1)
139
+ custom_ruleset_klass.add_rule(:rule_2)
140
+
141
+ expect(custom_ruleset_klass.new(subject).satisfied?).to eq true
142
+ end
143
+ end
144
+ end
145
+
146
+ context 'at least one rule is not satisfied' do
147
+ it 'returns false' do
148
+ with_mocked_rules do |rules|
149
+ subject = double
150
+ rules << mock_rule(:rule_1)
151
+ rules << mock_rule(:rule_2, is_satisfied: false)
152
+
153
+ custom_ruleset_klass = Class.new(Ruleset)
154
+ custom_ruleset_klass.add_rule(:rule_1)
155
+ custom_ruleset_klass.add_rule(:rule_2)
156
+
157
+ expect(custom_ruleset_klass.new(subject).satisfied?).to eq false
158
+ end
159
+ end
160
+
161
+ context 'when rule is not applicable' do
162
+ it 'returns true' do
163
+ with_mocked_rules do |rules|
164
+ subject = double
165
+ rules << mock_rule(:rule_1)
166
+ rules << mock_rule(:rule_2, is_satisfied: false, is_applicable: false)
167
+
168
+ custom_ruleset_klass = Class.new(Ruleset)
169
+ custom_ruleset_klass.add_rule(:rule_1)
170
+ custom_ruleset_klass.add_rule(:rule_2)
171
+
172
+ expect(custom_ruleset_klass.new(subject).satisfied?).to eq true
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'when provided with force: true' do
178
+ context 'when rule is forceable' do
179
+ it 'returns true' do
180
+ with_mocked_rules do |rules|
181
+ subject = double
182
+ rules << mock_rule(:rule_1)
183
+ rules << mock_rule(:rule_2, is_satisfied: false, is_forceable: true)
184
+
185
+ custom_ruleset_klass = Class.new(Ruleset)
186
+ custom_ruleset_klass.add_rule(:rule_1)
187
+ custom_ruleset_klass.add_rule(:rule_2)
188
+
189
+ expect(custom_ruleset_klass.new(subject).satisfied?(force: true)).to eq true
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'when rule is not forceable' do
195
+ it 'returns false' do
196
+ with_mocked_rules do |rules|
197
+ subject = double
198
+ rules << mock_rule(:rule_1)
199
+ rules << mock_rule(:rule_2, is_satisfied: false, is_forceable: false)
200
+
201
+ custom_ruleset_klass = Class.new(Ruleset)
202
+ custom_ruleset_klass.add_rule(:rule_1)
203
+ custom_ruleset_klass.add_rule(:rule_2)
204
+
205
+ expect(custom_ruleset_klass.new(subject).satisfied?(force: true)).to eq false
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ describe '#each' do
214
+ it 'yields all rules for ruleset' do
215
+ with_mocked_rules do |rules|
216
+ rules << (_, rule_1 = mock_rule(:rule_1))
217
+ rules << (_, rule_2 = mock_rule(:rule_2))
218
+ rules << (_, rule_3 = mock_rule(:rule_3))
219
+ custom_ruleset_klass_1 = Class.new(Ruleset)
220
+ custom_ruleset_klass_1.add_rule(:rule_1)
221
+ custom_ruleset_klass_1.add_rule(:rule_2)
222
+ Ruleset2 = Class.new(Ruleset)
223
+ Ruleset2.add_rule(:rule_3)
224
+ custom_ruleset_klass_1.add_rule(:ruleset_2)
225
+
226
+ ruleset = custom_ruleset_klass_1.new(double)
227
+
228
+ expect { |b| ruleset.each(&b) }.to yield_successive_args(rule_1, rule_2, rule_3)
229
+ ensure
230
+ remove_class(Ruleset2)
231
+ end
232
+ end
233
+ end
234
+
235
+ private
236
+
237
+ def mock_rule(rule_name, is_applicable: true, is_satisfied: true, is_forceable: true)
238
+ klass = Object.const_set(rule_name.to_s.classify, Class.new(Rule))
239
+ rule = double(
240
+ not_applicable?: !is_applicable,
241
+ satisfied?: is_satisfied,
242
+ forceable?: is_forceable
243
+ )
244
+ allow(klass).to receive(:new).with(anything) { rule }
245
+ [klass, rule]
246
+ end
247
+
248
+ def with_mocked_rules
249
+ rules_storage = []
250
+ yield rules_storage
251
+ ensure
252
+ rules_storage.each do |rule_klass, _rule_instance|
253
+ remove_class(rule_klass)
254
+ end
255
+ end
256
+
257
+ def remove_class(klass)
258
+ Object.send(:remove_const, klass.name.to_sym)
259
+ end
260
+ end
@@ -10,7 +10,7 @@ RSpec.describe Patterns::Service do
10
10
  expect(DoSomething.call).to be_kind_of(DoSomething)
11
11
  end
12
12
 
13
- it "instantiates service object passing arguments to constructor" do
13
+ it "instantiates service object passing keyword arguments to constructor" do
14
14
  DoSomething = Class.new(Patterns::Service) do
15
15
  def initialize(argument_1:, argument_2:); end
16
16
  def call; end
@@ -25,6 +25,21 @@ RSpec.describe Patterns::Service do
25
25
  }.not_to raise_error
26
26
  end
27
27
 
28
+ it "instantiates service object passing positional arguments to constructor" do
29
+ DoSomething = Class.new(Patterns::Service) do
30
+ def initialize(argument_1, argument_2); end
31
+ def call; end
32
+ end
33
+
34
+ expect {
35
+ DoSomething.call
36
+ }.to raise_error ArgumentError
37
+
38
+ expect {
39
+ DoSomething.call(10, 20)
40
+ }.not_to raise_error
41
+ end
42
+
28
43
  it "calls #call method on service object instance" do
29
44
  Spy = Class.new do
30
45
  def self.some_method; end
@@ -0,0 +1,79 @@
1
+ RSpec.describe StrongRuleset do
2
+ it 'inherites from Ruleset' do
3
+ custom_strong_ruleset_klass = Class.new(StrongRuleset)
4
+ expect(custom_strong_ruleset_klass.ancestors).to include Ruleset
5
+ end
6
+
7
+ context 'when any of rules is not applicable' do
8
+ it 'is not satisfied' do
9
+ with_mocked_rules do |rules|
10
+ subject = double
11
+ rules << mock_rule(:rule_1, is_applicable: false)
12
+ rules << mock_rule(:rule_2)
13
+
14
+ custom_ruleset_klass = Class.new(StrongRuleset)
15
+ custom_ruleset_klass.add_rule(:rule_1)
16
+ custom_ruleset_klass.add_rule(:rule_2)
17
+
18
+ expect(custom_ruleset_klass.new(subject).satisfied?).to eq false
19
+ end
20
+ end
21
+
22
+ context 'when not applicable rule is not satisfied' do
23
+ it 'is not forceable' do
24
+ with_mocked_rules do |rules|
25
+ subject = double
26
+ rules << mock_rule(:rule_1, is_applicable: false, is_satisfied: false)
27
+ rules << mock_rule(:rule_2)
28
+
29
+ custom_ruleset_klass = Class.new(StrongRuleset)
30
+ custom_ruleset_klass.add_rule(:rule_1)
31
+ custom_ruleset_klass.add_rule(:rule_2)
32
+
33
+ expect(custom_ruleset_klass.new(subject).forceable?).to eq false
34
+ end
35
+ end
36
+ end
37
+
38
+ it 'is not applicable' do
39
+ with_mocked_rules do |rules|
40
+ subject = double
41
+ rules << mock_rule(:rule_1, is_applicable: false)
42
+ rules << mock_rule(:rule_2)
43
+
44
+ custom_ruleset_klass = Class.new(StrongRuleset)
45
+ custom_ruleset_klass.add_rule(:rule_1)
46
+ custom_ruleset_klass.add_rule(:rule_2)
47
+
48
+ expect(custom_ruleset_klass.new(subject).applicable?).to eq false
49
+ end
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def mock_rule(rule_name, is_applicable: true, is_satisfied: true, is_forceable: true)
56
+ klass = Object.const_set(rule_name.to_s.classify, Class.new(Rule))
57
+ rule = double(
58
+ not_applicable?: !is_applicable,
59
+ applicable?: is_applicable,
60
+ satisfied?: is_satisfied,
61
+ forceable?: is_forceable
62
+ )
63
+ allow(klass).to receive(:new).with(anything) { rule }
64
+ [klass, rule]
65
+ end
66
+
67
+ def with_mocked_rules
68
+ rules_storage = []
69
+ yield rules_storage
70
+ ensure
71
+ rules_storage.each do |rule_klass, _rule_instance|
72
+ remove_class(rule_klass)
73
+ end
74
+ end
75
+
76
+ def remove_class(klass)
77
+ Object.send(:remove_const, klass.name.to_sym)
78
+ end
79
+ end
@@ -17,10 +17,15 @@
17
17
  #
18
18
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
19
 
20
- require "rails-patterns"
20
+ require "active_support/all"
21
+ require "active_support/testing/time_helpers"
21
22
  require "pry"
23
+ require "redis"
24
+ require "rails-patterns"
22
25
 
23
26
  RSpec.configure do |config|
27
+ config.include ActiveSupport::Testing::TimeHelpers
28
+
24
29
  # rspec-expectations config goes here. You can use an alternate
25
30
  # assertion/expectation library such as wrong or the stdlib/minitest
26
31
  # assertions if you prefer.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-patterns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stevo
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-21 00:00:00.000000000 Z
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby2_keywords
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +86,14 @@ dependencies:
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '1.0'
89
+ version: '2.0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '1.0'
96
+ version: '2.0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: juwelier
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -103,6 +117,7 @@ extra_rdoc_files:
103
117
  - README.md
104
118
  files:
105
119
  - ".document"
120
+ - ".github/workflows/ruby.yml"
106
121
  - ".rspec"
107
122
  - Gemfile
108
123
  - Gemfile.lock
@@ -111,22 +126,33 @@ files:
111
126
  - Rakefile
112
127
  - VERSION
113
128
  - lib/patterns.rb
129
+ - lib/patterns/calculation.rb
114
130
  - lib/patterns/collection.rb
115
131
  - lib/patterns/form.rb
116
132
  - lib/patterns/query.rb
133
+ - lib/patterns/rule.rb
134
+ - lib/patterns/ruleset.rb
117
135
  - lib/patterns/service.rb
136
+ - lib/patterns/strong_ruleset.rb
118
137
  - lib/rails-patterns.rb
119
138
  - rails-patterns.gemspec
139
+ - spec/helpers/custom_calculation.rb
140
+ - spec/helpers/custom_calculation_script.rb
141
+ - spec/helpers/rails_redis_cache_mock.rb
142
+ - spec/patterns/calculation_spec.rb
120
143
  - spec/patterns/collection_spec.rb
121
144
  - spec/patterns/form_spec.rb
122
145
  - spec/patterns/query_spec.rb
146
+ - spec/patterns/rule_spec.rb
147
+ - spec/patterns/ruleset_spec.rb
123
148
  - spec/patterns/service_spec.rb
149
+ - spec/patterns/strong_ruleset_spec.rb
124
150
  - spec/spec_helper.rb
125
151
  homepage: http://github.com/selleo/pattern
126
152
  licenses:
127
153
  - MIT
128
154
  metadata: {}
129
- post_install_message:
155
+ post_install_message:
130
156
  rdoc_options: []
131
157
  require_paths:
132
158
  - lib
@@ -134,16 +160,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
160
  requirements:
135
161
  - - ">="
136
162
  - !ruby/object:Gem::Version
137
- version: '0'
163
+ version: 2.5.0
138
164
  required_rubygems_version: !ruby/object:Gem::Requirement
139
165
  requirements:
140
166
  - - ">="
141
167
  - !ruby/object:Gem::Version
142
168
  version: '0'
143
169
  requirements: []
144
- rubyforge_project:
145
- rubygems_version: 2.6.10
146
- signing_key:
170
+ rubygems_version: 3.1.2
171
+ signing_key:
147
172
  specification_version: 4
148
173
  summary: A collection of lightweight, standardized, rails-oriented patterns.
149
174
  test_files: []