intar 2.2 → 2.5

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