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.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +64 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +120 -92
  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 +13 -18
  14. data/lib/iruby.rb +13 -6
  15. data/lib/iruby/backend.rb +38 -9
  16. data/lib/iruby/command.rb +68 -12
  17. data/lib/iruby/display.rb +81 -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.ipynb +55 -3
  22. data/lib/iruby/input/README.md +299 -0
  23. data/lib/iruby/input/autoload.rb +3 -2
  24. data/lib/iruby/input/builder.rb +4 -4
  25. data/lib/iruby/input/button.rb +2 -2
  26. data/lib/iruby/input/cancel.rb +1 -1
  27. data/lib/iruby/input/checkbox.rb +22 -4
  28. data/lib/iruby/input/date.rb +17 -6
  29. data/lib/iruby/input/field.rb +5 -4
  30. data/lib/iruby/input/file.rb +3 -3
  31. data/lib/iruby/input/form.rb +6 -6
  32. data/lib/iruby/input/label.rb +9 -3
  33. data/lib/iruby/input/multiple.rb +76 -0
  34. data/lib/iruby/input/popup.rb +5 -2
  35. data/lib/iruby/input/radio.rb +18 -6
  36. data/lib/iruby/input/select.rb +26 -12
  37. data/lib/iruby/input/textarea.rb +2 -1
  38. data/lib/iruby/input/widget.rb +2 -2
  39. data/lib/iruby/jupyter.rb +77 -0
  40. data/lib/iruby/kernel.rb +171 -31
  41. data/lib/iruby/ostream.rb +29 -8
  42. data/lib/iruby/session.rb +116 -0
  43. data/lib/iruby/session/{rbczmq.rb → cztop.rb} +21 -19
  44. data/lib/iruby/session/ffi_rzmq.rb +1 -1
  45. data/lib/iruby/session_adapter.rb +72 -0
  46. data/lib/iruby/session_adapter/cztop_adapter.rb +45 -0
  47. data/lib/iruby/session_adapter/ffirzmq_adapter.rb +55 -0
  48. data/lib/iruby/session_adapter/pyzmq_adapter.rb +77 -0
  49. data/lib/iruby/session_adapter/test_adapter.rb +49 -0
  50. data/lib/iruby/utils.rb +13 -2
  51. data/lib/iruby/version.rb +1 -1
  52. data/run-test.sh +12 -0
  53. data/tasks/ci.rake +65 -0
  54. data/test/helper.rb +133 -0
  55. data/test/integration_test.rb +22 -11
  56. data/test/iruby/backend_test.rb +37 -0
  57. data/test/iruby/command_test.rb +207 -0
  58. data/test/iruby/event_manager_test.rb +92 -0
  59. data/test/iruby/jupyter_test.rb +27 -0
  60. data/test/iruby/kernel_test.rb +153 -0
  61. data/test/iruby/mime_test.rb +43 -0
  62. data/test/iruby/multi_logger_test.rb +1 -2
  63. data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
  64. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
  65. data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
  66. data/test/iruby/session_adapter_test.rb +91 -0
  67. data/test/iruby/session_test.rb +48 -0
  68. data/test/run-test.rb +19 -0
  69. metadata +107 -50
  70. data/.travis.yml +0 -16
  71. data/CONTRIBUTORS +0 -19
  72. data/test/test_helper.rb +0 -5
@@ -0,0 +1,92 @@
1
+ module IRubyTest
2
+ class EventManagerTest < TestBase
3
+ def setup
4
+ @man = IRuby::EventManager.new([:foo, :bar])
5
+ end
6
+
7
+ def test_available_events
8
+ assert_equal([:foo, :bar],
9
+ @man.available_events)
10
+ end
11
+
12
+ sub_test_case("#register") do
13
+ sub_test_case("known event name") do
14
+ def test_register
15
+ fn = ->() {}
16
+ assert_equal(fn,
17
+ @man.register(:foo, &fn))
18
+ end
19
+ end
20
+
21
+ sub_test_case("unknown event name") do
22
+ def test_register
23
+ assert_raise_message("Unknown event name: baz") do
24
+ @man.register(:baz) {}
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ sub_test_case("#unregister") do
31
+ sub_test_case("no event is registered") do
32
+ def test_unregister
33
+ fn = ->() {}
34
+ assert_raise_message("Given callable object #{fn} is not registered as a foo callback") do
35
+ @man.unregister(:foo, fn)
36
+ end
37
+ end
38
+ end
39
+
40
+ sub_test_case("the registered callable is given") do
41
+ def test_unregister
42
+ results = { values: [] }
43
+ fn = ->(a) { values << a }
44
+
45
+ @man.register(:foo, &fn)
46
+
47
+ results[:retval] = @man.unregister(:foo, fn)
48
+
49
+ @man.trigger(:foo, 42)
50
+
51
+ assert_equal({
52
+ values: [],
53
+ retval: fn
54
+ },
55
+ results)
56
+ end
57
+ end
58
+ end
59
+
60
+ sub_test_case("#trigger") do
61
+ sub_test_case("no event is registered") do
62
+ def test_trigger
63
+ assert_nothing_raised do
64
+ @man.trigger(:foo)
65
+ end
66
+ end
67
+ end
68
+
69
+ sub_test_case("some events are registered") do
70
+ def test_trigger
71
+ values = []
72
+ @man.register(:foo) {|a| values << a }
73
+ @man.register(:foo) {|a| values << 10*a }
74
+ @man.register(:foo) {|a| values << 100+a }
75
+
76
+ @man.trigger(:foo, 5)
77
+
78
+ assert_equal([5, 50, 105],
79
+ values)
80
+ end
81
+ end
82
+
83
+ sub_test_case("unknown event name") do
84
+ def test_trigger
85
+ assert_raise_message("Unknown event name: baz") do
86
+ @man.trigger(:baz, 100)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -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,153 @@
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
+ end
153
+ end
@@ -0,0 +1,43 @@
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
+ end
23
+ end
24
+ end
25
+
26
+ sub_test_case("Rendering a file") do
27
+ def setup
28
+ @html = "<b>Bold Text</b>"
29
+ Dir.mktmpdir do |tmpdir|
30
+ @file = File.join(tmpdir, "test.html")
31
+ File.write(@file, @html)
32
+ yield
33
+ end
34
+ end
35
+
36
+ def test_display
37
+ File.open(@file, "rb") do |f|
38
+ res = IRuby::Display.display(f)
39
+ assert_equal(@html, res["text/html"])
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,8 +1,7 @@
1
1
  require 'stringio'
2
- require 'test_helper'
3
2
  require 'iruby/logger'
4
3
 
5
- class MultiLoggerTest < IRubyTest
4
+ class IRubyTest::MultiLoggerTest < IRubyTest::TestBase
6
5
  def test_multilogger
7
6
  out, err = StringIO.new, StringIO.new
8
7
  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