much-rails 0.1.0 → 0.2.1

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.
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MuchRails; end
4
+
5
+ class MuchRails::ServiceValidationErrors
6
+ attr_reader :hash
7
+
8
+ def initialize
9
+ @hash = {}
10
+ end
11
+
12
+ def add(exception_class, &block)
13
+ unless exception_class < Exception
14
+ raise(ArgumentError, "#{exception_class} is not an Exception")
15
+ end
16
+
17
+ @hash[exception_class] = block
18
+ end
19
+
20
+ def exception_classes
21
+ @hash.keys
22
+ end
23
+
24
+ def result_for(ex)
25
+ result_proc = nil
26
+ exception_class = ex.class
27
+ loop do
28
+ result_proc = @hash[exception_class]
29
+ break unless result_proc.nil?
30
+
31
+ exception_class =
32
+ if exception_class.superclass.nil?
33
+ raise ArgumentError, "#{ex.class} hasn't been configured"
34
+ else
35
+ exception_class.superclass
36
+ end
37
+ end
38
+
39
+ result_proc.call(ex)
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MuchRails
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -24,7 +24,7 @@ Gem::Specification.new do |gem|
24
24
  gem.required_ruby_version = "~> 2.5"
25
25
 
26
26
  gem.add_development_dependency("much-style-guide", ["~> 0.6.0"])
27
- gem.add_development_dependency("assert", ["~> 2.19.4"])
27
+ gem.add_development_dependency("assert", ["~> 2.19.5"])
28
28
  gem.add_development_dependency("rails", ["> 5.0", "< 7.0"])
29
29
 
30
30
  gem.add_dependency("activerecord", ["> 5.0", "< 7.0"])
@@ -13,7 +13,7 @@ module FakeActionController
13
13
  end
14
14
 
15
15
  mixin_class_methods do
16
- def before_action(method_name)
16
+ def before_action(method_name, **)
17
17
  before_actions << method_name
18
18
  end
19
19
 
@@ -52,7 +52,7 @@ class MuchRails::Action::BaseRouter
52
52
  should have_readers :name
53
53
  should have_readers :request_type_set, :url_set, :definitions
54
54
 
55
- should have_imeths :url_class, :apply_to
55
+ should have_imeths :url_class, :unrouted_urls, :apply_to
56
56
  should have_imeths :path_for, :url_for
57
57
  should have_imeths :request_type
58
58
  should have_imeths :base_url, :url
@@ -62,6 +62,7 @@ class MuchRails::Action::BaseRouter
62
62
  assert_that(subject.name).is_nil
63
63
  assert_that(subject.request_type_set).is_empty
64
64
  assert_that(subject.url_set).is_empty
65
+ assert_that(subject.unrouted_urls).is_empty
65
66
  assert_that(subject.definitions).is_empty
66
67
  assert_that(subject.base_url).equals(unit_class::DEFAULT_BASE_URL)
67
68
  assert_that(subject.url_class).equals(unit_class.url_class)
@@ -106,6 +107,7 @@ class MuchRails::Action::BaseRouter
106
107
  assert_that(subject.url_set).is_not_empty
107
108
  assert_that(url).is_kind_of(subject.url_class)
108
109
  assert_that(@url_set_add_call.args).equals([:url1, path])
110
+ assert_that(subject.unrouted_urls).equals([url])
109
111
 
110
112
  ex =
111
113
  assert_that{ subject.url(:url2.to_s, Factory.url) }
@@ -338,13 +340,14 @@ class MuchRails::Action::BaseRouter
338
340
 
339
341
  let(:router1){ unit_class.new }
340
342
 
341
- should have_imeths :empty?, :add, :fetch, :path_for, :url_for
343
+ should have_imeths :empty?, :urls, :add, :fetch, :path_for, :url_for
342
344
 
343
345
  should "add URLs" do
344
346
  assert_that(subject).is_empty
345
347
 
346
348
  url = subject.add(:url1.to_s, path = Factory.url)
347
349
  assert_that(subject).is_not_empty
350
+ assert_that(subject.urls).equals([url])
348
351
  assert_that(url).is_kind_of(router1.url_class)
349
352
  assert_that(@url_new_call.args).equals([router1, path, :url1])
350
353
 
