rash-command-shell 0.3.0 → 0.4.2.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.
- checksums.yaml +4 -4
- data/bin/rash +1 -1
- data/lib/rash.rb +38 -1
- data/lib/rash/capturing.rb +3 -0
- data/lib/rash/ext/filesystem.rb +148 -23
- data/lib/rash/jobcontrol.rb +1 -1
- data/lib/rash/pipeline.rb +99 -9
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 963d88b02cd2e9b8e448bb58808eb699917bfcc452c2530c979879d8acab934f
|
4
|
+
data.tar.gz: a9553ad99f9111c07c0de375968ce041a3cacea043e68af8e3eed9fa988e5203
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d19a800acd697b0e64a029b5b76dd7a2eb083de3601b5c78987be674156423a654624c845538be7038bc14ca0a845617adb974b8fa935fb1e4bd612f6d89765
|
7
|
+
data.tar.gz: 3dffa778fbb51114d0a114ff7c98952f43857304ed33150aa4a172fec7d4daf35f5092e637bb8547e04e9a1b4c139b91566bf4ccbb5c0130db82f03e90078115
|
data/bin/rash
CHANGED
@@ -4,7 +4,7 @@ if ARGV.empty?
|
|
4
4
|
exec("irb", "-r", "rash", *ARGV)
|
5
5
|
elsif ARGV[0] =~ /(-)?-v(ersion)?/
|
6
6
|
puts "Rash (c) 2020 Kellen Watt"
|
7
|
-
puts "Version 0.2.
|
7
|
+
puts "Version 0.4.2.1" # I may forget to update this
|
8
8
|
elsif File.exists?(ARGV[0]) && !File.directory?(ARGV[0])
|
9
9
|
require "rash"
|
10
10
|
file = ARGV.shift
|
data/lib/rash.rb
CHANGED
@@ -12,9 +12,24 @@ class Environment
|
|
12
12
|
Dir.chdir(dir.nil? ? "~" : dir.to_s)
|
13
13
|
@working_directory = Dir.pwd
|
14
14
|
ENV["OLDPWD"] = old.to_s
|
15
|
+
ENV["PWD"] = Dir.pwd
|
15
16
|
Dir.pwd
|
16
17
|
end
|
17
|
-
|
18
|
+
|
19
|
+
# Note that this works regardless of which version of chdir is used.
|
20
|
+
def push_dir(dir = nil)
|
21
|
+
@directory_stack.push(Dir.pwd)
|
22
|
+
self.chdir(dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
def pop_dir
|
26
|
+
self.chdir(@directory_stack.pop) if @directory_stack.size > 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def dirs
|
30
|
+
@directory_stack
|
31
|
+
end
|
32
|
+
|
18
33
|
def add_path(path)
|
19
34
|
ENV["PATH"] += File::PATH_SEPARATOR + (path.respond_to?(:path) ? path.path : path.to_s)
|
20
35
|
end
|
@@ -64,6 +79,10 @@ class Environment
|
|
64
79
|
end
|
65
80
|
end
|
66
81
|
|
82
|
+
def name?(v)
|
83
|
+
v.kind_of?(String) || v.kind_of?(Symbol)
|
84
|
+
end
|
85
|
+
|
67
86
|
private
|
68
87
|
|
69
88
|
def common_init
|
@@ -76,6 +95,8 @@ class Environment
|
|
76
95
|
|
77
96
|
@active_pipelines = []
|
78
97
|
|
98
|
+
@directory_stack = []
|
99
|
+
|
79
100
|
@prompt = {
|
80
101
|
AUTO_INDENT: true,
|
81
102
|
RETURN: ""
|
@@ -121,6 +142,17 @@ def cd(dir = nil)
|
|
121
142
|
$env.chdir(d)
|
122
143
|
end
|
123
144
|
|
145
|
+
def pushd(dir = nil)
|
146
|
+
case dir
|
147
|
+
when File, Dir
|
148
|
+
dir = dir.path if File.directory(dir.path)
|
149
|
+
end
|
150
|
+
$env.push_dir(dir)
|
151
|
+
end
|
152
|
+
|
153
|
+
def popd
|
154
|
+
$env.pop_dir
|
155
|
+
end
|
124
156
|
|
125
157
|
def run(file, *args)
|
126
158
|
filename = file.to_s
|
@@ -165,6 +197,11 @@ def which(command)
|
|
165
197
|
nil
|
166
198
|
end
|
167
199
|
|
200
|
+
# This breaks some default IRB functionality
|
201
|
+
# def self.respond_to_missing?(m, *args)
|
202
|
+
#
|
203
|
+
# which(m.to_s) || ($env.alias?(m) && !$env.aliasing_disabled) || $env.local_method?(m) || super
|
204
|
+
# end
|
168
205
|
|
169
206
|
# Note that I defy convention and don't define `respond_to_missing?`. This
|
170
207
|
# is because doing so screws with irb.
|
data/lib/rash/capturing.rb
CHANGED
@@ -2,11 +2,14 @@ class Environment
|
|
2
2
|
def capture_block(&block)
|
3
3
|
raise ArgumentError.new("no block provided") unless block_given?
|
4
4
|
result = nil
|
5
|
+
old_pipeline = @in_pipeline
|
5
6
|
begin
|
6
7
|
reader, writer = IO.pipe
|
7
8
|
self.stdout = writer
|
9
|
+
@in_pipeline = false
|
8
10
|
block.call
|
9
11
|
ensure
|
12
|
+
@in_pipeline = old_pipeline
|
10
13
|
reset_stdout
|
11
14
|
writer.close
|
12
15
|
result = reader.read
|
data/lib/rash/ext/filesystem.rb
CHANGED
@@ -6,30 +6,56 @@ class Environment
|
|
6
6
|
def initialize
|
7
7
|
common_init
|
8
8
|
@working_directory = Directory.root("/")
|
9
|
-
traverse_filetree("/", Dir.pwd)
|
10
9
|
end
|
11
10
|
|
12
11
|
def chdir(dir = nil)
|
13
12
|
old = @working_directory
|
14
|
-
traverse_filetree(
|
13
|
+
traverse_filetree(@working_directory.to_s, (dir.nil? ? "~" : dir.to_s))
|
15
14
|
ENV["OLDPWD"] = old.to_s
|
15
|
+
ENV["PWD"] = Dir.pwd
|
16
16
|
Dir.pwd
|
17
17
|
end
|
18
18
|
|
19
|
-
def local_def(name, &block)
|
20
|
-
@working_directory.add_local_method(name
|
19
|
+
def local_def(name, locked: false, &block)
|
20
|
+
@working_directory.add_local_method(name, &block)
|
21
|
+
@working_directory.lock_method(name) if locked
|
22
|
+
name.to_sym
|
21
23
|
end
|
22
24
|
|
23
25
|
def local_undef(name)
|
24
|
-
@working_directory.clear_local_method(name
|
26
|
+
@working_directory.clear_local_method(name)
|
25
27
|
end
|
26
28
|
|
27
29
|
def local_method?(name)
|
28
|
-
@working_directory.
|
30
|
+
@working_directory.local_method?(name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def local_methods
|
34
|
+
@working_directory.local_methods
|
29
35
|
end
|
30
36
|
|
31
37
|
def local_call(name, *args, &block)
|
32
|
-
@working_directory.
|
38
|
+
@working_directory.local_method(name).call(*args, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def local_var(name, v = nil, locked: false)
|
42
|
+
res = nil
|
43
|
+
if v.nil?
|
44
|
+
res = @working_directory.local_variable(name)
|
45
|
+
else
|
46
|
+
@working_directory.set_local_variable(name, v)
|
47
|
+
res = v
|
48
|
+
end
|
49
|
+
@working_directory.lock_variable(name) if locked
|
50
|
+
res
|
51
|
+
end
|
52
|
+
|
53
|
+
def local_var?(name)
|
54
|
+
@working_directory.local_variable?(name)
|
55
|
+
end
|
56
|
+
|
57
|
+
def local_vars
|
58
|
+
@working_directory.local_variables
|
33
59
|
end
|
34
60
|
|
35
61
|
private
|
@@ -65,7 +91,6 @@ class Environment
|
|
65
91
|
end
|
66
92
|
|
67
93
|
class Directory
|
68
|
-
attr_reader :local_methods
|
69
94
|
attr_reader :parent, :children
|
70
95
|
|
71
96
|
def self.root(dir)
|
@@ -76,9 +101,121 @@ class Environment
|
|
76
101
|
@path = Dir.new(dir)
|
77
102
|
@parent = parent
|
78
103
|
@children = []
|
79
|
-
@local_methods =
|
104
|
+
@local_methods = {}
|
105
|
+
@locked_methods = []
|
106
|
+
@local_variables = {}
|
107
|
+
@locked_variables = []
|
108
|
+
end
|
109
|
+
|
110
|
+
######################
|
111
|
+
# Local method methods
|
112
|
+
######################
|
113
|
+
|
114
|
+
def local_method(name)
|
115
|
+
name = name.to_sym
|
116
|
+
@local_methods[name] || @parent&.unlocked_local_method(name)
|
117
|
+
end
|
118
|
+
|
119
|
+
def local_method?(name)
|
120
|
+
name = name.to_sym
|
121
|
+
@local_methods.key?(name) || !!@parent&.unlocked_local_method?(name)
|
122
|
+
end
|
123
|
+
|
124
|
+
def local_methods
|
125
|
+
@local_methods.keys + (@parent&.unlocked_local_methods).to_a
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_local_method(name, &block)
|
129
|
+
raise ArgumentError.new "no method body provided" unless block_given?
|
130
|
+
@local_methods[name.to_sym] = block # if name already exists, its function is overriden
|
131
|
+
name.to_sym
|
132
|
+
end
|
133
|
+
|
134
|
+
def unlocked_local_method(name)
|
135
|
+
name = name.to_sym
|
136
|
+
@local_methods[name] || @parent&.unlocked_local_method(name)
|
137
|
+
end
|
138
|
+
|
139
|
+
def unlocked_local_method?(name)
|
140
|
+
name = name.to_sym
|
141
|
+
@local_methods.filter{|k, v| !@locked_methods.include?(k)}.key?(name) ||
|
142
|
+
!!@parent&.unlocked_local_method?(name)
|
143
|
+
end
|
144
|
+
|
145
|
+
def unlocked_local_methods
|
146
|
+
@local_methods.filter{|k, v| !@locked_methods.include?(k)}.keys + (@parent&.unlocked_local_methods).to_a
|
147
|
+
end
|
148
|
+
|
149
|
+
def lock_method(name)
|
150
|
+
n = name.to_sym
|
151
|
+
raise NameError.new("#{name} is not a local method", n) unless @local_methods.key?(n)
|
152
|
+
@locked_methods << n unless @locked_methods.include?(n)
|
153
|
+
n
|
154
|
+
end
|
155
|
+
|
156
|
+
# might not be useful
|
157
|
+
def clear_local_method(name)
|
158
|
+
@local_methods.delete(name.to_sym)
|
159
|
+
name.to_sym
|
160
|
+
end
|
161
|
+
|
162
|
+
######################
|
163
|
+
# Local variable stuff
|
164
|
+
######################
|
165
|
+
|
166
|
+
def local_variable(name)
|
167
|
+
name = name.to_sym
|
168
|
+
@local_variables[name] || @parent&.unlocked_local_variable(name)
|
169
|
+
end
|
170
|
+
|
171
|
+
def local_variable?(name)
|
172
|
+
@local_variables.include?(name.to_sym) || !!@parent&.unlocked_local_variable?(name.to_sym)
|
173
|
+
end
|
174
|
+
|
175
|
+
def local_variables
|
176
|
+
@local_variables.keys + (@parent&.unlocked_local_variables).to_a
|
177
|
+
end
|
178
|
+
|
179
|
+
def set_local_variable(name, value)
|
180
|
+
name = name.to_sym
|
181
|
+
if !@local_variables.key?(name) && @parent&.unlocked_local_variable?(name)
|
182
|
+
@parent&.set_local_variable(name, value)
|
183
|
+
else
|
184
|
+
@local_variables[name] = value
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def unlocked_local_variable(name)
|
189
|
+
name = name.to_sym
|
190
|
+
@local_variables.filter{|k| !@locked_variables.include?(k)}[name] || @parent&.unlocked_local_variable(name)
|
191
|
+
end
|
192
|
+
|
193
|
+
def unlocked_local_variable?(name)
|
194
|
+
name = name.to_sym
|
195
|
+
@local_variables.filter{|k,_v| !@locked_variables.include?(k)}.key?(name) ||
|
196
|
+
!!@parent&.unlocked_local_variable?(name)
|
197
|
+
end
|
198
|
+
|
199
|
+
def unlocked_local_variables
|
200
|
+
@local_variables.keys.filter{|k| !@locked_variables.include?(k)} + (@parent&.unlocked_local_variables).to_a
|
201
|
+
end
|
202
|
+
|
203
|
+
def lock_variable(name)
|
204
|
+
n = name.to_sym
|
205
|
+
raise NameError.new("#{name} is not a local variable", n) unless @local_variables.key?(n)
|
206
|
+
@locked_variables << n unless @locked_variables.include?(n)
|
207
|
+
n
|
208
|
+
end
|
209
|
+
|
210
|
+
def clear_local_variable(name)
|
211
|
+
@local_variables.delete(name.to_sym)
|
212
|
+
name.to_sym
|
80
213
|
end
|
81
214
|
|
215
|
+
###########################
|
216
|
+
# Generic traversal methods
|
217
|
+
###########################
|
218
|
+
|
82
219
|
def root?
|
83
220
|
parent.nil?
|
84
221
|
end
|
@@ -101,18 +238,6 @@ class Environment
|
|
101
238
|
dir
|
102
239
|
end
|
103
240
|
|
104
|
-
def add_local_method(name, &block)
|
105
|
-
raise ArgumentError.new "no method body provided" unless block_given?
|
106
|
-
@local_methods[name] = block # if name already exists, its function is overriden
|
107
|
-
name
|
108
|
-
end
|
109
|
-
|
110
|
-
# might not be useful
|
111
|
-
def clear_local_method(name)
|
112
|
-
@local_methods.delete(name)
|
113
|
-
name
|
114
|
-
end
|
115
|
-
|
116
241
|
def to_s
|
117
242
|
@path.path
|
118
243
|
end
|
@@ -121,10 +246,9 @@ end
|
|
121
246
|
|
122
247
|
# still could absolutely be more cleaned up, but it works
|
123
248
|
def self.method_missing(m, *args, &block)
|
124
|
-
exe = which(m.to_s)
|
125
249
|
if $env.local_method?(m)
|
126
250
|
$env.local_call(m, *args, &block)
|
127
|
-
elsif
|
251
|
+
elsif which(m.to_s) || ($env.alias?(m) && !$env.aliasing_disabled)
|
128
252
|
$env.dispatch(m, *args)
|
129
253
|
else
|
130
254
|
super
|
@@ -132,3 +256,4 @@ def self.method_missing(m, *args, &block)
|
|
132
256
|
end
|
133
257
|
|
134
258
|
$env = Environment.new
|
259
|
+
$env.chdir(Dir.pwd)
|
data/lib/rash/jobcontrol.rb
CHANGED
data/lib/rash/pipeline.rb
CHANGED
@@ -4,6 +4,10 @@ class Environment
|
|
4
4
|
@in_pipeline
|
5
5
|
end
|
6
6
|
|
7
|
+
def synced_pipeline?
|
8
|
+
@in_pipeline && @synchronous_pipeline
|
9
|
+
end
|
10
|
+
|
7
11
|
def make_pipeline(&block)
|
8
12
|
raise IOError.new("pipelining already enabled") if @in_pipeline
|
9
13
|
start_pipeline
|
@@ -14,9 +18,21 @@ class Environment
|
|
14
18
|
end
|
15
19
|
nil
|
16
20
|
end
|
21
|
+
|
22
|
+
def make_sync_pipeline(&block)
|
23
|
+
raise IOError.new("pipelining already enabled") if @in_pipeline
|
24
|
+
start_sync_pipeline
|
25
|
+
begin
|
26
|
+
block.call
|
27
|
+
ensure
|
28
|
+
end_sync_pipeline
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
17
32
|
|
18
33
|
def as_pipe_command(&block)
|
19
34
|
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
35
|
+
return as_sync_pipe_command(&block) if @synchronous_pipeline
|
20
36
|
|
21
37
|
input = (@active_pipelines.empty? ? $stdin : @active_pipelines.last.reader)
|
22
38
|
@active_pipelines << Pipeline.new
|
@@ -38,28 +54,81 @@ class Environment
|
|
38
54
|
nil
|
39
55
|
end
|
40
56
|
|
57
|
+
def as_sync_pipe_command(&block)
|
58
|
+
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
59
|
+
raise IOError.new("pipeline is not synchronous") unless @synchronous_pipeline
|
60
|
+
|
61
|
+
@next_pipe.close
|
62
|
+
@next_pipe = Pipeline.new # flush the output pipe
|
63
|
+
@prev_pipe.writer.close
|
64
|
+
|
65
|
+
input = (@first_sync_command ? $stdin : @prev_pipe.reader)
|
66
|
+
@first_sync_command = false
|
67
|
+
output = @next_pipe.writer
|
68
|
+
error = ($stderr == $stdout ? @next_pipe.writer : $stdin)
|
69
|
+
|
70
|
+
pid = fork do
|
71
|
+
@in_pipeline = false
|
72
|
+
@synchronous_pipeline = false
|
73
|
+
$stdin = input
|
74
|
+
$stdout = output
|
75
|
+
$stderr = error
|
76
|
+
block.call
|
77
|
+
exit!(true)
|
78
|
+
end
|
79
|
+
|
80
|
+
Process.wait(pid)
|
81
|
+
@prev_pipe, @next_pipe = @next_pipe, @prev_pipe
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
41
85
|
private
|
42
86
|
|
43
87
|
def start_pipeline
|
44
88
|
@in_pipeline = true
|
45
89
|
end
|
46
90
|
|
91
|
+
def start_sync_pipeline
|
92
|
+
@in_pipeline = true
|
93
|
+
@synchronous_pipeline = true
|
94
|
+
@first_sync_command = true
|
95
|
+
@prev_pipe = Pipeline.new
|
96
|
+
@next_pipe = Pipeline.new
|
97
|
+
end
|
98
|
+
|
47
99
|
def end_pipeline
|
48
100
|
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
49
101
|
@in_pipeline = false
|
50
102
|
if @active_pipelines.size > 0
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
103
|
+
begin
|
104
|
+
Process.wait(@active_pipelines.last.pid)
|
105
|
+
@active_pipelines.last.writer.close # probably redundant, but leaving it for now
|
106
|
+
IO.copy_stream(@active_pipelines.last.reader, $stdout)
|
107
|
+
@active_pipelines.pop.close
|
108
|
+
@active_pipelines.reverse_each {|pipe| pipe.terminate}
|
109
|
+
ensure
|
110
|
+
@active_pipelines.clear
|
111
|
+
end
|
57
112
|
end
|
58
113
|
end
|
59
114
|
|
115
|
+
def end_sync_pipeline
|
116
|
+
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
117
|
+
raise IOError.new("pipeline is not synchronous") unless @synchronous_pipeline
|
118
|
+
@next_pipe.close
|
119
|
+
@prev_pipe.writer.close
|
120
|
+
IO.copy_stream(@prev_pipe.reader, $stdout)
|
121
|
+
@prev_pipe.close
|
122
|
+
|
123
|
+
@next_pipe = @prev_pipe = @first_sync_command = nil
|
124
|
+
@synchronous_pipeline = @in_pipeline = false
|
125
|
+
end
|
126
|
+
|
60
127
|
# special method to be referenced from Environment#dispatch. Do not use directly
|
61
128
|
def add_pipeline(m, *args)
|
62
129
|
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
130
|
+
return add_sync_pipeline(m, *args) if @synchronous_pipeline
|
131
|
+
|
63
132
|
input = (@active_pipelines.empty? ? $stdin : @active_pipelines.last.reader)
|
64
133
|
@active_pipelines << Pipeline.new
|
65
134
|
output = @active_pipelines.last.writer
|
@@ -73,6 +142,23 @@ class Environment
|
|
73
142
|
@active_pipelines.last.link_process(pid)
|
74
143
|
end
|
75
144
|
|
145
|
+
def add_sync_pipeline(m, *args)
|
146
|
+
raise IOError.new("pipelining not enabled") unless @in_pipeline
|
147
|
+
raise IOError.new("pipeline is not synchronous") unless @synchronous_pipeline
|
148
|
+
|
149
|
+
# Ensure pipe is empty for writing
|
150
|
+
@next_pipe.close
|
151
|
+
@next_pipe = Pipeline.new
|
152
|
+
@prev_pipe.writer.close
|
153
|
+
|
154
|
+
input = (@first_sync_command ? $stdin : @prev_pipe.reader)
|
155
|
+
@first_sync_command = false
|
156
|
+
error = ($stderr == $stdout ? @next_pipe.writer : $stdin)
|
157
|
+
system_command(m, *args, out: @next_pipe.writer, input: input, err: error, except: true)
|
158
|
+
@prev_pipe, @next_pipe = @next_pipe, @prev_pipe
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
|
76
162
|
class Pipeline
|
77
163
|
attr_reader :writer, :reader, :pid
|
78
164
|
|
@@ -92,7 +178,7 @@ class Environment
|
|
92
178
|
|
93
179
|
def terminate
|
94
180
|
self.close
|
95
|
-
Process.kill(:
|
181
|
+
Process.kill(:TERM, @pid)
|
96
182
|
Process.wait(@pid)
|
97
183
|
end
|
98
184
|
|
@@ -103,6 +189,10 @@ class Environment
|
|
103
189
|
end
|
104
190
|
|
105
191
|
|
106
|
-
def in_pipeline(&block)
|
107
|
-
|
192
|
+
def in_pipeline(async: true, &block)
|
193
|
+
if async
|
194
|
+
$env.make_pipeline(&block)
|
195
|
+
else
|
196
|
+
$env.make_sync_pipeline(&block)
|
197
|
+
end
|
108
198
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rash-command-shell
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kellen Watt
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.2'
|
27
|
-
description: A Ruby-based shell
|
27
|
+
description: A Ruby-based command shell
|
28
28
|
email:
|
29
29
|
executables:
|
30
30
|
- rash
|
@@ -43,7 +43,9 @@ files:
|
|
43
43
|
homepage: https://github.com/KellenWatt/rash
|
44
44
|
licenses:
|
45
45
|
- MIT
|
46
|
-
metadata:
|
46
|
+
metadata:
|
47
|
+
documentation_uri: https://github.com/KellenWatt/rash/wiki
|
48
|
+
wiki: https://github.com/KellenWatt/rash/wiki
|
47
49
|
post_install_message:
|
48
50
|
rdoc_options: []
|
49
51
|
require_paths:
|