app_archetype 1.2.8 → 1.4.2

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/Gemfile.lock +102 -73
  4. data/README.md +166 -29
  5. data/app_archetype.gemspec +22 -19
  6. data/bin/app_archetype +20 -0
  7. data/bin/archetype +1 -1
  8. data/lib/app_archetype/cli.rb +171 -139
  9. data/lib/app_archetype/commands/delete_template.rb +58 -0
  10. data/lib/app_archetype/commands/find_templates.rb +66 -0
  11. data/lib/app_archetype/commands/list_templates.rb +49 -0
  12. data/lib/app_archetype/commands/new_template.rb +42 -0
  13. data/lib/app_archetype/commands/open_manifest.rb +48 -0
  14. data/lib/app_archetype/commands/print_path.rb +20 -0
  15. data/lib/app_archetype/commands/print_template_variables.rb +67 -0
  16. data/lib/app_archetype/commands/print_version.rb +19 -0
  17. data/lib/app_archetype/commands/render_template.rb +178 -0
  18. data/lib/app_archetype/commands.rb +13 -0
  19. data/lib/app_archetype/generators.rb +4 -3
  20. data/lib/app_archetype/template/manifest.rb +17 -1
  21. data/lib/app_archetype/template_manager.rb +13 -6
  22. data/lib/app_archetype/version.rb +1 -1
  23. data/lib/app_archetype.rb +40 -23
  24. data/lib/core_ext/string.rb +18 -12
  25. data/scripts/create_new_command +32 -0
  26. data/scripts/generators/command/manifest.json +15 -0
  27. data/scripts/generators/command/template/lib/app_archetype/commands/{{command_name.snake_case}}.rb.hbs +17 -0
  28. data/spec/app_archetype/cli/presenters_spec.rb +99 -99
  29. data/spec/app_archetype/cli/prompts_spec.rb +291 -291
  30. data/spec/app_archetype/cli_spec.rb +296 -65
  31. data/spec/app_archetype/commands/delete_template_spec.rb +132 -0
  32. data/spec/app_archetype/commands/find_templates_spec.rb +130 -0
  33. data/spec/app_archetype/commands/list_templates_spec.rb +55 -0
  34. data/spec/app_archetype/commands/new_template_spec.rb +84 -0
  35. data/spec/app_archetype/commands/open_manifest_spec.rb +113 -0
  36. data/spec/app_archetype/commands/print_path_spec.rb +22 -0
  37. data/spec/app_archetype/commands/print_template_variables_spec.rb +158 -0
  38. data/spec/app_archetype/commands/print_version_spec.rb +21 -0
  39. data/spec/app_archetype/commands/render_template_spec.rb +479 -0
  40. data/spec/app_archetype/generators_spec.rb +1 -1
  41. data/spec/app_archetype/template/manifest_spec.rb +31 -1
  42. data/spec/app_archetype/template_manager_spec.rb +32 -0
  43. data/spec/app_archetype_spec.rb +65 -0
  44. metadata +155 -80
  45. data/lib/app_archetype/cli/presenters.rb +0 -106
  46. 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
+ ARCHETYPE_CLI_COMMANDS = File.join(__dir__, 'commands', '*.rb')
4
+
5
+ Dir[ARCHETYPE_CLI_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
@@ -25,7 +25,8 @@ module AppArchetype
25
25
  'version' => AppArchetype::VERSION
26
26
  }
27
27
  },
28
- 'variables' => DEFAULT_VARS
28
+ 'variables' => DEFAULT_VARS,
29
+ 'next_steps' => []
29
30
  }
30
31
  end
31
32
 
@@ -48,7 +49,7 @@ module AppArchetype
48
49
  MD
49
50
  end
50
51
 
51
- class <<self
52
+ class << self
52
53
  ##
53
54
  # Render empty template renders a manifest and template folder at
54
55
  # the given path.
@@ -60,7 +61,7 @@ module AppArchetype
60
61
  # @param [String] path
61
62
  #
62
63
  def render_empty_template(name, path)
63
- template_path = File.join(path, name)
64
+ template_path = File.join(path, 'template')
64
65
  manifest_path = File.join(path, 'manifest.json')
65
66
  readme_path = File.join(path, 'README.md')
66
67
 
