iruby 0.4.0 → 0.5.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +24 -0
  4. data/Gemfile +0 -2
  5. data/LICENSE +1 -1
  6. data/README.md +66 -62
  7. data/Rakefile +10 -10
  8. data/ci/Dockerfile.main.erb +1 -3
  9. data/iruby.gemspec +13 -19
  10. data/lib/iruby.rb +2 -6
  11. data/lib/iruby/backend.rb +19 -5
  12. data/lib/iruby/display.rb +57 -41
  13. data/lib/iruby/formatter.rb +3 -3
  14. data/lib/iruby/input.rb +6 -6
  15. data/lib/iruby/input/autoload.rb +1 -1
  16. data/lib/iruby/input/builder.rb +4 -4
  17. data/lib/iruby/input/button.rb +2 -2
  18. data/lib/iruby/input/cancel.rb +1 -1
  19. data/lib/iruby/input/checkbox.rb +3 -3
  20. data/lib/iruby/input/date.rb +3 -3
  21. data/lib/iruby/input/field.rb +2 -2
  22. data/lib/iruby/input/file.rb +3 -3
  23. data/lib/iruby/input/form.rb +6 -6
  24. data/lib/iruby/input/label.rb +4 -4
  25. data/lib/iruby/input/multiple.rb +10 -10
  26. data/lib/iruby/input/popup.rb +2 -2
  27. data/lib/iruby/input/radio.rb +6 -6
  28. data/lib/iruby/input/select.rb +8 -8
  29. data/lib/iruby/input/textarea.rb +1 -1
  30. data/lib/iruby/input/widget.rb +2 -2
  31. data/lib/iruby/jupyter.rb +1 -0
  32. data/lib/iruby/kernel.rb +18 -13
  33. data/lib/iruby/ostream.rb +22 -10
  34. data/lib/iruby/session_adapter.rb +1 -3
  35. data/lib/iruby/session_adapter/pyzmq_adapter.rb +11 -10
  36. data/lib/iruby/utils.rb +4 -0
  37. data/lib/iruby/version.rb +1 -1
  38. data/run-test.sh +1 -1
  39. data/test/helper.rb +90 -0
  40. data/test/integration_test.rb +1 -2
  41. data/test/iruby/backend_test.rb +37 -0
  42. data/test/iruby/command_test.rb +0 -1
  43. data/test/iruby/jupyter_test.rb +0 -1
  44. data/test/iruby/mime_test.rb +32 -0
  45. data/test/iruby/multi_logger_test.rb +0 -1
  46. data/test/iruby/session_adapter/cztop_adapter_test.rb +1 -1
  47. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +1 -1
  48. data/test/iruby/session_adapter/session_adapter_test_base.rb +1 -3
  49. data/test/iruby/session_adapter_test.rb +42 -67
  50. data/test/iruby/session_test.rb +9 -15
  51. data/test/run-test.rb +18 -0
  52. metadata +68 -64
  53. data/.travis.yml +0 -41
  54. data/CONTRIBUTORS +0 -19
  55. data/lib/iruby/session/rbczmq.rb +0 -72
  56. data/lib/iruby/session_adapter/rbczmq_adapter.rb +0 -33
  57. data/test/iruby/session_adapter/rbczmq_adapter_test.rb +0 -37
  58. data/test/test_helper.rb +0 -48
@@ -4,13 +4,13 @@ module IRuby
4
4
  needs label: nil, icon: nil
5
5
 
6
6
  def widget_label
7
- div class: 'iruby-label input-group' do
8
- span class: 'input-group-addon' do
7
+ div class: 'iruby-label input-group' do
8
+ span class: 'input-group-addon' do
9
9
  text @label || to_label(@key)
10
10
  end
11
-
11
+
12
12
  yield
13
-
13
+
14
14
  if @icon
15
15
  span @icon, class: "input-group-addon"
16
16
  end
@@ -9,7 +9,7 @@ module IRuby
9
9
 
