linen 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/linen.rb CHANGED
@@ -18,8 +18,8 @@ require 'string_extensions'
18
18
 
19
19
 
20
20
  module Linen
21
- VERSION = "0.2.0"
22
- SVNRev = %q$Rev: 56 $
21
+ VERSION = "0.3.0"
22
+ SVNRev = %q$Rev: 71 $
23
23
 
24
24
 
25
25
  def self::plugins
@@ -36,6 +36,8 @@ end
36
36
  ### Plugin Infrastructure
37
37
  require 'linen/plugin_registry'
38
38
  require 'linen/plugin'
39
+ require 'linen/argument'
40
+ require 'linen/command'
39
41
 
40
42
 
41
43
  ### Other Infrastructure
@@ -0,0 +1,38 @@
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::Argument
11
+ attr_reader :prompt
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
20
+
21
+
22
+ def convert( value )
23
+ return value unless @conversion
24
+ return @conversion.call( value )
25
+ end
26
+
27
+
28
+ def validate( value )
29
+ if @validation.is_a? Proc
30
+ result = @validation.call( value )
31
+ else
32
+ result = ( value =~ @validation )
33
+ end
34
+
35
+ raise Linen::Plugin::ArgumentError, "Value '#{value}' is invalid for #{@name}." unless result
36
+ return value
37
+ end
38
+ end
data/lib/linen/cli.rb CHANGED
@@ -12,7 +12,7 @@ class Linen::CLI
12
12
  attr_accessor :prompt
13
13
  end
14
14
 
15
- @prompt = "linen> "
15
+ @prompt = "linen > "
16
16
 
17
17
  def self::parse_command( input )
18
18
  ### * nil means ctrl-d, so exit.
@@ -103,42 +103,25 @@ class Linen::CLI
103
103
 
104
104
 
105
105
  def self::execute_command( plugin, command, args )
106
- plugin = Linen.plugins[ plugin ]
107
- command = plugin.commands[ command ]
108
-
106
+ plugin = Linen.plugins[ plugin ]
107
+ command = plugin.commands[ command ]
109
108
  workspace = Linen::Workspace.new
109
+ results = command.validate_arguments( args )
110
110
 
111
- command.arguments.each do |arg_name|
112
- argument = plugin.arguments[ arg_name ]
113
-
114
- arg_value = args.shift
115
-
116
- begin
117
- if arg_value.nil?
118
- old_completion_proc = Readline.completion_proc
119
- Readline.completion_proc = Proc.new {}
120
-
121
- arg_value = Readline.readline( argument.prompt )
122
-
123
- Readline.completion_proc = old_completion_proc
124
- end
111
+ workspace.add_values( results )
112
+ command.execute( workspace )
113
+ end
125
114
 
126
- argument.validate arg_value
127
115
 
128
- rescue Linen::Plugin::ArgumentError => e
129
- print e
116
+ def self::reprompt( prompt = "Re-enter: " )
117
+ old_completion_proc = Readline.completion_proc
118
+ Readline.completion_proc = proc {}
130
119
 
131
- # reset arg_value to nil so we get prompted on retry
132
- arg_value = nil
120
+ input = Readline.readline( prompt )
133
121
 
134
- retry
135
- else
136
- arg_value = argument.convert( arg_value )
137
- workspace.set_value arg_name, arg_value
138
- end
139
- end
122
+ Readline.completion_proc = old_completion_proc
140
123
 
141
- puts command.execute( workspace )
124
+ return input
142
125
  end
143
126
 
144
127
 
@@ -208,8 +191,11 @@ To get help with a plugin, enter "help <plugin>". You may also enter
208
191
  unless completed_command
