thor 0.20.3 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -9
- data/lib/thor/actions/create_file.rb +4 -3
- data/lib/thor/actions/create_link.rb +3 -2
- data/lib/thor/actions/directory.rb +8 -18
- data/lib/thor/actions/empty_directory.rb +1 -1
- data/lib/thor/actions/file_manipulation.rb +22 -24
- data/lib/thor/actions/inject_into_file.rb +34 -13
- data/lib/thor/actions.rb +39 -30
- data/lib/thor/base.rb +196 -49
- data/lib/thor/command.rb +34 -18
- data/lib/thor/core_ext/hash_with_indifferent_access.rb +10 -0
- data/lib/thor/error.rb +14 -22
- data/lib/thor/group.rb +13 -2
- data/lib/thor/invocation.rb +2 -1
- data/lib/thor/line_editor/basic.rb +1 -1
- data/lib/thor/line_editor/readline.rb +6 -6
- data/lib/thor/line_editor.rb +2 -2
- data/lib/thor/nested_context.rb +29 -0
- data/lib/thor/parser/argument.rb +17 -1
- data/lib/thor/parser/arguments.rb +35 -15
- data/lib/thor/parser/option.rb +45 -13
- data/lib/thor/parser/options.rb +79 -11
- data/lib/thor/parser.rb +4 -4
- data/lib/thor/rake_compat.rb +3 -2
- data/lib/thor/runner.rb +43 -32
- data/lib/thor/shell/basic.rb +68 -162
- data/lib/thor/shell/color.rb +9 -43
- data/lib/thor/shell/column_printer.rb +29 -0
- data/lib/thor/shell/html.rb +7 -49
- data/lib/thor/shell/lcs_diff.rb +49 -0
- data/lib/thor/shell/table_printer.rb +118 -0
- data/lib/thor/shell/terminal.rb +42 -0
- data/lib/thor/shell/wrapped_printer.rb +38 -0
- data/lib/thor/shell.rb +5 -5
- data/lib/thor/util.rb +25 -8
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +182 -17
- data/thor.gemspec +22 -10
- metadata +25 -11
- data/CHANGELOG.md +0 -204
- data/lib/thor/core_ext/io_binary_read.rb +0 -12
- data/lib/thor/core_ext/ordered_hash.rb +0 -129
@@ -0,0 +1,29 @@
|
|
1
|
+
class Thor
|
2
|
+
class NestedContext
|
3
|
+
def initialize
|
4
|
+
@depth = 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def enter
|
8
|
+
push
|
9
|
+
|
10
|
+
yield
|
11
|
+
ensure
|
12
|
+
pop
|
13
|
+
end
|
14
|
+
|
15
|
+
def entered?
|
16
|
+
@depth.positive?
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def push
|
22
|
+
@depth += 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop
|
26
|
+
@depth -= 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/thor/parser/argument.rb
CHANGED
@@ -24,6 +24,14 @@ class Thor
|
|
24
24
|
validate! # Trigger specific validations
|
25
25
|
end
|
26
26
|
|
27
|
+
def print_default
|
28
|
+
if @type == :array and @default.is_a?(Array)
|
29
|
+
@default.map(&:dump).join(" ")
|
30
|
+
else
|
31
|
+
@default
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
27
35
|
def usage
|
28
36
|
required? ? banner : "[#{banner}]"
|
29
37
|
end
|
@@ -41,11 +49,19 @@ class Thor
|
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
52
|
+
def enum_to_s
|
53
|
+
if enum.respond_to? :join
|
54
|
+
enum.join(", ")
|
55
|
+
else
|
56
|
+
"#{enum.first}..#{enum.last}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
44
60
|
protected
|
45
61
|
|
46
62
|
def validate!
|
47
63
|
raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
|
48
|
-
raise ArgumentError, "An argument cannot have an enum other than an
|
64
|
+
raise ArgumentError, "An argument cannot have an enum other than an enumerable." if @enum && !@enum.is_a?(Enumerable)
|
49
65
|
end
|
50
66
|
|
51
67
|
def valid_type?(type)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Thor
|
2
|
-
class Arguments #:nodoc:
|
2
|
+
class Arguments #:nodoc:
|
3
3
|
NUMERIC = /[-+]?(\d*\.\d+|\d+)/
|
4
4
|
|
5
5
|
# Receives an array of args and returns two arrays, one with arguments
|
@@ -9,7 +9,7 @@ class Thor
|
|
9
9
|
arguments = []
|
10
10
|
|
11
11
|
args.each do |item|
|
12
|
-
break if item =~ /^-/
|
12
|
+
break if item.is_a?(String) && item =~ /^-/
|
13
13
|
arguments << item
|
14
14
|
end
|
15
15
|
|
@@ -30,7 +30,7 @@ class Thor
|
|
30
30
|
|
31
31
|
arguments.each do |argument|
|
32
32
|
if !argument.default.nil?
|
33
|
-
@assigns[argument.human_name] = argument.default
|
33
|
+
@assigns[argument.human_name] = argument.default.dup
|
34
34
|
elsif argument.required?
|
35
35
|
@non_assigned_required << argument
|
36
36
|
end
|
@@ -82,7 +82,7 @@ class Thor
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def current_is_value?
|
85
|
-
peek && peek.to_s !~
|
85
|
+
peek && peek.to_s !~ /^-{1,2}\S+/
|
86
86
|
end
|
87
87
|
|
88
88
|
# Runs through the argument array getting strings that contains ":" and
|
@@ -117,8 +117,18 @@ class Thor
|
|
117
117
|
#
|
118
118
|
def parse_array(name)
|
119
119
|
return shift if peek.is_a?(Array)
|
120
|
+
|
120
121
|
array = []
|
121
|
-
|
122
|
+
|
123
|
+
while current_is_value?
|
124
|
+
value = shift
|
125
|
+
|
126
|
+
if !value.empty?
|
127
|
+
validate_enum_value!(name, value, "Expected all values of '%s' to be one of %s; got %s")
|
128
|
+
end
|
129
|
+
|
130
|
+
array << value
|
131
|
+
end
|
122
132
|
array
|
123
133
|
end
|
124
134
|
|
@@ -134,11 +144,9 @@ class Thor
|
|
134
144
|
end
|
135
145
|
|
136
146
|
value = $&.index(".") ? shift.to_f : shift.to_i
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|
147
|
+
|
148
|
+
validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
|
149
|
+
|
142
150
|
value
|
143
151
|
end
|
144
152
|
|
@@ -152,15 +160,27 @@ class Thor
|
|
152
160
|
nil
|
153
161
|
else
|
154
162
|
value = shift
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
end
|
159
|
-
end
|
163
|
+
|
164
|
+
validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
|
165
|
+
|
160
166
|
value
|
161
167
|
end
|
162
168
|
end
|
163
169
|
|
170
|
+
# Raises an error if the switch is an enum and the values aren't included on it.
|
171
|
+
#
|
172
|
+
def validate_enum_value!(name, value, message)
|
173
|
+
return unless @switches.is_a?(Hash)
|
174
|
+
|
175
|
+
switch = @switches[name]
|
176
|
+
|
177
|
+
return unless switch
|
178
|
+
|
179
|
+
if switch.enum && !switch.enum.include?(value)
|
180
|
+
raise MalformattedArgumentError, message % [name, switch.enum_to_s, value]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
164
184
|
# Raises an error if @non_assigned_required array is not empty.
|
165
185
|
#
|
166
186
|
def check_requirement!
|
data/lib/thor/parser/option.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
class Thor
|
2
2
|
class Option < Argument #:nodoc:
|
3
|
-
attr_reader :aliases, :group, :lazy_default, :hide
|
3
|
+
attr_reader :aliases, :group, :lazy_default, :hide, :repeatable
|
4
4
|
|
5
5
|
VALID_TYPES = [:boolean, :numeric, :hash, :array, :string]
|
6
6
|
|
7
7
|
def initialize(name, options = {})
|
8
8
|
@check_default_type = options[:check_default_type]
|
9
9
|
options[:required] = false unless options.key?(:required)
|
10
|
+
@repeatable = options.fetch(:repeatable, false)
|
10
11
|
super
|
11
|
-
@lazy_default
|
12
|
-
@group
|
13
|
-
@aliases
|
14
|
-
@hide
|
12
|
+
@lazy_default = options[:lazy_default]
|
13
|
+
@group = options[:group].to_s.capitalize if options[:group]
|
14
|
+
@aliases = normalize_aliases(options[:aliases])
|
15
|
+
@hide = options[:hide]
|
15
16
|
end
|
16
17
|
|
17
18
|
# This parse quick options given as method_options. It makes several
|
@@ -57,7 +58,7 @@ class Thor
|
|
57
58
|
default = nil
|
58
59
|
if VALID_TYPES.include?(value)
|
59
60
|
value
|
60
|
-
elsif required = (value == :required) # rubocop:disable AssignmentInCondition
|
61
|
+
elsif required = (value == :required) # rubocop:disable Lint/AssignmentInCondition
|
61
62
|
:string
|
62
63
|
end
|
63
64
|
when TrueClass, FalseClass
|
@@ -68,7 +69,7 @@ class Thor
|
|
68
69
|
value.class.name.downcase.to_sym
|
69
70
|
end
|
70
71
|
|
71
|
-
new(name.to_s, :
|
72
|
+
new(name.to_s, required: required, type: type, default: default, aliases: aliases)
|
72
73
|
end
|
73
74
|
|
74
75
|
def switch_name
|
@@ -88,14 +89,27 @@ class Thor
|
|
88
89
|
|
89
90
|
sample = "[#{sample}]".dup unless required?
|
90
91
|
|
91
|
-
if boolean?
|
92
|
-
sample << ", [#{dasherize('no-' + human_name)}]
|
92
|
+
if boolean? && name != "force" && !name.match(/\A(no|skip)[\-_]/)
|
93
|
+
sample << ", [#{dasherize('no-' + human_name)}], [#{dasherize('skip-' + human_name)}]"
|
93
94
|
end
|
94
95
|
|
96
|
+
aliases_for_usage.ljust(padding) + sample
|
97
|
+
end
|
98
|
+
|
99
|
+
def aliases_for_usage
|
95
100
|
if aliases.empty?
|
96
|
-
|
101
|
+
""
|
102
|
+
else
|
103
|
+
"#{aliases.join(', ')}, "
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def show_default?
|
108
|
+
case default
|
109
|
+
when TrueClass, FalseClass
|
110
|
+
true
|
97
111
|
else
|
98
|
-
|
112
|
+
super
|
99
113
|
end
|
100
114
|
end
|
101
115
|
|
@@ -111,7 +125,7 @@ class Thor
|
|
111
125
|
|
112
126
|
def validate!
|
113
127
|
raise ArgumentError, "An option cannot be boolean and required." if boolean? && required?
|
114
|
-
validate_default_type!
|
128
|
+
validate_default_type!
|
115
129
|
end
|
116
130
|
|
117
131
|
def validate_default_type!
|
@@ -128,7 +142,19 @@ class Thor
|
|
128
142
|
@default.class.name.downcase.to_sym
|
129
143
|
end
|
130
144
|
|
131
|
-
|
145
|
+
expected_type = (@repeatable && @type != :hash) ? :array : @type
|
146
|
+
|
147
|
+
if default_type != expected_type
|
148
|
+
err = "Expected #{expected_type} default value for '#{switch_name}'; got #{@default.inspect} (#{default_type})"
|
149
|
+
|
150
|
+
if @check_default_type
|
151
|
+
raise ArgumentError, err
|
152
|
+
elsif @check_default_type == nil
|
153
|
+
Thor.deprecation_warning "#{err}.\n" +
|
154
|
+
"This will be rejected in the future unless you explicitly pass the options `check_default_type: false`" +
|
155
|
+
" or call `allow_incompatible_default_type!` in your code"
|
156
|
+
end
|
157
|
+
end
|
132
158
|
end
|
133
159
|
|
134
160
|
def dasherized?
|
@@ -142,5 +168,11 @@ class Thor
|
|
142
168
|
def dasherize(str)
|
143
169
|
(str.length > 1 ? "--" : "-") + str.tr("_", "-")
|
144
170
|
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def normalize_aliases(aliases)
|
175
|
+
Array(aliases).map { |short| short.to_s.sub(/^(?!\-)/, "-") }
|
176
|
+
end
|
145
177
|
end
|
146
178
|
end
|
data/lib/thor/parser/options.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Thor
|
2
|
-
class Options < Arguments #:nodoc:
|
2
|
+
class Options < Arguments #:nodoc:
|
3
3
|
LONG_RE = /^(--\w+(?:-\w+)*)$/
|
4
4
|
SHORT_RE = /^(-[a-z])$/i
|
5
5
|
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
|
@@ -29,8 +29,10 @@ class Thor
|
|
29
29
|
#
|
30
30
|
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
|
31
31
|
# an unknown option or a regular argument.
|
32
|
-
def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
|
32
|
+
def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false, relations = {})
|
33
33
|
@stop_on_unknown = stop_on_unknown
|
34
|
+
@exclusives = (relations[:exclusive_option_names] || []).select{|array| !array.empty?}
|
35
|
+
@at_least_ones = (relations[:at_least_one_option_names] || []).select{|array| !array.empty?}
|
34
36
|
@disable_required_check = disable_required_check
|
35
37
|
options = hash_options.values
|
36
38
|
super(options)
|
@@ -45,12 +47,12 @@ class Thor
|
|
45
47
|
@switches = {}
|
46
48
|
@extra = []
|
47
49
|
@stopped_parsing_after_extra_index = nil
|
50
|
+
@is_treated_as_value = false
|
48
51
|
|
49
52
|
options.each do |option|
|
50
53
|
@switches[option.switch_name] = option
|
51
54
|
|
52
|
-
option.aliases.each do |
|
53
|
-
name = short.to_s.sub(/^(?!\-)/, "-")
|
55
|
+
option.aliases.each do |name|
|
54
56
|
@shorts[name] ||= option.switch_name
|
55
57
|
end
|
56
58
|
end
|
@@ -74,8 +76,19 @@ class Thor
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
def
|
79
|
+
def shift
|
80
|
+
@is_treated_as_value = false
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
84
|
+
def unshift(arg, is_value: false)
|
85
|
+
@is_treated_as_value = is_value
|
86
|
+
super(arg)
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse(args) # rubocop:disable Metrics/MethodLength
|
78
90
|
@pile = args.dup
|
91
|
+
@is_treated_as_value = false
|
79
92
|
@parsing_options = true
|
80
93
|
|
81
94
|
while peek
|
@@ -88,7 +101,10 @@ class Thor
|
|
88
101
|
when SHORT_SQ_RE
|
89
102
|
unshift($1.split("").map { |f| "-#{f}" })
|
90
103
|
next
|
91
|
-
when EQ_RE
|
104
|
+
when EQ_RE
|
105
|
+
unshift($2, is_value: true)
|
106
|
+
switch = $1
|
107
|
+
when SHORT_NUM
|
92
108
|
unshift($2)
|
93
109
|
switch = $1
|
94
110
|
when LONG_RE, SHORT_RE
|
@@ -97,7 +113,8 @@ class Thor
|
|
97
113
|
|
98
114
|
switch = normalize_switch(switch)
|
99
115
|
option = switch_option(switch)
|
100
|
-
|
116
|
+
result = parse_peek(switch, option)
|
117
|
+
assign_result!(option, result)
|
101
118
|
elsif @stop_on_unknown
|
102
119
|
@parsing_options = false
|
103
120
|
@extra << shifted
|
@@ -116,12 +133,38 @@ class Thor
|
|
116
133
|
end
|
117
134
|
|
118
135
|
check_requirement! unless @disable_required_check
|
136
|
+
check_exclusive!
|
137
|
+
check_at_least_one!
|
119
138
|
|
120
139
|
assigns = Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
|
121
140
|
assigns.freeze
|
122
141
|
assigns
|
123
142
|
end
|
124
143
|
|
144
|
+
def check_exclusive!
|
145
|
+
opts = @assigns.keys
|
146
|
+
# When option A and B are exclusive, if A and B are given at the same time,
|
147
|
+
# the diffrence of argument array size will decrease.
|
148
|
+
found = @exclusives.find{ |ex| (ex - opts).size < ex.size - 1 }
|
149
|
+
if found
|
150
|
+
names = names_to_switch_names(found & opts).map{|n| "'#{n}'"}
|
151
|
+
class_name = self.class.name.split("::").last.downcase
|
152
|
+
fail ExclusiveArgumentError, "Found exclusive #{class_name} #{names.join(", ")}"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def check_at_least_one!
|
157
|
+
opts = @assigns.keys
|
158
|
+
# When at least one is required of the options A and B,
|
159
|
+
# if the both options were not given, none? would be true.
|
160
|
+
found = @at_least_ones.find{ |one_reqs| one_reqs.none?{ |o| opts.include? o} }
|
161
|
+
if found
|
162
|
+
names = names_to_switch_names(found).map{|n| "'#{n}'"}
|
163
|
+
class_name = self.class.name.split("::").last.downcase
|
164
|
+
fail AtLeastOneRequiredArgumentError, "Not found at least one of required #{class_name} #{names.join(", ")}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
125
168
|
def check_unknown!
|
126
169
|
to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra
|
127
170
|
|
@@ -132,11 +175,33 @@ class Thor
|
|
132
175
|
|
133
176
|
protected
|
134
177
|
|
178
|
+
# Option names changes to swith name or human name
|
179
|
+
def names_to_switch_names(names = [])
|
180
|
+
@switches.map do |_, o|
|
181
|
+
if names.include? o.name
|
182
|
+
o.respond_to?(:switch_name) ? o.switch_name : o.human_name
|
183
|
+
else
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
end.compact
|
187
|
+
end
|
188
|
+
|
189
|
+
def assign_result!(option, result)
|
190
|
+
if option.repeatable && option.type == :hash
|
191
|
+
(@assigns[option.human_name] ||= {}).merge!(result)
|
192
|
+
elsif option.repeatable
|
193
|
+
(@assigns[option.human_name] ||= []) << result
|
194
|
+
else
|
195
|
+
@assigns[option.human_name] = result
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
135
199
|
# Check if the current value in peek is a registered switch.
|
136
200
|
#
|
137
201
|
# Two booleans are returned. The first is true if the current value
|
138
202
|
# starts with a hyphen; the second is true if it is a registered switch.
|
139
203
|
def current_is_switch?
|
204
|
+
return [false, false] if @is_treated_as_value
|
140
205
|
case peek
|
141
206
|
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM
|
142
207
|
[true, switch?($1)]
|
@@ -148,6 +213,7 @@ class Thor
|
|
148
213
|
end
|
149
214
|
|
150
215
|
def current_is_switch_formatted?
|
216
|
+
return false if @is_treated_as_value
|
151
217
|
case peek
|
152
218
|
when LONG_RE, SHORT_RE, EQ_RE, SHORT_NUM, SHORT_SQ_RE
|
153
219
|
true
|
@@ -157,15 +223,16 @@ class Thor
|
|
157
223
|
end
|
158
224
|
|
159
225
|
def current_is_value?
|
226
|
+
return true if @is_treated_as_value
|
160
227
|
peek && (!parsing_options? || super)
|
161
228
|
end
|
162
229
|
|
163
230
|
def switch?(arg)
|
164
|
-
switch_option(normalize_switch(arg))
|
231
|
+
!switch_option(normalize_switch(arg)).nil?
|
165
232
|
end
|
166
233
|
|
167
234
|
def switch_option(arg)
|
168
|
-
if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
|
235
|
+
if match = no_or_skip?(arg) # rubocop:disable Lint/AssignmentInCondition
|
169
236
|
@switches[arg] || @switches["--#{match}"]
|
170
237
|
else
|
171
238
|
@switches[arg]
|
@@ -183,7 +250,8 @@ class Thor
|
|
183
250
|
@parsing_options
|
184
251
|
end
|
185
252
|
|
186
|
-
# Parse boolean values which can be given as --foo=true
|
253
|
+
# Parse boolean values which can be given as --foo=true or --foo for true values, or
|
254
|
+
# --foo=false, --no-foo or --skip-foo for false values.
|
187
255
|
#
|
188
256
|
def parse_boolean(switch)
|
189
257
|
if current_is_value?
|
@@ -194,7 +262,7 @@ class Thor
|
|
194
262
|
shift
|
195
263
|
false
|
196
264
|
else
|
197
|
-
!no_or_skip?(switch)
|
265
|
+
@switches.key?(switch) || !no_or_skip?(switch)
|
198
266
|
end
|
199
267
|
else
|
200
268
|
@switches.key?(switch) || !no_or_skip?(switch)
|
data/lib/thor/parser.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative "parser/argument"
|
2
|
+
require_relative "parser/arguments"
|
3
|
+
require_relative "parser/option"
|
4
|
+
require_relative "parser/options"
|
data/lib/thor/rake_compat.rb
CHANGED
@@ -25,6 +25,7 @@ class Thor
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.included(base)
|
28
|
+
super(base)
|
28
29
|
# Hack. Make rakefile point to invoker, so rdoc task is generated properly.
|
29
30
|
rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
|
30
31
|
Rake.application.instance_variable_set(:@rakefile, rakefile)
|
@@ -40,7 +41,7 @@ instance_eval do
|
|
40
41
|
def task(*)
|
41
42
|
task = super
|
42
43
|
|
43
|
-
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
|
44
|
+
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
|
44
45
|
non_namespaced_name = task.name.split(":").last
|
45
46
|
|
46
47
|
description = non_namespaced_name
|
@@ -58,7 +59,7 @@ instance_eval do
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def namespace(name)
|
61
|
-
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
|
62
|
+
if klass = Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
|
62
63
|
const_name = Thor::Util.camel_case(name.to_s).to_sym
|
63
64
|
klass.const_set(const_name, Class.new(Thor))
|
64
65
|
new_klass = klass.const_get(const_name)
|
data/lib/thor/runner.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "thor/core_ext/io_binary_read"
|
1
|
+
require_relative "../thor"
|
2
|
+
require_relative "group"
|
4
3
|
|
5
4
|
require "yaml"
|
6
|
-
require "digest/
|
5
|
+
require "digest/sha2"
|
7
6
|
require "pathname"
|
8
7
|
|
9
|
-
class Thor::Runner < Thor #:nodoc:
|
8
|
+
class Thor::Runner < Thor #:nodoc:
|
10
9
|
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
|
11
10
|
|
12
11
|
def self.banner(command, all = false, subcommand = false)
|
@@ -24,7 +23,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
24
23
|
initialize_thorfiles(meth)
|
25
24
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
26
25
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
27
|
-
klass.start(["-h", command].compact, :
|
26
|
+
klass.start(["-h", command].compact, shell: shell)
|
28
27
|
else
|
29
28
|
super
|
30
29
|
end
|
@@ -39,30 +38,42 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
39
38
|
klass, command = Thor::Util.find_class_and_command_by_namespace(meth)
|
40
39
|
self.class.handle_no_command_error(command, false) if klass.nil?
|
41
40
|
args.unshift(command) if command
|
42
|
-
klass.start(args, :
|
41
|
+
klass.start(args, shell: shell)
|
43
42
|
end
|
44
43
|
|
45
44
|
desc "install NAME", "Install an optionally named Thor file into your system commands"
|
46
|
-
method_options :
|
47
|
-
def install(name) # rubocop:disable MethodLength
|
45
|
+
method_options as: :string, relative: :boolean, force: :boolean
|
46
|
+
def install(name) # rubocop:disable Metrics/MethodLength
|
48
47
|
initialize_thorfiles
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
49
|
+
is_uri = name =~ %r{^https?\://}
|
50
|
+
|
51
|
+
if is_uri
|
52
|
+
base = name
|
53
|
+
package = :file
|
54
|
+
require "open-uri"
|
55
|
+
begin
|
56
|
+
contents = URI.open(name, &:read)
|
57
|
+
rescue OpenURI::HTTPError
|
58
|
+
raise Error, "Error opening URI '#{name}'"
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# If a directory name is provided as the argument, look for a 'main.thor'
|
62
|
+
# command in said directory.
|
63
|
+
begin
|
64
|
+
if File.directory?(File.expand_path(name))
|
65
|
+
base = File.join(name, "main.thor")
|
66
|
+
package = :directory
|
67
|
+
contents = File.open(base, &:read)
|
68
|
+
else
|
69
|
+
base = name
|
70
|
+
package = :file
|
71
|
+
require "open-uri"
|
72
|
+
contents = URI.open(name, &:read)
|
73
|
+
end
|
74
|
+
rescue Errno::ENOENT
|
75
|
+
raise Error, "Error opening file '#{name}'"
|
61
76
|
end
|
62
|
-
rescue OpenURI::HTTPError
|
63
|
-
raise Error, "Error opening URI '#{name}'"
|
64
|
-
rescue Errno::ENOENT
|
65
|
-
raise Error, "Error opening file '#{name}'"
|
66
77
|
end
|
67
78
|
|
68
79
|
say "Your Thorfile contains:"
|
@@ -83,16 +94,16 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
83
94
|
as = basename if as.empty?
|
84
95
|
end
|
85
96
|
|
86
|
-
location = if options[:relative] ||
|
97
|
+
location = if options[:relative] || is_uri
|
87
98
|
name
|
88
99
|
else
|
89
100
|
File.expand_path(name)
|
90
101
|
end
|
91
102
|
|
92
103
|
thor_yaml[as] = {
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
104
|
+
filename: Digest::SHA256.hexdigest(name + as),
|
105
|
+
location: location,
|
106
|
+
namespaces: Thor::Util.namespaces_in_content(contents, base)
|
96
107
|
}
|
97
108
|
|
98
109
|
save_yaml(thor_yaml)
|
@@ -111,7 +122,7 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
111
122
|
|
112
123
|
desc "version", "Show Thor version"
|
113
124
|
def version
|
114
|
-
|
125
|
+
require_relative "version"
|
115
126
|
say "Thor #{Thor::VERSION}"
|
116
127
|
end
|
117
128
|
|
@@ -153,14 +164,14 @@ class Thor::Runner < Thor #:nodoc: # rubocop:disable ClassLength
|
|
153
164
|
end
|
154
165
|
|
155
166
|
desc "installed", "List the installed Thor modules and commands"
|
156
|
-
method_options :
|
167
|
+
method_options internal: :boolean
|
157
168
|
def installed
|
158
169
|
initialize_thorfiles(nil, true)
|
159
170
|
display_klasses(true, options["internal"])
|
160
171
|
end
|
161
172
|
|
162
173
|
desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
|
163
|
-
method_options :
|
174
|
+
method_options substring: :boolean, group: :string, all: :boolean, debug: :boolean
|
164
175
|
def list(search = "")
|
165
176
|
initialize_thorfiles
|
166
177
|
|
@@ -302,7 +313,7 @@ private
|
|
302
313
|
say shell.set_color(namespace, :blue, true)
|
303
314
|
say "-" * namespace.size
|
304
315
|
|
305
|
-
print_table(list, :
|
316
|
+
print_table(list, truncate: true)
|
306
317
|
say
|
307
318
|
end
|
308
319
|
alias_method :display_tasks, :display_commands
|