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,178 @@
1
+ require 'tty-prompt'
2
+
3
+ module AppArchetype
4
+ module Commands
5
+ # Prompts user for variable values and renders template to disk
6
+ class RenderTemplate
7
+ def initialize(manager, destination_path, options = Hashie::Mash.new)
8
+ @manager = manager
9
+ @destination_path = destination_path
10
+ @options = options
11
+ @prompt = TTY::Prompt.new
12
+ end
13
+
14
+ ##
15
+ # Renders a template with instructions described
16
+ # in the manifest.
17
+ #
18
+ # First it looks to the options to determine the
19
+ # name of the manifest. If one is not provided
20
+ # then the user will be prompted to choose a manifest
21
+ # from the list.
22
+ #
23
+ # The manager will then attempt to find the manifest.
24
+ # if one is not found then a RuntimeError will be raised.
25
+ #
26
+ # Once the manifest is loaded the template will be loaded
27
+ # into memory.
28
+ #
29
+ # Then the variables specified in the manifest are
30
+ # resolved. This involves the command prompting
31
+ # for values.
32
+ #
33
+ # A plan can then be constructed with the template and
34
+ # variables, this plan is then devised and executed.
35
+ #
36
+ # When the render is successful a success message
37
+ # is sent to STDOUT to confirm the operation was
38
+ # successful.
39
+ #
40
+ def run
41
+ name = @options.name
42
+ name ||= @prompt.select('Please choose manifest', @manager.manifest_names)
43
+
44
+ manifest = @manager.find_by_name(name)
45
+
46
+ unless manifest
47
+ puts "✖ No template with name `#{name}` found."
48
+ return
49
+ end
50
+
51
+ template = manifest.template
52
+ template.load
53
+
54
+ resolve_variables(manifest)
55
+ render_template(
56
+ manifest,
57
+ template,
58
+ overwrite: @options.overwrite
59
+ )
60
+
61
+ puts("✔ Rendered #{name} to #{@destination_path}")
62
+ end
63
+
64
+ ##
65
+ # Prompts user for values for each variable
66
+ # specified in the given manifest. And then
67
+ # sets the value of those variables to the
68
+ # answers to the prompts.
69
+ #
70
+ # @param[AppArchetype::Template::Manifest] manifest
71
+ #
72
+ def resolve_variables(manifest)
73
+ manifest.variables.all.each do |var|
74
+ value = variable_prompt_for(var)
75
+ var.set!(value)
76
+ end
77
+ end
78
+
79
+ ##
80
+ # Builds plan to render template and executes
81
+ # it - essentially rendering the template to
82
+ # the output location
83
+ #
84
+ # @param [AppArchetype::Template::Manifest] manifest
85
+ # @param [AppArchetype::Template] template
86
+ # @param [Boolean] overwrite
87
+ #
88
+ def render_template(
89
+ manifest,
90
+ template,
91
+ overwrite: false
92
+ )
93
+ plan = AppArchetype::Template::Plan.new(
94
+ template,
95
+ manifest.variables,
96
+ destination_path: @destination_path,
97
+ overwrite: overwrite
98
+ )
99
+
100
+ plan.devise
101
+ plan.execute
102
+ end
103
+
104
+ ##
105
+ # Resolver for a given variable
106
+ #
107
+ # First, it will set the value if the value is set in
108
+ # the manifest.
109
+ #
110
+ # Otherwise it will call a function that prompts
111
+ # a user for input depending on type.
112
+ #
113
+ # By default it will call the string variable prompt
114
+ #
115
+ # @param [AppArchetype::Template::Variable] var
116
+ #
117
+ # @return [Object]
118
+ #
119
+ def variable_prompt_for(var)
120
+ return var.value if var.value?
121
+ return boolean_variable_prompt_for(var) if var.type == 'boolean'
122
+ return integer_variable_prompt_for(var) if var.type == 'integer'
123
+
124
+ string_variable_prompt_for(var)
125
+ end
126
+
127
+ ##
128
+ # Prompts and then asks for boolean input for
129
+ # a boolean variable
130
+ #
131
+ # @param [AppArchetype::Template::Variable] var
132
+ #
133
+ # @return [Boolean]
134
+ #
135
+ def boolean_variable_prompt_for(var)
136
+ puts "• #{var.name} (#{var.description})"
137
+
138
+ @prompt.yes?(
139
+ "Enter value for `#{var.name}` variable:",
140
+ default: var.default
141
+ )
142
+ end
143
+
144
+ ##
145
+ # Prompts and then asks for integer input for
146
+ # a integer variable
147
+ #
148
+ # @param [AppArchetype::Template::Variable] var
149
+ #
150
+ # @return [Integer]
151
+ #
152
+ def integer_variable_prompt_for(var)
153
+ puts "• #{var.name} (#{var.description})"
154
+
155
+ @prompt.ask("Enter value for `#{var.name}` variable:",
156
+ convert: :int,
157
+ default: var.default)
158
+ end
159
+
160
+ ##
161
+ # Prompts and then asks for string input for
162
+ # a string variable
163
+ #
164
+ # @param [AppArchetype::Template::Variable] var
165
+ #
166
+ # @return [String]
167
+ #
168
+ def string_variable_prompt_for(var)
169
+ puts "• #{var.name} (#{var.description})"
170
+
171
+ @prompt.ask(
172
+ "Enter value for `#{var.name}` variable:",
173
+ default: var.default
174
+ )
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,13 @@
1
+ require 'hashie'
2
+
3
+ COMMANDS = File.join(__dir__, 'commands', '*.rb')
4
+
5
+ Dir[COMMANDS].sort.each do |file|
6
+ require file
7
+ end
8
+
9
+ module AppArchetype
10
+ # Module for CLI command classes
11
+ module Commands
12
+ end
13
+ end
@@ -60,7 +60,7 @@ module AppArchetype
60
60
  # @param [String] path
