appl 1.2

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 (6) hide show
  1. checksums.yaml +7 -0
  2. data/bin/intar +156 -0
  3. data/doc/demoappl +69 -0
  4. data/lib/appl.rb +302 -0
  5. data/lib/intar.rb +451 -0
  6. metadata +65 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c17ebbb3f574a1d27df9610144f9881c3b8ef910
4
+ data.tar.gz: 6e68ffdb0dd1e1c227dc371f29e9d93fb7a1abef
5
+ SHA512:
6
+ metadata.gz: c16e0eb7be520d7eace0ab904c838d61ab3eaa29b34d3f2fda9d5c23b35f03721f244ffb814389399bb6f1a175ba68cdd39a2b9fefb7f4cc7bb4f84ce8dbeef0
7
+ data.tar.gz: 98cf8b5bde3d91115a0763e0561718f04a99d560134d52448f68384662af9814cad6fdc44a283352e00897cf323fd450e4f1c9e77de7c052f9a75ab7dbc4ae51
data/bin/intar ADDED
@@ -0,0 +1,156 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ #
4
+ # intar -- Interactive Ruby evaluation
5
+ #
6
+
7
+ require "intar"
8
+ require "appl"
9
+
10
+
11
+ class IntarApp < Application
12
+
13
+ NAME = "intar"
14
+ VERSION = APPL_VERSION
15
+ SUMMARY = "Interactive Ruby"
16
+ COPYRIGHT = "(C) 2008-2013 Bertram Scharpf <software@bertram-scharpf.de>"
17
+ LICENSE = "BSD"
18
+ AUTHOR = "Bertram Scharpf <software@bertram-scharpf.de>"
19
+
20
+ DESCRIPTION = <<EOT
21
+ Prompt for Ruby statements, evaluate them. This is a replacement
22
+ for "irb". The underlying library may be entered from inside any
23
+ Ruby program.
24
+
25
+ Example:
26
+
27
+ $ intar -p '%(33 1)c%t%c%> '
28
+
29
+ EOT
30
+
31
+ def quiet!
32
+ Intar.show = nil
33
+ end
34
+ def show= s
35
+ Intar.show = s.to_i
36
+ end
37
+ def prompt= p
38
+ Intar.prompt = p if p
39
+ end
40
+ def bw!
41
+ Intar.colour = false
42
+ end
43
+ def catch_exit!
44
+ Intar.catch_exit = (Intar.catch_exit||0) + 3
45
+ end
46
+ def histall!
47
+ Intar.histhid = false
48
+ end
49
+ def histfile= h
50
+ Intar.histfile = nil_if_none h
51
+ end
52
+ def histmax= m
53
+ Intar.histmax = (Integer m rescue m.to_i)
54
+ end
55
+ def configfile= c
56
+ @configfile = nil_if_none c
57
+ end
58
+
59
+ define_option "p", :prompt=, "STR",
60
+ "prompt - see source code for % escapes"
61
+ alias_option "p", "prompt"
62
+
63
+ define_option "q", :quiet!, "don't show results"
64
+ alias_option "q", "quiet"
65
+
66
+ define_option "S", :show=, "N", 1, "show result line limit (0=all)"
67
+ alias_option "S", "show"
68
+
69
+ define_option "r", :require, "FILE", "Ruby require"
70
+ alias_option "r", "require"
71
+
72
+ define_option "bw", :bw!, "black & white"
73
+
74
+ define_option "c", :configfile=, "FILE", ".intarrc",
75
+ "config file, NONE means none"
76
+ alias_option "c", "configfile"
77
+
78
+ define_option "H", :histfile=, "FILE", ".intar_history",
79
+ "history file, NONE means none"
80
+ alias_option "H", "histfile"
81
+
82
+ define_option "m", :histmax=, "NUM",
83
+ "maximum history entries to save"
84
+ alias_option "m", "histmax"
85
+
86
+ define_option "A", :histall!,
87
+ "pass lines starting with blanks to history"
88
+ alias_option "A", "histall"
89
+
90
+ define_option "E", :encoding=, "ENC", "set encoding (like ruby -E)"
91
+ alias_option "E", "encoding"
92
+
93
+ define_option "x", :catch_exit!,
94
+ "On exit exception: Wait 3 seconds for interrupt"
95
+ alias_option "x", "catchexit"
96
+ alias_option "x", "catch-exit"
97
+
98
+ define_option "h", :help, "show options"
99
+ alias_option "h", "help"
100
+ define_option "V", :version, "show version"
101
+ alias_option "V", "version"
102
+
103
+ def run
104
+ # @debug = true # Only development.
105
+ read_cfg
106
+ main = eval "self", TOPLEVEL_BINDING
107
+ Intar.open main do |i|
108
+ i.run *(@args.shift @args.length)
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def encoding= ei
115
+ e, i = ei.split ":"
116
+ Encoding.default_external = e if e and not e.empty?
117
+ Encoding.default_internal = i if i and not i.empty?
118
+ [ $stdin, $stdout, $stderr].each do |io|
119
+ io.set_encoding e, i
120
+ end
121
+ end
122
+
123
+
124
+ def read_cfg
125
+ c = @configfile
126
+ return unless c
127
+ unless c[ File::SEPARATOR] or (File.exists? c) then
128
+ c = File.expand_path c, "~"
129
+ return unless File.exists? c
130
+ end
131
+ r = File.read c
132
+ r.prepend "$SAFE = 1#$/"
133
+ Thread.new {
134
+ begin
135
+ eval r, TOPLEVEL_BINDING
136
+ rescue Exception
137
+ $@.pop 2
138
+ e = $@.shift
139
+ puts "#{e}: #$! (#{$!.class})"
140
+ $@.each { |l| puts "\t#{l}" }
141
+ raise "Error in config file #{c}"
142
+ end
143
+ }.value
144
+ end
145
+
146
+ def nil_if_none var
147
+ case var
148
+ when "", "NONE" then nil
149
+ else var
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ IntarApp.run
156
+
data/doc/demoappl ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # demoappl -- Just test the Application class
5
+ #
6
+
7
+ require "appl"
8
+
9
+ class DemoAppl < Application
10
+
11
+ NAME = "demoappl"
12
+ VERSION = "1.0"
13
+ SUMMARY = "Just test the Application class"
14
+ COPYRIGHT = "(C) 2011 Bertram Scharpf"
15
+ LICENSE = "For internal use only"
16
+ AUTHOR = "Bertram Scharpf <software@bertram-scharpf.de>"
17
+
18
+ DESCRIPTION = <<EOT
19
+ This is an example how to define an Application subclass.
20
+ The program just prints out its parameters.
21
+
22
+ EOT
23
+
24
+ OPTIONS_ENV = "DEMO_OPTS"
25
+
26
+ attr_writer :param, :default_param
27
+ attr_bang :switch, :raise, :debug
28
+
29
+ define_option "s", :switch!, "dummy switch"
30
+ alias_option "s", "switch"
31
+
32
+ define_option "p", :param=, "PARAM", "dummy parameter"
33
+ alias_option "p", "param"
34
+
35
+ define_option "d", :default_param=, "PARAM:dddd",
36
+ "dummy parameter with default value"
37
+ alias_option "d", "default-param"
38
+
39
+ define_option "r", :raise!, "raise an exception"
40
+ alias_option "r", "raise"
41
+
42
+ define_option "g", :debug!, "lots of ugly debugging information"
43
+ alias_option "g", "debug"
44
+
45
+ define_option "h", :help, "show this options list"
46
+ alias_option "h", "help"
47
+ define_option "V", :version, "show version information"
48
+ alias_option "V", "version"
49
+
50
+ UNKNOWN = "Sorry, unknown option"
51
+ STOPOPT = "no more options"
52
+ UNPROCA = "Warning: unprocessed arguments left"
53
+
54
+ def run
55
+ puts inspect
56
+ raise "stop" if @raise
57
+ ENV[ OPTIONS_ENV] or
58
+ puts "Try to set the environment variable #{OPTIONS_ENV}."
59
+ @args.clear
60
+ end
61
+
62
+ end
63
+
64
+ if false then
65
+ DemoAppl.run %w(-s -p rrrr qqqq -x -y -z)
66
+ else
67
+ DemoAppl.run
68
+ end
69
+
data/lib/appl.rb ADDED
@@ -0,0 +1,302 @@
1
+ #
2
+ # appl.rb -- Application class
3
+ #
4
+
5
+
6
+ class Application
7
+
8
+ APPL_VERSION = "1.2".freeze
9
+
10
+ OPTIONS_ENV = nil
11
+
12
+ STOPOPT = "stop option processing"
13
+ UNKNOWN = "Unknown option"
14
+ UNPROCA = "Warning: unprocessed arguments"
15
+
16
+ class OptionError < StandardError ; end
17
+ class Done < Exception ; end
18
+
19
+ def initialize args = nil
20
+ @args = args||self.class.cmdline_arguments
21
+ self.class.each_option { |opt,desc,arg,dfl,act|
22
+ begin
23
+ send act, dfl if dfl
24
+ rescue NoMethodError
25
+ raise OptionError, "Option action `#{act}' is not defined."
26
+ end
27
+ }
28
+ while @args.first =~ /\A-/ do
29
+ opt = $'
30
+ @args.shift
31
+ if opt =~ /\A-/ then
32
+ break if !$' or $'.empty?
33
+ opt = $'
34
+ if opt =~ /^=/ then opt = $` ; @args.unshift $' end
35
+ act = self.class.option_act @args, opt, nil
36
+ send *act
37
+ else
38
+ until not opt or opt.empty? do
39
+ c = opt.slice! 0, 1
40
+ if opt =~ /^=/ then opt = nil ; @args.unshift $' end
41
+ act = self.class.option_act @args, c, opt
42
+ send *act
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ def help
49
+ c = self.class
50
+ puts c.version
51
+ puts
52
+ puts c::DESCRIPTION
53
+ puts
54
+ c.show_options
55
+ if block_given? then
56
+ puts
57
+ yield
58
+ end
59
+ raise Done
60
+ end
61
+
62
+ def version
63
+ self.class.show_version
64
+ raise Done
65
+ end
66
+
67
+ VERSION = "0"
68
+ NAME = "appl"
69
+ SUMMARY = "Dummy application"
70
+ DESCRIPTION = <<-EOT
71
+ This base class does nothing by default.
72
+ EOT
73
+
74
+ def run
75
+ end
76
+
77
+ def execute
78
+ run
79
+ if @args.any? then
80
+ u = @args.join " "
81
+ puts "#{self.class::UNPROCA}: #{u}"
82
+ end
83
+ 0
84
+ rescue SignalException
85
+ raise if @debug
86
+ self.class.show_message $!.inspect
87
+ 128 + ($!.signo||2) # Ruby 1.8 returns signo +nil+; assume SIGINT
88
+ rescue
89
+ raise if @debug
90
+ self.class.show_message "Error: #$!", "(#{$!.class})"
91
+ $!.to_i rescue 1
92
+ end
93
+
94
+ HASH_ORDER = RUBY_VERSION >= "1.9"
95
+
96
+ class <<self
97
+
98
+ def run args = nil
99
+ e = execute args
100
+ exit e
101
+ end
102
+
103
+ def version
104
+ if self::VERSION =~ %r/\s/ then
105
+ self::VERSION
106
+ else
107
+ "#{self::NAME} #{self::VERSION} -- #{self::SUMMARY}"
108
+ end
109
+ end
110
+
111
+ private
112
+
113
+ def execute args = nil
114
+ i = new args
115
+ i.execute
116
+ rescue Done
117
+ 0
118
+ rescue OptionError
119
+ show_message $!
120
+ 127
121
+ end
122
+
123
+ def inherited sub
124
+ sub.instance_eval { @options, @aliases = {}, {} }
125
+ end
126
+
127
+ def attr_bang *syms
128
+ syms.each { |sym|
129
+ define_method :"#{sym}!" do
130
+ instance_variable_set :"@#{sym}", true
131
+ end
132
+ }
133
+ nil
134
+ end
135
+
136
+ public
137
+
138
+ def define_option opt, *param
139
+ delete_option opt
140
+ act = param.shift
141
+ desc = param.pop
142
+ arg = param.shift
143
+ if arg then
144
+ if param.empty? then
145
+ arg, dfl = arg.split /:/, 2
146
+ if dfl =~ /\A:/ then
147
+ dfl = $'.to_sym
148
+ end
149
+ else
150
+ dfl = param.shift
151
+ end
152
+ end
153
+ d = param.map { |x| "#{x}#$/" }.join
154
+ desc.insert 0, d
155
+ @options[ opt.to_s] = [ desc, arg, dfl, act]
156
+ nil
157
+ end
158
+ alias def_option define_option
159
+
160
+ def alias_option orig, opt
161
+ unalias_option opt
162
+ @aliases[ opt.to_s] = orig.to_s
163
+ nil
164
+ end
165
+
166
+ def delete_option opt
167
+ self < Application or return
168
+ superclass.delete_option opt
169
+ @options.delete opt
170
+ @aliases.reject! { |k,v| v == opt }
171
+ nil
172
+ end
173
+
174
+ def unalias_option opt
175
+ self < Application or return
176
+ superclass.unalias_option opt
177
+ @aliases.delete opt
178
+ nil
179
+ end
180
+
181
+ protected
182
+
183
+ def find_option_act opt
184
+ self < Application or return
185
+ @options[ opt] || @options[ @aliases[ opt]] ||
186
+ (superclass.find_option_act opt)
187
+ end
188
+
189
+ def all_options
190
+ if self < Application then
191
+ r = superclass.all_options
192
+ r.update @options
193
+ else
194
+ {}
195
+ end
196
+ end
197
+
198
+ def all_aliases
199
+ if self < Application then
200
+ r = superclass.all_aliases
201
+ r.update @aliases
202
+ else
203
+ {}
204
+ end
205
+ end
206
+
207
+ def options_desc &block
208
+ a = Hash.new do |h,k| h[ k] = [] end
209
+ all_aliases.each { |k,v|
210
+ a[ v].push k
211
+ }
212
+ a.values.each { |v| v.sort! } unless HASH_ORDER
213
+ each_option { |opt,desc,arg,dfl,|
214
+ yield opt, arg, dfl, desc
215
+ a[ opt].each { |l|
216
+ yield l, nil, nil, nil
217
+ }
218
+ }
219
+ yield "", nil, nil, self::STOPOPT
220
+ end
221
+
222
+ public
223
+
224
+ def each_option
225
+ o = all_options
226
+ o = o.sort_by { |k,v| k.swapcase } unless HASH_ORDER
227
+ o.each { |opt,(desc,arg,dfl,act)|
228
+ case dfl
229
+ when Symbol then dfl = const_get dfl
230
+ end
231
+ yield opt, desc, arg, dfl, act
232
+ }
233
+ end
234
+
235
+ def option_act args, opt, rest
236
+ dada = find_option_act opt
237
+ dada or raise OptionError, "#{self::UNKNOWN}: `#{opt}'."
238
+ desc, arg, dfl, act = *dada
239
+ r = [ act]
240
+ if arg then
241
+ p = rest.slice! 0, rest.length if rest and not rest.empty?
242
+ r.push p||args.shift
243
+ end
244
+ r
245
+ end
246
+
247
+ def show_options
248
+ options_desc do |opt,arg,dfl,desc|
249
+ opt = opt.length == 1 ? "-#{opt}" : "--#{opt}"
250
+ arg &&= "#{arg}"
251
+ dfl &&= "[#{dfl}]"
252
+ arg << dfl if arg && dfl
253
+ puts " %-10s %-12s %s" % [ opt, arg, desc]
254
+ end
255
+ end
256
+
257
+ def show_version
258
+ puts version
259
+ puts self::COPYRIGHT if const_defined? :COPYRIGHT
260
+ puts "License: #{self::LICENSE}" if const_defined? :LICENSE
261
+ a = []
262
+ a.push self::AUTHOR if const_defined? :AUTHOR
263
+ a.concat self::AUTHORS if const_defined? :AUTHORS
264
+ if a.any? then
265
+ a.flatten!
266
+ a.uniq!
267
+ j = a.join ", "
268
+ h = a.length == 1 ? "Author" : "Authors"
269
+ puts "#{h}: #{j}"
270
+ end
271
+ end
272
+
273
+ def show_message msg, extra = nil
274
+ if $stderr.tty? then
275
+ msg = "\e[31;1m#{msg}\e[m"
276
+ if extra then
277
+ extra = "\e[31m#{extra}\e[m"
278
+ end
279
+ end
280
+ if extra then
281
+ msg = [ msg, extra].join " "
282
+ end
283
+ $stderr.puts msg
284
+ end
285
+
286
+ def cmdline_arguments
287
+ r = []
288
+ oe = self::OPTIONS_ENV
289
+ eo = ENV[ oe] if oe
290
+ if eo then
291
+ eo.scan /"((?:\\.|[^"])*")|[^" \t]+/ do
292
+ r.push $1 ? (eval $1) : $&
293
+ end
294
+ end
295
+ r.concat $*
296
+ r
297
+ end
298
+
299
+ end
300
+
301
+ end
302
+
data/lib/intar.rb ADDED
@@ -0,0 +1,451 @@
1
+ #
2
+ # intar.rb -- Interactive Ruby evaluation
3
+ #
4
+
5
+
6
+ =begin rdoc
7
+
8
+ This could be opened not only by the Intar executable but also
9
+ everywhere inside your Ruby program.
10
+
11
+ = Example 1
12
+
13
+ require "intar"
14
+
15
+ Intar.prompt = "str(%(length)i):%03n%> "
16
+ a = "hello"
17
+ Intar.run a
18
+
19
+
20
+ = Example 2
21
+
22
+ require "intar"
23
+
24
+ class C
25
+ end
26
+
27
+ class IntarC < Intar
28
+ @show = 3
29
+ @prompt = "%(33 1)c%t%c%> "
30
+ @histfile = ".intarc_history"
31
+
32
+ class <<self
33
+ def open
34
+ super C.new
35
+ end
36
+ end
37
+ end
38
+
39
+ IntarC.open do |ia| ia.run end
40
+
41
+ =end
42
+
43
+
44
+ require "readline"
45
+ require "supplement"
46
+ require "supplement/terminal"
47
+
48
+
49
+ class Object
50
+ def empty_binding
51
+ binding
52
+ end
53
+ end
54
+
55
+ class Intar
56
+
57
+ class History
58
+
59
+ IND = " "
60
+ IND_RE = /^#{IND}/
61
+
62
+ def initialize filename
63
+ @filename = filename
64
+ return unless @filename
65
+ h = "~" unless @filename.starts_with "./"
66
+ @filename = File.expand_path @filename, h
67
+ File.exists? @filename and File.open @filename do |h|
68
+ c = []
69
+ h.each { |l|
70
+ case l
71
+ when IND_RE then c.push $'
72
+ else push c.join.chomp ; c.clear
73
+ end
74
+ }
75
+ push c.join.chomp
76
+ end
77
+ @num = Readline::HISTORY.length
78
+ end
79
+
80
+ def finish max
81
+ return unless @filename
82
+ @num.times { Readline::HISTORY.shift }
83
+ File.open @filename, "a" do |h|
84
+ a = []
85
+ while (c = Readline::HISTORY.shift) do a.push c end
86
+ if a.any? then
87
+ h.puts "# #{Time.now}"
88
+ a.each { |c|
89
+ c.each_line { |l| h.puts IND + l }
90
+ h.puts "-"
91
+ }
92
+ i = a.length
93
+ h.puts "# #{i} #{entry_str i} added"
94
+ end
95
+ end
96
+ n = File.open @filename do |h|
97
+ h.inject 0 do |i,l| i += 1 if l =~ IND_RE ; i end
98
+ end
99
+ i = max - n
100
+ if i < 0 then
101
+ f = nil
102
+ File.open @filename do |h|
103
+ h.each_line { |l|
104
+ f.push l if f
105
+ case l
106
+ when IND_RE then i += 1
107
+ else f ||= [] if i >= 0
108
+ end
109
+ }
110
+ end
111
+ f and File.open @filename, "w" do |h| h.puts f end
112
+ end
113
+ rescue Errno
114
+ # Forget it if there isn't enough disk space.
115
+ end
116
+
117
+ def push l
118
+ Readline::HISTORY.push l unless l.empty?
119
+ end
120
+
121
+ private
122
+
123
+ def entry_str i
124
+ i == 1 ? "entry" : "entries"
125
+ end
126
+
127
+ end
128
+
129
+ class <<self
130
+
131
+ attr_accessor :prompt, :show, :colour
132
+
133
+ attr_reader :histfile
134
+ def histfile= hf
135
+ @histfile = hf
136
+ if @history then
137
+ @history.finish @histmax
138
+ @history = History.new @histfile
139
+ end
140
+ end
141
+
142
+ # Maximum number of history entries.
143
+ attr_accessor :histmax
144
+
145
+ # Whether to hide entries starting with whitespace.
146
+ attr_accessor :histhid
147
+
148
+ # Shell prefix and Pipe suffix
149
+ attr_accessor :sh_pref, :pi_suff
150
+
151
+ # Whether <code>Kernel#exit</code> should be caught.
152
+ attr_accessor :catch_exit
153
+
154
+ private
155
+
156
+ def inherited sub
157
+ sub.class_eval {
158
+ s = superclass
159
+ @prompt = s.prompt
160
+ @show = s.show
161
+ @colour = s.colour
162
+ @histfile = s.histfile
163
+ @histmax = s.histmax
164
+ @histhid = s.histhid
165
+ @sh_pref = s.sh_pref
166
+ @pi_suff = s.pi_suff
167
+ @catch_exit = s.catch_exit
168
+ }
169
+ end
170
+
171
+ def history_file
172
+ if @history then
173
+ yield
174
+ else
175
+ @history = History.new @histfile
176
+ begin
177
+ yield
178
+ ensure
179
+ @history.finish @histmax
180
+ @history = nil
181
+ end
182
+ end
183
+ end
184
+
185
+ public
186
+
187
+ private :new
188
+ def open obj
189
+ history_file do
190
+ i = new obj
191
+ yield i
192
+ end
193
+ end
194
+
195
+ def run obj
196
+ open obj do |i| i.run end
197
+ end
198
+
199
+ def hist_add l
200
+ return if @histhid and l == /\A[ \t]+/
201
+ lst = Readline::HISTORY[-1] if Readline::HISTORY.length > 0
202
+ @history.push l unless l == lst
203
+ end
204
+
205
+ end
206
+
207
+ self.prompt = "%(32)c%i%c:%1c%03n%c%> "
208
+ self.show = 1
209
+ self.colour = true
210
+ self.histfile = nil
211
+ self.histmax = 500
212
+ self.histhid = true
213
+ self.sh_pref = "."
214
+ self.pi_suff = " |"
215
+ self.catch_exit = nil
216
+
217
+ private
218
+
219
+ def initialize obj
220
+ @obj = obj
221
+ @n = 0
222
+ end
223
+
224
+ OLDSET = <<-EOT
225
+ _, __, ___ = nil, nil, nil
226
+ proc { |r,n|
227
+ Array === __ or __ = []
228
+ Hash === ___ or ___ = {}
229
+ unless r.nil? or r.equal? __ or r.equal? ___ then
230
+ _ = r
231
+ __.delete r rescue nil
232
+ __.unshift r
233
+ ___[ n] = r
234
+ end
235
+ }
236
+ EOT
237
+
238
+ autoload :Etc, "etc"
239
+ autoload :Socket, "socket"
240
+
241
+ def cur_prompt
242
+ t = Time.now
243
+ self.class.prompt.gsub /%(?:
244
+ \(([^\)]*)\)
245
+ |
246
+ ([+-]?[0-9]+(?:\.[0-9]+)?)
247
+ )?(.)/nx do
248
+ case $3
249
+ when "s" then @obj.to_s
250
+ when "i" then $1.notempty? ? (@obj.send $1) : @obj.inspect
251
+ when "n" then "%#$2d" % @n
252
+ when "t" then t.strftime $1||"%X"
253
+ when "u" then Etc.getpwuid.name
254
+ when "h" then Socket.gethostname
255
+ when "w" then cwd_short
256
+ when "W" then File.basename cwd_short
257
+ when "c" then (colour *($1 || $2 || "").split.map { |x| x.to_i }).to_s
258
+ when ">" then Process.uid == 0 ? "#" : ">"
259
+ when "%" then $3
260
+ else $&
261
+ end
262
+ end
263
+ end
264
+
265
+ def colour *c
266
+ if self.class.colour then
267
+ s = c.map { |i| "%d" % i }.join ";"
268
+ "\e[#{s}m"
269
+ end
270
+ end
271
+
272
+ def switchcolour *c
273
+ s = colour *c
274
+ print s if s
275
+ end
276
+
277
+ def cwd_short
278
+ r = Dir.pwd
279
+ h = Etc.getpwuid.dir
280
+ r[ 0, h.length] == h and r[ 0, h.length] = "~"
281
+ r
282
+ end
283
+
284
+ def readline
285
+ r, @previous = @previous, nil
286
+ r or @n += 1
287
+ cp = cur_prompt
288
+ loop do
289
+ begin
290
+ l = Readline.readline r ? "" : cp
291
+ rescue Interrupt
292
+ puts "^C -- #{$!.inspect}"
293
+ retry
294
+ end
295
+ if r then
296
+ break if l.nil?
297
+ r << $/ << l
298
+ break if l.empty?
299
+ else
300
+ return if l.nil?
301
+ next unless l =~ /\S/
302
+ r = l
303
+ break unless l =~ /\\+\z/ and $&.length % 2 != 0
304
+ end
305
+ end
306
+ cp.strip!
307
+ cp.gsub! /\e\[[0-9]*(;[0-9]*)*m/, ""
308
+ @file = "#{self.class}/#{cp}"
309
+ self.class.hist_add r
310
+ r
311
+ end
312
+
313
+ # :stopdoc:
314
+ ARROW = "=> "
315
+ ELLIPSIS = "..."
316
+ # :startdoc:
317
+
318
+ def display r
319
+ return if r.nil?
320
+ show = (self.class.show or return)
321
+ i = r.inspect
322
+ if show > 0 then
323
+ siz, = $stdout.winsize
324
+ siz *= show
325
+ siz -= ARROW.length
326
+ if i.length > siz then
327
+ i.cut! siz-ELLIPSIS.length
328
+ i << ELLIPSIS
329
+ end
330
+ end
331
+ i.prepend ARROW
332
+ puts i
333
+ end
334
+
335
+ def pager doit
336
+ if doit then
337
+ IO.popen ENV[ "PAGER"]||"more", "w" do |pg|
338
+ begin
339
+ stdout = $stdout.dup
340
+ $stdout.reopen pg
341
+ yield
342
+ ensure
343
+ $stdout.reopen stdout
344
+ end
345
+ end
346
+ else
347
+ yield
348
+ end
349
+ end
350
+
351
+ public
352
+
353
+ class Exit < Exception ; end
354
+ class CmdFailed < Exception ; end
355
+
356
+ def run *precmds
357
+ bind = @obj.empty_binding
358
+ precmds.each { |l| eval l, bind }
359
+ oldset = eval OLDSET, bind
360
+ @cl = eval "caller.length", bind
361
+ while l = readline do
362
+ re_sh_pref = /\A#{Regexp.quote self.class.sh_pref}/
363
+ re_pi_suff = /#{Regexp.quote self.class.pi_suff}\z/
364
+ switchcolour
365
+ begin
366
+ pg = l.slice! re_pi_suff
367
+ r = pager pg do
368
+ unless l =~ re_sh_pref then
369
+ eval l, bind, @file
370
+ else
371
+ call_system $', bind
372
+ end
373
+ end
374
+ oldset.call r, @n
375
+ display r
376
+ rescue Exit
377
+ wait_exit and break
378
+ rescue CmdFailed
379
+ oldset.call $?, @n
380
+ switchcolour 33
381
+ puts "Exit code: #{$?.exitstatus}"
382
+ rescue LoadError
383
+ oldset.call $!, @n
384
+ show_exception
385
+ rescue ScriptError
386
+ if l[ $/] then
387
+ switchcolour 33
388
+ puts $!
389
+ else
390
+ @previous = l
391
+ end
392
+ rescue SystemExit
393
+ break if wait_exit
394
+ oldset.call $!, @n
395
+ show_exception
396
+ rescue Exception
397
+ oldset.call $!, @n
398
+ show_exception
399
+ ensure
400
+ switchcolour
401
+ end
402
+ end
403
+ puts
404
+ ensure
405
+ done
406
+ end
407
+
408
+ protected
409
+
410
+ def done
411
+ end
412
+
413
+ private
414
+
415
+ def wait_exit
416
+ c = self.class.catch_exit
417
+ c and c.times { print "." ; $stdout.flush ; sleep 1 }
418
+ true
419
+ rescue Interrupt
420
+ puts
421
+ end
422
+
423
+ def show_exception
424
+ unless $!.to_s.empty? then
425
+ switchcolour 31, 1
426
+ print $!
427
+ print " " unless $!.to_s =~ /\s\z/
428
+ end
429
+ switchcolour 31, 22
430
+ puts "(#{$!.class})"
431
+ switchcolour 33
432
+ bt = $@.dup
433
+ if bt.length > @cl then
434
+ bt.pop @cl
435
+ bt.push bt.pop[ /(.*:\d+):.*/, 1]
436
+ end
437
+ puts bt
438
+ end
439
+
440
+ def call_system l, bind
441
+ l.strip!
442
+ raise Exit if l.empty?
443
+ eot = "EOT0001"
444
+ eot.succ! while l[ eot]
445
+ l = eval "<<#{eot}\n#{l}\n#{eot}", bind, @file
446
+ system l or raise CmdFailed
447
+ nil
448
+ end
449
+
450
+ end
451
+
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appl
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.2'
5
+ platform: ruby
6
+ authors:
7
+ - Bertram Scharpf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: supplement
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ description: |
28
+ A base class for command line applications doing options parsing
29
+ and generating exit codes.
30
+ email: "<software@bertram-scharpf.de>"
31
+ executables:
32
+ - intar
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - bin/intar
37
+ - doc/demoappl
38
+ - lib/appl.rb
39
+ - lib/intar.rb
40
+ homepage: http://www.bertram-scharpf.de/software/appl
41
+ licenses:
42
+ - BSD
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements:
59
+ - Just Ruby
60
+ rubyforge_project: NONE
61
+ rubygems_version: 2.6.4
62
+ signing_key:
63
+ specification_version: 4
64
+ summary: Easy option parsing
65
+ test_files: []