cli-template 3.1.0 → 3.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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +44 -5
  4. data/lib/cli-template/helpers.rb +3 -0
  5. data/lib/cli-template/sequence.rb +5 -4
  6. data/lib/cli-template/version.rb +1 -1
  7. data/lib/templates/colon_namespaces/%project_name%.gemspec.tt +30 -0
  8. data/lib/templates/colon_namespaces/.gitignore +16 -0
  9. data/lib/templates/colon_namespaces/.rspec +2 -0
  10. data/lib/templates/colon_namespaces/CHANGELOG.md +7 -0
  11. data/lib/templates/colon_namespaces/Gemfile.tt +6 -0
  12. data/lib/templates/colon_namespaces/Guardfile +19 -0
  13. data/lib/templates/colon_namespaces/LICENSE.txt.tt +22 -0
  14. data/lib/templates/colon_namespaces/README.md.tt +47 -0
  15. data/lib/templates/colon_namespaces/Rakefile +6 -0
  16. data/lib/templates/colon_namespaces/exe/%project_name%.tt +14 -0
  17. data/lib/templates/colon_namespaces/lib/%project_name%.rb.tt +12 -0
  18. data/lib/templates/colon_namespaces/lib/%underscored_name%/cli.rb.tt +166 -0
  19. data/lib/templates/colon_namespaces/lib/%underscored_name%/command.rb.tt +186 -0
  20. data/lib/templates/colon_namespaces/lib/%underscored_name%/completer.rb.tt +145 -0
  21. data/lib/templates/colon_namespaces/lib/%underscored_name%/completer/script.rb.tt +6 -0
  22. data/lib/templates/colon_namespaces/lib/%underscored_name%/completer/script.sh.tt +16 -0
  23. data/lib/templates/{default → colon_namespaces}/lib/%underscored_name%/completions.rb.tt +0 -0
  24. data/lib/templates/colon_namespaces/lib/%underscored_name%/help.rb.tt +9 -0
  25. data/lib/templates/{default → colon_namespaces}/lib/%underscored_name%/help/completions.md.tt +0 -0
  26. data/lib/templates/{default → colon_namespaces}/lib/%underscored_name%/help/completions/script.md.tt +0 -0
  27. data/lib/templates/colon_namespaces/lib/%underscored_name%/help/hello.md.tt +5 -0
  28. data/lib/templates/colon_namespaces/lib/%underscored_name%/help/main.md.tt +5 -0
  29. data/lib/templates/colon_namespaces/lib/%underscored_name%/help/sub/goodbye.md.tt +5 -0
  30. data/lib/templates/{default → colon_namespaces}/lib/%underscored_name%/main.rb.tt +0 -0
  31. data/lib/templates/{default → colon_namespaces}/lib/%underscored_name%/rake_command.rb.tt +0 -0
  32. data/lib/templates/colon_namespaces/lib/%underscored_name%/sub.rb.tt +12 -0
  33. data/lib/templates/colon_namespaces/lib/%underscored_name%/version.rb.tt +3 -0
  34. data/lib/templates/colon_namespaces/spec/lib/cli_spec.rb.tt +37 -0
  35. data/lib/templates/colon_namespaces/spec/spec_helper.rb.tt +29 -0
  36. data/lib/templates/default/.gitignore +1 -1
  37. data/lib/templates/default/Gemfile.lock.tt +64 -0
  38. data/lib/templates/default/LICENSE.txt +1 -1
  39. data/lib/templates/default/lib/%project_name%.rb.tt +1 -2
  40. data/lib/templates/default/lib/%underscored_name%/cli.rb.tt +24 -165
  41. data/lib/templates/default/lib/%underscored_name%/command.rb.tt +21 -151
  42. data/lib/templates/default/lib/%underscored_name%/completer.rb.tt +58 -57
  43. data/lib/templates/default/lib/%underscored_name%/completer/script.sh.tt +4 -10
  44. data/lib/templates/default/lib/%underscored_name%/completion.rb.tt +15 -0
  45. data/lib/templates/default/lib/%underscored_name%/help/completion.md.tt +22 -0
  46. data/lib/templates/default/lib/%underscored_name%/help/completion_script.md.tt +3 -0
  47. data/lib/templates/default/spec/lib/cli_spec.rb.tt +18 -17
  48. data/lib/templates/default/spec/spec_helper.rb.tt +2 -2
  49. data/spec/lib/cli_spec.rb +49 -38
  50. metadata +35 -7
