iruby 0.2.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +62 -0
  3. data/CHANGES +62 -0
  4. data/Gemfile +3 -1
  5. data/LICENSE +1 -1
  6. data/README.md +148 -27
  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 +19 -3
  15. data/lib/iruby/backend.rb +22 -2
  16. data/lib/iruby/command.rb +76 -13
  17. data/lib/iruby/display.rb +69 -39
  18. data/lib/iruby/formatter.rb +5 -4
  19. data/lib/iruby/input.rb +41 -0
  20. data/lib/iruby/input/README.ipynb +502 -0
  21. data/lib/iruby/input/README.md +299 -0
  22. data/lib/iruby/input/autoload.rb +25 -0
  23. data/lib/iruby/input/builder.rb +67 -0
  24. data/lib/iruby/input/button.rb +47 -0
  25. data/lib/iruby/input/cancel.rb +32 -0
  26. data/lib/iruby/input/checkbox.rb +74 -0
  27. data/lib/iruby/input/date.rb +37 -0
  28. data/lib/iruby/input/field.rb +31 -0
  29. data/lib/iruby/input/file.rb +57 -0
  30. data/lib/iruby/input/form.rb +77 -0
  31. data/lib/iruby/input/label.rb +27 -0
  32. data/lib/iruby/input/multiple.rb +76 -0
  33. data/lib/iruby/input/popup.rb +41 -0
  34. data/lib/iruby/input/radio.rb +59 -0
  35. data/lib/iruby/input/select.rb +59 -0
  36. data/lib/iruby/input/textarea.rb +23 -0
  37. data/lib/iruby/input/widget.rb +34 -0
  38. data/lib/iruby/jupyter.rb +77 -0
  39. data/lib/iruby/kernel.rb +67 -22
  40. data/lib/iruby/ostream.rb +24 -8
  41. data/lib/iruby/session.rb +85 -67
  42. data/lib/iruby/session/cztop.rb +70 -0
  43. data/lib/iruby/session/ffi_rzmq.rb +87 -0
  44. data/lib/iruby/session/mixin.rb +47 -0
  45. data/lib/iruby/session_adapter.rb +66 -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/utils.rb +5 -2
  50. data/lib/iruby/version.rb +1 -1
  51. data/run-test.sh +12 -0
  52. data/tasks/ci.rake +65 -0
  53. data/test/helper.rb +90 -0
  54. data/test/integration_test.rb +22 -11
  55. data/test/iruby/backend_test.rb +37 -0
  56. data/test/iruby/command_test.rb +207 -0
  57. data/test/iruby/jupyter_test.rb +27 -0
  58. data/test/iruby/mime_test.rb +32 -0
  59. data/test/iruby/multi_logger_test.rb +1 -2
  60. data/test/iruby/session_adapter/cztop_adapter_test.rb +20 -0
  61. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +20 -0
  62. data/test/iruby/session_adapter/session_adapter_test_base.rb +27 -0
  63. data/test/iruby/session_adapter_test.rb +91 -0
  64. data/test/iruby/session_test.rb +47 -0
  65. data/test/run-test.rb +18 -0
  66. metadata +130 -46
  67. data/.travis.yml +0 -16
  68. data/CONTRIBUTORS +0 -19
  69. data/test/test_helper.rb +0 -5
@@ -0,0 +1,7 @@
1
+ FROM iruby-test-base:ruby-<%= ruby_version %>
2
+
3
+ RUN gem install cztop
4
+ RUN mkdir -p /iruby
5
+ ADD . /iruby
6
+ WORKDIR /iruby
7
+ RUN bundle install
@@ -0,0 +1 @@
1
+ jupyter-console>=6.0.0
data/docker/setup.sh ADDED
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+
3
+ set -ex
4
+
5
+ apt-get update
6
+ apt-get install -y --no-install-recommends \
7
+ libczmq-dev \
8
+ python3 \
9
+ python3-pip \
10
+ python3-setuptools \
11
+ python3-wheel
12
+
13
+ cd /tmp/iruby
14
+ bundle install --with test --without plot
15
+ pip3 install jupyter
data/docker/test.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+
3
+ set -ex
4
+
5
+ cd /tmp/iruby
6
+ bundle install --with test --without plot
7
+ bundle exec rake test
data/iruby.gemspec CHANGED
@@ -1,34 +1,30 @@
1
- # coding: utf-8
2
1
  require_relative 'lib/iruby/version'
