linen 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +72 -90
- data/examples/user.rb +51 -0
- data/lib/linen.rb +4 -3
- data/lib/linen/handlers/cli.rb +24 -16
- data/lib/linen/mixins/command_infrastructure.rb +91 -0
- data/lib/linen/simple_command.rb +3 -52
- data/lib/linen/two_phase_command.rb +3 -60
- data/spec/cli_spec.rb +47 -0
- data/spec/indifferent_hash_spec.rb +40 -0
- data/spec/plugins_spec.rb +35 -0
- metadata +11 -8
- data/test/test_cli.rb +0 -111
- data/test/test_indifferent_hash.rb +0 -51
- data/test/test_plugins.rb +0 -64
data/Rakefile
CHANGED
@@ -18,13 +18,13 @@
|
|
18
18
|
#
|
19
19
|
# == Version
|
20
20
|
#
|
21
|
-
# $Id: Rakefile
|
21
|
+
# $Id: Rakefile 399 2007-11-28 09:07:12Z bbleything $
|
22
22
|
#
|
23
23
|
|
24
24
|
require 'fileutils'
|
25
25
|
require 'rubygems'
|
26
26
|
require 'rake'
|
27
|
-
require 'rake/
|
27
|
+
require 'spec/rake/spectask'
|
28
28
|
require 'rake/rdoctask'
|
29
29
|
require 'rake/packagetask'
|
30
30
|
require 'rake/gempackagetask'
|
@@ -36,122 +36,104 @@ PKG_NAME = 'linen'
|
|
36
36
|
PKG_VERSION = Linen::VERSION
|
37
37
|
|
38
38
|
TEXT_FILES = %w( Rakefile README LICENSE )
|
39
|
-
TEST_FILES = Dir.glob('test/test_*').delete_if { |item| item.include?( "\.svn" ) }
|
40
39
|
LIB_FILES = Dir.glob('lib/**/*').delete_if { |item| item.include?( "\.svn" ) }
|
40
|
+
SPEC_FILES = Dir.glob('spec/*_spec.rb')
|
41
41
|
EXAMPLE_FILES = Dir.glob('examples/*.rb')
|
42
|
-
RELEASE_FILES = TEXT_FILES + LIB_FILES +
|
42
|
+
RELEASE_FILES = TEXT_FILES + LIB_FILES + SPEC_FILES + EXAMPLE_FILES
|
43
43
|
|
44
|
-
task :default =>
|
44
|
+
task :default => :spec
|
45
45
|
|
46
|
-
### Run the
|
47
|
-
Rake::
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
desc "Clean pkg, coverage, and rdoc; remove .bak files"
|
55
|
-
task :clean => [ :clobber_rdoc, :clobber_package, :clobber_coverage ] do
|
56
|
-
puts cmd = "find . -type f -name *.bak -delete"
|
57
|
-
`#{cmd}`
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
task :clobber_coverage do
|
62
|
-
puts cmd = "rm -rf coverage"
|
63
|
-
`#{cmd}`
|
46
|
+
### Run the specifications
|
47
|
+
Spec::Rake::SpecTask.new do |r|
|
48
|
+
r.rcov = true
|
49
|
+
r.rcov_dir = 'coverage'
|
50
|
+
r.libs = SPEC_FILES
|
51
|
+
r.spec_opts = %w(--format specdoc --color)
|
64
52
|
end
|
65
53
|
|
66
54
|
|
67
|
-
desc "
|
68
|
-
task :
|
69
|
-
|
70
|
-
|
55
|
+
desc "Clean pkg, coverage, and rdoc; remove .bak files"
|
56
|
+
task :clean => [ :clobber_rdoc, :clobber_package, :clobber_spec ] do
|
57
|
+
puts cmd = "find . -type f -name *.bak -delete"
|
58
|
+
`#{cmd}`
|
71
59
|
end
|
72
60
|
|
73
|
-
|
74
61
|
desc "Strip trailing whitespace and fix newlines for all release files"
|
75
62
|
task :fix_whitespace => [ :clean ] do
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
desc "Copy documentation to rubyforge"
|
115
|
-
task :update_rdoc => [ :rdoc ] do
|
116
|
-
Rake::SshDirPublisher.new("#{RUBYFORGE_USER}@rubyforge.org", "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}", "rdoc").upload
|
63
|
+
RELEASE_FILES.each do |filename|
|
64
|
+
next if File.directory? filename
|
65
|
+
|
66
|
+
File.open(filename) do |file|
|
67
|
+
newfile = ''
|
68
|
+
needs_love = false
|
69
|
+
|
70
|
+
file.readlines.each_with_index do |line, lineno|
|
71
|
+
if line =~ /[ \t]+$/
|
72
|
+
needs_love = true
|
73
|
+
puts "#{filename}: trailing whitespace on line #{lineno}"
|
74
|
+
line.gsub!(/[ \t]*$/, '')
|
75
|
+
end
|
76
|
+
|
77
|
+
if line.chomp == line
|
78
|
+
needs_love = true
|
79
|
+
puts "#{filename}: no newline on line #{lineno}"
|
80
|
+
line << "\n"
|
81
|
+
end
|
82
|
+
|
83
|
+
newfile << line
|
84
|
+
end
|
85
|
+
|
86
|
+
if needs_love
|
87
|
+
tempname = "#{filename}.new"
|
88
|
+
|
89
|
+
File.open(tempname, 'w').write(newfile)
|
90
|
+
File.chmod(File.stat(filename).mode, tempname)
|
91
|
+
|
92
|
+
FileUtils.ln filename, "#{filename}.bak"
|
93
|
+
FileUtils.ln tempname, filename, :force => true
|
94
|
+
File.unlink(tempname)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
117
98
|
end
|
118
99
|
|
119
100
|
|
120
101
|
### Genereate the RDoc documentation
|
121
102
|
Rake::RDocTask.new { |rdoc|
|
122
|
-
|
123
|
-
|
124
|
-
|
103
|
+
rdoc.rdoc_dir = 'rdoc'
|
104
|
+
rdoc.title = "Linen - A pluggable command-line interface library"
|
105
|
+
rdoc.options << '-SNmREADME'
|
125
106
|
|
126
|
-
|
127
|
-
|
128
|
-
|
107
|
+
rdoc.rdoc_files.include TEXT_FILES
|
108
|
+
rdoc.rdoc_files.include LIB_FILES
|
109
|
+
rdoc.rdoc_files.include Dir.glob('docs/**').delete_if {|f| f.include? 'jamis' }
|
129
110
|
}
|
130
111
|
|
131
112
|
|
132
113
|
### Create compressed packages
|
133
114
|
spec = Gem::Specification.new do |s|
|
134
|
-
|
135
|
-
|
115
|
+
s.name = PKG_NAME
|
116
|
+
s.version = PKG_VERSION
|
136
117
|
|
137
|
-
|
138
|
-
|
139
|
-
Linen is a library which can be used to build a command-line interface for any purpose. It features a plugin architecture to specify new tasks, Readline support, history, and more.
|
140
|
-
|
118
|
+
s.summary = "Linen - A pluggable command-line interface library"
|
119
|
+
s.description = <<-EOD
|
120
|
+
Linen is a library which can be used to build a command-line interface for any purpose. It features a plugin architecture to specify new tasks, Readline support, history, and more.
|
121
|
+
EOD
|
141
122
|
|
142
|
-
|
143
|
-
|
123
|
+
s.authors = "LAIKA, Inc."
|
124
|
+
s.homepage = "http://opensource.laika.com"
|
144
125
|
|
145
|
-
|
126
|
+
s.has_rdoc = true
|
146
127
|
|
147
|
-
|
148
|
-
|
128
|
+
s.files = RELEASE_FILES
|
129
|
+
s.test_files = SPEC_FILES
|
149
130
|
|
150
|
-
|
131
|
+
s.autorequire = 'linen'
|
151
132
|
end
|
152
133
|
|
134
|
+
|
153
135
|
Rake::GemPackageTask.new(spec) do |p|
|
154
|
-
|
155
|
-
|
156
|
-
|
136
|
+
p.gem_spec = spec
|
137
|
+
p.need_tar = true
|
138
|
+
p.need_zip = true
|
157
139
|
end
|
data/examples/user.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Demonstrates the use of argument options by way
|
4
|
+
# of hidden prompts.
|
5
|
+
#
|
6
|
+
# == Authors
|
7
|
+
#
|
8
|
+
# * Ben Bleything <bbleything@laika.com>
|
9
|
+
#
|
10
|
+
# == Copyright
|
11
|
+
#
|
12
|
+
# Copyright (c) 2007 Laika, Inc.
|
13
|
+
#
|
14
|
+
# This code released under the terms of the BSD license.
|
15
|
+
#
|
16
|
+
# == Version
|
17
|
+
#
|
18
|
+
# $Id: host.rb 274 2007-07-25 21:06:42Z bbleything $
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'rubygems'
|
22
|
+
require 'linen'
|
23
|
+
|
24
|
+
class UserPlugin < Linen::Plugin
|
25
|
+
description "Demonstrate a simple login action."
|
26
|
+
|
27
|
+
argument :username,
|
28
|
+
:prompt => 'Please enter your username: ',
|
29
|
+
:regex => /^\w+$/
|
30
|
+
|
31
|
+
argument :password,
|
32
|
+
:prompt => "Password (hint: it's your username, backwards): ",
|
33
|
+
:hide_input => true
|
34
|
+
|
35
|
+
command :login do
|
36
|
+
help_message "Attempts to log you in to a fake service."
|
37
|
+
|
38
|
+
required_arguments :username, :password
|
39
|
+
|
40
|
+
action do
|
41
|
+
if password == username.reverse
|
42
|
+
say "Login successful!"
|
43
|
+
else
|
44
|
+
say "Login failed :("
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Linen::CLI.prompt = "user > "
|
51
|
+
Linen.start
|
data/lib/linen.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
#
|
17
17
|
# == Version
|
18
18
|
#
|
19
|
-
# $Id: linen.rb
|
19
|
+
# $Id: linen.rb 407 2007-12-14 17:13:55Z bbleything $
|
20
20
|
#
|
21
21
|
|
22
22
|
### External libraries
|
@@ -30,8 +30,8 @@ require 'string_extensions'
|
|
30
30
|
|
31
31
|
|
32
32
|
module Linen
|
33
|
-
VERSION = "0.8.
|
34
|
-
SVNRev = %q$Rev:
|
33
|
+
VERSION = "0.8.2"
|
34
|
+
SVNRev = %q$Rev: 407 $
|
35
35
|
|
36
36
|
|
37
37
|
def self::plugins
|
@@ -50,6 +50,7 @@ end
|
|
50
50
|
require 'linen/plugin_registry'
|
51
51
|
require 'linen/plugin'
|
52
52
|
require 'linen/argument'
|
53
|
+
require 'linen/mixins/command_infrastructure'
|
53
54
|
require 'linen/simple_command'
|
54
55
|
require 'linen/two_phase_command'
|
55
56
|
|
data/lib/linen/handlers/cli.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
#
|
17
17
|
# == Version
|
18
18
|
#
|
19
|
-
# $Id: cli.rb
|
19
|
+
# $Id: cli.rb 407 2007-12-14 17:13:55Z bbleything $
|
20
20
|
#
|
21
21
|
|
22
22
|
class Linen::CLI < Linen::Handler
|
@@ -161,16 +161,20 @@ class Linen::CLI < Linen::Handler
|
|
161
161
|
|
162
162
|
input = ''
|
163
163
|
if command.requires_confirmation?
|
164
|
-
|
164
|
+
if command.can_inspect?
|
165
|
+
command.inspect( workspace )
|
166
|
+
else
|
167
|
+
puts "\nRunning '#{plugin.short_name} #{command.name}' with arguments:"
|
165
168
|
|
166
|
-
|
167
|
-
|
169
|
+
puts results.map { |arg, value|
|
170
|
+
next unless value
|
168
171
|
|
169
|
-
|
170
|
-
|
172
|
+
output = value
|
173
|
+
output = value.join( ', ' ) if value.is_a? Array
|
171
174
|
|
172
|
-
|
173
|
-
|
175
|
+
"#{arg}: #{output}"
|
176
|
+
}.join( "\n" )
|
177
|
+
end
|
174
178
|
|
175
179
|
while input !~ /^(y|n)/i
|
176
180
|
input = Readline.readline( "\nContinue [y/N]? ")
|
@@ -201,7 +205,7 @@ enter. Otherwise, enter a new value.
|
|
201
205
|
Current values
|
202
206
|
--------------
|
203
207
|
END
|
204
|
-
command.inspect( workspace )
|
208
|
+
command.inspect( workspace ) # inspects are required for two-phase commands
|
205
209
|
puts # blank line for clarity
|
206
210
|
|
207
211
|
current_values = command.editable_attrs.inject( Hash.new ) {|hash, value|
|
@@ -215,16 +219,20 @@ END
|
|
215
219
|
|
216
220
|
input = ''
|
217
221
|
if command.requires_confirmation?
|
218
|
-
|
222
|
+
if command.can_inspect?
|
223
|
+
command.inspect( workspace )
|
224
|
+
else
|
225
|
+
puts "\nRunning '#{plugin.short_name} #{command.name}' with arguments:"
|
219
226
|
|
220
|
-
|
221
|
-
|
227
|
+
puts results.map { |arg, value|
|
228
|
+
next unless value
|
222
229
|
|
223
|
-
|
224
|
-
|
230
|
+
output = value
|
231
|
+
output = value.join( ', ' ) if value.is_a? Array
|
225
232
|
|
226
|
-
|
227
|
-
|
233
|
+
"#{arg}: #{output}"
|
234
|
+
}.join( "\n" )
|
235
|
+
end
|
228
236
|
|
229
237
|
while input !~ /^(y|n)/i
|
230
238
|
input = Readline.readline( "\nContinue [y/N]? ")
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Common methods factored out of the command classes.
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * Ben Bleything <bbleything@laika.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2007 Laika, Inc.
|
12
|
+
#
|
13
|
+
# This code released under the terms of the BSD license.
|
14
|
+
#
|
15
|
+
# == Version
|
16
|
+
#
|
17
|
+
# $Id: simple_command.rb 391 2007-11-19 22:21:55Z bbleything $
|
18
|
+
#
|
19
|
+
|
20
|
+
module Linen::Plugin::CommandInfrastructure
|
21
|
+
def initialize( plugin, name, &block )
|
22
|
+
@plugin = plugin
|
23
|
+
@name = name
|
24
|
+
@arguments = []
|
25
|
+
@help_text = "No help for #{plugin.short_name} #{name}"
|
26
|
+
|
27
|
+
self.instance_eval &block
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def execute( workspace = Linen::Workspace.new )
|
32
|
+
return workspace.instance_eval( &@action_proc )
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def help
|
37
|
+
output = []
|
38
|
+
|
39
|
+
output << @help_text.wrap
|
40
|
+
output << nil # blank line
|
41
|
+
|
42
|
+
# this map turns our list of args into a list like this:
|
43
|
+
# <arg1> <arg2> <arg3> <arg4>...
|
44
|
+
arg_list = @arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
|
45
|
+
|
46
|
+
output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
|
47
|
+
|
48
|
+
return output.join( "\n" )
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#############################
|
53
|
+
# PLUGIN DEFINITION METHODS #
|
54
|
+
#############################
|
55
|
+
|
56
|
+
def help_message( message )
|
57
|
+
@help_text = message
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def action( &block )
|
62
|
+
@action_proc = block
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def require_confirmation
|
67
|
+
@require_confirmation = true
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
def inspect( workspace = Linen::Workspace.new, &block )
|
72
|
+
if block_given?
|
73
|
+
@inspect_proc = block
|
74
|
+
else
|
75
|
+
return workspace.instance_eval( &@inspect_proc )
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
##################
|
81
|
+
# HELPER METHODS #
|
82
|
+
##################
|
83
|
+
|
84
|
+
def requires_confirmation?
|
85
|
+
@require_confirmation
|
86
|
+
end
|
87
|
+
|
88
|
+
def can_inspect?
|
89
|
+
@inspect_proc
|
90
|
+
end
|
91
|
+
end
|
data/lib/linen/simple_command.rb
CHANGED
@@ -14,48 +14,18 @@
|
|
14
14
|
#
|
15
15
|
# == Version
|
16
16
|
#
|
17
|
-
# $Id: simple_command.rb
|
17
|
+
# $Id: simple_command.rb 407 2007-12-14 17:13:55Z bbleything $
|
18
18
|
#
|
19
19
|
|
20
20
|
class Linen::Plugin::SimpleCommand
|
21
|
-
|
22
|
-
|
23
|
-
def initialize( plugin, name, &block )
|
24
|
-
@plugin = plugin
|
25
|
-
@name = name
|
26
|
-
@arguments = []
|
27
|
-
@help_text = "No help for #{plugin.short_name} #{name}"
|
28
|
-
|
29
|
-
self.instance_eval &block
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
def execute( workspace = Linen::Workspace.new )
|
34
|
-
return workspace.instance_eval( &@action_proc )
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
def help
|
39
|
-
output = []
|
40
|
-
|
41
|
-
output << @help_text.wrap
|
42
|
-
output << nil # blank line
|
43
|
-
|
44
|
-
# this map turns our list of args into a list like this:
|
45
|
-
# <arg1> <arg2> <arg3> <arg4>...
|
46
|
-
arg_list = @arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
|
47
|
-
|
48
|
-
output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
|
49
|
-
|
50
|
-
return output.join( "\n" )
|
51
|
-
end
|
21
|
+
include Linen::Plugin::CommandInfrastructure
|
52
22
|
|
23
|
+
attr_reader :name
|
53
24
|
|
54
25
|
#############################
|
55
26
|
# PLUGIN DEFINITION METHODS #
|
56
27
|
#############################
|
57
28
|
|
58
|
-
|
59
29
|
def one_of( *args )
|
60
30
|
raise Linen::Plugin::ArgumentError,
|
61
31
|
"You may not specify both required and one_of arguments" if @argument_type == :required
|
@@ -87,21 +57,6 @@ class Linen::Plugin::SimpleCommand
|
|
87
57
|
alias required_argument required_arguments
|
88
58
|
|
89
59
|
|
90
|
-
def help_message( message )
|
91
|
-
@help_text = message
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def action( &block )
|
96
|
-
@action_proc = block
|
97
|
-
end
|
98
|
-
|
99
|
-
|
100
|
-
def require_confirmation
|
101
|
-
@require_confirmation = true
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
60
|
##################
|
106
61
|
# HELPER METHODS #
|
107
62
|
##################
|
@@ -119,10 +74,6 @@ class Linen::Plugin::SimpleCommand
|
|
119
74
|
end
|
120
75
|
|
121
76
|
|
122
|
-
def requires_confirmation?
|
123
|
-
@require_confirmation
|
124
|
-
end
|
125
|
-
|
126
77
|
#######
|
127
78
|
private
|
128
79
|
#######
|
@@ -14,41 +14,13 @@
|
|
14
14
|
#
|
15
15
|
# == Version
|
16
16
|
#
|
17
|
-
# $Id: two_phase_command.rb
|
17
|
+
# $Id: two_phase_command.rb 407 2007-12-14 17:13:55Z bbleything $
|
18
18
|
#
|
19
19
|
|
20
20
|
class Linen::Plugin::TwoPhaseCommand
|
21
|
-
|
22
|
-
|
23
|
-
def initialize( plugin, name, &block )
|
24
|
-
@plugin = plugin
|
25
|
-
@name = name
|
26
|
-
@arguments = []
|
27
|
-
@help_text = "No help for #{plugin.short_name} #{name}"
|
28
|
-
|
29
|
-
self.instance_eval &block
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
def execute( workspace = Linen::Workspace.new )
|
34
|
-
return workspace.instance_eval( &@action_proc )
|
35
|
-
end
|
36
|
-
|
21
|
+
include Linen::Plugin::CommandInfrastructure
|
37
22
|
|
38
|
-
|
39
|
-
output = []
|
40
|
-
|
41
|
-
output << @help_text.wrap
|
42
|
-
output << nil # blank line
|
43
|
-
|
44
|
-
# this map turns our list of args into a list like this:
|
45
|
-
# <arg1> <arg2> <arg3> <arg4>...
|
46
|
-
arg_list = @arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
|
47
|
-
|
48
|
-
output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
|
49
|
-
|
50
|
-
return output.join( "\n" )
|
51
|
-
end
|
23
|
+
attr_reader :name, :editable_attrs, :lookup_attr
|
52
24
|
|
53
25
|
|
54
26
|
#############################
|
@@ -64,32 +36,8 @@ class Linen::Plugin::TwoPhaseCommand
|
|
64
36
|
def editable_attributes( *attr_list )
|
65
37
|
@editable_attrs = attr_list
|
66
38
|
end
|
67
|
-
|
68
|
-
|
69
|
-
def help_message( message )
|
70
|
-
@help_text = message
|
71
|
-
end
|
72
|
-
|
73
|
-
|
74
|
-
def action( &block )
|
75
|
-
@action_proc = block
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
def require_confirmation
|
80
|
-
@require_confirmation = true
|
81
|
-
end
|
82
39
|
|
83
40
|
|
84
|
-
def inspect( workspace = Linen::Workspace.new, &block )
|
85
|
-
if block_given?
|
86
|
-
@inspect_proc = block
|
87
|
-
else
|
88
|
-
return workspace.instance_eval( &@inspect_proc )
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
41
|
##################
|
94
42
|
# HELPER METHODS #
|
95
43
|
##################
|
@@ -144,9 +92,4 @@ class Linen::Plugin::TwoPhaseCommand
|
|
144
92
|
|
145
93
|
return results
|
146
94
|
end
|
147
|
-
|
148
|
-
|
149
|
-
def requires_confirmation?
|
150
|
-
@require_confirmation
|
151
|
-
end
|
152
95
|
end
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Contains the specifications for the Linen::CLI class
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * Ben Bleything <bbleything@laika.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2007 Laika, Inc.
|
12
|
+
#
|
13
|
+
# This code released under the terms of the BSD license.
|
14
|
+
#
|
15
|
+
# == Version
|
16
|
+
#
|
17
|
+
# $Id: cli_spec.rb 399 2007-11-28 09:07:12Z bbleything $
|
18
|
+
#
|
19
|
+
|
20
|
+
require File.join(File.dirname(__FILE__),"spec_helper.rb")
|
21
|
+
|
22
|
+
describe "The CLI Handler's completion facility" do
|
23
|
+
include CompletionMatchers
|
24
|
+
|
25
|
+
it "raises an AmbiguousPluginError when it cannot canonicalize a plugin name" do
|
26
|
+
completing( '' ).should be_ambiguous
|
27
|
+
completing( 'te ' ).should be_ambiguous
|
28
|
+
|
29
|
+
completing( 'tes' ).should_not be_ambiguous
|
30
|
+
completing( 'tea' ).should_not be_ambiguous
|
31
|
+
completing( 'h' ).should_not be_ambiguous
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises an AmbiguousCommandError when it cannot canonicalize a command name" do
|
35
|
+
test_commands = Linen.plugins[ 'test' ].commands.keys.map {|k| k.to_s}.sort
|
36
|
+
starts_with_ad = test_commands.select {|c| c =~ /^ad/}
|
37
|
+
|
38
|
+
completing( 'tes ' ).should be_ambiguous
|
39
|
+
completing( 'test ' ).should be_ambiguous
|
40
|
+
|
41
|
+
lambda { Linen::CLI.expand_command( 'tes ad' ) }.should suggest_candidates( starts_with_ad )
|
42
|
+
lambda { Linen::CLI.expand_command( 'test ad' ) }.should suggest_candidates( starts_with_ad )
|
43
|
+
|
44
|
+
completing( 'tes adm' ).should expand_to( 'test administer' )
|
45
|
+
completing( 'test adm' ).should expand_to( 'test administer' )
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Contains the specifications for the IndifferentHash class
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * Ben Bleything <bbleything@laika.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2007 Laika, Inc.
|
12
|
+
#
|
13
|
+
# This code released under the terms of the BSD license.
|
14
|
+
#
|
15
|
+
# == Version
|
16
|
+
#
|
17
|
+
# $Id: indifferent_hash_spec.rb 399 2007-11-28 09:07:12Z bbleything $
|
18
|
+
#
|
19
|
+
|
20
|
+
require File.join(File.dirname(__FILE__),"spec_helper.rb")
|
21
|
+
|
22
|
+
describe IndifferentHash do
|
23
|
+
before( :all ) do
|
24
|
+
@ihash = IndifferentHash.new
|
25
|
+
@ihash[ :key ] = "value"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "doesn't care if you look up an entry via a string or symbol" do
|
29
|
+
@ihash[ :key ].should == "value"
|
30
|
+
@ihash[ 'key' ].should == "value"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "prefers matching key types when it is ambiguous" do
|
34
|
+
@ihash[ 'ambiguous' ] = "string"
|
35
|
+
@ihash[ :ambiguous ] = "symbol"
|
36
|
+
|
37
|
+
@ihash[ 'ambiguous' ].should == "string"
|
38
|
+
@ihash[ :ambiguous ].should == "symbol"
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Contains the specifications for the IndifferentHash class
|
4
|
+
#
|
5
|
+
# == Authors
|
6
|
+
#
|
7
|
+
# * Ben Bleything <bbleything@laika.com>
|
8
|
+
#
|
9
|
+
# == Copyright
|
10
|
+
#
|
11
|
+
# Copyright (c) 2007 Laika, Inc.
|
12
|
+
#
|
13
|
+
# This code released under the terms of the BSD license.
|
14
|
+
#
|
15
|
+
# == Version
|
16
|
+
#
|
17
|
+
# $Id: plugins_spec.rb 399 2007-11-28 09:07:12Z bbleything $
|
18
|
+
#
|
19
|
+
|
20
|
+
require File.join(File.dirname(__FILE__),"spec_helper.rb")
|
21
|
+
|
22
|
+
describe "The plugin help system" do
|
23
|
+
it "can find plugin help" do
|
24
|
+
HelpfulPlugin.help.should match( /plugin help/ )
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can find command help" do
|
28
|
+
HelpfulPlugin.commands[ :test ].help.should match( /command help/ )
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns a notice when no help is available" do
|
32
|
+
TestPlugin.help.should match( /^No help for test/ )
|
33
|
+
TestPlugin.commands[ :add ].help.should match( /^No help for test add/ )
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: linen
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.8.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.8.2
|
7
|
+
date: 2007-12-14 00:00:00 -08:00
|
8
8
|
summary: Linen - A pluggable command-line interface library
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -39,6 +39,8 @@ files:
|
|
39
39
|
- lib/linen/handler.rb
|
40
40
|
- lib/linen/handlers
|
41
41
|
- lib/linen/handlers/cli.rb
|
42
|
+
- lib/linen/mixins
|
43
|
+
- lib/linen/mixins/command_infrastructure.rb
|
42
44
|
- lib/linen/plugin.rb
|
43
45
|
- lib/linen/plugin_registry.rb
|
44
46
|
- lib/linen/simple_command.rb
|
@@ -46,15 +48,16 @@ files:
|
|
46
48
|
- lib/linen/workspace.rb
|
47
49
|
- lib/linen.rb
|
48
50
|
- lib/string_extensions.rb
|
49
|
-
-
|
50
|
-
-
|
51
|
-
-
|
51
|
+
- spec/cli_spec.rb
|
52
|
+
- spec/indifferent_hash_spec.rb
|
53
|
+
- spec/plugins_spec.rb
|
52
54
|
- examples/host.rb
|
53
55
|
- examples/math.rb
|
56
|
+
- examples/user.rb
|
54
57
|
test_files:
|
55
|
-
-
|
56
|
-
-
|
57
|
-
-
|
58
|
+
- spec/cli_spec.rb
|
59
|
+
- spec/indifferent_hash_spec.rb
|
60
|
+
- spec/plugins_spec.rb
|
58
61
|
rdoc_options: []
|
59
62
|
|
60
63
|
extra_rdoc_files: []
|
data/test/test_cli.rb
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
##############################################################
|
4
|
-
# Copyright 2007, LAIKA, Inc. #
|
5
|
-
# #
|
6
|
-
# Authors: #
|
7
|
-
# * Ben Bleything <bbleything@laika.com> #
|
8
|
-
##############################################################
|
9
|
-
|
10
|
-
require 'test/unit'
|
11
|
-
require 'linen'
|
12
|
-
|
13
|
-
class TestCLICommandCompletion < Test::Unit::TestCase
|
14
|
-
|
15
|
-
################
|
16
|
-
# test plugins #
|
17
|
-
################
|
18
|
-
|
19
|
-
class ::TestPlugin < Linen::Plugin
|
20
|
-
command :add do;end
|
21
|
-
command :administer do;end
|
22
|
-
command :somethingelse do;end
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
class ::TeaPlugin < Linen::Plugin
|
27
|
-
command :foo do;end
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
class ::OtherPlugin < Linen::Plugin
|
32
|
-
command :food do;end
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
#########
|
37
|
-
# tests #
|
38
|
-
#########
|
39
|
-
|
40
|
-
def test_plugin_completion
|
41
|
-
all_plugins = Linen.plugins.map {|p| p.short_name}.sort
|
42
|
-
|
43
|
-
assert_raises_plugin_ambiguity_error( all_plugins ) do
|
44
|
-
complete ''
|
45
|
-
end
|
46
|
-
|
47
|
-
assert_raises_plugin_ambiguity_error( all_plugins.select {|p| p =~ /^te/} ) do
|
48
|
-
complete 'te'
|
49
|
-
end
|
50
|
-
|
51
|
-
assert_nothing_raised do
|
52
|
-
### strip'ing because completion returns it with a trailing space
|
53
|
-
assert_equal "test", complete( 'tes' ).strip
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
def test_command_completion
|
59
|
-
test_commands = Linen.plugins[ 'test' ].commands.keys.map {|k| k.to_s}.sort
|
60
|
-
|
61
|
-
assert_raises_command_ambiguity_error( test_commands ) do
|
62
|
-
complete 'tes '
|
63
|
-
end
|
64
|
-
|
65
|
-
assert_raises_command_ambiguity_error( test_commands ) do
|
66
|
-
complete 'test '
|
67
|
-
end
|
68
|
-
|
69
|
-
starts_with_ad = test_commands.select {|c| c =~ /^ad/}
|
70
|
-
|
71
|
-
assert_raises_command_ambiguity_error( starts_with_ad ) do
|
72
|
-
assert_equal "test ad", complete( 'test ad' )
|
73
|
-
end
|
74
|
-
|
75
|
-
assert_raises_command_ambiguity_error( starts_with_ad ) do
|
76
|
-
assert_equal "test ad", complete( 'tes ad' )
|
77
|
-
end
|
78
|
-
|
79
|
-
assert_nothing_raised do
|
80
|
-
### strip'ing because completion returns it with a trailing space
|
81
|
-
assert_equal "test administer", complete( 'test adm' ).strip
|
82
|
-
assert_equal "test administer", complete( 'tes adm' ).strip
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
#######
|
88
|
-
private
|
89
|
-
#######
|
90
|
-
def complete( str )
|
91
|
-
return Linen::CLI.expand_command( str )
|
92
|
-
end
|
93
|
-
|
94
|
-
def assert_raises_ambiguity_error( exception, candidates, &block )
|
95
|
-
begin
|
96
|
-
block.call
|
97
|
-
rescue exception => e
|
98
|
-
assert_equal candidates, e.candidates
|
99
|
-
else
|
100
|
-
flunk 'no exception raised!'
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def assert_raises_plugin_ambiguity_error( candidates, &block )
|
105
|
-
assert_raises_ambiguity_error Linen::CLI::AmbiguousPluginError, candidates, &block
|
106
|
-
end
|
107
|
-
|
108
|
-
def assert_raises_command_ambiguity_error( candidates, &block )
|
109
|
-
assert_raises_ambiguity_error Linen::CLI::AmbiguousCommandError, candidates, &block
|
110
|
-
end
|
111
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
##############################################################
|
4
|
-
# Copyright 2007, LAIKA, Inc. #
|
5
|
-
# #
|
6
|
-
# Authors: #
|
7
|
-
# * Ben Bleything <bbleything@laika.com> #
|
8
|
-
##############################################################
|
9
|
-
|
10
|
-
require 'test/unit'
|
11
|
-
require 'indifferent_hash'
|
12
|
-
|
13
|
-
class TestIndifferentHash < Test::Unit::TestCase
|
14
|
-
def setup
|
15
|
-
@rhash = {
|
16
|
-
:symbol => 'regular symbol',
|
17
|
-
'string' => 'regular string'
|
18
|
-
}
|
19
|
-
|
20
|
-
@ihash = IndifferentHash.new
|
21
|
-
@ihash[ :symbol ] = 'indifferent symbol'
|
22
|
-
@ihash[ 'string' ] = 'indifferent string'
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
def test_string_to_symbol_lookups
|
27
|
-
key = 'symbol'
|
28
|
-
|
29
|
-
assert_nil @rhash[ key ]
|
30
|
-
assert_equal 'indifferent symbol', @ihash[ key ]
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
def test_symbol_to_string_lookups
|
35
|
-
key = :string
|
36
|
-
|
37
|
-
assert_nil @rhash[ key ]
|
38
|
-
assert_equal 'indifferent string', @ihash[ key ]
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
def test_literal_key_priority
|
43
|
-
ihash = IndifferentHash.new
|
44
|
-
|
45
|
-
ihash[ :key ] = "symbol"
|
46
|
-
ihash[ 'key' ] = "string"
|
47
|
-
|
48
|
-
assert_equal "symbol", ihash[ :key ]
|
49
|
-
assert_equal "string", ihash[ 'key' ]
|
50
|
-
end
|
51
|
-
end
|
data/test/test_plugins.rb
DELETED
@@ -1,64 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
##############################################################
|
4
|
-
# Copyright 2007, LAIKA, Inc. #
|
5
|
-
# #
|
6
|
-
# Authors: #
|
7
|
-
# * Ben Bleything <bbleything@laika.com> #
|
8
|
-
##############################################################
|
9
|
-
|
10
|
-
require 'test/unit'
|
11
|
-
require 'linen'
|
12
|
-
|
13
|
-
### a little helper for later
|
14
|
-
class String
|
15
|
-
def to_regex
|
16
|
-
return /#{self}/
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
class TestPlugins < Test::Unit::TestCase
|
22
|
-
|
23
|
-
########################
|
24
|
-
# "constant" variables #
|
25
|
-
########################
|
26
|
-
|
27
|
-
@description = "This is some descriptions"
|
28
|
-
@help_msg = "This is some help messagesess"
|
29
|
-
class << self
|
30
|
-
attr_reader :description, :help_msg
|
31
|
-
end
|
32
|
-
|
33
|
-
################
|
34
|
-
# test plugins #
|
35
|
-
################
|
36
|
-
|
37
|
-
class ::HelpfulPlugin < Linen::Plugin
|
38
|
-
description TestPlugins.description
|
39
|
-
|
40
|
-
command :test do
|
41
|
-
help_message TestPlugins.help_msg
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
class ::UnhelpfulPlugin < Linen::Plugin
|
47
|
-
command :test do;end
|
48
|
-
end
|
49
|
-
|
50
|
-
#########
|
51
|
-
# tests #
|
52
|
-
#########
|
53
|
-
|
54
|
-
def test_plugin_help
|
55
|
-
assert HelpfulPlugin.help =~ TestPlugins.description.to_regex
|
56
|
-
assert UnhelpfulPlugin.help =~ /No help for unhelpful/
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
def test_command_help
|
61
|
-
assert HelpfulPlugin.commands[ :test ].help =~ TestPlugins.help_msg.to_regex
|
62
|
-
assert UnhelpfulPlugin.commands[ :test ].help =~ /No help for unhelpful test/
|
63
|
-
end
|
64
|
-
end
|