pablo 1.0.3

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