linen 0.8.1 → 0.8.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.
- 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
|