magicka 1.0.0 → 1.1.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/README.md +3 -3
  4. data/config/check_specs.yml +0 -2
  5. data/config/yardstick.yml +8 -2
  6. data/lib/magicka/aggregator/method_builder.rb +35 -28
  7. data/lib/magicka/aggregator.rb +16 -8
  8. data/lib/magicka/display.rb +1 -1
  9. data/lib/magicka/element/class_methods.rb +2 -0
  10. data/lib/magicka/element.rb +4 -2
  11. data/lib/magicka/helper/aggregator_options.rb +64 -0
  12. data/lib/magicka/helper/class_methods.rb +10 -2
  13. data/lib/magicka/helper/method_builder.rb +10 -6
  14. data/lib/magicka/helper.rb +12 -6
  15. data/lib/magicka/version.rb +1 -1
  16. data/magicka.gemspec +1 -1
  17. data/spec/dummy/app/controllers/application_controller.rb +1 -0
  18. data/spec/dummy/app/controllers/documents_controller.rb +9 -0
  19. data/spec/dummy/app/models/document.rb +5 -0
  20. data/spec/dummy/app/models/magicka/data_entry.rb +7 -0
  21. data/spec/dummy/app/models/magicka/data_table.rb +6 -0
  22. data/spec/dummy/app/views/documents/show.html.erb +6 -0
  23. data/spec/dummy/app/views/templates/display/_data_entry.html.erb +2 -0
  24. data/spec/dummy/config/environments/development.rb +1 -0
  25. data/spec/dummy/config/initializers/magicka.rb +7 -0
  26. data/spec/dummy/config/routes.rb +1 -0
  27. data/spec/dummy/db/schema.rb +5 -0
  28. data/spec/integration/yard/magicka/helper_spec.rb +33 -0
  29. data/spec/lib/magicka/aggregator/class_methods_spec.rb +352 -0
  30. data/spec/lib/magicka/aggregator/method_builder_spec.rb +29 -0
  31. data/spec/lib/magicka/aggregator_spec.rb +0 -221
  32. data/spec/lib/magicka/helper/aggregator_options_spec.rb +99 -0
  33. data/spec/lib/magicka/helper/class_methods_spec.rb +101 -0
  34. data/spec/lib/magicka/helper_spec.rb +2 -18
  35. data/spec/support/factories/document.rb +7 -0
  36. data/spec/support/factory_bot.rb +7 -0
  37. data/spec/support/models/custom_aggregator.rb +12 -0
  38. data/spec/support/models/my_element.rb +6 -0
  39. metadata +21 -4