@@ -0,0 +1,29 @@
1
+ ENV["TEST"] = "1"
2
+
3
+ # CodeClimate test coverage: https://docs.codeclimate.com/docs/configuring-test-coverage
4
+ # require 'simplecov'
5
+ # SimpleCov.start
6
+
7
+ require "pp"
8
+
9
+ root = File.expand_path("../../", __FILE__)
10
+ require "#{root}/lib/<%= project_name %>"
11
+
12
+ module Helpers
13
+ def execute(cmd)
14
+ puts "Running: #{cmd}" if show_command?
15
+ out = `#{cmd}`
16
+ puts out if show_command?
17
+ out
18
+ end
19
+
20
+ # Added SHOW_COMMAND because DEBUG is also used by other libraries like
21
+ # bundler and it shows its internal debugging logging also.
22
+ def show_command?
23
+ ENV['DEBUG'] || ENV['SHOW_COMMAND']
24
+ end
25
+ end
26
+
27
+ RSpec.configure do |c|
28
+ c.include Helpers
29
+ end
@@ -3,10 +3,10 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- InstalledFiles
7
6
  _yardoc
8
7
  coverage
9
8
  doc/
9
+ InstalledFiles
10
10
  lib/bundler/man
11
11
  pkg
12
12
  rdoc
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ <%= project_name %> (0.1.0)
5
+ activesupport
6
+ colorize
7
+ rake
8
+ thor
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (5.1.4)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (~> 0.7)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ byebug (10.0.0)
19
+ codeclimate-test-reporter (1.0.8)
20
+ simplecov (<= 0.13)
21
+ colorize (0.8.1)
22
+ concurrent-ruby (1.0.5)
23
+ diff-lcs (1.3)
24
+ docile (1.1.5)
25
+ i18n (0.9.4)
26
+ concurrent-ruby (~> 1.0)
27
+ json (2.1.0)
28
+ minitest (5.11.3)
29
+ rake (12.3.0)
30
+ rspec (3.7.0)
31
+ rspec-core (~> 3.7.0)
32
+ rspec-expectations (~> 3.7.0)
33
+ rspec-mocks (~> 3.7.0)
34
+ rspec-core (3.7.1)
35
+ rspec-support (~> 3.7.0)
36
+ rspec-expectations (3.7.0)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.7.0)
39
+ rspec-mocks (3.7.0)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.7.0)
42
+ rspec-support (3.7.1)
43
+ simplecov (0.13.0)
44
+ docile (~> 1.1.0)
45
+ json (>= 1.8, < 3)
46
+ simplecov-html (~> 0.10.0)
47
+ simplecov-html (0.10.2)
48
+ thor (0.20.0)
49
+ thread_safe (0.3.6)
50
+ tzinfo (1.2.5)
51
+ thread_safe (~> 0.1)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ bundler
58
+ byebug
59
+ codeclimate-test-reporter
60
+ <%= project_name %>!
61
+ rspec
62
+
63
+ BUNDLED WITH
64
+ 1.16.1
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Tung Nguyen
1
+ Copyright (c) 2018 Tung Nguyen
2
2
 
3
3
  MIT License
4
4
 
@@ -4,9 +4,8 @@ require "<%= underscored_name %>/version"
4
4
  module <%= project_class_name %>
5
5
  autoload :Help, "<%= underscored_name %>/help"
6
6
  autoload :Command, "<%= underscored_name %>/command"
7
- autoload :RakeCommand, "<%= underscored_name %>/rake_command"
8
7
  autoload :CLI, "<%= underscored_name %>/cli"
9
8
  autoload :Sub, "<%= underscored_name %>/sub"
10
- autoload :Completions, "<%= underscored_name %>/completions"
9
+ autoload :Completion, "<%= underscored_name %>/completion"
11
10
  autoload :Completer, "<%= underscored_name %>/completer"
12
11
  end
@@ -1,176 +1,35 @@
1
- require "thor"
2
- require "active_support" # for autoload
3
- require "active_support/core_ext"
1
+ module <%= project_class_name %>
2
+ class CLI < Command
3
+ class_option :verbose, type: :boolean
4
+ class_option :noop, type: :boolean
4
5
 
