iruby 0.2.8 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +76 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +130 -82
  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 -17
  14. data/lib/iruby.rb +14 -6
  15. data/lib/iruby/backend.rb +41 -7
  16. data/lib/iruby/command.rb +68 -12
  17. data/lib/iruby/display.rb +80 -39
  18. data/lib/iruby/event_manager.rb +40 -0
  19. data/lib/iruby/formatter.rb +5 -4
  20. data/lib/iruby/input.rb +41 -0
  21. data/lib/iruby/input/README.ipynb +502 -0
  22. data/lib/iruby/input/README.md +299 -0
  23. data/lib/iruby/input/autoload.rb +25 -0
  24. data/lib/iruby/input/builder.rb +67 -0
  25. data/lib/iruby/input/button.rb +47 -0
  26. data/lib/iruby/input/cancel.rb +32 -0
  27. data/lib/iruby/input/checkbox.rb +74 -0
  28. data/lib/iruby/input/date.rb +37 -0
  29. data/lib/iruby/input/field.rb +31 -0
  30. data/lib/iruby/input/file.rb +57 -0
  31. data/lib/iruby/input/form.rb +77 -0
  32. data/lib/iruby/input/label.rb +27 -0
  33. data/lib/iruby/input/multiple.rb +76 -0
  34. data/lib/iruby/input/popup.rb +41 -0
  35. data/lib/iruby/input/radio.rb +59 -0
  36. data/lib/iruby/input/select.rb +59 -0
  37. data/lib/iruby/input/textarea.rb +23 -0
  38. data/lib/iruby/input/widget.rb +34 -0
  39. data/lib/iruby/jupyter.rb +77 -0
  40. data/lib/iruby/kernel.rb +106 -27
  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} +25 -13
  44. data/lib/iruby/session/ffi_rzmq.rb +15 -2
  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 +5 -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 +132 -43
  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_reply", "execute_result" ],
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