iruby 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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