linen 0.3.1 → 0.3.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.
@@ -8,15 +8,15 @@
8
8
  ##############################################################
9
9
 
10
10
  class IndifferentHash < Hash
11
- def []( key )
12
- candidate = self.fetch( key ) rescue false
13
- return candidate if candidate
11
+ def []( key )
12
+ candidate = self.fetch( key ) rescue false
13
+ return candidate if candidate
14
14
 
15
- [ :to_s, :intern ].each do |modifier|
16
- candidate = self.fetch( key.send(modifier) ) if key.respond_to? modifier rescue false
17
- return candidate if candidate
18
- end
15
+ [ :to_s, :intern ].each do |modifier|
16
+ candidate = self.fetch( key.send(modifier) ) if key.respond_to? modifier rescue false
17
+ return candidate if candidate
18
+ end
19
19
 
20
- return nil
21
- end
20
+ return nil
21
+ end
22
22
  end
@@ -18,18 +18,18 @@ require 'string_extensions'
18
18
 
19
19
 
20
20
  module Linen
21
- VERSION = "0.3.1"
22
- SVNRev = %q$Rev: 84 $
21
+ VERSION = "0.3.2"
22
+ SVNRev = %q$Rev: 86 $
23
23
 
24
24
 
25
- def self::plugins
26
- return Linen::PluginRegistry.instance
27
- end
25
+ def self::plugins
26
+ return Linen::PluginRegistry.instance
27
+ end
28
28
 
29
29
 
30
- def self::start
31
- Linen::CLI.start_loop
32
- end
30
+ def self::start
31
+ Linen::CLI.start_loop
32
+ end
33
33
  end
34
34
 
35
35
 
@@ -8,31 +8,31 @@
8
8
  ##############################################################
9
9
 
10
10
  class Linen::Plugin::Argument
11
- attr_reader :prompt
11
+ attr_reader :prompt
12
12
 
13
- def initialize( plugin, name, opts )
14
- @plugin = plugin
15
- @name = name
16
- @prompt = opts[:prompt] || "Please enter the value for #{@name}"
17
- @validation = opts[:validation] || /^\w+$/
18
- @conversion = opts[:conversion] || nil
19
- end
13
+ def initialize( plugin, name, opts )
14
+ @plugin = plugin
15
+ @name = name
16
+ @prompt = opts[:prompt] || "Please enter the value for #{@name}"
17
+ @validation = opts[:validation] || /^\w+$/
18
+ @conversion = opts[:conversion] || nil
19
+ end
20
20
 
21
21
 
22
- def convert( value )
23
- return value unless @conversion
24
- return @conversion.call( value )
25
- end
22
+ def convert( value )
23
+ return value unless @conversion
24
+ return @conversion.call( value )
25
+ end
26
26
 
27
27
 
28
- def validate( value )
29
- if @validation.is_a? Proc
30
- result = @validation.call( value )
31
- else
32
- result = ( value =~ @validation )
33
- end
28
+ def validate( value )
29
+ if @validation.is_a? Proc
30
+ result = @validation.call( value )
31
+ else
32
+ result = ( value =~ @validation )
33
+ end
34
34
 
35
- raise Linen::Plugin::ArgumentError, "Value '#{value}' is invalid for #{@name}." unless result
36
- return value
37
- end
35
+ raise Linen::Plugin::ArgumentError, "Value '#{value}' is invalid for #{@name}." unless result
36
+ return value
37
+ end
38
38
  end
@@ -8,144 +8,144 @@
8
8
  ##############################################################
9
9
 
10
10
  class Linen::CLI
