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,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/action/send_data_result"
5
+
6
+ class MuchRails::Action::SendDataResult
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::Action::SendDataResult"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::Action::SendDataResult }
12
+ end
13
+
14
+ class InitTests < UnitTests
15
+ desc "when init"
16
+ subject{ unit_class.new("DATA") }
17
+
18
+ should "know its attributes" do
19
+ assert_that(subject.command_name).equals(:send_data)
20
+ assert_that(subject.command_args).equals(["DATA"])
21
+ assert_that(subject.send_data_args).equals(subject.command_args)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/action/send_file_result"
5
+
6
+ class MuchRails::Action::SendFileResult
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::Action::SendFileResult"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::Action::SendFileResult }
12
+ end
13
+
14
+ class InitTests < UnitTests
15
+ desc "when init"
16
+ subject{ unit_class.new("FILE") }
17
+
18
+ should "know its attributes" do
19
+ assert_that(subject.command_name).equals(:send_file)
20
+ assert_that(subject.command_args).equals(["FILE"])
21
+ assert_that(subject.send_file_args).equals(subject.command_args)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/action/unprocessable_entity_result"
5
+
6
+ require "test/support/fake_action_controller"
7
+
8
+ class MuchRails::Action::UnprocessableEntityResult
9
+ class UnitTests < Assert::Context
10
+ desc "MuchRails::Action::UnprocessableEntityResult"
11
+ subject{ unit_class }
12
+
13
+ let(:unit_class){ MuchRails::Action::UnprocessableEntityResult }
14
+ end
15
+
16
+ class InitTests < UnitTests
17
+ desc "when init"
18
+ subject{ unit_class.new(errors1) }
19
+
20
+ let(:controller1){ FakeController.new(params1) }
21
+ let(:params1) do
22
+ {
23
+ MuchRails::Action::Router::ACTION_CLASS_PARAM_NAME => "Actions::Show",
24
+ }
25
+ end
26
+ let(:errors1) do
27
+ { field: "ERROR 1" }
28
+ end
29
+
30
+ should have_readers :errors
31
+
32
+ should "know its attributes" do
33
+ assert_that(subject.errors).equals(errors1)
34
+
35
+ controller1.instance_exec(subject, &subject.execute_block)
36
+ assert_that(controller1.render_called_with)
37
+ .equals(
38
+ json:
39
+ {
40
+ field: "ERROR 1",
41
+ "nested[field]" => "ERROR 1",
42
+ },
43
+ status: :unprocessable_entity,
44
+ )
45
+ end
46
+ end
47
+
48
+ class FakeController
49
+ include FakeActionController
50
+ end
51
+ end
@@ -0,0 +1,400 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "assert"
4
+ require "much-rails/action"
5
+
6
+ module MuchRails::Action
7
+ class UnitTests < Assert::Context
8
+ desc "MuchRails::Action"
9
+ subject{ unit_class }
10
+
11
+ let(:unit_class){ MuchRails::Action }
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(MuchRails.config.action, :namespace){ "Actions::" }
24
+ Assert.stub(receiver_class, :to_s) do
25
+ "#{MuchRails.config.action.namespace}Some::Namespace::For::"\
26
+ "#{MuchRails.config.action.namespace}Thing::Show"
27
+ end
28
+ end
29
+
30
+ let(:receiver_class) do
31
+ Class.new do
32
+ include MuchRails::Action
33
+ end
34
+ end
35
+
36
+ let(:block1){ ->{} }
37
+ let(:block2){ ->{} }
38
+
39
+ should have_imeths :action_error_class, :params_root, :required_params
40
+ should have_imeths :date_params, :time_params, :boolean_params, :format
41
+ should have_imeths :on_validation, :on_validation_blocks
42
+ should have_imeths :on_call, :on_call_block
43
+ should have_imeths :on_before_call, :on_before_call_blocks
44
+ should have_imeths :on_after_call, :on_after_call_blocks
45
+
46
+ should "be configured as expected" do
47
+ assert_that(subject).includes(MuchRails::Config)
48
+ assert_that(subject).includes(MuchRails::WrapAndCallMethod)
49
+
50
+ assert_that(subject.much_rails_action_config)
51
+ .is_instance_of(MuchRails::Action::MuchRailsActionConfig)
52
+ end
53
+
54
+ should "know its atributes" do
55
+ # action_error_class
56
+ assert_that(subject.action_error_class).is(MuchRails::Action::ActionError)
57
+
58
+ # params_root
59
+ assert_that{ subject.params_root("ROOT VALUE1", "ROOT VALUE2") }
60
+ .changes(
61
+ "subject.much_rails_action_config.params_root.dup",
62
+ from: nil,
63
+ to: ["ROOT VALUE1", "ROOT VALUE2"],
64
+ )
65
+ assert_that(subject.params_root).equals(["ROOT VALUE1", "ROOT VALUE2"])
66
+
67
+ # required_params
68
+ assert_that{ subject.required_params(:test_param, :other_param) }
69
+ .changes(
70
+ "subject.much_rails_action_config.required_params.dup",
71
+ from: [],
72
+ to: [:test_param, :other_param],
73
+ )
74
+ assert_that(subject.required_params).equals([:test_param, :other_param])
75
+
76
+ # date_params
77
+ assert_that{ subject.date_params(:test_param, :other_param) }
78
+ .changes(
79
+ "subject.much_rails_action_config.date_params.dup",
80
+ from: [],
81
+ to: [:test_param, :other_param],
82
+ )
83
+ assert_that(subject.date_params).equals([:test_param, :other_param])
84
+
85
+ # time_params
86
+ assert_that{ subject.time_params(:test_param, :other_param) }
87
+ .changes(
88
+ "subject.much_rails_action_config.time_params.dup",
89
+ from: [],
90
+ to: [:test_param, :other_param],
91
+ )
92
+ assert_that(subject.time_params).equals([:test_param, :other_param])
93
+
94
+ # boolean_params
95
+ assert_that{ subject.boolean_params(:test_param, :other_param) }
96
+ .changes(
97
+ "subject.much_rails_action_config.boolean_params.dup",
98
+ from: [],
99
+ to: [:test_param, :other_param],
100
+ )
101
+ assert_that(subject.boolean_params).equals([:test_param, :other_param])
102
+
103
+ # format
104
+ assert_that{ subject.format("VALUE") }
105
+ .changes(
106
+ "subject.much_rails_action_config.format.dup",
107
+ from: nil,
108
+ to: "VALUE",
109
+ )
110
+ assert_that(subject.format).equals("VALUE")
111
+
112
+ # on_validation
113
+ assert_that{ subject.on_validation(&block1) }
114
+ .changes(
115
+ "subject.much_rails_action_config.on_validation_blocks.dup",
116
+ from: [],
117
+ to: [block1],
118
+ )
119
+
120
+ # on_validation_blocks
121
+ assert_that{ subject.on_validation(&block2) }
122
+ .changes(
123
+ "subject.on_validation_blocks.dup",
124
+ from: [block1],
125
+ to: [block1, block2],
126
+ )
127
+
128
+ # on_call, on_call_block
129
+ subject.on_call(&block1)
130
+ assert_that(subject.much_rails_action_config.on_call_block)
131
+ .equals(block1)
132
+ assert_that(subject.on_call_block).equals(block1)
133
+
134
+ # on_before_call
135
+ assert_that{ subject.on_before_call(&block1) }
136
+ .changes(
137
+ "subject.much_rails_action_config.on_before_call_blocks.dup",
138
+ from: [],
139
+ to: [block1],
140
+ )
141
+
142
+ # on_before_call_blocks
143
+ assert_that{ subject.on_before_call(&block2) }
144
+ .changes(
145
+ "subject.on_before_call_blocks.dup",
146
+ from: [block1],
147
+ to: [block1, block2],
148
+ )
149
+
150
+ # on_after_call
151
+ assert_that{ subject.on_after_call(&block1) }
152
+ .changes(
153
+ "subject.much_rails_action_config.on_after_call_blocks.dup",
154
+ from: [],
155
+ to: [block1],
156
+ )
157
+
158
+ # on_after_call_blocks
159
+ assert_that{ subject.on_after_call(&block2) }
160
+ .changes(
161
+ "subject.on_after_call_blocks.dup",
162
+ from: [block1],
163
+ to: [block1, block2],
164
+ )
165
+
166
+ # default_action_template_name
167
+ assert_that(subject.default_action_template_name)
168
+ .equals(
169
+ "some/namespace/for/"\
170
+ "#{MuchRails.config.action.namespace.tableize.singularize}"\
171
+ "thing/show",
172
+ )
173
+ end
174
+ end
175
+
176
+ class InitTests < ReceiverTests
177
+ desc "when init"
178
+ subject do
179
+ receiver_class.new(
180
+ params: params1,
181
+ current_user: current_user1,
182
+ request: request1,
183
+ )
184
+ end
185
+
186
+ let(:receiver_class) do
187
+ Class.new do
188
+ include MuchRails::Action
189
+
190
+ attr_reader :before_call_called, :after_call_called, :call_called
191
+
192
+ params_root :some_root_param
193
+ required_params :name
194
+ date_params :entered_on
195
+ time_params :updated_at
196
+ boolean_params :active
197
+
198
+ format :json
199
+
200
+ on_validation do
201
+ if params[:validate_other_param] && params[:other_param].blank?
202
+ add_required_param_error(:other_param)
203
+ end
204
+
205
+ if params[:fail_custom_validation]
206
+ errors[:custom_validation] << "ERROR1"
207
+ end
208
+ end
209
+
210
+ on_before_call do
211
+ @before_call_called = true
212
+ end
213
+
214
+ on_call do
215
+ @call_called = true
216
+ end
217
+
218
+ on_after_call do
219
+ @after_call_called = true
220
+ end
221
+ end
222
+ end
223
+
224
+ let(:current_date){ Date.current }
225
+ let(:current_time){ Time.current }
226
+ let(:date1){ current_date }
227
+ let(:time1){ current_time.utc }
228
+
229
+ let(:params1) do
230
+ {
231
+ name: "NAME",
232
+ entered_on: current_date,
233
+ updated_at: current_time.utc,
234
+ active: "true",
235
+ }
236
+ end
237
+ let(:current_user1){ "CURRENT USER 1" }
238
+ let(:request1){ "REQUEST 1" }
239
+
240
+ should have_readers :params, :current_user, :request, :errors
241
+ should have_imeths :on_call, :valid_action?, :successful_action?
242
+
243
+ should "know its attributes" do
244
+ assert_that(subject.params).equals(params1.with_indifferent_access)
245
+ assert_that(subject.current_user).equals(current_user1)
246
+ assert_that(subject.request).equals(request1)
247
+ end
248
+
249
+ should "return the expected Result" do
250
+ result = subject.call
251
+ assert_that(result.head_args).equals([:ok])
252
+
253
+ assert_that(subject.before_call_called).is_true
254
+ assert_that(subject.call_called).is_true
255
+ assert_that(subject.after_call_called).is_true
256
+
257
+ assert_that(subject.entered_on).equals(date1)
258
+ assert_that(subject.updated_at.iso8601).equals(time1.iso8601)
259
+ assert_that(subject.active?).is_true
260
+ end
261
+
262
+ should "return the expected Result when halted in an on_validation block" do
263
+ receiver_class.on_validation{ halt }
264
+ result = subject.call
265
+ assert_that(result.head_args).equals([:ok])
266
+
267
+ assert_that(subject.before_call_called).is_nil
268
+ assert_that(subject.call_called).is_nil
269
+ assert_that(subject.after_call_called).is_nil
270
+ end
271
+
272
+ should "return the expected Result "\
273
+ "when halted in an on_before_call block" do
274
+ receiver_class.on_before_call{ halt }
275
+ result = subject.call
276
+ assert_that(result.head_args).equals([:ok])
277
+
278
+ assert_that(subject.before_call_called).is_true
279
+ assert_that(subject.call_called).is_nil
280
+ assert_that(subject.after_call_called).is_nil
281
+ end
282
+
283
+ should "return the expected Result when halted in the on_call block" do
284
+ receiver_class.on_call{ halt }
285
+ result = subject.call
286
+ assert_that(result.head_args).equals([:ok])
287
+
288
+ assert_that(subject.before_call_called).is_true
289
+ assert_that(subject.call_called).is_nil
290
+ assert_that(subject.after_call_called).is_true
291
+ end
292
+
293
+ should "return the expected Result when halted in an on_after_call block" do
294
+ receiver_class.on_after_call{ halt }
295
+ result = subject.call
296
+ assert_that(result.head_args).equals([:ok])
297
+
298
+ assert_that(subject.before_call_called).is_true
299
+ assert_that(subject.call_called).is_true
300
+ assert_that(subject.after_call_called).is_true
301
+ end
302
+
303
+ should "return the expected Result given an on_call block that renders" do
304
+ view_model = Object.new
305
+ receiver_class.on_call{ render(view_model) }
306
+ result = subject.call
307
+ assert_that(result.render_view_model).is(view_model)
308
+ assert_that(result.render_kargs)
309
+ .equals(template: subject.class.default_action_template_name)
310
+
311
+ receiver_class.on_call{ render("some/view/template", layout: false) }
312
+ action = receiver_class.new(params: params1)
313
+ result = action.call
314
+ assert_that(result.render_view_model).is_nil
315
+ assert_that(result.render_kargs)
316
+ .equals(
317
+ template: "some/view/template",
318
+ layout: false,
319
+ )
320
+
321
+ receiver_class.on_call do
322
+ render(view_model, "some/view/template", layout: false)
323
+ end
324
+ action = receiver_class.new(params: params1)
325
+ result = action.call
326
+ assert_that(result.render_view_model).is(view_model)
327
+ assert_that(result.render_kargs)
328
+ .equals(
329
+ template: "some/view/template",
330
+ layout: false,
331
+ )
332
+
333
+ receiver_class.on_call do
334
+ render(view_model, "some/view/template", template: "other/template")
335
+ end
336
+ action = receiver_class.new(params: params1)
337
+ result = action.call
338
+ assert_that(result.render_view_model).is(view_model)
339
+ assert_that(result.render_kargs).equals(template: "other/template")
340
+
341
+ receiver_class.on_call{ render(view_model, template: "other/template") }
342
+ action = receiver_class.new(params: params1)
343
+ result = action.call
344
+ assert_that(result.render_view_model).is(view_model)
345
+ assert_that(result.render_kargs).equals(template: "other/template")
346
+ end
347
+
348
+ should "return the expected Result given an on_call block that redirects" do
349
+ receiver_class.on_call{ redirect_to("URL") }
350
+ result = subject.call
351
+ assert_that(result.redirect_to_args).equals(["URL"])
352
+ end
353
+
354
+ should "return the expected Result "\
355
+ "given an on_call block that responds with a header" do
356
+ receiver_class.on_call{ head(:not_found) }
357
+ result = subject.call
358
+ assert_that(result.head_args).equals([:not_found])
359
+ end
360
+
361
+ should "return the expected Result "\
362
+ "given an on_call block that sends a file" do
363
+ receiver_class.on_call{ send_file("FILE") }
364
+ result = subject.call
365
+ assert_that(result.send_file_args).equals(["FILE"])
366
+ end
367
+
368
+ should "return the expected Result "\
369
+ "given an on_call block that sends data" do
370
+ receiver_class.on_call{ send_data("DATA") }
371
+ result = subject.call
372
+ assert_that(result.send_data_args).equals(["DATA"])
373
+ end
374
+
375
+ should "return the expected Result given invalid params" do
376
+ Assert.stub(subject, :valid_action?){ false }
377
+ result = subject.call
378
+ assert_that(result.errors).equals(subject.errors)
379
+
380
+ params1.delete(:name)
381
+ result = receiver_class.new(params: params1).call
382
+ assert_that(result.errors[:name]).includes("can't be blank")
383
+
384
+ params1[:entered_on] = "INVALID DATE"
385
+ result = receiver_class.new(params: params1).call
386
+ assert_that(result.errors[:entered_on]).includes("invalid date")
387
+
388
+ params1[:updated_at] = "INVALID TIME"
389
+ result = receiver_class.new(params: params1).call
390
+ assert_that(result.errors[:updated_at]).includes("invalid time")
391
+
392
+ params1[:validate_other_param] = true
393
+ params1[:other_param] = [nil, ""].sample
394
+ params1[:fail_custom_validation] = true
395
+ result = receiver_class.new(params: params1).call
396
+ assert_that(result.errors[:other_param]).includes("can't be blank")
397
+ assert_that(result.errors[:custom_validation]).includes("ERROR1")
398
+ end
399
+ end
400
+ end