@@ -0,0 +1,352 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Magicka::Aggregator::ClassMethods do
6
+ subject(:aggregator) { aggregator_class.new(renderer, model) }
7
+
8
+ let(:aggregator_class) { Class.new(Magicka::Aggregator) }
9
+ let(:model) { :my_model }
10
+ let(:renderer) { instance_double('renderer') }
11
+ let(:template) { 'templates/forms/input' }
12
+ let(:locals) { {} }
13
+
14
+ describe '.type' do
15
+ let(:type) { %w[form display other].sample }
16
+
17
+ it 'sets aggregator type' do
18
+ expect { aggregator_class.type(type) }
19
+ .to change(aggregator_class, :type)
20
+ .from(nil).to(type.to_sym)
21
+ end
22
+
23
+ context 'when type has not been set' do
24
+ let(:aggregator_class) do
25
+ Class.new(Magicka::Aggregator) do
26
+ def self.name
27
+ 'Magicka::MyClass'
28
+ end
29
+ end
30
+ end
31
+
32
+ it 'Uses class name as type' do
33
+ expect(aggregator_class.type)
34
+ .to eq(:my_class)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '.with_element' do
40
+ let(:element_class) { Magicka::Input }
41
+
42
+ context 'when seeting element class only' do
43
+ it do
44
+ expect { aggregator_class.with_element(element_class) }
45
+ .to add_method(:input)
46
+ .to(aggregator)
47
+ end
48
+
49
+ context 'when built method is called' do
50
+ let(:template) { 'templates/forms/input' }
51
+ let(:field) { :field }
52
+ let(:label) { 'Label' }
53
+ let(:placeholder) { 'Value' }
54
+
55
+ let(:locals) do
56
+ {
57
+ field: field,
58
+ label: label,
59
+ ng_errors: 'my_model.errors.field',
60
+ ng_model: 'my_model.field',
61
+ placeholder: placeholder
62
+ }
63
+ end
64
+
65
+ let(:arguments) do
66
+ {
67
+ label: label,
68
+ placeholder: placeholder
69
+ }
70
+ end
71
+
72
+ before do
73
+ aggregator_class.with_element(element_class)
74
+
75
+ allow(renderer)
76
+ .to receive(:render)
77
+ .with(partial: template, locals: locals)
78
+ end
79
+
80
+ it 'renders an input' do
81
+ aggregator.input(field, **arguments)
82
+
83
+ expect(renderer).to have_received(:render)
84
+ end
85
+
86
+ context 'when passing a custom model' do
87
+ let(:locals) do
88
+ {
89
+ field: field,
90
+ label: label,
91
+ ng_errors: 'my_custom_model.errors.field',
92
+ ng_model: 'my_custom_model.field',
93
+ placeholder: placeholder
94
+ }
95
+ end
96
+
97
+ it 'renders an input' do
98
+ aggregator.input(field, model: 'my_custom_model', **arguments)
99
+
100
+ expect(renderer).to have_received(:render)
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'when seeting element class and method' do
107
+ it do
108
+ expect { aggregator_class.with_element(element_class, :my_input) }
109
+ .to add_method(:my_input)
110
+ .to(aggregator)
111
+ end
112
+
113
+ context 'when built method is called' do
114
+ let(:template) { 'templates/forms/input' }
115
+ let(:field) { :field }
116
+ let(:label) { 'Label' }
117
+ let(:placeholder) { 'Value' }
118
+
119
+ let(:locals) do
120
+ {
121
+ field: field,
122
+ label: label,
123
+ ng_errors: 'my_model.errors.field',
124
+ ng_model: 'my_model.field',
125
+ placeholder: placeholder
126
+ }
127
+ end
128
+
129
+ let(:arguments) do
130
+ {
131
+ label: label,
132
+ placeholder: placeholder
133
+ }
134
+ end
135
+
136
+ before do
137
+ aggregator_class.with_element(element_class, :my_input)
138
+
139
+ allow(renderer)
140
+ .to receive(:render)
141
+ .with(partial: template, locals: locals)
142
+ end
143
+
144
+ it 'renders an input' do
145
+ aggregator.my_input(field, **arguments)
146
+
147
+ expect(renderer).to have_received(:render)
148
+ end
149
+
150
+ context 'when passing a custom model' do
151
+ let(:locals) do
152
+ {
153
+ field: field,
154
+ label: label,
155
+ ng_errors: 'my_custom_model.errors.field',
156
+ ng_model: 'my_custom_model.field',
157
+ placeholder: placeholder
158
+ }
159
+ end
160
+
161
+ it 'renders an input' do
162
+ aggregator.my_input(field, model: 'my_custom_model', **arguments)
163
+
164
+ expect(renderer).to have_received(:render)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ context 'when setting element class and template' do
171
+ it do
172
+ expect do
173
+ aggregator_class.with_element(element_class, template: template)
174
+ end
175
+ .to add_method(:input)
176
+ .to(aggregator)
177
+ end
178
+
179
+ context 'when built method is called' do
180
+ let(:template) { 'my_templates/my_input' }
181
+ let(:field) { :field }
182
+ let(:label) { 'Label' }
183
+ let(:placeholder) { 'Value' }
184
+
185
+ let(:locals) do
186
+ {
187
+ field: field,
188
+ label: label,
189
+ ng_errors: 'my_model.errors.field',
190
+ ng_model: 'my_model.field',
191
+ placeholder: placeholder
192
+ }
193
+ end
194
+
195
+ let(:arguments) do
196
+ {
197
+ label: label,
198
+ placeholder: placeholder
199
+ }
200
+ end
201
+
202
+ before do
203
+ aggregator_class.with_element(element_class, template: template)
204
+
205
+ allow(renderer)
206
+ .to receive(:render)
207
+ .with(partial: template, locals: locals)
208
+ end
209
+
210
+ it 'renders an input' do
211
+ aggregator.input(field, **arguments)
212
+
213
+ expect(renderer).to have_received(:render)
214
+ end
215
+
216
+ context 'when passing a custom model' do
217
+ let(:locals) do
218
+ {
219
+ field: field,
220
+ label: label,
221
+ ng_errors: 'my_custom_model.errors.field',
222
+ ng_model: 'my_custom_model.field',
223
+ placeholder: placeholder
224
+ }
225
+ end
226
+
227
+ it 'renders an input' do
228
+ aggregator.input(field, model: 'my_custom_model', **arguments)
229
+
230
+ expect(renderer).to have_received(:render)
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ context 'when element class is defined with a string' do
237
+ let(:element_class) { 'Magicka::Input' }
238
+
239
+ it do
240
+ expect { aggregator_class.with_element(element_class) }
241
+ .to add_method(:input)
242
+ .to(aggregator)
243
+ end
244
+
245
+ context 'when built method is called' do
246
+ let(:template) { 'templates/forms/input' }
247
+ let(:field) { :field }
248
+ let(:label) { 'Label' }
249
+ let(:placeholder) { 'Value' }
250
+
251
+ let(:locals) do
252
+ {
253
+ field: field,
254
+ label: label,
255
+ ng_errors: 'my_model.errors.field',
256
+ ng_model: 'my_model.field',
257
+ placeholder: placeholder
258
+ }
259
+ end
260
+
261
+ let(:arguments) do
262
+ {
263
+ label: label,
264
+ placeholder: placeholder
265
+ }
266
+ end
267
+
268
+ before do
269
+ aggregator_class.with_element(element_class)
270
+
271
+ allow(renderer)
272
+ .to receive(:render)
273
+ .with(partial: template, locals: locals)
274
+ end
275
+
276
+ it 'renders an input' do
277
+ aggregator.input(field, **arguments)
278
+
279
+ expect(renderer).to have_received(:render)
280
+ end
281
+
282
+ context 'when passing a custom model' do
283
+ let(:locals) do
284
+ {
285
+ field: field,
286
+ label: label,
287
+ ng_errors: 'my_custom_model.errors.field',
288
+ ng_model: 'my_custom_model.field',
289
+ placeholder: placeholder
290
+ }
291
+ end
292
+
293
+ it 'renders an input' do
294
+ aggregator.input(field, model: 'my_custom_model', **arguments)
295
+
296
+ expect(renderer).to have_received(:render)
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ context 'when element class is defined with a string and the element loaded later' do
303
+ let(:element_class) { 'Magicka::SpecDefinedInput' }
304
+
305
+ it do
306
+ expect { aggregator_class.with_element(element_class, :input) }
307
+ .to add_method(:input)
308
+ .to(aggregator)
309
+ end
310
+
311
+ context 'when built method is called' do
312
+ let(:template) { 'templates/forms/my_input' }
313
+ let(:field) { :field }
314
+ let(:label) { 'Label' }
315
+ let(:placeholder) { 'Value' }
316
+
317
+ let(:locals) do
318
+ {
319
+ field: field,
320
+ label: label,
321
+ ng_errors: 'my_model.errors.field',
322
+ ng_model: 'my_model.field',
323
+ placeholder: placeholder
324
+ }
325
+ end
326
+
327
+ let(:arguments) do
328
+ {
329
+ label: label,
330
+ placeholder: placeholder
331
+ }
332
+ end
333
+
334
+ before do
335
+ aggregator_class.with_element(element_class, :input, template: template)
336
+
337
+ Magicka.const_set(:SpecDefinedInput, Class.new(Magicka::Input))
338
+
339
+ allow(renderer)
340
+ .to receive(:render)
341
+ .with(partial: template, locals: locals)
342
+ end
343
+
344
+ it 'renders an input' do
345
+ aggregator.input(field, **arguments)
346
+
347
+ expect(renderer).to have_received(:render)
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Magicka::Aggregator::MethodBuilder do
6
+ subject(:builder) do
7
+ aggregator_class.new(aggregator_class, element_class_arg)
8
+ end
9
+
10
+ let(:aggregator_class) { Class.new(described_class) }
11
+ let(:element_class_arg) { element_class }
12
+ let(:element_class) { Magicka::MyElement }
13
+
14
+ describe '#element_class' do
15
+ context 'when passing an element class' do
16
+ it do
17
+ expect(builder.element_class).to eq(element_class)
18
+ end
19
+ end
20
+
21
+ context 'when passing an element class name' do
22
+ let(:element_class_arg) { element_class.to_s }
23
+
24
+ it do
25
+ expect(builder.element_class).to eq(element_class)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -11,227 +11,6 @@ describe Magicka::Aggregator do
11
11
  let(:template) { 'templates/forms/input' }
