linen 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,8 +18,8 @@ require 'string_extensions'
18
18
 
19
19
 
20
20
  module Linen
21
- VERSION = "0.6.4"
22
- SVNRev = %q$Rev: 223 $
21
+ VERSION = "0.7.0"
22
+ SVNRev = %q$Rev: 231 $
23
23
 
24
24
 
25
25
  def self::plugins
@@ -13,7 +13,7 @@ class Linen::Plugin::Argument
13
13
  def initialize( plugin, name, opts )
14
14
  @plugin = plugin
15
15
  @name = name
16
- @prompt = opts[ :prompt ] || "Please enter the value for #{@name}"
16
+ @prompt = opts[ :prompt ] || "Please enter the value for #{@name}: "
17
17
  @regex = opts[ :regex ] || //
18
18
  @process = opts[ :process ] || nil
19
19
  end
@@ -32,7 +32,7 @@ class Linen::Plugin::Argument
32
32
  end
33
33
  end
34
34
 
35
- raise Linen::Plugin::ArgumentError, "Invalid entry." unless value =~ @regex
35
+ raise Linen::Plugin::ArgumentError, "The value entered ('#{value}') is not a valid #{@name}." unless value =~ @regex
36
36
  return value unless @process
37
37
 
38
38
  begin
@@ -40,3 +40,5 @@ end
40
40
 
41
41
  class Linen::WorkspaceError < RuntimeError ; end
42
42
  class Linen::HandlerError < RuntimeError ; end
43
+
44
+ class Linen::Abort < RuntimeError ; end
@@ -8,10 +8,17 @@
8
8
  ##############################################################
9
9
 
10
10
  class Linen::Handler
11
- # placeholder. This will eventually become the abstract
12
- # class from which all handlers inherit.
13
-
14
- def self::say( input )
11
+ def self::say( input = '' )
15
12
  raise NotImplementedError, "You must override say() in the handler"
16
13
  end
14
+
15
+
16
+ def self::die( input = '' )
17
+ raise NotImplementedError, "You must override die() in the handler"
18
+ end
19
+
20
+
21
+ def self::history
22
+ raise NotImplementedError, "Handlers must provide a #history method that quacks like an Array"
23
+ end
17
24
  end
@@ -55,6 +55,10 @@ class Linen::CLI < Linen::Handler
55
55
  end
56
56
  elsif plugin.nil? or command.nil?
57
57
  puts "You must enter both a plugin name and a command."
58
+ elsif Linen.plugins[ plugin ].nil?
59
+ puts "Plugin '#{plugin}' not found."
60
+ elsif Linen.plugins[ plugin ].commands[ command ].nil?
61
+ puts "Command '#{command}' not found in '#{plugin}' plugin."
58
62
  else
59
63
  plugin, command, *args = canonicalize( input ).split
60
64
 
@@ -68,26 +72,43 @@ class Linen::CLI < Linen::Handler
68
72
 
69
73
  def self::start
70
74
  loop do
75
+ input = nil
76
+
71
77
  begin
72
78
  input = Readline.readline( @prompt )
73
- rescue Interrupt
74
- puts "\nPlease type 'quit' or 'exit' to quit."
75
- else
76
79
  parse_command input
80
+ rescue Interrupt
81
+ if input
82
+ puts "\nCommand aborted."
83
+ else
84
+ puts "\nPlease type 'quit' or 'exit' to quit."
85
+ end
86
+ rescue Linen::Plugin::ArgumentError => e
87
+ puts e.message
77
88
  end
78
89
 
79
90
  puts # blank line to clean things up
80
91
  end
81
92
  end
93
+
94
+
95
+ def self::history
96
+ return Readline::HISTORY
97
+ end
82
98
 
83
99
 
84
100
  #######
85
101
  private
86
102
  #######
87
103
 
88
- def self::say( input = "" )
104
+ def self::say( input = '' )
89
105
  puts input.wrap
90
106
  end
107
+
108
+
109
+ def self::die( input = '' )
110
+ raise Linen::Abort, input
111
+ end
91
112
 
92
113
 
93
114
  def self::canonicalize( input )
@@ -207,7 +228,7 @@ END
207
228
  end
208
229
 
209
230
 
210
- def self::reprompt( prompt = "Re-enter: " )
231
+ def self::prompt( prompt = "Re-enter: " )
211
232
  old_completion_proc = Readline.completion_proc
212
233
  Readline.completion_proc = proc {}
213
234
 
@@ -104,4 +104,13 @@ class Linen::Plugin
104
104
 
105
105
  @description = input
106
106
  end
107
+
108
+
109
+ ### give validation a way to fail without explicitly raising
110
+ ### an exception in the lambda
111
+ def self::fail( input = nil )
112
+ input ||= "Validation failed."
113
+
114
+ raise Linen::Plugin::ArgumentError, input
115
+ end
107
116
  end
@@ -113,37 +113,35 @@ class Linen::Plugin::SimpleCommand
113
113
  @require_confirmation
114
114
  end
115
115
 
116
- ###########
117
- private #
118
- ###########
116
+ #######
117
+ private
118
+ #######
119
119
 
120
120
  ### FIXME:bbleything
121
121
  ###
122
- ### The reprompting stuff below is going to come back to bite us when we try to
123
- ### add batch mode later... that said, in the interest of getting things out the
124
- ### door, we're going to leave it be for now.
122
+ ### Much of the reprompting stuff is gone, it only exists now to allow us to
123
+ ### prompt when users don't enter anything. We should consider moving the
124
+ ### argument fetching into a separate phase of execution, so as to prevent
125
+ ### the ridiculous duplication of history-manipulation code in the following
126
+ ### two methods (and generally make it clearer how the whole thing works), but
127
+ ### that's probably not going to make it into 0.7.0.
125
128
 
