iruby 0.7.3 → 0.8.0

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.
@@ -0,0 +1,380 @@
1
+ require "fileutils"
2
+ require "json"
3
+ require "optparse"
4
+ require "rbconfig"
5
+ require "singleton"
6
+
7
+ require_relative "error"
8
+ require_relative "kernel_app"
9
+
10
+ module IRuby
11
+ class Application
12
+ include Singleton
13
+
14
+ # Set the application instance up.
15
+ def setup(argv=nil)
16
+ @iruby_executable = File.expand_path($PROGRAM_NAME)
17
+ parse_command_line(argv)
18
+ end
19
+
20
+ # Parse the command line arguments
21
+ #
22
+ # @param argv [Array<String>, nil] The array of arguments.
23
+ private def parse_command_line(argv)
24
+ argv = ARGV.dup if argv.nil?
25
+ @argv = argv # save the original
26
+
27
+ case argv[0]
28
+ when "help"
29
+ # turn `iruby help notebook` into `iruby notebook -h`
30
+ argv = [*argv[1..-1], "-h"]
31
+ when "version"
32
+ # turn `iruby version` into `iruby -v`
33
+ argv = ["-v", *argv[1..-1]]
34
+ else
35
+ argv = argv.dup # prevent to break @argv
36
+ end
37
+
38
+ opts = OptionParser.new
39
+ opts.program_name = "IRuby"
40
+ opts.version = ::IRuby::VERSION
41
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] [subcommand] [options]"
42
+
43
+ opts.on_tail("-h", "--help") do
44
+ print_help(opts)
45
+ exit
46
+ end
47
+
48
+ opts.on_tail("-v", "--version") do
49
+ puts opts.ver
50
+ exit
51
+ end
52
+
53
+ opts.order!(argv)
54
+
55
+ if argv.length == 0 || argv[0].start_with?("-")
56
+ # If no subcommand is given, we use the console
57
+ argv = ["console", *argv]
58
+ end
59
+
60
+ begin
61
+ parse_sub_command(argv) if argv.length > 0
62
+ rescue InvalidSubcommandError => err
63
+ $stderr.puts err.message
64
+ print_help(opts, $stderr)
65
+ abort
66
+ end
67
+ end
68
+
69
+ SUB_COMMANDS = {
70
+ "register" => "Register IRuby kernel.",
71
+ "unregister" => "Unregister the existing IRuby kernel.",
72
+ "kernel" => "Launch IRuby kernel",
73
+ "console" => "Launch jupyter console with IRuby kernel"
74
+ }.freeze.each_value(&:freeze)
75
+
76
+ private_constant :SUB_COMMANDS
77
+
78
+ private def parse_sub_command(argv)
79
+ sub_cmd, *sub_argv = argv
80
+ case sub_cmd
81
+ when *SUB_COMMANDS.keys
82
+ @sub_cmd = sub_cmd.to_sym
83
+ @sub_argv = sub_argv
84
+ else
85
+ raise InvalidSubcommandError.new(sub_cmd, sub_argv)
86
+ end
87
+ end
88
+
89
+ private def print_help(opts, out=$stdout)
90
+ out.puts opts.help
91
+ out.puts
92
+ out.puts "Subcommands"
93
+ out.puts "==========="
94
+ SUB_COMMANDS.each do |name, description|
95
+ out.puts "#{name}"
96
+ out.puts " #{description}"
97
+ end
98
+ end
99
+
100
+ def run
101
+ case @sub_cmd
102
+ when :register
103
+ register_kernel(@sub_argv)
104
+ when :unregister
105
+ unregister_kernel(@sub_argv)
106
+ when :console
107
+ exec_jupyter(@sub_cmd.to_s, @sub_argv)
108
+ when :kernel
109
+ @sub_app = KernelApplication.new(@sub_argv)
110
+ @sub_app.run
111
+ else
112
+ raise "[IRuby][BUG] Unknown subcommand: #{@sub_cmd}; this must be treated in parse_command_line."
113
+ end
114
+ end
115
+
116
+ ruby_version_info = RUBY_VERSION.split('.')
117
+ DEFAULT_KERNEL_NAME = "ruby#{ruby_version_info[0]}".freeze
118
+ DEFAULT_DISPLAY_NAME = "Ruby #{ruby_version_info[0]} (iruby kernel)"
119
+
120
+ RegisterParams = Struct.new(
121
+ :name,
122
+ :display_name,
123
+ :profile,
124
+ :env,
125
+ :user,
126
+ :prefix,
127
+ :sys_prefix,
128
+ :force,
129
+ :ipython_dir
130
+ ) do
131
+ def initialize(*args)
132
+ super
133
+ self.name ||= DEFAULT_KERNEL_NAME
134
+ self.force = false
135
+ self.user = true
136
+ end
137
+ end
138
+
139
+ def register_kernel(argv)
140
+ params = parse_register_command_line(argv)
141
+
142
+ if params.name != DEFAULT_KERNEL_NAME
143
+ # `--name` is specified and `--display-name` is not
144
+ # default `params.display_name` to `params.name`
145
+ params.display_name ||= params.name
146
+ end
147
+
148
+ check_and_warn_kernel_in_default_ipython_directory(params)
149
+
150
+ if installed_kernel_exist?(params.name, params.ipython_dir)
151
+ unless params.force
152
+ $stderr.puts "IRuby kernel named `#{params.name}` already exists!"
153
+ $stderr.puts "Use --force to force register the new kernel."
154
+ exit 1
155
+ end
156
+ end
157
+
158
+ Dir.mktmpdir("iruby_kernel") do |tmpdir|
159
+ path = File.join(tmpdir, DEFAULT_KERNEL_NAME)
160
+ FileUtils.mkdir_p(path)
161
+
162
+ # Stage assets
163
+ assets_dir = File.expand_path("../assets", __FILE__)
164
+ FileUtils.cp_r(Dir.glob(File.join(assets_dir, "*")), path)
165
+
166
+ kernel_dict = {
167
+ "argv" => make_iruby_cmd(),
168
+ "display_name" => params.display_name || DEFAULT_DISPLAY_NAME,
169
+ "language" => "ruby",
170
+ "metadata" => {"debugger": false}
171
+ }
172
+
173
+ # TODO: Support params.profile
174
+ # TODO: Support params.env
175
+
176
+ kernel_content = JSON.pretty_generate(kernel_dict)
177
+ File.write(File.join(path, "kernel.json"), kernel_content)
178
+
179
+ args = ["--name=#{params.name}"]
180
+ args << "--user" if params.user
181
+ args << path
182
+
183
+ # TODO: Support params.prefix
184
+ # TODO: Support params.sys_prefix
185
+
186
+ system("jupyter", "kernelspec", "install", *args)
187
+ end
188
+ end
189
+
190
+ # Warn the existence of the IRuby kernel in the default IPython's kernels directory
191
+ private def check_and_warn_kernel_in_default_ipython_directory(params)
192
+ default_ipython_kernels_dir = File.expand_path("~/.ipython/kernels")
193
+ [params.name, "ruby"].each do |name|
194
+ if File.exist?(File.join(default_ipython_kernels_dir, name, "kernel.json"))
195
+ warn "IRuby kernel `#{name}` already exists in the deprecated IPython's data directory."
196
+ end
197
+ end
198
+ end
199
+
200
+ alias __system__ system
201
+
202
+ private def system(*cmdline, dry_run: false)
203
+ $stderr.puts "EXECUTE: #{cmdline.map {|x| x.include?(' ') ? x.inspect : x}.join(' ')}"
204
+ __system__(*cmdline) unless dry_run
205
+ end
206
+
207
+ private def installed_kernel_exist?(name, ipython_dir)
208
+ kernels_dir = resolve_kernelspec_dir(ipython_dir)
209
+ kernel_dir = File.join(kernels_dir, name)
210
+ File.file?(File.join(kernel_dir, "kernel.json"))
211
+ end
212
+
213
+ private def resolve_kernelspec_dir(ipython_dir)
214
+ if ENV.has_key?("JUPYTER_DATA_DIR")
215
+ if ENV.has_key?("IPYTHONDIR")
216
+ warn "both JUPYTER_DATA_DIR and IPYTHONDIR are supplied; IPYTHONDIR is ignored."
217
+ end
218
+ jupyter_data_dir = ENV["JUPYTER_DATA_DIR"]
219
+ return File.join(jupyter_data_dir, "kernels")
220
+ end
221
+
222
+ if ipython_dir.nil? && ENV.key?("IPYTHONDIR")
223
+ warn 'IPYTHONDIR is deprecated. Use JUPYTER_DATA_DIR instead.'
224
+ ipython_dir = ENV["IPYTHONDIR"]
225
+ end
226
+
227
+ if ipython_dir
228
+ File.join(ipython_dir, 'kerenels')
229
+ else
230
+ Jupyter.kernelspec_dir
231
+ end
232
+ end
233
+
234
+ private def make_iruby_cmd(executable: nil, extra_arguments: nil)
235
+ executable ||= default_executable
236
+ extra_arguments ||= []
237
+ [*Array(executable), "kernel", "-f", "{connection_file}", *extra_arguments]
238
+ end
239
+
240
+ private def default_executable
241
+ [RbConfig.ruby, @iruby_executable]
242
+ end
243
+
244
+ private def parse_register_command_line(argv)
245
+ opts = OptionParser.new
246
+ opts.banner = "Usage: #{$PROGRAM_NAME} register [options]"
247
+
248
+ params = RegisterParams.new
249
+
250
+ opts.on(
251
+ "--force",
252
+ "Force register a new kernel spec. The existing kernel spec will be removed."
253
+ ) { params.force = true }
254
+
255
+ opts.on(
256
+ "--user",
257
+ "Register for the current user instead of system-wide."
258
+ ) { params.user = true }
259
+
260
+ opts.on(
261
+ "--name=VALUE", String,
262
+ "Specify a name for the kernelspec. This is needed to have multiple IRuby kernels at the same time."
263
+ ) {|v| params.name = v }
264
+
265
+ opts.on(
266
+ "--display-name=VALUE", String,
267
+ "Specify the display name for the kernelspec. This is helpful when you have multiple IRuby kernels."
268
+ ) {|v| kernel_display_name = v }
269
+
270
+ # TODO: --profile
271
+ # TODO: --prefix
272
+ # TODO: --sys-prefix
273
+ # TODO: --env
274
+
275
+ define_ipython_dir_option(opts, params)
276
+
277
+ opts.order!(argv)
278
+
279
+ params
280
+ end
281
+
282
+ UnregisterParams = Struct.new(
283
+ :names,
284
+ #:profile,
285
+ #:user,
286
+ #:prefix,
287
+ #:sys_prefix,
288
+ :ipython_dir,
289
+ :force,
290
+ :yes
291
+ ) do
292
+ def initialize(*args, **kw)
293
+ super
294
+ self.names = []
295
+ # self.user = true
296
+ self.force = false
297
+ self.yes = false
298
+ end
299
+ end
300
+
301
+ def unregister_kernel(argv)
302
+ params = parse_unregister_command_line(argv)
303
+ opts = []
304
+ opts << "-y" if params.yes
305
+ opts << "-f" if params.force
306
+ system("jupyter", "kernelspec", "uninstall", *opts, *params.names)
307
+ end
308
+
309
+ private def parse_unregister_command_line(argv)
310
+ opts = OptionParser.new
311
+ opts.banner = "Usage: #{$PROGRAM_NAME} unregister [options] NAME [NAME ...]"
312
+
313
+ params = UnregisterParams.new
314
+
315
+ opts.on(
316
+ "-f", "--force",
317
+ "Force removal, don't prompt for confirmation."
318
+ ) { params.force = true}
319
+
320
+ opts.on(
321
+ "-y", "--yes",
322
+ "Answer yes to any prompts."
323
+ ) { params.yes = true }
324
+
325
+ # TODO: --user
326
+ # TODO: --profile
327
+ # TODO: --prefix
328
+ # TODO: --sys-prefix
329
+
330
+ define_ipython_dir_option(opts, params)
331
+
332
+ opts.order!(argv)
333
+
334
+ params.names = argv.dup
335
+
336
+ params
337
+ end
338
+
339
+ def exec_jupyter(sub_cmd, argv)
340
+ opts = OptionParser.new
341
+ opts.banner = "Usage: #{$PROGRAM_NAME} unregister [options]"
342
+
343
+ kernel_name = resolve_installed_kernel_name(DEFAULT_KERNEL_NAME)
344
+ opts.on(
345
+ "--kernel=NAME", String,
346
+ "The name of the default kernel to start."
347
+ ) {|v| kernel_name = v }
348
+
349
+ opts.order!(argv)
350
+
351
+ opts = ["--kernel=#{kernel_name}"]
352
+ exec("jupyter", "console", *opts)
353
+ end
354
+
355
+ private def resolve_installed_kernel_name(default_name)
356
+ kernels = IO.popen(["jupyter", "kernelspec", "list", "--json"], "r", err: File::NULL) do |jupyter_out|
357
+ JSON.load(jupyter_out.read)
358
+ end
359
+ unless kernels["kernelspecs"].key?(default_name)
360
+ return "ruby" if kernels["kernelspecs"].key?("ruby")
361
+ end
362
+ default_name
363
+ end
364
+
365
+ private def define_ipython_dir_option(opts, params)
366
+ opts.on(
367
+ "--ipython-dir=DIR", String,
368
+ "Specify the IPython's data directory (DEPRECATED)."
369
+ ) do |v|
370
+ if ENV.key?("JUPYTER_DATA_DIR")
371
+ warn 'Both JUPYTER_DATA_DIR and --ipython-dir are supplied; --ipython-dir is ignored.'
372
+ else
373
+ warn '--ipython-dir is deprecated. Use JUPYTER_DATA_DIR environment variable instead.'
374
+ end
375
+
376
+ params.ipython_dir = v
377
+ end
378
+ end
379
+ end
380
+ end
data/lib/iruby/backend.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  module IRuby
2
2
  In, Out = [nil], [nil]