12
12
  let(:locals) { {} }
13
13
 
14
- describe '.type' do
15
- let(:type) { %w[form display other].sample }
16
-
17
- it 'sets aggregator type' do
18
- expect { aggregator_class.type(type) }
19
- .to change(aggregator_class, :type)
20
- .from(nil).to(type.to_sym)
21
- end
22
-
23
- context 'when type has not been set' do
24
- let(:aggregator_class) do
25
- Class.new(described_class) do
26
- def self.name
27
- 'Magicka::MyClass'
28
- end
29
- end
30
- end
31
-
32
- it 'Uses class name as type' do
33
- expect(aggregator_class.type)
34
- .to eq(:my_class)
35
- end
36
- end
37
- end
38
-
39
- describe '.with_element' do
40
- context 'when seeting element class only' do
41
- it do
42
- expect { aggregator_class.with_element(Magicka::Input) }
43
- .to add_method(:input)
44
- .to(aggregator)
45
- end
46
-
47
- context 'when built method is called' do
48
- let(:template) { 'templates/forms/input' }
49
- let(:field) { :field }
50
- let(:label) { 'Label' }
51
- let(:placeholder) { 'Value' }
52
-
53
- let(:locals) do
54
- {
55
- field: field,
56
- label: label,
57
- ng_errors: 'my_model.errors.field',
58
- ng_model: 'my_model.field',
59
- placeholder: placeholder
60
- }
61
- end
62
-
63
- let(:arguments) do
64
- {
65
- label: label,
66
- placeholder: placeholder
67
- }
68
- end
69
-
70
- before do
71
- aggregator_class.with_element(Magicka::Input)
72
-
73
- allow(renderer)
74
- .to receive(:render)
75
- .with(partial: template, locals: locals)
76
- end
77
-
78
- it 'renders an input' do
79
- aggregator.input(field, **arguments)
80
-
81
- expect(renderer).to have_received(:render)
82
- end
83
-
84
- context 'when passing a custom model' do
85
- let(:locals) do
86
- {
87
- field: field,
88
- label: label,
89
- ng_errors: 'my_custom_model.errors.field',
90
- ng_model: 'my_custom_model.field',
91
- placeholder: placeholder
92
- }
93
- end
94
-
95
- it 'renders an input' do
96
- aggregator.input(field, model: 'my_custom_model', **arguments)
97
-
98
- expect(renderer).to have_received(:render)
99
- end
100
- end
101
- end
102
- end
103
-
104
- context 'when seeting element class and method' do
105
- it do
106
- expect { aggregator_class.with_element(Magicka::Input, :my_input) }
107
- .to add_method(:my_input)
108
- .to(aggregator)
109
- end
110
-
111
- context 'when built method is called' do
112
- let(:template) { 'templates/forms/input' }
113
- let(:field) { :field }
114
- let(:label) { 'Label' }
115
- let(:placeholder) { 'Value' }
116
-
117
- let(:locals) do
118
- {
119
- field: field,
120
- label: label,
121
- ng_errors: 'my_model.errors.field',
122
- ng_model: 'my_model.field',
123
- placeholder: placeholder
124
- }
125
- end
126
-
127
- let(:arguments) do
128
- {
129
- label: label,
130
- placeholder: placeholder
131
- }
132
- end
133
-
134
- before do
135
- aggregator_class.with_element(Magicka::Input, :my_input)
136
-
137
- allow(renderer)
138
- .to receive(:render)
139
- .with(partial: template, locals: locals)
140
- end
141
-
142
- it 'renders an input' do
143
- aggregator.my_input(field, **arguments)
144
-
145
- expect(renderer).to have_received(:render)
146
- end
147
-
148
- context 'when passing a custom model' do
149
- let(:locals) do
150
- {
151
- field: field,
152
- label: label,
153
- ng_errors: 'my_custom_model.errors.field',
154
- ng_model: 'my_custom_model.field',
155
- placeholder: placeholder
156
- }
157
- end
158
-
159
- it 'renders an input' do
160
- aggregator.my_input(field, model: 'my_custom_model', **arguments)
161
-
162
- expect(renderer).to have_received(:render)
163
- end
164
- end
165
- end
166
- end
167
-
168
- context 'when seeting element class and template' do
169
- it do
170
- expect do
171
- aggregator_class.with_element(Magicka::Input, template: template)
172
- end
173
- .to add_method(:input)
174
- .to(aggregator)
175
- end
176
-
177
- context 'when built method is called' do
178
- let(:template) { 'my_templates/my_input' }
179
- let(:field) { :field }
180
- let(:label) { 'Label' }
181
- let(:placeholder) { 'Value' }
182
-
183
- let(:locals) do
184
- {
185
- field: field,
186
- label: label,
187
- ng_errors: 'my_model.errors.field',
188
- ng_model: 'my_model.field',
189
- placeholder: placeholder
190
- }
191
- end
192
-
193
- let(:arguments) do
194
- {
195
- label: label,
196
- placeholder: placeholder
197
- }
198
- end
199
-
200
- before do
201
- aggregator_class.with_element(Magicka::Input, template: template)
202
-
203
- allow(renderer)
204
- .to receive(:render)
205
- .with(partial: template, locals: locals)
206
- end
207
-
208
- it 'renders an input' do
209
- aggregator.input(field, **arguments)
210
-
211
- expect(renderer).to have_received(:render)
212
- end
213
-
214
- context 'when passing a custom model' do
215
- let(:locals) do
216
- {
217
- field: field,
218
- label: label,
219
- ng_errors: 'my_custom_model.errors.field',
220
- ng_model: 'my_custom_model.field',
221
- placeholder: placeholder
222
- }
223
- end
224
-
225
- it 'renders an input' do
226
- aggregator.input(field, model: 'my_custom_model', **arguments)
227
-
228
- expect(renderer).to have_received(:render)
229
- end
230
- end
231
- end
232
- end
233
- end
234
-
235
14
  describe '#with_model' do
