iruby 0.4.0 → 0.7.1

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ubuntu.yml +69 -0
  3. data/CHANGES.md +219 -0
  4. data/Gemfile +0 -2
  5. data/LICENSE +1 -1
  6. data/README.md +81 -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 +6 -6
  11. data/lib/iruby/backend.rb +38 -10
  12. data/lib/iruby/command.rb +2 -6
  13. data/lib/iruby/display.rb +216 -81
  14. data/lib/iruby/event_manager.rb +40 -0
  15. data/lib/iruby/formatter.rb +3 -3
  16. data/lib/iruby/input.rb +6 -6
  17. data/lib/iruby/input/autoload.rb +1 -1
  18. data/lib/iruby/input/builder.rb +4 -4
  19. data/lib/iruby/input/button.rb +2 -2
  20. data/lib/iruby/input/cancel.rb +1 -1
  21. data/lib/iruby/input/checkbox.rb +3 -3
  22. data/lib/iruby/input/date.rb +3 -3
  23. data/lib/iruby/input/field.rb +2 -2
  24. data/lib/iruby/input/file.rb +3 -3
  25. data/lib/iruby/input/form.rb +6 -6
  26. data/lib/iruby/input/label.rb +4 -4
  27. data/lib/iruby/input/multiple.rb +10 -10
  28. data/lib/iruby/input/popup.rb +2 -2
  29. data/lib/iruby/input/radio.rb +6 -6
  30. data/lib/iruby/input/select.rb +8 -8
  31. data/lib/iruby/input/textarea.rb +1 -1
  32. data/lib/iruby/input/widget.rb +2 -2
  33. data/lib/iruby/jupyter.rb +1 -0
  34. data/lib/iruby/kernel.rb +157 -29
  35. data/lib/iruby/ostream.rb +27 -10
  36. data/lib/iruby/session.rb +1 -0
  37. data/lib/iruby/session_adapter.rb +7 -3
  38. data/lib/iruby/session_adapter/pyzmq_adapter.rb +11 -10
  39. data/lib/iruby/session_adapter/test_adapter.rb +49 -0
  40. data/lib/iruby/utils.rb +15 -0
  41. data/lib/iruby/version.rb +1 -1
  42. data/run-test.sh +1 -1
  43. data/test/helper.rb +136 -0
  44. data/test/integration_test.rb +1 -2
  45. data/test/iruby/backend_test.rb +37 -0
  46. data/test/iruby/command_test.rb +0 -1
  47. data/test/iruby/display_test.rb +188 -0
  48. data/test/iruby/event_manager_test.rb +92 -0
  49. data/test/iruby/jupyter_test.rb +0 -1
  50. data/test/iruby/kernel_test.rb +185 -0
  51. data/test/iruby/mime_test.rb +50 -0
  52. data/test/iruby/multi_logger_test.rb +0 -4
  53. data/test/iruby/session_adapter/cztop_adapter_test.rb +1 -1
  54. data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +1 -1
  55. data/test/iruby/session_adapter/session_adapter_test_base.rb +1 -3
  56. data/test/iruby/session_adapter_test.rb +42 -67
  57. data/test/iruby/session_test.rb +10 -15
  58. data/test/run-test.rb +19 -0
  59. metadata +74 -62
  60. data/.travis.yml +0 -41
  61. data/CHANGES +0 -143
  62. data/CONTRIBUTORS +0 -19
  63. data/lib/iruby/session/rbczmq.rb +0 -72
  64. data/lib/iruby/session_adapter/rbczmq_adapter.rb +0 -33
  65. data/test/iruby/session_adapter/rbczmq_adapter_test.rb +0 -37
  66. data/test/test_helper.rb +0 -48
data/Rakefile CHANGED
@@ -1,17 +1,17 @@
1
- require 'rake/testtask'
1
+ require "bundler/gem_helper"
2
2
 
