linen 0.5.0 → 0.6.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/lib/linen.rb +4 -3
- data/lib/linen/argument.rb +13 -1
- data/lib/linen/exceptions.rb +2 -1
- data/lib/linen/handlers/cli.rb +74 -8
- data/lib/linen/plugin.rb +8 -2
- data/lib/linen/{command.rb → simple_command.rb} +1 -1
- data/lib/linen/two_phase_command.rb +177 -0
- metadata +3 -2
data/lib/linen.rb
CHANGED
@@ -18,8 +18,8 @@ require 'string_extensions'
|
|
18
18
|
|
19
19
|
|
20
20
|
module Linen
|
21
|
-
VERSION = "0.
|
22
|
-
SVNRev = %q$Rev:
|
21
|
+
VERSION = "0.6.0"
|
22
|
+
SVNRev = %q$Rev: 137 $
|
23
23
|
|
24
24
|
|
25
25
|
def self::plugins
|
@@ -38,7 +38,8 @@ end
|
|
38
38
|
require 'linen/plugin_registry'
|
39
39
|
require 'linen/plugin'
|
40
40
|
require 'linen/argument'
|
41
|
-
require 'linen/
|
41
|
+
require 'linen/simple_command'
|
42
|
+
require 'linen/two_phase_command'
|
42
43
|
|
43
44
|
|
44
45
|
### handlers
|
data/lib/linen/argument.rb
CHANGED
@@ -19,7 +19,19 @@ class Linen::Plugin::Argument
|
|
19
19
|
end
|
20
20
|
|
21
21
|
|
22
|
-
def process( value )
|
22
|
+
def process( value, opts_hash = IndifferentHash.new )
|
23
|
+
opts_hash[ :mode ] ||= :simple
|
24
|
+
|
25
|
+
# if we're in edit mode, we need to take care of a couple of
|
26
|
+
# special cases before falling into the regular handling loop
|
27
|
+
if opts_hash[ :mode ] == :edit or opts_hash[ :mode ] == 'edit'
|
28
|
+
if value.empty? # means the user just hit enter. Return nil to indicate the value should be left alone
|
29
|
+
return nil
|
30
|
+
elsif value =~ /^\s+$/ # user entered only spaces. Empty string means "clear out previous value"
|
31
|
+
return ""
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
23
35
|
raise Linen::Plugin::ArgumentError unless value =~ @regex
|
24
36
|
return value unless @process
|
25
37
|
|
data/lib/linen/exceptions.rb
CHANGED
data/lib/linen/handlers/cli.rb
CHANGED
@@ -58,6 +58,9 @@ class Linen::CLI < Linen::Handler
|
|
58
58
|
else
|
59
59
|
plugin, command, *args = canonicalize( input ).split
|
60
60
|
|
61
|
+
plugin = Linen.plugins[ plugin ]
|
62
|
+
command = plugin.commands[ command ]
|
63
|
+
|
61
64
|
execute_command plugin, command, args
|
62
65
|
end
|
63
66
|
end
|
@@ -82,9 +85,9 @@ class Linen::CLI < Linen::Handler
|
|
82
85
|
private
|
83
86
|
#######
|
84
87
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
+
def self::say( input = "" )
|
89
|
+
puts input
|
90
|
+
end
|
88
91
|
|
89
92
|
|
90
93
|
def self::canonicalize( input )
|
@@ -108,10 +111,19 @@ class Linen::CLI < Linen::Handler
|
|
108
111
|
|
109
112
|
|
110
113
|
def self::execute_command( plugin, command, args )
|
111
|
-
|
112
|
-
|
114
|
+
if command.is_a? Linen::Plugin::SimpleCommand
|
115
|
+
execute_simple_command plugin, command, args
|
116
|
+
elsif command.is_a? Linen::Plugin::TwoPhaseCommand
|
117
|
+
execute_two_phase_command plugin, command, args
|
118
|
+
else
|
119
|
+
raise Linen::HandlerError, "Don't know how to execute a #{command.class}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
def self::execute_simple_command( plugin, command, args )
|
113
125
|
workspace = Linen::Workspace.new
|
114
|
-
|
126
|
+
workspace.add_values command.validate_arguments( args )
|
115
127
|
|
116
128
|
input = ''
|
117
129
|
if command.requires_confirmation?
|
@@ -133,10 +145,64 @@ class Linen::CLI < Linen::Handler
|
|
133
145
|
|
134
146
|
return unless input =~ /^y/i
|
135
147
|
end
|
136
|
-
|
137
|
-
workspace.add_values( results )
|
148
|
+
|
138
149
|
command.execute( workspace )
|
139
150
|
end
|
151
|
+
|
152
|
+
|
153
|
+
def self::execute_two_phase_command( plugin, command, args )
|
154
|
+
workspace = Linen::Workspace.new
|
155
|
+
|
156
|
+
# the first argument will always be the lookup argument,
|
157
|
+
# so shift it off since we don't want it below
|
158
|
+
object = command.lookup_object( args.shift )
|
159
|
+
workspace.add_values object
|
160
|
+
|
161
|
+
puts <<-END
|
162
|
+
|
163
|
+
You will now be prompted to edit one or more fields. To accept the
|
164
|
+
current value, just hit enter. To clear it, hit <space> and then
|
165
|
+
enter. Otherwise, enter a new value.
|
166
|
+
|
167
|
+
Current values
|
168
|
+
--------------
|
169
|
+
END
|
170
|
+
command.inspect( workspace )
|
171
|
+
puts # blank line for clarity
|
172
|
+
|
173
|
+
current_values = command.editable_attrs.inject( Hash.new ) {|hash, value|
|
174
|
+
hash[ value ] = object[ command.lookup_attr ].send( value )
|
175
|
+
hash
|
176
|
+
}
|
177
|
+
|
178
|
+
workspace.add_values current_values
|
179
|
+
workspace.add_values command.validate_arguments( args )
|
180
|
+
|
181
|
+
input = ''
|
182
|
+
if command.requires_confirmation?
|
183
|
+
puts "\nRunning '#{plugin.short_name} #{command.name}' with arguments:"
|
184
|
+
|
185
|
+
puts results.map { |arg, value|
|
186
|
+
next unless value
|
187
|
+
|
188
|
+
output = value
|
189
|
+
output = value.join( ', ' ) if value.is_a? Array
|
190
|
+
|
191
|
+
"#{arg}: #{output}"
|
192
|
+
}.join( "\n" )
|
193
|
+
|
194
|
+
while input !~ /^(y|n)/i
|
195
|
+
input = Readline.readline( "\nContinue [y/N]? ")
|
196
|
+
input = "n" if input == ''
|
197
|
+
end
|
198
|
+
|
199
|
+
return unless input =~ /^y/i
|
200
|
+
end
|
201
|
+
|
202
|
+
puts
|
203
|
+
|
204
|
+
command.execute( workspace )
|
205
|
+
end
|
140
206
|
|
141
207
|
|
142
208
|
def self::reprompt( prompt = "Re-enter: " )
|
data/lib/linen/plugin.rb
CHANGED
@@ -69,10 +69,16 @@ class Linen::Plugin
|
|
69
69
|
end
|
70
70
|
|
71
71
|
|
72
|
-
def self::command( name, &block )
|
72
|
+
def self::command( name, hash = {}, &block )
|
73
73
|
@commands ||= IndifferentHash.new
|
74
74
|
|
75
|
-
|
75
|
+
if hash[ :lookup_first ]
|
76
|
+
command = TwoPhaseCommand.new( self, name, &block )
|
77
|
+
else
|
78
|
+
command = SimpleCommand.new( self, name, &block )
|
79
|
+
end
|
80
|
+
|
81
|
+
@commands[ name ] = command
|
76
82
|
end
|
77
83
|
|
78
84
|
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
##############################################################
|
4
|
+
# Copyright 2007, LAIKA, Inc. #
|
5
|
+
# #
|
6
|
+
# Authors: #
|
7
|
+
# * Ben Bleything <bbleything@laika.com> #
|
8
|
+
##############################################################
|
9
|
+
|
10
|
+
class Linen::Plugin::TwoPhaseCommand
|
11
|
+
attr_reader :name, :editable_attrs, :lookup_attr
|
12
|
+
|
13
|
+
def initialize( plugin, name, &block )
|
14
|
+
@plugin = plugin
|
15
|
+
@name = name
|
16
|
+
@arguments = []
|
17
|
+
@help_text = "No help for #{plugin.short_name} #{name}"
|
18
|
+
|
19
|
+
self.instance_eval &block
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def execute( workspace = Linen::Workspace.new )
|
24
|
+
return workspace.instance_eval( &@action_proc )
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def help
|
29
|
+
output = []
|
30
|
+
|
31
|
+
output << @help_text.wrap
|
32
|
+
output << nil # blank line
|
33
|
+
|
34
|
+
# this map turns our list of args into a list like this:
|
35
|
+
# <arg1> <arg2> <arg3> <arg4>...
|
36
|
+
arg_list = @arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
|
37
|
+
|
38
|
+
output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
|
39
|
+
|
40
|
+
return output.join( "\n" )
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
#############################
|
45
|
+
# PLUGIN DEFINITION METHODS #
|
46
|
+
#############################
|
47
|
+
|
48
|
+
|
49
|
+
# def one_of( *args )
|
50
|
+
# raise Linen::Plugin::ArgumentError,
|
51
|
+
# "You may not specify both required and one_of arguments" if @argument_type == :required
|
52
|
+
#
|
53
|
+
# @argument_type = :one_of
|
54
|
+
#
|
55
|
+
# args.each do |arg|
|
56
|
+
# raise Linen::Plugin::ArgumentError,
|
57
|
+
# "Argument '#{arg}' has not been defined" unless @plugin.arguments.include? arg
|
58
|
+
#
|
59
|
+
# @arguments << arg
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
#
|
64
|
+
# def required_arguments( *args )
|
65
|
+
# raise Linen::Plugin::ArgumentError,
|
66
|
+
# "You may not specify both required and one_of arguments" if @argument_type == :one_of
|
67
|
+
#
|
68
|
+
# @argument_type = :required
|
69
|
+
#
|
70
|
+
# args.each do |arg|
|
71
|
+
# raise Linen::Plugin::ArgumentError,
|
72
|
+
# "Argument '#{arg}' has not been defined" unless @plugin.arguments.include? arg
|
73
|
+
#
|
74
|
+
# @arguments << arg
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# alias required_argument required_arguments
|
78
|
+
|
79
|
+
def lookup_by( attr_name, &block )
|
80
|
+
@lookup_attr = attr_name
|
81
|
+
@lookup_block = block
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def editable_attributes( *attr_list )
|
86
|
+
@editable_attrs = attr_list
|
87
|
+
end
|
88
|
+
|
89
|
+
|
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
|
+
def inspect( workspace = Linen::Workspace.new, &block )
|
106
|
+
if block_given?
|
107
|
+
@inspect_proc = block
|
108
|
+
else
|
109
|
+
return workspace.instance_eval( &@inspect_proc )
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
##################
|
115
|
+
# HELPER METHODS #
|
116
|
+
##################
|
117
|
+
|
118
|
+
def lookup_object( input )
|
119
|
+
results = IndifferentHash.new
|
120
|
+
|
121
|
+
argument = @plugin.arguments[ @lookup_attr ]
|
122
|
+
arg_value = input
|
123
|
+
|
124
|
+
begin
|
125
|
+
arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
|
126
|
+
|
127
|
+
processed_argument = argument.process( arg_value )
|
128
|
+
|
129
|
+
results[ @lookup_attr ] = @lookup_block.call( processed_argument )
|
130
|
+
rescue Linen::Plugin::ArgumentError => e
|
131
|
+
# reset arg_value to nil so we get prompted on retry
|
132
|
+
arg_value = nil
|
133
|
+
|
134
|
+
retry
|
135
|
+
end
|
136
|
+
|
137
|
+
return results
|
138
|
+
end
|
139
|
+
|
140
|
+
### FIXME:bbleything
|
141
|
+
###
|
142
|
+
### The reprompting stuff below is going to come back to bite us when we try to
|
143
|
+
### add batch mode later... that said, in the interest of getting things out the
|
144
|
+
### door, we're going to leave it be for now.
|
145
|
+
def validate_arguments( args )
|
146
|
+
results = IndifferentHash.new
|
147
|
+
|
148
|
+
@editable_attrs.each do |arg_name|
|
149
|
+
argument = @plugin.arguments[ arg_name ]
|
150
|
+
arg_value = args.shift
|
151
|
+
|
152
|
+
begin
|
153
|
+
arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
|
154
|
+
|
155
|
+
result = argument.process( arg_value, :mode => :edit )
|
156
|
+
|
157
|
+
if result.nil?
|
158
|
+
# user just hit enter; leave value as-is. noop.
|
159
|
+
elsif result == ""
|
160
|
+
results[ arg_name ] = ''
|
161
|
+
else
|
162
|
+
results[ arg_name ] = result
|
163
|
+
end
|
164
|
+
rescue Linen::Plugin::ArgumentError => e
|
165
|
+
# reset arg_value to nil so we get prompted on retry
|
166
|
+
arg_value = nil ; retry
|
167
|
+
end
|
168
|
+
|
169
|
+
return results
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
def requires_confirmation?
|
175
|
+
@require_confirmation
|
176
|
+
end
|
177
|
+
end
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: linen
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
6
|
+
version: 0.6.0
|
7
7
|
date: 2007-09-10 00:00:00 -07:00
|
8
8
|
summary: Linen - A pluggable command-line interface library
|
9
9
|
require_paths:
|
@@ -35,13 +35,14 @@ files:
|
|
35
35
|
- lib/indifferent_hash.rb
|
36
36
|
- lib/linen
|
37
37
|
- lib/linen/argument.rb
|
38
|
-
- lib/linen/command.rb
|
39
38
|
- lib/linen/exceptions.rb
|
40
39
|
- lib/linen/handler.rb
|
41
40
|
- lib/linen/handlers
|
42
41
|
- lib/linen/handlers/cli.rb
|
43
42
|
- lib/linen/plugin.rb
|
44
43
|
- lib/linen/plugin_registry.rb
|
44
|
+
- lib/linen/simple_command.rb
|
45
|
+
- lib/linen/two_phase_command.rb
|
45
46
|
- lib/linen/workspace.rb
|
46
47
|
- lib/linen.rb
|
47
48
|
- lib/string_extensions.rb
|