11
- class << self
12
- attr_accessor :prompt
13
- end
14
-
15
- @prompt = "linen > "
16
-
17
- def self::parse_command( input )
18
- ### * nil means ctrl-d, so exit.
19
- ### * if they said "quit" or "exit", do so
20
- ### * Size == 0 means empty command, so just return.
21
- ###
22
- ### otherwise, add to history.
23
- if input.nil?
24
- ### blank line to make ctrl-d not make the error live on the existing line
25
- puts ; cleanup and exit
26
- elsif input.chomp.size == 0 # empty string
27
- return
28
- else
29
- Readline::HISTORY.push( input )
30
- end
31
-
32
- plugin, command, *arguments = input.split
33
-
34
- if ['quit', 'exit'].abbrev.include? plugin
35
- cleanup and exit
36
- elsif ['help', '?'].abbrev.include? plugin
37
- # they entered "help <plugin> <command> or some subset there of, which means
38
- # that we have the plugin in command and the command in the first element of args.
39
- plugin = command.dup rescue nil
40
- command = arguments.shift rescue nil
41
-
42
- if plugin and command
43
- plugin, command = canonicalize( "#{plugin} #{command}" ).split rescue nil
44
-
45
- # if either plugin or command is nil, lookup will fail; bail
46
- return unless plugin = Linen.plugins[ plugin ]
47
- return unless command = plugin.commands[ command ]
48
-
49
- puts command.help
50
- elsif plugin
51
- return unless plugin = Linen.plugins[ canonicalize( plugin ) ]
52
- puts plugin.help
53
- else
54
- help
55
- end
56
- elsif plugin.nil? or command.nil?
57
- puts "You must enter both a plugin name and a command."
58
- else
59
- plugin, command, *args = canonicalize( input ).split
60
-
61
- execute_command plugin, command, args
62
- end
63
- end
64
-
65
-
66
- def self::start_loop
67
- loop do
68
- begin
69
- input = Readline.readline( @prompt )
70
- rescue Interrupt
71
- puts "\nPlease type 'quit' or 'exit' to quit."
72
- else
73
- parse_command input
74
- end
75
-
76
- puts # blank line to clean things up
77
- end
78
- end
79
-
80
-
81
- #######
82
- private
83
- #######
84
-
85
- def self::canonicalize( input )
86
- begin
87
- expansion = expand_command( input )
88
- rescue Linen::CLI::PluginNotFoundError, Linen::CLI::CommandNotFoundError, Linen::CLI::AmbiguousPluginError, Linen::CLI::AmbiguousCommandError => e
89
- puts e
90
- end
91
-
92
- return expansion
93
- end
94
-
95
-
96
- def self::cleanup
97
- puts "Exiting..."
98
-
99
- Linen.plugins.each do |p|
100
- p.cleanup
101
- end
102
- end
103
-
104
-
105
- def self::execute_command( plugin, command, args )
106
- plugin = Linen.plugins[ plugin ]
107
- command = plugin.commands[ command ]
108
- workspace = Linen::Workspace.new
109
- results = command.validate_arguments( args )
110
-
111
- input = ''
112
- if command.requires_confirmation?
113
- puts "Running '#{plugin.short_name} #{command.name}' with arguments:"
114
-
115
- puts results.map { |arg, value|
116
- next unless value
117
- "#{arg}: #{value}"
118
- }.join( "\n" )
119
-
120
- while input !~ /^(y|n)/i
121
- input = Readline.readline( "\nContinue [y/N]? ")
122
- input = "n" if input == ''
123
- end
124
- end
125
-
126
- if input =~ /^y/i
127
- puts # blank line
128
-
129
- workspace.add_values( results )
130
- command.execute( workspace )
131
- end
132
- end
133
-
134
-
135
- def self::reprompt( prompt = "Re-enter: " )
136
- old_completion_proc = Readline.completion_proc
137
- Readline.completion_proc = proc {}
11
+ class << self
12
+ attr_accessor :prompt
13
+ end
14
+
15
+ @prompt = "linen > "
16
+
17
+ def self::parse_command( input )
18
+ ### * nil means ctrl-d, so exit.
19
+ ### * if they said "quit" or "exit", do so
20
+ ### * Size == 0 means empty command, so just return.
21
+ ###
22
+ ### otherwise, add to history.
23
+ if input.nil?
24
+ ### blank line to make ctrl-d not make the error live on the existing line
25
+ puts ; cleanup and exit
26
+ elsif input.chomp.size == 0 # empty string
27
+ return
28
+ else
29
+ Readline::HISTORY.push( input )
30
+ end
31
+
32
+ plugin, command, *arguments = input.split
33
+
34
+ if ['quit', 'exit'].abbrev.include? plugin
35
+ cleanup and exit
36
+ elsif ['help', '?'].abbrev.include? plugin
37
+ # they entered "help <plugin> <command> or some subset there of, which means
38
+ # that we have the plugin in command and the command in the first element of args.
39
+ plugin = command.dup rescue nil
40
+ command = arguments.shift rescue nil
41
+
42
+ if plugin and command
43
+ plugin, command = canonicalize( "#{plugin} #{command}" ).split rescue nil
44
+
45
+ # if either plugin or command is nil, lookup will fail; bail
46
+ return unless plugin = Linen.plugins[ plugin ]
47
+ return unless command = plugin.commands[ command ]
48
+
49
+ puts command.help
50
+ elsif plugin
51
+ return unless plugin = Linen.plugins[ canonicalize( plugin ) ]
52
+ puts plugin.help
53
+ else
54
+ help
55
+ end
56
+ elsif plugin.nil? or command.nil?
57
+ puts "You must enter both a plugin name and a command."
58
+ else
59
+ plugin, command, *args = canonicalize( input ).split
60
+
61
+ execute_command plugin, command, args
62
+ end
63
+ end
64
+
65
+
66
+ def self::start_loop
67
+ loop do
68
+ begin
69
+ input = Readline.readline( @prompt )
70
+ rescue Interrupt
71
+ puts "\nPlease type 'quit' or 'exit' to quit."
72
+ else
73
+ parse_command input
74
+ end
75
+
76
+ puts # blank line to clean things up
77
+ end
78
+ end
79
+
80
+
81
+ #######
82
+ private
83
+ #######
84
+
85
+ def self::canonicalize( input )
86
+ begin
87
+ expansion = expand_command( input )
88
+ rescue Linen::CLI::PluginNotFoundError, Linen::CLI::CommandNotFoundError, Linen::CLI::AmbiguousPluginError, Linen::CLI::AmbiguousCommandError => e
89
+ puts e
90
+ end
91
+
92
+ return expansion
93
+ end
94
+
95
+
96
+ def self::cleanup
97
+ puts "Exiting..."
98
+
99
+ Linen.plugins.each do |p|
100
+ p.cleanup
101
+ end
102
+ end
103
+
104
+
105
+ def self::execute_command( plugin, command, args )
106
+ plugin = Linen.plugins[ plugin ]
107
+ command = plugin.commands[ command ]
108
+ workspace = Linen::Workspace.new
109
+ results = command.validate_arguments( args )
110
+
111
+ input = ''
112
+ if command.requires_confirmation?
113
+ puts "\nRunning '#{plugin.short_name} #{command.name}' with arguments:"
114
+
115
+ puts results.map { |arg, value|
116
+ next unless value
117
+ "#{arg}: #{value}"
118
+ }.join( "\n" )
119
+
120
+ while input !~ /^(y|n)/i
121
+ input = Readline.readline( "\nContinue [y/N]? ")
122
+ input = "n" if input == ''
123
+ end
124
+ end
125
+
126
+ if input =~ /^y/i
127
+ puts # blank line
138
128
 
