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.
@@ -0,0 +1,46 @@
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
+ #
27
+ # General purpose helpers.
28
+ module Helpers
29
+ private
30
+
31
+ #
32
+ # Indent text by n spaces.
33
+ def indent text, n
34
+ (' ' * n) + text.split(/\n/, -1).join("\n" + (' ' * n))
35
+ end
36
+
37
+ #
38
+ # Little rails-style helper.
39
+ def returning val
40
+ yield val
41
+ val
42
+ end
43
+ end
44
+
45
+ end
46
+
@@ -0,0 +1,89 @@
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 Option < Pablo::Parser
27
+
28
+ include Pablo::Helpers
29
+
30
+ def initialize *args, &block
31
+ super(*args, &block)
32
+ end
33
+
34
+ def parse args
35
+ name = nil
36
+ idx = args.zip((0...args.length).to_a).find_index { |(a,i)|
37
+ verifies?(a,i) and (name = matches?(a))
38
+ }
39
+
40
+ unless idx.nil?
41
+ args.consume idx
42
+ args.slice idx
43
+
44
+ unless @opts[:negates].nil?
45
+ @pablo.options[@opts[:negates].to_sym] = false
46
+ else
47
+ @pablo.options[name] = true
48
+ end
49
+
50
+ consume?(name, args)
51
+ run?(args)
52
+
53
+ args.unslice
54
+ true
55
+ else
56
+ false
57
+ end
58
+ end
59
+
60
+ #
61
+ # Format an option's names to be displayed to the user.
62
+ def names_to_user
63
+ @names.collect { |n| format(n) }.join('|')
64
+ end
65
+
66
+ #
67
+ # Format an option's names to be used in a Regexp
68
+ def names_to_rex
69
+ Regexp.new(@names.collect { |n| format(n) }.join('|'))
70
+ end
71
+
72
+ private
73
+
74
+ def format name
75
+ @toplevel ?
76
+ '--' + name.to_s :
77
+ '-' + name.to_s
78
+ end
79
+
80
+ def check_options
81
+ super()
82
+ raise ":negates expected to be a Symbol" unless
83
+ @opts[:negates].respond_to? :to_sym or @opts[:negates].nil?
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
@@ -0,0 +1,192 @@
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
+ #
27
+ # Superclass for Command, Option, Token etc.
28
+ # Handles common initialization tasks and provides helpers.
29
+ class Parser
30
+
31
+ include Pablo::Helpers
32
+
33
+ attr_accessor :names, :desc, :longdesc, :usage, :last_match
34
+
35
+ def initialize pablo, *args, &block
36
+ # set names, opts
37
+ @pablo, @toplevel, @block = pablo, pablo.toplevel?, block
38
+ @opts = Hash.new
39
+ @opts.merge!(args.delete_at(-1).to_hash) if args[-1].respond_to?(:to_hash)
40
+ check_options()
41
+
42
+ @file_methods =
43
+ %w{file? directory? exists? exist? executable? readable? writable?}.
44
+ collect(&:to_sym)
45
+ @verify, args = args.partition { |x|
46
+ [String, Array, Regexp, Proc, Fixnum, Range, Proc].include? x.class or @file_methods.include? x
47
+ }
48
+
49
+ [:position, :matches, :is].each do |sym|
50
+ @verify << @opts.delete(sym) unless @opts[sym].nil?
51
+ end
52
+
53
+ @names = args
54
+ check_names()
55
+
56
+ # build expansion table
57
+ names.each do |name|
58
+ name = format(name)
59
+ @pablo.expand << name unless @pablo.expand.include? name
60
+ end if @pablo.expands?(klass_to_sym())
61
+
62
+ # get desc, longdesc, usage
63
+ @desc, @longdesc, @usage = @opts[:desc], @opts[:longdesc], @opts[:usage]
64
+ %w{desc longdesc usage}.each { |sym| @opts.delete(sym.to_sym) }
65
+
66
+ # register
67
+ @pablo.registered << self
68
+ # set default
69
+ @names.each { |n| @pablo.send(klass_to_sym())[n] = @opts[:default] } unless @opts[:default].nil?
70
+ end
71
+
72
+ def klass_to_sym
73
+ case self
74
+ when Pablo::Command then :commands
75
+ when Pablo::Option then :options
76
+ when Pablo::Token then :tokens
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def format name
83
+ name.to_s
84
+ end
85
+
86
+ #
87
+ # If a block was given, this executes it.
88
+ # If a run object is specified, this executes the corresponding
89
+ # instance method.
90
+ def run? args
91
+ unless @block.nil?
92
+ @block.call(args, @pablo)
93
+ end
94
+
95
+ if @opts[:run] != false and not @pablo.run_object.nil?
96
+ meth = @names.find { |n|
97
+ @pablo.run_object.public_methods.any? { |m|
98
+ n == m.to_sym
99
+ }
100
+ }
101
+
102
+ unless meth.nil?
103
+ @pablo.run_object.send(meth, args, @pablo)
104
+ end
105
+ end
106
+ end
107
+
108
+ #
109
+ # Tests all the +@verify+ parameters against the given argument
110
+ # and index and returns +true+ if they all match and +false+ otherwise.
111
+ def verifies? arg, idx
112
+ @verify.all? do |ver|
113
+ case ver
114
+ when Array then ver.include? arg
115
+ when Regexp then ver =~ arg
116
+ when String then ver == arg
117
+ when Proc then ver.call(arg)
118
+ when Fixnum then ver == idx
119
+ when Range then ver.include? idx
120
+ when Proc then ver.call(arg, idx)
121
+ else # File methods
122
+ @file_methods.include?(ver) ?
123
+ File.send(ver, arg) :
124
+ true
125
+ end
126
+ end
127
+ end
128
+
129
+ #
130
+ # Returns true if +@opts[:consume]+ is not +nil+ and
131
+ # consumes whatever was specified in that case.
132
+ def consume? name, args
133
+ unless @opts[:consume].nil?
134
+ @pablo.send(klass_to_sym())[name] =
135
+ case @opts[:consume]
136
+ when String
137
+ args[0] == @opts[:consume] ?
138
+ returning(args[0]) { args.consume 0 } :
139
+ nil
140
+ when Array
141
+ returning(ret = @opts[:consume].find { |c| c == args[0] }) {
142
+ args.consume 0 unless ret.nil? }
143
+ when Regexp
144
+ args[0] =~ @opts[:consume] ?
145
+ returning(args[0]) { args.consume 0 } :
146
+ nil
147
+ when 1
148
+ returning(args[0]) { args.consume 0 }
149
+ when Fixnum
150
+ @opts[:consume] > 1 ?
151
+ returning(args[0...@opts[:consume]]) { args.consume 0 } :
152
+ nil
153
+ end
154
+
155
+ true
156
+ else false
157
+ end
158
+ end
159
+
160
+ #
161
+ # Expands the given +name+ if expansion is turned on for this
162
+ # type of Parser and the +name+ matches one of this parser's
163
+ # names - optionally with a prefix assigned.
164
+ # If not, the name is matched unexpanded.
165
+ # If no match is found, nil is returned.
166
+ def matches? arg
167
+ arg = @pablo.expand!(arg)
168
+
169
+ @last_match = @names.find do |n|
170
+ format(n.to_s) == arg
171
+ end
172
+ end
173
+
174
+ def check_names
175
+ raise ArgumentError.new("names must be Symbols") if @names.any? { |n| !n.is_a?(Symbol) }
176
+ end
177
+
178
+ def check_options
179
+ raise ":consume expected to be any of Fixnum, Array, String, Regexp" unless
180
+ [Fixnum, Array, String, Regexp].include? @opts[:consume].class or @opts[:consume].nil?
181
+ raise ":position expected to be any of Fixnum, Range" unless
182
+ [Fixnum, Range].include? @opts[:position].class or @opts[:position].nil?
183
+ raise ":is expected to be any of Array, String" unless
184
+ [Array, String].include? @opts[:is].class or @opts[:is].nil?
185
+ raise ":matches expected to be a Regexp" unless
186
+ @opts[:matches].is_a? Regexp or @opts[:matches].nil?
187
+ end
188
+
189
+ end
190
+
191
+ end
192
+
@@ -0,0 +1,66 @@
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 Token < Pablo::Parser
27
+
28
+ include Pablo::Helpers
29
+
30
+ def parse args
31
+ idx = args.zip((0...args.length).to_a).find_index { |(a,i)|
32
+ verifies?(a,i)
33
+ }
34
+
35
+ unless idx.nil?
36
+ name = @names[0]
37
+ args.slice idx
38
+ @names.each { |n| @pablo.tokens[n] = true } unless name.nil?
39
+
40
+ if returning(consume?(name, args)) { run?(args) }
41
+ @names[1..-1].each { |n| @pablo.tokens[n] = @pablo.tokens[@names[0]] }
42
+ end
43
+
44
+ args.unslice
45
+ true
46
+ else
47
+ false
48
+ end
49
+ end
50
+
51
+ #
52
+ # Format a token's names to be displayed to the user.
53
+ def names_to_user
54
+ @names.collect(&:to_s).join('|')
55
+ end
56
+
57
+ #
58
+ # Format a token's names to be used in a Regexp
59
+ def names_to_rex
60
+ Regexp.new(names_to_user)
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
@@ -0,0 +1,29 @@
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
+ VERSION = '1.0.3'
27
+
28
+ end
29
+
@@ -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
+ ----------------------------------------*/