10
10
  params[:key] = unique_key(key)
11
11
  params[:options] = args
12
-
12
+
13
13
  params[:default] = case params[:default]
14
14
  when false, nil
15
15
  []
@@ -24,12 +24,12 @@ module IRuby
24
24
 
25
25
  def widget_css
26
26
  <<-CSS
27
- .iruby-multiple {
27
+ .iruby-multiple {
28
28
  display: table;
29
29
  min-width: 25%;
30
30
  }
31
- .form-control.iruby-multiple-container {
32
- display: table;
31
+ .form-control.iruby-multiple-container {
32
+ display: table;
33
33
  }
34
34
  CSS
35
35
  end
@@ -54,17 +54,17 @@ module IRuby
54
54
  end
55
55
 
56
56
  def widget_html
57
- widget_label do
58
- div class: 'form-control iruby-multiple-container' do
57
+ widget_label do
58
+ div class: 'form-control iruby-multiple-container' do
59
59
  params = {
60
60
  size: @size,
61
61
  multiple: true,
62
- class: 'iruby-multiple',
62
+ class: 'iruby-multiple',
63
63
  :'data-iruby-key' => @key
64
64
  }
65
-
66
- select **params do
67
- @options.each do |o|
65
+
66
+ select **params do
67
+ @options.each do |o|
68
68
  option o, selected: @default.include?(o)
69
69
  end
70
70
  end
@@ -21,11 +21,11 @@ module IRuby
21
21
  #{widget_join :widget_js, @form, *@buttons}
22
22
 
23
23
  var popup = $(this);
24
-
24
+
25
25
  $('#iruby-form').submit(function() {
26
26
  popup.modal('hide');
27
27
  });
28
-
28
+
29
29
  Jupyter.notebook.keyboard_manager.disable();
30
30
  }
31
31
  });
@@ -6,7 +6,7 @@ module IRuby
6
6
  builder :radio do |*args, **params|
7
7
  key = :radio
8
8
  key, *args = args if args.first.is_a? Symbol
9
-
9
+
10
10
  params[:key] = unique_key(key)
11
11
  params[:options] = args
12
12
  params[:default] ||= false
@@ -24,7 +24,7 @@ module IRuby
24
24
  <<-JS
25
25
  $('.iruby-radio input').change(function(){
26
26
  var parent = $(this).closest('.iruby-radio');
27
- $(parent).data('iruby-value',
27
+ $(parent).data('iruby-value',
28
28
  $(parent).find(':checked').val()
29
29
  );
30
30
  });
@@ -38,13 +38,13 @@ module IRuby
38
38
  :'data-iruby-value' => @options.first,
39
39
  class: 'iruby-radio form-control'
40
40
  }
41
- widget_label do
41
+ widget_label do
42
42
  div **params do
43
43
  @options.each do |option|
44
- label class: 'radio-inline' do
44
+ label class: 'radio-inline' do
45
45
  input(
46
- name: @key,
47
- value: option,
46
+ name: @key,
47
+ value: option,
48
48
  type: 'radio',
49
49
  checked: @default == option
50
50
  )
@@ -20,7 +20,7 @@ module IRuby
20
20
 
21
21
  def widget_css
22
22
  <<-CSS
