Pablo 0.0.1

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.
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