linen 0.2.0 → 0.3.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 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