intar 2.2 → 2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2321cc815a7cfbdca083a93c4398557a04e0e9ba250ae6027999270a575b1955
4
- data.tar.gz: 7a4ec6cbc2188805c4e49f1f3c0b19ee7aa3c4b046e426c31966574225a90719
3
+ metadata.gz: cad6272b3ab1559bdebde9d6c9979fe065d4bf7bc57c49c85a0d6abf10071b0b
4
+ data.tar.gz: 3babbed5bbeab2e9f1b7da52ff16aec85f16f13da414f20fe3fdfac995ec0776
5
5
  SHA512:
6
- metadata.gz: cdd4525b5de83ce80d9b0368c8cadde74222f5f0b66621490741f717cfed92af77ed9a9ec644685eeaca10cf5b445821fa99d825028444e5f3b88ceaa4de04de
7
- data.tar.gz: 204c9e1dbfbd81ef89f595761b99a55bbe1543b3f4b3b09537c8622d1834add6976dccf31c18d288abb94d23744d9fce75f7a708cb13fe909eacf688cdbf8b57
6
+ metadata.gz: a3757b39f033d37efb3b0c36b547e788da344f084160b3f4cea112c6d23b9249db7bc0a766df605cf546f592810f1da2290e1bcf949f9179a0ed573f425b52ba
7
+ data.tar.gz: 8309a03d4e9a40a604829eaa70d18ed54db2d09d698a5d13474526e5a7cdf6a64bb1109c6fb8ab2c62443d5f97ec06225097408f206e8a3b527102f77e1558b2
data/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ = ruby-intar
2
+
3
+ Copyright (c) 2020, Bertram Scharpf <software@bertram-scharpf.de>.
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are
8
+ met:
9
+
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright
14
+ notice, this list of conditions and the following disclaimer in
15
+ the documentation and/or other materials provided with the
16
+ distribution.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
22
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
data/README ADDED
@@ -0,0 +1,45 @@
1
+ = ruby-intar -- Interactive Ruby
2
+
3
+ A simple Irb replacement
4
+
5
+
6
+
7
+ == About
8
+
9
+ The Intar project was started in times when Irb was a rather
10
+ unconvenient tool, without colors, difficult to call from
11
+ inside an application and so on.
12
+
13
+ Today, Intar is a tool far less complex than Irb.
14
+
15
+ Yet, Intar is more robust. Try this in Irb and in Intar:
16
+
17
+ prompt> Thread.new { sleep 3 ; Thread.main.raise "stop" }
18
+
19
+
20
+
21
+ == Usage
22
+
23
+ === Subcommands
24
+
25
+ obj.method & enter a sub-Intar
26
+ obj.each & enter multiple sub-Intars
27
+
28
+ \q exit from the innermost sub-Intar
29
+ \q! exit from the innermost sub-Intar loop
30
+ \q!! exit from all levels
31
+
32
+ \h get a list of all subcommands
33
+
34
+
35
+
36
+ == Author
37
+
38
+ Bertram Scharpf <software@bertram-scharpf.de>
39
+
40
+
41
+
42
+ == TODO
43
+
44
+ Write some more documentation.
45
+
data/lib/intar/prompt.rb CHANGED
@@ -16,11 +16,26 @@ class Intar
16
16
  @new = 0
17
17
  end
18
18
 
19
+ def push text
20
+ Readline.pre_input_hook = proc {
21
+ Readline.insert_text text
22
+ Readline.redisplay
23
+ }
24
+ nil
25
+ end
26
+
19
27
  def ask prompt
20
- l = Readline.readline prompt
28
+ begin
29
+ Readline.readline prompt
30
+ ensure
31
+ Readline.pre_input_hook = nil
32
+ end
21
33
  rescue Interrupt
22
- puts "^C -- #{$!.inspect}"
34
+ puts
23
35
  retry
36
+ rescue Exception
37
+ puts
38
+ raise
24
39
  end
25
40
 
26
41
  def last
@@ -31,12 +46,11 @@ class Intar
31
46
  i = Readline::HISTORY.length
32
47
  while i > 0 do
33
48
  i -= 1
34
- l = Readline::HISTORY[i]
35
- yield l
49
+ yield Readline::HISTORY[i]
36
50
  end
37
51
  end
38
52
 
39
- def push item
53
+ def push_history item
40
54
  item.empty? and return
41
55
  last != item or return
42
56
  Readline::HISTORY.push item
@@ -16,22 +16,24 @@ class Intar
16
16
  class Redirect
17
17
  def redirect_output
18
18
  out = outfile
