cli-template 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +58 -0
- data/.gitignore +17 -0
- data/.rspec +4 -0
- data/CHANGELOG.md +48 -0
- data/Gemfile +6 -0
- data/Guardfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +32 -0
- data/cli-template.gemspec +32 -0
- data/exe/cli-template +9 -0
- data/lib/cli-template.rb +12 -0
- data/lib/cli-template/cli.rb +17 -0
- data/lib/cli-template/command.rb +47 -0
- data/lib/cli-template/help.rb +9 -0
- data/lib/cli-template/help/new.md +4 -0
- data/lib/cli-template/helpers.rb +12 -0
- data/lib/cli-template/new.rb +74 -0
- data/lib/cli-template/sequence.rb +45 -0
- data/lib/cli-template/version.rb +3 -0
- data/lib/templates/skeleton/%project_name%.gemspec.tt +30 -0
- data/lib/templates/skeleton/.gitignore +16 -0
- data/lib/templates/skeleton/.rspec +2 -0
- data/lib/templates/skeleton/CHANGELOG.md +7 -0
- data/lib/templates/skeleton/Gemfile.tt +6 -0
- data/lib/templates/skeleton/Guardfile +19 -0
- data/lib/templates/skeleton/LICENSE.txt +22 -0
- data/lib/templates/skeleton/README.md.tt +47 -0
- data/lib/templates/skeleton/Rakefile +6 -0
- data/lib/templates/skeleton/exe/%project_name%.tt +14 -0
- data/lib/templates/skeleton/lib/%project_name%.rb.tt +10 -0
- data/lib/templates/skeleton/lib/%underscored_name%/cli.rb.tt +170 -0
- data/lib/templates/skeleton/lib/%underscored_name%/command.rb.tt +164 -0
- data/lib/templates/skeleton/lib/%underscored_name%/help.rb.tt +9 -0
- data/lib/templates/skeleton/lib/%underscored_name%/help/hello.md.tt +3 -0
- data/lib/templates/skeleton/lib/%underscored_name%/help/sub/goodbye.md.tt +3 -0
- data/lib/templates/skeleton/lib/%underscored_name%/main.rb.tt +21 -0
- data/lib/templates/skeleton/lib/%underscored_name%/rake_command.rb.tt +63 -0
- data/lib/templates/skeleton/lib/%underscored_name%/sub.rb.tt +12 -0
- data/lib/templates/skeleton/lib/%underscored_name%/version.rb.tt +3 -0
- data/lib/templates/skeleton/spec/lib/cli_spec.rb.tt +24 -0
- data/lib/templates/skeleton/spec/spec_helper.rb.tt +29 -0
- data/spec/lib/cli_spec.rb +61 -0
- data/spec/spec_helper.rb +33 -0
- metadata +217 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'colorize'
|
3
|
+
require 'active_support/core_ext/string'
|
4
|
+
require 'thor'
|
5
|
+
require 'bundler'
|
6
|
+
|
7
|
+
class CliTemplate::Sequence < Thor::Group
|
8
|
+
include Thor::Actions
|
9
|
+
include CliTemplate::Helpers
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
File.expand_path("../../templates/skeleton", __FILE__)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def clone_project
|
17
|
+
unless git_installed?
|
18
|
+
abort "Unable to detect git installation on your system. Git needs to be installed in order to use the --repo option."
|
19
|
+
end
|
20
|
+
|
21
|
+
if File.exist?(project_name)
|
22
|
+
abort "The folder #{project_name} already exists."
|
23
|
+
else
|
24
|
+
run "git clone https://github.com/#{options[:repo]} #{project_name}"
|
25
|
+
end
|
26
|
+
confirm_cli_project
|
27
|
+
end
|
28
|
+
|
29
|
+
def confirm_cli_project
|
30
|
+
jets_project = File.exist?("#{project_name}/config/application.rb")
|
31
|
+
unless jets_project
|
32
|
+
puts "It does not look like the repo #{options[:repo]} is a jets project. Maybe double check that it is? Exited.".colorize(:red)
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def copy_project
|
38
|
+
puts "Creating new project called #{project_name}."
|
39
|
+
directory ".", project_name
|
40
|
+
end
|
41
|
+
|
42
|
+
def git_installed?
|
43
|
+
system("type git > /dev/null")
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "<%= underscored_name %>/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "<%= project_name %>"
|
8
|
+
spec.version = <%= project_class_name %>::VERSION
|
9
|
+
spec.authors = ["Tung Nguyen"]
|
10
|
+
spec.email = ["tongueroo@gmail.com"]
|
11
|
+
spec.description = "Generated with cli-template tool. Please write a gem description"
|
12
|
+
spec.summary = "Generated with cli-template tool. Please write a gem summary"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "thor"
|
23
|
+
spec.add_dependency "colorize"
|
24
|
+
spec.add_dependency "rake"
|
25
|
+
spec.add_dependency "activesupport"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler"
|
28
|
+
spec.add_development_dependency "byebug"
|
29
|
+
spec.add_development_dependency "rspec"
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
guard "bundler", cmd: "bundle" do
|
2
|
+
watch("Gemfile")
|
3
|
+
watch(/^.+\.gemspec/)
|
4
|
+
end
|
5
|
+
|
6
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
7
|
+
require "guard/rspec/dsl"
|
8
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
9
|
+
|
10
|
+
# RSpec files
|
11
|
+
rspec = dsl.rspec
|
12
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
13
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
14
|
+
watch(rspec.spec_files)
|
15
|
+
|
16
|
+
# Ruby files
|
17
|
+
ruby = dsl.ruby
|
18
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Tung Nguyen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# <%= project_class_name %>
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/GEMNAME.png)](http://badge.fury.io/rb/GEMNAME)
|
4
|
+
[![CircleCI](https://circleci.com/gh/USER/REPO.svg?style=svg)](https://circleci.com/gh/USER/REPO)
|
5
|
+
[![Dependency Status](https://gemnasium.com/USER/REPO.png)](https://gemnasium.com/USER/REPO)
|
6
|
+
[![Coverage Status](https://coveralls.io/repos/USER/REPO/badge.png)](https://coveralls.io/r/USER/REPO)
|
7
|
+
[![Join the chat at https://gitter.im/USER/REPO](https://badges.gitter.im/USER/REPO.svg)](https://gitter.im/USER/REPO?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
+
[![Support](https://img.shields.io/badge/get-support-blue.svg)](https://boltops.com?utm_source=badge&utm_medium=badge&utm_campaign=cli-template)
|
9
|
+
|
10
|
+
TODO: Write a gem description
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
```sh
|
15
|
+
<%= project_name %> hello yourname
|
16
|
+
<%= project_name %> sub:goodbye yourname
|
17
|
+
```
|
18
|
+
|
19
|
+
The CLI tool also detects and tasks in the current folder's Rakefile and delegate to those tasks.
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
Add this line to your application's Gemfile:
|
24
|
+
|
25
|
+
```sh
|
26
|
+
gem "<%= project_name %>"
|
27
|
+
```
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
```sh
|
32
|
+
bundle
|
33
|
+
```
|
34
|
+
|
35
|
+
Or install it yourself as:
|
36
|
+
|
37
|
+
```sh
|
38
|
+
gem install <%= project_name %>
|
39
|
+
```
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
1. Fork it
|
44
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
45
|
+
3. Commit your changes (`git commit -am "Add some feature"`)
|
46
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
47
|
+
5. Create new Pull Request
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Trap ^C
|
4
|
+
Signal.trap("INT") {
|
5
|
+
puts "\nCtrl-C detected. Exiting..."
|
6
|
+
sleep 1
|
7
|
+
exit
|
8
|
+
}
|
9
|
+
|
10
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
11
|
+
require "<%= project_name %>"
|
12
|
+
require "<%= underscored_name %>/cli"
|
13
|
+
|
14
|
+
<%= project_class_name %>::CLI.start(ARGV)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
$:.unshift(File.expand_path("../", __FILE__))
|
2
|
+
require "<%= underscored_name %>/version"
|
3
|
+
|
4
|
+
module <%= project_class_name %>
|
5
|
+
autoload :Help, "<%= underscored_name %>/help"
|
6
|
+
autoload :Command, "<%= underscored_name %>/command"
|
7
|
+
autoload :RakeCommand, "<%= underscored_name %>/rake_command"
|
8
|
+
autoload :CLI, "<%= underscored_name %>/cli"
|
9
|
+
autoload :Sub, "<%= underscored_name %>/sub"
|
10
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "active_support" # for autoload
|
3
|
+
require "active_support/core_ext"
|
4
|
+
|
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 stripe
|
37
|
+
# 2. 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
|
73
|
+
# 3. help menu with all commands when both Thor and Rake tasks are not found
|
74
|
+
def lookup(full_command)
|
75
|
+
thor_task_found = <%= project_class_name %>::Command.namespaced_commands.include?(full_command)
|
76
|
+
if thor_task_found
|
77
|
+
return <%= project_class_name %>::Command.klass_from_namespace(namespace)
|
78
|
+
end
|
79
|
+
|
80
|
+
rake_task_found = <%= project_class_name %>::RakeCommand.namespaced_commands.include?(full_command)
|
81
|
+
if rake_task_found
|
82
|
+
return <%= project_class_name %>::RakeCommand
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def version_flags
|
87
|
+
["--version", "-v"]
|
88
|
+
end
|
89
|
+
|
90
|
+
# ["-h", "-?", "--help", "-D", "help"]
|
91
|
+
def help_flags
|
92
|
+
Thor::HELP_MAPPINGS + ["help"]
|
93
|
+
end
|
94
|
+
|
95
|
+
def namespace
|
96
|
+
return nil unless full_command
|
97
|
+
|
98
|
+
if full_command.include?(':')
|
99
|
+
words = full_command.split(':')
|
100
|
+
words.pop
|
101
|
+
words.join(':')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def meth
|
106
|
+
return nil unless full_command
|
107
|
+
|
108
|
+
if full_command.include?(':')
|
109
|
+
full_command.split(':').pop
|
110
|
+
else
|
111
|
+
full_command
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Allow calling version via:
|
116
|
+
# <%= project_name %> version
|
117
|
+
# <%= project_name %> --version
|
118
|
+
# <%= project_name %> -v
|
119
|
+
def version_flag?
|
120
|
+
args = @given_args
|
121
|
+
args.length == 1 && !(args & version_flags).empty?
|
122
|
+
end
|
123
|
+
|
124
|
+
def main_help
|
125
|
+
if version_flag?
|
126
|
+
<%= project_class_name %>::Main.perform("version", ["version"])
|
127
|
+
return
|
128
|
+
end
|
129
|
+
|
130
|
+
shell = Thor::Shell::Basic.new
|
131
|
+
shell.say "Commands:"
|
132
|
+
shell.print_table(thor_list, :indent => 2, :truncate => true)
|
133
|
+
|
134
|
+
unless rake_list.empty?
|
135
|
+
shell.say "\nCommands via rake:"
|
136
|
+
shell.print_table(rake_list, :indent => 2, :truncate => true)
|
137
|
+
end
|
138
|
+
|
139
|
+
shell.say "\n"
|
140
|
+
shell.say main_help_body
|
141
|
+
end
|
142
|
+
|
143
|
+
def thor_list
|
144
|
+
<%= project_class_name %>::Command.help_list(show_all_tasks)
|
145
|
+
end
|
146
|
+
|
147
|
+
def rake_list
|
148
|
+
list = <%= project_class_name %>::RakeCommand.formatted_rake_tasks(show_all_tasks)
|
149
|
+
list.map do |array|
|
150
|
+
array[0] = "<%= project_name %> #{array[0]}"
|
151
|
+
array
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def show_all_tasks
|
156
|
+
@given_args.include?("--all") || @given_args.include?("-A")
|
157
|
+
end
|
158
|
+
|
159
|
+
def main_help_body
|
160
|
+
<<-EOL
|
161
|
+
Add -h to any of the commands for more help. Examples:
|
162
|
+
|
163
|
+
<%= project_name %> hello -h
|
164
|
+
<%= project_name %> version
|
165
|
+
<%= project_name %> -h
|
166
|
+
|
167
|
+
EOL
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "active_support" # for autoload
|
3
|
+
require "active_support/core_ext"
|
4
|
+
|
5
|
+
# Override thor's long_desc identation behavior
|
6
|
+
# https://github.com/erikhuda/thor/issues/398
|
7
|
+
class Thor
|
8
|
+
module Shell
|
9
|
+
class Basic
|
10
|
+
def print_wrapped(message, options = {})
|
11
|
+
message = "\n#{message}" unless message[0] == "\n"
|
12
|
+
stdout.puts message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module <%= project_class_name %>
|
19
|
+
class Command < Thor
|
20
|
+
class << self
|
21
|
+
# thor_args is an array of commands. Examples:
|
22
|
+
# ["help"]
|
23
|
+
# ["dynamodb:migrate"]
|
24
|
+
#
|
25
|
+
# Same signature as RakeCommand.perform. Not using full_command.
|
26
|
+
#
|
27
|
+
# To call a thor task via ruby.
|
28
|
+
# Signature is a little weird with the repetition, examples:
|
29
|
+
#
|
30
|
+
# <%= project_class_name %>::Main.perform("hello", ["hello"])
|
31
|
+
# <%= project_class_name %>::Main.perform("dynamodb:migrate", ["migrate"])
|
32
|
+
#
|
33
|
+
def perform(full_command, thor_args)
|
34
|
+
config = {} # doesnt seem like config is used
|
35
|
+
dispatch(nil, thor_args, nil, config)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Track all command subclasses.
|
39
|
+
def subclasses
|
40
|
+
@subclasses ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
def inherited(base)
|
44
|
+
super
|
45
|
+
|
46
|
+
if base.name
|
47
|
+
self.subclasses << base
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Useful for help menu when we need to have all the definitions loaded.
|
52
|
+
# Using constantize instead of require so we dont care about
|
53
|
+
# order. The eager load actually uses autoloading.
|
54
|
+
def eager_load!
|
55
|
+
path = File.expand_path("../../", __FILE__)
|
56
|
+
Dir.glob("#{path}/**/*.rb").select do |path|
|
57
|
+
next if !File.file?(path)
|
58
|
+
|
59
|
+
class_name = path
|
60
|
+
.sub(/\.rb$/,'')
|
61
|
+
.sub(%r{.*/lib/},'')
|
62
|
+
.classify
|
63
|
+
|
64
|
+
if class_name.include?('-')
|
65
|
+
puts "WARN: Unable to autoload a class with a dash in the name" if debug?
|
66
|
+
next
|
67
|
+
end
|
68
|
+
|
69
|
+
# special mapping cases
|
70
|
+
special_cases = {
|
71
|
+
"<%= project_class_name %>::Cli" => "<%= project_class_name %>::CLI",
|
72
|
+
"<%= project_class_name %>::Version" => "<%= project_class_name %>::VERSION",
|
73
|
+
}
|
74
|
+
class_name = special_cases[class_name] || class_name
|
75
|
+
|
76
|
+
puts "eager_load! loading path: #{path} class_name: #{class_name}" if debug?
|
77
|
+
class_name.constantize # dont have to worry about order.
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Fully qualifed task names. Examples:
|
82
|
+
# build
|
83
|
+
# process:controller
|
84
|
+
# dynamodb:migrate:down
|
85
|
+
def namespaced_commands
|
86
|
+
eager_load!
|
87
|
+
subclasses.map do |klass|
|
88
|
+
klass.all_tasks.keys.map do |task_name|
|
89
|
+
klass = klass.to_s.sub('<%= project_class_name %>::','')
|
90
|
+
namespace = klass =~ /^Main/ ? nil : klass.underscore.gsub('/',':')
|
91
|
+
[namespace, task_name].compact.join(':')
|
92
|
+
end
|
93
|
+
end.flatten.sort
|
94
|
+
end
|
95
|
+
|
96
|
+
# Use <%= project_class_name %> banner instead of Thor to account for namespaces in commands.
|
97
|
+
def banner(command, namespace = nil, subcommand = false)
|
98
|
+
namespace = namespace_from_class(self)
|
99
|
+
command_name = command.usage # set with desc when defining tht Thor class
|
100
|
+
namespaced_command = [namespace, command_name].compact.join(':')
|
101
|
+
|
102
|
+
"<%= project_name %> #{namespaced_command}"
|
103
|
+
end
|
104
|
+
|
105
|
+
def namespace_from_class(klass)
|
106
|
+
namespace = klass.to_s.sub('<%= project_class_name %>::', '').underscore.gsub('/',':')
|
107
|
+
namespace unless namespace == "main"
|
108
|
+
end
|
109
|
+
|
110
|
+
def help_list(all=false)
|
111
|
+
# hack to show hidden comands when requested
|
112
|
+
Thor::HiddenCommand.class_eval do
|
113
|
+
def hidden?; false; end
|
114
|
+
end if all
|
115
|
+
|
116
|
+
list = []
|
117
|
+
eager_load!
|
118
|
+
subclasses.each do |klass|
|
119
|
+
commands = klass.printable_commands(true, false)
|
120
|
+
commands.reject! { |array| array[0].include?(':help') }
|
121
|
+
list += commands
|
122
|
+
end
|
123
|
+
|
124
|
+
list.sort_by! { |array| array[0] }
|
125
|
+
end
|
126
|
+
|
127
|
+
def klass_from_namespace(namespace)
|
128
|
+
if namespace.nil?
|
129
|
+
<%= project_class_name %>::Main
|
130
|
+
else
|
131
|
+
class_name = namespace.gsub(':','/')
|
132
|
+
class_name = "<%= project_class_name %>::#{class_name.classify}"
|
133
|
+
class_name.constantize
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# If this fails to match then it'l just return the original full command
|
138
|
+
def autocomplete(full_command)
|
139
|
+
return nil if full_command.nil? # <%= project_name %> help
|
140
|
+
|
141
|
+
eager_load!
|
142
|
+
|
143
|
+
words = full_command.split(':')
|
144
|
+
namespace = words[0..-2].join(':') if words.size > 1
|
145
|
+
command = words.last
|
146
|
+
|
147
|
+
# Thor's normalize_command_name autocompletes the command but then we need to add the namespace back
|
148
|
+
begin
|
149
|
+
thor_subclass = klass_from_namespace(namespace) # could NameError
|
150
|
+
command = thor_subclass.normalize_command_name(command) # could Thor::AmbiguousCommandError
|
151
|
+
[namespace, command].compact.join(':')
|
152
|
+
rescue NameError
|
153
|
+
full_command # return original full_command
|
154
|
+
rescue Thor::AmbiguousCommandError => e
|
155
|
+
full_command # return original full_command
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def debug?
|
160
|
+
ENV['DEBUG'] && !ENV['TEST']
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|