nrepl-lazuli 0.2.6 → 0.3.1

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: fb08e5429998d1320a2f3b4db07b336c389af0e3a1f008c67dbb4236af27af4a
4
- data.tar.gz: 9eb7a44c8d716860eeb09f18025dd5dd47713554384e9be249683b1ec7b11bf9
3
+ metadata.gz: 2439208ce1a3db5af7c886aa95b577bb713667461c92d129e997f378ca704926
4
+ data.tar.gz: 6aabf3d36d3996ff158a2c50ebaa6239570e4799614a8d7110d50df7ca1ede4f
5
5
  SHA512:
6
- metadata.gz: f3aec4c5b770994bb11be7f6fdfcbbaa4c0a1050e4964c0a10cd0cf4b95c6014ce0dd40cc765cad1815b93f429bb0c2a3a66a70aa03f730392d03bad0c71e29c
7
- data.tar.gz: 33d341eddae865f76f8463353b2232aaec4edd480f12301856bf618223f8f23fe7b237397e5d39135e3d745e9c57cbf22c6e658b61f9fa68c9756ccc81c65c35
6
+ metadata.gz: 755e29ac97e588baca03a48914cc968d23d96961c66c4a3778554bc29b2d14f05ac236f9d15a1b565318cab9a11c28bc1a07cf096911da656f1450c4ae52ac7f
7
+ data.tar.gz: a6fabeadef479c719f9fa60b53587e85d0d25fd88e96a03311103b0a5a581cccb54425ebd68c9e75cb01e69335dc755631699153bb44501ec51d756d0dc693a8
@@ -4,18 +4,18 @@ module NREPL
4
4
 
5
5
  def initialize(
6
6
  input, debug: false, out: input,
7
- watches: NREPL.class_variable_get(:@@bindings),
8
7
  binding: nil,
9
- bindings: {}
8
+ bindings: {},
9
+ bindings_by_id: {}
10
10
  )
11
11
  @debug = debug
12
12
  @in = input
13
13
  @out = out
14
14
  @pending_evals = {}
15
- @watches = watches
16
15
  @counter = 0
17
16
  @binding = binding
18
17
  @bindings = bindings
18
+ @bindings_by_id = bindings_by_id
19
19
  end
20
20
 
21
21
  def treat_messages!
@@ -28,6 +28,8 @@ module NREPL
28
28
  treat_msg(msg)
29
29
  end
30
30
  @pending_evals.each { |(i, _)| clear_eval!(i) }
31
+ rescue Errno::ECONNRESET
32
+ @pending_evals.each { |(i, _)| clear_eval!(i) }
31
33
  end
32
34
 
33
35
  def treat_msg(msg)
@@ -40,6 +42,9 @@ module NREPL
40
42
  eval_op(msg, false)
41
43
  when 'eval_pause'
42
44
  eval_op(msg, true)
45
+ when 'last_exception'
46
+ ex = Server.class_variable_get(:@@last_exception)
47
+ send_msg(response_for(msg, { 'result' => ex.inspect, 'status' => ['done'] }))
43
48
  when 'eval_resume'
44
49
  msg['id'] ||= "eval_#{@counter += 1}"
45
50
  stop_id = msg['stop_id']
@@ -52,7 +57,14 @@ module NREPL
52
57
  when 'unwatch'
53
58
  msg['id'] ||= "eval_#{@counter += 1}"
54
59
  watch_id = msg['watch_id']
55
- @watches.delete(watch_id)
60
+ info = @bindings_by_id.delete(watch_id)
61
+ if(info)
62
+ file_info = @bindings.fetch(info[:file], {})
63
+ content = file_info.fetch(info[:row], {})
64
+ content.delete(watch_id)
65
+ file_info.delete(info[:row]) if(content.empty?)
66
+ @bindings.delete(info[:file]) if(file_info.empty?)
67
+ end
56
68
 
