rash-command-shell 0.3.1 → 0.4.2.2
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 +2 -2
- data/lib/rash.rb +39 -3
- data/lib/rash/ext/filesystem.rb +150 -23
- data/lib/rash/jobcontrol.rb +1 -1
- data/lib/rash/pipeline.rb +98 -8
- data/lib/rash/redirection.rb +1 -1
- 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: dfc5e5ad65a440c46d61615f3af54351e8cea6d65ca029c0a6d6a8ad8532d1ea
|
4
|
+
data.tar.gz: fe22cba6e10c9e03ff2dac578fb21f5247defb3e8523ae596f67b372667d1c2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48d51cb3c68949accf870d3e80fd526d570d420fd28bc3de4a4a5a94ac18a3fb070c37531ef736a467e8c0642aa790f9ae99db9e565bbd46a12f0f170e86e5c1
|
7
|
+
data.tar.gz: c61f1b1689ccd5031b14c4a4bb14dba0b002f9d820af0eb0c4b1be03e13bb026449bfa0b5159d9aaa92c8e178f80e83cb7447ce17af6c64613295aa6838fa561
|
data/bin/rash
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
if ARGV.empty?
|
4
|
-
exec("irb", "-r", "rash", *ARGV)
|
4
|
+
exec(["irb", "rash"], "-r", "rash", *ARGV)
|
5
5
|
elsif ARGV[0] =~ /(-)?-v(ersion)?/
|
6
6
|
puts "Rash (c) 2020 Kellen Watt"
|
7
|
-
puts "Version 0.2.2" # I may forget to update this
|
7
|
+
puts "Version 0.4.2.2" # 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,11 +95,12 @@ 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: ""
|
82
103
|
}
|
83
|
-
ENV["RASHDIR"] = File.dirname(__FILE__)
|
84
104
|
end
|
85
105
|
|
86
106
|
def resolve_command(m, *args, literal: false)
|
@@ -121,6 +141,17 @@ def cd(dir = nil)
|
|
121
141
|
$env.chdir(d)
|
122
142
|
end
|
123
143
|
|
144
|
+
def pushd(dir = nil)
|
145
|
+
case dir
|
146
|
+
when File, Dir
|
147
|
+
dir = dir.path if File.directory(dir.path)
|
148
|
+
end
|
149
|
+
$env.push_dir(dir)
|
150
|
+
end
|
151
|
+
|
152
|
+
def popd
|
153
|
+
$env.pop_dir
|
154
|
+
end
|
124
155
|
|
125
156
|
def run(file, *args)
|
126
157
|
filename = file.to_s
|
@@ -165,6 +196,11 @@ def which(command)
|
|
165
196
|
nil
|
166
197
|
end
|
167
198
|
|
199
|
+
# This breaks some default IRB functionality
|
200
|
+
# def self.respond_to_missing?(m, *args)
|
201
|
+
#
|
202
|
+
# which(m.to_s) || ($env.alias?(m) && !$env.aliasing_disabled) || $env.local_method?(m) || super
|
203
|
+
# end
|
168
204
|
|
169
205
|
# Note that I defy convention and don't define `respond_to_missing?`. This
|
170
206
|
# is because doing so screws with irb.
|
@@ -177,6 +213,6 @@ def self.method_missing(m, *args, &block)
|
|
177
213
|
end
|
178
214
|
end
|
179
215
|
|
180
|
-
|
216
|
+
Process.setproctitle("rash")
|
181
217
|
run_command_file = "#{$env.HOME}/.rashrc"
|
182
218
|
load run_command_file if File.file?(run_command_file)
|
data/lib/rash/ext/filesystem.rb
CHANGED
@@ -6,30 +6,58 @@ 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)
|
29
31
|
end
|
30
32
|
|
33
|
+
def local_methods
|
34
|
+
@working_directory.local_methods
|
35
|
+
end
|
36
|
+
|
37
|
+
# This ultimately behaves similarly to a lambda in function if that ever changes,
|
38
|
+
# then the proc needs to be converted to a lambda.
|
31
39
|
def local_call(name, *args, &block)
|
32
|
-
@working_directory.
|
40
|
+
@working_directory.local_method(name).call(*args, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def local_var(name, v = nil, locked: false)
|
44
|
+
res = nil
|
45
|
+
if v.nil?
|
46
|
+
res = @working_directory.local_variable(name)
|
47
|
+
else
|
48
|
+
@working_directory.set_local_variable(name, v)
|
49
|
+
res = v
|
50
|
+
end
|
51
|
+
@working_directory.lock_variable(name) if locked
|
52
|
+
res
|
53
|
+
end
|
54
|
+
|
55
|
+
def local_var?(name)
|
56
|
+
@working_directory.local_variable?(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def local_vars
|
60
|
+
@working_directory.local_variables
|
33
61
|
end
|
34
62
|
|
35
63
|
private
|
@@ -65,7 +93,6 @@ class Environment
|
|
65
93
|
end
|
66
94
|
|
67
95
|
class Directory
|
68
|
-
attr_reader :local_methods
|
69
96
|
attr_reader :parent, :children
|
70
97
|
|
71
98
|
def self.root(dir)
|
@@ -76,9 +103,121 @@ class Environment
|
|
76
103
|
@path = Dir.new(dir)
|
77
104
|
@parent = parent
|
78
105
|
@children = []
|
79
|
-
@local_methods =
|
106
|
+
@local_methods = {}
|
107
|
+
@locked_methods = []
|
108
|
+
@local_variables = {}
|
109
|
+
@locked_variables = []
|
110
|
+
end
|
111
|
+
|
112
|
+
######################
|
113
|
+
# Local method methods
|
114
|
+
######################
|
115
|
+
|
116
|
+
def local_method(name)
|
117
|
+
name = name.to_sym
|
118
|
+
@local_methods[name] || @parent&.unlocked_local_method(name)
|
119
|
+
end
|
120
|
+
|
121
|
+
def local_method?(name)
|
122
|
+
name = name.to_sym
|
123
|
+
@local_methods.key?(name) || !!@parent&.unlocked_local_method?(name)
|
124
|
+
end
|
125
|
+
|
126
|
+
def local_methods
|
127
|
+
@local_methods.keys + (@parent&.unlocked_local_methods).to_a
|
128
|
+
end
|
129
|
+
|
130
|
+
def add_local_method(name, &block)
|
131
|
+
raise ArgumentError.new "no method body provided" unless block_given?
|
132
|
+
@local_methods[name.to_sym] = block # if name already exists, its function is overriden
|
133
|
+
name.to_sym
|
134
|
+
end
|
135
|
+
|
136
|
+
def unlocked_local_method(name)
|
137
|
+
name = name.to_sym
|
138
|
+
@local_methods[name] || @parent&.unlocked_local_method(name)
|
139
|
+
end
|
140
|
+
|
141
|
+
def unlocked_local_method?(name)
|
142
|
+
name = name.to_sym
|
143
|
+
@local_methods.filter{|k, v| !@locked_methods.include?(k)}.key?(name) ||
|
144
|
+
!!@parent&.unlocked_local_method?(name)
|
145
|
+
end
|
146
|
+
|
147
|
+
def unlocked_local_methods
|
148
|
+
@local_methods.filter{|k, v| !@locked_methods.include?(k)}.keys + (@parent&.unlocked_local_methods).to_a
|
149
|
+
end
|
150
|
+
|
151
|
+
def lock_method(name)
|
152
|
+
n = name.to_sym
|
153
|
+
raise NameError.new("#{name} is not a local method", n) unless @local_methods.key?(n)
|
154
|
+
@locked_methods << n unless @locked_methods.include?(n)
|
155
|
+
n
|
156
|
+
end
|
157
|
+
|
158
|
+
# might not be useful
|
159
|
+
def clear_local_method(name)
|
160
|
+
@local_methods.delete(name.to_sym)
|
161
|
+
name.to_sym
|
162
|
+
end
|
163
|
+
|
164
|
+
######################
|
165
|
+
# Local variable stuff
|
166
|
+
######################
|
167
|
+
|
168
|
+
def local_variable(name)
|
169
|
+
name = name.to_sym
|
170
|
+
@local_variables[name] || @parent&.unlocked_local_variable(name)
|
171
|
+
end
|
172
|
+
|
173
|
+
def local_variable?(name)
|
174
|
+
@local_variables.include?(name.to_sym) || !!@parent&.unlocked_local_variable?(name.to_sym)
|
175
|
+
end
|
176
|
+
|
177
|
+
def local_variables
|
178
|
+
@local_variables.keys + (@parent&.unlocked_local_variables).to_a
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_local_variable(name, value)
|
182
|
+
name = name.to_sym
|
183
|
+
if !@local_variables.key?(name) && @parent&.unlocked_local_variable?(name)
|
184
|
+
@parent&.set_local_variable(name, value)
|
185
|
+
else
|
186
|
+
@local_variables[name] = value
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def unlocked_local_variable(name)
|
191
|
+
name = name.to_sym
|
192
|
+
@local_variables.filter{|k| !@locked_variables.include?(k)}[name] || @parent&.unlocked_local_variable(name)
|
193
|
+
end
|
194
|
+
|
195
|
+
def unlocked_local_variable?(name)
|
196
|
+
name = name.to_sym
|
197
|
+
@local_variables.filter{|k,_v| !@locked_variables.include?(k)}.key?(name) ||
|
198
|
+
!!@parent&.unlocked_local_variable?(name)
|
199
|
+
end
|
200
|
+
|
201
|
+
def unlocked_local_variables
|
202
|
+
@local_variables.keys.filter{|k| !@locked_variables.include?(k)} + (@parent&.unlocked_local_variables).to_a
|
203
|
+
end
|
204
|
+
|
205
|
+
def lock_variable(name)
|
206
|
+
n = name.to_sym
|
207
|
+
raise NameError.new("#{name} is not a local variable", n) unless @local_variables.key?(n)
|
208
|
+
@locked_variables << n unless @locked_variables.include?(n)
|
209
|
+
n
|
210
|
+
end
|
211
|
+
|
212
|
+
def clear_local_variable(name)
|
213
|
+
@local_variables.delete(name.to_sym)
|
214
|
+
name.to_sym
|
80
215
|
end
|
81
216
|
|
217
|
+
###########################
|
218
|
+
# Generic traversal methods
|
219
|
+
###########################
|
220
|
+
|
82
221
|
def root?
|
83
222
|
parent.nil?
|
84
223
|
end
|
@@ -101,18 +240,6 @@ class Environment
|
|
101
240
|
dir
|
102
241
|
end
|
103
242
|
|
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
243
|
def to_s
|
117
244
|
@path.path
|
118
245
|
end
|
@@ -121,10 +248,9 @@ end
|
|
121
248
|
|
122
249
|
# still could absolutely be more cleaned up, but it works
|
123
250
|
def self.method_missing(m, *args, &block)
|
124
|
-
exe = which(m.to_s)
|
125
251
|
if $env.local_method?(m)
|
126
252
|
$env.local_call(m, *args, &block)
|
127
|
-
elsif
|
253
|
+
elsif which(m.to_s) || ($env.alias?(m) && !$env.aliasing_disabled)
|
128
254
|
$env.dispatch(m, *args)
|
129
255
|
else
|
130
256
|
super
|
@@ -132,3 +258,4 @@ def self.method_missing(m, *args, &block)
|
|
132
258
|
end
|
133
259
|
|
134
260
|
$env = Environment.new
|
261
|
+
$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
|
|
@@ -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
|
data/lib/rash/redirection.rb
CHANGED
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.2
|
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_uri: https://github.com/KellenWatt/rash/wiki
|
47
49
|
post_install_message:
|
48
50
|
rdoc_options: []
|
49
51
|
require_paths:
|