5
- class <%= project_class_name %>::CLI
6
- def self.start(given_args=ARGV)
7
- new(given_args).start
8
- end
9
-
10
- def self.thor_tasks
11
- <%= project_class_name %>::Command.namespaced_commands
12
- end
13
-
14
- def initialize(given_args=ARGV, **config)
15
- @given_args = given_args.dup
16
- @config = config
17
- end
18
-
19
- def start
20
- setup_auto_load
21
- command_class = lookup(full_command)
22
- if command_class
23
- command_class.perform(full_command, thor_args)
24
- else
25
- main_help
26
- end
27
- end
28
-
29
- def setup_auto_load
30
- autoload_paths = [File.expand_path("../../", __FILE__)]
31
- ActiveSupport::Dependencies.autoload_paths += autoload_paths
32
- end
33
-
34
- # thor_args normalized the args Array to work with our Thor command
35
- # subclasses.
36
- # 1. The namespace is stripped
37
- # 2. The help is shifted in front if a help flag is detected
38
- def thor_args
39
- args = @given_args.clone
40
-
41
- # Allow calling for help via:
42
- # cli-template command help
43
- # cli-template command -h
44
- # cli-template command --help
45
- # cli-template command -D
46
- #
47
- # as well thor's normal way:
48
- #
49
- # cli-template help command
50
- help_args = args & help_flags
51
- if help_args.empty?
52
- args[0] = meth # reassigns the command without the namespace
53
- else
54
- # Allow using help flags at the end of the command to trigger help menu
55
- args -= help_flags # remove "help" and help flags from args
56
- args[0] = meth # first command will always be the meth now since
57
- # we removed the help flags
58
- args.unshift("help")
59
- end
60
- args.compact
61
- end
62
-
63
- def full_command
64
- # Removes any args that starts with -, those are option args.
65
- # Also remove "help" flag.
66
- args = @given_args.reject {|o| o =~ /^-/ } - help_flags
67
- command = args[0] # first argument should always be the command
68
- <%= project_class_name %>::Command.autocomplete(command)
69
- end
70
-
71
- # 1. look up Thor tasks
72
- # 2. look up Rake tasks - currently disabled
73
- # 3. help menu with all commands when both Thor and Rake tasks are not found
74
- #
75
- # Example:
76
- #
77
- # lookup("sub:hello") => Sub
78
- def lookup(full_command)
79
- thor_task_found = <%= project_class_name %>::Command.namespaced_commands.include?(full_command)
80
- if thor_task_found
81
- return <%= project_class_name %>::Command.klass_from_namespace(namespace)
82
- end
83
-
84
- rake_task_found = <%= project_class_name %>::RakeCommand.namespaced_commands.include?(full_command)
85
- if rake_task_found
86
- return <%= project_class_name %>::RakeCommand
87
- end
88
- end
89
-
90
- def version_flags
91
- ["--version", "-v"]
92
- end
93
-
94
- # ["-h", "-?", "--help", "-D", "help"]
95
- def help_flags
96
- Thor::HELP_MAPPINGS + ["help"]
97
- end
98
-
99
- def namespace
100
- return nil unless full_command
101
-
102
- if full_command.include?(':')
103
- words = full_command.split(':')
104
- words.pop
105
- words.join(':')
6
+ desc "hello NAME", "say hello to NAME"
7
+ long_desc Help.text(:hello)
8
+ option :from, desc: "from person"
9
+ def hello(name="you")
10
+ puts "from: #{options[:from]}" if options[:from]
11
+ puts "Hello #{name}"
106
12
  end
107
- end
108
13
 
109
- def meth
110
- return nil unless full_command
14
+ desc "sub SUBCOMMAND", "sub subcommands"
15
+ long_desc Help.text(:sub)
16
+ subcommand "sub", Sub
111
17
 
112
- if full_command.include?(':')
113
- full_command.split(':').pop
114
- else
115
- full_command
18
+ desc "completion *PARAMS", "prints words for auto-completion"
19
+ long_desc Help.text("completion")
20
+ def completion(*params)
21
+ Completer.new(CLI, *params).run
116
22
  end
117
- end
118
-
119
- # Allow calling version via:
120
- # <%= project_name %> version
121
- # <%= project_name %> --version
122
- # <%= project_name %> -v
123
- def version_flag?
124
- args = @given_args
125
- args.length == 1 && !(args & version_flags).empty?
126
- end
127
23
 