3
- require 'date'
4
2
 
5
3
  Gem::Specification.new do |s|
6
4
  s.name = 'iruby'
7
- s.date = Date.today.to_s
8
5
  s.version = IRuby::VERSION
9
6
  s.authors = ['Daniel Mendler', 'The SciRuby developers']
10
7
  s.email = ['mail@daniel-mendler.de']
11
- s.summary = 'Ruby Kernel for Jupyter/IPython'
12
- s.description = 'A Ruby kernel for Jupyter/IPython frontends (e.g. notebook). Try it at try.jupyter.org.'
8
+ s.summary = 'Ruby Kernel for Jupyter'
9
+ s.description = 'A Ruby kernel for Jupyter environment. Try it at try.jupyter.org.'
13
10
  s.homepage = 'https://github.com/SciRuby/iruby'
14
11
  s.license = 'MIT'
15
12
 
16
- s.files = `git ls-files`.split($/)
13
+ s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
14
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
15
  s.test_files = s.files.grep(%r{^test/})
19
- s.require_paths = %w(lib)
16
+ s.require_paths = %w[lib]
20
17
 
21
- m = "Consider installing the optional dependencies to get additional functionality:\n"
22
- File.read('Gemfile').scan(/gem\s+'(.*?)'/) { m << " * #{$1}\n" }
23
- s.post_install_message = m << "\n"
18
+ s.required_ruby_version = '>= 2.3.0'
24
19
 
25
- s.required_ruby_version = '>= 2.1.0'
20
+ s.add_dependency 'bond', '~> 0.5'
21
+ s.add_dependency 'data_uri', '~> 0.1'
22
+ s.add_dependency 'ffi-rzmq'
23
+ s.add_dependency 'mime-types', '>= 3.3.1'
24
+ s.add_dependency 'multi_json', '~> 1.11'
26
25
 
27
- s.add_development_dependency 'rake', '~> 10.4'
28
- s.add_development_dependency 'minitest', '~> 5.6'
29
-
30
- s.add_runtime_dependency 'bond', '~> 0.5'
31
- s.add_runtime_dependency 'rbczmq', '~> 1.7'
32
- s.add_runtime_dependency 'multi_json', '~> 1.11'
33
- s.add_runtime_dependency 'mimemagic', '~> 0.3'
26
+ s.add_development_dependency 'pycall', '>= 1.2.1'
27
+ s.add_development_dependency 'rake'
28
+ s.add_development_dependency 'test-unit'
29
+ s.add_development_dependency 'test-unit-rr'
34
30
  end
data/lib/iruby.rb CHANGED
@@ -1,16 +1,32 @@
1
- require 'rbczmq'
2
- require 'mimemagic'
1
+ require 'mime/types'
3
2
  require 'multi_json'
4
3
  require 'securerandom'
5
4
  require 'openssl'
6
5
  require 'tempfile'
7
6
  require 'set'
7
+
8
8
  require 'iruby/version'
9
+ require 'iruby/jupyter'
9
10
  require 'iruby/kernel'
10
11
  require 'iruby/backend'
11
- require 'iruby/session'
12
12
  require 'iruby/ostream'
13
+ require 'iruby/input'
13
14
  require 'iruby/formatter'
14
15
  require 'iruby/utils'
15
16
  require 'iruby/display'
16
17
  require 'iruby/comm'