23
- .iruby-select {
23
+ .iruby-select {
24
24
  min-width: 25%;
25
25
  margin-left: 0 !important;
26
26
  }
@@ -30,7 +30,7 @@ module IRuby
30
30
  def widget_js
31
31
  <<-JS
32
32
  $('.iruby-select').change(function(){
33
- $(this).data('iruby-value',
33
+ $(this).data('iruby-value',
34
34
  $(this).find('option:selected').text()
35
35
  );
36
36
  });
@@ -38,16 +38,16 @@ module IRuby
38
38
  end
39
39
 
40
40
  def widget_html
41
- widget_label do
42
- div class: 'form-control' do
41
+ widget_label do
42
+ div class: 'form-control' do
43
43
  params = {
44
- class: 'iruby-select',
44
+ class: 'iruby-select',
45
45
  :'data-iruby-key' => @key,
46
46
  :'data-iruby-value' => @default
47
47
  }
48
-
49
- select **params do
50
- @options.each do |o|
48
+
49
+ select **params do
50
+ @options.each do |o|
51
51
  option o, selected: @default == o
52
52
  end
53
53
  end
@@ -9,7 +9,7 @@ module IRuby
9
9
  end
10
10
 
11
11
  def widget_html
12
- widget_label do
12
+ widget_label do
13
13
  textarea(
14
14
  @default,
15
15
  rows: @rows,
@@ -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")
data/lib/iruby/jupyter.rb CHANGED
@@ -31,6 +31,7 @@ module IRuby
31
31
 
32
32
  # returns %APPDATA%
33
33
  def windows_user_appdata
34
+ require 'fiddle/import'
34
35
  check_windows
35
36
  path = Fiddle::Pointer.malloc(2 * 300) # uint16_t[300]
36
37
  csidl_appdata = 0x001a
data/lib/iruby/kernel.rb CHANGED
@@ -59,14 +59,21 @@ module IRuby
59
59
  @session.send(:reply, :kernel_info_reply,
60
60
  protocol_version: '5.0',
61
61
  implementation: 'iruby',
62
- banner: "IRuby #{IRuby::VERSION} (with #{@session.description})",
63
62
  implementation_version: IRuby::VERSION,
64
63
  language_info: {
65
64
  name: 'ruby',
66
65
  version: RUBY_VERSION,
67
66
  mimetype: 'application/x-ruby',
68
67
  file_extension: '.rb'
69
- })
68
+ },
69
+ banner: "IRuby #{IRuby::VERSION} (with #{@session.description})",
70
+ help_links: [
71
+ {
72
+ text: "Ruby Documentation",
73
+ url: "https://ruby-doc.org/"
74
+ }
75
+ ],
76
+ status: :ok)
70
77
  end
71
78
 
72
79
  def send_status(status)
@@ -94,6 +101,7 @@ module IRuby
94
101
  content = error_content(e)
95
102
  @session.send(:publish, :error, content)
96
103
  content[:status] = :error
104
+ content[:execution_count] = @execution_count
97
105
  end
98
106
  @session.send(:reply, :execute_reply, content)
99
107
  @session.send(:publish, :execute_result,
@@ -103,9 +111,11 @@ module IRuby
103
111
  end
104
112
 
105
113
  def error_content(e)
114
+ rindex = e.backtrace.rindex{|line| line.start_with?(@backend.eval_path)} || -1
115
+ backtrace = SyntaxError === e && rindex == -1 ? [] : e.backtrace[0..rindex]
106
116
  { ename: e.class.to_s,
107
117
  evalue: e.message,
108
- traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *e.backtrace] }
118
+ traceback: ["#{RED}#{e.class}#{RESET}: #{e.message}", *backtrace] }
109
119
  end
110
120
 
111
121
  def is_complete_request(msg)
@@ -123,9 +133,10 @@ module IRuby
123
133
  end
124
134
  @session.send(:reply, :complete_reply,
125
135
  matches: @backend.complete(code),
126
- status: :ok,
127
136
  cursor_start: start.to_i,
128
- cursor_end: msg[:content]['cursor_pos'])
137
+ cursor_end: msg[:content]['cursor_pos'],
138
+ metadata: {},
139
+ status: :ok)
129
140
  end
130
141
 
131
142
  def connect_request(msg)
@@ -144,14 +155,8 @@ module IRuby
144
155
  end
145
156
 
146
157
  def inspect_request(msg)