209
192
  refined_candidates = command_candidates.select {|c| c =~ /^#{command}/}
210
193
 
211
- raise Linen::CLI::CommandNotFoundError, "Command '#{command}' not found." if refined_candidates.empty?
212
- raise Linen::CLI::AmbiguousCommandError.new( refined_candidates, command ), "The command you entered ('#{command}') is ambiguous; please select from the following:"
194
+ raise Linen::CLI::CommandNotFoundError,
195
+ "Command '#{command}' not found." if refined_candidates.empty?
196
+
197
+ raise Linen::CLI::AmbiguousCommandError.new( refined_candidates, command ),
198
+ "The command you entered ('#{command}') is ambiguous; please select from the following:"
213
199
  end
214
200
 
215
201
  ### if we've gotten here, we're golden. Everything is completed. Rejoice!
@@ -0,0 +1,167 @@
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::Command
11
+ def initialize( plugin, name, &block )
12
+ @plugin = plugin
13
+ @name = name
14
+ @arguments = []
15
+ @help_text = "No help for #{plugin.short_name} #{name}"
16
+
17
+ self.instance_eval &block
18
+ end
19
+
20
+
21
+ def execute( workspace = Linen::Workspace.new )
22
+ return workspace.instance_eval( &@action_proc )
23
+ end
24
+
25
+
26
+ def help
27
+ output = []
28
+
29
+ output << @help_text.wrap
30
+ output << nil # blank line
31
+
32
+ # this map turns our list of args into a list like this:
33
+ # <arg1> <arg2> <arg3> <arg4>...
34
+ arg_list = arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
35
+
36
+ output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
37
+
38
+ return output.join( "\n" )
39
+ end
40
+
41
+
42
+ #############################
43
+ # PLUGIN DEFINITION METHODS #
44
+ #############################
45
+
46
+
47
+ def one_of( *args )
48
+ raise Linen::Plugin::ArgumentError,
49
+ "You may not specify both required and one_of arguments" if @argument_type == :required
50
+
51
+ @argument_type = :one_of
52
+
53
+ args.each do |arg|
54
+ raise Linen::Plugin::ArgumentError,
55
+ "Argument '#{arg}' has not been defined" unless @plugin.arguments.include? arg
56
+
57
+ @arguments << arg
58
+ end
59
+ end
60
+
61
+
62
+ def required_arguments( *args )
63
+ raise Linen::Plugin::ArgumentError,
64
+ "You may not specify both required and one_of arguments" if @argument_type == :one_of
65
+
66
+ @argument_type = :required
67
+
68
+ args.each do |arg|
69
+ raise Linen::Plugin::ArgumentError,
70
+ "Argument '#{arg}' has not been defined" unless @plugin.arguments.include? arg
71
+
72
+ @arguments << arg
73
+ end
74
+ end
75
+ alias required_argument required_arguments
76
+
77
+
78
+ def help_message( message )
79
+ @help_text = message
80
+ end
81
+
82
+
83
+ def action( &block )
84
+ @action_proc = block
85
+ end
86
+
87
+
88
+ ##################
89
+ # HELPER METHODS #
90
+ ##################
91
+
92
+ def validate_arguments( args )
93
+ if @argument_type == :one_of
94
+ return validate_one_of_arguments( args.first )
95
+ else # @argument_type == :required
96
+ return validate_required_arguments( args )
97
+ end
98
+
99
+ # this is a Can't Happen(tm) so I'm comfortable with the crappy
100
+ # exception string. :P
101
+ raise "Something has happened!"
102
+ end
103
+
104
+
105
+ ###########
106
+ private #
107
+ ###########
108
+
109
+ ### FIXME:bbleything
110
+ ###
111
+ ### The reprompting stuff below is going to come back to bite us when we try to
112
+ ### add batch mode later... that said, in the interest of getting things out the
113
+ ### door, we're going to leave it be for now.
114
+
115
+ def validate_one_of_arguments( arg )
116
+ results = IndifferentHash.new
117
+
118
+ begin
119
+ @arguments.each do |arg_name|
120
+ argument = @plugin.arguments[ arg_name ]
121
+
122
+ results[ arg_name ] = argument.validate( arg ) rescue nil
123
+ end
124
+
125
+ raise Linen::Plugin::ArgumentError,
126
+ "The value you entered ('#{arg}') is invalid for all arguments." if
127
+ results.values.compact.empty?
128
+
129
+ rescue Linen::Plugin::ArgumentError => e
130
+ print "#{e} "
131
+
132
+ arg = Linen::CLI.reprompt.split.first
133
+
134
+ retry
135
+ end
136
+
137
+ return results
138
+ end
139
+
140
+
141
+ def validate_required_arguments( args )
142
+ results = IndifferentHash.new
143
+
144
+ @arguments.each do |arg_name|
145
+ argument = @plugin.arguments[ arg_name ]
146
+ arg_value = args.shift
147
+
148
+ begin
149
+ arg_value = Linen::CLI.reprompt( argument.prompt ) if arg_value.nil?
150
+
151
+ argument.validate arg_value
152
+
153
+ rescue Linen::Plugin::ArgumentError => e
154
+ print "#{e} "
155
+
156
+ # reset arg_value to nil so we get prompted on retry
157
+ arg_value = nil
158
+
159
+ retry
160
+ else
161
+ results[ arg_name ] = argument.convert( arg_value )
162
+ end
163
+ end
164
+
165
+ return results
166
+ end
167
+ end
data/lib/linen/plugin.rb CHANGED
@@ -59,7 +59,7 @@ class Linen::Plugin
59
59
  ### so return the hash.
60
60
  def self::arguments( *args )
61
61
  @defined_arguments ||= IndifferentHash.new
62
-
62
+
63
63
  return @defined_arguments if args.empty?
64
64
 
65
65
  args.each do |arg|
@@ -98,92 +98,3 @@ class Linen::Plugin
98
98
  @description = input
99
99
  end
100
100
  end
101
-
102
- class Linen::Plugin::Argument
103
- attr_reader :name, :prompt
104
-
105
- def initialize( plugin, name, opts )
106
- @plugin = plugin
107
- @name = name
108
- @prompt = opts[:prompt] || "Please enter the value for #{@name}"
109
- @validation = opts[:validation] || /^\w+$/
110
- @conversion = opts[:conversion] || nil
111
- end
112
-
113
-
114
- def convert( value )
115
- return value unless @conversion
116
- return @conversion.call( value )
117
- end
118
-
119
-
120
- def validate( value )
121
- if @validation.is_a? Proc
122
- result = @validation.call( value )
123
- else
124
- result = ( value =~ @validation )
125
- end
126
-
127
- raise Linen::Plugin::ArgumentError, "Value '#{value}' is invalid for #{self.name}. " unless result
128
- end
129
- end
130
-
131
- class Linen::Plugin::Command
132
- attr_reader :name, :arguments
133
-
134
- def initialize( plugin, name, &block )
135
-
136
- @plugin = plugin
137
- @name = name
138
- @arguments = []
139
- @help_text = "No help for #{plugin.short_name} #{name}"
140
-
141
- self.instance_eval &block
142
- end
143
-
144
-
145
- def execute( workspace = Linen::Workspace.new )
146
- return workspace.instance_eval( &@action_proc )
147
- end
148
-
149
-
150
- def help
151
- output = []
152
-
153
- output << @help_text.wrap
154
- output << nil # blank line
155
-
156
- # this map turns our list of args into a list like this:
157
- # <arg1> <arg2> <arg3> <arg4>...
158
- arg_list = arguments.map {|a| "<#{a.to_s}>"}.join( ' ' )
159
-
160
- output << "Usage: #{@plugin.short_name} #{name} #{arg_list}"
161
-
162
- return output.join( "\n" )
163
- end
164
-
165
-
166
- #######
167
- private
168
- #######
169
-
170
- def required_arguments( *args )
171
- args.each do |arg|
172
- raise Linen::Plugin::ArgumentError,
173
- "Argument '#{arg}' has not been defined" unless @plugin.arguments.include? arg
174
-
175
- @arguments << arg
176
- end
177
- end
178
- alias required_argument required_arguments
179
-
180
-
181
- def help_message( message )
182
- @help_text = message
183
- end
184
-
185
-
186
- def action( &block )
187
- @action_proc = block
188
- end
189
- end
@@ -17,4 +17,13 @@ class Linen::Workspace
17
17
  # add ivar
18
18
  instance_variable_set "@#{name}", value
19
19
  end
20
+
21
+ def add_values( hash )
22
+ raise ArgumentError,
23
+ "must send a hash" unless hash.is_a? Hash
24
+
25
+ hash.each do |k,v|
26
+ self.set_value k, v
27
+ end
28
+ end
20
29
  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.2.0
6
+ version: 0.3.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:
@@ -34,7 +34,9 @@ files:
34
34
  - LICENSE
35
35
  - lib/indifferent_hash.rb
36
36
  - lib/linen
37
+ - lib/linen/argument.rb
37
38
  - lib/linen/cli.rb
39
+ - lib/linen/command.rb
38
40
  - lib/linen/exceptions.rb
39
41
  - lib/linen/plugin.rb
40
42
  - lib/linen/plugin_registry.rb