app_archetype 1.2.8 → 1.3.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +36 -9
  3. data/README.md +150 -28
  4. data/app_archetype.gemspec +3 -0
  5. data/bin/app_archetype +20 -0
  6. data/bin/archetype +1 -1
  7. data/lib/app_archetype/cli.rb +171 -139
  8. data/lib/app_archetype/commands/delete_template.rb +58 -0
  9. data/lib/app_archetype/commands/find_templates.rb +66 -0
  10. data/lib/app_archetype/commands/list_templates.rb +49 -0
  11. data/lib/app_archetype/commands/new_template.rb +42 -0
  12. data/lib/app_archetype/commands/open_manifest.rb +48 -0
  13. data/lib/app_archetype/commands/print_path.rb +20 -0
  14. data/lib/app_archetype/commands/print_template_variables.rb +67 -0
  15. data/lib/app_archetype/commands/print_version.rb +19 -0
  16. data/lib/app_archetype/commands/render_template.rb +178 -0
  17. data/lib/app_archetype/commands.rb +13 -0
  18. data/lib/app_archetype/generators.rb +1 -1
  19. data/lib/app_archetype/template_manager.rb +9 -0
  20. data/lib/app_archetype/version.rb +1 -1
  21. data/lib/app_archetype.rb +40 -23
  22. data/scripts/create_new_command +32 -0
  23. data/scripts/generators/command/manifest.json +15 -0
  24. data/scripts/generators/command/template/lib/app_archetype/commands/{{command_name.snake_case}}.rb.hbs +17 -0
  25. data/spec/app_archetype/cli/presenters_spec.rb +99 -99
  26. data/spec/app_archetype/cli/prompts_spec.rb +291 -291
  27. data/spec/app_archetype/cli_spec.rb +427 -65
  28. data/spec/app_archetype/commands/delete_template_spec.rb +132 -0
  29. data/spec/app_archetype/commands/find_templates_spec.rb +130 -0
  30. data/spec/app_archetype/commands/list_templates_spec.rb +55 -0
  31. data/spec/app_archetype/commands/new_template_spec.rb +84 -0
  32. data/spec/app_archetype/commands/open_manifest_spec.rb +113 -0
  33. data/spec/app_archetype/commands/print_path_spec.rb +22 -0
  34. data/spec/app_archetype/commands/print_template_variables_spec.rb +158 -0
  35. data/spec/app_archetype/commands/print_version_spec.rb +21 -0
  36. data/spec/app_archetype/commands/render_template_spec.rb +479 -0
  37. data/spec/app_archetype/generators_spec.rb +1 -1
  38. data/spec/app_archetype/template_manager_spec.rb +32 -0
  39. data/spec/app_archetype_spec.rb +65 -0
  40. metadata +79 -4
  41. data/lib/app_archetype/cli/presenters.rb +0 -106
  42. data/lib/app_archetype/cli/prompts.rb +0 -152