3
- begin
4
- require 'bundler/gem_tasks'
5
- rescue Exception
6
- end
3
+ base_dir = File.join(File.dirname(__FILE__))
4
+
5
+ helper = Bundler::GemHelper.new(base_dir)
6
+ helper.install
7
7
 
8
8
  FileList['tasks/**.rake'].each {|f| load f }
9
9
 
10
- Rake::TestTask.new('test') do |t|
11
- t.libs << 'lib'
12
- t.libs << 'test'
13
- t.test_files = FileList['test/**/*_test.rb']
14
- t.verbose = true
10
+ desc "Run tests"
11
+ task :test do
12
+ cd(base_dir) do
13
+ ruby("test/run-test.rb")
14
+ end
15
15
  end
16
16
 
17
17
  task default: 'test'
@@ -1,8 +1,6 @@
1
1
  FROM iruby-test-base:ruby-<%= ruby_version %>
2
2
 
3
- RUN gem install cztop \
4
- && gem install rbczmq -- --with-system-libs
5
-
3
+ RUN gem install cztop
6
4
  RUN mkdir -p /iruby
7
5
  ADD . /iruby
8
6
  WORKDIR /iruby
data/iruby.gemspec CHANGED
@@ -1,36 +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 'data_uri', '~> 0.1'
21
+ s.add_dependency 'ffi-rzmq'
22
+ s.add_dependency 'irb'
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'
28
- s.add_development_dependency 'minitest'
29
- s.add_development_dependency 'ffi-rzmq'
30
26
  s.add_development_dependency 'pycall', '>= 1.2.1'
31
-
32
- s.add_runtime_dependency 'bond', '~> 0.5'
33
- s.add_runtime_dependency 'multi_json', '~> 1.11'
34
- s.add_runtime_dependency 'mimemagic', '~> 0.3'
35
- s.add_runtime_dependency 'data_uri', '~> 0.1'
27
+ s.add_development_dependency 'rake'
28
+ s.add_development_dependency 'test-unit'
29
+ s.add_development_dependency 'test-unit-rr'
36
30
  end
data/lib/iruby.rb CHANGED
@@ -1,12 +1,16 @@
1
- require 'mimemagic'
1
+ require 'fileutils'
2
+ require 'mime/types'
2
3
  require 'multi_json'
3
4
  require 'securerandom'
4
5
  require 'openssl'
5
6
  require 'tempfile'
6
7
  require 'set'
8
+ require 'stringio'
7
9
 
8
10
  require 'iruby/version'
9
11
  require 'iruby/jupyter'
12
+ require 'iruby/event_manager'
13
+ require 'iruby/logger'
10
14
  require 'iruby/kernel'
11
15
  require 'iruby/backend'
12
16
  require 'iruby/ostream'
@@ -24,11 +28,7 @@ if ENV.fetch('IRUBY_OLD_SESSION', false)
24
28
  begin
25
29
  require 'iruby/session/cztop'
26
30
  rescue LoadError
27
- begin
28
- require 'iruby/session/rbczmq'
29
- rescue LoadError
30
- STDERR.puts "You should install ffi-rzmq, cztop, or rbczmq before running iruby notebook. See README."
31
- end
31
+ STDERR.puts "Please install ffi-rzmq or cztop before running iruby. See README."
32
32
  end
33
33
  end
34
34
  else
data/lib/iruby/backend.rb CHANGED
@@ -1,10 +1,9 @@
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)
7
- b = TOPLEVEL_BINDING
6
+ b = eval_binding
8
7
 
9
8
  b.local_variable_set(:_ih, In) unless b.local_variable_defined?(:_ih)
10
9
  b.local_variable_set(:_oh, Out) unless b.local_variable_defined?(:_oh)
