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,16 @@
1
+ require 'active_support/all'
2
+ require 'active_support/testing/time_helpers'
3
+ require_relative 'rails_redis_cache_mock'
4
+ require_relative '../../lib/patterns/calculation'
5
+
6
+ CustomCalculation = Class.new(Patterns::Calculation) do
7
+ set_cache_expiry_every 1.hour
8
+ class_attribute :counter
9
+ self.counter = 0
10
+
11
+ private
12
+
13
+ def result
14
+ self.class.counter += 1
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'rails_redis_cache_mock'
2
+ require_relative 'custom_calculation'
3
+
4
+ CustomCalculation.result
@@ -0,0 +1,5 @@
1
+ class Rails
2
+ def self.cache
3
+ @cache ||= ActiveSupport::Cache::RedisCacheStore.new
4
+ end
5
+ end
@@ -0,0 +1,200 @@
1
+ RSpec.describe Patterns::Calculation do
2
+ before(:all) do
3
+ class Rails
4
+ def self.cache
5
+ @cache ||= ActiveSupport::Cache::MemoryStore.new
6
+ end
7
+ end
8
+ end
9
+
10
+ after(:all) do
11
+ Object.send(:remove_const, :Rails)
12
+ end
13
+
14
+ after do
15
+ Object.send(:remove_const, :CustomCalculation) if defined?(CustomCalculation)
16
+ Rails.cache.clear
17
+ ActiveSupport::Cache::RedisCacheStore.new.clear
18
+ end
19
+
20
+ describe ".result" do
21
+ it "returns a result of the calculation within a #result method" do
22
+ CustomCalculation = Class.new(Patterns::Calculation) do
23
+ private
24
+
25
+ def result
26
+ 50
27
+ end
28
+ end
29
+
30
+ expect(CustomCalculation.result).to eq 50
31
+ end
32
+
33
+ it "#result, #result_for and #calculate are aliases" do
34
+ CustomCalculation = Class.new(Patterns::Calculation)
35
+
36
+ expect(CustomCalculation.method(:result)).to eq CustomCalculation.method(:result_for)
37
+ expect(CustomCalculation.method(:result)).to eq CustomCalculation.method(:calculate)
38
+ end
39
+
40
+ it "exposes the first argument as a subject" do
41
+ CustomCalculation = Class.new(Patterns::Calculation) do
42
+ private
43
+
44
+ def result
45
+ subject
46
+ end
47
+ end
48
+
49
+ expect(CustomCalculation.result('test')).to eq 'test'
50
+ end
51
+
52
+ it "exposes all keyword arguments using #options" do
53
+ CustomCalculation = Class.new(Patterns::Calculation) do
54
+ private
55
+
56
+ def result
57
+ [options[:arg_1], options[:arg_2]]
58
+ end
59
+ end
60
+
61
+ expect(CustomCalculation.result(nil, arg_1: 20, arg_2: 30)).to eq([20, 30])
62
+ end
63
+ end
64
+
65
+ describe "caching" do
66
+ it "caches result for 'set_cache_expiry_every' period" do
67
+ travel_to DateTime.new(2017, 1, 1, 12, 0) do
68
+ CustomCalculation = Class.new(Patterns::Calculation) do
69
+ set_cache_expiry_every 1.hour
70
+
71
+ class_attribute :counter
72
+ self.counter = 0
73
+
74
+ private
75
+
76
+ def result
77
+ self.class.counter += 1
78
+ end
79
+ end
80
+
81
+ expect(CustomCalculation.result).to eq 1
82
+ expect(CustomCalculation.result).to eq 1
83
+ end
84
+
85
+ travel_to DateTime.new(2017, 1, 1, 13, 1) do
86
+ expect(CustomCalculation.result).to eq 2
87
+ expect(CustomCalculation.result).to eq 2
88
+ end
89
+ end
90
+
91
+ it "caches result for every option passed" do
92
+ CustomCalculation = Class.new(Patterns::Calculation) do
93
+ set_cache_expiry_every 1.hour
94
+
95
+ class_attribute :counter
96
+ self.counter = 0
97
+
98
+ private
99
+
100
+ def result
101
+ self.class.counter += 1
102
+ end
103
+ end
104
+
105
+ expect(CustomCalculation.result(123)).to eq 1
106
+ expect(CustomCalculation.result(123)).to eq 1
107
+ expect(CustomCalculation.result(1024)).to eq 2
108
+ expect(CustomCalculation.result(1024)).to eq 2
109
+ expect(CustomCalculation.result(1024, arg: 1)).to eq 3
110
+ expect(CustomCalculation.result(1024, arg: 1)).to eq 3
111
+ end
112
+
113
+ it "caches result for every option passed dependant on the class" do
114
+ CustomCalculation = Class.new(Patterns::Calculation) do
115
+ set_cache_expiry_every 1.hour
116
+
117
+ class_attribute :counter
118
+ self.counter = 0
119
+
120
+ private
121
+
122
+ def result
123
+ self.class.counter += 1
124
+ end
125
+ end
126
+
127
+ DifferentCalculation = Class.new(Patterns::Calculation) do
128
+ set_cache_expiry_every 1.hour
129
+
130
+ class_attribute :counter
131
+ self.counter = 100
132
+
133
+ private
134
+
135
+ def result
136
+ self.class.counter += 1
137
+ end
138
+ end
139
+
140
+ expect(CustomCalculation.result(123)).to eq 1
141
+ expect(CustomCalculation.result(123)).to eq 1
142
+ expect(DifferentCalculation.result(123)).to eq 101
143
+ expect(DifferentCalculation.result(123)).to eq 101
144
+
145
+ Object.send(:remove_const, :DifferentCalculation)
146
+ end
147
+
148
+ it "does not cache result if 'set_cache_expiry_every' is not set" do
149
+ CustomCalculation = Class.new(Patterns::Calculation) do
150
+ class_attribute :counter
151
+ self.counter = 0
152
+
153
+ private
154
+
155
+ def result
156
+ self.class.counter += 1
157
+ end
158
+ end
159
+
160
+ expect(CustomCalculation.result).to eq 1
161
+ expect(CustomCalculation.result).to eq 2
162
+ end
163
+
164
+ describe "when RedisCacheStore is used" do
165
+ it "does not store data in cache if 'cache_expiry_period' is not set" do
166
+ client = Redis.new
167
+ class Rails
168
+ def self.cache
169
+ @cache ||= ActiveSupport::Cache::RedisCacheStore.new
170
+ end
171
+ end
172
+
173
+ CustomCalculation = Class.new(Patterns::Calculation) do
174
+ class_attribute :counter
175
+ self.counter = 0
176
+
177
+ private
178
+
179
+ def result
180
+ self.class.counter += 1
181
+ end
182
+ end
183
+
184
+ expect(CustomCalculation.result).to eq 1
185
+ expect(CustomCalculation.result).to eq 2
186
+ expect(client.keys).to be_empty
187
+ end
188
+ end
189
+
190
+ it "uses cache keys consistent between processes" do
191
+ `bundle exec ruby spec/helpers/custom_calculation.rb`
192
+ Process.spawn('bundle exec ruby spec/helpers/custom_calculation_script.rb')
193
+ Process.spawn('bundle exec ruby spec/helpers/custom_calculation_script.rb')
194
+ Process.spawn('bundle exec ruby spec/helpers/custom_calculation_script.rb')
195
+ Process.waitall
196
+
197
+ expect(Redis.new.keys.length).to eq 1
198
+ end
199
+ end
200
+ end
@@ -316,7 +316,7 @@ RSpec.describe Patterns::Form do
316
316
  end
