github_cli 0.5.3 → 0.5.4
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.
- data/.travis.yml +14 -3
- data/CHANGELOG.md +15 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +41 -44
- data/README.md +77 -14
- data/Rakefile +4 -2
- data/features/assignee.feature +1 -0
- data/features/blob.feature +1 -0
- data/features/collaborator.feature +1 -0
- data/features/commit.feature +2 -1
- data/features/config.feature +27 -28
- data/features/event.feature +1 -0
- data/features/init.feature +20 -23
- data/features/key.feature +5 -5
- data/features/milestone.feature +3 -2
- data/features/reference.feature +3 -2
- data/features/starring.feature +1 -0
- data/features/support/hooks.rb +1 -1
- data/features/tag.feature +2 -1
- data/features/tree.feature +17 -0
- data/features/watching.feature +1 -0
- data/fixtures/simple_config +3 -5
- data/github_cli.gemspec +1 -1
- data/lib/github_cli/api.rb +11 -6
- data/lib/github_cli/apis/event.rb +8 -8
- data/lib/github_cli/apis/label.rb +0 -12
- data/lib/github_cli/apis/starring.rb +5 -5
- data/lib/github_cli/apis/watching.rb +5 -5
- data/lib/github_cli/cli.rb +21 -30
- data/lib/github_cli/command.rb +1 -1
- data/lib/github_cli/commands/authorizations.rb +28 -2
- data/lib/github_cli/commands/collaborators.rb +12 -12
- data/lib/github_cli/commands/commits.rb +18 -2
- data/lib/github_cli/commands/events.rb +6 -8
- data/lib/github_cli/commands/followers.rb +1 -1
- data/lib/github_cli/commands/labels.rb +22 -20
- data/lib/github_cli/commands/milestones.rb +43 -13
- data/lib/github_cli/commands/references.rb +21 -6
- data/lib/github_cli/commands/starring.rb +3 -2
- data/lib/github_cli/commands/tags.rb +16 -1
- data/lib/github_cli/commands/trees.rb +11 -5
- data/lib/github_cli/commands/watching.rb +3 -2
- data/lib/github_cli/config.rb +15 -6
- data/lib/github_cli/dsl.rb +2 -2
- data/lib/github_cli/formatter.rb +2 -3
- data/lib/github_cli/formatters/csv.rb +29 -14
- data/lib/github_cli/formatters/table.rb +2 -3
- data/lib/github_cli/man/gcli-config.1 +17 -13
- data/lib/github_cli/man/gcli-config.1.txt +23 -21
- data/lib/github_cli/vendor/thor/actions/create_link.rb +3 -0
- data/lib/github_cli/vendor/thor/actions/directory.rb +29 -10
- data/lib/github_cli/vendor/thor/actions/file_manipulation.rb +9 -3
- data/lib/github_cli/vendor/thor/actions.rb +18 -18
- data/lib/github_cli/vendor/thor/base.rb +97 -89
- data/lib/github_cli/vendor/thor/{task.rb → command.rb} +16 -12
- data/lib/github_cli/vendor/thor/core_ext/hash_with_indifferent_access.rb +5 -0
- data/lib/github_cli/vendor/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/github_cli/vendor/thor/error.rb +4 -7
- data/lib/github_cli/vendor/thor/group.rb +34 -32
- data/lib/github_cli/vendor/thor/invocation.rb +28 -26
- data/lib/github_cli/vendor/thor/parser/options.rb +66 -26
- data/lib/github_cli/vendor/thor/rake_compat.rb +3 -2
- data/lib/github_cli/vendor/thor/runner.rb +21 -20
- data/lib/github_cli/vendor/thor/shell/basic.rb +20 -16
- data/lib/github_cli/vendor/thor/shell/color.rb +13 -9
- data/lib/github_cli/vendor/thor/shell/html.rb +13 -9
- data/lib/github_cli/vendor/thor/util.rb +214 -210
- data/lib/github_cli/vendor/thor/version.rb +1 -1
- data/lib/github_cli/vendor/thor.rb +232 -153
- data/lib/github_cli/version.rb +1 -1
- data/man/gcli-config.1.ronn +14 -11
- data/spec/github_cli/commands/assignees_spec.rb +20 -0
- data/spec/github_cli/commands/blobs_spec.rb +21 -0
- data/spec/github_cli/commands/collaborators_spec.rb +31 -0
- data/spec/github_cli/commands/commits_spec.rb +26 -0
- data/spec/github_cli/commands/emails_spec.rb +24 -0
- data/spec/github_cli/commands/events_spec.rb +56 -0
- data/spec/github_cli/commands/followers_spec.rb +44 -0
- data/spec/github_cli/commands/keys_spec.rb +36 -0
- data/spec/github_cli/commands/labels_spec.rb +61 -0
- data/spec/github_cli/commands/milestones_spec.rb +47 -0
- data/spec/github_cli/commands/references_spec.rb +42 -0
- data/spec/github_cli/commands/starring_spec.rb +40 -0
- data/spec/github_cli/commands/tags_spec.rb +26 -0
- data/spec/github_cli/commands/trees_spec.rb +32 -0
- data/spec/github_cli/commands/watching_spec.rb +40 -0
- data/spec/github_cli/config_spec.rb +109 -116
- data/spec/github_cli/util/convert_value_spec.rb +19 -0
- data/spec/github_cli/util/convert_values_spec.rb +14 -0
- data/spec/github_cli/util_spec.rb +0 -29
- metadata +51 -19
- data/lib/github_cli/vendor/thor/core_ext/dir_escape.rb +0 -0
- data/lib/github_cli/vendor/thor/core_ext/file_binary_read.rb +0 -9
- data/lib/github_cli/vendor/thor/empty.txt +0 -0
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'thor/base'
|
2
2
|
|
3
3
|
# Thor has a special class called Thor::Group. The main difference to Thor class
|
4
|
-
# is that it invokes all
|
4
|
+
# is that it invokes all commands at once. It also include some methods that allows
|
5
5
|
# invocations to be done at the class method, which are not available to Thor
|
6
|
-
#
|
6
|
+
# commands.
|
7
7
|
class Thor::Group
|
8
8
|
class << self
|
9
9
|
# The description for this Thor::Group. If none is provided, but a source root
|
@@ -14,11 +14,11 @@ class Thor::Group
|
|
14
14
|
# description<String>:: The description for this Thor::Group.
|
15
15
|
#
|
16
16
|
def desc(description=nil)
|
17
|
-
case description
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
@desc = case description
|
18
|
+
when nil
|
19
|
+
@desc || from_superclass(:desc, nil)
|
20
|
+
else
|
21
|
+
description
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -48,7 +48,7 @@ class Thor::Group
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# Invoke the given namespace or class given. It adds an instance
|
51
|
-
# method that will invoke the klass and
|
51
|
+
# method that will invoke the klass and command. You can give a block to
|
52
52
|
# configure how it will be invoked.
|
53
53
|
#
|
54
54
|
# The namespace/class given will have its options showed on the help
|
@@ -64,12 +64,12 @@ class Thor::Group
|
|
64
64
|
|
65
65
|
class_eval <<-METHOD, __FILE__, __LINE__
|
66
66
|
def _invoke_#{name.to_s.gsub(/\W/, '_')}
|
67
|
-
klass,
|
67
|
+
klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
|
68
68
|
|
69
69
|
if klass
|
70
70
|
say_status :invoke, #{name.inspect}, #{verbose.inspect}
|
71
71
|
block = self.class.invocation_blocks[#{name.inspect}]
|
72
|
-
_invoke_for_class_method klass,
|
72
|
+
_invoke_for_class_method klass, command, &block
|
73
73
|
else
|
74
74
|
say_status :error, %(#{name.inspect} [not found]), :red
|
75
75
|
end
|
@@ -100,7 +100,7 @@ class Thor::Group
|
|
100
100
|
# In some cases you want to customize how a specified hook is going to be
|
101
101
|
# invoked. You can do that by overwriting the class method
|
102
102
|
# prepare_for_invocation. The class method must necessarily return a klass
|
103
|
-
# and an optional
|
103
|
+
# and an optional command.
|
104
104
|
#
|
105
105
|
# ==== Custom invocations
|
106
106
|
#
|
@@ -127,12 +127,12 @@ class Thor::Group
|
|
127
127
|
|
128
128
|
value = options[#{name.inspect}]
|
129
129
|
value = #{name.inspect} if TrueClass === value
|
130
|
-
klass,
|
130
|
+
klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
|
131
131
|
|
132
132
|
if klass
|
133
133
|
say_status :invoke, value, #{verbose.inspect}
|
134
134
|
block = self.class.invocation_blocks[#{name.inspect}]
|
135
|
-
_invoke_for_class_method klass,
|
135
|
+
_invoke_for_class_method klass, command, &block
|
136
136
|
else
|
137
137
|
say_status :error, %(\#{value} [not found]), :red
|
138
138
|
end
|
@@ -149,7 +149,7 @@ class Thor::Group
|
|
149
149
|
#
|
150
150
|
def remove_invocation(*names)
|
151
151
|
names.each do |name|
|
152
|
-
|
152
|
+
remove_command(name)
|
153
153
|
remove_class_option(name)
|
154
154
|
invocations.delete(name)
|
155
155
|
invocation_blocks.delete(name)
|
@@ -196,21 +196,22 @@ class Thor::Group
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
-
# Returns
|
200
|
-
def
|
199
|
+
# Returns commands ready to be printed.
|
200
|
+
def printable_commands(*)
|
201
201
|
item = []
|
202
202
|
item << banner
|
203
203
|
item << (desc ? "# #{desc.gsub(/\s+/m,' ')}" : "")
|
204
204
|
[item]
|
205
205
|
end
|
206
|
+
alias printable_tasks printable_commands
|
206
207
|
|
207
|
-
def handle_argument_error(
|
208
|
+
def handle_argument_error(command, error, arity=nil) #:nodoc:
|
208
209
|
if arity > 0
|
209
|
-
msg = "#{basename} #{
|
210
|
+
msg = "#{basename} #{command.name} takes #{arity} argument"
|
210
211
|
msg << "s" if arity > 1
|
211
212
|
msg << ", but it should not."
|
212
213
|
else
|
213
|
-
msg = "You should not pass arguments to #{basename} #{
|
214
|
+
msg = "You should not pass arguments to #{basename} #{command.name}."
|
214
215
|
end
|
215
216
|
|
216
217
|
raise error, msg
|
@@ -219,7 +220,7 @@ class Thor::Group
|
|
219
220
|
protected
|
220
221
|
|
221
222
|
# The method responsible for dispatching given the args.
|
222
|
-
def dispatch(
|
223
|
+
def dispatch(command, given_args, given_opts, config) #:nodoc:
|
223
224
|
if Thor::HELP_MAPPINGS.include?(given_args.first)
|
224
225
|
help(config[:shell])
|
225
226
|
return
|
@@ -230,10 +231,9 @@ class Thor::Group
|
|
230
231
|
|
231
232
|
instance = new(args, opts, config)
|
232
233
|
yield instance if block_given?
|
233
|
-
args = instance.args
|
234
234
|
|
235
|
-
if
|
236
|
-
instance.
|
235
|
+
if command
|
236
|
+
instance.invoke_command(all_commands[command])
|
237
237
|
else
|
238
238
|
instance.invoke_all
|
239
239
|
end
|
@@ -242,22 +242,24 @@ class Thor::Group
|
|
242
242
|
# The banner for this class. You can customize it if you are invoking the
|
243
243
|
# thor class by another ways which is not the Thor::Runner.
|
244
244
|
def banner
|
245
|
-
"#{basename} #{
|
245
|
+
"#{basename} #{self_command.formatted_usage(self, false)}"
|
246
246
|
end
|
247
247
|
|
248
|
-
# Represents the whole class as a
|
249
|
-
def
|
250
|
-
Thor::
|
248
|
+
# Represents the whole class as a command.
|
249
|
+
def self_command #:nodoc:
|
250
|
+
Thor::DynamicCommand.new(self.namespace, class_options)
|
251
251
|
end
|
252
|
+
alias self_task self_command
|
252
253
|
|
253
254
|
def baseclass #:nodoc:
|
254
255
|
Thor::Group
|
255
256
|
end
|
256
257
|
|
257
|
-
def
|
258
|
-
|
258
|
+
def create_command(meth) #:nodoc:
|
259
|
+
commands[meth.to_s] = Thor::Command.new(meth, nil, nil, nil, nil)
|
259
260
|
true
|
260
261
|
end
|
262
|
+
alias create_task create_command
|
261
263
|
end
|
262
264
|
|
263
265
|
include Thor::Base
|
@@ -266,19 +268,19 @@ class Thor::Group
|
|
266
268
|
|
267
269
|
# Shortcut to invoke with padding and block handling. Use internally by
|
268
270
|
# invoke and invoke_from_option class methods.
|
269
|
-
def _invoke_for_class_method(klass,
|
271
|
+
def _invoke_for_class_method(klass, command=nil, *args, &block) #:nodoc:
|
270
272
|
with_padding do
|
271
273
|
if block
|
272
274
|
case block.arity
|
273
275
|
when 3
|
274
|
-
block.call(self, klass,
|
276
|
+
block.call(self, klass, command)
|
275
277
|
when 2
|
276
278
|
block.call(self, klass)
|
277
279
|
when 1
|
278
280
|
instance_exec(klass, &block)
|
279
281
|
end
|
280
282
|
else
|
281
|
-
invoke klass,
|
283
|
+
invoke klass, command, *args
|
282
284
|
end
|
283
285
|
end
|
284
286
|
end
|
@@ -6,12 +6,12 @@ class Thor
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
# This method is responsible for receiving a name and find the proper
|
9
|
-
# class and
|
9
|
+
# class and command for it. The key is an optional parameter which is
|
10
10
|
# available only in class methods invocations (i.e. in Thor::Group).
|
11
11
|
def prepare_for_invocation(key, name) #:nodoc:
|
12
12
|
case name
|
13
13
|
when Symbol, String
|
14
|
-
Thor::Util.
|
14
|
+
Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
|
15
15
|
else
|
16
16
|
name
|
17
17
|
end
|
@@ -25,15 +25,15 @@ class Thor
|
|
25
25
|
super
|
26
26
|
end
|
27
27
|
|
28
|
-
# Receives a name and invokes it. The name can be a string (either "
|
29
|
-
# "namespace:
|
30
|
-
# cannot be guessed by name, it can also be supplied as second argument.
|
28
|
+
# Receives a name and invokes it. The name can be a string (either "command" or
|
29
|
+
# "namespace:command"), a Thor::Command, a Class or a Thor instance. If the
|
30
|
+
# command cannot be guessed by name, it can also be supplied as second argument.
|
31
31
|
#
|
32
32
|
# You can also supply the arguments, options and configuration values for
|
33
|
-
# the
|
33
|
+
# the command to be invoked, if none is given, the same values used to
|
34
34
|
# initialize the invoker are used to initialize the invoked.
|
35
35
|
#
|
36
|
-
# When no name is given, it will invoke the default
|
36
|
+
# When no name is given, it will invoke the default command of the current class.
|
37
37
|
#
|
38
38
|
# ==== Examples
|
39
39
|
#
|
@@ -54,16 +54,16 @@ class Thor
|
|
54
54
|
# end
|
55
55
|
# end
|
56
56
|
#
|
57
|
-
# You can notice that the method "foo" above invokes two
|
57
|
+
# You can notice that the method "foo" above invokes two commands: "bar",
|
58
58
|
# which belongs to the same class and "hello" which belongs to the class B.
|
59
59
|
#
|
60
|
-
# By using an invocation system you ensure that a
|
60
|
+
# By using an invocation system you ensure that a command is invoked only once.
|
61
61
|
# In the example above, invoking "foo" will invoke "b:hello" just once, even
|
62
62
|
# if it's invoked later by "bar" method.
|
63
63
|
#
|
64
64
|
# When class A invokes class B, all arguments used on A initialization are
|
65
65
|
# supplied to B. This allows lazy parse of options. Let's suppose you have
|
66
|
-
# some rspec
|
66
|
+
# some rspec commands:
|
67
67
|
#
|
68
68
|
# class Rspec < Thor::Group
|
69
69
|
# class_option :mock_framework, :type => :string, :default => :rr
|
@@ -100,30 +100,31 @@ class Thor
|
|
100
100
|
end
|
101
101
|
|
102
102
|
args.unshift(nil) if Array === args.first || NilClass === args.first
|
103
|
-
|
103
|
+
command, args, opts, config = args
|
104
104
|
|
105
|
-
klass,
|
105
|
+
klass, command = _retrieve_class_and_command(name, command)
|
106
106
|
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
107
107
|
|
108
108
|
args, opts, config = _parse_initialization_options(args, opts, config)
|
109
|
-
klass.send(:dispatch,
|
109
|
+
klass.send(:dispatch, command, args, opts, config) do |instance|
|
110
110
|
instance.parent_options = options
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
# Invoke the given
|
115
|
-
def
|
114
|
+
# Invoke the given command if the given args.
|
115
|
+
def invoke_command(command, *args) #:nodoc:
|
116
116
|
current = @_invocations[self.class]
|
117
117
|
|
118
|
-
unless current.include?(
|
119
|
-
current <<
|
120
|
-
|
118
|
+
unless current.include?(command.name)
|
119
|
+
current << command.name
|
120
|
+
command.run(self, *args)
|
121
121
|
end
|
122
122
|
end
|
123
|
+
alias invoke_task invoke_command
|
123
124
|
|
124
|
-
# Invoke all
|
125
|
+
# Invoke all commands for the current instance.
|
125
126
|
def invoke_all #:nodoc:
|
126
|
-
self.class.
|
127
|
+
self.class.all_commands.map { |_, command| invoke_command(command) }
|
127
128
|
end
|
128
129
|
|
129
130
|
# Invokes using shell padding.
|
@@ -138,21 +139,22 @@ class Thor
|
|
138
139
|
{ :invocations => @_invocations }
|
139
140
|
end
|
140
141
|
|
141
|
-
# This method simply retrieves the class and
|
142
|
-
# If the name is nil or the given name is a
|
142
|
+
# This method simply retrieves the class and command to be invoked.
|
143
|
+
# If the name is nil or the given name is a command in the current class,
|
143
144
|
# use the given name and return self as class. Otherwise, call
|
144
145
|
# prepare_for_invocation in the current class.
|
145
|
-
def
|
146
|
+
def _retrieve_class_and_command(name, sent_command=nil) #:nodoc:
|
146
147
|
case
|
147
148
|
when name.nil?
|
148
149
|
[self.class, nil]
|
149
|
-
when self.class.
|
150
|
+
when self.class.all_commands[name.to_s]
|
150
151
|
[self.class, name.to_s]
|
151
152
|
else
|
152
|
-
klass,
|
153
|
-
[klass,
|
153
|
+
klass, command = self.class.prepare_for_invocation(nil, name)
|
154
|
+
[klass, command || sent_command]
|
154
155
|
end
|
155
156
|
end
|
157
|
+
alias _retrieve_class_and_task _retrieve_class_and_command
|
156
158
|
|
157
159
|
# Initialize klass using values stored in the @_initializer.
|
158
160
|
def _parse_initialization_options(args, opts, config) #:nodoc:
|
@@ -5,27 +5,32 @@ class Thor
|
|
5
5
|
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
|
6
6
|
SHORT_SQ_RE = /^-([a-z]{2,})$/i # Allow either -x -v or -xv style for single char args
|
7
7
|
SHORT_NUM = /^(-[a-z])#{NUMERIC}$/i
|
8
|
+
OPTS_END = '--'.freeze
|
8
9
|
|
9
10
|
# Receives a hash and makes it switches.
|
10
11
|
def self.to_switches(options)
|
11
12
|
options.map do |key, value|
|
12
13
|
case value
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
14
|
+
when true
|
15
|
+
"--#{key}"
|
16
|
+
when Array
|
17
|
+
"--#{key} #{value.map{ |v| v.inspect }.join(' ')}"
|
18
|
+
when Hash
|
19
|
+
"--#{key} #{value.map{ |k,v| "#{k}:#{v}" }.join(' ')}"
|
20
|
+
when nil, false
|
21
|
+
""
|
22
|
+
else
|
23
|
+
"--#{key} #{value.inspect}"
|
23
24
|
end
|
24
25
|
end.join(" ")
|
25
26
|
end
|
26
27
|
|
27
28
|
# Takes a hash of Thor::Option and a hash with defaults.
|
28
|
-
|
29
|
+
#
|
30
|
+
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
|
31
|
+
# an unknown option or a regular argument.
|
32
|
+
def initialize(hash_options={}, defaults={}, stop_on_unknown=false)
|
33
|
+
@stop_on_unknown = stop_on_unknown
|
29
34
|
options = hash_options.values
|
30
35
|
super(options)
|
31
36
|
|
@@ -41,7 +46,8 @@ class Thor
|
|
41
46
|
@switches[option.switch_name] = option
|
42
47
|
|
43
48
|
option.aliases.each do |short|
|
44
|
-
|
49
|
+
name = short.to_s.sub(/^(?!\-)/, '-')
|
50
|
+
@shorts[name] ||= option.switch_name
|
45
51
|
end
|
46
52
|
end
|
47
53
|
end
|
@@ -50,15 +56,30 @@ class Thor
|
|
50
56
|
@extra
|
51
57
|
end
|
52
58
|
|
59
|
+
def peek
|
60
|
+
return super unless @parsing_options
|
61
|
+
|
62
|
+
result = super
|
63
|
+
if result == OPTS_END
|
64
|
+
shift
|
65
|
+
@parsing_options = false
|
66
|
+
super
|
67
|
+
else
|
68
|
+
result
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
53
72
|
def parse(args)
|
54
73
|
@pile = args.dup
|
74
|
+
@parsing_options = true
|
55
75
|
|
56
76
|
while peek
|
57
|
-
|
58
|
-
|
77
|
+
if parsing_options?
|
78
|
+
match, is_switch = current_is_switch?
|
79
|
+
shifted = shift
|
59
80
|
|
60
|
-
|
61
|
-
|
81
|
+
if is_switch
|
82
|
+
case shifted
|
62
83
|
when SHORT_SQ_RE
|
63
84
|
unshift($1.split('').map { |f| "-#{f}" })
|
64
85
|
next
|
@@ -67,16 +88,24 @@ class Thor
|
|
67
88
|
switch = $1
|
68
89
|
when LONG_RE, SHORT_RE
|
69
90
|
switch = $1
|
91
|
+
end
|
92
|
+
|
93
|
+
switch = normalize_switch(switch)
|
94
|
+
option = switch_option(switch)
|
95
|
+
@assigns[option.human_name] = parse_peek(switch, option)
|
96
|
+
elsif @stop_on_unknown
|
97
|
+
@parsing_options = false
|
98
|
+
@extra << shifted
|
99
|
+
@extra << shift while peek
|
100
|
+
break
|
101
|
+
elsif match
|
102
|
+
@extra << shifted
|
103
|
+
@extra << shift while peek && peek !~ /^-/
|
104
|
+
else
|
105
|
+
@extra << shifted
|
70
106
|
end
|
71
|
-
|
72
|
-
switch = normalize_switch(switch)
|
73
|
-
option = switch_option(switch)
|
74
|
-
@assigns[option.human_name] = parse_peek(switch, option)
|
75
|
-
elsif match
|
76
|
-
@extra << shifted
|
77
|
-
@extra << shift while peek && peek !~ /^-/
|
78
107
|
else
|
79
|
-
@extra <<
|
108
|
+
@extra << shift
|
80
109
|
end
|
81
110
|
end
|
82
111
|
|
@@ -95,8 +124,10 @@ class Thor
|
|
95
124
|
|
96
125
|
protected
|
97
126
|
|
98
|
-
#
|
127
|
+
# Check if the current value in peek is a registered switch.
|
99
128
|
#
|
129
|
+
# Two booleans are returned. The first is true if the current value
|
130
|
+
# starts with a hyphen; the second is true if it is a registered switch.
|
100
131
|
def current_is_switch?
|
101
132
|
case peek
|
102
133
|
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
@@ -117,6 +148,10 @@ class Thor
|
|
117
148
|
end
|
118
149
|
end
|
119
150
|
|
151
|
+
def current_is_value?
|
152
|
+
peek && (!parsing_options? || super)
|
153
|
+
end
|
154
|
+
|
120
155
|
def switch?(arg)
|
121
156
|
switch_option(normalize_switch(arg))
|
122
157
|
end
|
@@ -135,6 +170,11 @@ class Thor
|
|
135
170
|
(@shorts[arg] || arg).tr('_', '-')
|
136
171
|
end
|
137
172
|
|
173
|
+
def parsing_options?
|
174
|
+
peek
|
175
|
+
@parsing_options
|
176
|
+
end
|
177
|
+
|
138
178
|
# Parse boolean values which can be given as --foo=true, --foo or --no-foo.
|
139
179
|
#
|
140
180
|
def parse_boolean(switch)
|
@@ -156,7 +196,7 @@ class Thor
|
|
156
196
|
# Parse the value at the peek analyzing if it requires an input or not.
|
157
197
|
#
|
158
198
|
def parse_peek(switch, option)
|
159
|
-
if current_is_switch_formatted? || last?
|
199
|
+
if parsing_options? && (current_is_switch_formatted? || last?)
|
160
200
|
if option.boolean?
|
161
201
|
# No problem for boolean types
|
162
202
|
elsif no_or_skip?(switch)
|
@@ -6,12 +6,13 @@ class Thor
|
|
6
6
|
# rake package tasks. For example, to use rspec rake tasks, one can do:
|
7
7
|
#
|
8
8
|
# require 'thor/rake_compat'
|
9
|
+
# require 'rspec/core/rake_task'
|
9
10
|
#
|
10
11
|
# class Default < Thor
|
11
12
|
# include Thor::RakeCompat
|
12
13
|
#
|
13
|
-
#
|
14
|
-
# t.spec_opts = ['--options', "
|
14
|
+
# RSpec::Core::RakeTask.new(:spec) do |t|
|
15
|
+
# t.spec_opts = ['--options', "./.rspec"]
|
15
16
|
# t.spec_files = FileList['spec/**/*_spec.rb']
|
16
17
|
# end
|
17
18
|
# end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'thor/group'
|
3
|
-
require 'thor/core_ext/
|
3
|
+
require 'thor/core_ext/io_binary_read'
|
4
4
|
|
5
5
|
require 'fileutils'
|
6
6
|
require 'open-uri'
|
@@ -16,33 +16,33 @@ class Thor::Runner < Thor #:nodoc:
|
|
16
16
|
def help(meth = nil)
|
17
17
|
if meth && !self.respond_to?(meth)
|
18
18
|
initialize_thorfiles(meth)
|
19
|
-
klass,
|
20
|
-
self.class.
|
21
|
-
klass.start(["-h",
|
19
|
+
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
20
|
+
self.class.handle_no_command_error(command, false) if klass.nil?
|
21
|
+
klass.start(["-h", command].compact, :shell => self.shell)
|
22
22
|
else
|
23
23
|
super
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
# If a
|
28
|
-
# Thor::Runner is then
|
27
|
+
# If a command is not found on Thor::Runner, method missing is invoked and
|
28
|
+
# Thor::Runner is then responsible for finding the command in all classes.
|
29
29
|
#
|
30
30
|
def method_missing(meth, *args)
|
31
31
|
meth = meth.to_s
|
32
32
|
initialize_thorfiles(meth)
|
33
|
-
klass,
|
34
|
-
self.class.
|
35
|
-
args.unshift(
|
33
|
+
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
34
|
+
self.class.handle_no_command_error(command, false) if klass.nil?
|
35
|
+
args.unshift(command) if command
|
36
36
|
klass.start(args, :shell => self.shell)
|
37
37
|
end
|
38
38
|
|
39
|
-
desc "install NAME", "Install an optionally named Thor file into your system
|
39
|
+
desc "install NAME", "Install an optionally named Thor file into your system commands"
|
40
40
|
method_options :as => :string, :relative => :boolean, :force => :boolean
|
41
41
|
def install(name)
|
42
42
|
initialize_thorfiles
|
43
43
|
|
44
44
|
# If a directory name is provided as the argument, look for a 'main.thor'
|
45
|
-
#
|
45
|
+
# command in said directory.
|
46
46
|
begin
|
47
47
|
if File.directory?(File.expand_path(name))
|
48
48
|
base, package = File.join(name, "main.thor"), :directory
|
@@ -143,14 +143,14 @@ class Thor::Runner < Thor #:nodoc:
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
desc "installed", "List the installed Thor modules and
|
146
|
+
desc "installed", "List the installed Thor modules and commands"
|
147
147
|
method_options :internal => :boolean
|
148
148
|
def installed
|
149
149
|
initialize_thorfiles(nil, true)
|
150
150
|
display_klasses(true, options["internal"])
|
151
151
|
end
|
152
152
|
|
153
|
-
desc "list [SEARCH]", "List the available thor
|
153
|
+
desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
|
154
154
|
method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
|
155
155
|
def list(search="")
|
156
156
|
initialize_thorfiles
|
@@ -168,8 +168,8 @@ class Thor::Runner < Thor #:nodoc:
|
|
168
168
|
|
169
169
|
private
|
170
170
|
|
171
|
-
def self.banner(
|
172
|
-
"thor " +
|
171
|
+
def self.banner(command, all = false, subcommand = false)
|
172
|
+
"thor " + command.formatted_usage(self, all, subcommand)
|
173
173
|
end
|
174
174
|
|
175
175
|
def thor_root
|
@@ -276,25 +276,25 @@ class Thor::Runner < Thor #:nodoc:
|
|
276
276
|
def display_klasses(with_modules=false, show_internal=false, klasses=Thor::Base.subclasses)
|
277
277
|
klasses -= [Thor, Thor::Runner, Thor::Group] unless show_internal
|
278
278
|
|
279
|
-
raise Error, "No Thor
|
279
|
+
raise Error, "No Thor commands available" if klasses.empty?
|
280
280
|
show_modules if with_modules && !thor_yaml.empty?
|
281
281
|
|
282
282
|
list = Hash.new { |h,k| h[k] = [] }
|
283
283
|
groups = klasses.select { |k| k.ancestors.include?(Thor::Group) }
|
284
284
|
|
285
285
|
# Get classes which inherit from Thor
|
286
|
-
(klasses - groups).each { |k| list[k.namespace.split(":").first] += k.
|
286
|
+
(klasses - groups).each { |k| list[k.namespace.split(":").first] += k.printable_commands(false) }
|
287
287
|
|
288
288
|
# Get classes which inherit from Thor::Base
|
289
|
-
groups.map! { |k| k.
|
289
|
+
groups.map! { |k| k.printable_commands(false).first }
|
290
290
|
list["root"] = groups
|
291
291
|
|
292
292
|
# Order namespaces with default coming first
|
293
293
|
list = list.sort{ |a,b| a[0].sub(/^default/, '') <=> b[0].sub(/^default/, '') }
|
294
|
-
list.each { |n,
|
294
|
+
list.each { |n, commands| display_commands(n, commands) unless commands.empty? }
|
295
295
|
end
|
296
296
|
|
297
|
-
def
|
297
|
+
def display_commands(namespace, list) #:nodoc:
|
298
298
|
list.sort!{ |a,b| a[0] <=> b[0] }
|
299
299
|
|
300
300
|
say shell.set_color(namespace, :blue, true)
|
@@ -303,6 +303,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
303
303
|
print_table(list, :truncate => true)
|
304
304
|
say
|
305
305
|
end
|
306
|
+
alias display_tasks display_commands
|
306
307
|
|
307
308
|
def show_modules #:nodoc:
|
308
309
|
info = []
|
@@ -58,10 +58,10 @@ class Thor
|
|
58
58
|
# ==== Example
|
59
59
|
# say("I know you knew that.")
|
60
60
|
#
|
61
|
-
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)
|
61
|
+
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)\Z/))
|
62
62
|
message = message.to_s
|
63
63
|
|
64
|
-
message = set_color(message, *color) if color
|
64
|
+
message = set_color(message, *color) if color && can_display_colors?
|
65
65
|
|
66
66
|
spaces = " " * padding
|
67
67
|
|
@@ -226,20 +226,20 @@ class Thor
|
|
226
226
|
answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
|
227
227
|
|
228
228
|
case answer
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
229
|
+
when is?(:yes), is?(:force), ""
|
230
|
+
return true
|
231
|
+
when is?(:no), is?(:skip)
|
232
|
+
return false
|
233
|
+
when is?(:always)
|
234
|
+
return @always_force = true
|
235
|
+
when is?(:quit)
|
236
|
+
say 'Aborting...'
|
237
|
+
raise SystemExit
|
238
|
+
when is?(:diff)
|
239
|
+
show_diff(destination, yield) if block_given?
|
240
|
+
say 'Retrying...'
|
241
|
+
else
|
242
|
+
say file_collision_help
|
243
243
|
end
|
244
244
|
end
|
245
245
|
end
|
@@ -275,6 +275,10 @@ class Thor
|
|
275
275
|
|
276
276
|
protected
|
277
277
|
|
278
|
+
def can_display_colors?
|
279
|
+
false
|
280
|
+
end
|
281
|
+
|
278
282
|
def lookup_color(color)
|
279
283
|
return color unless color.is_a?(Symbol)
|
280
284
|
self.class.const_get(color.to_s.upcase)
|