@@ -33,45 +32,74 @@ 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
- require 'bond'
40
- Bond.start(debug: true)
39
+ require 'irb'
40
+ require 'irb/completion'
41
+ IRB.setup(nil)
42
+ @main = TOPLEVEL_BINDING.eval("self").dup
43
+ @workspace = IRB::WorkSpace.new(@main)
44
+ @irb = IRB::Irb.new(@workspace)
45
+ @eval_path = @irb.context.irb_path
46
+ IRB.conf[:MAIN_CONTEXT] = @irb.context
47
+ end
48
+
49
+ def eval_binding
50
+ @workspace.binding
41
51
  end
42
52
 
43
53
  def eval(code, store_history)
44
- TOPLEVEL_BINDING.eval(code)
54
+ @irb.context.evaluate(code, 0)
55
+ @irb.context.last_value
45
56
  end
46
57
 
47
58
  def complete(code)
48
- Bond.agent.call(code, code)
59
+ IRB::InputCompletor::CompletionProc.call(code)
49
60
  end
50
61
  end
51
62
 
52
63
  class PryBackend
64
+ attr_reader :eval_path
53
65
  prepend History
54
66
 
55
67
  def initialize
56
68
  require 'pry'
57
- Pry.memory_size = 3
69
+ Pry.memory_size = 3
58
70
  Pry.pager = false # Don't use the pager
59
71
  Pry.print = proc {|output, value|} # No result printing
60
72
  Pry.exception_handler = proc {|output, exception, _| }
73
+ @eval_path = Pry.eval_path
61
74
  reset
62
75
  end
63
76
 
77
+ def eval_binding
78
+ TOPLEVEL_BINDING
79
+ end
80
+
64
81
  def eval(code, store_history)
82
+ Pry.current_line = 1
65
83
  @pry.last_result = nil
66
84
  unless @pry.eval(code)
67
85
  reset
68
86
  raise SystemExit
69
87
  end
70
- unless @pry.eval_string.empty?
88
+
89
+ # Pry::Code.complete_expression? return false
90
+ if !@pry.eval_string.empty?
71
91
  syntax_error = @pry.eval_string
72
92
  @pry.reset_eval_string
73
- @pry.evaluate_ruby syntax_error
93
+ @pry.evaluate_ruby(syntax_error)
94
+
95
+ # Pry::Code.complete_expression? raise SyntaxError
96
+ # evaluate again for current line number
97
+ elsif @pry.last_result_is_exception? &&
98
+ @pry.last_exception.is_a?(SyntaxError) &&
99
+ @pry.last_exception.is_a?(Pry::UserError)
100
+ @pry.evaluate_ruby(code)
74
101
  end
102
+
75
103
  raise @pry.last_exception if @pry.last_result_is_exception?
76
104
  @pry.push_initial_binding unless @pry.current_binding # ensure that we have a binding
77
105
  @pry.last_result
@@ -82,7 +110,7 @@ module IRuby
82
110
  end
83
111
 
84
112
  def reset
85
- @pry = Pry.new(output: $stdout, target: TOPLEVEL_BINDING)
113
+ @pry = Pry.new(output: $stdout, target: eval_binding)
86
114
  end
87
115
  end
88
116
  end
data/lib/iruby/command.rb CHANGED
@@ -1,7 +1,4 @@
1
- require 'iruby/jupyter'
2
-
3
- require 'fileutils'
4
- require 'multi_json'
1
+ require 'iruby'
5
2
 
6
3
  module IRuby
7
4
  class Command
@@ -92,7 +89,6 @@ Try `ipython help` for more information.
92
89
  end
93
90
 
94
91
  def run_kernel
95
- require 'iruby/logger'
96
92
  IRuby.logger = MultiLogger.new(*Logger.new(STDOUT))
97
93
  STDOUT.sync = true # FIXME: This can make the integration test.
98
94
 
@@ -131,7 +127,7 @@ Try `ipython help` for more information.
131
127
  check_registered_kernel
132
128
  check_bundler {|e| STDERR.puts "Could not load bundler: #{e.message}" }