19
- stdin, stdout = $stdin.dup, $stdout.dup
20
- $stdin .reopen "/dev/null"
21
- $stdout.reopen out
22
- yield
23
- ensure
24
- $stdin .reopen stdin
25
- $stdout.reopen stdout
26
- out.close
19
+ begin
20
+ stdin, stdout = $stdin.dup, $stdout.dup
21
+ $stdin .reopen "/dev/null"
22
+ $stdout.reopen out
23
+ yield
24
+ ensure
25
+ $stdin .reopen stdin
26
+ $stdout.reopen stdout
27
+ out.close
28
+ end
27
29
  end
28
30
  end
29
31
 
30
32
  class RedirectPipe < Redirect
31
33
  class <<self
32
34
  def detect line, pager
33
- if line.slice! /\s+\|\z/ then
34
- new pager
35
+ if line.slice! /\s+\|(\b[^|&;{}()\[\]]*)?\z/ then
36
+ new $1||pager
35
37
  end
36
38
  end
37
39
  end
@@ -39,7 +41,9 @@ class Intar
39
41
  @pager = pager||ENV[ "PAGER"]||"more"
40
42
  end
41
43
  def outfile
42
- IO.popen @pager.to_s, "w" rescue raise Failed, "Pipe error: #$!"
44
+ IO.popen @pager.to_s, "w"
45
+ rescue Errno::ENOENT
46
+ raise Failed, "Pipe error: #$!"
43
47
  end
44
48
  end
45
49
 
data/lib/intar/version.rb CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  class Intar
6
6
 
7
- VERSION = "2.2".freeze
7
+ VERSION = "2.5".freeze
8
8
 
9
9
  end
10
10
 
data/lib/intar.rb CHANGED
@@ -63,7 +63,7 @@ class Intar
63
63
 
64
64
 
65
65
  DEFAULTS = {
66
- prompt: "%(32)c%i%c:%1c%03n%c%> ",
66
+ prompt: "%(32)c%16i%c:%1c%d:%3n%c%> ",
67
67
  color: true,
68
68
  show: 1,
69
69
  shownil: false,
@@ -74,53 +74,66 @@ class Intar
74
74
  histmax: 500,
75
75
  }
76
76
 
77
+ @@current = nil
78
+
79
+ attr_reader :params, :prompt, :depth, :n
77
80
  def initialize obj = nil, **params
78
81
  @obj = obj.nil? ? (eval "self", TOPLEVEL_BINDING) : obj
79
- @params = DEFAULTS.dup.update params
82
+ if @@current then
83
+ @params = @@current.params
84
+ @prompt = @@current.prompt
85
+ @depth = @@current.depth + 1
86
+ else
87
+ @params = DEFAULTS.dup.update params
88
+ @prompt = Prompt.new
89
+ @depth = 0
90
+ end
91
+ @n = 1
92
+
80
93
  @binding = @obj.intar_binding
81
- @n = 0
82
- @prompt = Prompt.new
83
94
  end
84
95
 
85
96
 
86
97
  class Quit < Exception ; end
87
- class Failed < Exception ; end
98
+ class Bye < Quit ; end
99
+ class Break < Bye ; end
100
+ class Failed < StandardError ; end
88
101
 
89
102
  def run
90
- prompt_load_history
91
- oldset = eval OLDSET, @binding
92
- while l = readline do
93
- begin
94
- @redir = find_redirect l
95
- r = if l =~ /\A\\(\w+|.)\s*(.*?)\s*\Z/ then
96
- m = get_metacommand $1
97
- send m.method, (eval_param $2)
98
- else
99
- begin
100
- @redir.redirect_output do eval l, @binding, @file end
103
+ handle_history do
104
+ set_current do
105
+ oldset = eval OLDSET, @binding
106
+ loop do
107
+ l = readline
108
+ l or break
109
+ @redir = find_redirect l
110
+ r = begin
111
+ if l =~ /\A\\(\w+|.)\s*(.*?)\s*\Z/ then
112
+ send (get_metacommand $1).method, (eval_param $2)
113
+ else
114
+ l.sub! %r/\s*&\s*\z/, SUB
115
+ @redir.redirect_output do eval l, @binding, @file end
116
+ end
117
+ rescue Bye
118
+ raise if @depth.nonzero?
119
+ break
120
+ rescue Quit
121
+ break
101
122
  rescue SyntaxError
102
123
  raise if l.end_with? $/
103
124
  @previous = l
104
125
  next
126
+ rescue Exception
127
+ break if SystemExit === $! and not @params[ :catch_exit]
128
+ show_exception
129
+ $!
105
130
  end
131
+ display r
132
+ oldset.call r, @n
133
+ @n += 1
106
134
  end
107
- rescue Quit
108
- break
109
- rescue Failed
110
- switchcolor 31, 1
111
- puts $!
112
- switchcolor
113
- r = $!
114
- rescue Exception
115
- break if SystemExit === $! and not @params[ :catch_exit]
116
- show_exception
117
- r = $!
118
- else
119
- display r
120
135
  end