61
61
  #
62
62
  def render_empty_template(name, path)
63
- template_path = File.join(path, name)
63
+ template_path = File.join(path, 'template')
64
64
  manifest_path = File.join(path, 'manifest.json')
65
65
  readme_path = File.join(path, 'README.md')
66
66
 
@@ -109,5 +109,14 @@ module AppArchetype
109
109
 
110
110
  results.first
111
111
  end
112
+
113
+ ##
114
+ # Returns a list of manifest names from loaded templates
115
+ #
116
+ # @return [Array]
117
+ #
118
+ def manifest_names
119
+ @manifests.map(&:name)
120
+ end
112
121
  end
113
122
  end
@@ -2,5 +2,5 @@ module AppArchetype
2
2
  ##
3
3
  # AppArchetype version
4
4
  #
5
- VERSION = '1.2.8'.freeze
5
+ VERSION = '1.3.0'.freeze
6
6
  end
data/lib/app_archetype.rb CHANGED
@@ -7,41 +7,58 @@ require 'app_archetype/template_manager'
7
7
  require 'app_archetype/renderer'
8
8
  require 'app_archetype/generators'
9
9
 
10
- require 'app_archetype/cli/prompts'
11
-
12
10
  require 'app_archetype/version'
11
+ require_relative './app_archetype/commands'
13
12
 
14
13
  # AppArchetype is the namespace for app_archetype
15
14
  module AppArchetype