133
129
 
134
- Kernel.exec('ipython', *@args)
130
+ Process.exec('ipython', *@args)
135
131
  end
136
132
 
137
133
  def check_registered_kernel
data/lib/iruby/display.rb CHANGED
@@ -1,64 +1,149 @@
1
+ require "set"
2
+
1
3
  module IRuby
2
4
  module Display
5
+ DEFAULT_MIME_TYPE_FORMAT_METHODS = {
6
+ "text/html" => :to_html,
7
+ "text/markdown" => :to_markdown,
8
+ "image/svg+xml" => :to_svg,
9
+ "image/png" => :to_png,
10
+ "appliation/pdf" => :to_pdf,
11
+ "image/jpeg" => :to_jpeg,
12
+ "text/latex" => [:to_latex, :to_tex],
13
+ # NOTE: Do not include the entry of "application/json" because
14
+ # all objects can respond to `to_json` due to json library
15
+ # "application/json" => :to_json,
16
+ "application/javascript" => :to_javascript,
17
+ nil => :to_iruby,
18
+ "text/plain" => :inspect
19
+ }.freeze
20
+
3
21
  class << self
22
+ # @private
4
23
  def convert(obj, options)
5
24
  Representation.new(obj, options)
6
25
  end
7
26
 
27
+ # @private
8
28
  def display(obj, options = {})
9
29
  obj = convert(obj, options)
10
30
  options = obj.options
11
31
  obj = obj.object
12
32
 
13
33
  fuzzy_mime = options[:format] # Treated like a fuzzy mime type
14
- raise 'Invalid argument :format' unless !fuzzy_mime || String === fuzzy_mime
34
+ unless !fuzzy_mime || String === fuzzy_mime
35
+ raise 'Invalid argument :format'
36
+ end
37
+
15
38
  if exact_mime = options[:mime]
16
39
  raise 'Invalid argument :mime' unless String === exact_mime
17
40
  raise 'Invalid mime type' unless exact_mime.include?('/')
18
41
  end
19
42
 
20
- data = {}
21
-
22
- # Render additional representation
23
- render(data, obj, exact_mime, fuzzy_mime)
24
-
25
- # IPython always requires a text representation
26
- render(data, obj, 'text/plain', nil) unless data['text/plain']
43
+ data = render_mimebundle(obj, exact_mime, fuzzy_mime)
44
+
45
+ # Render by additional formatters
46
+ render_by_registry(data, obj, exact_mime, fuzzy_mime)
47
+
48
+ # Render by to_xxx methods
49
+ DEFAULT_MIME_TYPE_FORMAT_METHODS.each do |mime, methods|
50
+ next if mime.nil? && !data.empty? # for to_iruby
51
+
52
+ next if mime && data.key?(mime) # do not overwrite
53
+
54
+ method = Array(methods).find {|m| obj.respond_to?(m) }
55
+ next if method.nil?
56
+
57
+ result = obj.send(method)
58
+ case mime
59
+ when nil # to_iruby
60
+ case result
61
+ when nil
62
+ # do nothing
63
+ next
64
+ when Array
65
+ mime, result = result
66
+ else
67
+ warn(("Ignore the result of to_iruby method of %p because " +
68
+ "it does not return a pair of mime-type and formatted representation") % obj)
69
+ next
70
+ end
71
+ end
72
+ data[mime] = result
73
+ end
27
74
 
28
75
  # As a last resort, interpret string representation of the object
29
76
  # as the given mime type.
30
- data[exact_mime] = protect(exact_mime, obj) if exact_mime && !data.any? {|m,_| exact_mime == m }
77
+ if exact_mime && !data.key?(exact_mime)
78
+ data[exact_mime] = protect(exact_mime, obj)
79
+ end
31
80
 
32
81
  data
33
82
  end
34
83
 