121
- oldset.call r, @n
122
136
  end
123
- prompt_save_history
124
137
  end
125
138
 
126
139
  def execute code
@@ -130,6 +143,26 @@ class Intar
130
143
 
131
144
  private
132
145
 
146
+ def handle_history
147
+ unless @depth.nonzero? then
148
+ begin
149
+ prompt_load_history
150
+ yield
151
+ ensure
152
+ prompt_save_history
153
+ end
154
+ else
155
+ yield
156
+ end
157
+ end
158
+
159
+ def set_current
160
+ old, @@current = @@current, self
161
+ yield
162
+ ensure
163
+ @@current = old
164
+ end
165
+
133
166
  def find_redirect line
134
167
  RedirectPipe.detect line, @params[ :pager] or
135
168
  RedirectFile.detect line, @params[ :output] or
@@ -137,6 +170,14 @@ class Intar
137
170
  end
138
171
 
139
172
 
173
+ SUB = <<~EOT
174
+ \ do |obj|
175
+ Intar.run obj
176
+ rescue Intar::Break
177
+ break
178
+ end
179
+ EOT
180
+
140
181
  OLDSET = <<~EOT
141
182
  _, __, ___ = nil, nil, nil
142
183
  proc { |r,n|
@@ -155,55 +196,66 @@ class Intar
155
196
 
156
197
  def cur_prompt prev
157
198
  p = @params[ :prompt].to_s
158
- p.gsub /%(?:
159
- \(([^\)]+)?\)
160
- |
161
- ([+-]?[0-9]+(?:\.[0-9]+)?)
162
- )?(.)/nx do
163
- case $3
164
- when "s" then @obj.to_s
165
- when "i" then $1 ? (@obj.send $1) : @obj.inspect
166
- when "n" then "%#$2d" % @n
167
- when "t" then Time.now.strftime $1||"%X"
168
- when "u" then Etc.getpwuid.name
169
- when "h" then Socket.gethostname
170
- when "w" then cwd_short
171
- when "W" then File.basename cwd_short
172
- when "c" then color *($1 || $2 || "").split.map { |x| x.to_i }
199
+ p.gsub /%
200
+ (\d+)?
201
+ (?:\(([^)]*)\)|\{([^}]*)\})?
202
+ (.)/nx do
203
+ sub = $2||$3
204
+ case $4
205
+ when "s" then str_axe $1, @obj.to_s
206
+ when "i" then str_axe $1, (sub ? (@obj.send sub) : @obj.inspect)
207
+ when "C" then str_axe $1, @obj.class.name
208
+ when "n" then "%0#$1d" % @n
209
+ when "d" then "%0#$1d" % @depth
210
+ when "t" then str_axe $1, (Time.now.strftime sub||"%X")
211
+ when "u" then str_axe $1, Etc.getpwuid.name
212
+ when "h" then str_axe $1, Socket.gethostname
213
+ when "w" then str_axe $1, cwd_short
214
+ when "W" then str_axe $1, (File.basename cwd_short)
215
+ when "c" then color [$1,sub].compact.map { |c| c.scan %r/\d+/ }.flatten
173
216
  when ">" then prev ? "." : Process.uid == 0 ? "#" : ">"
174
- when "%" then $3
217
+ when "%" then $4
175
218
  else $&
176
219
  end
177
220
  end
178
221
  end
179
222
 
180
- def color *c
223
+ def str_axe len, str
224
+ if len then
225
+ str.axe len.to_i
226
+ else
227
+ str
228
+ end
229
+ end
230
+
231
+ def color codes
181
232
  if @params[ :color] then
182
- s = c.map { |i| "%d" % i }.join ";"
183
- "\e[#{s}m"
233
+ "\e[#{codes.join ';'}m"
184
234
  end
185
235
  end
186
236
 
187
237
  def switchcolor *c
188
- s = color *c
238
+ s = color c
189
239
  print s
190
240
  end
191
241
 
192
242
  def cwd_short
193
243
  r = Dir.pwd
194
244
  h = Etc.getpwuid.dir
195
- r[ 0, h.length] == h and r[ 0, h.length] = "~"
245
+ if r[ 0, h.length] == h then
246
+ n = r[ h.length]
247
+ r[ 0, h.length] = "~" if !n || n == "/"
248
+ end
196
249
  r
197
250
  end
198
251
 
199
252
  def readline
200
253
  r, @previous = @previous, nil
201
- r or @n += 1
202
254
  begin
203
255
  cp = cur_prompt r
204
256
  l = @prompt.ask cp
205
257
  return if l.nil?