317
317
 
318
318
  describe "#to_model" do
319
- it "retruns itself" do
319
+ it "returns itself" do
320
320
  CustomForm = Class.new(Patterns::Form)
321
321
 
322
322
  form = CustomForm.new(double)
@@ -345,86 +345,132 @@ RSpec.describe Patterns::Form do
345
345
  end
346
346
  end
347
347
 
348
- describe "#model_name" do
349
- describe "#param_key" do
350
- context "resource exists" do
351
- context "resource responds to #model_name" do
352
- context "param_key is not defined" do
353
- it "returns object responding to #param_key returning resource#param_key" do
354
- CustomForm = Class.new(Patterns::Form)
355
- resource = double(model_name: double(param_key: "resource_key"))
356
-
357
- form = CustomForm.new(resource)
358
- result = form.model_name
359
-
360
- expect(result).to respond_to(:param_key)
361
- expect(result.param_key).to eq "resource_key"
362
- end
363
- end
364
-
365
- context "param_key is defined" do
366
- it "returns param_key" do
367
- CustomForm = Class.new(Patterns::Form) do
368
- param_key "test_key"
369
- end
370
- resource = double(model_name: double(param_key: "resource_key"))
348
+ describe "#to_param" do
349
+ context "resource exists" do
350
+ context "resource responds to #to_param" do
351
+ it "returns resource#to_param" do
352
+ CustomForm = Class.new(Patterns::Form)
353
+ resource = double(to_param: 100)
371
354
 