35
- def clear_output(wait=false)
36
- IRuby::Kernel.instance.session.send(:publish, :clear_output, {wait: wait})
84
+ # @private
85
+ def clear_output(wait = false)
86
+ IRuby::Kernel.instance.session.send(:publish, :clear_output, wait: wait)
37
87
  end
38
88
 
39
89
  private
40
90
 
41
91
  def protect(mime, data)
42
- MimeMagic.new(mime).text? ? data.to_s : [data.to_s].pack('m0')
92
+ ascii?(mime) ? data.to_s : [data.to_s].pack('m0')
93
+ end
94
+
95
+ # Each of the following mime types must be a text type,
96
+ # but mime-types library tells us it is a non-text type.
97
+ FORCE_TEXT_TYPES = Set[
98
+ "application/javascript",
99
+ "image/svg+xml"
100
+ ].freeze
101
+
102
+ def ascii?(mime)
103
+ if FORCE_TEXT_TYPES.include?(mime)
104
+ true
105
+ else
106
+ MIME::Type.new(mime).ascii?
107
+ end
43
108
  end
44
109
 
45
- def render(data, obj, exact_mime, fuzzy_mime)
110
+ private def render_mimebundle(obj, exact_mime, fuzzy_mime)
111
+ data = {}
112
+ if obj.respond_to?(:to_iruby_mimebundle)
113
+ include_mime = [exact_mime].compact
114
+ formats, metadata = obj.to_iruby_mimebundle(include: include_mime)
115
+ formats.each do |mime, value|
116
+ if fuzzy_mime.nil? || mime.include?(fuzzy_mime)
117
+ data[mime] = value
118
+ end
119
+ end
120
+ end
121
+ data
122
+ end
123
+
124
+ private def render_by_registry(data, obj, exact_mime, fuzzy_mime)
46
125
  # Filter matching renderer by object type
47
- renderer = Registry.renderer.select {|r| r.match?(obj) }
126
+ renderer = Registry.renderer.select { |r| r.match?(obj) }
48
127
 
49
128
  matching_renderer = nil
50
129
 
51
130
  # Find exactly matching display by exact_mime
52
- matching_renderer = renderer.find {|r| exact_mime == r.mime } if exact_mime
131
+ if exact_mime
132
+ matching_renderer = renderer.find { |r| exact_mime == r.mime }
133
+ end
53
134
 
54
135
  # Find fuzzy matching display by fuzzy_mime
55
- matching_renderer ||= renderer.find {|r| r.mime && r.mime.include?(fuzzy_mime) } if fuzzy_mime
136
+ if fuzzy_mime
137
+ matching_renderer ||= renderer.find { |r| r.mime&.include?(fuzzy_mime) }
138
+ end
56
139
 
57
140
  renderer.unshift matching_renderer if matching_renderer
58
141
 
59
142
  # Return first render result which has the right mime type
60
143
  renderer.each do |r|
61
144
  mime, result = r.render(obj)
145
+ next if data.key?(mime)
146
+
62
147
  if mime && result && (!exact_mime || exact_mime == mime) && (!fuzzy_mime || mime.include?(fuzzy_mime))
63
148
  data[mime] = protect(mime, result)
64
149
  break
@@ -69,11 +154,25 @@ module IRuby
69
154
  end
70
155
  end
71
156
 
157
+ private def render_by_to_iruby(data, obj)
158
+ if obj.respond_to?(:to_iruby)
159
+ result = obj.to_iruby
160
+ mime, rep = case result
161
+ when Array
162
+ result
163
+ else
164
+ [nil, result]
165
+ end
166
+ data[mime] = rep
167
+ end
168
+ end
169
+
72
170
  class Representation
73
171
  attr_reader :object, :options
74
172
 
75
173
  def initialize(object, options)
76
- @object, @options = object, options
174
+ @object = object
175
+ @options = options
77
176
  end
78
177
 
79
178
  class << self
@@ -90,11 +189,68 @@ module IRuby
90
189
  end