139
- input = Readline.readline( prompt )
129
+ workspace.add_values( results )
130
+ command.execute( workspace )
131
+ end
132
+ end
140
133
 
141
- Readline.completion_proc = old_completion_proc
142
-
143
- return input
144
- end
145
134
 
135
+ def self::reprompt( prompt = "Re-enter: " )
136
+ old_completion_proc = Readline.completion_proc
137
+ Readline.completion_proc = proc {}
146
138
 
147
- def self::help
148
- puts <<-END
139
+ input = Readline.readline( prompt )
140
+
141
+ Readline.completion_proc = old_completion_proc
142
+
143
+ return input
144
+ end
145
+
146
+
147
+ def self::help
148
+ puts <<-END
149
149
  Usage: <plugin> <command> [<argument>, <argument>...]
150
150
 
151
151
  You may shorten the plugin and commands as long as the abbreviation
@@ -154,92 +154,92 @@ is non-ambiguous. For example, given two plugins 'addition' and
154
154
 
155
155
  Available plugins and commands:
156
156
 
157
- END
157
+ END
158
158
 
159
- Linen.plugins.each do |plugin|
160
- puts "- #{plugin.short_name}"
159
+ Linen.plugins.each do |plugin|
160
+ puts "- #{plugin.short_name}"
161
161
 