3
3
 
4
+ class << self
5
+ attr_accessor :silent_assignment
6
+ end
7
+ self.silent_assignment = false
8
+
4
9
  module History
5
10
  def eval(code, store_history)
6
11
  b = eval_binding
@@ -52,8 +57,8 @@ module IRuby
52
57
  end
53
58
 
54
59
  def eval(code, store_history)
55
- @irb.context.evaluate(code, 0)
56
- @irb.context.last_value
60
+ @irb.context.evaluate(@irb.build_statement(code), 0)
61
+ @irb.context.last_value unless IRuby.silent_assignment && assignment_expression?(code)
57
62
  end
58
63
 
59
64
  def complete(code)
@@ -69,6 +74,10 @@ module IRuby
69
74
  wrapper_module.include(*args)
70
75
  end
71
76
  end
77
+
78
+ def assignment_expression?(code)
79
+ @irb.respond_to?(:assignment_expression?) && @irb.assignment_expression?(code)
80
+ end
72
81
  end
73
82
 
74
83
  class PryBackend
@@ -0,0 +1,12 @@
1
+ module IRuby
2
+ class Error < StandardError
3
+ end
4
+
5
+ class InvalidSubcommandError < Error
6
+ def initialize(name, argv)
7
+ @name = name
8
+ @argv = argv
9
+ super("Invalid subcommand name: #{@name}")
10
+ end
11
+ end
12
+ end
data/lib/iruby/jupyter.rb CHANGED
@@ -2,8 +2,11 @@ module IRuby
2
2
  module Jupyter