57
69
  send_msg(response_for(msg, {
58
70
  'status' => ['done'],
@@ -110,7 +122,6 @@ module NREPL
110
122
  begin
111
123
  eval_msg(msg, stop)
112
124
  rescue Exception => e
113
- puts e.backtrace
114
125
  send_exception(msg, e)
115
126
  ensure
116
127
  @pending_evals.delete(id) unless stop
@@ -150,7 +161,7 @@ module NREPL
150
161
  original_bind = if msg['stop_id']
151
162
  @pending_evals.fetch(msg['stop_id'], {})[:binding]
152
163
  elsif msg['watch_id']
153
- @watches.fetch(msg['watch_id'], {})[:binding]
164
+ @bindings_by_id.fetch(msg['watch_id'], {})[:binding]
154
165
  else
155
166
  find_row_based_binding(msg) || @binding
156
167
  end
@@ -162,6 +173,12 @@ module NREPL
162
173
  end
163
174
  end
164
175
 
176
+ private def evaluate_code(code, file, line, bind)
177
+ bind ||= @@binding
178
+ line = line ? line + 1 : 1
179
+ eval(code, bind, file || "EVAL", line).inspect
180
+ end
181
+
165
182
  private def find_row_based_binding(msg)
166
183
  file = msg['file']
167
184
  row = msg['line']
@@ -170,7 +187,7 @@ module NREPL
170
187
  rows_bindings = @bindings[file]
171
188
  return unless rows_bindings
172
189
  found_row = row.downto(-1).find { |k| rows_bindings[k] }
173
- rows_bindings[found_row][:binding] if found_row
190
+ rows_bindings[found_row].values[-1] if found_row
174
191
  end
175
192
 
176
193
  private def define_stop_function!(msg, method_name)
@@ -228,9 +245,6 @@ module NREPL
228
245
  send_msg(response_for(msg, { 'versions' => versions }))
229
246
  end
230
247
 
231
- # @param [TCPSocket] client
232
- # @param [Hash] msg
233
- # @param [Exception] e
234
248
  def send_exception(msg, e)
235
249
  send_msg(response_for(msg, { 'ex' => e.message, 'status' => ['done', 'error'] }))
236
250
  end
@@ -244,8 +258,4 @@ module NREPL
244
258
  end
245
259
 
246
260
  # To avoid locally binding with the NREPL::Connection module
247
- b = binding
248
- define_method(:evaluate_code) do |code, file, line, bind|
249
- bind ||= b
250
- eval(code, bind, file || "EVAL", line || 0).inspect
251
- end
261
+ NREPL::Connection.class_variable_set(:@@binding, binding)
@@ -13,6 +13,14 @@ module NREPL
13
13
  attr_reader :debug, :port, :host
14
14
  alias debug? debug
15
15
 
16
+ def self.spawn(args = {})
17
+ t = Thread.new {
18
+ new(**args).start
19
+ }
20
+ sleep 0.1
21
+ t[:nrepl_server]
22
+ end
23
+
16
24
  def self.start(**kwargs)
17
25
  new(**kwargs).start
18
26
  end
@@ -21,7 +29,14 @@ module NREPL
21
29
  new(**kwargs.merge(binding: binding)).start
22
30
  end
23
31
 
24
- def initialize(port: DEFAULT_PORT, host: DEFAULT_HOST, debug: false, binding: nil, pwd: Dir.pwd)
32
+ def initialize(
33
+ port: DEFAULT_PORT,
34
+ host: DEFAULT_HOST,
35
+ debug: false,
36
+ binding: nil,
37
+ pwd: Dir.pwd,
38
+ tracing: true
39
+ )
25
40
  @port = port
26
41
  @pwd = pwd
27
42
  @host = host
@@ -29,8 +44,12 @@ module NREPL
29
44
  @connections = Set.new
30
45
  @binding = binding
31
46
  @bindings = {}
47
+ @bindings_by_id = {}
48
+ @tracing = tracing
49
+ Thread.current[:nrepl_server] = self
32
50
  NREPL.class_variable_set(:@@connections, @connections)
33
51
  NREPL.class_variable_set(:@@bindings, @bindings)
52
+ NREPL.class_variable_set(:@@bindings_by_id, @bindings_by_id)
34
53
  end
35
54
 
36
55
  private def record_port
@@ -44,31 +63,45 @@ module NREPL
44
63
  puts "Running in debug mode" if debug?
45
64
  record_port
46
65
 
66
+ @old_out, @old_err = $stdout, $stderr
47
67
  $stdout = FakeStdout.new(@connections, STDOUT, "out")
48
68
  $stderr = FakeStdout.new(@connections, STDERR, "err")
49
- auto_create_bindings!
69
+ auto_create_bindings! if @tracing
50
70
 
51
71
  Signal.trap("INT") { stop }
52
72
  Signal.trap("TERM") { stop }
53
73
 
54
- s = TCPServer.new(host, port)
74
+ @socket = TCPServer.new(host, port)
55
75
  loop do
56
- Thread.start(s.accept) do |client|
57
- connection = Connection.new(client, debug: debug?, binding: @binding, bindings: @bindings)
76
+ break if @socket.closed?
77
+ Thread.start(@socket.accept) do |client|
78
+ connection = Connection.new(
79
+ client,
80
+ debug: debug?,
81
+ binding: @binding,
82
+ bindings_by_id: @bindings_by_id,
83
+ bindings: @bindings
84
+ )
58
85
  @connections << connection
59
86
  connection.treat_messages!
60
87
  @connections.delete(connection)
61
88
  end
62
89
  end
90
+ rescue IOError
91
+ puts "Server closed" if debug?
63
92
  ensure
64
93
  File.unlink(PORT_FILENAME)
65
94
  end
66
95
 
67
96
  def auto_create_bindings!
68
97
  dir_regex = Regexp.new("^#{Regexp.escape(@pwd)}")
69
- @call_trace = TracePoint.new(:call) do |tp|
98
+ @call_trace = TracePoint.new(:class, :call) do |tp|
99
+ id = "#{tp.path}:#{tp.lineno}"
100
+ b = tp.binding
101
+ @bindings_by_id[id] = {binding: b, file: tp.path, row: tp.lineno-1}
70
102
  @bindings[tp.path] ||= {}
71
- @bindings[tp.path][tp.lineno-1] = {binding: tp.binding, id: "#{tp.path}:#{tp.lineno}"}
103
+ @bindings[tp.path][tp.lineno-1] ||= {}
104
+ @bindings[tp.path][tp.lineno-1][id] = b
72
105
  if tp.path =~ dir_regex
73
106
  @connections.each do |connection|
74
107
  connection.send_msg(
@@ -82,16 +115,17 @@ module NREPL
82
115
  end
83
116
  @call_trace.enable
84
117
 
85
- # @ex_trace = TracePoint.new(:raise) do |tp|
86
- # $foo = [tp.lineno, tp.event, tp.raised_exception, tp.binding, caller_locations]
87
- # # p $foo
88
- # end
89
- # @ex_trace.enable
118
+ @ex_trace = TracePoint.new(:raise) do |tp|
119
+ e = tp.raised_exception
120
+ @@last_exception = [:error, e.inspect.sub(/\>$/, ' stack=' + e.backtrace.inspect+'>')]
121
+ end
122
+ @ex_trace.enable
90
123
  end
91
124
 
92
125
  def stop
93
- Thread.exit
94
- exit(0)
126
+ @connections = []
127
+ $stdout, $stderr = @old_out, @old_err
128
+ @socket.close
95
129
  end
96
130
  end
97
131
 
data/lib/nrepl-lazuli.rb CHANGED
@@ -8,16 +8,19 @@ module NREPL
8
8
 
9
9
  require_relative 'nrepl-lazuli/server'
10
10
  @@bindings = {}
11
+ @@bindings_by_id = {}
11
12
  @@connections = Set.new
12
13
 
13
14
  def self.watch!(binding, id=nil)
14
15
  loc = caller_locations[0]
15
- file = loc.absolute_path
16
+ file = loc.path
16
17
  row = loc.lineno
17
18
  id ||= "#{file}:#{row}"
18
19
 
20
+ @@bindings_by_id[id] = {binding: binding, file: file, row: loc.lineno-1}
19
21
  @@bindings[file] ||= {}
20
- @@bindings[file][loc.lineno-1] = {id: id, binding: binding}
22
+ @@bindings[file][loc.lineno-1] ||= {}
23
+ @@bindings[file][loc.lineno-1][id] = binding
21
24
 
22
25
  @@connections.each do |connection|
23
26
  connection.send_msg(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nrepl-lazuli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maurício Szabo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-05 00:00:00.000000000 Z
11
+ date: 2024-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bencode
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  requirements: []
57
- rubygems_version: 3.5.3
57
+ rubygems_version: 3.5.9
58
58
  signing_key:
59
59
  specification_version: 4
60
60
  summary: A Ruby nREPL server