iruby 0.3 → 0.7.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.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES.md +203 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +137 -87
  7. data/Rakefile +36 -10
  8. data/ci/Dockerfile.base.erb +41 -0
  9. data/ci/Dockerfile.main.erb +7 -0
  10. data/ci/requirements.txt +1 -0
  11. data/docker/setup.sh +15 -0
  12. data/docker/test.sh +7 -0
  13. data/iruby.gemspec +14 -18
  14. data/lib/iruby.rb +14 -8
  15. data/lib/iruby/backend.rb +38 -10
  16. data/lib/iruby/command.rb +67 -15
  17. data/lib/iruby/display.rb +77 -41
  18. data/lib/iruby/event_manager.rb +40 -0
  19. data/lib/iruby/formatter.rb +3 -3
  20. data/lib/iruby/input.rb +6 -6
  21. data/lib/iruby/input/README.md +299 -0
  22. data/lib/iruby/input/autoload.rb +1 -1
  23. data/lib/iruby/input/builder.rb +4 -4
  24. data/lib/iruby/input/button.rb +2 -2
  25. data/lib/iruby/input/cancel.rb +1 -1
  26. data/lib/iruby/input/checkbox.rb +3 -3
  27. data/lib/iruby/input/date.rb +3 -3
  28. data/lib/iruby/input/field.rb +2 -2
  29. data/lib/iruby/input/file.rb +3 -3
  30. data/lib/iruby/input/form.rb +6 -6
  31. data/lib/iruby/input/label.rb +4 -4
  32. data/lib/iruby/input/multiple.rb +10 -10
  33. data/lib/iruby/input/popup.rb +2 -2
  34. data/lib/iruby/input/radio.rb +6 -6
  35. data/lib/iruby/input/select.rb +8 -8
  36. data/lib/iruby/input/textarea.rb +1 -1
  37. data/lib/iruby/input/widget.rb +2 -2
  38. data/lib/iruby/jupyter.rb +77 -0
  39. data/lib/iruby/kernel.rb +204 -36
  40. data/lib/iruby/ostream.rb +29 -8
  41. data/lib/iruby/session.rb +117 -0
  42. data/lib/iruby/session/cztop.rb +4 -0
  43. data/lib/iruby/session_adapter.rb +72 -0
  44. data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
  45. data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
  46. data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
  47. data/lib/iruby/session_adapter/test_adapter.rb +49 -0
  48. data/lib/iruby/utils.rb +13 -2
  49. data/lib/iruby/version.rb +1 -1
  50. data/run-test.sh +12 -0
  51. data/tasks/ci.rake +65 -0
  52. data/test/helper.rb +136 -0
  53. data/test/integration_test.rb +22 -11
  54. data/test/iruby/backend_test.rb +37 -0
  55. data/test/iruby/command_test.rb +207 -0
  56. data/test/iruby/event_manager_test.rb +92 -0
  57. data/test/iruby/jupyter_test.rb +27 -0
  58. data/test/iruby/kernel_test.rb +185 -0
  59. data/test/iruby/mime_test.rb +50 -0
  60. data/test/iruby/multi_logger_test.rb +1 -5
  61. data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
  62. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
  63. data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
  64. data/test/iruby/session_adapter_test.rb +91 -0
  65. data/test/iruby/session_test.rb +48 -0
  66. data/test/run-test.rb +19 -0
  67. metadata +120 -50
  68. data/.travis.yml +0 -16
  69. data/CHANGES +0 -143
  70. data/CONTRIBUTORS +0 -19
  71. data/lib/iruby/session/rbczmq.rb +0 -68
  72. data/test/test_helper.rb +0 -5