16
- def self.render(
17
- name,
18
- templates_dir,
19
- destination_path: Dir.pwd,
20
- overwrite: true,
21
- variables: []
15
+ ##
16
+ # Self contained template render method
17
+ #
18
+ # Takes collection directory and template name to
19
+ # load a new manager and find the desired template
20
+ #
21
+ # Then executes a render template command with the
22
+ # found template
23
+ #
24
+ # Returns the manifest rendered. Target can optionally
25
+ # be set to overwrite
26
+ #
27
+ # This method is to be used for self contained rendering#
28
+ # scripts.
29
+ #
30
+ # @param [String] collection_dir
31
+ # @param [String] template_name
32
+ # @param [String] destination_path
33
+ # @param [Boolean] overwrite
34
+ #
35
+ # @return [AppArchetype::Template::Manifest]
36
+ #
37
+ def self.render_template(
38
+ collection_dir: ENV.fetch('ARCHETYPE_TEMPLATE_DIR'),
39
+ template_name: '',
40
+ destination_path: '',
41
+ overwrite: false
22
42
  )
23
- manifest_file = File.join(templates_dir, name, 'manifest.json')
43
+ manager = AppArchetype::TemplateManager.new(collection_dir)
44
+ manager.load
24
45
 
25
- manifest = AppArchetype::Template::Manifest.new_from_file(manifest_file)
46
+ manifest = manager.find_by_name(template_name)
26
47
 
27
48
  template = manifest.template
28
49
  template.load
29
50
 
30
- variables.each { |var| manifest.variables.add(var) }
31
-
32
- manifest.variables.all.each do |var|
33
- value = AppArchetype::CLI::Prompts.variable_prompt_for(var)
34
- var.set!(value)
35
- end
36
-
37
- plan = AppArchetype::Template::Plan.new(
38
- template,
39
- manifest.variables,
40
- destination_path: destination_path,
51
+ options = Hashie::Mash.new(
52
+ name: template_name,
41
53
  overwrite: overwrite
42
54
  )
43
55
 
44
- plan.devise
45
- plan.execute
56
+ command = AppArchetype::Commands::RenderTemplate.new(
57
+ manager, destination_path, options
58
+ )
59
+
60
+ command.run
61
+
62
+ manifest
46
63
  end
47
64
  end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/app_archetype'
4
+
5
+ puts 'CREATE NEW COMMAND'
6
+
7
+ manifest = AppArchetype.render_template(
8
+ collection_dir: File.join(__dir__, 'generators'),
9
+ template_name: 'command',
10
+ destination_path: File.expand_path(File.join(__dir__, '..'))
11
+ )
12
+
13
+ command_name = manifest.variables.get('command_name').value
14
+
15
+ next_steps = <<~TEXT
16
+ ✔ Command created
17
+
18
+ TODO:
19
+
20
+ Add the following to cli.rb within AppArchetype::CLI:
21
+
22
+ ```
23
+ desc '#{command_name.snake_case}', 'TODO: description'
24
+
25
+ def #{command_name.snake_case}
26
+ cmd = AppArchetype::Commands::#{command_name.camel_case}.new(options)
27
+ cmd.run
28
+ end
29
+ ```
30
+ TEXT
31
+
32
+ puts next_steps
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "command",
3
+ "version": "1.0.0",
4
+ "metadata": {
5
+ "app_archetype": {
6
+ "version": "1.2.7"
7
+ }
8
+ },
9
+ "variables": {
10
+ "command_name": {
11
+ "type": "string",
12
+ "description": "Name of command (i.e. create_new_thing)"
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,17 @@
1
+ require 'tty-prompt'
2
+
3
+ module AppArchetype
4
+ module Commands
5
+ class {{command_name.camel_case}}
6
+ def initialize(manager, options)
7
+ @manager = manager
8
+ @options = options
9
+ @prompt = TTY::Prompt.new
10
+ end
11
+
12
+ def run
13
+ puts('✔ {{command_name.snake_case}} complete')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,99 +1,99 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe AppArchetype::CLI::Presenters do
4
- describe '.manifest_list' do
5
- let(:manifest) do
6
- double(
7
- AppArchetype::Template::Manifest,
8
- name: 'test_manifest',
9
- version: '1.0.0'
10
- )
11
- end
12
- let(:manifest_list_row) { ['test_manifest', '1.0.0'] }
13
-
14
- let(:presenter) { double(CliFormat::Presenter) }
15
- let(:manifests) { [manifest, manifest] }
16
-
17
- before do
18
- allow(presenter).to receive(:show)
19
- allow(subject).to receive(:table).and_return(presenter)
20
-
21
- described_class.manifest_list(manifests)
22
- end
23
-
24
- it 'builds table presenter' do
25
- expect(subject).to have_received(:table).with(
26
- header: AppArchetype::CLI::Presenters::RESULT_HEADER,
27
- data: [manifest_list_row, manifest_list_row]
28
- )
29
- end
30
-
31
- it 'shows table' do
32
- expect(presenter).to have_received(:show)
33
- end
34
- end
35
-
36
- describe '.variable_list' do
37
- let(:variable) do
38
- double(
39
- AppArchetype::Template::Variable,
40
- name: 'foo',
41
- description: 'a foo',
42
- default: 'yolo',
43
- value: 'bar'
44
- )
45
- end
46
- let(:variable_row) { ['foo', 'a foo', 'yolo'] }
47
-
48
- let(:presenter) { double(CliFormat::Presenter) }
49
- let(:variables) { [variable, variable] }
50
-
51
- before do
52
- allow(presenter).to receive(:show)
53
- allow(subject).to receive(:table).and_return(presenter)
54
-
55
- described_class.variable_list(variables)
56
- end
57
-
58
- it 'builds table presenter' do
59
- expect(subject).to have_received(:table).with(
60
- header: AppArchetype::CLI::Presenters::VARIABLE_HEADER,
61
- data: [variable_row, variable_row]
62
- )
63
- end
64
-
65
- it 'shows table' do
66
- expect(presenter).to have_received(:show)
67
- end
68
- end
69
-
70
- describe '.validation_results' do
71
- let(:results) do
72
- [
73
- 'something went wrong',
74
- 'something went wrong'
75
- ]
76
- end
77
-
78
- let(:result_row) { ['something went wrong'] }
79
- let(:presenter) { double(CliFormat::Presenter) }
80
-
81
- before do
82
- allow(presenter).to receive(:show)
83
- allow(subject).to receive(:table).and_return(presenter)
84
-
85
- described_class.validation_result(results)
86
- end
87
-
88
- it 'builds table presenter' do
89
- expect(subject).to have_received(:table).with(
90
- header: AppArchetype::CLI::Presenters::VALIDATION_HEADER,
91
- data: [result_row, result_row]
92
- )
93
- end
94
-
95
- it 'shows table' do
96
- expect(presenter).to have_received(:show)
97
- end
98
- end
99
- end
1
+ # require 'spec_helper'
2
+
3
+ # RSpec.xdescribe AppArchetype::CLI::Presenters do
4
+ # describe '.manifest_list' do
5
+ # let(:manifest) do
6
+ # double(
7
+ # AppArchetype::Template::Manifest,
8
+ # name: 'test_manifest',
9
+ # version: '1.0.0'
10
+ # )
11
+ # end
12
+ # let(:manifest_list_row) { ['test_manifest', '1.0.0'] }
13
+
14
+ # let(:presenter) { double(CliFormat::Presenter) }
15
+ # let(:manifests) { [manifest, manifest] }
16
+
17
+ # before do
18
+ # allow(presenter).to receive(:show)
19
+ # allow(subject).to receive(:table).and_return(presenter)
20
+
21
+ # described_class.manifest_list(manifests)
22
+ # end
23
+
24
+ # it 'builds table presenter' do
25
+ # expect(subject).to have_received(:table).with(
26
+ # header: AppArchetype::CLI::Presenters::RESULT_HEADER,
27
+ # data: [manifest_list_row, manifest_list_row]
28
+ # )
29
+ # end
30
+
31
+ # it 'shows table' do
32
+ # expect(presenter).to have_received(:show)
33
+ # end
34
+ # end
35
+
36
+ # describe '.variable_list' do
37
+ # let(:variable) do
38
+ # double(
39
+ # AppArchetype::Template::Variable,
40
+ # name: 'foo',
41
+ # description: 'a foo',
42
+ # default: 'yolo',
43
+ # value: 'bar'
44
+ # )
45
+ # end
46
+ # let(:variable_row) { ['foo', 'a foo', 'yolo'] }
47
+
48
+ # let(:presenter) { double(CliFormat::Presenter) }
49
+ # let(:variables) { [variable, variable] }
50
+
51
+ # before do
52
+ # allow(presenter).to receive(:show)
53
+ # allow(subject).to receive(:table).and_return(presenter)
54
+
55
+ # described_class.variable_list(variables)
56
+ # end
57
+
58
+ # it 'builds table presenter' do
59
+ # expect(subject).to have_received(:table).with(
60
+ # header: AppArchetype::CLI::Presenters::VARIABLE_HEADER,
61
+ # data: [variable_row, variable_row]
62
+ # )
63
+ # end
64
+
65
+ # it 'shows table' do
66
+ # expect(presenter).to have_received(:show)
67
+ # end
68
+ # end
69
+
70
+ # describe '.validation_results' do
71
+ # let(:results) do
72
+ # [
73
+ # 'something went wrong',
74
+ # 'something went wrong'
75
+ # ]
76
+ # end
77
+
78
+ # let(:result_row) { ['something went wrong'] }
79
+ # let(:presenter) { double(CliFormat::Presenter) }
80
+
81
+ # before do
82
+ # allow(presenter).to receive(:show)
83
+ # allow(subject).to receive(:table).and_return(presenter)
84
+
85
+ # described_class.validation_result(results)
86
+ # end
87
+
88
+ # it 'builds table presenter' do
89
+ # expect(subject).to have_received(:table).with(
90
+ # header: AppArchetype::CLI::Presenters::VALIDATION_HEADER,
91
+ # data: [result_row, result_row]
92
+ # )
93
+ # end
94
+
95
+ # it 'shows table' do
96
+ # expect(presenter).to have_received(:show)
97
+ # end
98
+ # end
99
+ # end