18
+
19
+ if ENV.fetch('IRUBY_OLD_SESSION', false)
20
+ require 'iruby/session/mixin'
21
+ begin
22
+ require 'iruby/session/ffi_rzmq'
23
+ rescue LoadError
24
+ begin
25
+ require 'iruby/session/cztop'
26
+ rescue LoadError
27
+ STDERR.puts "Please install ffi-rzmq or cztop before running iruby. See README."
28
+ end
29
+ end
30
+ else
31
+ require 'iruby/session'
32
+ end
data/lib/iruby/backend.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module IRuby
2
2
  In, Out = [nil], [nil]
3
- ::In, ::Out = In, Out
4
3
 
5
4
  module History
6
5
  def eval(code, store_history)
@@ -33,15 +32,17 @@ module IRuby
33
32
  end
34
33
 
35
34
  class PlainBackend
35
+ attr_reader :eval_path
36
36
  prepend History
37
37
 
38
38
  def initialize
39
39
  require 'bond'
40
40
  Bond.start(debug: true)
41
+ @eval_path = '(iruby)'
41
42
  end
42
43
 
43
44
  def eval(code, store_history)
44
- TOPLEVEL_BINDING.eval(code)
45
+ TOPLEVEL_BINDING.eval(code, @eval_path, 1)
45
46
  end
46
47
 
47
48
  def complete(code)
@@ -50,22 +51,41 @@ module IRuby
50
51
  end
51
52
 
52
53
  class PryBackend
54
+ attr_reader :eval_path
53
55
  prepend History
54
56
 
55
57
  def initialize
56
58
  require 'pry'
59
+ Pry.memory_size = 3
57
60
  Pry.pager = false # Don't use the pager
58
61
  Pry.print = proc {|output, value|} # No result printing
59
62
  Pry.exception_handler = proc {|output, exception, _| }
63
+ @eval_path = Pry.eval_path
60
64
  reset
61
65
  end
62
66
 
63
67
  def eval(code, store_history)
68
+ Pry.current_line = 1
64
69
  @pry.last_result = nil
65
70
  unless @pry.eval(code)
66
71
  reset
67
72
  raise SystemExit
68
73
  end
74
+
75
+ # Pry::Code.complete_expression? return false
76
+ if !@pry.eval_string.empty?
77
+ syntax_error = @pry.eval_string
78
+ @pry.reset_eval_string
79
+ @pry.evaluate_ruby(syntax_error)
80
+
81
+ # Pry::Code.complete_expression? raise SyntaxError
82
+ # evaluate again for current line number
83
+ elsif @pry.last_result_is_exception? &&
84
+ @pry.last_exception.is_a?(SyntaxError) &&
85
+ @pry.last_exception.is_a?(Pry::UserError)
86
+ @pry.evaluate_ruby(code)
87
+ end
88
+
69
89
  raise @pry.last_exception if @pry.last_result_is_exception?
70
90
  @pry.push_initial_binding unless @pry.current_binding # ensure that we have a binding
71
91
  @pry.last_result
data/lib/iruby/command.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'iruby/jupyter'
2
+
1
3
  require 'fileutils'
2
4
  require 'multi_json'
3
5
 
@@ -6,15 +8,18 @@ module IRuby
6
8
  def initialize(args)
7
9
  @args = args
8
10
 
9
- ipython_dir = ENV['IPYTHONDIR'] || '~/.ipython'
10
- @args.each do |arg|
11
- ipython_dir = $1 if arg =~ /\A--ipython-dir=(.*)\Z/
12
- end
13
- @kernel_dir = File.join(File.expand_path(ipython_dir), 'kernels', 'ruby')
14
- @kernel_file = File.join(@kernel_dir, 'kernel.json')
11
+ @ipython_dir = File.expand_path("~/.ipython")
12
+ @kernel_dir = resolve_kernelspec_dir.freeze
13
+ @kernel_file = File.join(@kernel_dir, 'kernel.json').freeze
15
14
  @iruby_path = File.expand_path $0
16
15
  end
17
16
 
17
+ attr_reader :ipython_dir, :kernel_dir, :kernel_file
18
+
19
+ def ipython_kernel_dir
20
+ File.join(File.expand_path(@ipython_dir), 'kernels', 'ruby')
21
+ end
22
+
18
23
  def run