147
- result = @backend.eval(msg[:content]['code'])
148
- @session.send(:reply, :inspect_reply,
149
- status: :ok,
150
- data: Display.display(result),
151
- metadata: {})
152
- rescue Exception => e
153
- IRuby.logger.warn "Inspection error: #{e.message}\n#{e.backtrace.join("\n")}"
154
- @session.send(:reply, :inspect_reply, status: :error)
158
+ # not yet implemented. See (#119).
159
+ @session.send(:reply, :inspect_reply, status: :ok, found: false, data: {}, metadata: {})
155
160
  end
156
161
 
157
162
  def comm_open(msg)
data/lib/iruby/ostream.rb CHANGED
@@ -25,26 +25,38 @@ module IRuby
25
25
  alias_method :next, :read
26
26
  alias_method :readline, :read
27
27
 
28
- def write(s)
29
- raise 'I/O operation on closed file' unless @session
30
- @session.send(:publish, :stream, name: @name, text: s.to_s)
31
- nil
28
+ def write(*obj)
29
+ str = build_string { |sio| sio.write(*obj) }
30
+ session_send(str)
32
31
  end
33
32
  alias_method :<<, :write
34
33
  alias_method :print, :write
35
34
 
36
- def printf(*fmt)
37
- write sprintf(*fmt)
35
+ def printf(format, *obj)
36
+ str = build_string { |sio| sio.printf(format, *obj) }
37
+ session_send(str)
38
38
  end
39
39
 
40
- def puts(*lines)
41
- lines = [''] if lines.empty?
42
- lines.each { |s| write("#{s}\n")}
43
- nil
40
+ def puts(*obj)
41
+ str = build_string { |sio| sio.puts(*obj) }
42
+ session_send(str)
44
43
  end
45
44
 
46
45
  def writelines(lines)
47
46
  lines.each { |s| write(s) }
48
47
  end
48
+
49
+ private
50
+
51
+ def build_string
52
+ StringIO.open { |sio| yield(sio); sio.string }
53
+ end
54
+
55
+ def session_send(str)
56
+ raise 'I/O operation on closed file' unless @session
57
+
58
+ @session.send(:publish, :stream, name: @name, text: str)
59
+ nil
60
+ end
49
61
  end
50
62
  end
@@ -36,15 +36,13 @@ module IRuby
36
36
 
37
37
  require_relative 'session_adapter/ffirzmq_adapter'
38
38
  require_relative 'session_adapter/cztop_adapter'
39
- require_relative 'session_adapter/rbczmq_adapter'
40
39
  require_relative 'session_adapter/pyzmq_adapter'
41
40
 
42
41
  def self.select_adapter_class(name=nil)
43
42
  classes = {
44
43
  'ffi-rzmq' => SessionAdapter::FfirzmqAdapter,
45
44
  'cztop' => SessionAdapter::CztopAdapter,
46
- 'rbczmq' => SessionAdapter::RbczmqAdapter,
47
- 'pyzmq' => SessionAdapter::PyzmqAdapter
45
+ # 'pyzmq' => SessionAdapter::PyzmqAdapter
48
46
  }
49
47
  if (name ||= ENV.fetch('IRUBY_SESSION_ADAPTER', nil))
50
48
  cls = classes[name]
@@ -1,14 +1,19 @@
1
1
  module IRuby
2
2
  module SessionAdapter
3
3
  class PyzmqAdapter < BaseAdapter
4
- def self.load_requirements
5
- require 'pycall'
6
- @zmq = PyCall.import_module('zmq')
7
- rescue PyCall::PyError => error
8
- raise LoadError, error.message
9
- end
10
4
 
11
5
  class << self
6
+ def load_requirements
7
+ require 'pycall'
8
+ import_pyzmq
9
+ end
10
+
11
+ def import_pyzmq
12
+ @zmq = PyCall.import_module('zmq')
13
+ rescue PyCall::PyError => error
14
+ raise LoadError, error.message
15
+ end
16
+
12
17
  attr_reader :zmq
13
18
  end
14
19
 
@@ -20,10 +25,6 @@ module IRuby
20
25
  make_socket(:PUB, protocol, host, port)
21
26
  end
22
27
 
