pablo 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,76 @@
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
+ # Safely encapsules the arguments and provides means to
27
+ # manipulate them
28
+ class Arguments
29
+
30
+ # undef all instance methods so we can use this as
31
+ # a proxy to the underlying Array
32
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
33
+
34
+ def method_missing sym, *args, &block
35
+ @slices[-1][:arr].send(sym, *args, &block)
36
+ end
37
+
38
+ def initialize arr
39
+ @slices = [{:idx => 0, :arr => arr}]
40
+ end
41
+
42
+ def consume idx
43
+ @slices[-1][:arr].delete_at idx
44
+ end
45
+
46
+ def consumed?
47
+ @slices[-1][:arr].empty?
48
+ end
49
+
50
+ def consume_all
51
+ @slices[-1][:arr].clear
52
+ end
53
+
54
+ #
55
+ # Constrain arguments on the subset +idx..-1+.
56
+ def slice idx
57
+ @slices << {
58
+ :idx => idx,
59
+ :arr => @slices[-1][:arr][idx..-1]
60
+ }
61
+ end
62
+
63
+ #
64
+ # Remove arguments constrain and reconcile arguments
65
+ # with slice.
66
+ def unslice
67
+ raise "cannot unslice fully unsliced Arguments" unless @slices.length > 1
68
+ idx, arr = @slices[-1][:idx], @slices[-1][:arr]
69
+ @slices[-2][:arr][idx..-1] = arr
70
+ @slices.delete_at(-1)
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
@@ -0,0 +1,57 @@
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
+ # Runs the given +block+, whenever something needs to be given color.
28
+ # The block will be given the following arguments:
29
+ # * The string to colorize
30
+ # * A symbol indicating the type of the String. The color should be
31
+ # guessed from that. Can be any of:
32
+ # * :h1 - First class heading
33
+ # * :h2 - Second class heading
34
+ # * :usage - Usage information
35
+ # * :em - Highlighted word
36
+ def colorizing &block
37
+ raise "colorize expects a block" unless block_given?
38
+ @colorize = block
39
+ end
40
+
41
+ #
42
+ # Colorize the given +string+ of the given +type+.
43
+ # See Pablo#colorize for valid values of +type+.
44
+ # If no colorization function is given, the +string+ is returned
45
+ # uncolored.
46
+ def colorize string, type
47
+ if type == :text
48
+ string.gsub(/\$([^$]+)\$/ )do |match|
49
+ colorize(match[1..-2], :em)
50
+ end
51
+ else
52
+ @colorize.nil? ? string : (@colorize.call(string, type))
53
+ end
54
+ end
55
+
56
+ end
57
+
@@ -0,0 +1,71 @@
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 Command < Pablo::Parser
27
+
28
+ def initialize *args, &block
29
+ super(*args, &block)
30
+ @opts[:consume_all] = @pablo.consume_all? if @opts[:consume_all].nil?
31
+ end
32
+
33
+ def parse args
34
+ name = nil
35
+ idx = args.zip((0...args.length).to_a).find_index { |(a,i)|
36
+ verifies?(a,i) and (name = matches?(a))
37
+ }
38
+
39
+ unless idx.nil?
40
+ args.consume idx
41
+ args.slice idx
42
+
43
+ @pablo.commands[name] = true
44
+
45
+ unless returning(consume?(name, args)) { run?(args) }
46
+ args.consume_all if @toplevel and @opts[:consume_all]
47
+ end
48
+
49
+ args.unslice
50
+ true
51
+ else
52
+ false
53
+ end
54
+ end
55
+
56
+ #
57
+ # Format a command's names to be displayed to the user.
58
+ def names_to_user
59
+ @names.collect(&:to_s).join('|')
60
+ end
61
+
62
+ #
63
+ # Format a command's names to be used in a Regexp.
64
+ def names_to_rex
65
+ Regexp.new(names_to_user)
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
@@ -0,0 +1,68 @@
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 MissingArgumentError < RuntimeError
27
+ def initialize name, arg = nil
28
+ @name, @arg = name, arg
29
+ end
30
+
31
+ def to_s
32
+ @arg ?
33
+ "Missing argument '#{@arg}' for '#{@name}'." :
34
+ "Missing argument for '#{@name}'."
35
+ end
36
+ end
37
+
38
+ class WrongArgumentError < RuntimeError
39
+ def initialize name, arg = nil, type = nil
40
+ @name, @arg, @type = name, arg, type
41
+ end
42
+
43
+ def to_s
44
+ (@arg ?
45
+ "Wrong argument '#{@arg}' for '#{@name}'." :
46
+ "Wrong argument for '#{@name}'.") +
47
+ (@type ?
48
+ " Expected #{@type}." :
49
+ '')
50
+ end
51
+ end
52
+
53
+ #
54
+ # Displays a message about a missing argument
55
+ # and exits parsing.
56
+ def missing_argument *args
57
+ raise MissingArgumentError.new @cur.last_match, *args
58
+ end
59
+
60
+ #
61
+ # Displays a message about a wrong argument (format)
62
+ # and exits parsing.
63
+ def wrong_argument *args
64
+ raise WrongArgumentError.new @cur.last_match, *args
65
+ end
66
+
67
+ end
68
+
@@ -0,0 +1,58 @@
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
+ # Whether or not the given +type+ is subject to expansion.
28
+ def expands? type
29
+ @opts[:expand] == true or @opts[:expand] == type
30
+ end
31
+
32
+ #
33
+ # Expands the given +arg+ument if possible.
34
+ def expand! arg
35
+ arr = @expand.find_all { |e| e.start_with?(arg) }
36
+
37
+ case arr.length
38
+ when 1 then arr[0]
39
+ when 0 then arg
40
+ else
41
+ @ambiguity.call(arg, arr) unless @ambiguity.nil?
42
+ arg
43
+ end
44
+ end
45
+
46
+ #
47
+ # The block given to this method will be called each time an
48
+ # argument could not be expanded because there were multiple
49
+ # parsers that matched it.
50
+ # The block will be passed the argument and an Array containing
51
+ # the matching parser names as parameters.
52
+ def ambiguity &block
53
+ raise "Pablo#ambiguity needs a block to do something sensible" unless block_given?
54
+ @ambiguity = block
55
+ end
56
+
57
+ end
58
+
data/lib/pablo/help.rb ADDED
@@ -0,0 +1,191 @@
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
+ # The class that handles standard help displaying.
28
+ class HelpCommand < Pablo::Command
29
+ private
30
+
31
+ def run? args
32
+ super(args)
33
+ args.empty? ? @pablo.help() : @pablo.help(args[0])
34
+ throw :abort
35
+ end
36
+ end
37
+
38
+ #
39
+ # The class that handles standard version displaying.
40
+ class VersionCommand < Pablo::Command
41
+ private
42
+
43
+ def run? args
44
+ super(args)
45
+ @pablo.version()
46
+ throw :abort
47
+ end
48
+ end
49
+
50
+ #
51
+ # The class that handles standard License displaying.
52
+ class LicenseCommand < Pablo::Command
53
+ private
54
+
55
+ def run? args
56
+ super(args)
57
+ @pablo.license()
58
+ throw :abort
59
+ end
60
+ end
61
+
62
+ #
63
+ # Creates the standard license command.
64
+ def license_command options = {}, &block
65
+ desc('Shows the license of this program.') unless @pending[:desc]
66
+ longdesc("Displays information about the license of this program.") unless @pending[:longdesc]
67
+ exec(Pablo::LicenseCommand, :license, options, &block)
68
+ end
69
+
70
+ #
71
+ # Creates the standard version command.
72
+ def version_command options = {}, &block
73
+ desc('Shows the version of this program.') unless @pending[:desc]
74
+ longdesc("Displays information about the version of this program.") unless @pending[:longdesc]
75
+ exec(Pablo::VersionCommand, :version, options, &block)
76
+ end
77
+
78
+ #
79
+ # Creates the standard help command.
80
+ def help_command options = {}, &block
81
+ desc('Displays this message.') unless @pending[:desc]
82
+ longdesc("Shows a simple help message for this program.\n" +
83
+ "If a command is given as well, a more detailed message about that\n" +
84
+ "particular command is shown (such as this one).") unless @pending[:longdesc]
85
+ usage('[<command>]') unless @pending[:usage]
86
+ exec(Pablo::HelpCommand, :help, options, &block)
87
+ end
88
+
89
+ #
90
+ # Creates standard ambiguity output.
91
+ def ambiguity_command
92
+ ambiguity do |arg,arr|
93
+ $stdout.puts "Ambiguous argument '#{arg}'. Could be any of:"
94
+
95
+ arr.each do |name|
96
+ $stdout.puts " * #{name}"
97
+ end
98
+
99
+ throw :abort
100
+ end
101
+ end
102
+
103
+ #
104
+ # Print the help screen.
105
+ # * command == nil: program help
106
+ # * else: specific command's help
107
+ def help command = nil
108
+ if command.nil?
109
+ put_header
110
+
111
+ $stdout.puts "\n #{colorize(@opts[:program], :em)} #{colorize(@opts[:usage], :usage)}\n" unless @opts[:usage].nil?
112
+ $stdout.puts "\n#{indent colorize(@opts[:longdesc], :text), 3}" unless @opts[:longdesc].nil?
113
+
114
+ cmdlen = @registered.collect(&:names_to_user).max_by(&:length).length
115
+
116
+ [:commands, :options].each do |type|
117
+ parsers = @registered.find_all { |p| p.klass_to_sym == type }
118
+
119
+ unless parsers.empty?
120
+ $stdout.puts
121
+ $stdout.puts ' ' + colorize("#{type.to_s.capitalize}:", :h2)
122
+
123
+ parsers.each { |p|
124
+ p.desc ?
125
+ $stdout.puts(" #{colorize(p.names_to_user.ljust(cmdlen), :em)} : #{colorize(p.desc, :text)}") :
126
+ $stdout.puts(' ' + colorize(p.names_to_user.ljust(cmdlen), :em))
127
+ }
128
+ end
129
+ end
130
+
131
+ tokens = @registered.find_all { |p| p.is_a? Pablo::Token and not p.desc.nil? }
132
+ unless tokens.empty?
133
+ $stdout.puts
134
+ $stdout.puts ' ' + colorize("Tokens:", :h2)
135
+
136
+ tokens.each { |t|
137
+ $stdout.puts " #{colorize(t.names_to_user.ljust(cmdlen), :em)} : #{t.desc}"
138
+ }
139
+ end
140
+ else
141
+ command = expand!(command)
142
+ found = @registered.find do |item|
143
+ if not item.names_to_rex.nil? and item.names_to_rex =~ command
144
+ put_header
145
+
146
+ $stdout.print "\n " + colorize(item.names_to_user, :em)
147
+ $stdout.print ' ' + colorize(item.usage, :usage) unless item.usage.nil?
148
+ $stdout.puts "\n\n"
149
+ $stdout.puts indent(colorize(item.longdesc, :text), 1) unless item.longdesc.nil?
150
+ true
151
+ else false
152
+ end
153
+ end
154
+
155
+ if found.nil?
156
+ $stdout.puts "Sorry, but I don't know '#{colorize(command, :em)}'."
157
+ $stdout.puts "Try running '#{colorize('help', :em)}' without parameters to get a list of all the commands, options etc."
158
+ end
159
+ end
160
+ end
161
+
162
+ #
163
+ # Print version screen and stop processing.
164
+ def version
165
+ $stdout.puts colorize("#{@opts[:program]} #{@opts[:version]}", :h1)
166
+ $stdout.puts @opts[:capabilities].join(' ') unless @opts[:capabilities].nil?
167
+ end
168
+
169
+ #
170
+ # Print license and stop processing. Nothing else.
171
+ def license
172
+ if File.exist? @opts[:license].to_s
173
+ open(@opts[:license]) { |f| $stdout.puts f.read }
174
+ else
175
+ $stdout.puts colorize(@opts[:license], :text)
176
+ end
177
+ end
178
+
179
+ #
180
+ # Prints the standard header for most Pablo output.
181
+ def put_header
182
+ unless @opts[:program].nil?
183
+ str = "#{@opts[:program]}"
184
+ str << " #{@opts[:version]}" unless @opts[:version].nil?
185
+ str << " - #{@opts[:desc]}" unless @opts[:desc].nil?
186
+ $stdout.puts ' ' + colorize(str, :h1)
187
+ end
188
+ end
189
+
190
+ end
191
+