19
24
  case @args.first
20
25
  when 'version', '-v', '--version'
@@ -23,11 +28,12 @@ module IRuby
23
28
  when 'help', '-h', '--help'
24
29
  print_help
25
30
  when 'register'
26
- if registered_iruby_path && !@args.include?('--force')
31
+ force_p = @args.include?('--force')
32
+ if registered_iruby_path && !force_p
27
33
  STDERR.puts "#{@kernel_file} already exists!\nUse --force to force a register."
28
34
  exit 1
29
35
  end
30
- register_kernel
36
+ register_kernel(force_p)
31
37
  when 'unregister'
32
38
  unregister_kernel
33
39
  when 'kernel'
@@ -39,6 +45,38 @@ module IRuby
39
45
 
40
46
  private
41
47
 
48
+ def resolve_kernelspec_dir
49
+ if ENV.has_key?('JUPYTER_DATA_DIR')
50
+ if ENV.has_key?('IPYTHONDIR')
51
+ warn 'both JUPYTER_DATA_DIR and IPYTHONDIR are supplied; IPYTHONDIR is ignored.'
52
+ end
53
+ if @args.find {|x| /\A--ipython-dir=/ =~ x }
54
+ warn 'both JUPYTER_DATA_DIR and --ipython-dir are supplied; --ipython-dir is ignored.'
55
+ end
56
+ jupyter_data_dir = ENV['JUPYTER_DATA_DIR']
57
+ return File.join(jupyter_data_dir, 'kernels', 'ruby')
58
+ end
59
+
60
+ if ENV.has_key?('IPYTHONDIR')
61
+ warn 'IPYTHONDIR is deprecated. Use JUPYTER_DATA_DIR instead.'
62
+ ipython_dir = ENV['IPYTHONDIR']
63
+ end
64
+
65
+ @args.each do |arg|
66
+ next unless /\A--ipython-dir=(.*)\Z/ =~ arg
67
+ ipython_dir = Regexp.last_match[1]
68
+ warn '--ipython-dir is deprecated. Use JUPYTER_DATA_DIR environment variable instead.'
69
+ break
70
+ end
71
+
72
+ if ipython_dir
73
+ @ipython_dir = ipython_dir
74
+ ipython_kernel_dir
75
+ else
76
+ File.join(Jupyter.kernelspec_dir, 'ruby')
77
+ end
78
+ end
79
+
42
80
  def print_help
43
81
  puts %{
44
82
  Usage:
@@ -56,6 +94,8 @@ Try `ipython help` for more information.
56
94
  def run_kernel
57
95
  require 'iruby/logger'
58
96
  IRuby.logger = MultiLogger.new(*Logger.new(STDOUT))
97
+ STDOUT.sync = true # FIXME: This can make the integration test.
98
+
59
99
  @args.reject! {|arg| arg =~ /\A--log=(.*)\Z/ && IRuby.logger.loggers << Logger.new($1) }
60
100
  IRuby.logger.level = @args.delete('--debug') ? Logger::DEBUG : Logger::INFO
61
101
 
@@ -64,7 +104,7 @@ Try `ipython help` for more information.
64
104
  Dir.chdir(working_dir) if working_dir
65
105
 
66
106
  require boot_file if boot_file
67
- check_bundler {|e| IRuby.logger.warn "Could not load bundler: #{e.message}\n#{e.backtrace.join("\n")}" }
107
+ check_bundler {|e| IRuby.logger.warn "Could not load bundler: #{e.message}" }
68
108
 
69
109
  require 'iruby'
70
110
  Kernel.new(config_file).run
@@ -95,7 +135,7 @@ Try `ipython help` for more information.
95
135
  end
96
136
 
97
137
  def check_registered_kernel
98
- if kernel = registered_iruby_path
138
+ if (kernel = registered_iruby_path)
99
139
  STDERR.puts "#{@iruby_path} differs from registered path #{registered_iruby_path}.
100
140
  This might not work. Run 'iruby register --force' to fix it." if @iruby_path != kernel
101
141
  else
@@ -106,20 +146,39 @@ This might not work. Run 'iruby register --force' to fix it." if @iruby_path !=
106
146
  def check_bundler
107
147
  require 'bundler'
108
148
  raise %q{iruby is missing from Gemfile. This might not work.
109
- Add `gem 'iruby'` to your Gemfile to fix it.} unless Bundler.definition.dependencies.any? {|s| s.name == 'iruby' }
149
+ Add `gem 'iruby'` to your Gemfile to fix it.} unless Bundler.definition.specs.any? {|s| s.name == 'iruby' }
110
150
  Bundler.setup