23
- def make_pub_socket(protocol, host, port)
24
- make_socket(:REP, protocol, host, port)
25
- end
26
-
27
28
  def heartbeat_loop(sock)
28
29
  PyCall.sys.path.append(File.expand_path('../pyzmq', __FILE__))
29
30
  heartbeat = PyCall.import_module('iruby.heartbeat')
data/lib/iruby/utils.rb CHANGED
@@ -10,6 +10,10 @@ module IRuby
10
10
  metadata: {}) unless obj.nil?
11
11
  end
12
12
 
13
+ def clear_output(wait=false)
14
+ Display.clear_output(wait)
15
+ end
16
+
13
17
  def table(s, **options)
14
18
  html(HTML.table(s, options))
15
19
  end
data/lib/iruby/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module IRuby
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.0'
3
3
  end
data/run-test.sh CHANGED
@@ -4,7 +4,7 @@ set -ex
4
4
 
5
5
  export PYTHON=python3
6
6
 
7
- ADAPTERS="cztop rbczmq ffi-rzmq pyzmq"
7
+ ADAPTERS="cztop ffi-rzmq pyzmq"
8
8
 
9
9
  for adapter in $ADAPTERS; do
10
10
  export IRUBY_TEST_SESSION_ADAPTER_NAME=$adapter
data/test/helper.rb ADDED
@@ -0,0 +1,90 @@
1
+ require "iruby"
2
+ require "test/unit"
3
+ require "test/unit/rr"
4
+ require "tmpdir"
5
+
6
+ module IRubyTest
7
+ class TestBase < Test::Unit::TestCase
8
+ def assert_output(stdout=nil, stderr=nil)
9
+ flunk "assert_output requires a block to capture output." unless block_given?
10
+
11
+ out, err = capture_io do
12
+ yield
13
+ end
14
+
15
+ y = check_assert_output_result(stderr, err, "stderr")
16
+ x = check_assert_output_result(stdout, out, "stdout")
17
+
18
+ (!stdout || x) && (!stderr || y)
19
+ end
20
+
21
+ private
22
+
23
+ def capture_io
24
+ captured_stdout = StringIO.new
25
+ captured_stderr = StringIO.new
26
+
27
+ orig_stdout, $stdout = $stdout, captured_stdout
28
+ orig_stderr, $stderr = $stderr, captured_stderr
29
+
30
+ yield
31
+
32
+ return captured_stdout.string, captured_stderr.string
33
+ ensure
34
+ $stdout = orig_stdout
35
+ $stderr = orig_stderr
36
+ end
37
+
38
+ def check_assert_output_result(expected, actual, name)
39
+ if expected
40
+ message = "In #{name}"
41
+ case expected
42
+ when Regexp
43
+ assert_match(expected, actual, message)
44
+ else
45
+ assert_equal(expected, actual, message)
46
+ end
47
+ end
48
+ end
49
+
50
+ def ignore_warning
51
+ saved, $VERBOSE = $VERBOSE , nil
52
+ yield
53
+ ensure
54
+ $VERBOSE = saved
55
+ end
56
+
57
+ def with_env(env)
58
+ keys = env.keys
59
+ saved_values = ENV.values_at(*keys)
60
+ ENV.update(env)
61
+ yield
62
+ ensure
63
+ if keys && saved_values
64
+ keys.zip(saved_values) do |k, v|
65
+ ENV[k] = v
66
+ end
67
+ end
68
+ end
69
+
70
+ def windows_only
71
+ omit('windows only test') unless windows?
72
+ end
73
+
74
+ def apple_only
75
+ omit('apple only test') unless windows?
76
+ end
77
+
78
+ def unix_only
79
+ omit('unix only test') if windows? || apple?
80
+ end
81
+
82
+ def windows?
83
+ /mingw|mswin/ =~ RUBY_PLATFORM
84
+ end
85
+
86
+ def apple?
87
+ /darwin/ =~ RUBY_PLATFORM
88
+ end
89
+ end
90
+ end