206
- @prompt.push l unless !r and @params[ :histhid] and l =~ /\A[ \t]+/
258
+ @prompt.push_history l unless !r and @params[ :histhid] and l =~ /\A[ \t]+/
207
259
  if r then
208
260
  r << $/ << l
209
261
  else
@@ -240,18 +292,19 @@ class Intar
240
292
  puts i
241
293
  end
242
294
 
295
+ PACKAGE_BACKTRACE = %r/#{File.basename __FILE__, ".rb"}.*:\d+:in/
296
+
243
297
  def show_exception
244
298
  unless $!.to_s.empty? then
245
- switchcolor 31, 1
299
+ switchcolor 1, 31
246
300
  print $!
247
301
  print " " unless $!.to_s =~ /\s\z/
248
302
  end
249
- switchcolor 31, 22
303
+ switchcolor 22, 31
250
304
  puts "(#{$!.class})"
251
305
  switchcolor 33
252
306
  $@.each { |b|
253
- r = b.starts_with? __FILE__
254
- break if r and (b.rest r) =~ /\A:\d+:/
307
+ break if b =~ PACKAGE_BACKTRACE
255
308
  puts b
256
309
  }
257
310
  switchcolor
@@ -348,36 +401,36 @@ class Intar
348
401
  Leave Intar.
349
402
  EOT
350
403
  def cmd_quit x
351
- raise Quit
404
+ lx = $&.length.nonzero? if x =~ /!*/
405
+ raise lx ? (lx > 1 ? Bye : Break) : Quit
352
406
  end
353
407
 
354
408
  metacmd %w(cd), "Change directory", <<~EOT
355
409
  Switch to a different working directory.
356
- Former directories will be kept in a stack.
410
+ Former directories will be pushed to a stack.
357
411
 
358
- %[N] exchange with stack item #N
359
- =[N] drop and set to stack item #N
360
- -[N] drop stack item #N
412
+ N|PATH|% change directory and push
413
+ -N|PATH|% drop stack item
414
+ =N|PATH|% change directory but do not push
361
415
 
362
- Default N is 1.
416
+ Default N or % is 1.
363
417
  EOT
364
418
  def cmd_cd x
365
419
  @wds ||= []
366
420
  y = Dir.getwd
367
- if x =~ /\A([%=-])?(\d+)?\z/ then
368
- x = $2 ? (@wds.delete_at -$2.to_i) : @wds.pop
369
- x or raise Failed, ($2 ? "No directory ##$2." : "No last directory.")
370
- case $1
371
- when "-" then x = nil
372
- when "=" then y = nil
373
- end
374
- end
375
421
  if x then
376
- x = File.expand_path x
377
- Dir.chdir x rescue raise Failed, $!.to_s
378
- @wds.push y if y
379
- y = Dir.getwd
380
- @wds.delete y
422
+ cmd = x.slice! /\A[=-]/
423
+ x = case x
424
+ when /\A\d+\z/ then @wds[ -x.to_i] or raise Failed, "No directory ##{x}."
425
+ when /\A%?\z/ then @wds.last or raise Failed, "No last directory."
426
+ else File.expand_path x
427
+ end
428
+ @wds.delete x
429
+ if cmd != "-" then
430
+ Dir.chdir x
431
+ @wds.push y if cmd != "="
432
+ y = x
433
+ end
381
434
  end
382
435
  @redir.redirect_output do
383
436
  i = @wds.length
@@ -464,7 +517,7 @@ class Intar
464
517
  EOT
465
518
  def cmd_input x
466
519
  x or raise Failed, "No input file given."
467
- l = File.read x rescue raise Failed, $!.to_s
520
+ l = File.read x
468
521
  @redir.redirect_output do
469
522
  eval l, @binding, x
470
523
  end
@@ -475,7 +528,7 @@ class Intar
475
528
  EOT
476
529
  def cmd_output x
477
530
  if x then
478
- File.open x, "w" do end rescue raise Failed, "File error: #$!"
531
+ File.open x, "w" do end
479
532
  end
480
533
  @params[ :output] = x
481
534
  end
@@ -495,7 +548,6 @@ class Intar
495
548
  p = File.read fn
496
549
  p.strip!
497
550
  @prompt.push p
498
- @redir.redirect_output do eval p, @binding, @file end
499
551
  ensure
500
552
  File.unlink fn
501
553
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: intar
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.2'
4
+ version: '2.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bertram Scharpf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-24 00:00:00.000000000 Z
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appl
@@ -47,6 +47,8 @@ executables:
47
47
  extensions: []
48
48
  extra_rdoc_files: []
49
49
  files:
50
+ - LICENSE
51
+ - README
50
52
  - bin/intar
51
53
  - lib/intar.rb
52
54
  - lib/intar/prompt.rb