pablo 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig ADDED
Binary file
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 1.0.3 / 2009-05-05
2
+
3
+ * First release of version 1
4
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ /*---- DON'T PANIC License 1.1 -----------
2
+
3
+ Don't panic, this piece of software is
4
+ free, i.e. you can do with it whatever
5
+ you like, including, but not limited to:
6
+
7
+ * using it
8
+ * copying it
9
+ * (re)distributing it
10
+ * burning/burying/shredding it
11
+ * eating it
12
+ * using it to obtain world domination
13
+ * and ignoring it
14
+
15
+ Under the sole condition that you
16
+
17
+ * CONSIDER buying the author a strong
18
+ brownian motion producer, say a nice
19
+ hot cup of tea, should you ever meet
20
+ him in person.
21
+
22
+ ----------------------------------------*/
data/Manifest.txt ADDED
@@ -0,0 +1,26 @@
1
+ History.txt
2
+ LICENSE.txt
3
+ Manifest.txt
4
+ README.txt
5
+ lib/pablo.rb
6
+ lib/pablo/always.rb
7
+ lib/pablo/arguments.rb
8
+ lib/pablo/color.rb
9
+ lib/pablo/command.rb
10
+ lib/pablo/errors.rb
11
+ lib/pablo/expansion.rb
12
+ lib/pablo/help.rb
13
+ lib/pablo/helpers.rb
14
+ lib/pablo/option.rb
15
+ lib/pablo/parser.rb
16
+ lib/pablo/token.rb
17
+ lib/pablo/version.rb
18
+ test/fixtures/license.txt
19
+ test/fixtures/load_yaml.yml
20
+ test/fixtures/output.yml
21
+ test/help_fixtures.rb
22
+ test/test_arguments.rb
23
+ test/test_expansion.rb
24
+ test/test_output.rb
25
+ test/test_pablo.rb
26
+ test/test_parsers.rb
data/README.txt ADDED
@@ -0,0 +1,61 @@
1
+ = pablo
2
+
3
+ Support for pablo is given at http://pablo.rubyforge.org/.
4
+ If you have questions, problems, want to report bugs or request features, this is the
5
+ place for you.
6
+ Have fun with it!
7
+
8
+ == DESCRIPTION
9
+
10
+ This is pablo, a Ruby commandline parser that follows the command/option paradigm.
11
+ pablo stands for "PArsing BLOcks" (I know, it's a really stupid name).
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Commandline parsing following the well-known command/option paradigm (like `gem` does).
16
+ * Easy declaration and description of commands/options via YAML syntax
17
+ * Auto-generated `help`, `version` and `license` commands
18
+ * Optional expansion of commands and options and detection of ambiguities
19
+
20
+ == SYNOPSIS:
21
+
22
+ pablo ARGV, :program => 'test', :desc => 'a test program',
23
+ :version => '1.0', :license => 'GPL or something' do
24
+
25
+ desc('prints foo')
26
+ option :foo do
27
+ puts 'foo'
28
+ end
29
+
30
+ help_command
31
+ version_command
32
+ license_command
33
+ ambiguity_command
34
+
35
+ command :bar do |args, pablo|
36
+ option :goo || missing_argument('goo')
37
+
38
+ if pablo.options[:goo]
39
+ puts 'goo'
40
+ else
41
+ puts 'bar'
42
+ end
43
+ end
44
+ end
45
+
46
+ == REQUIREMENTS:
47
+
48
+ * none so far
49
+
50
+ == INSTALL:
51
+
52
+ * On Linux:
53
+ sudo gem install -t pablo
54
+ * On Windows:
55
+ gem install -t pablo
56
+
57
+ == LICENSE:
58
+
59
+ DON'T PANIC License v1.1
60
+ See LICENSE.txt for full license text
61
+
data/lib/pablo.rb ADDED
@@ -0,0 +1,298 @@
1
+ ###### DON'T PANIC License 1.1 ###########
2
+ #
3
+ # Don't panic, this piece of software is
4
+ # free, i.e. you can do with it whatever
5
+ # you like, including, but not limited to:
6
+ #
7
+ # * using it
8
+ # * copying it
9
+ # * (re)distributing it
10
+ # * burning/burying/shredding it
11
+ # * eating it
12
+ # * using it to obtain world domination
13
+ # * and ignoring it
14
+ #
15
+ # Under the sole condition that you
16
+ #
17
+ # * CONSIDER buying the author a strong
18
+ # brownian motion producer, say a nice
19
+ # hot cup of tea, should you ever meet
20
+ # him in person.
21
+ #
22
+ ##########################################
23
+
24
+ # other libs
25
+ require 'yaml'
26
+
27
+ # global helpers
28
+ require 'pablo/helpers'
29
+
30
+ # standard equipment
31
+ require 'pablo/arguments'
32
+ require 'pablo/parser'
33
+ require 'pablo/command'
34
+ require 'pablo/option'
35
+ require 'pablo/token'
36
+ require 'pablo/always'
37
+
38
+ # additional gadgets
39
+ require 'pablo/color'
40
+ require 'pablo/errors'
41
+ require 'pablo/expansion'
42
+ require 'pablo/help'
43
+
44
+ #
45
+ # Shortcut. Creates a Pablo instance, instance_evals the
46
+ # given block on it an calls Pablo#parse.
47
+ # Also, if +args+ is empty, +ARGV+ will be used.
48
+ def pablo args, opts = Hash.new, &block
49
+ raise 'pablo needs a block to do something senisble' unless block_given?
50
+ args = [ARGV] if args.empty?
51
+ p = Pablo.new opts
52
+ p.instance_eval(&block)
53
+ p.parse args
54
+ end
55
+
56
+ #
57
+ # Does the heavy lifting.
58
+ class Pablo
59
+
60
+ include Pablo::Helpers
61
+
62
+ attr_accessor :args
63
+ attr_accessor :options, :commands, :tokens
64
+ attr_accessor :registered, :expand
65
+
66
+ #
67
+ # * +opts+: options for Pablo
68
+ # * :command_consumes_all => true|false
69
+ # Forces toplevel commands (not) to consume all arguments after
70
+ # being applied.
71
+ # I'm still looking for a better name for that option, so it may
72
+ # be subject to change.
73
+ # * :expand => true|false|Array
74
+ # Turns on the automatic abbreviation expansion mechanism for
75
+ # * all parsers (true)
76
+ # * no parsers (false)
77
+ # * a specific parser (Array containing :commands and/or :options)
78
+ # * :program => String
79
+ # The name of the Program to be displayed by +help+ and +version+.
80
+ # * :version => String
81
+ # The version of the Program to be displayed by +version+ and +help+.
82
+ # * :usage => String
83
+ # The usage information of the Program to be displayed by +help+, e.g.
84
+ # [<command>] [<options>]
85
+ def initialize opts = Hash.new
86
+ @opts = {
87
+ :command_consumes_all => true,
88
+ :expand => false
89
+ }.merge(opts)
90
+
91
+ check_options()
92
+
93
+ @finalize = @colorize = @cur = nil
94
+ @toplevel, @args, @pending = true, nil, Hash.new
95
+ @expand, @ambiguity, @registered = Array.new, nil, Array.new
96
+ @options, @commands, @tokens = Hash.new, Hash.new, Hash.new
97
+ end
98
+
99
+ #
100
+ # Starts the parsing process on the given +args+,
101
+ # according to the registered parsers.
102
+ def parse args
103
+ @toplevel, @args = false, Pablo::Arguments.new(args)
104
+
105
+ catch :abort do
106
+ begin
107
+ @registered.each { |parser|
108
+ @cur = parser
109
+ parser.parse(@args)
110
+ }
111
+ true
112
+ rescue MissingArgumentError, WrongArgumentError => e
113
+ $stderr.puts e.message
114
+ false
115
+ end
116
+ end
117
+ end
118
+
119
+ #
120
+ # Define a command.
121
+ # +args+ must be:
122
+ # * at least one name for the command
123
+ # * a hash of options:
124
+ # * :default
125
+ # The default value to be set if the command is not recognized.
126
+ # * :consume_all => true|false
127
+ # Whether (or not) the command should consume_all remaining
128
+ # arguments after it has been recognized
129
+ # * :consume => Fixnum|String|Regexp|Array
130
+ # * Fixnum: consume the next n arguments
131
+ # * String: consume if the next argument equals that String. Else
132
+ # the option will not match.
133
+ # * Regexp: consume if the next argument matches that Regexp. Else
134
+ # the option will not match.
135
+ # * Array: consume next +arr.length+ arguments if they equal those
136
+ # given in the Array.
137
+ # * :expand => Proc
138
+ # A Proc that will be passed a single argument String and a single
139
+ # name of the token as parameters and has to return a Boolean indicating
140
+ # whether or not the String is an abbreviation of that name.
141
+ def command *args, &block
142
+ exec(Pablo::Command, *args, &block)
143
+ end
144
+ alias_method :cmd, :command
145
+
146
+ #
147
+ # Define an option.
148
+ # +args+ must be:
149
+ # * at least one name for the command
150
+ # * a hash of options:
151
+ # * :default
152
+ # The default value to be set if the option is not recognized.
153
+ # * :negative => true|false|String
154
+ # If +true+, the option will have a counterpart named +--no<name>+.
155
+ # If a String, the option will have a counterpart named
156
+ # +--<string><name>+.
157
+ # * :consume => Fixnum|String|Regexp|Array
158
+ # * Fixnum: consume the next n arguments
159
+ # * String: consume if the next argument equals that String. Else
160
+ # the option will not match.
161
+ # * Regexp: consume if the next argument matches that Regexp. Else
162
+ # the option will not match.
163
+ # * Array: consume next +arr.length+ arguments if they equal those
164
+ # given in the Array.
165
+ # * :expand => Proc
166
+ # A Proc that will be passed a single argument String and a single
167
+ # name of the token as parameters and has to return a Boolean indicating
168
+ # whether or not the String is an abbreviation of that name.
169
+ def option *args, &block
170
+ exec(Pablo::Option, *args, &block)
171
+ end
172
+ alias_method :opt, :option
173
+
174
+ #
175
+ # Define a token.
176
+ # +args+ must be:
177
+ # * at least one name for the command
178
+ # * a hash of options:
179
+ # * :default
180
+ # The default value to be set if the token is not recognized.
181
+ # * :consume => Fixnum|String|Regexp|Array
182
+ # * Fixnum: consume the next n arguments
183
+ # * String: consume if the next argument equals that String. Else
184
+ # the option will not match.
185
+ # * Regexp: consume if the next argument matches that Regexp. Else
186
+ # the option will not match.
187
+ # * Array: consume next +arr.length+ arguments if they equal those
188
+ # given in the Array.
189
+ def token *args, &block
190
+ exec(Pablo::Token, *args, &block)
191
+ end
192
+ alias_method :tok, :token
193
+
194
+ #
195
+ # Define arbitrary code to always run at that stage of parsing.
196
+ def always &block
197
+ exec(Pablo::Always, &block)
198
+ end
199
+
200
+ #
201
+ # Set the short description of the next parser.
202
+ def desc d
203
+ @pending[:desc] = d
204
+ end
205
+
206
+ #
207
+ # Set the long description of the next parser.
208
+ def longdesc l
209
+ @pending[:longdesc] = l
210
+ end
211
+
212
+ #
213
+ # Set the usage information of the next parser.
214
+ def usage u
215
+ @pending[:usage] = u
216
+ end
217
+
218
+ #
219
+ # Loads whole parsers and global options from a YAML source.
220
+ # +yml+ can either be a String of YAML or the path of a YAML file.
221
+ def load_yaml yml
222
+ yml = open(yml).read() if File.exist?(yml)
223
+ opts = YAML::load(yml)
224
+
225
+ parsers = opts.delete(:parsers)
226
+ @opts.merge!(opts)
227
+
228
+ parsers.each do |p|
229
+ type = [:command, :token, :option, :help_command,
230
+ :ambiguity_command, :license_command, :version_command].find { |s| !p[s].nil? }
231
+
232
+ unless type.nil?
233
+ args = p.delete(type)
234
+
235
+ if args.is_a? Array then args << p
236
+ else args = [p]
237
+ end
238
+
239
+ type == :ambiguity_command ?
240
+ self.send(type) : self.send(type, *args)
241
+ end
242
+ end
243
+ end
244
+
245
+ #
246
+ # Whether or not we dwell at toplevel currently.
247
+ # Only valid within a Command, Option, Token etc,
248
+ # but NOT within this class.
249
+ def toplevel?
250
+ @toplevel
251
+ end
252
+
253
+ #
254
+ # Sets the run object for this pablo instance.
255
+ def run= object
256
+ @opts[:run] = object
257
+ end
258
+
259
+ #
260
+ # Returns the object which keeps all the instance methods corresponding
261
+ # to the defined parsers - or +nil+ if none was given
262
+ def run_object
263
+ @opts[:run]
264
+ end
265
+
266
+ #
267
+ # Whether or not commands should consume all arguments after they
268
+ # parsed something.
269
+ def consume_all?
270
+ @opts[:command_consumes_all]
271
+ end
272
+
273
+ private
274
+
275
+ def check_options
276
+ raise ":expand expects any of true, false, :commands, :options" unless
277
+ [true, false, :commands, :options].include? @opts[:expand]
278
+ %w{program version usage}.each { |sym|
279
+ raise ":#{sym} expects a String" unless
280
+ @opts[sym.to_sym].nil? or @opts[sym.to_sym].respond_to? :to_str
281
+ }
282
+ end
283
+
284
+ #
285
+ # Generalization of command, option etc. methods.
286
+ def exec klass, *args, &block
287
+ opts = args[-1].respond_to?(:to_hash) ?
288
+ args.delete_at(-1).to_hash : Hash.new
289
+ opts = @pending.merge(opts)
290
+ @pending.clear
291
+ args << opts
292
+
293
+ e = klass.new(self, *args, &block)
294
+ e.parse(@args) unless @toplevel
295
+ end
296
+
297
+ end
298
+
@@ -0,0 +1,44 @@
1
+ ###### DON'T PANIC License 1.1 ###########
2
+ #
3
+ # Don't panic, this piece of software is
4
+ # free, i.e. you can do with it whatever
5
+ # you like, including, but not limited to:
6
+ #
7
+ # * using it
8
+ # * copying it
9
+ # * (re)distributing it
10
+ # * burning/burying/shredding it
11
+ # * eating it
12
+ # * using it to obtain world domination
13
+ # * and ignoring it
14
+ #
15
+ # Under the sole condition that you
16
+ #
17
+ # * CONSIDER buying the author a strong
18
+ # brownian motion producer, say a nice
19
+ # hot cup of tea, should you ever meet
20
+ # him in person.
21
+ #
22
+ ##########################################
23
+
24
+ class Pablo
25
+
26
+ class Always
27
+
28
+ def initialize pablo, *args, &block
29
+ @pablo, @block = pablo, block
30
+ @pablo.registered << self
31
+ end
32
+
33
+ def parse args
34
+ @block.call(args, @pablo)
35
+ end
36
+
37
+ def names_to_user; ''; end
38
+ def names_to_rex; nil; end
39
+ def klass_to_sym; :always; end
40
+
41
+ end
42
+
43
+ end
44
+