much-rails 0.0.1 → 0.2.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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/lib/much-rails.rb +85 -0
  4. data/lib/much-rails/action.rb +415 -0
  5. data/lib/much-rails/action/base_command_result.rb +22 -0
  6. data/lib/much-rails/action/base_result.rb +14 -0
  7. data/lib/much-rails/action/base_router.rb +474 -0
  8. data/lib/much-rails/action/controller.rb +100 -0
  9. data/lib/much-rails/action/head_result.rb +18 -0
  10. data/lib/much-rails/action/redirect_to_result.rb +18 -0
  11. data/lib/much-rails/action/render_result.rb +25 -0
  12. data/lib/much-rails/action/router.rb +101 -0
  13. data/lib/much-rails/action/send_data_result.rb +18 -0
  14. data/lib/much-rails/action/send_file_result.rb +18 -0
  15. data/lib/much-rails/action/unprocessable_entity_result.rb +37 -0
  16. data/lib/much-rails/assets.rb +54 -0
  17. data/lib/much-rails/boolean.rb +7 -0
  18. data/lib/much-rails/call_method.rb +27 -0
  19. data/lib/much-rails/call_method_callbacks.rb +122 -0
  20. data/lib/much-rails/change_action.rb +83 -0
  21. data/lib/much-rails/change_action_result.rb +59 -0
  22. data/lib/much-rails/config.rb +55 -0
  23. data/lib/much-rails/date.rb +50 -0
  24. data/lib/much-rails/decimal.rb +7 -0
  25. data/lib/much-rails/destroy_action.rb +32 -0
  26. data/lib/much-rails/destroy_service.rb +67 -0
  27. data/lib/much-rails/has_slug.rb +7 -0
  28. data/lib/much-rails/input_value.rb +19 -0
  29. data/lib/much-rails/json.rb +29 -0
  30. data/lib/much-rails/layout.rb +142 -0
  31. data/lib/much-rails/layout/helper.rb +25 -0
  32. data/lib/much-rails/mixin.rb +7 -0
  33. data/lib/much-rails/not_given.rb +7 -0
  34. data/lib/much-rails/rails_routes.rb +29 -0
  35. data/lib/much-rails/railtie.rb +39 -0
  36. data/lib/much-rails/records.rb +5 -0
  37. data/lib/much-rails/records/always_destroyable.rb +30 -0
  38. data/lib/much-rails/records/not_destroyable.rb +30 -0
  39. data/lib/much-rails/records/validate_destroy.rb +92 -0
  40. data/lib/much-rails/result.rb +7 -0
  41. data/lib/much-rails/save_action.rb +32 -0
  42. data/lib/much-rails/save_service.rb +68 -0
  43. data/lib/much-rails/service.rb +18 -0
  44. data/lib/much-rails/service_validation_errors.rb +41 -0
  45. data/lib/much-rails/time.rb +28 -0
  46. data/lib/much-rails/version.rb +3 -1
  47. data/lib/much-rails/view_models.rb +3 -0
  48. data/lib/much-rails/view_models/breadcrumb.rb +11 -0
  49. data/lib/much-rails/wrap_and_call_method.rb +41 -0
  50. data/lib/much-rails/wrap_method.rb +45 -0
  51. data/much-rails.gemspec +20 -4
  52. data/test/helper.rb +20 -2
  53. data/test/support/actions/show.rb +11 -0
  54. data/test/support/config/routes/test.rb +3 -0
  55. data/test/support/factory.rb +2 -0
  56. data/test/support/fake_action_controller.rb +63 -0
  57. data/test/unit/action/base_command_result_tests.rb +43 -0
  58. data/test/unit/action/base_result_tests.rb +22 -0
  59. data/test/unit/action/base_router_tests.rb +530 -0
  60. data/test/unit/action/controller_tests.rb +110 -0
  61. data/test/unit/action/head_result_tests.rb +24 -0
  62. data/test/unit/action/redirect_to_result_tests.rb +24 -0
  63. data/test/unit/action/render_result_tests.rb +43 -0
  64. data/test/unit/action/router_tests.rb +252 -0
  65. data/test/unit/action/send_data_result_tests.rb +24 -0
  66. data/test/unit/action/send_file_result_tests.rb +24 -0
  67. data/test/unit/action/unprocessable_entity_result_tests.rb +51 -0
  68. data/test/unit/action_tests.rb +400 -0
  69. data/test/unit/assets_tests.rb +127 -0
  70. data/test/unit/boolean_tests.rb +17 -0
  71. data/test/unit/call_method_callbacks_tests.rb +176 -0
  72. data/test/unit/call_method_tests.rb +62 -0
  73. data/test/unit/change_action_result_tests.rb +113 -0
  74. data/test/unit/change_action_tests.rb +260 -0
  75. data/test/unit/config_tests.rb +68 -0
  76. data/test/unit/date_tests.rb +55 -0
  77. data/test/unit/decimal_tests.rb +17 -0
  78. data/test/unit/destroy_action_tests.rb +83 -0
  79. data/test/unit/destroy_service_tests.rb +238 -0
  80. data/test/unit/has_slug_tests.rb +17 -0
  81. data/test/unit/input_value_tests.rb +34 -0
  82. data/test/unit/json_tests.rb +55 -0
  83. data/test/unit/layout_tests.rb +155 -0
  84. data/test/unit/mixin_tests.rb +17 -0
  85. data/test/unit/much-rails_tests.rb +82 -4
  86. data/test/unit/not_given_tests.rb +17 -0
  87. data/test/unit/rails_routes_tests.rb +28 -0
  88. data/test/unit/records/always_destroyable_tests.rb +43 -0
  89. data/test/unit/records/not_destroyable_tests.rb +40 -0
  90. data/test/unit/records/validate_destroy_tests.rb +252 -0
  91. data/test/unit/result_tests.rb +17 -0
  92. data/test/unit/save_action_tests.rb +83 -0
  93. data/test/unit/save_service_tests.rb +264 -0
  94. data/test/unit/service_tests.rb +33 -0
  95. data/test/unit/service_validation_errors_tests.rb +107 -0
  96. data/test/unit/time_tests.rb +58 -0
  97. data/test/unit/view_models/breadcrumb_tests.rb +53 -0
  98. data/test/unit/wrap_and_call_method_tests.rb +163 -0
  99. data/test/unit/wrap_method_tests.rb +112 -0
  100. metadata +356 -7
  101. data/test/unit/.keep +0 -0
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/result"
5
+
6
+ class MuchRails::Result
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::Result"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::Result }
12
+
13
+ should "be MuchResult" do
14
+ assert_that(unit_class).is(MuchResult)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/save_action"
5
+
6
+ module MuchRails::SaveAction
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::SaveAction"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::SaveAction }
12
+
13
+ should "include MuchRails::Mixin" do
14
+ assert_that(subject).includes(MuchRails::Mixin)
15
+ end
16
+ end
17
+
18
+ class ReceiverTests < UnitTests
19
+ desc "receiver"
20
+ subject{ receiver_class }
21
+
22
+ setup do
23
+ Assert.stub_on_call(receiver_class, :change_result) do |call|
24
+ @change_action_class_change_result_call = call
25
+ end
26
+ end
27
+
28
+ let(:receiver_class) do
29
+ Class.new do
30
+ include MuchRails::SaveAction
31
+
32
+ save_result{ MuchRails::Result.success }
33
+
34
+ on_call{}
35
+ end
36
+ end
37
+
38
+ should have_imeths :save_result
39
+
40
+ should "be configured as expected" do
41
+ assert_that(subject).includes(MuchRails::ChangeAction)
42
+ end
43
+
44
+ should "call .change_result for its .save_result method" do
45
+ subject.save_result
46
+
47
+ assert_that(@change_action_class_change_result_call).is_not_nil
48
+ end
49
+ end
50
+
51
+ class InitTests < ReceiverTests
52
+ desc "when init"
53
+ subject do
54
+ receiver_class.new(
55
+ params: {},
56
+ current_user: nil,
57
+ request: nil,
58
+ )
59
+ end
60
+
61
+ should have_imeths :save_result
62
+
63
+ should "call #change_result for its #save_result method" do
64
+ Assert.stub_on_call(subject, :change_result) do |call|
65
+ @change_action_instance_change_result_call = call
66
+ end
67
+
68
+ subject.save_result
69
+ assert_that(@change_action_instance_change_result_call).is_not_nil
70
+ end
71
+
72
+ should "raise a custom error message if no save result block is defined" do
73
+ Assert.stub(
74
+ receiver_class.much_rails_change_action_config,
75
+ :change_result_block,
76
+ ){ nil }
77
+
78
+ exception = assert_that{ subject.save_result }.raises
79
+ assert_that(exception.message)
80
+ .equals("A `save_result` block must be defined.")
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/save_service"
5
+
6
+ module MuchRails::SaveService
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::SaveService"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::SaveService }
12
+
13
+ should "include MuchRails::Mixin" do
14
+ assert_that(subject).includes(MuchRails::Mixin)
15
+ end
16
+ end
17
+
18
+ class ReceiverTests < UnitTests
19
+ desc "receiver"
20
+ subject{ receiver_class }
21
+
22
+ let(:receiver_class) do
23
+ Class.new do
24
+ include MuchRails::SaveService
25
+
26
+ def initialize(exception: nil)
27
+ @exception = exception
28
+ end
29
+
30
+ def on_call
31
+ raise @exception if @exception
32
+
33
+ MuchRails::Result.success
34
+ end
35
+ end
36
+ end
37
+
38
+ should "include MuchRails::Service" do
39
+ assert_that(subject).includes(MuchRails::Service)
40
+ end
41
+
42
+ should "return success" do
43
+ assert_that(subject.call.success?).is_true
44
+ end
45
+ end
46
+
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::SaveService::ValidationErrors,
59
+ :exception_classes,
60
+ ){ exception_classes }
61
+ Assert.stub_on_call(
62
+ MuchRails::SaveService::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
+ ActiveRecord::RecordInvalid.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(ActiveRecord::RecordInvalid)
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
+
130
+ setup do
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
+ ]
142
+ end
143
+
144
+ should "call #exception_classes on its ServiceValidationErrors" do
145
+ assert_that(subject.exception_classes).is(exception_classes)
146
+ end
147
+ end
148
+
149
+ class ValidationErrorsResultForTests < ValidationErrorsTests
150
+ desc ".result_for"
151
+
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
161
+
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 ValidationErrorsResultForRecordInvalidTests < ValidationErrorsTests
172
+ desc "when .result_for is passed an ActiveRecord::RecordInvalid"
173
+
174
+ let(:exception){ ActiveRecord::RecordInvalid.new(record) }
175
+ let(:record){ FakeRecord.new }
176
+
177
+ let(:no_record_exception){ ActiveRecord::RecordInvalid.new }
178
+
179
+ should "return a failure result with the record and validation errors" do
180
+ result = subject.result_for(exception)
181
+
182
+ assert_that(result.failure?).is_true
183
+ assert_that(result.exception).equals(exception)
184
+ assert_that(result.validation_errors).equals(record.errors.to_h)
185
+ assert_that(result.validation_error_messages)
186
+ .equals(record.errors.full_messages.to_a)
187
+ end
188
+
189
+ should "return a failure result with the exception and empty "\
190
+ "record errors" do
191
+ result = subject.result_for(no_record_exception)
192
+
193
+ assert_that(result.failure?).is_true
194
+ assert_that(result.exception).equals(no_record_exception)
195
+ assert_that(result.validation_errors).equals({})
196
+ assert_that(result.validation_error_messages).equals([])
197
+ end
198
+ end
199
+
200
+ class FailureResultTests < UnitTests
201
+ desc "FailureResult"
202
+ subject{ unit_class::FailureResult }
203
+
204
+ setup do
205
+ Assert.stub_tap_on_call(MuchResult, :failure) do |_, call|
206
+ @much_result_failure_call = call
207
+ end
208
+ end
209
+
210
+ let(:exception){ StandardError.new(Factory.string) }
211
+ let(:validation_errors){ { Factory.symbol => Factory.string } }
212
+ let(:custom_value){ Factory.string }
213
+
214
+ should have_imeths :new
215
+
216
+ should "use MuchResult.failure to build a result" do
217
+ result =
218
+ subject.new(
219
+ exception: exception,
220
+ validation_errors: validation_errors,
221
+ custom: custom_value,
222
+ )
223
+ assert_that(result.failure?).is_true
224
+ assert_that(@much_result_failure_call.kargs)
225
+ .equals(
226
+ exception: exception,
227
+ validation_errors: validation_errors,
228
+ custom: custom_value,
229
+ )
230
+ end
231
+
232
+ should "raise an error without an exception or validation errors" do
233
+ assert_that{
234
+ subject.new(validation_errors: validation_errors)
235
+ }.raises(ArgumentError)
236
+ end
237
+
238
+ should "raise an error without an exception or validation errors" do
239
+ assert_that{
240
+ subject.new(exception: exception)
241
+ }.raises(ArgumentError)
242
+ end
243
+ end
244
+
245
+ class FakeRecord
246
+ def self.i18n_scope
247
+ "fake_record"
248
+ end
249
+
250
+ def errors
251
+ Errors.new
252
+ end
253
+
254
+ class Errors
255
+ def to_h
256
+ { some_field: %w[ERROR1 ERROR2] }
257
+ end
258
+
259
+ def full_messages
260
+ ["some_field ERROR1", "some_field ERROR2"]
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/service"
5
+
6
+ module MuchRails::Service
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::Service"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::Service }
12
+
13
+ should "include MuchRails::Mixin" do
14
+ assert_that(subject).includes(MuchRails::Mixin)
15
+ end
16
+ end
17
+
18
+ class ReceiverTests < UnitTests
19
+ desc "receiver"
20
+ subject{ receiver_class }
21
+
22
+ let(:receiver_class) do
23
+ Class.new do
24
+ include MuchRails::Service
25
+ end
26
+ end
27
+
28
+ should "be configured as expected" do
29
+ assert_that(subject).includes(MuchRails::CallMethodCallbacks)
30
+ assert_that(subject).includes(MuchRails::WrapAndCallMethod)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MuchRails::ServiceValidationErrors
4
+ class UnitTests < Assert::Context
5
+ desc "MuchRails::ServiceValidationErrors"
6
+ subject{ unit_class }
7
+
8
+ let(:unit_class){ MuchRails::ServiceValidationErrors }
9
+ end
10
+
11
+ class InitTests < UnitTests
12
+ desc "when init"
13
+ subject{ unit_class.new }
14
+
15
+ should have_readers :hash
16
+ should have_imeths :add, :exception_classes, :result_for
17
+ end
18
+
19
+ class InitAddTests < InitTests
20
+ desc "#add"
21
+
22
+ let(:exception_class){ StandardError }
23
+ let(:block){ proc{ MuchResult.failure } }
24
+
25
+ let(:invalid_exception_class) do
26
+ [
27
+ Class.new,
28
+ Factory.string,
29
+ nil,
30
+ ].sample
31
+ end
32
+
33
+ should "add an exception class and block" do
34
+ subject.add(exception_class, &block)
35
+ assert_that(subject.hash[exception_class]).is(block)
36
+ end
37
+
38
+ should "raise an error when it's not passed an Exception" do
39
+ assert_that{
40
+ subject.add(invalid_exception_class, &block)
41
+ }.raises(ArgumentError)
42
+ end
43
+ end
44
+
45
+ class InitExceptionClassesTests < InitTests
46
+ desc "#exception_classes"
47
+
48
+ setup do
49
+ exception_classes.each do |exception_class|
50
+ subject.add(exception_class, &block)
51
+ end
52
+ end
53
+
54
+ let(:exception_classes) do
55
+ [
56
+ StandardError,
57
+ ArgumentError,
58
+ RuntimeError,
59
+ ]
60
+ end
61
+ let(:block){ proc{ MuchResult.failure } }
62
+
63
+ should "return all the added exception classes" do
64
+ assert_that(subject.exception_classes).equals(exception_classes)
65
+ end
66
+ end
67
+
68
+ class InitResultForTests < InitTests
69
+ desc "#result_for"
70
+
71
+ setup do
72
+ subject.add(exception_class, &block)
73
+ end
74
+
75
+ let(:exception){ exception_class.new(Factory.string) }
76
+ let(:exception_class){ StandardError }
77
+ let(:block) do
78
+ proc{ MuchResult.failure(error_message: failure_result_error_message) }
79
+ end
80
+ let(:failure_result_error_message){ Factory.string }
81
+
82
+ let(:inherited_exception){ RuntimeError.new(Factory.string) }
83
+
84
+ let(:invalid_exception){ Exception.new(Factory.string) }
85
+
86
+ should "return the result of calling the added block "\
87
+ "for the exception class" do
88
+ result = subject.result_for(exception)
89
+ assert_that(result.failure?).is_true
90
+ assert_that(result.error_message).equals(failure_result_error_message)
91
+ end
92
+
93
+ should "return the result of calling the added block "\
94
+ "for an exception class ancestor" do
95
+ result = subject.result_for(exception)
96
+ assert_that(result.failure?).is_true
97
+ assert_that(result.error_message).equals(failure_result_error_message)
98
+ end
99
+
100
+ should "raise an error if a block hasn't been added "\
101
+ "for the exception class" do
102
+ assert_that{
103
+ subject.result_for(invalid_exception)
104
+ }.raises(ArgumentError)
105
+ end
106
+ end
107
+ end