372
- form = CustomForm.new(resource)
373
- result = form.model_name
355
+ form = CustomForm.new(resource)
374
356
 
375
- expect(result.param_key).to eq "test_key"
376
- end
377
- end
357
+ expect(form.to_param).to eq 100
378
358
  end
359
+ end
360
+ end
361
+
362
+ context "resource does not exist" do
363
+ it "returns nil" do
364
+ CustomForm = Class.new(Patterns::Form)
379
365
 
380
- context "resource does not respond to #model_name" do
381
- context "param_key is not defined" do
382
- it "raises NoParamKey" do
383
- CustomForm = Class.new(Patterns::Form)
366
+ form = CustomForm.new
384
367
 
385
- form = CustomForm.new(double)
368
+ expect(form.to_param).to eq nil
369
+ end
370
+ end
371
+ end
386
372
 
387
- expect { form.model_name }.to raise_error(Patterns::Form::NoParamKey)
388
- end
389
- end
373
+ describe "#model_name" do
374
+ context "resource exists" do
375
+ context "resource responds to #model_name" do
376
+ context "param_key is not defined" do
377
+ it "returns object's model name param_key, route_key and singular_route_key" do
378
+ CustomForm = Class.new(Patterns::Form)
379
+ resource = double(model_name: double(
380
+ param_key: "resource_key",
381
+ route_key: "resource_keys",
382
+ singular_route_key: "resource_key"
383
+ ))
390
384
 
391
- context "param_key is defined" do
392
- it "returns param_key" do
393
- CustomForm = Class.new(Patterns::Form) do
394
- param_key "test_key"
395
- end
385
+ form = CustomForm.new(resource)
386
+ result = form.model_name
396
387
 
397
- form = CustomForm.new(double)
398
- result = form.model_name
388
+ expect(result).to have_attributes(
389
+ param_key: "resource_key",
390
+ route_key: "resource_keys",
391
+ singular_route_key: "resource_key"
392
+ )
393
+ end
394
+ end
399
395
 
400
- expect(result.param_key).to eq "test_key"
396
+ context "param_key is defined" do
397
+ it "returns param_key, route_key and singular_route_key derived from param key" do
398
+ CustomForm = Class.new(Patterns::Form) do
399
+ param_key "test_key"
401
400
  end
401
+ resource = double(model_name: double(
402
+ param_key: "resource_key",
403
+ route_key: "resource_keys",
404
+ singular_route_key: "resource_key"
405
+ ))
406
+
407
+ form = CustomForm.new(resource)
408
+ result = form.model_name
409
+
410
+ expect(result).to have_attributes(
411
+ param_key: "test_key",
412
+ route_key: "test_keys",
413
+ singular_route_key: "test_key"
414
+ )
402
415
  end