@@ -38,11 +38,14 @@ module AppArchetype
38
38
  },
39
39
  variables: {
40
40
  type: 'object'
41
+ },
42
+ next_steps: {
43
+ type: 'array'
41
44
  }
42
45
  }
43
46
  }.freeze
44
47
 
45
- class <<self
48
+ class << self
46
49
  ##
47
50
  # Creates a [AppArchetype::Template] from a manifest json so long as the
48
51
  # manifest is compatible with this version of AppArchetype.
@@ -130,6 +133,19 @@ module AppArchetype
130
133
  @data.metadata
131
134
  end
132
135
 
136
+ ##
137
+ # Next steps getter
138
+ #
139
+ # @return [String]
140
+ #
141
+ def next_steps
142
+ steps = @data.next_steps
143
+
144
+ return [] unless steps
145
+
146
+ steps
147
+ end
148
+
133
149
  ##
134
150
  # Parent path of the manifest (working directory)
135
151
  #
@@ -27,12 +27,10 @@ module AppArchetype
27
27
  Dir.glob(
28
28
  File.join(@template_dir, '**', 'manifest.json*')
29
29
  ).each do |manifest|
30
- begin
31
- @manifests << AppArchetype::Template::Manifest.new_from_file(manifest)
32
- rescue StandardError
33
- puts "WARN: `#{manifest}` is invalid, skipping"
34
- next
35
- end
30
+ @manifests << AppArchetype::Template::Manifest.new_from_file(manifest)
31
+ rescue StandardError
32
+ puts "WARN: `#{manifest}` is invalid, skipping"
33
+ next
36
34
  end
37
35
  end
38
36
 
@@ -109,5 +107,14 @@ module AppArchetype
109
107
 
110
108
  results.first
111
109
  end
110
+
111
+ ##
112
+ # Returns a list of manifest names from loaded templates
113
+ #
114
+ # @return [Array]
115
+ #
116
+ def manifest_names
117
+ @manifests.map(&:name)
118
+ end
112
119
  end
113
120
  end
@@ -2,5 +2,5 @@ module AppArchetype
2
2
  ##
3
3
  # AppArchetype version
4
4
  #
5
- VERSION = '1.2.8'.freeze
5
+ VERSION = '1.4.2'.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
@@ -7,8 +7,9 @@ class String
7
7
  #
8
8
  # @return [String]
9
9
  #
10
- def snake_case
11
- helper.snake_case(self)
10
+ def snake_case(str = nil)
11
+ str ||= self
12
+ helper.snake_case(str)
12
13
  end
13
14
 
14
15
  ##
@@ -16,8 +17,9 @@ class String
16
17
  #
17
18
  # @return [String]
18
19
  #
19
- def dash_case
20
- helper.dash_case(self)
20
+ def dash_case(str = nil)
21
+ str ||= self
22
+ helper.dash_case(str)
21
23
  end
22
24
 
23
25
  ##
@@ -25,8 +27,9 @@ class String
25
27
  #
26
28
  # @return [String]
27
29
  #
28
- def camel_case
29
- helper.camel_case(self)
30
+ def camel_case(str = nil)
31
+ str ||= self
32
+ helper.camel_case(str)
30
33
  end
31
34
 
32
35
  ##
@@ -34,8 +37,9 @@ class String
34
37
  #
35
38
  # @return [String]
36
39
  #
37
- def pluralize
38
- helper.pluralize(self)
40
+ def pluralize(str = nil)
41
+ str ||= self
42
+ helper.pluralize(str)
39
43
  end
40
44
 
41
45
  ##
@@ -43,8 +47,9 @@ class String
43
47
  #
44
48
  # @return [String]
45
49
  #
46
- def singularize
47
- helper.singularize(self)
50
+ def singularize(str = nil)
51
+ str ||= self
52
+ helper.singularize(str)
48
53
  end
49
54
 
50
55
  ##
@@ -52,8 +57,9 @@ class String
52
57
  #
53
58
  # @return [String]
54
59
  #
55
- def randomize(size = 5)
56
- helper.randomize(self, size.to_s)
60
+ def randomize(size = 5, str = nil)
61
+ str ||= self
62
+ helper.randomize(str, size.to_s)
57
63
  end
58
64
 
59
65
  private
@@ -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