Pablo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +20 -0
  2. data/lib/pablo.rb +458 -0
  3. data/tests/help.rb +135 -0
  4. data/tests/tests.rb +290 -0
  5. metadata +55 -0
data/README ADDED
@@ -0,0 +1,20 @@
1
+
2
+ This is Pablo, a Ruby commandline parser that is entirely based on the concept of blocks.
3
+ Pablo stands for "PArsing BLOcks" (I know, it's a really stupid name).
4
+
5
+ _______________________________________________________
6
+
7
+ License: Creative Commons Attribution 3.0 Germany
8
+ For further information regarding this license, visit:
9
+ http://creativecommons.org/licenses/by/3.0/de/
10
+ ______________________________________________________
11
+
12
+
13
+ Support for Pablo is given at http://pablo.rubyforge.org/ .
14
+ =============================
15
+
16
+ If you have questions, problems, want to report bugs or request features, this is the
17
+ place for you.
18
+
19
+ Have fun with it!
20
+
data/lib/pablo.rb ADDED
@@ -0,0 +1,458 @@
1
+ # This is Pablo, a commandline parser for Ruby based entirely on the
2
+ # concept of blocks.
3
+ #
4
+ # If you want to find out more or need a tutorial, go to
5
+ # http://pablo.rubyforge.org/
6
+ # You'll find a nice wiki there!
7
+ #
8
+ # Author:: Fabian Streitel (karottenreibe)
9
+ # Copyright:: Copyright (c) 2008 Fabian Streitel
10
+ # License:: Creative Commons Attribution 3.0 Germany
11
+ # For further information regarding this license, you can go to
12
+ # http://creativecommons.org/licenses/by/3.0/de/
13
+ # Homepage:: http://pablo.rubyforge.org/
14
+ # Git repo:: http://www.github.org/pablo-commandline-parser/
15
+ #
16
+
17
+ module Pablo
18
+ ##
19
+ # Parses arguments with the help of the tokens defined in the +block+.
20
+ #
21
+ # The arguments passed to the parser can be
22
+ # - one Hash, containing the options for the parsing process and
23
+ # - one Array, containing the arguments that should be parsed
24
+ #
25
+ # Either of the two can be omitted.
26
+ # If no arguments Array is found, +ARGV+ is parsed.
27
+ # If no options Hash is found, the defaults are used.
28
+ #
29
+ # See _Pablo::Parser#command_ and _Pablo::Parser#option_ for more details.
30
+ #
31
+ def self.parse *argsopts, &block
32
+ # parse arguments and options apart
33
+ args, opts = nil, {}
34
+ args = argsopts[1] if argsopts[1].is_a? Array
35
+ args = argsopts[0] if argsopts[0].is_a? Array
36
+ opts = argsopts[1] if argsopts[1].is_a? Hash
37
+ opts = argsopts[0] if argsopts[0].is_a? Hash
38
+
39
+ args = ARGV if args.nil?
40
+ # do under NO circumstances modify the real args
41
+ args = args.dup
42
+
43
+ # create tokens
44
+ p = Pablo::TopLevel.new opts
45
+ p.instance_eval &block if block_given?
46
+
47
+ # test on a present help command
48
+ return if p.help? args
49
+
50
+ # prepare arguments for marking
51
+ args.collect! { |a| [ [], a ] }
52
+
53
+ # start marking
54
+ p.mark args
55
+
56
+ # start parsing
57
+ # we process the args until there are no remaining tokens that request parsing
58
+ empty = !args.any? { |pair| not pair[0].empty? }
59
+
60
+ # do the defaults if noone wants parsing
61
+ return p.do_defaults if empty
62
+
63
+ while not empty
64
+ # get the next token
65
+ next_token = args.index { |pair| not pair[0].empty? }
66
+ # parse it
67
+ args[next_token][0][0].parse args
68
+ # test on empty again
69
+ empty = !args.any? { |pair| not pair[0].empty? }
70
+ end
71
+ end
72
+
73
+ ##
74
+ # The base class for all parsing tokens, i.e. Options and Commands.
75
+ #
76
+ # Each token is expected to implement a mark and a parse method.
77
+ # The mark method is expected to mark all the occurrences of the command with a reference to
78
+ # it's +self+ object.
79
+ # The parse method will get all the parameters (including subcommands) for consuming.
80
+ #
81
+ class Token
82
+ ##
83
+ # Initializes the structure so it's ready for processing
84
+ #
85
+ def initialize toplevel
86
+ @toplevel = toplevel
87
+ @toplevel.everyone << self if self != @toplevel
88
+ @aliases = []
89
+ @run = lambda {}
90
+ @requests = []
91
+ @tokens = []
92
+ @default = false
93
+ @sdesc = ""
94
+ @ldesc = ""
95
+ end
96
+
97
+ attr_reader :tokens
98
+
99
+ ##
100
+ # Sets the +block+ to run on discovery of the token.
101
+ #
102
+ def run &block
103
+ @run = block if block_given?
104
+ end
105
+
106
+ ##
107
+ # Adds the alias +a+ to the list of aliases for this token.
108
+ #
109
+ def name a
110
+ @aliases << a.to_s
111
+ end
112
+
113
+ attr_reader :aliases
114
+
115
+ ##
116
+ # Marks all occurences of this command's aliases
117
+ #
118
+ def mark args
119
+ args.collect { |pair|
120
+ @aliases.each { |a| pair[0] << self if pair[1] == a }
121
+ pair
122
+ }
123
+
124
+ mark_children args
125
+ end
126
+
127
+ ##
128
+ # A very basic implementation of parse that can be utilized by subclasses to make their
129
+ # code look tidier.
130
+ #
131
+ # Basically goes through the +args+ and removes the consumed arguments if there are any
132
+ # and calls the +@run+ block if there is any.
133
+ #
134
+ # If you supply a +block+ it will be executed instead of the +@run+ block.
135
+ #
136
+ def parse args, &block
137
+ # if no block has been given, we do the default
138
+ # watch out here: if you use a name that is already present (like args) for
139
+ # the block argument variable, it will actually use the already present
140
+ # variable! (not nice!)
141
+ block = lambda { |argus| @run.call argus } unless block_given?
142
+
143
+ return args if ( not @run and not block_given? ) or # no need to parse if we don't run anything...
144
+ @aliases.empty? # ...or don't have any names anyways.
145
+
146
+ # find ourselves
147
+ myself = args.index { |pair| pair[0].include? self }
148
+ # if we're not present, we can go
149
+ return args unless myself
150
+
151
+ # where the next mark is
152
+ stop = args[myself+1..-1].index { |pair| not pair[0].empty? }
153
+ stop += myself+1 if stop
154
+
155
+ # which arguments we will consume
156
+ myargs = args[myself+1...stop] unless stop.nil?
157
+ myargs = args[myself+1..-1] if stop.nil?
158
+
159
+ # and call the block
160
+ block.call unmark(myargs)
161
+
162
+ # consume the arguments if there are any
163
+ (0..args.length-1).each { |i|
164
+ # remove ourselves from our call
165
+ args[i][0].delete self if myself == i
166
+
167
+ # if others have registered for these arguments as well, let them have
168
+ # their fair share of the cake.
169
+ if args[myself] and args[myself][0].empty?
170
+ # remove the whole call if there's noone else requesting it
171
+ args[i] = nil if myself == i
172
+ # remove our arguments
173
+ args[i] = nil if myself < i and ( not stop or i < stop )
174
+ end
175
+ }
176
+
177
+ args.reject! { |a| a.nil? }
178
+ end
179
+
180
+ ##
181
+ # Goes through +@tokens+ and let's each of them mark the args.
182
+ #
183
+ def mark_children args
184
+ org_args = args.dup
185
+ @tokens.each { |t| args = t.mark args }
186
+ args
187
+ end
188
+
189
+ ##
190
+ # Goes through +@tokens+ and let's each of them parse the args.
191
+ #
192
+ def parse_children args
193
+ @tokens.each { |t| args = t.parse args }
194
+ args
195
+ end
196
+
197
+ ##
198
+ # Whether or not the current token is a default token.
199
+ # I.e. it will be called in case no (recognized) arguments were supplied for the parent
200
+ # command (or the entire argument string if this is a level 1 token).
201
+ #
202
+ # _Note:_
203
+ # The blocks of default tokens' +@run+ blocks will be supplied with an empty array as a
204
+ # single argument when run as a default.
205
+ #
206
+ def default!; @default = true; end
207
+ attr_accessor :default
208
+
209
+ ##
210
+ # Run the associated block explicitly.
211
+ # Used when running default commands.
212
+ #
213
+ def run!
214
+ @run.call [] if @run
215
+ end
216
+
217
+ ##
218
+ # Removes all markings from the +args+ so they can be passed to the +@run+ block.
219
+ #
220
+ def unmark args
221
+ args.collect { |pair| pair[1] }
222
+ end
223
+
224
+ ##
225
+ # Call this to provide a short descriptive text for the +--help/-h/help+ command
226
+ #
227
+ def short_desc desc
228
+ @sdesc = desc
229
+ end
230
+
231
+ attr_reader :sdesc
232
+
233
+ ##
234
+ # Call this to provide a longer description of what the token does.
235
+ # This will be displayed when the user calls +--help/-h/help _command_+.
236
+ #
237
+ def long_desc desc
238
+ @ldesc = desc
239
+ end
240
+
241
+ attr_reader :ldesc
242
+ end
243
+
244
+ ##
245
+ # Keeps and parses an option.
246
+ # Simple, easy, no children.
247
+ #
248
+ class Option < Pablo::Token
249
+ ##
250
+ # Marks all occurences of this command's aliases
251
+ #
252
+ def mark args
253
+ args.collect { |pair|
254
+ @aliases.each { |a|
255
+ if a.length == 2 and '-' == a[0..0]
256
+ match = /-(.*)/.match pair[1]
257
+ pair[0] << self if match and match[1].include? a[1..1]
258
+ else
259
+ pair[0] << self if pair[1] == a
260
+ end
261
+ }
262
+ pair
263
+ }
264
+
265
+ mark_children args
266
+ end
267
+
268
+ ##
269
+ # Special name function for options. It prepends '--' or '-' to the name passed.
270
+ # Only exception, if the name already starts with '-' nothing will be changed.
271
+ #
272
+ def name a
273
+ if '-' == a[0..0] then super a
274
+ elsif 1 == a.length then super '-' + a
275
+ else super '--' + a
276
+ end
277
+ end
278
+ end
279
+
280
+ ##
281
+ # Keeps and parses a command.
282
+ # More sophisticated than an option, can have children.
283
+ #
284
+ class Command < Pablo::Token
285
+ ##
286
+ # Adds a subcommand to the current command. The +block+ will be executed in the context of
287
+ # the new command and can be used to set its aliases, what code to run on discovery etc.
288
+ #
289
+ def command &block
290
+ return unless block_given?
291
+ c = Pablo::Command.new @toplevel
292
+ c.instance_eval &block
293
+ @tokens << c
294
+ end
295
+
296
+ ##
297
+ # Adds an option to the command. The +block+ will be executed in the context of the option
298
+ # and can be used to set its aliases, what code to run on discovery etc.
299
+ #
300
+ def option &block
301
+ o = Pablo::Option.new @toplevel
302
+ o.instance_eval &block
303
+ @tokens << o
304
+ end
305
+
306
+ ##
307
+ # Implementation of parse for commands:
308
+ # - Let children mark
309
+ # - Parse ourselves using standard parse implementation
310
+ # - Let children parse
311
+ # - Return parsed args
312
+ #
313
+ def parse args
314
+ # will someone just for one second PLEASE think about the children!
315
+
316
+ # use the standard implementation to do the dirty job.
317
+ super args
318
+
319
+ # let the children have their fun as well!
320
+ parse_children args
321
+ end
322
+ end
323
+
324
+ ##
325
+ # Special TopLevel parser.
326
+ # Only instantiated by +Pablo::parse+. Contains additional commands.
327
+ #
328
+ class TopLevel < Pablo::Command
329
+ def initialize options
330
+ @everyone = []
331
+ @options = options
332
+ @help = false
333
+ super self # set toplevel
334
+ end
335
+
336
+ attr_accessor :everyone
337
+
338
+ ##
339
+ # Will run the default token's run block, if there is one or will try to show
340
+ # the help otherwise.
341
+ #
342
+ def do_defaults
343
+ done = false
344
+ @tokens.each { |t|
345
+ if t.default
346
+ t.run!
347
+ done = true
348
+ end
349
+ }
350
+
351
+ help? [] unless done
352
+ end
353
+
354
+ ##
355
+ # Tests whether a help command is present in +args+ and +help!+ has been called
356
+ # and if so:
357
+ # - executes +Pablo::help+
358
+ # - and returns true
359
+ # otherwise only returns false.
360
+ #
361
+ def help? args
362
+ return false unless @help
363
+ found = args.index { |a|
364
+ @help_aliases.any? { |h| h == a }
365
+ }
366
+ found = 0 if args.empty?
367
+ return false unless found
368
+ Pablo::help args[found+1..-1], @everyone, @options
369
+ return true
370
+ end
371
+
372
+ ##
373
+ # Instructs Pablo to display a help message generated from the +short_desc+
374
+ # and +long_desc+ descriptions of the tokens.
375
+ #
376
+ # +alis+ are the aliases the help command should respond to.
377
+ # By default these are _help_, _--help_ and _-h_.
378
+ #
379
+ def help! alis = ['help', '--help', '-h']
380
+ @help = true
381
+ @help_aliases = alis
382
+ end
383
+ end
384
+
385
+ ##TODO: Version command and version in help command
386
+ ##TODO: caseless aliases!
387
+
388
+ ##
389
+ # Displays a help message generated from the +short_desc+ and +long_desc+
390
+ # specifications of the tokens.
391
+ #
392
+ # Output depends on +args+.
393
+ #
394
+ # +tokens+ must be a complete list of all tokens defined in the parser.
395
+ #
396
+ # +options+ must be a hash of options that will be used to generate the
397
+ # output, namely +:program+, +:version+, +:usage+.
398
+ #
399
+ def self.help args, tokens, options
400
+ msg = ""
401
+ aliases = []
402
+ tokens.each { |t| t.aliases.each { |a| aliases << [a,t] } }
403
+
404
+ # whether help for a special command is requested or not
405
+ found = aliases.find { |a| a[0] == args[0] }
406
+ found = found[1] if found
407
+
408
+ # program name and version
409
+ puts "#{options[:program]} v#{options[:version].join '.'}" if
410
+ options[:program] and options[:version]
411
+
412
+ # usage
413
+ puts "Usage: #{options[:usage]}" if options[:usage]
414
+
415
+ if found # do long_desc
416
+ # print long_desc
417
+ print "Help for "
418
+ print case found
419
+ when Pablo::Command then 'command'
420
+ when Pablo::Option then 'option'
421
+ else 'Token'
422
+ end
423
+ puts " '#{args[0]}':"
424
+ puts
425
+ puts found.ldesc
426
+
427
+ # print aliases
428
+ puts
429
+ puts "::Aliases"
430
+ puts found.aliases.join ", "
431
+
432
+ # print subcommands if any
433
+ strs = []
434
+ found.tokens.each { |t| strs << t.aliases[0] }
435
+ puts "\n::Subcommands" unless strs.empty?
436
+ puts strs.join " "
437
+ else # do short_descs
438
+ # print short_descs
439
+ puts '::Available commands and options'
440
+ puts
441
+
442
+ strs = []
443
+ tokens.each { |t| strs << [ t.aliases.join(' '), t.sdesc ] }
444
+ maxrow = strs.max_by { |x| x[0].length } || ['']
445
+ maxlen = maxrow[0].length.to_i + 2
446
+ strs.each { |s| msg += s[0].ljust(maxlen) + '| ' + s[1] + "\n" }
447
+ puts msg
448
+
449
+ # print defaults if any
450
+ strs = []
451
+ tokens.each { |t| strs << t.aliases[0] if t.default }
452
+ puts "\n::Defaults" unless strs.empty?
453
+ puts strs.join ", "
454
+ end
455
+ end
456
+
457
+ end
458
+
data/tests/help.rb ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'lib/pablo'
4
+
5
+ def error msg
6
+ # win does not support ANSI color sequences
7
+ puts "\e[31m" + msg + "\e[0m" unless PLATFORM =~ /win32/
8
+ puts msg if PLATFORM =~ /win32/
9
+ raise msg
10
+ end
11
+
12
+ def message msg
13
+ # win does not support ANSI color sequences
14
+ puts "\e[33m" + msg + "\e[0m" unless PLATFORM =~ /win32/
15
+ puts msg if PLATFORM =~ /win32/
16
+ end
17
+
18
+ class Help < Test::Unit::TestCase
19
+ def testHelp
20
+ args = ['help']
21
+
22
+ puts
23
+ message 'Expected output: some stupid help message'
24
+ message "-----------------------------------------"
25
+
26
+ Pablo::parse args, :program => 'stupid', :version => [1,0,5],
27
+ :usage => 'stupid --null <String>' do
28
+ option {
29
+ name 'null'
30
+ short_desc 'Displays a lot of zeros'
31
+ run { error "option 'null' incorrectly called!" }
32
+ long_desc 'Zero Zero Zero Zero Zero Zero\nZero!'
33
+ }
34
+
35
+ command {
36
+ name 'oneortwo'
37
+ name 'anotherone'
38
+ short_desc 'Displays one or two'
39
+ long_desc 'One two? One two!\noneoneone twotwotwo.'
40
+ run { error "command 'oneortwo' incorrectly called!" }
41
+ default!
42
+ }
43
+
44
+ help!
45
+ end
46
+
47
+ message '-----------------------------------------'
48
+ message 'End of expected output'
49
+ end
50
+
51
+ def testCommandHelp
52
+ args = ['help', 'oneortwo']
53
+
54
+ puts
55
+ message 'Expected output: some stupid command help'
56
+ message '-----------------------------------------'
57
+
58
+ Pablo::parse args, :program => 'stupid', :version => [1,0,5],
59
+ :usage => 'stupid --null <String>' do
60
+ option {
61
+ name 'n'
62
+ name 'null'
63
+ short_desc 'Displays a lot of zeros'
64
+ long_desc "Zero Zero Zero Zero Zero Zero\nZero!"
65
+ run { error "option 'null' incorrectly called!" }
66
+ }
67
+
68
+ command {
69
+ name 'oneortwo'
70
+ name 'anotherone'
71
+ short_desc 'Displays one or two'
72
+ long_desc "One two? One two!\noneoneone twotwotwo."
73
+ default!
74
+ run { error "command 'oneortwo' incorrectly called!" }
75
+
76
+ command {
77
+ name 'threeAndFour'
78
+ }
79
+ }
80
+
81
+ help!
82
+ end
83
+
84
+ message '-----------------------------------------'
85
+ message 'End of expected output'
86
+ puts
87
+ end
88
+
89
+ def testHelpAliases
90
+ args = ['huuulpy']
91
+
92
+ puts
93
+ message 'Expected output: the same message again'
94
+ message "-----------------------------------------"
95
+
96
+ Pablo::parse args, :program => 'stupid', :version => [1,0,5],
97
+ :usage => 'stupid --null <String>' do
98
+ option {
99
+ name 'null'
100
+ short_desc 'Displays a lot of zeros'
101
+ run { error "option 'null' incorrectly called!" }
102
+ long_desc 'Zero Zero Zero Zero Zero Zero\nZero!'
103
+ }
104
+
105
+ command {
106
+ name 'oneortwo'
107
+ name 'anotherone'
108
+ short_desc 'Displays one or two'
109
+ long_desc 'One two? One two!\noneoneone twotwotwo.'
110
+ run { error "command 'oneortwo' incorrectly called!" }
111
+ default!
112
+ }
113
+
114
+ help! ['huuulpy', 'foo']
115
+ end
116
+
117
+ message '-----------------------------------------'
118
+ message 'End of expected output'
119
+ end
120
+
121
+ def testHelpDefault
122
+
123
+ puts
124
+ message 'Expected output: an empty help message'
125
+ message "-----------------------------------------"
126
+
127
+ Pablo::parse [] do
128
+ help!
129
+ end
130
+
131
+ message '-----------------------------------------'
132
+ message 'End of expected output'
133
+ end
134
+ end
135
+
data/tests/tests.rb ADDED
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+ require 'lib/pablo'
4
+
5
+ class Tests < Test::Unit::TestCase
6
+ def self.val
7
+ @@val
8
+ end
9
+
10
+ def self.val= v
11
+ @@val = v
12
+ end
13
+
14
+ def testSingleCommand
15
+ args = [ "add", "5" ]
16
+ Tests.val = 0
17
+
18
+ Pablo::parse args do
19
+ command {
20
+ name 'add'
21
+ run { |args| Tests.val += args[0].to_i }
22
+ }
23
+ end
24
+
25
+ assert_equal 5, Tests.val
26
+ end
27
+
28
+ def testSingleCharOption
29
+ args = [ "-n", "3" ]
30
+ Tests.val = 0
31
+
32
+ Pablo::parse args do
33
+ option {
34
+ name 'n'
35
+ run { |args| Tests.val += args[0].to_i }
36
+ }
37
+ end
38
+
39
+ assert_equal 3, Tests.val
40
+
41
+ end
42
+
43
+ def testMultiCharOption
44
+ args = [ "--nojo", "3" ]
45
+ Tests.val = 0
46
+
47
+ Pablo::parse args do
48
+ option {
49
+ name 'nojo'
50
+ run { |args| Tests.val += args[0].to_i }
51
+ }
52
+ end
53
+
54
+ assert_equal 3, Tests.val
55
+
56
+ end
57
+
58
+ def testDashPrependedOption
59
+ args = [ "-nojo", "3" ]
60
+ Tests.val = 0
61
+
62
+ Pablo::parse args do
63
+ option {
64
+ name '-nojo'
65
+ run { |args| Tests.val += args[0].to_i }
66
+ }
67
+ end
68
+
69
+ assert_equal 3, Tests.val
70
+
71
+ end
72
+
73
+ def testOptionMerging
74
+ args = [ "-no", "3" ]
75
+ Tests.val = 0
76
+
77
+ Pablo::parse args do
78
+ option {
79
+ name 'n'
80
+ run { |args| Tests.val += args[0].to_i }
81
+ }
82
+
83
+ option {
84
+ name 'o'
85
+ run { |args| Tests.val += args[0].to_i }
86
+ }
87
+ end
88
+
89
+ assert_equal 6, Tests.val
90
+
91
+ end
92
+
93
+ def testUnneccessaryData
94
+ args = [ "bla", "blu", "-n", "3", "dudu" ]
95
+ Tests.val = []
96
+
97
+ Pablo::parse args do
98
+ option {
99
+ name 'n'
100
+ run { |args|
101
+ Tests.val << args[0].to_i << args.count }
102
+ }
103
+ end
104
+
105
+ assert_equal 3, Tests.val[0]
106
+ assert_equal 2, Tests.val[1]
107
+
108
+ end
109
+
110
+ def testManyTokens
111
+ args = [ "add", "5", "add", "3", "-r", "2", "-m", "add", "3", "-m" ]
112
+ Tests.val = [ [0,0], [0,0], [0,0], 0 ]
113
+
114
+ Pablo::parse args do
115
+ command {
116
+ name 'add'
117
+ run { |args|
118
+ Tests.val[0][0] += 1 #call counter
119
+ Tests.val[0][1] += args.count #args counter
120
+ Tests.val[3] += args[0].to_i
121
+ }
122
+ }
123
+
124
+ option {
125
+ name 'r'
126
+ run { |args|
127
+ Tests.val[1][0] += 1
128
+ Tests.val[1][1] += args.count
129
+ Tests.val[3] -= args[0].to_i
130
+ }
131
+ }
132
+
133
+ option {
134
+ name 'm'
135
+ run { |args|
136
+ Tests.val[2][0] += 1
137
+ Tests.val[2][1] += args.count
138
+ Tests.val[3] += 10
139
+ }
140
+ }
141
+ end
142
+
143
+ assert_equal [3, 3], Tests.val[0]
144
+ assert_equal [1, 1], Tests.val[1]
145
+ assert_equal [2, 0], Tests.val[2]
146
+ assert_equal 29, Tests.val[3]
147
+
148
+ end
149
+
150
+ def testDefault
151
+ args = []
152
+ Tests.val= 0
153
+
154
+ Pablo::parse args do
155
+ command {
156
+ name 'never'
157
+ run { |args| Tests.val += 1 }
158
+ }
159
+
160
+ command {
161
+ name 'ever'
162
+ run { |args| Tests.val += 2 }
163
+ default!
164
+ }
165
+
166
+ command {
167
+ name 'java'
168
+ run { |args| Tests.val += 4 }
169
+ default!
170
+ }
171
+ end
172
+
173
+ assert_equal 6, Tests.val
174
+ end
175
+
176
+ def testDefaultCluttered
177
+ args = ['junky', 'bacon']
178
+ Tests.val= 0
179
+
180
+ Pablo::parse args do
181
+ command {
182
+ name 'never'
183
+ run { |args| Tests.val += 1 }
184
+ }
185
+
186
+ command {
187
+ name 'ever'
188
+ run { |args| Tests.val += 2 }
189
+ default!
190
+ }
191
+ end
192
+
193
+ assert_equal 2, Tests.val
194
+ end
195
+
196
+ ##TODO: still failing!
197
+ =begin
198
+ def testDefaultLevel2
199
+ args = ["bla"]
200
+ Tests.val= 0
201
+
202
+ Pablo::parse args do
203
+ command {
204
+ name 'never'
205
+ run { |args| Tests.val += 1 }
206
+ }
207
+
208
+ command {
209
+ name 'bla'
210
+ run { |args| Tests.val += 4 }
211
+
212
+ option {
213
+ name 'ever'
214
+ run { |args| Tests.val += 2 }
215
+ default!
216
+ }
217
+ }
218
+ end
219
+
220
+ assert_equal 6, Tests.val
221
+ end
222
+ =end
223
+
224
+ ##TODO: make code-order possible.
225
+ def testNaturalOrder
226
+ args = ["--first", "second"]
227
+ Tests.val = []
228
+
229
+ Pablo::parse args do
230
+ command {
231
+ name 'second'
232
+ run { |args| Tests.val << 2 }
233
+ }
234
+
235
+ option {
236
+ name 'first'
237
+ run { |args| Tests.val << 1 }
238
+ }
239
+ end
240
+
241
+ assert_equal [1,2], Tests.val
242
+ end
243
+
244
+ def testEmptyParser
245
+ Pablo::parse do
246
+ end
247
+ Pablo::parse
248
+ end
249
+
250
+ ##TODO: implement children before parent as well
251
+ ##TODO: implement passing of args from children to parents as well
252
+ def testParentBeforeChildren
253
+ args = ['add', 5, '--mul', 2]
254
+ Tests.val = 0
255
+
256
+ Pablo::parse args do
257
+ command {
258
+ name 'add'
259
+ run { |args| Tests.val += args[0].to_i }
260
+
261
+ option {
262
+ name 'mul'
263
+ run { |args| Tests.val *= args[0].to_i }
264
+ }
265
+ }
266
+ end
267
+
268
+ assert_equal 10, Tests.val
269
+ end
270
+
271
+ def testMultiOptions
272
+ args = ['-nu']
273
+ Tests.val = 0
274
+
275
+ Pablo::parse args do
276
+ option {
277
+ name 'n'
278
+ run { |args| Tests.val += 2 }
279
+ }
280
+
281
+ option {
282
+ name 'u'
283
+ run { |args| Tests.val += 5 }
284
+ }
285
+ end
286
+
287
+ assert_equal 7, Tests.val
288
+ end
289
+ end
290
+
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Pablo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Fabian Streitel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-07 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: karottenreibe @nospam@ gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/pablo.rb
26
+ - README
27
+ has_rdoc: true
28
+ homepage: http://pablo.rubyforge.org/
29
+ post_install_message:
30
+ rdoc_options: []
31
+
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: "0"
39
+ version:
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ requirements: []
47
+
48
+ rubyforge_project: pablo
49
+ rubygems_version: 1.3.1
50
+ signing_key:
51
+ specification_version: 2
52
+ summary: A commandline parser for Ruby that is entirely based on blocks.
53
+ test_files:
54
+ - tests/help.rb
55
+ - tests/tests.rb