403
416
  end
404
417
  end
405
418
 
406
- context "resource does not exist" do
419
+ context "resource does not respond to #model_name" do
407
420
  context "param_key is not defined" do
408
421
  it "raises NoParamKey" do
409
422
  CustomForm = Class.new(Patterns::Form)
410
423
 
411
- form = CustomForm.new
424
+ form = CustomForm.new(double)
412
425
 
413
426
  expect { form.model_name }.to raise_error(Patterns::Form::NoParamKey)
414
427
  end
415
428
  end
416
429
 
417
430
  context "param_key is defined" do
418
- it "returns param_key" do
431
+ it "returns param_key, route_key and singular_route_key derived from param key" do
419
432
  CustomForm = Class.new(Patterns::Form) do
420
433
  param_key "test_key"
421
434
  end
422
435
 
423
- form = CustomForm.new
436
+ form = CustomForm.new(double)
424
437
  result = form.model_name
425
438
 
426
- expect(result.param_key).to eq "test_key"
439
+ expect(result).to have_attributes(
440
+ param_key: "test_key",
441
+ route_key: "test_keys",
442
+ singular_route_key: "test_key"
443
+ )
444
+ end
445
+ end
446
+ end
447
+ end
448
+
449
+ context "resource does not exist" do
450
+ context "param_key is not defined" do
451
+ it "raises NoParamKey" do
452
+ CustomForm = Class.new(Patterns::Form)
453
+
454
+ form = CustomForm.new
455
+
456
+ expect { form.model_name }.to raise_error(Patterns::Form::NoParamKey)
457
+ end
458
+ end
459
+
460
+ context "param_key is defined" do
461
+ it "returns param_key, route_key and singular_route_key derived from param key" do
462
+ CustomForm = Class.new(Patterns::Form) do
463
+ param_key "test_key"
427
464
  end
465
+
466
+ form = CustomForm.new
467
+ result = form.model_name
468
+
469
+ expect(result).to have_attributes(
470
+ param_key: "test_key",
471
+ route_key: "test_keys",
472
+ singular_route_key: "test_key"
473
+ )
428
474
  end
429
475
  end
430
476
  end
@@ -0,0 +1,44 @@
1
+ RSpec.describe Rule do
2
+ after(:each) do
3
+ Object.send(:remove_const, :CustomRule) if defined?(CustomRule)
4
+ end
5
+
6
+ it 'requires subject as the first argument' do
7
+ CustomRule = Class.new(Rule)
8
+
9
+ expect { CustomRule.new }.to raise_error ArgumentError
10
+ expect { CustomRule.new(Object.new) }.not_to raise_error
11
+ end
12
+
13
+ it 'requires #satisfied? method to be defined' do
14
+ InvalidCustomRule = Class.new(Rule)
15
+ CustomRule = Class.new(Rule) do
16
+ def satisfied?
17
+ true
18
+ end
19
+ end
20
+
21
+ expect { InvalidCustomRule.new(Object.new).satisfied? }.to raise_error NotImplementedError
22
+ expect { CustomRule.new(Object.new).satisfied? }.not_to raise_error
23
+ end
24
+
25
+ describe '#satisfied?' do
26
+ context 'when subject meets the conditions' do
27
+ it 'returns true' do
28
+ article = OpenStruct.new('published?' => true, 'deleted?' => false)
29
+
30
+ ArticleIsPublishedRule = Class.new(Rule) do
31
+ def satisfied?
32
+ subject.published?
33
+ end
34
+
35
+ def not_applicable?
36
+ subject.deleted?
37
+ end
38
+ end
39
+
40
+ expect(ArticleIsPublishedRule.new(article).satisfied?).to eq true
41
+ end
42
+ end
43
+ end
44
+ end