91
190
  end
92
191
 
192
+ class FormatMatcher
193
+ def initialize(&block)
194
+ @block = block
195
+ end
196
+
197
+ def call(obj)
198
+ @block.(obj)
199
+ end
200
+
201
+ def inspect
202
+ "#{self.class.name}[%p]" % @block
203
+ end
204
+ end
205
+
206
+ class RespondToFormatMatcher < FormatMatcher
207
+ def initialize(name)
208
+ super() {|obj| obj.respond_to?(name) }
209
+ @name = name
210
+ end
211
+
212
+ attr_reader :name
213
+
214
+ def inspect
215
+ "#{self.class.name}[respond_to?(%p)]" % name
216
+ end
217
+ end
218
+
219
+ class TypeFormatMatcher < FormatMatcher
220
+ def initialize(class_block)
221
+ super() do |obj|
222
+ begin
223
+ self.klass === obj
224
+ # We have to rescue all exceptions since constant autoloading could fail with a different error
225
+ rescue Exception
226
+ false
227
+ end
228
+ end
229
+ @class_block = class_block
230
+ end
231
+
232
+ def klass
233
+ @class_block.()
234
+ end
235
+
236
+ def inspect
237
+ klass = begin
238
+ @class_block.()
239
+ rescue Exception
240
+ @class_block
241
+ end
242
+ "#{self.class.name}[%p]" % klass
243
+ end
244
+ end
245
+
93
246
  class Renderer
94
- attr_reader :match, :mime, :render, :priority
247
+ attr_reader :match, :mime, :priority
95
248
 
96
249
  def initialize(match, mime, render, priority)
97
- @match, @mime, @render, @priority = match, mime, render, priority
250
+ @match = match
251
+ @mime = mime
252
+ @render = render
253
+ @priority = priority
98
254
  end
99
255
 
100
256
  def match?(obj)
@@ -114,36 +270,22 @@ module IRuby
114
270
  @renderer ||= []
115
271
  end
116
272
 
117
- SUPPORTED_MIMES = %w(
118
- text/plain
119
- text/html
120
- text/latex
121
- application/json
122
- application/javascript
123
- image/png
124
- image/jpeg
125
- image/svg+xml)
126
-
127
273
  def match(&block)
128
- @match = block
274
+ @match = FormatMatcher.new(&block)
129
275
  priority 0
130
276
  nil
131
277
  end
132
278
 
133
279
  def respond_to(name)
134
- match {|obj| obj.respond_to?(name) }
280
+ @match = RespondToFormatMatcher.new(name)
281
+ priority 0
282
+ nil
135
283
  end
136
284
 
137
285
  def type(&block)
138
- match do |obj|
139
- begin
140
- block.call === obj
141
- # We have to rescue all exceptions since constant autoloading could fail with a different error
142
- rescue Exception
143
- rescue #NameError
144
- false
145
- end
146
- end
286
+ @match = TypeFormatMatcher.new(block)
287
+ priority 0
288
+ nil
147
289
  end
148
290
 
149
291
  def priority(p)
@@ -153,7 +295,7 @@ module IRuby
153
295
 
154
296
  def format(mime = nil, &block)
155
297
  renderer << Renderer.new(@match, mime, block, @priority)
156
- renderer.sort_by! {|r| -r.priority }
298
+ renderer.sort_by! { |r| -r.priority }
157
299
 
158
300
  # Decrease priority implicitly for all formats
159
301
  # which are added later for a type.
@@ -170,6 +312,7 @@ module IRuby
170
312
  end
171
313
 
172
314
  type { Numo::NArray }
315
+ format 'text/plain', &:inspect
173
316
  format 'text/latex' do |obj|
174
317
  obj.ndim == 2 ?
175
318
  LaTeX.matrix(obj, obj.shape[0], obj.shape[1]) :
@@ -180,6 +323,7 @@ module IRuby
180
323
  end
