ori 0.1.0
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/MIT-LICENSE +20 -0
- data/README.html +158 -0
- data/README.md +160 -0
- data/Rakefile +60 -0
- data/VERSION.yml +5 -0
- data/lib/misc/method_aliases.rb +11 -0
- data/lib/ori.rb +47 -0
- data/lib/ori/auto_config.rb +78 -0
- data/lib/ori/colorize.rb +62 -0
- data/lib/ori/config.rb +27 -0
- data/lib/ori/extensions.rb +4 -0
- data/lib/ori/extensions/object/ri.rb +88 -0
- data/lib/ori/internals.rb +411 -0
- data/lib/ori/library.rb +59 -0
- data/lib/ori/list_method.rb +247 -0
- data/lib/ori/request.rb +118 -0
- data/lib/ori/tools.rb +142 -0
- data/ori.gemspec +82 -0
- data/samples/NOTES +3 -0
- data/samples/basic_extension.rb +27 -0
- data/samples/basic_inheritance.rb +99 -0
- data/samples/self_singletons.rb +36 -0
- data/samples/singleton_class_includes_module.rb +33 -0
- data/spec/auto_config_spec.rb +33 -0
- data/spec/colorize_spec.rb +26 -0
- data/spec/inspector_spec.rb +75 -0
- data/spec/internals_spec.rb +219 -0
- data/spec/list_method_spec.rb +118 -0
- data/spec/request_spec.rb +72 -0
- data/spec/site/NOTES +3 -0
- data/spec/site/library_spec.rb +33 -0
- data/spec/site/spec_helper.rb +1 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/tools_spec.rb +109 -0
- metadata +107 -0
data/lib/ori/library.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module ORI
|
4
|
+
# ri lookup library.
|
5
|
+
class Library #:nodoc:
|
6
|
+
# Mask of ri command to fetch content. Example:
|
7
|
+
#
|
8
|
+
# ri -T -f ansi %s
|
9
|
+
attr_accessor :frontend
|
10
|
+
|
11
|
+
# Shell escape mode. <tt>:unix</tt> or <tt>:windows</tt>.
|
12
|
+
attr_accessor :shell_escape
|
13
|
+
|
14
|
+
def initialize(attrs = {})
|
15
|
+
@cache = {}
|
16
|
+
attrs.each {|k, v| send("#{k}=", v)}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Lookup an article.
|
20
|
+
#
|
21
|
+
# lookup("Kernel#puts") # => content or nil.
|
22
|
+
def lookup(topic)
|
23
|
+
if @cache.has_key? topic
|
24
|
+
@cache[topic]
|
25
|
+
else
|
26
|
+
require_frontend
|
27
|
+
|
28
|
+
etopic = case @shell_escape
|
29
|
+
when :unix
|
30
|
+
Tools.shell_escape(topic)
|
31
|
+
when :windows
|
32
|
+
Tools.win_shell_escape(topic)
|
33
|
+
else
|
34
|
+
topic
|
35
|
+
end
|
36
|
+
|
37
|
+
cmd = @frontend % etopic
|
38
|
+
##p "cmd", cmd
|
39
|
+
content = `#{cmd} 2>&1`
|
40
|
+
##p "content", content
|
41
|
+
|
42
|
+
# NOTES:
|
43
|
+
# * Windows' ri always returns 0 even if article is not found. Work around it with a hack.
|
44
|
+
# * Unix's ri sometimes returns 0 when it offers suggestions. Try `ri Object#is_ax?`.
|
45
|
+
@cache[topic] = if $?.exitstatus != 0 or content.lines.count < 4
|
46
|
+
nil
|
47
|
+
else
|
48
|
+
content
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def require_frontend
|
56
|
+
raise "`frontend` is not set" if not @frontend
|
57
|
+
end
|
58
|
+
end # Library
|
59
|
+
end # ORI
|
@@ -0,0 +1,247 @@
|
|
1
|
+
module ORI
|
2
|
+
# Our method representation suitable for listing.
|
3
|
+
class ListMethod #:nodoc:
|
4
|
+
OWN_MARKER = ["~", " "]
|
5
|
+
|
6
|
+
# Object. Can be anything, including <em>nil</em>.
|
7
|
+
attr_reader :obj
|
8
|
+
|
9
|
+
attr_reader :method_name
|
10
|
+
attr_reader :inspector
|
11
|
+
|
12
|
+
def initialize(attrs = {})
|
13
|
+
attrs.each {|k, v| send("#{k}=", v)}
|
14
|
+
clear_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
#--------------------------------------- Accessors and pseudo accessors
|
18
|
+
|
19
|
+
# Return method access substring: "::" or "#".
|
20
|
+
def access
|
21
|
+
# NOTE: It is *WRONG* to rely on Ruby's `inspect` to handle things because
|
22
|
+
# it doesn't work for cases when singleton methods are included from modules.
|
23
|
+
@cache[:access] ||= (module? and not inspector.match /instance/) ? "::" : "#"
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspector=(s)
|
27
|
+
@inspector = s.to_s
|
28
|
+
clear_cache
|
29
|
+
end
|
30
|
+
|
31
|
+
def instance?
|
32
|
+
access == "#"
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_name=(s)
|
36
|
+
@method_name = s.to_s
|
37
|
+
clear_cache
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fetch method object.
|
41
|
+
def method_object
|
42
|
+
require_valid
|
43
|
+
|
44
|
+
@cache[:method_object] ||= if @inspector.match /instance/
|
45
|
+
@obj._ori_instance_method(@method_name)
|
46
|
+
else
|
47
|
+
@obj._ori_method(@method_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def module?
|
52
|
+
@cache[:is_module] ||= begin
|
53
|
+
require_obj
|
54
|
+
@obj.is_a? Module
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def obj=(obj)
|
59
|
+
@obj = obj
|
60
|
+
@obj_present = true
|
61
|
+
clear_cache
|
62
|
+
end
|
63
|
+
|
64
|
+
def obj_module
|
65
|
+
@cache[:obj_module] ||= obj.is_a?(Module) ? obj : obj.class
|
66
|
+
end
|
67
|
+
|
68
|
+
def obj_module_name
|
69
|
+
@cache[:obj_module_name] ||= Tools.get_module_name(obj_module)
|
70
|
+
end
|
71
|
+
|
72
|
+
def owner
|
73
|
+
@cache[:owner] ||= method_object.owner
|
74
|
+
end
|
75
|
+
|
76
|
+
# Get, if possible, <tt>obj</tt> singleton class.
|
77
|
+
# Some objects, e.g. <tt>Fixnum</tt> instances, don't have a singleton class.
|
78
|
+
def obj_singleton_class
|
79
|
+
@cache[:obj_singleton] ||= begin
|
80
|
+
class << obj #:nodoc:
|
81
|
+
self
|
82
|
+
end
|
83
|
+
rescue
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return <tt>true</tt> if method is natively owned by <tt>obj</tt> class.
|
89
|
+
def own?
|
90
|
+
@cache[:is_own] ||= begin
|
91
|
+
require_valid
|
92
|
+
owner == obj_module || owner == obj_singleton_class
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def owner_name
|
97
|
+
@cache[:owner_name] ||= Tools.get_module_name(owner)
|
98
|
+
end
|
99
|
+
|
100
|
+
def private?
|
101
|
+
visibility == :private
|
102
|
+
end
|
103
|
+
|
104
|
+
def protected?
|
105
|
+
visibility == :protected
|
106
|
+
end
|
107
|
+
|
108
|
+
def public?
|
109
|
+
visibility == :public
|
110
|
+
end
|
111
|
+
|
112
|
+
def singleton?
|
113
|
+
access == "::"
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return visibility: <tt>:public</tt>, <tt>:protected</tt>, <tt>:private</tt>.
|
117
|
+
def visibility
|
118
|
+
@cache[:visibility] ||= begin
|
119
|
+
require_valid
|
120
|
+
|
121
|
+
if @inspector.match /private/
|
122
|
+
:private
|
123
|
+
elsif @inspector.match /protected/
|
124
|
+
:protected
|
125
|
+
else
|
126
|
+
:public
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#---------------------------------------
|
132
|
+
|
133
|
+
# Format self into a string.
|
134
|
+
# Options:
|
135
|
+
#
|
136
|
+
# :color => true|false
|
137
|
+
def format(options = {})
|
138
|
+
options = options.dup
|
139
|
+
o = {}
|
140
|
+
o[k = :color] = (v = options.delete(k)).nil?? true : v
|
141
|
+
raise ArgumentError, "Unknown option(s): #{options.inspect}" if not options.empty?
|
142
|
+
|
143
|
+
require_valid
|
144
|
+
|
145
|
+
Colorize.colorize *[
|
146
|
+
(own?? [[:list_method, :own_marker], OWN_MARKER[0]] : [[:list_method, :not_own_marker], OWN_MARKER[1]]),
|
147
|
+
[[:list_method, :obj_module_name], obj_module_name],
|
148
|
+
([[:list_method, :owner_name], "(#{owner_name})"] if not own?),
|
149
|
+
[[:list_method, :access], access],
|
150
|
+
[[:list_method, :name], method_name],
|
151
|
+
([[:list_method, :visibility], " [#{visibility}]"] if not public?),
|
152
|
+
[[:reset]],
|
153
|
+
].compact.flatten(1).reject {|v| v.is_a? Array and not o[:color]}
|
154
|
+
end
|
155
|
+
|
156
|
+
# Match entire formatted record against RE.
|
157
|
+
def fullmatch(re)
|
158
|
+
format(:color => false).match(re)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Match method name against RE.
|
162
|
+
def match(re)
|
163
|
+
@method_name.match(re)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Quick format. No options, no hashes, no checks.
|
167
|
+
def qformat
|
168
|
+
#"#{owner_name}#{access}#{@method_name} [#{visibility}]" # Before multi-obj support.
|
169
|
+
"#{obj_module_name}#{access}#{@method_name} [#{visibility}]"
|
170
|
+
end
|
171
|
+
|
172
|
+
def ri_topics
|
173
|
+
@cache[:ri_topics] ||= begin
|
174
|
+
require_valid
|
175
|
+
|
176
|
+
# Build "hierarchy methods". Single record is:
|
177
|
+
#
|
178
|
+
# ["Kernel", "#", "dup"]
|
179
|
+
hmethods = []
|
180
|
+
|
181
|
+
# Always stuff self in front of the line regardless of if we have method or not.
|
182
|
+
hmethods << [obj_module_name, access, method_name]
|
183
|
+
|
184
|
+
ancestors = []
|
185
|
+
ancestors += obj_module.ancestors
|
186
|
+
ancestors += obj_singleton_class.ancestors if obj_singleton_class # E.g. when module extends class.
|
187
|
+
|
188
|
+
ancestors.each do |mod|
|
189
|
+
mav = Tools.get_methods(mod, :inspector_arg => false, :to_mav => true)
|
190
|
+
##p "mav", mav
|
191
|
+
found = mav.select {|method_name,| method_name == self.method_name}
|
192
|
+
##p "found", found
|
193
|
+
found.each do |method_name, access|
|
194
|
+
hmethods << [Tools.get_module_name(mod), access, method_name]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Misdoc hack -- stuff Object#meth lookup if Kernel#meth is present. For methods like Kernel#is_a?.
|
199
|
+
if (found = hmethods.find {|mod, access| [mod, access] == ["Kernel", "#"]}) and not hmethods.find {|mod,| mod == "Object"}
|
200
|
+
hmethods << ["Object", "#", found.last]
|
201
|
+
end
|
202
|
+
|
203
|
+
hmethods.uniq
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def valid?
|
208
|
+
[
|
209
|
+
@obj_present,
|
210
|
+
@method_name,
|
211
|
+
@inspector,
|
212
|
+
].all?
|
213
|
+
end
|
214
|
+
|
215
|
+
#---------------------------------------
|
216
|
+
|
217
|
+
# Support <tt>Enumerable#sort</tt>.
|
218
|
+
def <=>(other)
|
219
|
+
[@method_name, access, obj_module_name] <=> [other.method_name, other.access, obj_module_name]
|
220
|
+
end
|
221
|
+
|
222
|
+
# Support <tt>Array#uniq</tt>.
|
223
|
+
def hash
|
224
|
+
@cache[:hash] ||= qformat.hash
|
225
|
+
end
|
226
|
+
|
227
|
+
# Support <tt>Array#uniq</tt>.
|
228
|
+
def eql?(other)
|
229
|
+
hash == other.hash
|
230
|
+
end
|
231
|
+
|
232
|
+
#---------------------------------------
|
233
|
+
private
|
234
|
+
|
235
|
+
def clear_cache
|
236
|
+
@cache = {}
|
237
|
+
end
|
238
|
+
|
239
|
+
def require_obj
|
240
|
+
raise "`obj` is not set" if not @obj_present
|
241
|
+
end
|
242
|
+
|
243
|
+
def require_valid
|
244
|
+
raise "Object is not valid" if not valid?
|
245
|
+
end
|
246
|
+
end # ListMethod
|
247
|
+
end
|
data/lib/ori/request.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
module ORI
|
2
|
+
# <tt>something.ri [something]</tt> request logic.
|
3
|
+
#
|
4
|
+
# NOTE: This class DOES NOT validate particular options to be passed to <tt>get_list_methods</tt>.
|
5
|
+
class Request #:nodoc:
|
6
|
+
class ParseError < Exception #:nodoc:
|
7
|
+
end
|
8
|
+
|
9
|
+
# Options for <tt>Internals::get_list_methods</tt>.
|
10
|
+
attr_accessor :glm_options
|
11
|
+
|
12
|
+
# <tt>:self</tt>, <tt>:list</tt>, <tt>:method</tt> or <tt>:error</tt>.
|
13
|
+
attr_accessor :kind
|
14
|
+
|
15
|
+
# Message. E.g. for <tt>:error</tt> kind this is the message for the user.
|
16
|
+
attr_accessor :message
|
17
|
+
|
18
|
+
def initialize(attrs = {})
|
19
|
+
@glm_options = {}
|
20
|
+
attrs.each {|k, v| send("#{k}=", v)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def error?
|
24
|
+
@kind == :error
|
25
|
+
end
|
26
|
+
|
27
|
+
def list?
|
28
|
+
@kind == :list
|
29
|
+
end
|
30
|
+
|
31
|
+
def method?
|
32
|
+
@kind == :method
|
33
|
+
end
|
34
|
+
|
35
|
+
def self?
|
36
|
+
@kind == :self
|
37
|
+
end
|
38
|
+
|
39
|
+
#---------------------------------------
|
40
|
+
|
41
|
+
# Parse arguments into a new <tt>Request</tt> object.
|
42
|
+
#
|
43
|
+
# parse()
|
44
|
+
# parse(//)
|
45
|
+
# parse(//, :all)
|
46
|
+
# parse(//, :all => true, :access => "#")
|
47
|
+
# parse(:puts)
|
48
|
+
# parse("#puts")
|
49
|
+
# parse("::puts")
|
50
|
+
def self.parse(*args)
|
51
|
+
r = new(:glm_options => {:objs => []})
|
52
|
+
|
53
|
+
begin
|
54
|
+
if args.size < 1
|
55
|
+
# Fixnum.ri
|
56
|
+
# 5.ri
|
57
|
+
r.kind = :self
|
58
|
+
else
|
59
|
+
# At least 1 argument is present.
|
60
|
+
arg1 = args.shift
|
61
|
+
|
62
|
+
case arg1
|
63
|
+
when Symbol, String
|
64
|
+
# ri :meth
|
65
|
+
# ri "#meth"
|
66
|
+
# ri "::meth"
|
67
|
+
r.kind = :method
|
68
|
+
if args.size > 0
|
69
|
+
raise ParseError, "Unexpected arguments after #{arg1.inspect}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# This is important -- look through all available methods.
|
73
|
+
r.glm_options[:all] = true
|
74
|
+
|
75
|
+
method_name = if arg1.to_s.match /\A(::|#)(.+)\z/
|
76
|
+
r.glm_options[:access] = $1
|
77
|
+
$2
|
78
|
+
else
|
79
|
+
arg1.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
r.glm_options[:re] = /\A#{Regexp.escape(method_name)}\z/
|
83
|
+
|
84
|
+
when Regexp
|
85
|
+
# ri //
|
86
|
+
# ri //, :all
|
87
|
+
# ri /kk/, :option => value etc.
|
88
|
+
r.kind = :list
|
89
|
+
r.glm_options[:re] = arg1
|
90
|
+
args.each do |arg|
|
91
|
+
if arg.is_a? Hash
|
92
|
+
if arg.has_key?(k = :join)
|
93
|
+
r.glm_options[:objs] += [arg.delete(k)].flatten(1)
|
94
|
+
end
|
95
|
+
|
96
|
+
r.glm_options.merge! arg
|
97
|
+
elsif [String, Symbol].include? arg.class
|
98
|
+
r.glm_options.merge! arg.to_sym => true
|
99
|
+
else
|
100
|
+
raise ParseError, "Unsupported argument #{arg.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Don't bother making `objs` unique, we're just the request parser.
|
105
|
+
|
106
|
+
else
|
107
|
+
raise ParseError, "Unsupported argument #{arg1.inspect}"
|
108
|
+
end # case arg1
|
109
|
+
end # if args.size < 1
|
110
|
+
rescue ParseError => e
|
111
|
+
r.kind = :error
|
112
|
+
r.message = e.message
|
113
|
+
end
|
114
|
+
|
115
|
+
r
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/ori/tools.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
module ORI
|
2
|
+
# Generic tools.
|
3
|
+
module Tools #:nodoc:
|
4
|
+
ANSI_ATTRS = {
|
5
|
+
:reset => 0,
|
6
|
+
:bold => 1,
|
7
|
+
:underscore => 4,
|
8
|
+
:underline => 4,
|
9
|
+
:blink => 5,
|
10
|
+
:reverse => 7,
|
11
|
+
:concealed => 8,
|
12
|
+
:black => 30,
|
13
|
+
:red => 31,
|
14
|
+
:green => 32,
|
15
|
+
:yellow => 33,
|
16
|
+
:blue => 34,
|
17
|
+
:magenta => 35,
|
18
|
+
:cyan => 36,
|
19
|
+
:white => 37,
|
20
|
+
:on_black => 40,
|
21
|
+
:on_red => 41,
|
22
|
+
:on_green => 42,
|
23
|
+
:on_yellow => 43,
|
24
|
+
:on_blue => 44,
|
25
|
+
:on_magenta => 45,
|
26
|
+
:on_cyan => 46,
|
27
|
+
:on_white => 47,
|
28
|
+
}
|
29
|
+
|
30
|
+
# Default inspectors for <tt>get_methods</tt>.
|
31
|
+
GET_METHODS_INSPECTORS = [
|
32
|
+
:private_instance_methods,
|
33
|
+
:protected_instance_methods,
|
34
|
+
:public_instance_methods,
|
35
|
+
:private_methods,
|
36
|
+
:protected_methods,
|
37
|
+
:public_methods,
|
38
|
+
]
|
39
|
+
|
40
|
+
# Build an ANSI sequence.
|
41
|
+
#
|
42
|
+
# ansi() # => ""
|
43
|
+
# ansi(:red) # => "\e[31m"
|
44
|
+
# ansi(:red, :bold) # => "\e[31;1m"
|
45
|
+
# puts "Hello, #{ansi(:bold)}user#{ansi(:reset)}"
|
46
|
+
def self.ansi(*attrs)
|
47
|
+
codes = attrs.map {|attr| ANSI_ATTRS[attr.to_sym] or raise ArgumentError, "Unknown attribute #{attr.inspect}"}
|
48
|
+
codes.empty?? "" : "\e[#{codes.join(';')}m"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Inspect an object with various inspectors.
|
52
|
+
# Options:
|
53
|
+
#
|
54
|
+
# :inspectors => [] # Array of inspectors, e.g. [:public_instance_methods].
|
55
|
+
# :inspector_arg => T|F # Arg to pass to inspector. Default is <tt>true</tt>
|
56
|
+
# :to_mav => T|F # Post-transform list into [method_name, access, visibility] ("MAV"). Default is <tt>false</tt>.
|
57
|
+
#
|
58
|
+
# Examples:
|
59
|
+
#
|
60
|
+
# get_methods(obj)
|
61
|
+
# # => [[inspector, [methods]], [inspector, [methods]], ...]
|
62
|
+
# get_methods(obj, :to_mav => true)
|
63
|
+
# # => [[method_name, access, visibility], [method_name, access, visibility], ...]
|
64
|
+
def self.get_methods(obj, options = {})
|
65
|
+
options = options.dup
|
66
|
+
o = {}
|
67
|
+
o[k = :inspectors] = (v = options.delete(k)).nil?? GET_METHODS_INSPECTORS : v
|
68
|
+
o[k = :inspector_arg] = (v = options.delete(k)).nil?? true : v
|
69
|
+
o[k = :to_mav] = (v = options.delete(k)).nil?? false : v
|
70
|
+
raise ArgumentError, "Unknown option(s): #{options.inspect}" if not options.empty?
|
71
|
+
|
72
|
+
out = []
|
73
|
+
|
74
|
+
o[:inspectors].each do |inspector|
|
75
|
+
next if not obj.respond_to? inspector
|
76
|
+
out << [inspector.to_s, obj.send(inspector, o[:inspector_arg]).sort.map(&:to_s)]
|
77
|
+
end
|
78
|
+
|
79
|
+
if o[:to_mav]
|
80
|
+
mav = []
|
81
|
+
|
82
|
+
is_module = obj.is_a? Module
|
83
|
+
|
84
|
+
out.each do |inspector, methods|
|
85
|
+
##puts "-- inspector-#{inspector.inspect}"
|
86
|
+
access = (is_module and not inspector.match /instance/) ? "::" : "#"
|
87
|
+
|
88
|
+
visibility = if inspector.match /private/
|
89
|
+
:private
|
90
|
+
elsif inspector.match /protected/
|
91
|
+
:protected
|
92
|
+
else
|
93
|
+
:public
|
94
|
+
end
|
95
|
+
|
96
|
+
methods.each do |method_name|
|
97
|
+
mav << [method_name, access, visibility]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
out = mav.uniq # NOTE: Dupes are possible, e.g. when custom inspectors are given.
|
102
|
+
end
|
103
|
+
|
104
|
+
out
|
105
|
+
end
|
106
|
+
|
107
|
+
# Return name of a module, even a "nameless" one.
|
108
|
+
def self.get_module_name(mod)
|
109
|
+
if mod.name.to_s.empty?
|
110
|
+
if mat = mod.inspect.match(/#<Class:.*?\b(.+?)(?:>|:[0#])/)
|
111
|
+
mat[1]
|
112
|
+
end
|
113
|
+
else
|
114
|
+
mod.name
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Escape string for use in Unix shell command.
|
119
|
+
# Credits http://stackoverflow.com/questions/1306680/shellwords-shellescape-implementation-for-ruby-1-8.
|
120
|
+
def self.shell_escape(s)
|
121
|
+
# An empty argument will be skipped, so return empty quotes.
|
122
|
+
return "''" if s.empty?
|
123
|
+
|
124
|
+
s = s.dup
|
125
|
+
|
126
|
+
# Process as a single byte sequence because not all shell
|
127
|
+
# implementations are multibyte aware.
|
128
|
+
s.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
|
129
|
+
|
130
|
+
# A LF cannot be escaped with a backslash because a backslash + LF
|
131
|
+
# combo is regarded as line continuation and simply ignored.
|
132
|
+
s.gsub!(/\n/, "'\n'")
|
133
|
+
|
134
|
+
s
|
135
|
+
end
|
136
|
+
|
137
|
+
# Escape string for use in Windows command. Word "shell" is used for similarity.
|
138
|
+
def self.win_shell_escape(s)
|
139
|
+
s
|
140
|
+
end
|
141
|
+
end # Tools
|
142
|
+
end # ORI
|