@@ -0,0 +1,27 @@
1
+ require 'iruby/jupyter'
2
+
3
+ module IRubyTest
4
+ class JupyterDefaultKernelSpecDirectoryTest < TestBase
5
+ def setup
6
+ @kernel_spec = IRuby::Jupyter.kernelspec_dir
7
+ end
8
+
9
+ def test_default_windows
10
+ windows_only
11
+ appdata = IRuby::Jupyter.send :windows_user_appdata
12
+ assert_equal(File.join(appdata, 'jupyter/kernels'), @kernel_spec)
13
+ end
14
+
15
+ def test_default_apple
16
+ apple_only
17
+ assert_equal(File.expand_path('~/Library/Jupyter/kernels'), @kernel_spec)
18
+ end
19
+
20
+ def test_default_unix
21
+ unix_only
22
+ with_env('XDG_DATA_HOME' => nil) do
23
+ assert_equal(File.expand_path('~/.local/share/jupyter/kernels'), @kernel_spec)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,185 @@
1
+ require "base64"
2
+
3
+ module IRubyTest
4
+ class KernelTest < TestBase
5
+ def setup
6
+ super
7
+ with_session_adapter("test")
8
+ @kernel = IRuby::Kernel.instance
9
+ end
10
+
11
+ sub_test_case("iruby_initialized event") do
12
+ def setup
13
+ super
14
+ @initialized_kernel = nil
15
+ @callback = IRuby::Kernel.events.register(:initialized) do |kernel|
16
+ @initialized_kernel = kernel
17
+ end
18
+ end
19
+
20
+ def teardown
21
+ IRuby::Kernel.events.unregister(:initialized, @callback)
22
+ end
23
+
24
+ def test_iruby_initialized_event
25
+ with_session_adapter("test")
26
+ assert_same(IRuby::Kernel.instance, @initialized_kernel)
27
+ end
28
+ end
29
+
30
+ def test_execute_request
31
+ obj = Object.new
32
+
33
+ class << obj
34
+ def to_html
35
+ "<b>HTML</b>"
36
+ end
37
+
38
+ def inspect
39
+ "!!! inspect !!!"
40
+ end
41
+ end
42
+
43
+ ::IRubyTest.define_singleton_method(:test_object) { obj }
44
+
45
+ msg_types = []
46
+ execute_reply = nil
47
+ execute_result = nil
48
+ @kernel.session.adapter.send_callback = ->(sock, msg) do
49
+ header = msg[:header]
50
+ content = msg[:content]
51
+ msg_types << header["msg_type"]
52
+ case header["msg_type"]
53
+ when "execute_reply"
54
+ execute_reply = content
55
+ when "execute_result"
56
+ execute_result = content
57
+ end
58
+ end
59
+
60
+ msg = {
61
+ content: {
62
+ "code" => "IRubyTest.test_object",
63
+ "silent" => false,
64
+ "store_history" => false,
65
+ "user_expressions" => {},
66
+ "allow_stdin" => false,
67
+ "stop_on_error" => true,
68
+ }
69
+ }
70
+ @kernel.execute_request(msg)
71
+
72
+ assert_equal({
73
+ msg_types: [ "execute_input", "execute_result", "execute_reply" ],
74
+ execute_reply: {
75
+ status: "ok",
76
+ user_expressions: {},
77
+ },
78
+ execute_result: {
79
+ data: {
80
+ "text/html" => "<b>HTML</b>",
81
+ "text/plain" => "!!! inspect !!!"
82
+ },
83
+ metadata: {},
84
+ }
85
+ },
86
+ {
87
+ msg_types: msg_types,
88
+ execute_reply: {
89
+ status: execute_reply["status"],
90
+ user_expressions: execute_reply["user_expressions"]
91
+ },
92
+ execute_result: {
93
+ data: execute_result["data"],
94
+ metadata: execute_result["metadata"]
95
+ }
96
+ })
97
+ end
98
+
99
+ def test_events_around_of_execute_request
100
+ event_history = []
101
+
102
+ @kernel.events.register(:pre_execute) do
103
+ event_history << :pre_execute
104
+ end
105
+
106
+ @kernel.events.register(:pre_run_cell) do |exec_info|
107
+ event_history << [:pre_run_cell, exec_info]
108
+ end
109
+
110
+ @kernel.events.register(:post_execute) do
111
+ event_history << :post_execute
112
+ end
113
+
114
+ @kernel.events.register(:post_run_cell) do |result|
115
+ event_history << [:post_run_cell, result]
116
+ end
117
+
118
+ msg = {
119
+ content: {
120
+ "code" => "true",
121
+ "silent" => false,
122
+ "store_history" => false,
123
+ "user_expressions" => {},
124
+ "allow_stdin" => false,
125
+ "stop_on_error" => true,
126
+ }
127
+ }
128
+ @kernel.execute_request(msg)
129
+
130
+ msg = {
131
+ content: {
132
+ "code" => "true",
133
+ "silent" => true,
134
+ "store_history" => false,
135
+ "user_expressions" => {},
136
+ "allow_stdin" => false,
137
+ "stop_on_error" => true,
138
+ }
139
+ }
140
+ @kernel.execute_request(msg)
141
+
142
+ assert_equal([
143
+ :pre_execute,
144
+ [:pre_run_cell, IRuby::ExecutionInfo.new("true", false, false)],
145
+ :post_execute,
146
+ [:post_run_cell, true],
147
+ :pre_execute,
148
+ :post_execute
149
+ ],
150
+ event_history)
151
+ end
152
+
153
+ sub_test_case("#switch_backend!") do
154
+ sub_test_case("") do
155
+ def test_switch_backend
156
+ classes = []
157
+
158
+ # First pick the default backend class
159
+ classes << @kernel.instance_variable_get(:@backend).class
160
+
161
+ @kernel.switch_backend!(:pry)
162
+ classes << @kernel.instance_variable_get(:@backend).class
163
+
164
+ @kernel.switch_backend!(:irb)
165
+ classes << @kernel.instance_variable_get(:@backend).class
166
+
167
+ @kernel.switch_backend!(:pry)
168
+ classes << @kernel.instance_variable_get(:@backend).class
169
+
170
+ @kernel.switch_backend!(:plain)
171
+ classes << @kernel.instance_variable_get(:@backend).class
172
+
173
+ assert_equal([
174
+ IRuby::PlainBackend,
175
+ IRuby::PryBackend,
176
+ IRuby::PlainBackend,
177
+ IRuby::PryBackend,
178
+ IRuby::PlainBackend
179
+ ],
180
+ classes)
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,50 @@
1
+ class IRubyTest::MimeTest < IRubyTest::TestBase
2
+ sub_test_case("IRuby::Display") do
3
+ sub_test_case(".display") do
4
+ sub_test_case("with mime type") do
5
+ test("text/html") do
6
+ html = "<b>Bold Text</b>"
7
+
8
+ obj = Object.new
9
+ obj.define_singleton_method(:to_s) { html }
10
+
11
+ res = IRuby::Display.display(obj, mime: "text/html")
12
+ assert_equal({ plain: obj.inspect, html: html },
13
+ { plain: res["text/plain"], html: res["text/html"] })
14
+ end
15
+
16
+ test("application/javascript") do
17
+ data = "alert('Hello World!')"
18
+ res = IRuby::Display.display(data, mime: "application/javascript")
19
+ assert_equal(data,
20
+ res["application/javascript"])
21
+ end
22
+
23
+ test("image/svg+xml") do
24
+ data = '<svg height="30" width="100"><text x="0" y="15" fill="red">SVG</text></svg>'
25
+ res = IRuby::Display.display(data, mime: "image/svg+xml")
26
+ assert_equal(data,
27
+ res["image/svg+xml"])
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ sub_test_case("Rendering a file") do
34
+ def setup
35
+ @html = "<b>Bold Text</b>"
36
+ Dir.mktmpdir do |tmpdir|
37
+ @file = File.join(tmpdir, "test.html")
38
+ File.write(@file, @html)
39
+ yield
40
+ end
41
+ end
42
+
43
+ def test_display
44
+ File.open(@file, "rb") do |f|
45
+ res = IRuby::Display.display(f)
46
+ assert_equal(@html, res["text/html"])
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,8 +1,4 @@
1
- require 'stringio'
2
- require 'test_helper'
3
- require 'iruby/logger'
4
-
5
- class MultiLoggerTest < IRubyTest
1
+ class IRubyTest::MultiLoggerTest < IRubyTest::TestBase
6
2
  def test_multilogger