236
15
  let(:expected_aggregator) do
237
16
  aggregator_class.new(renderer, 'my_model.inner')
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Magicka::Helper::AggregatorOptions do
6
+ subject(:options) { described_class.new(options_hash) }
7
+
8
+ let(:options_hash) do
9
+ {
10
+ aggregator: aggregator,
11
+ type: type,
12
+ config_block: config_block
13
+ }
14
+ end
15
+
16
+ let(:aggregator_class) { Class.new(Magicka::Aggregator) }
17
+ let(:aggregator) { aggregator_class }
18
+ let(:type) { :my_aggregator }
19
+ let(:config_block) do
20
+ proc { with_element(Magicka::Input) }
21
+ end
22
+
23
+ describe '#configured_aggregator' do
24
+ let(:renderer) { instance_double(ActionView::OutputBuffer) }
25
+ let(:model) { Object.new }
26
+ let(:element_class) { Magicka::Input }
27
+
28
+ before do
29
+ allow(element_class).to receive(:render).with(
30
+ renderer: renderer,
31
+ field: :name,
32
+ model: model,
33
+ template: nil
34
+ )
35
+ end
36
+
37
+ context 'when aggregator is a class' do
38
+ context 'when config block is given' do
39
+ it 'returns the given aggregator class' do
40
+ expect(options.configured_aggregator)
41
+ .to be(aggregator)
42
+ end
43
+
44
+ it 'configure the aggregator' do
45
+ options.configured_aggregator.new(renderer, model)
46
+ .input(:name)
47
+
48
+ expect(element_class).to have_received(:render)
49
+ end
50
+ end
51
+
52
+ context 'when config block is not given' do
53
+ let(:config_block) { nil }
54
+
55
+ it 'returns the given aggregator class' do
56
+ expect(options.configured_aggregator)
57
+ .to be(aggregator)
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'when aggregator is a String' do
63
+ let(:aggregator) { "Magicka::#{aggregator_name}" }
64
+ let(:aggregator_name) { :CustomAggregator }
65
+
66
+ before { Magicka.const_set(aggregator_name, aggregator_class) }
67
+
68
+ context 'when config block is given' do
69
+ let(:aggregator_name) { :CustomAggregator1 }
70
+
71
+ it 'returns the given aggregator class' do
72
+ expect(options.configured_aggregator)
73
+ .to be(aggregator_class)
74
+ end
75
+ end
76
+
77
+ context 'when config block is given and is called' do
78
+ let(:aggregator_name) { :CustomAggregator2 }
79
+
80
+ it 'configure the aggregator' do
81
+ options.configured_aggregator.new(renderer, model)
82
+ .input(:name)
83
+
84
+ expect(element_class).to have_received(:render)
85
+ end
86
+ end
87
+
88
+ context 'when config block is not given' do
89
+ let(:aggregator_name) { :CustomAggregator3 }
90
+ let(:config_block) { nil }
91
+
92
+ it 'returns the given aggregator class' do
93
+ expect(options.configured_aggregator)
94
+ .to be(aggregator_class)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end