181
324
 
182
325
  type { NArray }
326
+ format 'text/plain', &:inspect
183
327
  format 'text/latex' do |obj|
184
328
  obj.dim == 2 ?
185
329
  LaTeX.matrix(obj.transpose(1, 0), obj.shape[1], obj.shape[0]) :
@@ -239,61 +383,52 @@ module IRuby
239
383
  end
240
384
  end
241
385
 
242
- match do |obj|
243
- defined?(Magick::Image) && Magick::Image === obj ||
244
- defined?(MiniMagick::Image) && MiniMagick::Image === obj
245
- end
246
- format 'image' do |obj|
386
+ format_magick_image = ->(obj) do
247
387
  format = obj.format || 'PNG'
248
- [format == 'PNG' ? 'image/png' : 'image/jpeg', obj.to_blob {|i| i.format = format }]
249
- end
250
-
251
- type { Gruff::Base }
252
- format 'image/png' do |obj|
253
- obj.to_blob
388
+ [
389
+ format == 'PNG' ? 'image/png' : 'image/jpeg',
390
+ obj.to_blob {|i| i.format = format }
391
+ ]
254
392
  end
255
393
 
256
- respond_to :to_html
257
- format 'text/html' do |obj|
258
- obj.to_html
394
+ match do |obj|
395
+ defined?(Magick::Image) && Magick::Image === obj ||
396
+ defined?(MiniMagick::Image) && MiniMagick::Image === obj
259
397
  end
398
+ format 'image', &format_magick_image
260
399
 
261
- respond_to :to_latex
262
- format 'text/latex' do |obj|
263
- obj.to_latex
400
+ type { Gruff::Base }
401
+ format 'image' do |obj|
402
+ image = obj.to_image
403
+ format_magick_image.(obj.to_image)
264
404
  end
265
405
 
266
- respond_to :to_tex
267
- format 'text/latex' do |obj|
268
- obj.to_tex
406
+ match do |obj|
407
+ defined?(Vips::Image) && Vips::Image === obj
269
408
  end
270
-
271
- respond_to :to_javascript
272
- format 'text/javascript' do |obj|
273
- obj.to_javascript
409
+ format do |obj|
410
+ # handles Vips::Error, vips_image_get: field "vips-loader" not found
411
+ loader = obj.get('vips-loader') rescue nil
412
+ if loader == 'jpegload'
413
+ ['image/jpeg', obj.write_to_buffer('.jpg')]
414
+ else
415
+ # falls back to png for other/unknown types
416
+ ['image/png', obj.write_to_buffer('.png')]
417
+ end
274
418
  end
275
419
 
276
- respond_to :to_svg
420
+ type { Rubyvis::Mark }
277
421
  format 'image/svg+xml' do |obj|
278
- obj.render if defined?(Rubyvis) && Rubyvis::Mark === obj
422
+ obj.render
279
423
  obj.to_svg
280
424
  end
281
425
 
282
- respond_to :to_iruby
283
- format do |obj|
284
- obj.to_iruby
285
- end
286
-
287
- match {|obj| obj.respond_to?(:path) && File.readable?(obj.path) }
426
+ match { |obj| obj.respond_to?(:path) && obj.method(:path).arity == 0 && File.readable?(obj.path) }
288
427
  format do |obj|
289
- mime = MimeMagic.by_path(obj.path).to_s
290
- [mime, File.read(obj.path)] if SUPPORTED_MIMES.include?(mime)
291
- end
292
-
293
- type { Object }
294
- priority -1000
295
- format 'text/plain' do |obj|
296
- obj.inspect
428
+ mime = MIME::Types.of(obj.path).first.to_s
429
+ if mime && DEFAULT_MIME_TYPE_FORMAT_METHODS.key?(mime)
430
+ [mime, File.read(obj.path)]
431
+ end
297
432
  end
298
433
  end
299
434
  end