162
- plugin.commands.each do |name, command|
163
- puts " - #{name}"
164
- end
165
- end
162
+ plugin.commands.each do |name, command|
163
+ puts " - #{name}"
164
+ end
165
+ end
166
166
 
167
- puts <<-END
167
+ puts <<-END
168
168
 
169
169
  To get help with a plugin, enter "help <plugin>". You may also enter
170
170
  "help <plugin> <command>" for help on a specific command.
171
- END
172
- end
173
-
174
-
175
- ### First, try to complete the plugin name. If we can't,
176
- ### raise an exception saying so.
177
- ###
178
- ### Second, try to complete the command name. If we can't,
179
- ### raise an exception saying so.
180
- ###
181
- ### The caller is now responsible for flow control.
182
- def self::expand_command( str )
183
- plugin_candidates = Linen.plugins.collect {|p| p.short_name}.sort
184
-
185
- ### empty string means we're trying to complete the plugin with nothing to go on
186
- raise Linen::CLI::AmbiguousPluginError.new( plugin_candidates ) if str.empty?
187
-
188
- plugin, command, *arguments = str.split
189
-
190
- ### attempt to complete the plugin, raising an exception if it failes
191
- completed_plugin = plugin_candidates.abbrev[ plugin ]
192
-
193
- unless completed_plugin
194
- refined_candidates = plugin_candidates.select {|p| p =~ /^#{plugin}/}
195
-
196
- raise Linen::CLI::PluginNotFoundError, "Plugin '#{plugin}' not found." if refined_candidates.empty?
197
- raise Linen::CLI::AmbiguousPluginError.new( refined_candidates, plugin )
198
- end
199
-
200
- ### if there's no command entered and no space after the plugin,
201
- ### just return the plugin
202
- return completed_plugin if command.nil? and str !~ /\s$/
203
-
204
- ### If we've gotten here, we've now got the plugin in completed_plugin,
205
- ### so attempt to complete the command
206
- command_candidates = Linen.plugins[ completed_plugin ].commands.keys.map {|k| k.to_s}.sort
207
-
208
- completed_command = command_candidates.abbrev[ command ]
209
-
210
- unless completed_command
211
- refined_candidates = command_candidates.select {|c| c =~ /^#{command}/}
212
-
213
- raise Linen::CLI::CommandNotFoundError,
214
- "Command '#{command}' not found." if refined_candidates.empty?
215
-
216
- raise Linen::CLI::AmbiguousCommandError.new( refined_candidates, command ),
217
- "The command you entered ('#{command}') is ambiguous; please select from the following:"
218
- end
219
-
220
- ### if we've gotten here, we're golden. Everything is completed. Rejoice!
221
- output = completed_plugin
222
- output << " " + completed_command if completed_command
223
- output << " " + arguments.join(' ') unless arguments.empty?
224
-
225
- return output
226
- end
227
-
228
- Readline.basic_word_break_characters = ""
229
-
230
- Readline.completion_proc = proc do |str|
231
- begin
232
- output = expand_command( str )
233
- rescue Linen::CLI::PluginNotFoundError, Linen::CLI::CommandNotFoundError => e
234
- output = ''
235
- rescue Linen::CLI::AmbiguousPluginError => e
236
- output = e.candidates
237
- rescue Linen::CLI::AmbiguousCommandError => e
238
- output = e.candidates.map {|c| "#{str.split.first} #{c}"}
239
- ensure
240
- return output
241
- end
242
- end
171
+ END
172
+ end
173
+
174
+
175
+ ### First, try to complete the plugin name. If we can't,
176
+ ### raise an exception saying so.
177
+ ###
178
+ ### Second, try to complete the command name. If we can't,
179
+ ### raise an exception saying so.
180
+ ###
181
+ ### The caller is now responsible for flow control.
182
+ def self::expand_command( str )
183
+ plugin_candidates = Linen.plugins.collect {|p| p.short_name}.sort
184
+
185
+ ### empty string means we're trying to complete the plugin with nothing to go on
186
+ raise Linen::CLI::AmbiguousPluginError.new( plugin_candidates ) if str.empty?
187
+
188
+ plugin, command, *arguments = str.split
189
+
190
+ ### attempt to complete the plugin, raising an exception if it failes
191
+ completed_plugin = plugin_candidates.abbrev[ plugin ]
192
+
193
+ unless completed_plugin
194
+ refined_candidates = plugin_candidates.select {|p| p =~ /^#{plugin}/}
195
+
196
+ raise Linen::CLI::PluginNotFoundError, "Plugin '#{plugin}' not found." if refined_candidates.empty?
197
+ raise Linen::CLI::AmbiguousPluginError.new( refined_candidates, plugin )
198
+ end
199
+
200
+ ### if there's no command entered and no space after the plugin,
201
+ ### just return the plugin
202
+ return completed_plugin if command.nil? and str !~ /\s$/
203
+
204
+ ### If we've gotten here, we've now got the plugin in completed_plugin,
205
+ ### so attempt to complete the command
206
+ command_candidates = Linen.plugins[ completed_plugin ].commands.keys.map {|k| k.to_s}.sort
207
+
208
+ completed_command = command_candidates.abbrev[ command ]
209
+
210
+ unless completed_command
211
+ refined_candidates = command_candidates.select {|c| c =~ /^#{command}/}
212
+
213
+ raise Linen::CLI::CommandNotFoundError,
214
+ "Command '#{command}' not found." if refined_candidates.empty?
215
+
216
+ raise Linen::CLI::AmbiguousCommandError.new( refined_candidates, command ),
217
+ "The command you entered ('#{command}') is ambiguous; please select from the following:"
218
+ end
219
+
220
+ ### if we've gotten here, we're golden. Everything is completed. Rejoice!
221
+ output = completed_plugin
222
+ output << " " + completed_command if completed_command
223
+ output << " " + arguments.join(' ') unless arguments.empty?
224
+
225
+ return output
226
+ end
227
+
228
+ Readline.basic_word_break_characters = ""
229
+
230
+ Readline.completion_proc = proc do |str|
231
+ begin
232
+ output = expand_command( str )
233
+ rescue Linen::CLI::PluginNotFoundError, Linen::CLI::CommandNotFoundError => e
234
+ output = ''
235
+ rescue Linen::CLI::AmbiguousPluginError => e
236
+ output = e.candidates
237
+ rescue Linen::CLI::AmbiguousCommandError => e
238
+ output = e.candidates.map {|c| "#{str.split.first} #{c}"}
239
+ ensure
240
+ return output
241
+ end
242
+ end
243
243
  end
244
244
 
245
245
  Signal.trap( 'INT' ) { raise Interrupt }