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.
- checksums.yaml +4 -4
- data/.github/workflows/ubuntu.yml +69 -0
- data/CHANGES.md +219 -0
- data/Gemfile +0 -2
- data/LICENSE +1 -1
- data/README.md +81 -62
- data/Rakefile +10 -10
- data/ci/Dockerfile.main.erb +1 -3
- data/iruby.gemspec +13 -19
- data/lib/iruby.rb +6 -6
- data/lib/iruby/backend.rb +38 -10
- data/lib/iruby/command.rb +2 -6
- data/lib/iruby/display.rb +216 -81
- data/lib/iruby/event_manager.rb +40 -0
- data/lib/iruby/formatter.rb +3 -3
- data/lib/iruby/input.rb +6 -6
- data/lib/iruby/input/autoload.rb +1 -1
- data/lib/iruby/input/builder.rb +4 -4
- data/lib/iruby/input/button.rb +2 -2
- data/lib/iruby/input/cancel.rb +1 -1
- data/lib/iruby/input/checkbox.rb +3 -3
- data/lib/iruby/input/date.rb +3 -3
- data/lib/iruby/input/field.rb +2 -2
- data/lib/iruby/input/file.rb +3 -3
- data/lib/iruby/input/form.rb +6 -6
- data/lib/iruby/input/label.rb +4 -4
- data/lib/iruby/input/multiple.rb +10 -10
- data/lib/iruby/input/popup.rb +2 -2
- data/lib/iruby/input/radio.rb +6 -6
- data/lib/iruby/input/select.rb +8 -8
- data/lib/iruby/input/textarea.rb +1 -1
- data/lib/iruby/input/widget.rb +2 -2
- data/lib/iruby/jupyter.rb +1 -0
- data/lib/iruby/kernel.rb +157 -29
- data/lib/iruby/ostream.rb +27 -10
- data/lib/iruby/session.rb +1 -0
- data/lib/iruby/session_adapter.rb +7 -3
- data/lib/iruby/session_adapter/pyzmq_adapter.rb +11 -10
- data/lib/iruby/session_adapter/test_adapter.rb +49 -0
- data/lib/iruby/utils.rb +15 -0
- data/lib/iruby/version.rb +1 -1
- data/run-test.sh +1 -1
- data/test/helper.rb +136 -0
- data/test/integration_test.rb +1 -2
- data/test/iruby/backend_test.rb +37 -0
- data/test/iruby/command_test.rb +0 -1
- data/test/iruby/display_test.rb +188 -0
- data/test/iruby/event_manager_test.rb +92 -0
- data/test/iruby/jupyter_test.rb +0 -1
- data/test/iruby/kernel_test.rb +185 -0
- data/test/iruby/mime_test.rb +50 -0
- data/test/iruby/multi_logger_test.rb +0 -4
- data/test/iruby/session_adapter/cztop_adapter_test.rb +1 -1
- data/test/iruby/session_adapter/ffirzmq_adapter_test.rb +1 -1
- data/test/iruby/session_adapter/session_adapter_test_base.rb +1 -3
- data/test/iruby/session_adapter_test.rb +42 -67
- data/test/iruby/session_test.rb +10 -15
- data/test/run-test.rb +19 -0
- metadata +74 -62
- data/.travis.yml +0 -41
- data/CHANGES +0 -143
- data/CONTRIBUTORS +0 -19
- data/lib/iruby/session/rbczmq.rb +0 -72
- data/lib/iruby/session_adapter/rbczmq_adapter.rb +0 -33
- data/test/iruby/session_adapter/rbczmq_adapter_test.rb +0 -37
- data/test/test_helper.rb +0 -48
data/Rakefile
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require "bundler/gem_helper"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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'
|
data/ci/Dockerfile.main.erb
CHANGED
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
|
12
|
-
s.description = 'A Ruby kernel for Jupyter
|
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
|
16
|
+
s.require_paths = %w[lib]
|
20
17
|
|
21
|
-
|
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.
|
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.
|
33
|
-
s.
|
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 '
|
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
|
-
|
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 =
|
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 '
|
40
|
-
|
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
|
-
|
54
|
+
@irb.context.evaluate(code, 0)
|
55
|
+
@irb.context.last_value
|
45
56
|
end
|
46
57
|
|
47
58
|
def complete(code)
|
48
|
-
|
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
|
-
|
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
|
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:
|
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
|
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
|
-
|
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
|
-
|
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
|
23
|
-
|
24
|
-
|
25
|
-
#
|
26
|
-
|
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
|
-
|
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
|
-
|
36
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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, :
|
247
|
+
attr_reader :match, :mime, :priority
|
95
248
|
|
96
249
|
def initialize(match, mime, render, priority)
|
97
|
-
@match
|
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
|
280
|
+
@match = RespondToFormatMatcher.new(name)
|
281
|
+
priority 0
|
282
|
+
nil
|
135
283
|
end
|
136
284
|
|
137
285
|
def type(&block)
|
138
|
-
match
|
139
|
-
|
140
|
-
|
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
|
-
|
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
|
-
[
|
249
|
-
|
250
|
-
|
251
|
-
|
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
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
262
|
-
format '
|
263
|
-
obj.
|
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
|
-
|
267
|
-
|
268
|
-
obj.to_tex
|
406
|
+
match do |obj|
|
407
|
+
defined?(Vips::Image) && Vips::Image === obj
|
269
408
|
end
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
-
|
420
|
+
type { Rubyvis::Mark }
|
277
421
|
format 'image/svg+xml' do |obj|
|
278
|
-
obj.render
|
422
|
+
obj.render
|
279
423
|
obj.to_svg
|
280
424
|
end
|
281
425
|
|
282
|
-
respond_to :
|
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 =
|
290
|
-
|
291
|
-
|
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
|