@@ -472,8 +475,7 @@ class MuchRails::Action::BaseRouter
472
475
  definition1 =
473
476
  definition_class.new(
474
477
  http_method: http_method1,
475
- path: url_path1,
476
- name: url_name1,
478
+ url: url1,
477
479
  default_action_class_name: default_action_class_name1,
478
480
  request_type_actions: request_type_actions1,
479
481
  called_from: caller1,
@@ -496,8 +498,7 @@ class MuchRails::Action::BaseRouter
496
498
  subject do
497
499
  definition_class.new(
498
500
  http_method: http_method1,
499
- path: url_path1,
500
- name: url_name1,
501
+ url: url1,
501
502
  default_action_class_name: default_action_class_name1,
502
503
  request_type_actions: request_type_actions1,
503
504
  default_params: default_params1,
@@ -509,19 +510,21 @@ class MuchRails::Action::BaseRouter
509
510
  { Factory.string => Factory.string }
510
511
  end
511
512
 
512
- should have_readers :http_method, :path, :name, :default_params
513
+ should have_readers :http_method, :url, :default_params
513
514
  should have_readers :default_action_class_name, :request_type_actions
514
- should have_reader :called_from
515
+ should have_readers :called_from
516
+ should have_imeths :path, :name, :has_default_action_class_name?
515
517
 
516
518
  should "know its attributes" do
517
519
  assert_that(subject.http_method).equals(http_method1)
518
- assert_that(subject.path).equals(url_path1)
519
- assert_that(subject.name).equals(url_name1)
520
+ assert_that(subject.url).equals(url1)
520
521
  assert_that(subject.default_params).equals(default_params1)
521
522
  assert_that(subject.default_action_class_name)
522
523
  .equals(default_action_class_name1)
523
524
  assert_that(subject.request_type_actions).equals(request_type_actions1)
524
525
  assert_that(subject.called_from).equals(caller1)
526
+ assert_that(subject.path).equals(url_path1)
527
+ assert_that(subject.name).equals(url_name1)
525
528
  end
526
529
  end
527
530
  end
@@ -16,6 +16,10 @@ module MuchRails::Action::Controller
16
16
  should "include MuchRails::Mixin" do
17
17
  assert_that(subject).includes(MuchRails::Mixin)
18
18
  end
19
+
20
+ should "know its constants" do
21
+ assert_that(subject::DEFAULT_ACTION_CLASS_FORMAT).equals(:any)
22
+ end
19
23
  end
20
24
 
21
25
  class ReceiverTests < UnitTests
@@ -44,8 +48,14 @@ module MuchRails::Action::Controller
44
48
 
45
49
  should have_readers :much_rails_action_class
46
50
 
47
- should have_imeths MuchRails::Action::Router::CONTROLLER_METHOD_NAME
51
+ should have_imeths(
52
+ MuchRails::Action::Router::CONTROLLER_CALL_ACTION_METHOD_NAME,
53
+ )
54
+ should have_imeths(
55
+ MuchRails::Action::Router::CONTROLLER_NOT_FOUND_METHOD_NAME,
56
+ )
48
57
  should have_imeths :much_rails_action_class_name
58
+ should have_imeths :much_rails_action_class_format
49
59
  should have_imeths :much_rails_action_params
50
60
  should have_imeths :require_much_rails_action_class
51
61
  should have_imeths :permit_all_much_rails_action_params
@@ -54,6 +64,9 @@ module MuchRails::Action::Controller
54
64
  assert_that(subject.much_rails_action_class_name)
55
65
  .equals("::Actions::Show")
56
66
 
67
+ assert_that(subject.much_rails_action_class_format)
68
+ .equals(unit_module::DEFAULT_ACTION_CLASS_FORMAT)
69
+
57
70
  assert_that(subject.much_rails_action_params)
58
71
  .equals(
59
72
  nested: { value: "VALUE 1" },
@@ -61,6 +74,11 @@ module MuchRails::Action::Controller
61
74
  )
62
75
 
63
76
  assert_that(subject.much_rails_action_class).equals(Actions::Show)
77
+
78
+ Actions::Show.format(:html)
79
+ receiver = receiver_class.new(params1)
80
+ assert_that(receiver.much_rails_action_class_format).equals(:html)
81
+ Actions::Show.format(nil)
64
82
  end
65
83
  end
66
84
 
@@ -89,49 +107,4 @@ module MuchRails::Action::Controller
89
107
  .raises(MuchRails::Action::ActionError)
90
108
  end
91
109
  end
92
-
93
- class FakeController
94
- def self.before_action(method_name)
95
- before_actions << method_name
96
- end
97
-
98
- def self.before_actions
99
- @before_actions ||= []
100
- end
101
-
102
- attr_reader :params, :head_called_with
103
-
104
- def initialize(params)
105
- @params = FakeParams.new(params)
106
- self.class.before_actions.each do |before_action|
107
- public_send(before_action)
108
- end
109
- end
110
-
111
- def head(*args)
112
- @head_called_with = args
113
- self
114
- end
115
- end
116
-
117
- class FakeParams
118
- def initialize(params)
119
- @params = params
120
- end
121
-
122
- def permit!
123
- @permit_called = true
124
- self
125
- end
126
-
127
- def [](key)
128
- @params[key]
129
- end
130
-
131
- def to_h
132
- raise "params haven't been permitted" unless @permit_called
133
-
134
- @params
135
- end
136
- end
137
110
  end
@@ -22,8 +22,10 @@ class MuchRails::Action::Router
22
22
 
23
23
  should "know its constants" do
24
24
  assert_that(subject::DEFAULT_CONTROLLER_NAME).equals("application")
25
- assert_that(subject::CONTROLLER_METHOD_NAME)
25
+ assert_that(subject::CONTROLLER_CALL_ACTION_METHOD_NAME)
26
26
  .equals(:much_rails_call_action)
27
+ assert_that(subject::CONTROLLER_NOT_FOUND_METHOD_NAME)
28
+ .equals(:much_rails_not_found)
27
29
  assert_that(subject::ACTION_CLASS_PARAM_NAME)
28
30
  .equals(:much_rails_action_class_name)
29
31
  assert_that(subject.url_class).equals(unit_class::URL)
@@ -88,17 +90,25 @@ class MuchRails::Action::Router
88
90
  subject.patch(url_name, default_class_name)
89
91
  subject.delete(url_name, default_class_name)
90
92
 
93
+ url2_name = Factory.symbol
94
+ url2_path = Factory.url
95
+ subject.url(url2_name, url2_path)
96
+
91
97
  application_routes = FakeApplicationRoutes.new
92
98
  subject.draw(application_routes)
93
99
 
100
+ expected_draw_url_to =
101
+ "#{subject.controller_name}"\
102
+ "##{unit_class::CONTROLLER_NOT_FOUND_METHOD_NAME}"
94
103
  expected_draw_route_to =
95
- "#{subject.controller_name}##{unit_class::CONTROLLER_METHOD_NAME}"
104
+ "#{subject.controller_name}"\
105
+ "##{unit_class::CONTROLLER_CALL_ACTION_METHOD_NAME}"
96
106
  expected_default_defaults =
97
107
  { unit_class::ACTION_CLASS_PARAM_NAME => default_class_name }
98
108
 
99
- assert_that(application_routes.get_calls.size).equals(2)
100
- assert_that(application_routes.get_calls.first.pargs).equals([url_path])
101
- assert_that(application_routes.get_calls.first.kargs)
109
+ assert_that(application_routes.get_calls.size).equals(3)
110
+ assert_that(application_routes.get_calls[0].pargs).equals([url_path])
111
+ assert_that(application_routes.get_calls[0].kargs)
102
112
  .equals(
103
113
  to: expected_draw_route_to,
104
114
  as: url_name,
@@ -106,13 +116,19 @@ class MuchRails::Action::Router
106
116
  { unit_class::ACTION_CLASS_PARAM_NAME => request_type_class_name },
107
117
  constraints: request_type_proc,
108
118
  )
109
- assert_that(application_routes.get_calls.last.pargs).equals([url_path])
110
- assert_that(application_routes.get_calls.last.kargs)
119
+ assert_that(application_routes.get_calls[1].pargs).equals([url_path])
120
+ assert_that(application_routes.get_calls[1].kargs)
111
121
  .equals(
112
122
  to: expected_draw_route_to,
113
123
  as: url_name,
114
124
  defaults: expected_default_defaults,
115
125
  )
126
+ assert_that(application_routes.get_calls[2].pargs).equals([url2_path])
127
+ assert_that(application_routes.get_calls[2].kargs)
128
+ .equals(
129
+ to: expected_draw_url_to,
130
+ as: url2_name,
131
+ )
116
132
 
117
133
  assert_that(application_routes.post_calls.size).equals(1)
118
134
  assert_that(application_routes.post_calls.last.pargs).equals([url_path])
@@ -44,45 +44,189 @@ module MuchRails::DestroyService
44
44
  end
45
45
  end
46
46
 
47
- class DestructionInvalidErrorSetupTests < ReceiverTests
48
- desc "with a MuchRails::Records::ValidateDestroy::DestructionInvalid error"
47
+ class ReceiverInitTests < ReceiverTests
48
+ desc "when init"
49
+ subject{ receiver_class.new(exception: exception) }
50
+
51
+ let(:exception){ nil }
52
+ end
53
+
54
+ class ReceiverInitAroundCallCallbackTests < ReceiverInitTests
55
+ desc "around_call callback"
56
+ setup do
57
+ Assert.stub(
58
+ MuchRails::DestroyService::ValidationErrors,
59
+ :exception_classes,
60
+ ){ exception_classes }
61
+ Assert.stub_on_call(
62
+ MuchRails::DestroyService::ValidationErrors,
63
+ :result_for,
64
+ ) do |call|
65
+ @result_for_call = call
66
+ validation_error_result
67
+ end
68
+ end
69
+
70
+ let(:exception){ exceptions.sample }
71
+ let(:exceptions) do
72
+ [
73
+ RuntimeError.new(Factory.string),
74
+ ArgumentError.new(Factory.string),
75
+ MuchRails::Records::DestructionInvalid.new(FakeRecord.new),
76
+ ]
77
+ end
78
+ let(:exception_classes){ exceptions.map(&:class) }
79
+ let(:validation_error_result) do
80
+ MuchResult.failure(error: result_error_message)
81
+ end
82
+ let(:result_error_message){ Factory.string }
83
+
84
+ should "rescue raised exceptions and "\
85
+ "use the ValidationErrors to build a result" do
86
+ result = subject.call
87
+
88
+ assert_that(result.failure?).is_true
89
+ assert_that(result.error).equals(result_error_message)
90
+ end
91
+ end
92
+
93
+ class ValidationErrorsTests < UnitTests
94
+ desc "ValidationErrors"
95
+ subject{ unit_class::ValidationErrors }
96
+
97
+ should have_imeths :add, :exception_classes, :result_for
98
+ should have_imeths :service_validation_errors
99
+
100
+ should "know its ServiceValidationErrors" do
101
+ assert_that(subject.service_validation_errors)
102
+ .is_an_instance_of(MuchRails::ServiceValidationErrors)
103
+ assert_that(subject.service_validation_errors.exception_classes)
104
+ .includes(MuchRails::Records::DestructionInvalid)
105
+ end
106
+ end
107
+
108
+ class ValidationErrorsAddTests < ValidationErrorsTests
109
+ desc ".add"
110
+
111
+ setup do
112
+ Assert.stub_on_call(subject.service_validation_errors, :add) do |call|
113
+ @add_call = call
114
+ end
115
+ end
116
+
117
+ let(:exception_class){ StandardError }
118
+ let(:block){ proc{ MuchResult.failure } }
119
+
120
+ should "call #add on its ServiceValidationErrors" do
121
+ subject.add(exception_class, &block)
122
+ assert_that(@add_call.args).equals([exception_class])
123
+ assert_that(@add_call.block).is(block)
124
+ end
125
+ end
126
+
127
+ class ValidationErrorsExceptionClassesTests < ValidationErrorsTests
128
+ desc ".exception_classes"
129
+
49
130
  setup do
50
- Assert.stub(exception, :record){ record }
131
+ Assert.stub(
132
+ subject.service_validation_errors,
133
+ :exception_classes,
134
+ ){ exception_classes }
135
+ end
136
+
137
+ let(:exception_classes) do
138
+ [
139
+ StandardError,
140
+ ArgumentError,
141
+ ]
51
142
  end
52
143
 
53
- let(:exception) do
54
- MuchRails::Records::ValidateDestroy::DestructionInvalid.new
144
+ should "call #exception_classes on its ServiceValidationErrors" do
145
+ assert_that(subject.exception_classes).is(exception_classes)
55
146
  end
56
147
  end
57
148
 
58
- class ExceptionWithDestructionErrorMessagesTests <
59
- DestructionInvalidErrorSetupTests
60
- desc "with an exception record that has destruction_error_messages"
149
+ class ValidationErrorsResultForTests < ValidationErrorsTests
150
+ desc ".result_for"
61
151
 
62
- let(:record){ @fake_record ||= FakeRecord.new }
152
+ setup do
153
+ Assert.stub_on_call(
154
+ subject.service_validation_errors,
155
+ :result_for,
156
+ ) do |call|
157
+ @result_for_call = call
158
+ result_for_result
159
+ end
160
+ end
63
161
 
64
- should "return a failure result with the exception and validation_errors" do
65
- result = subject.call(exception: exception)
162
+ let(:exception){ StandardError.new(Factory.string) }
163
+ let(:result_for_result){ MuchResult.failure }
164
+
165
+ should "call #result_for on its ServiceValidationErrors" do
166
+ assert_that(subject.result_for(exception)).is(result_for_result)
167
+ assert_that(@result_for_call.args).equals([exception])
168
+ end
169
+ end
170
+
171
+ class ValidationErrorsResultForDestructionInvalidTests < ValidationErrorsTests
172
+ desc "when .result_for is passed an MuchRails::Records::DestructionInvalid"
173
+
174
+ let(:exception){ MuchRails::Records::DestructionInvalid.new(record) }
175
+ let(:record){ FakeRecord.new }
176
+
177
+ should "return a failure result with the record and validation errors" do
178
+ result = subject.result_for(exception)
66
179
 
67
180
  assert_that(result.failure?).is_true
68
181
  assert_that(result.exception).equals(exception)
69
- assert_that(result.validation_errors).equals(exception.destruction_errors)
182
+ assert_that(result.validation_errors).equals(exception.errors.to_h)
183
+ assert_that(result.validation_error_messages)
184
+ .equals(exception.error_full_messages.to_a)
70
185
  end
71
186
  end
72
187
 
73
- class ExceptionWithoutDestructionErrorMessagesTests <
74
- DestructionInvalidErrorSetupTests
75
- desc "with an exception record that has no destruction_error_messages"
188
+ class FailureResultTests < UnitTests
189
+ desc "FailureResult"
190
+ subject{ unit_class::FailureResult }
191
+
192
+ setup do
193
+ Assert.stub_tap_on_call(MuchResult, :failure) do |_, call|
194
+ @much_result_failure_call = call
195
+ end
196
+ end
76
197
 
77
- let(:record){ nil }
198
+ let(:exception){ StandardError.new(Factory.string) }
199
+ let(:validation_errors){ { Factory.symbol => Factory.string } }
200
+ let(:custom_value){ Factory.string }
78
201
 
79
- should "return a failure result with the exception and empty "\
80
- "validation_errors" do
81
- result = subject.call(exception: exception)
202
+ should have_imeths :new
82
203
 
204
+ should "use MuchResult.failure to build a result" do
205
+ result =
206
+ subject.new(
207
+ exception: exception,
208
+ validation_errors: validation_errors,
209
+ custom: custom_value,
210
+ )
83
211
  assert_that(result.failure?).is_true
84
- assert_that(result.exception).equals(exception)
85
- assert_that(result.validation_errors).equals({})
212
+ assert_that(@much_result_failure_call.kargs)
213
+ .equals(
214
+ exception: exception,
215
+ validation_errors: validation_errors,
216
+ custom: custom_value,
217
+ )
218
+ end
219
+
220
+ should "raise an error without an exception or validation errors" do
221
+ assert_that{
222
+ subject.new(validation_errors: validation_errors)
223
+ }.raises(ArgumentError)
224
+ end
225
+
226
+ should "raise an error without an exception or validation errors" do
227
+ assert_that{
228
+ subject.new(exception: exception)
229
+ }.raises(ArgumentError)
86
230
  end
87
231
  end
88
232