3
3
  class << self
4
4
  # User's default kernelspec directory is described here:
5
- # https://jupyter.readthedocs.io/en/latest/projects/jupyter-directories.html
5
+ # https://docs.jupyter.org/en/latest/use/jupyter-directories.html
6
6
  def default_data_dir
7
+ data_dir = ENV["JUPYTER_DATA_DIR"]
8
+ return data_dir if data_dir
9
+
7
10
  case
8
11
  when windows?
9
12
  appdata = windows_user_appdata
data/lib/iruby/kernel.rb CHANGED
@@ -176,8 +176,9 @@ module IRuby
176
176
  # @private
177
177
  def execute_request(msg)
178
178
  code = msg[:content]['code']
179
- store_history = msg[:content]['store_history']
180
179
  silent = msg[:content]['silent']
180
+ # https://jupyter-client.readthedocs.io/en/stable/messaging.html#execute
181
+ store_history = silent ? false : msg[:content].fetch('store_history', true)
181
182
 
182
183
  @execution_count += 1 if store_history
183
184
 
@@ -218,7 +219,8 @@ module IRuby
218
219
  end
219
220
 
220
221
  events.trigger(:post_execute)
221
- events.trigger(:post_run_cell, result) unless silent
222
+ # **{} is for Ruby2.7. Gnuplot#to_hash returns an Array.
223
+ events.trigger(:post_run_cell, result, **{}) unless silent
222
224
 