126
129
  def validate_one_of_arguments( arg )
127
130
  results = IndifferentHash.new
128
-
129
- begin
130
- @arguments.each do |arg_name|
131
- argument = @plugin.arguments[ arg_name ]
132
-
133
- results[ arg_name ] = argument.process( arg ) rescue nil
134
- end
135
-
136
- raise Linen::Plugin::ArgumentError,
137
- "The value you entered ('#{arg}') is invalid for all arguments." if
138
- results.values.compact.empty?
139
- rescue Linen::Plugin::ArgumentError => e
140
- puts e.message
141
- arg = Linen::CLI.reprompt.split.first
142
-
143
- retry
131
+
132
+ # put the argument onto the command history if it wasn't already there
133
+ command_line = Linen::Workspace.handler.history.pop.strip
134
+ command_line << " #{arg}" unless command_line =~ /#{arg}$/
135
+ Linen::Workspace.handler.history.push command_line.squeeze( ' ' ).strip
136
+
137
+ @arguments.each do |arg_name|
138
+ argument = @plugin.arguments[ arg_name ]
139
+ results[ arg_name ] = argument.process( arg ) rescue nil
144
140
  end
145
-
146
- return results
141
+
142
+ raise Linen::Plugin::ArgumentError,
143
+ "The value you entered ('#{arg}') is invalid for all arguments." if
144
+ results.values.compact.empty?
147
145
  end
148
146
 
149
147
 
@@ -152,20 +150,17 @@ class Linen::Plugin::SimpleCommand
152
150
 
153
151
  @arguments.each do |arg_name|
154
152
  argument = @plugin.arguments[ arg_name ]
153
+
154
+ # prompt if we don't have the arg on the stack already
155
155
  arg_value = args.shift
156
-
157
- begin
158
- arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
159
-
160
- results[ arg_name ] = argument.process( arg_value )
161
- rescue Linen::Plugin::ArgumentError => e
162
- puts e.message
163
-
164
- # reset arg_value to nil so we get prompted on retry
165
- arg_value = nil
166
-
167
- retry
168
- end
156
+ arg_value ||= Linen::Workspace.handler.prompt( argument.prompt )
157
+
158
+ # put the arg value back onto the command line
159
+ command_line = Linen::Workspace.handler.history.pop
160
+ command_line << " #{arg_value}" unless command_line =~ /#{arg_value}$/
161
+ Linen::Workspace.handler.history.push command_line.squeeze( ' ' ).strip
162
+
163
+ results[ arg_name ] = argument.process( arg_value )
169
164
  end
170
165
 
171
166
  return results
@@ -45,37 +45,6 @@ class Linen::Plugin::TwoPhaseCommand
45
45
  # PLUGIN DEFINITION METHODS #
46
46
  #############################
47
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
48
  def lookup_by( attr_name, &block )
80
49
  @lookup_attr = attr_name
81
50
  @lookup_block = block
@@ -121,27 +90,21 @@ class Linen::Plugin::TwoPhaseCommand
121
90
  argument = @plugin.arguments[ @lookup_attr ]
122
91
  arg_value = input
123
92
 
124
- begin
125
- arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
126
-
127
- processed_argument = argument.process( arg_value )
93
+ # prompt if we didn't get an arg value
94
+ arg_value ||= Linen::CLI.prompt( argument.prompt )
128
95
 
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
96
+ # put the command back onto the history
97
+ command_line = Linen::Workspace.handler.history.pop
98
+ command_line << " #{arg_value}" unless command_line =~ /#{arg_value}$/
99
+ Linen::Workspace.handler.history.push command_line.squeeze( ' ' ).strip
100
+
101
+ processed_argument = argument.process( arg_value )
102
+ results[ @lookup_attr ] = @lookup_block.call( processed_argument )
136
103
 
137
104
  return results
138
105
  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.
106
+
107
+
145
108
  def validate_arguments( args )
146
109
  results = IndifferentHash.new
147
110
 
@@ -150,7 +113,7 @@ class Linen::Plugin::TwoPhaseCommand
150
113
  arg_value = args.shift
151
114
 
152
115
  begin
153
- arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
116
+ arg_value = Linen::CLI.prompt( argument.prompt ) if arg_value.nil?
154
117
 
155
118
  result = argument.process( arg_value, :mode => :edit )
156
119
 
@@ -162,6 +125,8 @@ class Linen::Plugin::TwoPhaseCommand
162
125
  results[ arg_name ] = result
163
126
  end
164
127
  rescue Linen::Plugin::ArgumentError => e
128
+ puts e.message
129
+
165
130
  # reset arg_value to nil so we get prompted on retry
166
131
  arg_value = nil ; retry
167
132
  end
@@ -38,4 +38,8 @@ class Linen::Workspace
38
38
  def method_missing( *args )
39
39
  @@handler.send( *args )
40
40
  end
41
+
42
+ def self::handler
43
+ return @@handler
44
+ end
41
45
  end
@@ -9,7 +9,7 @@
9
9
 
10
10
  class String
11
11
  def wrap(line_width = 72)
12
- self.gsub(/\n/, "\n\n").gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
12
+ self.gsub(/\n/, "\n\n").gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").chomp
13
13
  end
14
14
  end
15
15
 
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.4
6
+ version: 0.7.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: