iruby 0.2.7 → 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 (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