223
225
  @session.send(:reply, :execute_reply, content)
224
226
  end
@@ -0,0 +1,108 @@
1
+ module IRuby
2
+ class KernelApplication
3
+ def initialize(argv)
4
+ parse_command_line(argv)
5
+ end
6
+
7
+ def run
8
+ if @test_mode
9
+ dump_connection_file
10
+ return
11
+ end
12
+
13
+ run_kernel
14
+ end
15
+
16
+ DEFAULT_CONNECTION_FILE = "kernel-#{Process.pid}.json".freeze
17
+
18
+ private def parse_command_line(argv)
19
+ opts = OptionParser.new
20
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options] [subcommand] [options]"
21
+
22
+ @connection_file = nil
23
+ opts.on(
24
+ "-f CONNECTION_FILE", String,
25
+ "JSON file in which to store connection info (default: kernel-<pid>.json)"
26
+ ) {|v| @connection_file = v }
27
+
28
+ @test_mode = false
29
+ opts.on(
30
+ "--test",
31
+ "Run as test mode; dump the connection file and exit."
32
+ ) { @test_mode = true }
33
+
34
+ @log_file = nil
35
+ opts.on(
36
+ "--log=FILE", String,
37
+ "Specify the log file."
38
+ ) {|v| @log_file = v }
39
+
40
+ @log_level = Logger::INFO
41
+ opts.on(
42
+ "--debug",
43
+ "Set log-level debug"
44
+ ) { @log_level = Logger::DEBUG }
45
+
46
+ opts.order!(argv)
47
+
48
+ if @connection_file.nil?
49
+ # Without -f option, the connection file is at the beginning of the rest arguments
50
+ if argv.length <= 3
51
+ @connection_file, @boot_file, @work_dir = argv
52
+ else
53
+ raise ArgumentError, "Too many commandline arguments"
54
+ end
55
+ else
56
+ if argv.length <= 2
57
+ @boot_file, @work_dir = argv
58
+ else
59
+ raise ArgumentError, "Too many commandline arguments"
60
+ end
61
+ end
62
+
63
+ @connection_file ||= DEFAULT_CONNECTION_FILE
64
+ end
65
+
66
+ private def dump_connection_file
67
+ puts File.read(@connection_file)
68
+ end
69
+
70
+ private def run_kernel
71
+ IRuby.logger = MultiLogger.new(*Logger.new(STDOUT))
72
+ STDOUT.sync = true # FIXME: This can make the integration test.
73
+
74
+ IRuby.logger.loggers << Logger.new(@log_file) unless @log_file.nil?
75
+ IRuby.logger.level = @log_level
76
+
77
+ if @work_dir
78
+ IRuby.logger.debug("iruby kernel") { "Change the working directory: #{@work_dir}" }
79
+ Dir.chdir(@work_dir)
80
+ end
81
+
82
+ if @boot_file
83
+ IRuby.logger.debug("iruby kernel") { "Load the boot file: #{@boot_file}" }
84
+ require @boot_file
85
+ end
86
+
87
+ check_bundler {|e| IRuby.logger.warn "Could not load bundler: #{e.message}" }
88
+
89
+ require "iruby"
90
+ Kernel.new(@connection_file).run
91
+ rescue Exception => e
92
+ IRuby.logger.fatal "Kernel died: #{e.message}\n#{e.backtrace.join("\n")}"
93
+ exit 1
94
+ end
95
+
96
+ private def check_bundler
97
+ require "bundler"
98
+ unless Bundler.definition.specs.any? {|s| s.name == "iruby" }
99
+ raise %{IRuby is missing from Gemfile. This might not work. Add `gem "iruby"` in your Gemfile to fix it.}
100
+ end
101
+ Bundler.setup
102
+ rescue LoadError
103
+ # do nothing
104
+ rescue Exception => e
105
+ yield e
106
+ end
107
+ end
108
+ end
data/lib/iruby/logger.rb CHANGED
@@ -6,10 +6,20 @@ module IRuby
6
6
  end