7
3
  out, err = StringIO.new, StringIO.new
8
4
  logger = IRuby::MultiLogger.new(Logger.new(out), Logger.new(err))
@@ -0,0 +1,20 @@
1
+ require_relative 'session_adapter_test_base'
2
+ require 'iruby'
3
+
4
+ module IRubyTest
5
+ if ENV['IRUBY_TEST_SESSION_ADAPTER_NAME'] == 'cztop'
6
+ class CztopAdapterTest < SessionAdapterTestBase
7
+ def adapter_class
8
+ IRuby::SessionAdapter::CztopAdapter
9
+ end
10
+
11
+ def test_send
12
+ assert(adapter_class.available?)
13
+ end
14
+
15
+ def test_recv
16
+ omit
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'session_adapter_test_base'
2
+ require 'iruby'
3
+
4
+ module IRubyTest
5
+ if ENV['IRUBY_TEST_SESSION_ADAPTER_NAME'] == 'ffi-rzmq'
6
+ class FfirzmqAdapterTest < SessionAdapterTestBase
7
+ def adapter_class
8
+ IRuby::SessionAdapter::FfirzmqAdapter
9
+ end
10
+
11
+ def test_send
12
+ assert(adapter_class.available?)
13
+ end
14
+
15
+ def test_recv
16
+ omit
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ module IRubyTest
2
+ class SessionAdapterTestBase < TestBase
3
+ # https://jupyter-client.readthedocs.io/en/stable/kernels.html#connection-files
4
+ def make_connection_config
5
+ {
6
+ "control_port" => 50160,
7
+ "shell_port" => 57503,
8
+ "transport" => "tcp",
9
+ "signature_scheme" => "hmac-sha256",
10
+ "stdin_port" => 52597,
11
+ "hb_port" => 42540,
12
+ "ip" => "127.0.0.1",
13
+ "iopub_port" => 40885,
14
+ "key" => "a0436f6c-1916-498b-8eb9-e81ab9368e84"
15
+ }
16
+ end
17
+
18
+ def setup
19
+ @config = make_connection_config
20
+ @session_adapter = adapter_class.new(@config)
21
+
22
+ unless adapter_class.available?
23
+ omit("#{@session_adapter.name} is unavailable")
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,91 @@
1
+ module IRubyTest
2
+ class SessionAdapterTest < TestBase
3
+ def test_available_p_return_false_when_load_error
4
+ subclass = Class.new(IRuby::SessionAdapter::BaseAdapter)
5
+ class << subclass
6
+ def load_requirements
7
+ raise LoadError
8
+ end
9
+ end
10
+ refute subclass.available?
11
+ end
12
+
13
+ def test_select_adapter_class_with_cztop
14
+ assert_rr do
15
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { true }
16
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { false }
17
+ stub(IRuby::SessionAdapter::PyzmqAdapter).available? { false }
18
+
19
+ cls = IRuby::SessionAdapter.select_adapter_class
20
+ assert_equal IRuby::SessionAdapter::CztopAdapter, cls
21
+ end
22
+ end
23
+
24
+ def test_select_adapter_class_with_ffirzmq
25
+ assert_rr do
26
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { true }
27
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { false }
28
+ stub(IRuby::SessionAdapter::PyzmqAdapter).available? { false }
29
+
30
+ cls = IRuby::SessionAdapter.select_adapter_class
31
+ assert_equal IRuby::SessionAdapter::FfirzmqAdapter, cls
32
+ end
33
+ end
34
+
35
+ def test_select_adapter_class_with_pyzmq
36
+ omit("pyzmq adapter is disabled")
37
+ assert_rr do
38
+ stub(IRuby::SessionAdapter::PyzmqAdapter).available? { true }
39
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { false }
40
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { false }
41
+
42
+ cls = IRuby::SessionAdapter.select_adapter_class
43
+ assert_equal IRuby::SessionAdapter::PyzmqAdapter, cls
44
+ end
45
+ end
46
+
47
+ def test_select_adapter_class_with_env
48
+ with_env('IRUBY_SESSION_ADAPTER' => 'cztop') do
49
+ assert_rr do
50
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { true }
51
+ assert_equal IRuby::SessionAdapter::CztopAdapter, IRuby::SessionAdapter.select_adapter_class
52
+ end
53
+
54
+ assert_rr do
55
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { false }
56
+ assert_raises IRuby::SessionAdapterNotFound do
57
+ IRuby::SessionAdapter.select_adapter_class
58
+ end
59
+ end
60
+ end
61
+
62
+ with_env('IRUBY_SESSION_ADAPTER' => 'ffi-rzmq') do
63
+ assert_rr do
64
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { true }
65
+ assert_equal IRuby::SessionAdapter::FfirzmqAdapter, IRuby::SessionAdapter.select_adapter_class
66
+ end
67
+
68
+ assert_rr do
69
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { false }
70
+ assert_raises IRuby::SessionAdapterNotFound do
71
+ IRuby::SessionAdapter.select_adapter_class
72
+ end
73
+ end
74
+ end
75
+
76
+ with_env('IRUBY_SESSION_ADAPTER' => 'pyzmq') do
77
+ # pyzmq adapter is disabled
78
+ #
79
+ # IRuby::SessionAdapter::PyzmqAdapter.stub :available?, true do
80
+ # assert_equal IRuby::SessionAdapter::PyzmqAdapter, IRuby::SessionAdapter.select_adapter_class
81
+ # end
82
+ #
83
+ # IRuby::SessionAdapter::PyzmqAdapter.stub :available?, false do
84
+ # assert_raises IRuby::SessionAdapterNotFound do
85
+ # IRuby::SessionAdapter.select_adapter_class
86
+ # end
87
+ # end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,48 @@
1
+ module IRubyTest
2
+ class SessionAdapterSelectionTest < TestBase
3
+ def setup
4
+ # https://jupyter-client.readthedocs.io/en/stable/kernels.html#connection-files
5
+ @session_config = {
6
+ "control_port" => 0,
7
+ "shell_port" => 0,
8
+ "transport" => "tcp",
9
+ "signature_scheme" => "hmac-sha256",
10
+ "stdin_port" => 0,
11
+ "hb_port" => 0,
12
+ "ip" => "127.0.0.1",
13
+ "iopub_port" => 0,
14
+ "key" => "a0436f6c-1916-498b-8eb9-e81ab9368e84"
15
+ }
16
+ end
17
+
18
+ def test_new_with_session_adapter
19
+ adapter_name = ENV['IRUBY_TEST_SESSION_ADAPTER_NAME']
20
+ adapter_class = case adapter_name
21
+ when 'cztop'
22
+ IRuby::SessionAdapter::CztopAdapter
23
+ when 'ffi-rzmq'
24
+ IRuby::SessionAdapter::FfirzmqAdapter
25
+ when 'pyzmq'
26
+ omit("pyzmq adapter is disabled")
27
+ # IRuby::SessionAdapter::PyzmqAdapter
28
+ else
29
+ flunk "Unknown session adapter: #{adapter_name.inspect}"
30
+ end
31
+
32
+ session = IRuby::Session.new(@session_config, adapter_name)
33
+ assert_kind_of(adapter_class, session.adapter)
34
+ end
35
+
36
+ def test_without_any_session_adapter
37
+ assert_rr do
38
+ stub(IRuby::SessionAdapter::CztopAdapter).available? { false }
39
+ stub(IRuby::SessionAdapter::FfirzmqAdapter).available? { false }
40
+ stub(IRuby::SessionAdapter::PyzmqAdapter).available? { false }
41
+ stub(IRuby::SessionAdapter::TestAdapter).available? { false }
42
+ assert_raises IRuby::SessionAdapterNotFound do
43
+ IRuby::Session.new(@session_config)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end