engineyard-serverside 2.0.0 → 2.0.1
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/lib/engineyard-serverside/paths.rb +0 -1
- data/lib/engineyard-serverside/version.rb +1 -1
- data/lib/vendor/thor/{LICENSE → LICENSE.md} +2 -2
- data/lib/vendor/thor/README.md +28 -0
- data/lib/vendor/thor/lib/thor.rb +183 -48
- data/lib/vendor/thor/lib/thor/actions.rb +66 -23
- data/lib/vendor/thor/lib/thor/actions/create_file.rb +5 -3
- data/lib/vendor/thor/lib/thor/actions/create_link.rb +57 -0
- data/lib/vendor/thor/lib/thor/actions/directory.rb +14 -7
- data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +24 -5
- data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +106 -21
- data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +15 -10
- data/lib/vendor/thor/lib/thor/base.rb +144 -43
- data/lib/vendor/thor/lib/thor/core_ext/dir_escape.rb +0 -0
- data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +1 -1
- data/lib/vendor/thor/lib/thor/error.rb +6 -1
- data/lib/vendor/thor/lib/thor/group.rb +41 -27
- data/lib/vendor/thor/lib/thor/invocation.rb +48 -58
- data/lib/vendor/thor/lib/thor/parser/argument.rb +29 -22
- data/lib/vendor/thor/lib/thor/parser/arguments.rb +26 -5
- data/lib/vendor/thor/lib/thor/parser/option.rb +42 -49
- data/lib/vendor/thor/lib/thor/parser/options.rb +39 -30
- data/lib/vendor/thor/lib/thor/rake_compat.rb +13 -8
- data/lib/vendor/thor/lib/thor/runner.rb +27 -20
- data/lib/vendor/thor/lib/thor/shell.rb +10 -5
- data/lib/vendor/thor/lib/thor/shell/basic.rb +228 -78
- data/lib/vendor/thor/lib/thor/shell/color.rb +40 -4
- data/lib/vendor/thor/lib/thor/shell/html.rb +123 -0
- data/lib/vendor/thor/lib/thor/task.rb +83 -53
- data/lib/vendor/thor/lib/thor/util.rb +57 -21
- data/lib/vendor/thor/lib/thor/version.rb +1 -1
- data/lib/vendor/thor/thor.gemspec +21 -115
- metadata +109 -217
- data/lib/vendor/thor/CHANGELOG.rdoc +0 -89
- data/lib/vendor/thor/README.rdoc +0 -297
- data/lib/vendor/thor/Thorfile +0 -69
@@ -50,10 +50,46 @@ class Thor
|
|
50
50
|
# on Highline implementation and it automatically appends CLEAR to the end
|
51
51
|
# of the returned String.
|
52
52
|
#
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
# Pass foreground, background and bold options to this method as
|
54
|
+
# symbols.
|
55
|
+
#
|
56
|
+
# Example:
|
57
|
+
#
|
58
|
+
# set_color "Hi!", :red, :on_white, :bold
|
59
|
+
#
|
60
|
+
# The available colors are:
|
61
|
+
#
|
62
|
+
# :bold
|
63
|
+
# :black
|
64
|
+
# :red
|
65
|
+
# :green
|
66
|
+
# :yellow
|
67
|
+
# :blue
|
68
|
+
# :magenta
|
69
|
+
# :cyan
|
70
|
+
# :white
|
71
|
+
# :on_black
|
72
|
+
# :on_red
|
73
|
+
# :on_green
|
74
|
+
# :on_yellow
|
75
|
+
# :on_blue
|
76
|
+
# :on_magenta
|
77
|
+
# :on_cyan
|
78
|
+
# :on_white
|
79
|
+
def set_color(string, *colors)
|
80
|
+
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
81
|
+
ansi_colors = colors.map { |color| lookup_color(color) }
|
82
|
+
"#{ansi_colors.join}#{string}#{CLEAR}"
|
83
|
+
else
|
84
|
+
# The old API was `set_color(color, bold=boolean)`. We
|
85
|
+
# continue to support the old API because you should never
|
86
|
+
# break old APIs unnecessarily :P
|
87
|
+
foreground, bold = colors
|
88
|
+
foreground = self.class.const_get(foreground.to_s.upcase) if foreground.is_a?(Symbol)
|
89
|
+
|
90
|
+
bold = bold ? BOLD : ""
|
91
|
+
"#{bold}#{foreground}#{string}#{CLEAR}"
|
92
|
+
end
|
57
93
|
end
|
58
94
|
|
59
95
|
protected
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'thor/shell/basic'
|
2
|
+
|
3
|
+
class Thor
|
4
|
+
module Shell
|
5
|
+
# Inherit from Thor::Shell::Basic and add set_color behavior. Check
|
6
|
+
# Thor::Shell::Basic to see all available methods.
|
7
|
+
#
|
8
|
+
class HTML < Basic
|
9
|
+
# The start of an HTML bold sequence.
|
10
|
+
BOLD = "font-weight: bold"
|
11
|
+
|
12
|
+
# Set the terminal's foreground HTML color to black.
|
13
|
+
BLACK = 'color: black'
|
14
|
+
# Set the terminal's foreground HTML color to red.
|
15
|
+
RED = 'color: red'
|
16
|
+
# Set the terminal's foreground HTML color to green.
|
17
|
+
GREEN = 'color: green'
|
18
|
+
# Set the terminal's foreground HTML color to yellow.
|
19
|
+
YELLOW = 'color: yellow'
|
20
|
+
# Set the terminal's foreground HTML color to blue.
|
21
|
+
BLUE = 'color: blue'
|
22
|
+
# Set the terminal's foreground HTML color to magenta.
|
23
|
+
MAGENTA = 'color: magenta'
|
24
|
+
# Set the terminal's foreground HTML color to cyan.
|
25
|
+
CYAN = 'color: cyan'
|
26
|
+
# Set the terminal's foreground HTML color to white.
|
27
|
+
WHITE = 'color: white'
|
28
|
+
|
29
|
+
# Set the terminal's background HTML color to black.
|
30
|
+
ON_BLACK = 'background-color: black'
|
31
|
+
# Set the terminal's background HTML color to red.
|
32
|
+
ON_RED = 'background-color: red'
|
33
|
+
# Set the terminal's background HTML color to green.
|
34
|
+
ON_GREEN = 'background-color: green'
|
35
|
+
# Set the terminal's background HTML color to yellow.
|
36
|
+
ON_YELLOW = 'background-color: yellow'
|
37
|
+
# Set the terminal's background HTML color to blue.
|
38
|
+
ON_BLUE = 'background-color: blue'
|
39
|
+
# Set the terminal's background HTML color to magenta.
|
40
|
+
ON_MAGENTA = 'background-color: magenta'
|
41
|
+
# Set the terminal's background HTML color to cyan.
|
42
|
+
ON_CYAN = 'background-color: cyan'
|
43
|
+
# Set the terminal's background HTML color to white.
|
44
|
+
ON_WHITE = 'background-color: white'
|
45
|
+
|
46
|
+
# Set color by using a string or one of the defined constants. If a third
|
47
|
+
# option is set to true, it also adds bold to the string. This is based
|
48
|
+
# on Highline implementation and it automatically appends CLEAR to the end
|
49
|
+
# of the returned String.
|
50
|
+
#
|
51
|
+
def set_color(string, *colors)
|
52
|
+
if colors.all? { |color| color.is_a?(Symbol) || color.is_a?(String) }
|
53
|
+
html_colors = colors.map { |color| lookup_color(color) }
|
54
|
+
"<span style=\"#{html_colors.join("; ")};\">#{string}</span>"
|
55
|
+
else
|
56
|
+
color, bold = colors
|
57
|
+
html_color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
58
|
+
styles = [html_color]
|
59
|
+
styles << BOLD if bold
|
60
|
+
"<span style=\"#{styles.join("; ")};\">#{string}</span>"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Ask something to the user and receives a response.
|
65
|
+
#
|
66
|
+
# ==== Example
|
67
|
+
# ask("What is your name?")
|
68
|
+
#
|
69
|
+
# TODO: Implement #ask for Thor::Shell::HTML
|
70
|
+
def ask(statement, color=nil)
|
71
|
+
raise NotImplementedError, "Implement #ask for Thor::Shell::HTML"
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
# Overwrite show_diff to show diff with colors if Diff::LCS is
|
77
|
+
# available.
|
78
|
+
#
|
79
|
+
def show_diff(destination, content) #:nodoc:
|
80
|
+
if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
|
81
|
+
actual = File.binread(destination).to_s.split("\n")
|
82
|
+
content = content.to_s.split("\n")
|
83
|
+
|
84
|
+
Diff::LCS.sdiff(actual, content).each do |diff|
|
85
|
+
output_diff_line(diff)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def output_diff_line(diff) #:nodoc:
|
93
|
+
case diff.action
|
94
|
+
when '-'
|
95
|
+
say "- #{diff.old_element.chomp}", :red, true
|
96
|
+
when '+'
|
97
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
98
|
+
when '!'
|
99
|
+
say "- #{diff.old_element.chomp}", :red, true
|
100
|
+
say "+ #{diff.new_element.chomp}", :green, true
|
101
|
+
else
|
102
|
+
say " #{diff.old_element.chomp}", nil, true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Check if Diff::LCS is loaded. If it is, use it to create pretty output
|
107
|
+
# for diff.
|
108
|
+
#
|
109
|
+
def diff_lcs_loaded? #:nodoc:
|
110
|
+
return true if defined?(Diff::LCS)
|
111
|
+
return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
|
112
|
+
|
113
|
+
@diff_lcs_loaded = begin
|
114
|
+
require 'diff/lcs'
|
115
|
+
true
|
116
|
+
rescue LoadError
|
117
|
+
false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -1,24 +1,9 @@
|
|
1
1
|
class Thor
|
2
|
-
class Task < Struct.new(:name, :description, :usage, :options)
|
2
|
+
class Task < Struct.new(:name, :description, :long_description, :usage, :options)
|
3
3
|
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(name, options=nil)
|
8
|
-
super(name.to_s, "A dynamically-generated task", name.to_s, options)
|
9
|
-
end
|
10
|
-
|
11
|
-
def run(instance, args=[])
|
12
|
-
if (instance.methods & [name.to_s, name.to_sym]).empty?
|
13
|
-
super
|
14
|
-
else
|
15
|
-
instance.class.handle_no_task_error(name)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(name, description, usage, options=nil)
|
21
|
-
super(name.to_s, description, usage, options || {})
|
5
|
+
def initialize(name, description, long_description, usage, options=nil)
|
6
|
+
super(name.to_s, description, long_description, usage, options || {})
|
22
7
|
end
|
23
8
|
|
24
9
|
def initialize_copy(other) #:nodoc:
|
@@ -26,30 +11,43 @@ class Thor
|
|
26
11
|
self.options = other.options.dup if other.options
|
27
12
|
end
|
28
13
|
|
14
|
+
def hidden?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
29
18
|
# By default, a task invokes a method in the thor class. You can change this
|
30
19
|
# implementation to create custom tasks.
|
31
20
|
def run(instance, args=[])
|
32
|
-
|
33
|
-
|
21
|
+
arity = nil
|
22
|
+
|
23
|
+
if private_method?(instance)
|
24
|
+
instance.class.handle_no_task_error(name)
|
25
|
+
elsif public_method?(instance)
|
26
|
+
arity = instance.method(name).arity
|
27
|
+
instance.send(name, *args)
|
28
|
+
elsif local_method?(instance, :method_missing)
|
29
|
+
instance.send(:method_missing, name.to_sym, *args)
|
30
|
+
else
|
31
|
+
instance.class.handle_no_task_error(name)
|
32
|
+
end
|
34
33
|
rescue ArgumentError => e
|
35
34
|
handle_argument_error?(instance, e, caller) ?
|
36
|
-
instance.class.handle_argument_error(self, e) : (raise e)
|
35
|
+
instance.class.handle_argument_error(self, e, arity) : (raise e)
|
37
36
|
rescue NoMethodError => e
|
38
37
|
handle_no_method_error?(instance, e, caller) ?
|
39
38
|
instance.class.handle_no_task_error(name) : (raise e)
|
40
39
|
end
|
41
40
|
|
42
|
-
# Returns the formatted usage by injecting given required arguments
|
41
|
+
# Returns the formatted usage by injecting given required arguments
|
43
42
|
# and required options into the given usage.
|
44
|
-
def formatted_usage(klass, namespace=true)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
formatted = if namespace
|
49
|
-
"#{namespace.gsub(/^(default|thor:runner:)/,'')}:"
|
50
|
-
else
|
51
|
-
""
|
43
|
+
def formatted_usage(klass, namespace = true, subcommand = false)
|
44
|
+
if namespace
|
45
|
+
namespace = klass.namespace
|
46
|
+
formatted = "#{namespace.gsub(/^(default)/,'')}:"
|
52
47
|
end
|
48
|
+
formatted = "#{klass.namespace.split(':').last} " if subcommand
|
49
|
+
|
50
|
+
formatted ||= ""
|
53
51
|
|
54
52
|
# Add usage with required arguments
|
55
53
|
formatted << if klass && !klass.arguments.empty?
|
@@ -67,36 +65,68 @@ class Thor
|
|
67
65
|
formatted.strip
|
68
66
|
end
|
69
67
|
|
70
|
-
|
68
|
+
protected
|
71
69
|
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
def not_debugging?(instance)
|
71
|
+
!(instance.class.respond_to?(:debugging) && instance.class.debugging)
|
72
|
+
end
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
def required_options
|
75
|
+
@required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ")
|
76
|
+
end
|
79
77
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
78
|
+
# Given a target, checks if this class name is a public method.
|
79
|
+
def public_method?(instance) #:nodoc:
|
80
|
+
!(instance.public_methods & [name.to_s, name.to_sym]).empty?
|
81
|
+
end
|
85
82
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
83
|
+
def private_method?(instance)
|
84
|
+
!(instance.private_methods & [name.to_s, name.to_sym]).empty?
|
85
|
+
end
|
90
86
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
87
|
+
def local_method?(instance, name)
|
88
|
+
methods = instance.public_methods(false) + instance.private_methods(false) + instance.protected_methods(false)
|
89
|
+
!(methods & [name.to_s, name.to_sym]).empty?
|
90
|
+
end
|
91
|
+
|
92
|
+
def sans_backtrace(backtrace, caller) #:nodoc:
|
93
|
+
saned = backtrace.reject { |frame| frame =~ FILE_REGEXP || (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) }
|
94
|
+
saned -= caller
|
95
|
+
end
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
def handle_argument_error?(instance, error, caller)
|
98
|
+
not_debugging?(instance) && error.message =~ /wrong number of arguments/ && begin
|
99
|
+
saned = sans_backtrace(error.backtrace, caller)
|
100
|
+
# Ruby 1.9 always include the called method in the backtrace
|
101
|
+
saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
|
99
102
|
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def handle_no_method_error?(instance, error, caller)
|
106
|
+
not_debugging?(instance) &&
|
107
|
+
error.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
|
108
|
+
end
|
109
|
+
end
|
100
110
|
|
111
|
+
# A task that is hidden in help messages but still invocable.
|
112
|
+
class HiddenTask < Task
|
113
|
+
def hidden?
|
114
|
+
true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# A dynamic task that handles method missing scenarios.
|
119
|
+
class DynamicTask < Task
|
120
|
+
def initialize(name, options=nil)
|
121
|
+
super(name.to_s, "A dynamically-generated task", name.to_s, name.to_s, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
def run(instance, args=[])
|
125
|
+
if (instance.methods & [name.to_s, name.to_sym]).empty?
|
126
|
+
super
|
127
|
+
else
|
128
|
+
instance.class.handle_no_task_error(name)
|
129
|
+
end
|
130
|
+
end
|
101
131
|
end
|
102
132
|
end
|
@@ -8,11 +8,11 @@ class Thor
|
|
8
8
|
#
|
9
9
|
# 1) Methods to convert thor namespaces to constants and vice-versa.
|
10
10
|
#
|
11
|
-
# Thor::
|
11
|
+
# Thor::Util.namespace_from_thor_class(Foo::Bar::Baz) #=> "foo:bar:baz"
|
12
12
|
#
|
13
13
|
# 2) Loading thor files and sandboxing:
|
14
14
|
#
|
15
|
-
# Thor::
|
15
|
+
# Thor::Util.load_thorfile("~/.thor/foo")
|
16
16
|
#
|
17
17
|
module Util
|
18
18
|
|
@@ -128,38 +128,37 @@ class Thor
|
|
128
128
|
# ==== Parameters
|
129
129
|
# namespace<String>
|
130
130
|
#
|
131
|
-
def self.find_class_and_task_by_namespace(namespace)
|
132
|
-
if namespace.include?(?:)
|
131
|
+
def self.find_class_and_task_by_namespace(namespace, fallback = true)
|
132
|
+
if namespace.include?(?:) # look for a namespaced task
|
133
133
|
pieces = namespace.split(":")
|
134
134
|
task = pieces.pop
|
135
135
|
klass = Thor::Util.find_by_namespace(pieces.join(":"))
|
136
136
|
end
|
137
|
-
|
138
|
-
unless klass
|
137
|
+
unless klass # look for a Thor::Group with the right name
|
139
138
|
klass, task = Thor::Util.find_by_namespace(namespace), nil
|
140
139
|
end
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# The same as namespace_to_thor_class_and_task!, but raises an error if a klass
|
146
|
-
# could not be found.
|
147
|
-
def self.find_class_and_task_by_namespace!(namespace)
|
148
|
-
klass, task = find_class_and_task_by_namespace(namespace)
|
149
|
-
raise Error, "Could not find namespace or task #{namespace.inspect}." unless klass
|
140
|
+
if !klass && fallback # try a task in the default namespace
|
141
|
+
task = namespace
|
142
|
+
klass = Thor::Util.find_by_namespace('')
|
143
|
+
end
|
150
144
|
return klass, task
|
151
145
|
end
|
152
146
|
|
153
147
|
# Receives a path and load the thor file in the path. The file is evaluated
|
154
148
|
# inside the sandbox to avoid namespacing conflicts.
|
155
149
|
#
|
156
|
-
def self.load_thorfile(path, content=nil)
|
150
|
+
def self.load_thorfile(path, content=nil, debug=false)
|
157
151
|
content ||= File.binread(path)
|
158
152
|
|
159
153
|
begin
|
160
154
|
Thor::Sandbox.class_eval(content, path)
|
161
155
|
rescue Exception => e
|
162
|
-
$stderr.puts
|
156
|
+
$stderr.puts("WARNING: unable to load thorfile #{path.inspect}: #{e.message}")
|
157
|
+
if debug
|
158
|
+
$stderr.puts(*e.backtrace)
|
159
|
+
else
|
160
|
+
$stderr.puts(e.backtrace.first)
|
161
|
+
end
|
163
162
|
end
|
164
163
|
end
|
165
164
|
|
@@ -185,7 +184,7 @@ class Thor
|
|
185
184
|
end
|
186
185
|
end
|
187
186
|
|
188
|
-
# Returns the root where thor files are located,
|
187
|
+
# Returns the root where thor files are located, depending on the OS.
|
189
188
|
#
|
190
189
|
def self.thor_root
|
191
190
|
File.join(user_home, ".thor").gsub(/\\/, '/')
|
@@ -199,7 +198,7 @@ class Thor
|
|
199
198
|
# If we don't #gsub the \ character, Dir.glob will fail.
|
200
199
|
#
|
201
200
|
def self.thor_root_glob
|
202
|
-
files = Dir["#{thor_root}/*"]
|
201
|
+
files = Dir["#{escape_globs(thor_root)}/*"]
|
203
202
|
|
204
203
|
files.map! do |file|
|
205
204
|
File.directory?(file) ? File.join(file, "main.thor") : file
|
@@ -209,6 +208,7 @@ class Thor
|
|
209
208
|
# Where to look for Thor files.
|
210
209
|
#
|
211
210
|
def self.globs_for(path)
|
211
|
+
path = escape_globs(path)
|
212
212
|
["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
|
213
213
|
end
|
214
214
|
|
@@ -217,8 +217,27 @@ class Thor
|
|
217
217
|
#
|
218
218
|
def self.ruby_command
|
219
219
|
@ruby_command ||= begin
|
220
|
-
|
221
|
-
ruby
|
220
|
+
ruby_name = RbConfig::CONFIG['ruby_install_name']
|
221
|
+
ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name)
|
222
|
+
ruby << RbConfig::CONFIG['EXEEXT']
|
223
|
+
|
224
|
+
# avoid using different name than ruby (on platforms supporting links)
|
225
|
+
if ruby_name != 'ruby' && File.respond_to?(:readlink)
|
226
|
+
begin
|
227
|
+
alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
|
228
|
+
alternate_ruby << RbConfig::CONFIG['EXEEXT']
|
229
|
+
|
230
|
+
# ruby is a symlink
|
231
|
+
if File.symlink? alternate_ruby
|
232
|
+
linked_ruby = File.readlink alternate_ruby
|
233
|
+
|
234
|
+
# symlink points to 'ruby_install_name'
|
235
|
+
ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
|
236
|
+
end
|
237
|
+
rescue NotImplementedError
|
238
|
+
# just ignore on windows
|
239
|
+
end
|
240
|
+
end
|
222
241
|
|
223
242
|
# escape string in case path to ruby executable contain spaces.
|
224
243
|
ruby.sub!(/.*\s.*/m, '"\&"')
|
@@ -226,5 +245,22 @@ class Thor
|
|
226
245
|
end
|
227
246
|
end
|
228
247
|
|
248
|
+
# Returns a string that has had any glob characters escaped.
|
249
|
+
# The glob characters are `* ? { } [ ]`.
|
250
|
+
#
|
251
|
+
# ==== Examples
|
252
|
+
#
|
253
|
+
# Thor::Util.escape_globs('[apps]') # => '\[apps\]'
|
254
|
+
#
|
255
|
+
# ==== Parameters
|
256
|
+
# String
|
257
|
+
#
|
258
|
+
# ==== Returns
|
259
|
+
# String
|
260
|
+
#
|
261
|
+
def self.escape_globs(path)
|
262
|
+
path.to_s.gsub(/[*?{}\[\]]/, '\\\\\\&')
|
263
|
+
end
|
264
|
+
|
229
265
|
end
|
230
266
|
end
|