128
- def main_help
129
- if version_flag?
130
- <%= project_class_name %>::Main.perform("version", ["version"])
131
- return
24
+ desc "completion_script", "generates script that can be eval to setup auto-completion", hide: true
25
+ long_desc Help.text("completion_script")
26
+ def completion_script
27
+ Completer::Script.generate
132
28
  end
133
29
 
134
- shell = Thor::Shell::Basic.new
135
- shell.say "Commands:"
136
- shell.print_table(thor_list, :indent => 2, :truncate => true)
137
-
138
- # TODO: commenting out for now, feels weird to show the rake tasks
139
- # automatically also by default. Maybe add an option for this.
140
- # unless rake_list.empty?
141
- # shell.say "\nCommands via rake:"
142
- # shell.print_table(rake_list, :indent => 2, :truncate => true)
143
- # end
144
-
145
- shell.say "\n"
146
- shell.say main_help_body
147
- end
148
-
149
- def thor_list
150
- <%= project_class_name %>::Command.help_list(show_all_tasks)
151
- end
152
-
153
- def rake_list
154
- list = <%= project_class_name %>::RakeCommand.formatted_rake_tasks(show_all_tasks)
155
- list.map do |array|
156
- array[0] = "<%= project_name %> #{array[0]}"
157
- array
30
+ desc "version", "prints version"
31
+ def version
32
+ puts VERSION
158
33
  end
159
34
  end
160
-
161
- def show_all_tasks
162
- @given_args.include?("--all") || @given_args.include?("-A")
163
- end
164
-
165
- def main_help_body
166
- <<-EOL
167
- Add -h to any of the commands for more help. Examples:
168
-
169
- <%= project_name %> hello -h
170
- <%= project_name %> version
171
- <%= project_name %> -h
172
-
173
- EOL
174
- end
175
-
176
35
  end
@@ -1,6 +1,4 @@
1
1
  require "thor"
2
- require "active_support" # for autoload
3
- require "active_support/core_ext"
4
2
 
5
3
  # Override thor's long_desc identation behavior
6
4
  # https://github.com/erikhuda/thor/issues/398
@@ -18,159 +16,31 @@ end
18
16
  module <%= project_class_name %>
19
17
  class Command < Thor
20
18
  class << self
