taco_it 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/taco CHANGED
@@ -12,7 +12,7 @@ end
12
12
  require 'taco/commander/import'
13
13
 
14
14
  program :name, 'taco'
15
- program :version, '1.5.1'
15
+ program :version, '1.5.2'
16
16
  program :description, 'simple command line issue tracking'
17
17
 
18
18
  command :init do |c|
@@ -0,0 +1,8 @@
1
+
2
+ module Blank
3
+ def self.included base
4
+ base.class_eval do
5
+ instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,226 @@
1
+
2
+ require 'optparse'
3
+
4
+ module Commander
5
+ class Command
6
+
7
+ attr_accessor :name, :examples, :syntax, :description
8
+ attr_accessor :summary, :proxy_options, :options
9
+
10
+ ##
11
+ # Options struct.
12
+
13
+ class Options
14
+ include Blank
15
+
16
+ def initialize
17
+ @table = {}
18
+ end
19
+
20
+ def __hash__
21
+ @table
22
+ end
23
+
24
+ def method_missing meth, *args, &block
25
+ meth.to_s =~ /=$/ ? @table[meth.to_s.chop.to_sym] = args.first : @table[meth]
26
+ end
27
+
28
+ def default defaults = {}
29
+ @table = defaults.merge! @table
30
+ end
31
+
32
+ def inspect
33
+ "<Commander::Command::Options #{ __hash__.map { |k,v| "#{k}=#{v.inspect}" }.join(', ') }>"
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Initialize new command with specified _name_.
39
+
40
+ def initialize name
41
+ @name, @examples, @when_called = name.to_s, [], []
42
+ @options, @proxy_options = [], []
43
+ @argument_validator = nil
44
+ end
45
+
46
+ ##
47
+ # Add a usage example for this command.
48
+ #
49
+ # Usage examples are later displayed in help documentation
50
+ # created by the help formatters.
51
+ #
52
+ # === Examples
53
+ #
54
+ # command :something do |c|
55
+ # c.example "Should do something", "my_command something"
56
+ # end
57
+ #
58
+
59
+ def example description, command
60
+ @examples << [description, command]
61
+ end
62
+
63
+
64
+ def arguments proc
65
+ @argument_validator = proc
66
+ end
67
+
68
+ ##
69
+ # Add an option.
70
+ #
71
+ # Options are parsed via OptionParser so view it
72
+ # for additional usage documentation. A block may optionally be
73
+ # passed to handle the option, otherwise the _options_ struct seen below
74
+ # contains the results of this option. This handles common formats such as:
75
+ #
76
+ # -h, --help options.help # => bool
77
+ # --[no-]feature options.feature # => bool
78
+ # --large-switch options.large_switch # => bool
79
+ # --file FILE options.file # => file passed
80
+ # --list WORDS options.list # => array
81
+ # --date [DATE] options.date # => date or nil when optional argument not set
82
+ #
83
+ # === Examples
84
+ #
85
+ # command :something do |c|
86
+ # c.option '--recursive', 'Do something recursively'
87
+ # c.option '--file FILE', 'Specify a file'
88
+ # c.option('--info', 'Display info') { puts "handle with block" }
89
+ # c.option '--[no-]feature', 'With or without feature'
90
+ # c.option '--list FILES', Array, 'List the files specified'
91
+ #
92
+ # c.when_called do |args, options|
93
+ # do_something_recursively if options.recursive
94
+ # do_something_with_file options.file if options.file
95
+ # end
96
+ # end
97
+ #
98
+ # === Help Formatters
99
+ #
100
+ # This method also parses the arguments passed in order to determine
101
+ # which were switches, and which were descriptions for the
102
+ # option which can later be used within help formatters
103
+ # using option[:switches] and option[:description].
104
+ #
105
+ # === Input Parsing
106
+ #
107
+ # Since Commander utilizes OptionParser you can pre-parse and evaluate
108
+ # option arguments. Simply require 'optparse/time', or 'optparse/date', as these
109
+ # objects must respond to #parse.
110
+ #
111
+ # c.option '--time TIME', Time
112
+ # c.option '--date [DATE]', Date
113
+ #
114
+
115
+ def option *args, &block
116
+ switches, description = Runner.separate_switches_from_description(*args)
117
+ proc = block || option_proc(switches)
118
+ @options << {
119
+ :args => args,
120
+ :proc => proc,
121
+ :switches => switches,
122
+ :description => description,
123
+ }
124
+ end
125
+
126
+ ##
127
+ # Handle execution of command. The handler may be a class,
128
+ # object, or block (see examples below).
129
+ #
130
+ # === Examples
131
+ #
132
+ # # Simple block handling
133
+ # c.when_called do |args, options|
134
+ # # do something
135
+ # end
136
+ #
137
+ # # Create inst of Something and pass args / options
138
+ # c.when_called MyLib::Command::Something
139
+ #
140
+ # # Create inst of Something and use arbitrary method
141
+ # c.when_called MyLib::Command::Something, :some_method
142
+ #
143
+ # # Pass an object to handle callback (requires method symbol)
144
+ # c.when_called SomeObject, :some_method
145
+ #
146
+
147
+ def when_called *args, &block
148
+ raise ArgumentError, 'must pass an object, class, or block.' if args.empty? and !block
149
+ @when_called = block ? [block] : args
150
+ end
151
+ alias :action :when_called
152
+
153
+ ##
154
+ # Run the command with _args_.
155
+ #
156
+ # * parses options, call option blocks
157
+ # * invokes when_called proc
158
+ #
159
+
160
+ def run *args
161
+ call parse_options_and_call_procs(*args)
162
+ end
163
+
164
+ #:stopdoc:
165
+
166
+ ##
167
+ # Parses options and calls associated procs,
168
+ # returning the arguments remaining.
169
+
170
+ def parse_options_and_call_procs *args
171
+ return args if args.empty?
172
+ @options.inject OptionParser.new do |opts, option|
173
+ opts.on(*option[:args], &option[:proc])
174
+ opts
175
+ end.parse! args
176
+ end
177
+
178
+ ##
179
+ # Call the commands when_called block with _args_.
180
+
181
+ def call args = []
182
+ object = @when_called.shift
183
+ meth = @when_called.shift || :call
184
+ options = proxy_option_struct
185
+
186
+ if @argument_validator
187
+ raise ArgumentError.new("Unexpected arguments: #{args.join(' ')}") unless @argument_validator.call(args)
188
+ elsif args.size > 0
189
+ raise ArgumentError.new("Unexpected arguments: #{args.join(' ')}")
190
+ end
191
+
192
+ case object
193
+ when Proc ; object.call(args, options)
194
+ when Class ; meth != :call ? object.new.send(meth, args, options) : object.new(args, options)
195
+ else object.send(meth, args, options) if object
196
+ end
197
+ end
198
+
199
+ ##
200
+ # Creates an Options instance populated with the option values
201
+ # collected by the #option_proc.
202
+
203
+ def proxy_option_struct
204
+ proxy_options.inject Options.new do |options, (option, value)|
205
+ # options that are present will evaluate to true
206
+ value = true if value.nil?
207
+ options.__send__ :"#{option}=", value
208
+ options
209
+ end
210
+ end
211
+
212
+ ##
213
+ # Option proxy proc used when a block is not explicitly passed
214
+ # via the #option method. This allows commander to auto-populate
215
+ # and work with option values.
216
+
217
+ def option_proc switches
218
+ lambda { |value| proxy_options << [Runner.switch_to_sym(switches.last), value] }
219
+ end
220
+
221
+ def inspect
222
+ "<Commander::Command:#{name}>"
223
+ end
224
+
225
+ end
226
+ end
@@ -0,0 +1,26 @@
1
+
2
+ class Array
3
+
4
+ ##
5
+ # Split _string_ into an array. Used in
6
+ # conjunction with Highline's #ask, or #ask_for_array
7
+ # methods, which must respond to #parse.
8
+ #
9
+ # This method allows escaping of whitespace. For example
10
+ # the arguments foo bar\ baz will become ['foo', 'bar baz']
11
+ #
12
+ # === Example
13
+ #
14
+ # # ask invokes Array#parse
15
+ # list = ask 'Favorite cookies:', Array
16
+ #
17
+ # # or use ask_for_CLASS
18
+ # list = ask_for_array 'Favorite cookies: '
19
+ #
20
+
21
+ def self.parse string
22
+ # Using reverse + lookahead to work around Ruby 1.8's lack of lookbehind
23
+ string.reverse.split(/\s(?!\\)/).reverse.map { |s| s.reverse.gsub('\\ ', ' ') }
24
+ end
25
+
26
+ end
@@ -0,0 +1,11 @@
1
+
2
+ class Object
3
+
4
+ ##
5
+ # Return the current binding.
6
+
7
+ def get_binding
8
+ binding
9
+ end
10
+
11
+ end
@@ -0,0 +1,3 @@
1
+
2
+ require 'taco/commander/core_ext/array'
3
+ require 'taco/commander/core_ext/object'
@@ -0,0 +1,13 @@
1
+
2
+ module Commander
3
+ module Delegates
4
+ %w( add_command command program run! global_option
5
+ commands alias_command default_command ).each do |meth|
6
+ eval <<-END, binding, __FILE__, __LINE__
7
+ def #{meth} *args, &block
8
+ ::Commander::Runner.instance.#{meth} *args, &block
9
+ end
10
+ END
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+
2
+ module Commander
3
+
4
+ ##
5
+ # = Help Formatter
6
+ #
7
+ # Commander's help formatters control the output when
8
+ # either the help command, or --help switch are called.
9
+ # The default formatter is Commander::HelpFormatter::Terminal.
10
+
11
+ module HelpFormatter
12
+ class Base
13
+ def initialize runner; @runner = runner end
14
+ def render; 'Implement global help here' end
15
+ def render_command command; "Implement help for #{command.name} here" end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+
2
+ <%= $terminal.color "NAME", :bold %>:
3
+
4
+ <%= @name %>
5
+ <% if @syntax -%>
6
+
7
+ <%= $terminal.color "SYNOPSIS", :bold %>:
8
+
9
+ <%= @syntax -%>
10
+
11
+ <% end -%>
12
+
13
+ <%= $terminal.color "DESCRIPTION", :bold %>:
14
+
15
+ <%= Commander::HelpFormatter.indent 4, (@description || @summary || 'No description.') -%>
16
+
17
+ <% unless @examples.empty? -%>
18
+
19
+ <%= $terminal.color "EXAMPLES", :bold %>:
20
+ <% for description, command in @examples -%>
21
+
22
+ # <%= description %>
23
+ <%= command %>
24
+ <% end -%>
25
+ <% end -%>
26
+ <% unless @options.empty? -%>
27
+
28
+ <%= $terminal.color "OPTIONS", :bold %>:
29
+ <% for option in @options -%>
30
+
31
+ <%= option[:switches].join ', ' %>
32
+ <%= option[:description] %>
33
+ <% end -%>
34
+ <% end -%>
35
+
@@ -0,0 +1,36 @@
1
+ <%= $terminal.color "NAME", :bold %>:
2
+
3
+ <%= program :name %>
4
+
5
+ <%= $terminal.color "DESCRIPTION", :bold %>:
6
+
7
+ <%= Commander::HelpFormatter.indent 4, program(:description) %>
8
+
9
+ <%= $terminal.color "COMMANDS", :bold %>:
10
+ <% for name, command in @commands.sort -%>
11
+ <% unless alias? name %>
12
+ <%= "%-20s %s" % [command.name, command.summary || command.description] -%>
13
+ <% end -%>
14
+ <% end %>
15
+ <% unless @aliases.empty? %>
16
+ <%= $terminal.color "ALIASES", :bold %>:
17
+ <% for alias_name, args in @aliases.sort %>
18
+ <%= "%-20s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] -%>
19
+ <% end %>
20
+ <% end %>
21
+ <% unless @options.empty? -%>
22
+ <%= $terminal.color "GLOBAL OPTIONS", :bold %>:
23
+ <% for option in @options -%>
24
+
25
+ <%= option[:switches].join ', ' %>
26
+ <%= option[:description] %>
27
+ <% end -%>
28
+ <% end -%>
29
+ <% if program :help -%>
30
+ <% for title, body in program(:help) %>
31
+ <%= $terminal.color title.to_s.upcase, :bold %>:
32
+
33
+ <%= body %>
34
+ <% end -%>
35
+ <% end -%>
36
+
@@ -0,0 +1,20 @@
1
+
2
+ require 'erb'
3
+
4
+ module Commander
5
+ module HelpFormatter
6
+ class Terminal < Base
7
+ def render
8
+ template(:help).result @runner.get_binding
9
+ end
10
+
11
+ def render_command command
12
+ template(:command_help).result command.get_binding
13
+ end
14
+
15
+ def template name
16
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal', "#{name}.erb")), nil, '-')
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+
2
+ <%= @name %>
3
+ <% if @syntax -%>
4
+
5
+ Usage: <%= @syntax %>
6
+ <% end -%>
7
+ <% if @description || @summary -%>
8
+
9
+ <%= @description || @summary %>
10
+ <% end -%>
11
+ <% unless @examples.empty? -%>
12
+
13
+ Examples:
14
+ <% for description, command in @examples -%>
15
+
16
+ # <%= description %>
17
+ <%= command %>
18
+ <% end -%>
19
+ <% end -%>
20
+ <% unless @options.empty? -%>
21
+
22
+ Options:
23
+ <% for option in @options -%>
24
+ <%= "%-20s %s" % [option[:switches].join(', '), option[:description]] %>
25
+ <% end -%>
26
+ <% end -%>
27
+
@@ -0,0 +1,29 @@
1
+ <%= program :name %>
2
+
3
+ <%= program :description %>
4
+
5
+ Commands:
6
+ <% for name, command in @commands.sort -%>
7
+ <% unless alias? name -%>
8
+ <%= "%-20s %s" % [command.name, command.summary || command.description] %>
9
+ <% end -%>
10
+ <% end -%>
11
+ <% unless @aliases.empty? %>
12
+ Aliases:
13
+ <% for alias_name, args in @aliases.sort -%>
14
+ <%= "%-20s %s %s" % [alias_name, command(alias_name).name, args.join(' ')] %>
15
+ <% end -%>
16
+ <% end %>
17
+ <% unless @options.empty? -%>
18
+ Global Options:
19
+ <% for option in @options -%>
20
+ <%= "%-20s %s" % [option[:switches].join(', '), option[:description]] -%>
21
+ <% end -%>
22
+ <% end -%>
23
+ <% if program :help -%>
24
+ <% for title, body in program(:help) %>
25
+ <%= title %>:
26
+ <%= body %>
27
+ <% end %>
28
+ <% end -%>
29
+
@@ -0,0 +1,12 @@
1
+
2
+ require 'erb'
3
+
4
+ module Commander
5
+ module HelpFormatter
6
+ class TerminalCompact < Terminal
7
+ def template name
8
+ ERB.new(File.read(File.join(File.dirname(__FILE__), 'terminal_compact', "#{name}.erb")), nil, '-')
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Commander
3
+ module HelpFormatter
4
+ autoload :Base, 'taco/commander/help_formatters/base'
5
+ autoload :Terminal, 'taco/commander/help_formatters/terminal'
6
+ autoload :TerminalCompact, 'taco/commander/help_formatters/terminal_compact'
7
+
8
+ module_function
9
+ def indent amount, text
10
+ text.gsub("\n", "\n" + (' ' * amount))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+
2
+ require 'taco/commander'
3
+ require 'taco/commander/delegates'
4
+
5
+ include Commander::Delegates
6
+
7
+ $terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first - 5 rescue 80 if $stdin.tty?
8
+ at_exit { run! }
@@ -0,0 +1,8 @@
1
+
2
+ module Commander
3
+ module Platform
4
+ def self.jruby?
5
+ defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby')
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,405 @@
1
+
2
+ require 'optparse'
3
+
4
+ module Commander
5
+ class Runner
6
+
7
+ #--
8
+ # Exceptions
9
+ #++
10
+
11
+ class CommandError < StandardError; end
12
+ class InvalidCommandError < CommandError; end
13
+
14
+ ##
15
+ # Array of commands.
16
+
17
+ attr_reader :commands
18
+
19
+ ##
20
+ # Global options.
21
+
22
+ attr_reader :options
23
+
24
+ ##
25
+ # Hash of help formatter aliases.
26
+
27
+ attr_reader :help_formatter_aliases
28
+
29
+ ##
30
+ # Initialize a new command runner. Optionally
31
+ # supplying _args_ for mocking, or arbitrary usage.
32
+
33
+ def initialize args = ARGV
34
+ @args, @commands, @aliases, @options = args, {}, {}, []
35
+ @help_formatter_aliases = help_formatter_alias_defaults
36
+ @program = program_defaults
37
+ create_default_commands
38
+ end
39
+
40
+ ##
41
+ # Return singleton Runner instance.
42
+
43
+ def self.instance
44
+ @singleton ||= new
45
+ end
46
+
47
+ ##
48
+ # Run command parsing and execution process.
49
+
50
+ def run!
51
+ trace = false
52
+ require_program :version, :description
53
+ trap('INT') { abort program(:int_message) } if program(:int_message)
54
+ trap('INT') { program(:int_block).call } if program(:int_block)
55
+ global_option('-h', '--help', 'Display help documentation') do
56
+ args = @args - %w[-h --help]
57
+ command(:help).run(*args)
58
+ return
59
+ end
60
+ global_option('-v', '--version', 'Display version information') { say version; return }
61
+ global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true }
62
+ parse_global_options
63
+ remove_global_options options, @args
64
+ unless trace
65
+ begin
66
+ run_active_command
67
+ rescue InvalidCommandError => e
68
+ abort "Error: Invalid command. See 'taco --help' for more information."
69
+ rescue Exception => e
70
+ abort "Error: #{e.to_s}"
71
+ end
72
+ else
73
+ run_active_command
74
+ end
75
+ end
76
+
77
+ ##
78
+ # Return program version.
79
+
80
+ def version
81
+ '%s %s' % [program(:name), program(:version)]
82
+ end
83
+
84
+ ##
85
+ # Assign program information.
86
+ #
87
+ # === Examples
88
+ #
89
+ # # Set data
90
+ # program :name, 'Commander'
91
+ # program :version, Commander::VERSION
92
+ # program :description, 'Commander utility program.'
93
+ # program :help, 'Copyright', '2008 TJ Holowaychuk'
94
+ # program :help, 'Anything', 'You want'
95
+ # program :int_message 'Bye bye!'
96
+ # program :help_formatter, :compact
97
+ # program :help_formatter, Commander::HelpFormatter::TerminalCompact
98
+ #
99
+ # # Get data
100
+ # program :name # => 'Commander'
101
+ #
102
+ # === Keys
103
+ #
104
+ # :version (required) Program version triple, ex: '0.0.1'
105
+ # :description (required) Program description
106
+ # :name Program name, defaults to basename of executable
107
+ # :help_formatter Defaults to Commander::HelpFormatter::Terminal
108
+ # :help Allows addition of arbitrary global help blocks
109
+ # :int_message Message to display when interrupted (CTRL + C)
110
+ #
111
+
112
+ def program key, *args, &block
113
+ if key == :help and !args.empty?
114
+ @program[:help] ||= {}
115
+ @program[:help][args.first] = args.at(1)
116
+ elsif key == :help_formatter && !args.empty?
117
+ @program[key] = (@help_formatter_aliases[args.first] || args.first)
118
+ elsif block
119
+ @program[key] = block
120
+ else
121
+ unless args.empty?
122
+ @program[key] = (args.count == 1 && args[0]) || args
123
+ end
124
+ @program[key]
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Creates and yields a command instance when a block is passed.
130
+ # Otherwise attempts to return the command, raising InvalidCommandError when
131
+ # it does not exist.
132
+ #
133
+ # === Examples
134
+ #
135
+ # command :my_command do |c|
136
+ # c.when_called do |args|
137
+ # # Code
138
+ # end
139
+ # end
140
+ #
141
+
142
+ def command name, &block
143
+ yield add_command(Commander::Command.new(name)) if block
144
+ @commands[name.to_s]
145
+ end
146
+
147
+ ##
148
+ # Add a global option; follows the same syntax as Command#option
149
+ # This would be used for switches such as --version, --trace, etc.
150
+
151
+ def global_option *args, &block
152
+ switches, description = Runner.separate_switches_from_description *args
153
+ @options << {
154
+ :args => args,
155
+ :proc => block,
156
+ :switches => switches,
157
+ :description => description,
158
+ }
159
+ end
160
+
161
+ ##
162
+ # Alias command _name_ with _alias_name_. Optionally _args_ may be passed
163
+ # as if they were being passed straight to the original command via the command-line.
164
+
165
+ def alias_command alias_name, name, *args
166
+ @commands[alias_name.to_s] = command name
167
+ @aliases[alias_name.to_s] = args
168
+ end
169
+
170
+ ##
171
+ # Default command _name_ to be used when no other
172
+ # command is found in the arguments.
173
+
174
+ def default_command name
175
+ @default_command = name
176
+ end
177
+
178
+ ##
179
+ # Add a command object to this runner.
180
+
181
+ def add_command command
182
+ @commands[command.name] = command
183
+ end
184
+
185
+ ##
186
+ # Check if command _name_ is an alias.
187
+
188
+ def alias? name
189
+ @aliases.include? name.to_s
190
+ end
191
+
192
+ ##
193
+ # Check if a command _name_ exists.
194
+
195
+ def command_exists? name
196
+ @commands[name.to_s]
197
+ end
198
+
199
+ #:stopdoc:
200
+
201
+ ##
202
+ # Get active command within arguments passed to this runner.
203
+
204
+ def active_command
205
+ @__active_command ||= command(command_name_from_args)
206
+ end
207
+
208
+ ##
209
+ # Attempts to locate a command name from within the arguments.
210
+ # Supports multi-word commands, using the largest possible match.
211
+
212
+ def command_name_from_args
213
+ @__command_name_from_args ||= (valid_command_names_from(*@args.dup).sort.last || @default_command)
214
+ end
215
+
216
+ ##
217
+ # Returns array of valid command names found within _args_.
218
+
219
+ def valid_command_names_from *args
220
+ arg_string = args.delete_if { |value| value =~ /^-/ }.join ' '
221
+ commands.keys.find_all { |name| name if /^#{name}\b/.match arg_string }
222
+ end
223
+
224
+ ##
225
+ # Help formatter instance.
226
+
227
+ def help_formatter
228
+ @__help_formatter ||= program(:help_formatter).new self
229
+ end
230
+
231
+ ##
232
+ # Return arguments without the command name.
233
+
234
+ def args_without_command_name
235
+ removed = []
236
+ parts = command_name_from_args.split rescue []
237
+ @args.dup.delete_if do |arg|
238
+ removed << arg if parts.include?(arg) and not removed.include?(arg)
239
+ end
240
+ end
241
+
242
+ ##
243
+ # Returns hash of help formatter alias defaults.
244
+
245
+ def help_formatter_alias_defaults
246
+ return :compact => HelpFormatter::TerminalCompact
247
+ end
248
+
249
+ ##
250
+ # Returns hash of program defaults.
251
+
252
+ def program_defaults
253
+ return :help_formatter => HelpFormatter::Terminal,
254
+ :name => File.basename($0)
255
+ end
256
+
257
+ ##
258
+ # Creates default commands such as 'help' which is
259
+ # essentially the same as using the --help switch.
260
+
261
+ def create_default_commands
262
+ command :help do |c|
263
+ c.syntax = 'commander help [command]'
264
+ c.description = 'Display global or [command] help documentation.'
265
+ c.example 'Display global help', 'command help'
266
+ c.example "Display help for 'foo'", 'command help foo'
267
+ c.when_called do |args, options|
268
+ if args.empty?
269
+ say help_formatter.render
270
+ else
271
+ command = command args.join(' ')
272
+ begin
273
+ require_valid_command command
274
+ rescue InvalidCommandError => e
275
+ abort "#{e}. Use --help for more information"
276
+ end
277
+ say help_formatter.render_command(command)
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ ##
284
+ # Raises InvalidCommandError when a _command_ is not found.
285
+
286
+ def require_valid_command command = active_command
287
+ raise InvalidCommandError, 'invalid command', caller if command.nil?
288
+ end
289
+
290
+ ##
291
+ # Removes global _options_ from _args_. This prevents an invalid
292
+ # option error from occurring when options are parsed
293
+ # again for the command.
294
+
295
+ def remove_global_options options, args
296
+ # TODO: refactor with flipflop, please TJ ! have time to refactor me !
297
+ options.each do |option|
298
+ switches = option[:switches].dup
299
+ next if switches.empty?
300
+
301
+ if switchHasArg = switches.any? { |s| s =~ /[ =]/ }
302
+ switches.map! { |s| s[0, s.index('=') || s.index(' ') || s.length] }
303
+ end
304
+
305
+ past_switch, arg_removed = false, false
306
+ args.delete_if do |arg|
307
+ if switches.any? { |s| arg[0, s.length] == s }
308
+ arg_removed = !switchHasArg
309
+ past_switch = true
310
+ elsif past_switch && !arg_removed && arg !~ /^-/
311
+ arg_removed = true
312
+ else
313
+ arg_removed = true
314
+ false
315
+ end
316
+ end
317
+ end
318
+ end
319
+
320
+ ##
321
+ # Parse global command options.
322
+
323
+ def parse_global_options
324
+
325
+ parser = options.inject(OptionParser.new) do |options, option|
326
+ options.on *option[:args], &global_option_proc(option[:switches], &option[:proc])
327
+ end
328
+
329
+ options = @args.dup
330
+ begin
331
+ parser.parse!(options)
332
+ rescue OptionParser::InvalidOption => e
333
+ # Remove the offending args and retry.
334
+ options = options.reject { |o| e.args.include?(o) }
335
+ retry
336
+ end
337
+ end
338
+
339
+ ##
340
+ # Returns a proc allowing for commands to inherit global options.
341
+ # This functionality works whether a block is present for the global
342
+ # option or not, so simple switches such as --verbose can be used
343
+ # without a block, and used throughout all commands.
344
+
345
+ def global_option_proc switches, &block
346
+ lambda do |value|
347
+ unless active_command.nil?
348
+ active_command.proxy_options << [Runner.switch_to_sym(switches.last), value]
349
+ end
350
+ yield value if block and !value.nil?
351
+ end
352
+ end
353
+
354
+ ##
355
+ # Raises a CommandError when the program any of the _keys_ are not present, or empty.
356
+
357
+ def require_program *keys
358
+ keys.each do |key|
359
+ raise CommandError, "program #{key} required" if program(key).nil? or program(key).empty?
360
+ end
361
+ end
362
+
363
+ ##
364
+ # Return switches and description separated from the _args_ passed.
365
+
366
+ def self.separate_switches_from_description *args
367
+ switches = args.find_all { |arg| arg.to_s =~ /^-/ }
368
+ description = args.last unless !args.last.is_a? String or args.last.match(/^-/)
369
+ return switches, description
370
+ end
371
+
372
+ ##
373
+ # Attempts to generate a method name symbol from +switch+.
374
+ # For example:
375
+ #
376
+ # -h # => :h
377
+ # --trace # => :trace
378
+ # --some-switch # => :some_switch
379
+ # --[no-]feature # => :feature
380
+ # --file FILE # => :file
381
+ # --list of,things # => :list
382
+ #
383
+
384
+ def self.switch_to_sym switch
385
+ switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
386
+ end
387
+
388
+ ##
389
+ # Run the active command.
390
+
391
+ def run_active_command
392
+ require_valid_command
393
+ if alias? command_name_from_args
394
+ active_command.run *(@aliases[command_name_from_args.to_s] + args_without_command_name)
395
+ else
396
+ active_command.run *args_without_command_name
397
+ end
398
+ end
399
+
400
+ def say *args #:nodoc:
401
+ $terminal.say *args
402
+ end
403
+
404
+ end
405
+ end
@@ -0,0 +1,3 @@
1
+ module Commander
2
+ VERSION = '4.1.4'
3
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taco_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -35,18 +35,36 @@ executables:
35
35
  extensions: []
36
36
  extra_rdoc_files: []
37
37
  files:
38
- - lib/taco.rb
39
38
  - lib/taco/change.rb
40
39
  - lib/taco/cli.rb
40
+ - lib/taco/commander/blank.rb
41
+ - lib/taco/commander/command.rb
42
+ - lib/taco/commander/core_ext/array.rb
43
+ - lib/taco/commander/core_ext/object.rb
44
+ - lib/taco/commander/core_ext.rb
45
+ - lib/taco/commander/delegates.rb
46
+ - lib/taco/commander/help_formatters/base.rb
47
+ - lib/taco/commander/help_formatters/terminal/command_help.erb
48
+ - lib/taco/commander/help_formatters/terminal/help.erb
49
+ - lib/taco/commander/help_formatters/terminal.rb
50
+ - lib/taco/commander/help_formatters/terminal_compact/command_help.erb
51
+ - lib/taco/commander/help_formatters/terminal_compact/help.erb
52
+ - lib/taco/commander/help_formatters/terminal_compact.rb
53
+ - lib/taco/commander/help_formatters.rb
54
+ - lib/taco/commander/import.rb
55
+ - lib/taco/commander/platform.rb
56
+ - lib/taco/commander/runner.rb
57
+ - lib/taco/commander/version.rb
41
58
  - lib/taco/commander.rb
59
+ - lib/taco/defaults/index.html.erb
60
+ - lib/taco/defaults/taco_profile
61
+ - lib/taco/defaults/tacorc
42
62
  - lib/taco/issue.rb
43
63
  - lib/taco/schema.rb
44
64
  - lib/taco/taco.rb
45
65
  - lib/taco/taco_profile.rb
46
66
  - lib/taco/tacorc.rb
47
- - lib/taco/defaults/index.html.erb
48
- - lib/taco/defaults/taco_profile
49
- - lib/taco/defaults/tacorc
67
+ - lib/taco.rb
50
68
  - bin/taco
51
69
  homepage: http://github.com/mikepartelow/taco
52
70
  licenses: []