rcommand 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/CHANGELOG +2 -0
- data/README +42 -0
- data/install.rb +30 -0
- data/lib/rcommand.rb +287 -0
- data/rakefile +113 -0
- data/test/command_test.rb +63 -0
- metadata +47 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
RCommand is a generic way for ruby scripts to present a full-featured
|
2
|
+
command interface to users, complete with command history and tab completion.
|
3
|
+
|
4
|
+
== Example
|
5
|
+
require 'rcommand'
|
6
|
+
|
7
|
+
command_line = RCommand.new(STDIN, STDOUT)
|
8
|
+
command_line.for_prompt do
|
9
|
+
command_line.io_write.print("#{command_line.history.size}:> ")
|
10
|
+
end
|
11
|
+
|
12
|
+
# Default events shown here in full, for demonstration purposes. Omitting
|
13
|
+
# them will give the same behavior.
|
14
|
+
command_line.on_single_tab do |partial|
|
15
|
+
matches = RCommand.matches(partial, command_line.history)
|
16
|
+
common_prefix = RCommand.common_prefix(matches)
|
17
|
+
common_prefix.nil? ? partial : common_prefix
|
18
|
+
end
|
19
|
+
command_line.on_double_tab do |partial|
|
20
|
+
matches = RCommand.matches(partial, command_line.history)
|
21
|
+
if matches.size > 1
|
22
|
+
command_line.io_write.puts()
|
23
|
+
for match in matches.uniq
|
24
|
+
command_line.io_write.puts(match)
|
25
|
+
end
|
26
|
+
command_line.prompt()
|
27
|
+
command_line.io_write.print(partial)
|
28
|
+
end
|
29
|
+
partial
|
30
|
+
end
|
31
|
+
command_line.on_key_up do |partial|
|
32
|
+
command_line.prev()
|
33
|
+
end
|
34
|
+
command_line.on_key_down do |partial|
|
35
|
+
command_line.next()
|
36
|
+
end
|
37
|
+
|
38
|
+
loop do
|
39
|
+
command_line.prompt()
|
40
|
+
result = command_line.gets()
|
41
|
+
command_line.io_write.puts("Example command: #{result}")
|
42
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'find'
|
3
|
+
require 'ftools'
|
4
|
+
|
5
|
+
include Config
|
6
|
+
|
7
|
+
# this was adapted from rdoc's install.rb by ways of Log4r
|
8
|
+
|
9
|
+
$sitedir = CONFIG["sitelibdir"]
|
10
|
+
unless $sitedir
|
11
|
+
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
|
12
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
13
|
+
$sitedir = $:.find {|x| x =~ /site_ruby/ }
|
14
|
+
if !$sitedir
|
15
|
+
$sitedir = File.join($libdir, "site_ruby")
|
16
|
+
elsif $sitedir !~ Regexp.quote(version)
|
17
|
+
$sitedir = File.join($sitedir, version)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# the acual gruntwork
|
22
|
+
Dir.chdir("lib")
|
23
|
+
|
24
|
+
Find.find("rcommand.rb") { |f|
|
25
|
+
if f[-3..-1] == ".rb"
|
26
|
+
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
|
27
|
+
else
|
28
|
+
File::makedirs(File.join($sitedir, *f.split(/\//)))
|
29
|
+
end
|
30
|
+
}
|
data/lib/rcommand.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2005 Robert Aman
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
RCOMMAND_VERSION = "0.1.0"
|
25
|
+
|
26
|
+
$:.unshift(File.dirname(__FILE__))
|
27
|
+
|
28
|
+
# RCommand is a generic way for ruby scripts to present a full-featured
|
29
|
+
# command interface to users with command history and tab completion.
|
30
|
+
class RCommand
|
31
|
+
|
32
|
+
# Returns all commands in a command list that match a partial command.
|
33
|
+
def self.matches(partial, command_list)
|
34
|
+
matches = []
|
35
|
+
for command in command_list
|
36
|
+
unless command.kind_of? String
|
37
|
+
raise "Expecting String, got #{command.class.name} instead."
|
38
|
+
end
|
39
|
+
matches << command if command[0...(partial.size)] == partial
|
40
|
+
end
|
41
|
+
return matches
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns any prefix shared by all commands in a list, or the empty
|
45
|
+
# string if there was no prefix.
|
46
|
+
def self.common_prefix(command_list)
|
47
|
+
return "" unless command_list.kind_of? Enumerable
|
48
|
+
return "" if command_list.size == 0
|
49
|
+
command_list.each do |command|
|
50
|
+
unless command.kind_of? String
|
51
|
+
raise "Expecting String, got #{command.class.name} instead."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
prefix = ""
|
55
|
+
command_list = command_list.sort do |a, b|
|
56
|
+
a.size <=> b.size
|
57
|
+
end
|
58
|
+
for i in 0..command_list[0].size
|
59
|
+
for command in command_list
|
60
|
+
return prefix if command_list[0][i] != command[i]
|
61
|
+
end
|
62
|
+
prefix = command_list[0][0..i]
|
63
|
+
end
|
64
|
+
return prefix
|
65
|
+
end
|
66
|
+
|
67
|
+
# Creates a new RCommand interface object.
|
68
|
+
def initialize(io_read, io_write)
|
69
|
+
unless io_read.kind_of? IO
|
70
|
+
raise "Expecting object of type IO, got #{io_read.class.name}."
|
71
|
+
end
|
72
|
+
unless io_write.kind_of? IO
|
73
|
+
raise "Expecting object of type IO, got #{io_write.class.name}."
|
74
|
+
end
|
75
|
+
@io_read = io_read
|
76
|
+
@io_write = io_write
|
77
|
+
@history = []
|
78
|
+
@history_index = nil
|
79
|
+
@tab_count = 0
|
80
|
+
@prompt_proc = nil
|
81
|
+
@single_tab_proc = lambda do |partial|
|
82
|
+
matches = RCommand.matches(partial, self.history)
|
83
|
+
common_prefix = RCommand.common_prefix(matches)
|
84
|
+
common_prefix.nil? ? partial : common_prefix
|
85
|
+
end
|
86
|
+
@double_tab_proc = lambda do |partial|
|
87
|
+
matches = RCommand.matches(partial, self.history)
|
88
|
+
if matches.size > 1
|
89
|
+
self.io_write.puts()
|
90
|
+
for match in matches.uniq
|
91
|
+
self.io_write.puts(match)
|
92
|
+
end
|
93
|
+
self.prompt()
|
94
|
+
self.io_write.print(partial)
|
95
|
+
end
|
96
|
+
partial
|
97
|
+
end
|
98
|
+
@key_up_proc = lambda do |partial|
|
99
|
+
self.prev()
|
100
|
+
end
|
101
|
+
@key_down_proc = lambda do |partial|
|
102
|
+
self.next()
|
103
|
+
end
|
104
|
+
@key_left_proc = nil
|
105
|
+
@key_right_proc = nil
|
106
|
+
@interupt_proc = lambda do
|
107
|
+
self.io_write.print("\n")
|
108
|
+
system("stty sane")
|
109
|
+
exit
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
attr_reader :io_read
|
114
|
+
attr_reader :io_write
|
115
|
+
attr_reader :history
|
116
|
+
attr_accessor :history_index
|
117
|
+
|
118
|
+
def for_prompt(&block); @prompt_proc = block; end
|
119
|
+
def on_single_tab(&block); @single_tab_proc = block; end
|
120
|
+
def on_double_tab(&block); @double_tab_proc = block; end
|
121
|
+
def on_key_up(&block); @key_up_proc = block; end
|
122
|
+
def on_key_down(&block); @key_down_proc = block; end
|
123
|
+
def on_key_left(&block); @key_left_proc = block; end
|
124
|
+
def on_key_right(&block); @key_right_proc = block; end
|
125
|
+
def on_interupt(&block); @interupt_proc = block; end
|
126
|
+
|
127
|
+
# Displays the prompt, if any.
|
128
|
+
def prompt()
|
129
|
+
@prompt_proc.call() unless @prompt_proc.nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
# Sets the command line to the previous command.
|
133
|
+
def prev()
|
134
|
+
if self.history_index.nil?
|
135
|
+
self.history_index = self.history.size - 1
|
136
|
+
else
|
137
|
+
self.history_index -= 1
|
138
|
+
self.history_index = 0 if self.history_index < 0
|
139
|
+
end
|
140
|
+
self.history[self.history_index]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Sets the command line to the next command.
|
144
|
+
def next()
|
145
|
+
if self.history_index.nil?
|
146
|
+
nil
|
147
|
+
else
|
148
|
+
self.history_index += 1
|
149
|
+
if self.history_index > self.history.size - 1
|
150
|
+
self.history_index = self.history.size - 1
|
151
|
+
""
|
152
|
+
else
|
153
|
+
self.history[self.history_index]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Adds a command to the command line.
|
159
|
+
def <<(command)
|
160
|
+
command = command[0..-1] if command[-1] == "\n"
|
161
|
+
command = command[0..-1] if command[-1] == "\r"
|
162
|
+
if @history[-1] == ""
|
163
|
+
@history.pop()
|
164
|
+
end
|
165
|
+
@history << command if command != ""
|
166
|
+
@history_index = nil
|
167
|
+
end
|
168
|
+
|
169
|
+
# Returns the command string entered by the user.
|
170
|
+
def gets()
|
171
|
+
command = ""
|
172
|
+
char = nil
|
173
|
+
loop do
|
174
|
+
char = getc()
|
175
|
+
next if char.nil?
|
176
|
+
next if char == 0
|
177
|
+
if char != 9
|
178
|
+
@tab_count = 0
|
179
|
+
end
|
180
|
+
if char == 3
|
181
|
+
@interupt_proc.call() unless @interupt_proc.nil?
|
182
|
+
elsif char == 10
|
183
|
+
@io_write.print("\n")
|
184
|
+
self << command
|
185
|
+
break
|
186
|
+
elsif char == 9
|
187
|
+
@tab_count += 1
|
188
|
+
replacement = nil
|
189
|
+
if @tab_count == 1
|
190
|
+
unless @single_tab_proc.nil?
|
191
|
+
replacement =
|
192
|
+
@single_tab_proc.call(command)
|
193
|
+
end
|
194
|
+
elsif @tab_count > 1
|
195
|
+
unless @double_tab_proc.nil?
|
196
|
+
replacement =
|
197
|
+
@double_tab_proc.call(command)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
if replacement != nil && replacement.size > command.size
|
201
|
+
@io_write.print(
|
202
|
+
8.chr * command.size +
|
203
|
+
" " * command.size +
|
204
|
+
8.chr * command.size)
|
205
|
+
@io_write.print(replacement)
|
206
|
+
command = replacement
|
207
|
+
end
|
208
|
+
elsif char == 8 || char == 127
|
209
|
+
if command.size > 0
|
210
|
+
command = command[0..-2]
|
211
|
+
@io_write.print(8.chr + " " + 8.chr)
|
212
|
+
end
|
213
|
+
else
|
214
|
+
command << char.chr
|
215
|
+
replacement = nil
|
216
|
+
if command.index("\e[A") != nil
|
217
|
+
command.gsub!("\e[A", "")
|
218
|
+
unless @key_up_proc.nil?
|
219
|
+
replacement =
|
220
|
+
@key_up_proc.call(command)
|
221
|
+
end
|
222
|
+
elsif command.index("\e[B") != nil
|
223
|
+
command.gsub!("\e[B", "")
|
224
|
+
unless @key_down_proc.nil?
|
225
|
+
replacement =
|
226
|
+
@key_down_proc.call(command)
|
227
|
+
end
|
228
|
+
elsif command.index("\e[C") != nil
|
229
|
+
command.gsub!("\e[C", "")
|
230
|
+
unless @key_right_proc.nil?
|
231
|
+
replacement =
|
232
|
+
@key_right_proc.call(command)
|
233
|
+
end
|
234
|
+
elsif command.index("\e[D") != nil
|
235
|
+
command.gsub!("\e[D", "")
|
236
|
+
unless @key_left_proc.nil?
|
237
|
+
replacement =
|
238
|
+
@key_left_proc.call(command)
|
239
|
+
end
|
240
|
+
else
|
241
|
+
if (char == "["[0] && command[-2] != "\e"[0]) ||
|
242
|
+
(char != "\e"[0] && char != "["[0])
|
243
|
+
@io_write.print(char.chr)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
if replacement != nil
|
247
|
+
@io_write.print(
|
248
|
+
8.chr * command.size +
|
249
|
+
" " * command.size +
|
250
|
+
8.chr * command.size)
|
251
|
+
@io_write.print(replacement)
|
252
|
+
command = replacement
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
return command
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
# Returns a single character without waiting for the enter key to be
|
261
|
+
# pressed.
|
262
|
+
def getc()
|
263
|
+
char = nil
|
264
|
+
begin
|
265
|
+
if @io_read == STDIN
|
266
|
+
if RUBY_PLATFORM =~ /mswin/
|
267
|
+
require "Win32API"
|
268
|
+
char = Win32API.new("crtdll", "_getch", [], "L").Call
|
269
|
+
else
|
270
|
+
begin
|
271
|
+
system("stty cbreak -echo")
|
272
|
+
char = @io_read.readchar()
|
273
|
+
ensure
|
274
|
+
system("stty -cbreak -echo")
|
275
|
+
end
|
276
|
+
end
|
277
|
+
else
|
278
|
+
char = @io_read.readchar()
|
279
|
+
end
|
280
|
+
rescue Interrupt
|
281
|
+
return 3
|
282
|
+
rescue Exception
|
283
|
+
return nil
|
284
|
+
end
|
285
|
+
return char
|
286
|
+
end
|
287
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/contrib/rubyforgepublisher'
|
8
|
+
|
9
|
+
PKG_NAME = 'rcommand'
|
10
|
+
PKG_VERSION = '0.1.0'
|
11
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
12
|
+
|
13
|
+
RELEASE_NAME = "REL #{PKG_VERSION}"
|
14
|
+
|
15
|
+
RUBY_FORGE_PROJECT = "rcommand"
|
16
|
+
RUBY_FORGE_USER = "sporkmonger"
|
17
|
+
|
18
|
+
PKG_FILES = FileList[
|
19
|
+
"lib/**/*", "test/**/*", "examples/**/*", "doc/**/*", "[A-Z]*", "install.rb", "rakefile"
|
20
|
+
].exclude(/\bCVS\b|~$/).exclude(/database\.yml/)
|
21
|
+
|
22
|
+
desc "Default Task"
|
23
|
+
task :default => [ :test_all ]
|
24
|
+
|
25
|
+
# Run the unit tests
|
26
|
+
|
27
|
+
Rake::TestTask.new("test_all") { |t|
|
28
|
+
t.libs << "test"
|
29
|
+
t.pattern = 'test/*_test.rb'
|
30
|
+
t.verbose = true
|
31
|
+
}
|
32
|
+
|
33
|
+
# Generate the RDoc documentation
|
34
|
+
|
35
|
+
Rake::RDocTask.new { |rdoc|
|
36
|
+
rdoc.rdoc_dir = 'doc'
|
37
|
+
rdoc.title = "RCommand -- generic interactive command handler"
|
38
|
+
rdoc.options << '--line-numbers' << '--inline-source' <<
|
39
|
+
'--accessor' << 'cattr_accessor=object'
|
40
|
+
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
41
|
+
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
42
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
43
|
+
}
|
44
|
+
|
45
|
+
# Create compressed packages
|
46
|
+
|
47
|
+
dist_dirs = [ "lib", "test" ]
|
48
|
+
|
49
|
+
spec = Gem::Specification.new do |s|
|
50
|
+
s.name = PKG_NAME
|
51
|
+
s.version = PKG_VERSION
|
52
|
+
s.summary = "Command handler."
|
53
|
+
s.description = "A generic interactive command handler."
|
54
|
+
|
55
|
+
s.files = [ "rakefile", "install.rb", "README", "CHANGELOG" ]
|
56
|
+
dist_dirs.each do |dir|
|
57
|
+
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if do |item|
|
58
|
+
item.include?( "\.svn" ) || item.include?( "database\.yml" )
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
s.require_path = 'lib'
|
63
|
+
s.autorequire = 'rcommand'
|
64
|
+
|
65
|
+
s.has_rdoc = true
|
66
|
+
s.extra_rdoc_files = %w( README )
|
67
|
+
s.rdoc_options.concat ['--main', 'README']
|
68
|
+
|
69
|
+
s.author = "Bob Aman"
|
70
|
+
s.email = "bob@sporkmonger.com"
|
71
|
+
s.homepage = "http://sporkmonger.com/projects/rcommand"
|
72
|
+
s.rubyforge_project = "rcommand"
|
73
|
+
end
|
74
|
+
|
75
|
+
Rake::GemPackageTask.new(spec) do |p|
|
76
|
+
p.gem_spec = spec
|
77
|
+
p.need_tar = true
|
78
|
+
p.need_zip = true
|
79
|
+
end
|
80
|
+
|
81
|
+
task :lines do
|
82
|
+
lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
|
83
|
+
|
84
|
+
for file_name in FileList["lib/**/*.rb"]
|
85
|
+
f = File.open(file_name)
|
86
|
+
|
87
|
+
while line = f.gets
|
88
|
+
lines += 1
|
89
|
+
next if line =~ /^\s*$/
|
90
|
+
next if line =~ /^\s*#/
|
91
|
+
codelines += 1
|
92
|
+
end
|
93
|
+
puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
|
94
|
+
|
95
|
+
total_lines += lines
|
96
|
+
total_codelines += codelines
|
97
|
+
|
98
|
+
lines, codelines = 0, 0
|
99
|
+
end
|
100
|
+
|
101
|
+
puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Publishing ------------------------------------------------------
|
106
|
+
|
107
|
+
desc "Publish the API documentation"
|
108
|
+
task :pdoc => [:rdoc] do
|
109
|
+
Rake::SshDirPublisher.new(
|
110
|
+
"vacindak@sporkmonger.com",
|
111
|
+
"public_html/projects/rcommand/api",
|
112
|
+
"doc").upload
|
113
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rcommand'
|
3
|
+
|
4
|
+
class CommandTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_command_history
|
9
|
+
command_line = RCommand.new(STDIN, STDOUT)
|
10
|
+
|
11
|
+
command_line << "first command"
|
12
|
+
command_line << "second command"
|
13
|
+
command_line << "third command"
|
14
|
+
|
15
|
+
assert_equal(nil, command_line.next())
|
16
|
+
assert_equal("third command", command_line.prev())
|
17
|
+
assert_equal("second command", command_line.prev())
|
18
|
+
assert_equal("first command", command_line.prev())
|
19
|
+
assert_equal("second command", command_line.next())
|
20
|
+
assert_equal("third command", command_line.next())
|
21
|
+
assert_equal("", command_line.next())
|
22
|
+
assert_equal(3, command_line.history.size)
|
23
|
+
|
24
|
+
command_line << "fourth command"
|
25
|
+
|
26
|
+
assert_equal(nil, command_line.next())
|
27
|
+
assert_equal("fourth command", command_line.prev())
|
28
|
+
assert_equal(4, command_line.history.size)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_command_matches
|
32
|
+
history = [
|
33
|
+
"good",
|
34
|
+
"better",
|
35
|
+
"best",
|
36
|
+
"bestest"
|
37
|
+
]
|
38
|
+
|
39
|
+
assert_equal(3, RCommand.matches("b", history).size)
|
40
|
+
assert_equal(3, RCommand.matches("be", history).size)
|
41
|
+
assert_equal(2, RCommand.matches("bes", history).size)
|
42
|
+
assert_equal(2, RCommand.matches("best", history).size)
|
43
|
+
assert_equal(1, RCommand.matches("beste", history).size)
|
44
|
+
assert_equal(1, RCommand.matches("bestes", history).size)
|
45
|
+
assert_equal(1, RCommand.matches("bestest", history).size)
|
46
|
+
|
47
|
+
assert_equal(1, RCommand.matches("g", history).size)
|
48
|
+
assert_equal(1, RCommand.matches("go", history).size)
|
49
|
+
assert_equal(1, RCommand.matches("goo", history).size)
|
50
|
+
assert_equal(1, RCommand.matches("good", history).size)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_command_common_prefix
|
54
|
+
assert_equal("",
|
55
|
+
RCommand.common_prefix(["good", "better", "best", "bestest"]))
|
56
|
+
assert_equal("be",
|
57
|
+
RCommand.common_prefix(["better", "best", "bestest"]))
|
58
|
+
assert_equal("best",
|
59
|
+
RCommand.common_prefix(["best", "bestest"]))
|
60
|
+
assert_equal("bestest",
|
61
|
+
RCommand.common_prefix(["bestest"]))
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: rcommand
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2006-03-27 00:00:00 -05:00
|
8
|
+
summary: Command handler.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: bob@sporkmonger.com
|
12
|
+
homepage: http://sporkmonger.com/projects/rcommand
|
13
|
+
rubyforge_project: rcommand
|
14
|
+
description: A generic interactive command handler.
|
15
|
+
autorequire: rcommand
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Bob Aman
|
31
|
+
files:
|
32
|
+
- rakefile
|
33
|
+
- install.rb
|
34
|
+
- README
|
35
|
+
- CHANGELOG
|
36
|
+
- lib/rcommand.rb
|
37
|
+
- test/command_test.rb
|
38
|
+
test_files: []
|
39
|
+
rdoc_options:
|
40
|
+
- "--main"
|
41
|
+
- README
|
42
|
+
extra_rdoc_files:
|
43
|
+
- README
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
requirements: []
|
47
|
+
dependencies: []
|