@@ -0,0 +1,479 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe AppArchetype::Commands::RenderTemplate do
4
+ let(:manager) { double(AppArchetype::TemplateManager) }
5
+ let(:destination_path) { 'path/to/output' }
6
+ let(:options) { Hashie::Mash.new }
7
+ let(:prompt) { double(TTY::Prompt) }
8
+
9
+ subject { described_class.new(manager, destination_path, options) }
10
+
11
+ before do
12
+ subject.instance_variable_set(:@prompt, prompt)
13
+
14
+ allow(subject).to receive(:puts)
15
+ allow(prompt).to receive(:ask)
16
+ allow(prompt).to receive(:yes?)
17
+ allow(prompt).to receive(:select)
18
+ end
19
+
20
+ describe '#run' do
21
+ let(:manifest_names) { %s( manifest1 manifest2 ) }
22
+ let(:manifest_name) { 'some-manifest' }
23
+ let(:template) { double(AppArchetype::Template) }
24
+ let(:overwrite) { true }
25
+
26
+ context 'when a name is provided in options' do
27
+ let(:options) do
28
+ Hashie::Mash.new(
29
+ name: manifest_name,
30
+ overwrite: overwrite
31
+ )
32
+ end
33
+
34
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
35
+
36
+ before do
37
+ allow(manager)
38
+ .to receive(:find_by_name)
39
+ .and_return(manifest)
40
+
41
+ allow(manifest).to receive(:template).and_return(template)
42
+ allow(template).to receive(:load)
43
+ allow(subject).to receive(:resolve_variables)
44
+ allow(subject).to receive(:render_template)
45
+ allow(subject).to receive(:puts)
46
+
47
+ subject.run
48
+ end
49
+
50
+ describe 'and template is found' do
51
+ it 'finds template by name' do
52
+ expect(manager)
53
+ .to have_received(:find_by_name)
54
+ .with(manifest_name)
55
+ end
56
+
57
+ it 'loads the template' do
58
+ expect(template)
59
+ .to have_received(:load)
60
+ end
61
+
62
+ it 'resolves variables' do
63
+ expect(subject)
64
+ .to have_received(:resolve_variables)
65
+ .with(manifest)
66
+ end
67
+
68
+ it 'renders template' do
69
+ expect(subject)
70
+ .to have_received(:render_template)
71
+ .with(
72
+ manifest,
73
+ template,
74
+ overwrite: overwrite
75
+ )
76
+ end
77
+
78
+ it 'prints success message' do
79
+ expect(subject)
80
+ .to have_received(:puts)
81
+ .with("✔ Rendered #{manifest_name} to #{destination_path}")
82
+ end
83
+ end
84
+
85
+ describe 'when template is not found' do
86
+ let(:manifest) { nil }
87
+
88
+ it 'attempts to find the template by name' do
89
+ expect(manager)
90
+ .to have_received(:find_by_name)
91
+ .with(manifest_name)
92
+ end
93
+
94
+ it 'prints no template found message' do
95
+ expect(subject)
96
+ .to have_received(:puts)
97
+ .with("✖ No template with name `#{manifest_name}` found.")
98
+ end
99
+
100
+ it 'does not resolve variables' do
101
+ expect(subject)
102
+ .not_to have_received(:resolve_variables)
103
+ end
104
+
105
+ it 'does not render template' do
106
+ expect(subject)
107
+ .not_to have_received(:render_template)
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'when name is not provided in options' do
113
+ let(:options) do
114
+ Hashie::Mash.new(
115
+ overwrite: overwrite
116
+ )
117
+ end
118
+
119
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
120
+
121
+ before do
122
+ allow(prompt).to receive(:select).and_return(manifest_name)
123
+ allow(manager)
124
+ .to receive(:manifest_names)
125
+ .and_return(manifest_names)
126
+
127
+ allow(manager)
128
+ .to receive(:find_by_name)
129
+ .and_return(manifest)
130
+
131
+ allow(manifest).to receive(:template).and_return(template)
132
+ allow(template).to receive(:load)
133
+ allow(subject).to receive(:resolve_variables)
134
+ allow(subject).to receive(:render_template)
135
+ allow(subject).to receive(:puts)
136
+
137
+ subject.run
138
+ end
139
+
140
+ it 'prompts user to select their manifest from a list' do
141
+ expect(prompt)
142
+ .to have_received(:select)
143
+ .with('Please choose manifest', manifest_names)
144
+ end
145
+
146
+ it 'loads the template' do
147
+ expect(template)
148
+ .to have_received(:load)
149
+ end
150
+
151
+ it 'resolves variables' do
152
+ expect(subject)
153
+ .to have_received(:resolve_variables)
154
+ .with(manifest)
155
+ end
156
+
157
+ it 'renders template' do
158
+ expect(subject)
159
+ .to have_received(:render_template)
160
+ .with(
161
+ manifest,
162
+ template,
163
+ overwrite: overwrite
164
+ )
165
+ end
166
+
167
+ it 'prints success message' do
168
+ expect(subject)
169
+ .to have_received(:puts)
170
+ .with("✔ Rendered #{manifest_name} to #{destination_path}")
171
+ end
172
+ end
173
+ end
174
+
175
+ describe '#resolve_variables' do
176
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
177
+ let(:variable_manager) { double(AppArchetype::Template::VariableManager) }
178
+ let(:variable) { double(AppArchetype::Template::Variable) }
179
+ let(:variables) { [variable, variable] }
180
+ let(:prompt_response) { 'some-value' }
181
+
182
+ before do
183
+ allow(manifest).to receive(:variables).and_return(variable_manager)
184
+ allow(variable_manager).to receive(:all).and_return(variables)
185
+ allow(subject).to receive(:variable_prompt_for).and_return(prompt_response)
186
+ allow(variable).to receive(:set!)
187
+
188
+ subject.resolve_variables(manifest)
189
+ end
190
+
191
+ it 'executes the variable prompt for each variable' do
192
+ expect(subject)
193
+ .to have_received(:variable_prompt_for)
194
+ .with(variable)
195
+ .twice
196
+ end
197
+
198
+ it 'sets the variable with the prompt result' do
199
+ expect(variable)
200
+ .to have_received(:set!)
201
+ .with(prompt_response)
202
+ .twice
203
+ end
204
+ end
205
+
206
+ describe '#render_template' do
207
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
208
+ let(:template) { double(AppArchetype::Template) }
209
+ let(:variables) { double(AppArchetype::Template::VariableManager) }
210
+ let(:plan) { double(AppArchetype::Template::Plan) }
211
+
212
+ before do
213
+ allow(manifest).to receive(:variables)
214
+ .and_return(variables)
215
+
216
+ allow(plan).to receive(:devise)
217
+ allow(plan).to receive(:execute)
218
+
219
+ allow(AppArchetype::Template::Plan)
220
+ .to receive(:new)
221
+ .and_return(plan)
222
+
223
+ subject.render_template(
224
+ manifest,
225
+ template
226
+ )
227
+ end
228
+
229
+ it 'constructs a plan' do
230
+ expect(AppArchetype::Template::Plan)
231
+ .to have_received(:new)
232
+ .with(template, variables, destination_path: destination_path, overwrite: false)
233
+ end
234
+
235
+ it 'devises the plan' do
236
+ expect(plan).to have_received(:devise)
237
+ end
238
+
239
+ it 'executes the plan' do
240
+ expect(plan).to have_received(:execute)
241
+ end
242
+ end
243
+
244
+ describe '#variable_prompt_for' do
245
+ let(:bool_prompt_resp) { true }
246
+ let(:int_prompt_resp) { 3 }
247
+ let(:str_prompt_resp) { 'resp' }
248
+
249
+ before do
250
+ allow(subject)
251
+ .to receive(:boolean_variable_prompt_for)
252
+ .and_return(bool_prompt_resp)
253
+
254
+ allow(subject)
255
+ .to receive(:integer_variable_prompt_for)
256
+ .and_return(int_prompt_resp)
257
+
258
+ allow(subject)
259
+ .to receive(:string_variable_prompt_for)
260
+ .and_return(str_prompt_resp)
261
+ end
262
+
263
+ context 'when variable is set' do
264
+ let(:set_variable) do
265
+ AppArchetype::Template::Variable.new(
266
+ 'string',
267
+ {
268
+ name: 'string',
269
+ description: 'a string',
270
+ value: 'already-set',
271
+ type: 'string'
272
+ }
273
+ )
274
+ end
275
+
276
+ before do
277
+ @resp = subject.variable_prompt_for(set_variable)
278
+ end
279
+
280
+ it 'returns set value' do
281
+ expect(@resp).to eq 'already-set'
282
+ end
283
+ end
284
+
285
+ context 'when variable is a boolean type' do
286
+ let(:variable) do
287
+ AppArchetype::Template::Variable.new(
288
+ 'boolean',
289
+ {
290
+ name: 'bool',
291
+ description: 'a boolean',
292
+ default: false,
293
+ type: 'boolean'
294
+ }
295
+ )
296
+ end
297
+
298
+ before do
299
+ @resp = subject.variable_prompt_for(variable)
300
+ end
301
+
302
+ it 'returns a boolean prompt for the variable' do
303
+ expect(subject).to have_received(:boolean_variable_prompt_for).with(variable)
304
+ end
305
+
306
+ it 'returns prompt response' do
307
+ expect(@resp).to eq bool_prompt_resp
308
+ end
309
+ end
310
+
311
+ context 'when variable is integer type' do
312
+ let(:variable) do
313
+ AppArchetype::Template::Variable.new(
314
+ 'integer',
315
+ {
316
+ name: 'int',
317
+ description: 'a integer',
318
+ default: 2,
319
+ type: 'integer'
320
+ }
321
+ )
322
+ end
323
+
324
+ before do
325
+ @resp = subject.variable_prompt_for(variable)
326
+ end
327
+
328
+ it 'returns a integer prompt for the variable' do
329
+ expect(subject).to have_received(:integer_variable_prompt_for).with(variable)
330
+ end
331
+
332
+ it 'returns prompt response' do
333
+ expect(@resp).to eq int_prompt_resp
334
+ end
335
+ end
336
+
337
+ context 'when variable is string type' do
338
+ let(:variable) do
339
+ AppArchetype::Template::Variable.new(
340
+ 'string',
341
+ {
342
+ name: 'string',
343
+ description: 'a string',
344
+ default: false,
345
+ type: 'string'
346
+ }
347
+ )
348
+ end
349
+
350
+ before do
351
+ @resp = subject.variable_prompt_for(variable)
352
+ end
353
+
354
+ it 'returns a string prompt for the variable' do
355
+ expect(subject).to have_received(:string_variable_prompt_for).with(variable)
356
+ end
357
+
358
+ it 'returns prompt response' do
359
+ expect(@resp).to eq str_prompt_resp
360
+ end
361
+ end
362
+ end
363
+
364
+ describe '#boolean_variable_prompt_for' do
365
+ let(:variable_name) { 'some-boolean' }
366
+ let(:variable_description) { 'A test boolean' }
367
+ let(:variable_default) { true }
368
+
369
+ let(:variable_spec) do
370
+ {
371
+ name: variable_name,
372
+ description: variable_description,
373
+ default: variable_default
374
+ }
375
+ end
376
+
377
+ let(:variable) do
378
+ AppArchetype::Template::Variable.new(
379
+ variable_name,
380
+ variable_spec
381
+ )
382
+ end
383
+
384
+ before do
385
+ subject.boolean_variable_prompt_for(variable)
386
+ end
387
+
388
+ it 'prints boolean prompt message' do
389
+ expect(subject).to have_received(:puts)
390
+ .with("• #{variable_name} (#{variable_description})")
391
+ end
392
+
393
+ it 'asks for boolean value for variable' do
394
+ expect(prompt).to have_received(:yes?)
395
+ .with(
396
+ "Enter value for `#{variable_name}` variable:",
397
+ default: variable_default
398
+ )
399
+ end
400
+ end
401
+
402
+ describe '#integer_variable_prompt_for' do
403
+ let(:variable_name) { 'some-integer' }
404
+ let(:variable_description) { 'A test integer' }
405
+ let(:variable_default) { 1 }
406
+
407
+ let(:variable_spec) do
408
+ {
409
+ name: variable_name,
410
+ description: variable_description,
411
+ default: variable_default
412
+ }
413
+ end
414
+
415
+ let(:variable) do
416
+ AppArchetype::Template::Variable.new(
417
+ variable_name,
418
+ variable_spec
419
+ )
420
+ end
421
+
422
+ before do
423
+ subject.integer_variable_prompt_for(variable)
424
+ end
425
+
426
+ it 'prints integer prompt message' do
427
+ expect(subject).to have_received(:puts)
428
+ .with("• #{variable_name} (#{variable_description})")
429
+ end
430
+
431
+ it 'asks for integer value for variable' do
432
+ expect(prompt)
433
+ .to have_received(:ask)
434
+ .with(
435
+ "Enter value for `#{variable_name}` variable:",
436
+ convert: :int,
437
+ default: variable_default
438
+ )
439
+ end
440
+ end
441
+
442
+ describe '#string_variable_prompt_for' do
443
+ let(:variable_name) { 'some-string' }
444
+ let(:variable_description) { 'A test string' }
445
+ let(:variable_default) { 'default string' }
446
+
447
+ let(:variable_spec) do
448
+ {
449
+ name: variable_name,
450
+ description: variable_description,
451
+ default: variable_default
452
+ }
453
+ end
454
+
455
+ let(:variable) do
456
+ AppArchetype::Template::Variable.new(
457
+ variable_name,
458
+ variable_spec
459
+ )
460
+ end
461
+
462
+ before do
463
+ subject.string_variable_prompt_for(variable)
464
+ end
465
+
466
+ it 'prints string prompt message' do
467
+ expect(subject).to have_received(:puts)
468
+ .with("• #{variable_name} (#{variable_description})")
469
+ end
470
+
471
+ it 'asks for string value for message' do
472
+ expect(prompt).to have_received(:ask)
473
+ .with(
474
+ "Enter value for `#{variable_name}` variable:",
475
+ default: variable_default
476
+ )
477
+ end
478
+ end
479
+ end
@@ -101,7 +101,7 @@ RSpec.describe AppArchetype::Generators do
101
101
  it 'makes template dir' do