21
- # thor_args is an array of commands. Examples:
22
- # ["help"]
23
- # ["dynamodb:migrate"]
24
- #
25
- # Same signature as RakeCommand.perform. Signature is a little weird
26
- # with some repetition. Examples:
27
- #
28
- # <%= project_class_name %>::Main.perform("hello", ["hello"])
29
- # <%= project_class_name %>::Main.perform("dynamodb:migrate", ["migrate"])
30
- #
31
- def perform(full_command, thor_args)
32
- config = {} # doesnt seem like config is used
33
- dispatch(nil, thor_args, nil, config)
34
- end
35
-
36
- # Track all command subclasses.
37
- def subclasses
38
- @subclasses ||= []
39
- end
40
-
41
- def inherited(base)
42
- super
43
-
44
- if base.name
45
- self.subclasses << base
46
- end
47
- end
48
-
49
- # Useful for help menu when we need to have all the definitions loaded.
50
- # Using constantize instead of require so we dont care about
51
- # order. The eager load actually uses autoloading.
52
- def eager_load!
53
- path = File.expand_path("../../", __FILE__)
54
- Dir.glob("#{path}/**/*.rb").select do |path|
55
- next if !File.file?(path)
56
-
57
- class_name = path
58
- .sub(/\.rb$/,'')
59
- .sub(%r{.*/lib/},'')
60
- .classify
61
-
62
- if class_name.include?('-')
63
- puts "WARN: Unable to autoload a class with a dash in the name" if debug?
64
- next
65
- end
66
-
67
- class_name = class_map[class_name] || class_name
68
-
69
- puts "eager_load! loading path: #{path} class_name: #{class_name}" if debug?
70
- class_name.constantize # dont have to worry about order.
71
- end
72
- end
73
-
74
- # Special class mapping cases. This is because ActiveSupport's autoloading
75
- # forces a specific naming convention.
76
- def class_map
77
- map = {
78
- "<%= project_class_name %>::Cli" => "<%= project_class_name %>::CLI",
79
- "<%= project_class_name %>::Version" => "<%= project_class_name %>::VERSION",
80
- "<%= project_class_name %>::Completion" => "<%= project_class_name %>::Completions",
81
- }
82
- map.merge(additional_class_map)
83
- map
84
- end
85
-
86
- # Override this if you need add addtional class mappings.
87
- def additional_class_map
88
- {}
89
- end
90
-
91
- # Fully qualifed task names. Examples:
92
- # hello
93
- # sub:goodbye
94
- def namespaced_commands
95
- eager_load!
96
- subclasses.map do |klass|
97
- klass.all_tasks.keys.map do |task_name|
98
- klass = klass.to_s.sub('<%= project_class_name %>::','')
99
- namespace = klass =~ /^Main/ ? nil : klass.underscore.gsub('/',':')
100
- [namespace, task_name].compact.join(':')
101
- end
102
- end.flatten.sort
103
- end
104
-
105
- # Use <%= project_class_name %> banner instead of Thor to account for namespaces in commands.
106
- def banner(command, namespace = nil, subcommand = false)
107
- namespace = namespace_from_class(self)
108
- command_name = command.usage # set with desc when defining tht Thor class
109
- namespaced_command = [namespace, command_name].compact.join(':')
110
-
111
- "<%= project_name %> #{namespaced_command}"
112
- end
113
-
114
- def namespace_from_class(klass)
115
- namespace = klass.to_s.sub('<%= project_class_name %>::', '').underscore.gsub('/',':')
116
- namespace unless namespace == "main"
117
- end
118
-
119
- def help_list(all=false)
120
- # hack to show hidden comands when requested
121
- Thor::HiddenCommand.class_eval do
122
- def hidden?; false; end
123
- end if all
124
-
125
- list = []
126
- eager_load!
127
- subclasses.each do |klass|
128
- commands = klass.printable_commands(true, false)
129
- commands.reject! { |array| array[0].include?(':help') }
130
- list += commands
19
+ def dispatch(m, args, options, config)
20
+ # Allow calling for help via:
21
+ # <%= project_name %> command help
22
+ # <%= project_name %> command -h
23
+ # <%= project_name %> command --help
24
+ # <%= project_name %> command -D
25
+ #
26
+ # as well thor's normal way:
27
+ #
28
+ # <%= project_name %> help command
29
+ help_flags = Thor::HELP_MAPPINGS + ["help"]
30
+ if args.length > 1 && !(args & help_flags).empty?
31
+ args -= help_flags
32
+ args.insert(-2, "help")
131
33
  end
132
34
 
133
- list.sort_by! { |array| array[0] }
134
- end
135
-
136
- # Example:
137
- # klass_from_namespace(nil) => Main
138
- # klass_from_namespace("sub") => Sub
139
- def klass_from_namespace(namespace)
140
- if namespace.nil?
141
- <%= project_class_name %>::Main
142
- else
143
- class_name = namespace.gsub(':','/')
144
- class_name = "<%= project_class_name %>::#{class_name.classify}"
145
- class_name = class_map[class_name] || class_name
146
- class_name.constantize
35
+ # <%= project_name %> version
36
+ # <%= project_name %> --version
37
+ # <%= project_name %> -v
38
+ version_flags = ["--version", "-v"]
39
+ if args.length == 1 && !(args & version_flags).empty?
40
+ args = ["version"]
147
41
  end
148
- end
149
-
150
- # If this fails to match then it'l just return the original full command
151
- def autocomplete(full_command)
152
- return nil if full_command.nil? # <%= project_name %> help
153
-
154
- eager_load!
155
-
156
- words = full_command.split(':')
157
- namespace = words[0..-2].join(':') if words.size > 1
158
- command = words.last
159
42
 
160
- # Thor's normalize_command_name autocompletes the command but then we need to add the namespace back
161
- begin
162
- thor_subclass = klass_from_namespace(namespace) # could NameError
163
- command = thor_subclass.normalize_command_name(command) # could Thor::AmbiguousCommandError
164
- [namespace, command].compact.join(':')
165
- rescue NameError
166
- full_command # return original full_command
167
- rescue Thor::AmbiguousCommandError => e
168
- full_command # return original full_command
169
- end
170
- end
171
-
172
- def debug?
173
- ENV['DEBUG'] && !ENV['TEST']
43
+ super
174
44
  end
175
45
  end
176
46
  end