7
7
 
8
8
  class MultiLogger < BasicObject
9
+ def initialize(*loggers, level: ::Logger::DEBUG)
10
+ @loggers = loggers
11
+ @level = level
12
+ end
13
+
9
14
  attr_reader :loggers
10
15
 
11
- def initialize(*loggers)
12
- @loggers = loggers
16
+ attr_reader :level
17
+
18
+ def level=(new_level)
19
+ @loggers.each do |l|
20
+ l.level = new_level
21
+ end
22
+ @level = new_level
13
23
  end
14
24
 
15
25
  def method_missing(name, *args, &b)
@@ -23,7 +23,7 @@ module IRuby
23
23
  idents, msg_list = frames[0..i-1], frames[i+1..-1]
24
24
 
25
25
  minlen = 5
26
- raise 'malformed message, must have at least #{minlen} elements' unless msg_list.length >= minlen
26
+ raise "malformed message, must have at least #{minlen} elements" unless msg_list.length >= minlen
27
27
  s, header, parent_header, metadata, content, buffers = *msg_list
28
28
  raise 'Invalid signature' unless s == sign(msg_list[1..-1])
29
29
  {
data/lib/iruby/session.rb CHANGED
@@ -2,6 +2,7 @@ require 'iruby/session_adapter'
2
2
  require 'iruby/session/mixin'
3
3
 
4
4
  require 'securerandom'
5
+ require 'time'
5
6
 
6
7
  module IRuby
7
8
  class Session
@@ -79,6 +80,7 @@ module IRuby
79
80
  header = {
80
81
  msg_type: message_type,
81
82
  msg_id: SecureRandom.uuid,
83
+ date: Time.now.utc.iso8601,
82
84
  username: 'kernel',
83
85
  session: @session_id,
84
86
  version: '5.0'
@@ -40,14 +40,12 @@ module IRuby
40
40
 
41
41
  require_relative 'session_adapter/ffirzmq_adapter'
42
42
  require_relative 'session_adapter/cztop_adapter'
43
- require_relative 'session_adapter/pyzmq_adapter'
44
43
  require_relative 'session_adapter/test_adapter'
45
44
 
46
45
  def self.select_adapter_class(name=nil)
47
46
  classes = {
48
47
  'ffi-rzmq' => SessionAdapter::FfirzmqAdapter,
49
48
  'cztop' => SessionAdapter::CztopAdapter,
50
- # 'pyzmq' => SessionAdapter::PyzmqAdapter
51
49
  'test' => SessionAdapter::TestAdapter,
52
50
  }
53
51
  if (name ||= ENV.fetch('IRUBY_SESSION_ADAPTER', nil))
@@ -61,6 +59,9 @@ module IRuby
61
59
  "Session adapter `#{name}` is unavailable"
62
60
  end
63
61
  end
62
+ if name == 'cztop'
63
+ warn "WARNING: cztop was deprecated and will be removed; Use ffi-rzmq, instead."
64
+ end
64
65
  return cls
65
66
  end
66
67
  classes.each_value do |cls|
data/lib/iruby/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module IRuby
2
- VERSION = '0.7.3'
2
+ VERSION = '0.8.0'
3
3
  end
data/test/helper.rb CHANGED
@@ -2,18 +2,36 @@ require "iruby"
2
2
  require "json"
3
3
  require 'multi_json'
4
4
  require "pathname"
5
+ require "rbconfig"
5
6
  require "test/unit"
6
7
  require "test/unit/rr"
7
8
  require "tmpdir"
8
9
 
9
-
10
10
  IRuby.logger = IRuby::MultiLogger.new(*Logger.new(STDERR, level: Logger::Severity::INFO))
11
11
 
12
12
  module IRubyTest
13
13
  class TestBase < Test::Unit::TestCase
14
+ TEST_DIR = File.expand_path("..", __FILE__).freeze
15
+ EXE_DIR = File.expand_path("../exe", TEST_DIR).freeze
16
+ LIB_DIR = File.expand_path("../lib", TEST_DIR).freeze
17
+
18
+ RUBY = RbConfig.ruby.freeze
19
+ IRUBY_PATH = File.join(EXE_DIR, "iruby").freeze
20
+
21
+ def iruby_command(*args)
22
+ [RUBY, "-I#{LIB_DIR}", IRUBY_PATH, *args]
23
+ end
24
+
14
25
  def self.startup
15
- @__config_dir = Dir.mktmpdir("iruby-test")
26
+ @__work_dir = Dir.mktmpdir("iruby-test-data")
27
+
28
+ @__jupyter_data_dir = File.join(@__work_dir, "jupyter")
29
+ @__save_jupyter_data_dir = ENV["JUPYTER_DATA_DIR"]
30
+ ENV["JUPYTER_DATA_DIR"] = @__jupyter_data_dir
31
+
32
+ @__config_dir = File.join(@__work_dir, "config")
16
33
  @__config_path = Pathname.new(@__config_dir) + "config.json"
34
+ @__config_path.dirname.mkpath
17
35
  File.write(@__config_path, {
18
36
  control_port: 50160,
19
37
  shell_port: 57503,
@@ -30,7 +48,8 @@ module IRubyTest
30
48
  end
31
49
 
32
50
  def self.shutdown
33
- FileUtils.remove_entry_secure(@__config_dir)
51
+ FileUtils.remove_entry_secure(@__work_dir)
52
+ ENV["JUPYTER_DATA_DIR"] = @__save_jupyter_data_dir
34
53
  end
35
54
 
36
55
  def self.test_config_filename