102
102
  expect(FileUtils)
103
103
  .to have_received(:mkdir_p)
104
- .with(File.join(templates_path, name))
104
+ .with(File.join(templates_path, 'template'))
105
105
  end
106
106
 
107
107
  it 'renders blank manifest' do
@@ -218,4 +218,36 @@ RSpec.describe AppArchetype::TemplateManager do
218
218
  end
219
219
  end
220
220
  end
221
+
222
+ describe '#manifest_names' do
223
+ let(:manifest) do
224
+ AppArchetype::Template::Manifest.new(
225
+ 'path/to/manifest.json',
226
+ 'name' => 'manifest'
227
+ )
228
+ end
229
+
230
+ let(:manifests) do
231
+ [
232
+ manifest,
233
+ manifest,
234
+ manifest
235
+ ]
236
+ end
237
+
238
+ before do
239
+ subject.instance_variable_set(:@manifests, manifests)
240
+ @result = subject.manifest_names
241
+ end
242
+
243
+ it 'returns array of manifest names' do
244
+ expect(@result).to eq(
245
+ %w[
246
+ manifest
247
+ manifest
248
+ manifest
249
+ ]
250
+ )
251
+ end
252
+ end
221
253
  end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe AppArchetype do
4
+ let(:collection_dir) { 'path/to/collection' }
5
+ let(:template_name) { 'template' }
6
+ let(:destination_path) { 'path/to/destination' }
7
+
8
+ describe '.render_template' do
9
+ let(:manager) { double(AppArchetype::TemplateManager) }
10
+ let(:manifest) { double(AppArchetype::Template::Manifest) }
11
+ let(:template) { double(AppArchetype::Template) }
12
+ let(:command) { double(AppArchetype::Commands::RenderTemplate) }
13
+ let(:options) do
14
+ Hashie::Mash.new(
15
+ name: template_name,
16
+ overwrite: false
17
+ )
18
+ end
19
+
20
+ before do
21
+ allow(AppArchetype::TemplateManager)
22
+ .to receive(:new)
23
+ .and_return(manager)
24
+
25
+ allow(manager).to receive(:load)
26
+ allow(manager).to receive(:find_by_name).and_return(manifest)
27
+ allow(manifest).to receive(:template).and_return(template)
28
+ allow(template).to receive(:load)
29
+
30
+ allow(AppArchetype::Commands::RenderTemplate)
31
+ .to receive(:new)
32
+ .and_return(command)
33
+
34
+ allow(command).to receive(:run)
35
+
36
+ @manifest = described_class.render_template(
37
+ collection_dir: collection_dir,
38
+ template_name: template_name,
39
+ destination_path: destination_path
40
+ )
41
+ end
42
+
43
+ it 'loads manager' do
44
+ expect(manager).to have_received(:load)
45
+ end
46
+
47
+ it 'finds template by name' do
48
+ expect(manager).to have_received(:find_by_name)
49
+ end
50
+
51
+ it 'loads template' do
52
+ expect(template).to have_received(:load)
53
+ end
54
+
55
+ it 'runs render command' do
56
+ expect(AppArchetype::Commands::RenderTemplate)
57
+ .to have_received(:new)
58
+ .with(manager, destination_path, options)
59
+ end
60
+
61
+ it 'returns manifest' do
62
+ expect(@manifest).to eq manifest
63
+ end
64
+ end
65
+ end