111
151
  rescue LoadError
112
152
  rescue Exception => e
113
153
  yield(e)
114
154
  end
115
155
 
116
- def register_kernel
156
+ def register_kernel(force_p=false)
157
+ if force_p
158
+ unregister_kernel_in_ipython_dir
159
+ else
160
+ return unless check_existing_kernel_in_ipython_dir
161
+ end
117
162
  FileUtils.mkpath(@kernel_dir)
118
- File.write(@kernel_file, MultiJson.dump(argv: [ @iruby_path, 'kernel', '{connection_file}' ],
163
+ unless RUBY_PLATFORM =~ /mswin(?!ce)|mingw|cygwin/
164
+ File.write(@kernel_file, MultiJson.dump(argv: [ @iruby_path, 'kernel', '{connection_file}' ],
119
165
  display_name: "Ruby #{RUBY_VERSION}", language: 'ruby'))
166
+ else
167
+ ruby_path, iruby_path = [RbConfig.ruby, @iruby_path].map{|path| path.gsub('/', '\\\\')}
168
+ File.write(@kernel_file, MultiJson.dump(argv: [ ruby_path, iruby_path, 'kernel', '{connection_file}' ],
169
+ display_name: "Ruby #{RUBY_VERSION}", language: 'ruby'))
170
+ end
171
+
120
172
  FileUtils.copy(Dir[File.join(__dir__, 'assets', '*')], @kernel_dir) rescue nil
121
173
  end
122
174
 
175
+ def check_existing_kernel_in_ipython_dir
176
+ return true unless File.file?(File.join(ipython_kernel_dir, 'kernel.json'))
177
+ warn "IRuby kernel file already exists in the deprecated IPython's data directory."
178
+ warn "Using --force, you can replace the old kernel file with the new one in Jupyter's data directory."
179
+ false
180
+ end
181
+
123
182
  def registered_iruby_path
124
183
  File.exist?(@kernel_file) && MultiJson.load(File.read(@kernel_file))['argv'].first
125
184
  end
@@ -127,5 +186,9 @@ Add `gem 'iruby'` to your Gemfile to fix it.} unless Bundler.definition.dependen
127
186
  def unregister_kernel
128
187
  FileUtils.rm_rf(@kernel_dir)
129
188
  end
189
+
190
+ def unregister_kernel_in_ipython_dir
191
+ FileUtils.rm_rf(ipython_kernel_dir)
192
+ end
130
193
  end
131
194
  end
data/lib/iruby/display.rb CHANGED
@@ -11,7 +11,10 @@ module IRuby
11
11
  obj = obj.object
12
12
 
13
13
  fuzzy_mime = options[:format] # Treated like a fuzzy mime type
14
- raise 'Invalid argument :format' unless !fuzzy_mime || String === fuzzy_mime
14
+ unless !fuzzy_mime || String === fuzzy_mime
15
+ raise 'Invalid argument :format'
16
+ end
17
+
15
18
  if exact_mime = options[:mime]
16
19
  raise 'Invalid argument :mime' unless String === exact_mime
17
20
  raise 'Invalid mime type' unless exact_mime.include?('/')
@@ -27,28 +30,38 @@ module IRuby
27
30
 
28
31
  # As a last resort, interpret string representation of the object
29
32
  # as the given mime type.
30
- data[exact_mime] = protect(exact_mime, obj) if exact_mime && !data.any? {|m,_| exact_mime == m }
33
+ if exact_mime && data.none? { |m, _| exact_mime == m }
34
+ data[exact_mime] = protect(exact_mime, obj)
35
+ end
31
36
 
32
37
  data
33
38
  end
34
39
 
40
+ def clear_output(wait = false)
41
+ IRuby::Kernel.instance.session.send(:publish, :clear_output, wait: wait)
42
+ end
43
+
35
44
  private
36
45
 
37
46
  def protect(mime, data)
38
- MimeMagic.new(mime).text? ? data.to_s : [data.to_s].pack('m0')
47
+ MIME::Type.new(mime).ascii? ? data.to_s : [data.to_s].pack('m0')
39
48
  end
40
49
 
41
50
  def render(data, obj, exact_mime, fuzzy_mime)
42
51
  # Filter matching renderer by object type
43
- renderer = Registry.renderer.select {|r| r.match?(obj) }
52
+ renderer = Registry.renderer.select { |r| r.match?(obj) }
44
53
 
45
54
  matching_renderer = nil
46
55
 
47
56
  # Find exactly matching display by exact_mime
48
- matching_renderer = renderer.find {|r| exact_mime == r.mime } if exact_mime
57
+ if exact_mime
58
+ matching_renderer = renderer.find { |r| exact_mime == r.mime }
59
+ end
49
60
 
50
61
  # Find fuzzy matching display by fuzzy_mime
51
- matching_renderer ||= renderer.find {|r| r.mime && r.mime.include?(fuzzy_mime) } if fuzzy_mime
62
+ if fuzzy_mime
63
+ matching_renderer ||= renderer.find { |r| r.mime&.include?(fuzzy_mime) }
64
+ end
52
65
 
53
66
  renderer.unshift matching_renderer if matching_renderer
54
67
 
@@ -69,7 +82,8 @@ module IRuby
69
82
  attr_reader :object, :options
70
83
 
71
84
  def initialize(object, options)
72
- @object, @options = object, options
85
+ @object = object
86
+ @options = options
73
87
  end
74
88
 
75
89
  class << self
@@ -87,10 +101,13 @@ module IRuby
87
101
  end
88
102
 
89
103
  class Renderer
90
- attr_reader :match, :mime, :render, :priority
104
+ attr_reader :match, :mime, :priority
91
105
 
92
106
  def initialize(match, mime, render, priority)
93
- @match, @mime, @render, @priority = match, mime, render, priority
107
+ @match = match
108
+ @mime = mime
109
+ @render = render
110
+ @priority = priority
94
111
  end
95
112
 
96
113
  def match?(obj)
@@ -110,7 +127,7 @@ module IRuby
110
127
  @renderer ||= []
111
128
  end
112
129
 
113
- SUPPORTED_MIMES = %w(
130
+ SUPPORTED_MIMES = %w[
114
131
  text/plain
115
132
  text/html
116
133
  text/latex
@@ -118,7 +135,8 @@ module IRuby
118
135
  application/javascript
119
136
  image/png
120
137
  image/jpeg
121
- image/svg+xml)
138
+ image/svg+xml
139
+ ]
122
140
 
123
141
  def match(&block)
124
142
  @match = block
@@ -127,7 +145,7 @@ module IRuby
127
145
  end
128
146
 
129
147
  def respond_to(name)
130
- match {|obj| obj.respond_to?(name) }
148
+ match { |obj| obj.respond_to?(name) }
131
149
  end
132
150
 
133
151
  def type(&block)
@@ -149,7 +167,7 @@ module IRuby
149
167
 
150
168
  def format(mime = nil, &block)
151
169
  renderer << Renderer.new(@match, mime, block, @priority)
152
- renderer.sort_by! {|r| -r.priority }
170
+ renderer.sort_by! { |r| -r.priority }
153
171
 
154
172
  # Decrease priority implicitly for all formats
155
173
  # which are added later for a type.
@@ -165,7 +183,19 @@ module IRuby
165
183
  LaTeX.vector(obj.to_a)
166
184
  end
167
185
 
186
+ type { Numo::NArray }
187
+ format 'text/plain', &:inspect
188
+ format 'text/latex' do |obj|
189
+ obj.ndim == 2 ?
190
+ LaTeX.matrix(obj, obj.shape[0], obj.shape[1]) :
191
+ LaTeX.vector(obj.to_a)
192
+ end
193
+ format 'text/html' do |obj|
194
+ HTML.table(obj.to_a)
195
+ end
196
+
168
197
  type { NArray }
198
+ format 'text/plain', &:inspect
169
199
  format 'text/latex' do |obj|
170
200
  obj.dim == 2 ?
171
201
  LaTeX.matrix(obj.transpose(1, 0), obj.shape[1], obj.shape[0]) :
@@ -227,37 +257,41 @@ module IRuby
227
257
 
228
258
  match do |obj|
229
259
  defined?(Magick::Image) && Magick::Image === obj ||
230
- defined?(MiniMagick::Image) && MiniMagick::Image === obj
260
+ defined?(MiniMagick::Image) && MiniMagick::Image === obj
231
261
  end
232
262
  format 'image' do |obj|
233
263
  format = obj.format || 'PNG'
234
- [format == 'PNG' ? 'image/png' : 'image/jpeg', obj.to_blob {|i| i.format = format }]
264
+ [format == 'PNG' ? 'image/png' : 'image/jpeg', obj.to_blob { |i| i.format = format }]
235
265
  end
236
266
 
237
- type { Gruff::Base }
238
- format 'image/png' do |obj|
239
- obj.to_blob
267
+ match do |obj|
268
+ defined?(Vips::Image) && Vips::Image === obj
240
269
  end
270
+ format do |obj|
271
+ # handles Vips::Error, vips_image_get: field "vips-loader" not found
272
+ loader = obj.get('vips-loader') rescue nil
273
+ if loader == 'jpegload'
274
+ ['image/jpeg', obj.write_to_buffer('.jpg')]
275
+ else
276
+ # falls back to png for other/unknown types
277
+ ['image/png', obj.write_to_buffer('.png')]
278
+ end
279
+ end
280
+
281
+ type { Gruff::Base }
282
+ format 'image/png', &:to_blob
241
283
 
242
284
  respond_to :to_html
243
- format 'text/html' do |obj|
244
- obj.to_html
245
- end
285
+ format 'text/html', &:to_html
246
286
 
247
287
  respond_to :to_latex
248
- format 'text/latex' do |obj|
249
- obj.to_latex
250
- end
288
+ format 'text/latex', &:to_latex
251
289
 
252
290
  respond_to :to_tex
253
- format 'text/latex' do |obj|
254
- obj.to_tex
255
- end
291
+ format 'text/latex', &:to_tex
256
292
 
257
293
  respond_to :to_javascript
258
- format 'text/javascript' do |obj|
259
- obj.to_javascript
260
- end
294
+ format 'text/javascript', &:to_javascript
261
295
 
262
296
  respond_to :to_svg
263
297
  format 'image/svg+xml' do |obj|
@@ -266,21 +300,17 @@ module IRuby
266
300
  end
267
301
 
268
302
  respond_to :to_iruby
269
- format do |obj|
270
- obj.to_iruby
271
- end
303
+ format(&:to_iruby)
272
304
 
273
- match {|obj| obj.respond_to?(:path) && File.readable?(obj.path) }
305
+ match { |obj| obj.respond_to?(:path) && obj.method(:path).arity == 0 && File.readable?(obj.path) }
274
306
  format do |obj|
275
- mime = MimeMagic.by_path(obj.path).to_s
307
+ mime = MIME::Types.of(obj.path).first.to_s
276
308
  [mime, File.read(obj.path)] if SUPPORTED_MIMES.include?(mime)
277
309
  end
278
310
 
279
311
  type { Object }
280
- priority -1000
281
- format 'text/plain' do |obj|
282
- obj.inspect
283
- end
312
+ priority(-1000)
313
+ format 'text/plain', &:inspect
284
314
  end
285
315
  end
286
316
  end