iruby 0.2.9 → 0.6.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 +5 -5
- data/.github/workflows/ubuntu.yml +62 -0
- data/CHANGES +64 -0
- data/Gemfile +3 -1
- data/LICENSE +1 -1
- data/README.md +120 -92
- data/Rakefile +36 -10
- data/ci/Dockerfile.base.erb +41 -0
- data/ci/Dockerfile.main.erb +7 -0
- data/ci/requirements.txt +1 -0
- data/docker/setup.sh +15 -0
- data/docker/test.sh +7 -0
- data/iruby.gemspec +13 -18
- data/lib/iruby.rb +13 -6
- data/lib/iruby/backend.rb +38 -9
- data/lib/iruby/command.rb +68 -12
- data/lib/iruby/display.rb +81 -41
- data/lib/iruby/event_manager.rb +40 -0
- data/lib/iruby/formatter.rb +3 -3
- data/lib/iruby/input.rb +6 -6
- data/lib/iruby/input/README.ipynb +55 -3
- data/lib/iruby/input/README.md +299 -0
- data/lib/iruby/input/autoload.rb +3 -2
- data/lib/iruby/input/builder.rb +4 -4
- data/lib/iruby/input/button.rb +2 -2
- data/lib/iruby/input/cancel.rb +1 -1
- data/lib/iruby/input/checkbox.rb +22 -4
- data/lib/iruby/input/date.rb +17 -6
- data/lib/iruby/input/field.rb +5 -4
- data/lib/iruby/input/file.rb +3 -3
- data/lib/iruby/input/form.rb +6 -6
- data/lib/iruby/input/label.rb +9 -3
- data/lib/iruby/input/multiple.rb +76 -0
- data/lib/iruby/input/popup.rb +5 -2
- data/lib/iruby/input/radio.rb +18 -6
- data/lib/iruby/input/select.rb +26 -12
- data/lib/iruby/input/textarea.rb +2 -1
- data/lib/iruby/input/widget.rb +2 -2
- data/lib/iruby/jupyter.rb +77 -0
- data/lib/iruby/kernel.rb +171 -31
- data/lib/iruby/ostream.rb +29 -8
- data/lib/iruby/session.rb +116 -0
- data/lib/iruby/session/{rbczmq.rb → cztop.rb} +21 -19
- data/lib/iruby/session/ffi_rzmq.rb +1 -1
- data/lib/iruby/session_adapter.rb +72 -0
- data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
- data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
- data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
- data/lib/iruby/session_adapter/test_adapter.rb +49 -0
- data/lib/iruby/utils.rb +13 -2
- data/lib/iruby/version.rb +1 -1
- data/run-test.sh +12 -0
- data/tasks/ci.rake +65 -0
- data/test/helper.rb +133 -0
- data/test/integration_test.rb +22 -11
- data/test/iruby/backend_test.rb +37 -0
- data/test/iruby/command_test.rb +207 -0
- data/test/iruby/event_manager_test.rb +92 -0
- data/test/iruby/jupyter_test.rb +27 -0
- data/test/iruby/kernel_test.rb +153 -0
- data/test/iruby/mime_test.rb +43 -0
- data/test/iruby/multi_logger_test.rb +1 -2
- data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
- data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
- data/test/iruby/session_adapter_test.rb +91 -0
- data/test/iruby/session_test.rb +48 -0
- data/test/run-test.rb +19 -0
- metadata +107 -50
- data/.travis.yml +0 -16
- data/CONTRIBUTORS +0 -19
- data/test/test_helper.rb +0 -5
data/lib/iruby/input/select.rb
CHANGED
@@ -1,24 +1,36 @@
|
|
1
1
|
module IRuby
|
2
2
|
module Input
|
3
3
|
class Select < Label
|
4
|
-
needs :options
|
4
|
+
needs :options, :default
|
5
5
|
|
6
6
|
builder :select do |*args, **params|
|
7
7
|
key = :select
|
8
8
|
key, *args = args if args.first.is_a? Symbol
|
9
9
|
|
10
|
-
key = unique_key(key)
|
11
|
-
|
10
|
+
params[:key] = unique_key(key)
|
11
|
+
params[:options] = args
|
12
|
+
params[:default] ||= false
|
13
|
+
|
14
|
+
unless params[:options].include? params[:default]
|
15
|
+
params[:options] = [nil, *params[:options].compact]
|
16
|
+
end
|
17
|
+
|
18
|
+
add_field Select.new(**params)
|
12
19
|
end
|
13
20
|
|
14
21
|
def widget_css
|
15
|
-
|
22
|
+
<<-CSS
|
23
|
+
.iruby-select {
|
24
|
+
min-width: 25%;
|
25
|
+
margin-left: 0 !important;
|
26
|
+
}
|
27
|
+
CSS
|
16
28
|
end
|
17
29
|
|
18
30
|
def widget_js
|
19
31
|
<<-JS
|
20
32
|
$('.iruby-select').change(function(){
|
21
|
-
$(this).data('iruby-value',
|
33
|
+
$(this).data('iruby-value',
|
22
34
|
$(this).find('option:selected').text()
|
23
35
|
);
|
24
36
|
});
|
@@ -26,16 +38,18 @@ module IRuby
|
|
26
38
|
end
|
27
39
|
|
28
40
|
def widget_html
|
29
|
-
widget_label do
|
30
|
-
div class: 'form-control' do
|
41
|
+
widget_label do
|
42
|
+
div class: 'form-control' do
|
31
43
|
params = {
|
32
|
-
class: 'iruby-select',
|
44
|
+
class: 'iruby-select',
|
33
45
|
:'data-iruby-key' => @key,
|
34
|
-
:'data-iruby-value' => @
|
46
|
+
:'data-iruby-value' => @default
|
35
47
|
}
|
36
|
-
|
37
|
-
select **params do
|
38
|
-
@options.each
|
48
|
+
|
49
|
+
select **params do
|
50
|
+
@options.each do |o|
|
51
|
+
option o, selected: @default == o
|
52
|
+
end
|
39
53
|
end
|
40
54
|
end
|
41
55
|
end
|
data/lib/iruby/input/textarea.rb
CHANGED
data/lib/iruby/input/widget.rb
CHANGED
@@ -9,13 +9,13 @@ module IRuby
|
|
9
9
|
def content; widget_html; end
|
10
10
|
|
11
11
|
def self.builder method, &block
|
12
|
-
Builder.instance_eval do
|
12
|
+
Builder.instance_eval do
|
13
13
|
define_method method, &block
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def widget_join method, *args
|
18
|
-
strings = args.map do |arg|
|
18
|
+
strings = args.map do |arg|
|
19
19
|
arg.is_a?(String) ? arg : arg.send(method)
|
20
20
|
end
|
21
21
|
strings.uniq.join("\n")
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module IRuby
|
2
|
+
module Jupyter
|
3
|
+
class << self
|
4
|
+
# User's default kernelspec directory is described here:
|
5
|
+
# https://jupyter.readthedocs.io/en/latest/projects/jupyter-directories.html
|
6
|
+
def default_data_dir
|
7
|
+
case
|
8
|
+
when windows?
|
9
|
+
appdata = windows_user_appdata
|
10
|
+
if !appdata.empty?
|
11
|
+
File.join(appdata, 'jupyter')
|
12
|
+
else
|
13
|
+
jupyter_config_dir = ENV.fetch('JUPYTER_CONFIG_DIR', File.expand_path('~/.jupyter'))
|
14
|
+
File.join(jupyter_config_dir, 'data')
|
15
|
+
end
|
16
|
+
when apple?
|
17
|
+
File.expand_path('~/Library/Jupyter')
|
18
|
+
else
|
19
|
+
xdg_data_home = ENV.fetch('XDG_DATA_HOME', '')
|
20
|
+
data_home = xdg_data_home[0] ? xdg_data_home : File.expand_path('~/.local/share')
|
21
|
+
File.join(data_home, 'jupyter')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def kernelspec_dir(data_dir=nil)
|
26
|
+
data_dir ||= default_data_dir
|
27
|
+
File.join(data_dir, 'kernels')
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# returns %APPDATA%
|
33
|
+
def windows_user_appdata
|
34
|
+
require 'fiddle/import'
|
35
|
+
check_windows
|
36
|
+
path = Fiddle::Pointer.malloc(2 * 300) # uint16_t[300]
|
37
|
+
csidl_appdata = 0x001a
|
38
|
+
case call_SHGetFolderPathW(Fiddle::NULL, csidl_appdata, Fiddle::NULL, 0, path)
|
39
|
+
when 0
|
40
|
+
len = (1 ... (path.size/2)).find {|i| path[2*i, 2] == "\0\0" }
|
41
|
+
path = path.to_str(2*len).encode(Encoding::UTF_8, Encoding::UTF_16LE)
|
42
|
+
else
|
43
|
+
ENV.fetch('APPDATA', '')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def call_SHGetFolderPathW(hwnd, csidl, hToken, dwFlags, pszPath)
|
48
|
+
require 'fiddle/import'
|
49
|
+
shell32 = Fiddle::Handle.new('shell32')
|
50
|
+
func = Fiddle::Function.new(
|
51
|
+
shell32['SHGetFolderPathW'],
|
52
|
+
[
|
53
|
+
Fiddle::TYPE_VOIDP,
|
54
|
+
Fiddle::TYPE_INT,
|
55
|
+
Fiddle::TYPE_VOIDP,
|
56
|
+
Fiddle::TYPE_INT,
|
57
|
+
Fiddle::TYPE_VOIDP
|
58
|
+
],
|
59
|
+
Fiddle::TYPE_INT,
|
60
|
+
Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[:stdcall])
|
61
|
+
func.(hwnd, csidl, hToken, dwFlags, pszPath)
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_windows
|
65
|
+
raise 'the current platform is not Windows' unless windows?
|
66
|
+
end
|
67
|
+
|
68
|
+
def windows?
|
69
|
+
/mingw|mswin/ =~ RUBY_PLATFORM
|
70
|
+
end
|
71
|
+
|
72
|
+
def apple?
|
73
|
+
/darwin/ =~ RUBY_PLATFORM
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/iruby/kernel.rb
CHANGED
@@ -1,29 +1,90 @@
|
|
1
1
|
module IRuby
|
2
|
+
ExecutionInfo = Struct.new(:raw_cell, :store_history, :silent)
|
3
|
+
|
2
4
|
class Kernel
|
3
5
|
RED = "\e[31m"
|
4
|
-
WHITE = "\e[37m"
|
5
6
|
RESET = "\e[0m"
|
6
7
|
|
7
|
-
|
8
|
+
@events = EventManager.new([:initialized])
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Return the event manager defined in the `IRuby::Kernel` class.
|
12
|
+
# This event manager can handle the following event:
|
13
|
+
#
|
14
|
+
# - `initialized`: The event occurred after the initialization of
|
15
|
+
# a `IRuby::Kernel` instance is finished
|
16
|
+
#
|
17
|
+
# @example Registering initialized event
|
18
|
+
# IRuby::Kernel.events.register(:initialized) do |result|
|
19
|
+
# STDERR.puts "IRuby kernel has been initialized"
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @see IRuby::EventManager
|
23
|
+
# @see IRuby::Kernel#events
|
24
|
+
attr_reader :events
|
25
|
+
|
26
|
+
# Returns the singleton kernel instance
|
8
27
|
attr_accessor :instance
|
9
28
|
end
|
10
29
|
|
30
|
+
# Returns a session object
|
11
31
|
attr_reader :session
|
12
32
|
|
13
|
-
|
33
|
+
EVENTS = [
|
34
|
+
:pre_execute,
|
35
|
+
:pre_run_cell,
|
36
|
+
:post_run_cell,
|
37
|
+
:post_execute
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
def initialize(config_file, session_adapter_name=nil)
|
14
41
|
@config = MultiJson.load(File.read(config_file))
|
15
42
|
IRuby.logger.debug("IRuby kernel start with config #{@config}")
|
16
43
|
Kernel.instance = self
|
17
44
|
|
18
|
-
@session = Session.new(@config)
|
45
|
+
@session = Session.new(@config, session_adapter_name)
|
19
46
|
$stdout = OStream.new(@session, :stdout)
|
20
47
|
$stderr = OStream.new(@session, :stderr)
|
21
48
|
|
49
|
+
init_parent_process_poller
|
50
|
+
|
51
|
+
@events = EventManager.new(EVENTS)
|
22
52
|
@execution_count = 0
|
23
53
|
@backend = create_backend
|
24
54
|
@running = true
|
55
|
+
|
56
|
+
self.class.events.trigger(:initialized, self)
|
25
57
|
end
|
26
58
|
|
59
|
+
# Returns the event manager defined in a `IRuby::Kernel` instance.
|
60
|
+
# This event manager can handle the following events:
|
61
|
+
#
|
62
|
+
# - `pre_execute`: The event occurred before running the code
|
63
|
+
#
|
64
|
+
# - `pre_run_cell`: The event occurred before running the code and
|
65
|
+
# if the code execution is not silent
|
66
|
+
#
|
67
|
+
# - `post_execute`: The event occurred after running the code
|
68
|
+
#
|
69
|
+
# - `post_run_cell`: The event occurred after running the code and
|
70
|
+
# if the code execution is not silent
|
71
|
+
#
|
72
|
+
# The callback functions of `pre_run_cell` event must take one argument
|
73
|
+
# to get an `ExecutionInfo` object.
|
74
|
+
# The callback functions of `post_run_cell` event must take one argument
|
75
|
+
# to get the result of the code execution.
|
76
|
+
#
|
77
|
+
# @example Registering post_run_cell event
|
78
|
+
# IRuby::Kernel.instance.events.register(:post_run_cell) do |result|
|
79
|
+
# STDERR.puts "The result of the last execution: %p" % result
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# @see IRuby::EventManager
|
83
|
+
# @see IRuby::ExecutionInfo
|
84
|
+
# @see IRuby::Kernel.events
|
85
|
+
attr_reader :events
|
86
|
+
|
87
|
+
# @private
|
27
88
|
def create_backend
|
28
89
|
PryBackend.new
|
29
90
|
rescue Exception => e
|
@@ -31,6 +92,7 @@ module IRuby
|
|
31
92
|
PlainBackend.new
|
32
93
|
end
|
33
94
|
|
95
|
+
# @private
|
34
96
|
def run
|
35
97
|
send_status :starting
|
36
98
|
while @running
|
@@ -38,8 +100,10 @@ module IRuby
|
|
38
100
|
end
|
39
101
|
end
|
40
102
|
|
103
|
+
# @private
|
41
104
|
def dispatch
|
42
105
|
msg = @session.recv(:reply)
|
106
|
+
IRuby.logger.debug "Kernel#dispatch: msg = #{msg}"
|
43
107
|
type = msg[:header]['msg_type']
|
44
108
|
raise "Unknown message type: #{msg.inspect}" unless type =~ /comm_|_request\Z/ && respond_to?(type)
|
45
109
|
begin
|
@@ -50,31 +114,54 @@ module IRuby
|
|
50
114
|
end
|
51
115
|
rescue Exception => e
|
52
116
|
IRuby.logger.debug "Kernel error: #{e.message}\n#{e.backtrace.join("\n")}"
|
53
|
-
@session.send(:publish, :error,
|
117
|
+
@session.send(:publish, :error, error_content(e))
|
54
118
|
end
|
55
119
|
|
120
|
+
# @private
|
56
121
|
def kernel_info_request(msg)
|
57
122
|
@session.send(:reply, :kernel_info_reply,
|
58
123
|
protocol_version: '5.0',
|
59
124
|
implementation: 'iruby',
|
60
|
-
banner: "IRuby #{IRuby::VERSION}",
|
61
125
|
implementation_version: IRuby::VERSION,
|
62
126
|
language_info: {
|
63
127
|
name: 'ruby',
|
64
128
|
version: RUBY_VERSION,
|
65
129
|
mimetype: 'application/x-ruby',
|
66
130
|
file_extension: '.rb'
|
67
|
-
}
|
131
|
+
},
|
132
|
+
banner: "IRuby #{IRuby::VERSION} (with #{@session.description})",
|
133
|
+
help_links: [
|
134
|
+
{
|
135
|
+
text: "Ruby Documentation",
|
136
|
+
url: "https://ruby-doc.org/"
|
137
|
+
}
|
138
|
+
],
|
139
|
+
status: :ok)
|
68
140
|
end
|
69
141
|
|
142
|
+
# @private
|
70
143
|
def send_status(status)
|
144
|
+
IRuby.logger.debug "Send status: #{status}"
|
71
145
|
@session.send(:publish, :status, execution_state: status)
|
72
146
|
end
|
73
147
|
|
148
|
+
# @private
|
74
149
|
def execute_request(msg)
|
75
150
|
code = msg[:content]['code']
|
76
|
-
|
77
|
-
|
151
|
+
store_history = msg[:content]['store_history']
|
152
|
+
silent = msg[:content]['silent']
|
153
|
+
|
154
|
+
@execution_count += 1 if store_history
|
155
|
+
|
156
|
+
unless silent
|
157
|
+
@session.send(:publish, :execute_input, code: code, execution_count: @execution_count)
|
158
|
+
end
|
159
|
+
|
160
|
+
events.trigger(:pre_execute)
|
161
|
+
unless silent
|
162
|
+
exec_info = ExecutionInfo.new(code, store_history, silent)
|
163
|
+
events.trigger(:pre_run_cell, exec_info)
|
164
|
+
end
|
78
165
|
|
79
166
|
content = {
|
80
167
|
status: :ok,
|
@@ -82,84 +169,137 @@ module IRuby
|
|
82
169
|
user_expressions: {},
|
83
170
|
execution_count: @execution_count
|
84
171
|
}
|
172
|
+
|
85
173
|
result = nil
|
86
174
|
begin
|
87
|
-
result = @backend.eval(code,
|
175
|
+
result = @backend.eval(code, store_history)
|
88
176
|
rescue SystemExit
|
89
177
|
content[:payload] << { source: :ask_exit }
|
90
178
|
rescue Exception => e
|
91
|
-
content =
|
179
|
+
content = error_content(e)
|
92
180
|
@session.send(:publish, :error, content)
|
181
|
+
content[:status] = :error
|
182
|
+
content[:execution_count] = @execution_count
|
183
|
+
end
|
184
|
+
|
185
|
+
unless result.nil? || silent
|
186
|
+
@session.send(:publish, :execute_result,
|
187
|
+
data: Display.display(result),
|
188
|
+
metadata: {},
|
189
|
+
execution_count: @execution_count)
|
93
190
|
end
|
191
|
+
|
192
|
+
events.trigger(:post_execute)
|
193
|
+
events.trigger(:post_run_cell, result) unless silent
|
194
|
+
|
94
195
|
@session.send(:reply, :execute_reply, content)
|
95
|
-
@session.send(:publish, :execute_result,
|
96
|
-
data: Display.display(result),
|
97
|
-
metadata: {},
|
98
|
-
execution_count: @execution_count) unless result.nil? || msg[:content]['silent']
|
99
196
|
end
|
100
197
|
|
101
|
-
|
102
|
-
|
103
|
-
|
198
|
+
# @private
|
199
|
+
def error_content(e)
|
200
|
+
rindex = e.backtrace.rindex{|line| line.start_with?(@backend.eval_path)} || -1
|
201
|
+
backtrace = SyntaxError === e && rindex == -1 ? [] : e.backtrace[0..rindex]
|
202
|
+
{ ename: e.class.to_s,
|
104
203
|
evalue: e.message,
|
105
|
-
traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *
|
106
|
-
|
204
|
+
traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *backtrace] }
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def is_complete_request(msg)
|
209
|
+
# FIXME: the code completeness should be judged by using ripper or other Ruby parser
|
210
|
+
@session.send(:reply, :is_complete_reply,
|
211
|
+
status: :unknown)
|
107
212
|
end
|
108
213
|
|
214
|
+
# @private
|
109
215
|
def complete_request(msg)
|
110
216
|
# HACK for #26, only complete last line
|
111
217
|
code = msg[:content]['code']
|
112
|
-
if start = code.rindex(
|
218
|
+
if start = code.rindex(/\s|\R/)
|
113
219
|
code = code[start+1..-1]
|
114
220
|
start += 1
|
115
221
|
end
|
116
222
|
@session.send(:reply, :complete_reply,
|
117
223
|
matches: @backend.complete(code),
|
118
|
-
status: :ok,
|
119
224
|
cursor_start: start.to_i,
|
120
|
-
cursor_end: msg[:content]['cursor_pos']
|
225
|
+
cursor_end: msg[:content]['cursor_pos'],
|
226
|
+
metadata: {},
|
227
|
+
status: :ok)
|
121
228
|
end
|
122
229
|
|
230
|
+
# @private
|
123
231
|
def connect_request(msg)
|
124
232
|
@session.send(:reply, :connect_reply, Hash[%w(shell_port iopub_port stdin_port hb_port).map {|k| [k, @config[k]] }])
|
125
233
|
end
|
126
234
|
|
235
|
+
# @private
|
127
236
|
def shutdown_request(msg)
|
128
237
|
@session.send(:reply, :shutdown_reply, msg[:content])
|
129
238
|
@running = false
|
130
239
|
end
|
131
240
|
|
241
|
+
# @private
|
132
242
|
def history_request(msg)
|
133
243
|
# we will just send back empty history for now, pending clarification
|
134
244
|
# as requested in ipython/ipython#3806
|
135
245
|
@session.send(:reply, :history_reply, history: [])
|
136
246
|
end
|
137
247
|
|
248
|
+
# @private
|
138
249
|
def inspect_request(msg)
|
139
|
-
|
140
|
-
@session.send(:reply, :inspect_reply,
|
141
|
-
status: :ok,
|
142
|
-
data: Display.display(result),
|
143
|
-
metadata: {})
|
144
|
-
rescue Exception => e
|
145
|
-
IRuby.logger.warn "Inspection error: #{e.message}\n#{e.backtrace.join("\n")}"
|
146
|
-
@session.send(:reply, :inspect_reply, status: :error)
|
250
|
+
# not yet implemented. See (#119).
|
251
|
+
@session.send(:reply, :inspect_reply, status: :ok, found: false, data: {}, metadata: {})
|
147
252
|
end
|
148
253
|
|
254
|
+
# @private
|
149
255
|
def comm_open(msg)
|
150
256
|
comm_id = msg[:content]['comm_id']
|
151
257
|
target_name = msg[:content]['target_name']
|
152
258
|
Comm.comm[comm_id] = Comm.target[target_name].new(target_name, comm_id)
|
153
259
|
end
|
154
260
|
|
261
|
+
# @private
|
155
262
|
def comm_msg(msg)
|
156
263
|
Comm.comm[msg[:content]['comm_id']].handle_msg(msg[:content]['data'])
|
157
264
|
end
|
158
265
|
|
266
|
+
# @private
|
159
267
|
def comm_close(msg)
|
160
268
|
comm_id = msg[:content]['comm_id']
|
161
269
|
Comm.comm[comm_id].handle_close(msg[:content]['data'])
|
162
270
|
Comm.comm.delete(comm_id)
|
163
271
|
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def init_parent_process_poller
|
276
|
+
pid = ENV.fetch('JPY_PARENT_PID', 0).to_i
|
277
|
+
return unless pid > 1
|
278
|
+
|
279
|
+
case RUBY_PLATFORM
|
280
|
+
when /mswin/, /mingw/
|
281
|
+
# TODO
|
282
|
+
else
|
283
|
+
@parent_poller = start_parent_process_pollar_unix
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def start_parent_process_pollar_unix
|
288
|
+
Thread.start do
|
289
|
+
IRuby.logger.warn("parent process poller thread started.")
|
290
|
+
loop do
|
291
|
+
begin
|
292
|
+
current_ppid = Process.ppid
|
293
|
+
if current_ppid == 1
|
294
|
+
IRuby.logger.warn("parent process appears to exited, shutting down.")
|
295
|
+
exit!(1)
|
296
|
+
end
|
297
|
+
sleep 1
|
298
|
+
rescue Errno::EINTR
|
299
|
+
# ignored
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
164
304
|
end
|
165
305
|
end
|