iruby 0.1.11 → 0.1.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f7cb8c6ec6b18164c82d06e8e82dde35af450ac
4
- data.tar.gz: 2bbb33fa995c381801d319eda788622ff7cf588a
3
+ metadata.gz: 47cc7be0c54041de9aa2e48644f0812f5f902bbc
4
+ data.tar.gz: a656cdee3051efdd8db801c68ca12796577f2a6c
5
5
  SHA512:
6
- metadata.gz: ebf7533b241c7ed0586fb681079550f56b9b1e49a85ec1df3b1a38289efc0cef8bd04c1b3486c46735d627e2b27623eb67c1ec0bc8cbbbd438419feebbbcb2c0
7
- data.tar.gz: 6f1c2ff436d7990eb99725b9c8d308763cdf9b1c068837bd17cc40d950146400e20fa35af323ff684bf868018965fe3f2268bb4d60ec0dc143bc3dacf5143367
6
+ metadata.gz: e18bc7e9a5fc371c552d58224a00ce42b0190c9e4e69e3be9c5bf0c2acaa137eaaf61d042c589197f77504d1fbd61aaa707306b41984d52386a86f7c8746cdae
7
+ data.tar.gz: 693f4ef8e4d09190326a05ee7ab62cbe2c06c72de5c7ab4c7a4ea502d720bbe363a9586bdba0fd4cc3a73c8db5d2fa807b019e73a39390725b3a05167c4c2432
data/CHANGES CHANGED
@@ -1,3 +1,10 @@
1
+ 0.1.12
2
+
3
+ * IRuby#table add option maxrows
4
+ * powerful display system with format and datatype registry, see #25
5
+ * Add IRuby#javascript
6
+ * Add IRuby#svg
7
+
1
8
  0.1.11
2
9
 
3
10
  * Push binding if pry binding stack is empty
data/lib/iruby.rb CHANGED
@@ -11,5 +11,6 @@ require 'iruby/kernel'
11
11
  require 'iruby/backend'
12
12
  require 'iruby/session'
13
13
  require 'iruby/ostream'
14
+ require 'iruby/formatter'
14
15
  require 'iruby/utils'
15
16
  require 'iruby/display'
data/lib/iruby/display.rb CHANGED
@@ -1,40 +1,206 @@
1
1
  module IRuby
2
- class Display
3
- attr_reader :data
4
-
5
- SUPPORTED_MIMES = %w(
6
- text/plain
7
- text/html
8
- text/latex
9
- application/json
10
- application/javascript
11
- image/png
12
- image/jpeg
13
- image/svg+xml)
14
-
15
- def initialize(obj, options)
16
- @data = { 'text/plain' => obj.inspect }
17
- if options[:mime]
18
- add(options[:mime], obj)
19
- elsif obj.respond_to?(:to_iruby)
20
- add(*obj.to_iruby)
21
- elsif obj.respond_to?(:to_html)
22
- add('text/html', obj.to_html)
23
- elsif obj.respond_to?(:to_svg)
24
- obj.render if defined?(Rubyvis) && Rubyvis::Mark === obj
25
- add('image/svg+xml', obj.to_svg)
26
- elsif obj.respond_to?(:to_latex)
27
- add('text/latex', obj.to_latex)
28
- elsif defined?(Gruff::Base) && Gruff::Base === obj
29
- add('image/png', obj.to_blob)
30
- elsif (defined?(Magick::Image) && Magick::Image === obj) ||
31
- (defined?(MiniMagick::Image) && MiniMagick::Image === obj)
32
- format = obj.format || 'PNG'
33
- add(format == 'PNG' ? 'image/png' : 'image/jpeg', obj.to_blob {|i| i.format = format })
34
- elsif obj.respond_to?(:path) && File.readable?(obj.path)
35
- mime = MimeMagic.by_path(obj.path).to_s
36
- add(mime, File.read(obj.path)) if SUPPORTED_MIMES.include?(mime)
37
- elsif defined?(Gnuplot::Plot) && Gnuplot::Plot === obj
2
+ module Display
3
+ class << self
4
+ def convert(obj, options)
5
+ Representation.new(obj, options)
6
+ end
7
+
8
+ def display(obj, options = {})
9
+ obj = convert(obj, options)
10
+ options = obj.options
11
+ obj = obj.object
12
+
13
+ exact_mime = options[:mime]
14
+ fuzzy_mime = options[:format] # Treated like a fuzzy mime type
15
+ raise 'Invalid argument :format' unless !fuzzy_mime || String === fuzzy_mime
16
+ if exact_mime
17
+ raise 'Invalid argument :mime' unless String === exact_mime
18
+ raise 'Invalid mime type' unless exact_mime.include?('/')
19
+ end
20
+
21
+ data = {}
22
+
23
+ # Render additional representation
24
+ render(data, obj, exact_mime, fuzzy_mime)
25
+
26
+ # IPython always requires a text representation
27
+ render(data, obj, 'text/plain', nil) unless data['text/plain']
28
+
29
+ # As a last resort, interpret string representation of the object
30
+ # as the given mime type.
31
+ data[exact_mime] = protect(exact_mime, obj) if exact_mime && !data.any? {|m,_| exact_mime == m }
32
+
33
+ data
34
+ end
35
+
36
+ private
37
+
38
+ def protect(mime, data)
39
+ MimeMagic.new(mime).text? ? data.to_s : [data.to_s].pack('m0')
40
+ end
41
+
42
+ def render(data, obj, exact_mime, fuzzy_mime)
43
+ # Filter matching renderer by object type
44
+ renderer = Registry.renderer.select {|r| r.match?(obj) }
45
+
46
+ matching_renderer = nil
47
+
48
+ # Find exactly matching display by exact_mime
49
+ matching_renderer = renderer.find {|r| exact_mime == r.mime } if exact_mime
50
+
51
+ # Find fuzzy matching display by fuzzy_mime
52
+ matching_renderer ||= renderer.find {|r| r.mime && r.mime.include?(fuzzy_mime) } if fuzzy_mime
53
+
54
+ renderer.unshift matching_renderer if matching_renderer
55
+
56
+ # Return first render result which has the right mime type
57
+ renderer.each do |r|
58
+ mime, result = r.render(obj)
59
+ if mime && result && (!exact_mime || exact_mime == mime) && (!fuzzy_mime || mime.include?(fuzzy_mime))
60
+ data[mime] = protect(mime, result)
61
+ break
62
+ end
63
+ end
64
+
65
+ nil
66
+ end
67
+ end
68
+
69
+ class Representation
70
+ attr_reader :object, :options
71
+
72
+ def initialize(object, options)
73
+ @object, @options = object, options
74
+ end
75
+
76
+ class << self
77
+ alias old_new new
78
+
79
+ def new(obj, options)
80
+ options = { format: options } if String === options
81
+ if Representation === obj
82
+ options = obj.options.merge(options)
83
+ obj = obj.object
84
+ end
85
+ old_new(obj, options)
86
+ end
87
+ end
88
+ end
89
+
90
+ class Renderer
91
+ attr_reader :match, :mime, :render, :priority
92
+
93
+ def initialize(match, mime, render, priority)
94
+ @match, @mime, @render, @priority = match, mime, render, priority
95
+ end
96
+
97
+ def match?(obj)
98
+ @match.call(obj)
99
+ rescue NameError
100
+ false
101
+ end
102
+
103
+ def render(obj)
104
+ result = @render.call(obj)
105
+ Array === result ? result : [@mime, result]
106
+ end
107
+ end
108
+
109
+ module Registry
110
+ extend self
111
+
112
+ def renderer
113
+ @renderer ||= []
114
+ end
115
+
116
+ SUPPORTED_MIMES = %w(
117
+ text/plain
118
+ text/html
119
+ text/latex
120
+ application/json
121
+ application/javascript
122
+ image/png
123
+ image/jpeg
124
+ image/svg+xml)
125
+
126
+ def match(&block)
127
+ @match = block
128
+ priority 0
129
+ nil
130
+ end
131
+
132
+ def respond_to(name)
133
+ match {|obj| obj.respond_to?(name) }
134
+ end
135
+
136
+ def type(&block)
137
+ match {|obj| block.call === obj }
138
+ end
139
+
140
+ def priority(p)
141
+ @priority = p
142
+ nil
143
+ end
144
+
145
+ def format(mime = nil, &block)
146
+ renderer << Renderer.new(@match, mime, block, @priority)
147
+ renderer.sort_by! {|r| -r.priority }
148
+
149
+ # Decrease priority implicitly for all formats
150
+ # which are added later for a type.
151
+ # Overwrite with the `priority` method!
152
+ @priority -= 1
153
+ nil
154
+ end
155
+
156
+ type { NMatrix }
157
+ format 'text/latex' do |obj|
158
+ obj.dim == 2 ?
159
+ LaTeX.matrix(obj, obj.shape[0], obj.shape[1]) :
160
+ LaTeX.vector(obj.to_a)
161
+ end
162
+
163
+ type { NArray }
164
+ format 'text/latex' do |obj|
165
+ obj.dim == 2 ?
166
+ LaTeX.matrix(obj.transpose, obj.shape[1], obj.shape[0]) :
167
+ LaTeX.vector(obj.to_a)
168
+ end
169
+ format 'text/html' do |obj|
170
+ HTML.table(obj.to_a)
171
+ end
172
+
173
+ type { Matrix }
174
+ format 'text/latex' do |obj|
175
+ LaTeX.matrix(obj, obj.row_count, obj.column_count)
176
+ end
177
+ format 'text/html' do |obj|
178
+ HTML.table(obj.to_a)
179
+ end
180
+
181
+ type { GSL::Matrix }
182
+ format 'text/latex' do |obj|
183
+ LaTeX.matrix(obj, obj.size1, obj.size2)
184
+ end
185
+ format 'text/html' do |obj|
186
+ HTML.table(obj.to_a)
187
+ end
188
+
189
+ type { GSL::Vector }
190
+ format 'text/latex' do |obj|
191
+ LaTeX.vector(obj.to_a)
192
+ end
193
+ format 'text/html' do |obj|
194
+ HTML.table(obj.to_a)
195
+ end
196
+
197
+ type { GSL::Complex }
198
+ format 'text/latex' do |obj|
199
+ "$#{obj.re}+#{obj.im}i$"
200
+ end
201
+
202
+ type { Gnuplot::Plot }
203
+ format 'image/svg+xml' do |obj|
38
204
  Tempfile.open('plot') do |f|
39
205
  obj.terminal 'svg enhanced'
40
206
  obj.output f.path
@@ -42,47 +208,58 @@ module IRuby
42
208
  io << obj.to_gplot
43
209
  io << obj.store_datasets
44
210
  end
45
- add('image/svg+xml', File.read(f.path))
211
+ File.read(f.path)
46
212
  end
47
- elsif defined?(Matrix) && Matrix === obj
48
- add('text/latex', format_matrix(obj, obj.row_count, obj.column_count))
49
- elsif defined?(GSL::Matrix) && GSL::Matrix === obj
50
- add('text/latex', format_matrix(obj, obj.size1, obj.size2))
51
- elsif defined?(GSL::Vector) && GSL::Vector === obj
52
- add('text/latex', format_vector(obj.to_a))
53
- elsif defined?(GSL::Complex) && GSL::Complex === obj
54
- add('text/latex', "$#{obj.re}+#{obj.im}i$")
55
- elsif defined?(NArray) && NArray === obj
56
- add('text/latex', obj.dim == 2 ?
57
- format_matrix(obj.transpose, obj.shape[1], obj.shape[0]) :
58
- format_vector(obj.to_a))
59
- elsif defined?(NMatrix) && NMatrix === obj
60
- add('text/latex', obj.dim == 2 ?
61
- format_matrix(obj, obj.shape[0], obj.shape[1]) :
62
- format_vector(obj.to_a))
63
213
  end
64
- end
65
214
 
66
- private
215
+ match {|obj| Magick::Image === obj || MiniMagick::Image === obj }
216
+ format 'image' do |obj|
217
+ format = obj.format || 'PNG'
218
+ [format == 'PNG' ? 'image/png' : 'image/jpeg', obj.to_blob {|i| i.format = format }]
219
+ end
67
220
 
68
- def format_vector(v)
69
- "$$\\left(\\begin{array}{#{'c' * v.size}} #{v.map(&:to_s).join(' & ')} \\end{array}\\right)$$"
70
- end
221
+ type { Gruff::Base }
222
+ format 'image/png' do |obj|
223
+ obj.to_blob
224
+ end
71
225
 
72
- def format_matrix(m, row_count, column_count)
73
- s = "$$\\left(\\begin{array}{#{'c' * column_count}}\n"
74
- (0...row_count).each do |i|
75
- s << ' ' << m[i,0].to_s
76
- (1...column_count).each do |j|
77
- s << '&' << m[i,j].to_s
78
- end
79
- s << "\\\\\n"
226
+ respond_to :to_html
227
+ format 'text/html' do |obj|
228
+ obj.to_html
229
+ end
230
+
231
+ respond_to :to_latex
232
+ format 'text/latex' do |obj|
233
+ obj.to_latex
234
+ end
235
+
236
+ respond_to :to_javascript
237
+ format 'text/javascript' do |obj|
238
+ obj.to_javascript
239
+ end
240
+
241
+ respond_to :to_svg
242
+ format 'image/svg+xml' do |obj|
243
+ obj.render if defined?(Rubyvis) && Rubyvis::Mark === obj
244
+ obj.to_svg
80
245
  end
81
- s << "\\end{array}\\right)$$"
82
- end
83
246
 
84
- def add(mime, data)
85
- @data[mime] = MimeMagic.new(mime).text? ? data.to_s : [data.to_s].pack('m0')
247
+ respond_to :to_iruby
248
+ format do |obj|
249
+ obj.to_iruby
250
+ end
251
+
252
+ match {|obj| obj.respond_to?(:path) && File.readable?(obj.path) }
253
+ format do |obj|
254
+ mime = MimeMagic.by_path(obj.path).to_s
255
+ [mime, File.read(obj.path)] if SUPPORTED_MIMES.include?(mime)
256
+ end
257
+
258
+ type { Object }
259
+ priority -1000
260
+ format 'text/plain' do |obj|
261
+ obj.inspect
262
+ end
86
263
  end
87
264
  end
88
265
  end
@@ -0,0 +1,73 @@
1
+ module IRuby
2
+ module LaTeX
3
+ extend self
4
+
5
+ def vector(v)
6
+ x = 'c' * v.size
7
+ y = v.map(&:to_s).join(' & ')
8
+ "$$\\left(\\begin{array}{#{x}} #{y} \\end{array}\\right)$$"
9
+ end
10
+
11
+ def matrix(m, row_count, column_count)
12
+ s = "$$\\left(\\begin{array}{#{'c' * column_count}}\n"
13
+ (0...row_count).each do |i|
14
+ s << ' ' << m[i,0].to_s
15
+ (1...column_count).each do |j|
16
+ s << '&' << m[i,j].to_s
17
+ end
18
+ s << "\\\\\n"
19
+ end
20
+ s << "\\end{array}\\right)$$"
21
+ end
22
+ end
23
+
24
+ module HTML
25
+ extend self
26
+
27
+ def table(obj, options = {})
28
+ options[:maxrows] = 15 unless options.include?(:maxrows)
29
+ return obj unless Enumerable === obj
30
+ keys = nil
31
+ size = 0
32
+ rows = []
33
+ obj.each_with_index do |row, i|
34
+ row = row.flatten(1) if obj.respond_to?(:keys)
35
+ if row.respond_to?(:keys)
36
+ # Array of Hashes
37
+ keys ||= Set.new
38
+ keys.merge(row.keys)
39
+ elsif row.respond_to?(:map)
40
+ # Array of Arrays
41
+ size = row.size if size < row.size
42
+ end
43
+ if options[:maxrows] && i > options[:maxrows]
44
+ rows << '...'
45
+ break
46
+ end
47
+ rows << row
48
+ end
49
+ table = '<table>'
50
+ if keys
51
+ keys.merge(0...size)
52
+ table << '<tr>' << keys.map {|k| "<th>#{k}</th>"}.join << '</tr>'
53
+ else
54
+ keys = 0...size
55
+ end
56
+ rows.each do |row|
57
+ table << '<tr>'
58
+ if row.respond_to?(:map)
59
+ row = keys.map {|k| "<td>#{row[k] rescue nil}</td>" }
60
+ if row.empty?
61
+ table << "<td#{keys.size > 1 ? " colspan='#{keys.size}'" : ''}></td>"
62
+ else
63
+ table << row.join
64
+ end
65
+ else
66
+ table << "<td#{keys.size > 1 ? " colspan='#{keys.size}'" : ''}>#{row}</td>"
67
+ end
68
+ table << '</tr>'
69
+ end
70
+ table << '</table>'
71
+ end
72
+ end
73
+ end
data/lib/iruby/kernel.rb CHANGED
@@ -68,7 +68,7 @@ module IRuby
68
68
 
69
69
  def display(obj, options={})
70
70
  unless obj.nil?
71
- content = { data: Display.new(obj, options).data, metadata: {}, execution_count: @execution_count }
71
+ content = { data: Display.display(obj, options), metadata: {}, execution_count: @execution_count }
72
72
  @session.send(@pub_socket, 'pyout', content)
73
73
  end
74
74
  nil
data/lib/iruby/utils.rb CHANGED
@@ -1,71 +1,33 @@
1
1
  module IRuby
2
- class MimeString < String
3
- attr_reader :mime
4
-
5
- def initialize(mime, data)
6
- super(data.to_s)
7
- @mime = mime
8
- end
9
-
10
- def to_iruby
11
- [@mime, self]
12
- end
2
+ def self.convert(object, options)
3
+ Display.convert(object, options)
13
4
  end
14
5
 
15
- def self.display(obj, options={})
6
+ def self.display(obj, options = {})
16
7
  Kernel.instance.display(obj, options)
17
8
  end
18
9
 
19
- def self.table(obj)
20
- return obj unless Enumerable === obj
21
- keys = nil
22
- size = 0
23
- rows = []
24
- obj.each do |row|
25
- row = row.flatten(1) if obj.respond_to?(:keys)
26
- if row.respond_to?(:keys)
27
- # Array of Hashes
28
- keys ||= Set.new
29
- keys.merge(row.keys)
30
- elsif row.respond_to?(:map)
31
- # Array of Arrays
32
- size = row.size if size < row.size
33
- end
34
- rows << row
35
- end
36
- table = '<table>'
37
- if keys
38
- keys.merge(0...size)
39
- table << '<tr>' << keys.map {|k| "<th>#{k}</th>"}.join << '</tr>'
40
- else
41
- keys = 0...size
42
- end
43
- rows.each do |row|
44
- table << '<tr>'
45
- if row.respond_to?(:map)
46
- row = keys.map {|k| "<td>#{row[k] rescue nil}</td>" }
47
- if row.empty?
48
- table << "<td#{keys.size > 1 ? " colspan='#{keys.size}'" : ''}></td>"
49
- else
50
- table << row.join
51
- end
52
- else
53
- table << "<td#{keys.size > 1 ? " colspan='#{keys.size}'" : ''}>#{row}</td>"
54
- end
55
- table << '</tr>'
56
- end
57
- html(table << '</table>')
10
+ def self.table(s)
11
+ html(HTML.table(s))
58
12
  end
59
13
 
60
14
  def self.latex(s)
61
- MimeString.new('text/latex', s)
15
+ convert(s, mime: 'text/latex')
62
16
  end
63
17
 
64
18
  def self.math(s)
65
- MimeString.new('text/latex', "$$#{s}$$")
19
+ convert("$$#{s}$$", mime: 'text/latex')
66
20
  end
67
21
 
68
22
  def self.html(s)
69
- MimeString.new('text/html', s)
23
+ convert(s, mime: 'text/html')
24
+ end
25
+
26
+ def self.javascript(s)
27
+ convert(s, mime: 'application/javascript')
28
+ end
29
+
30
+ def self.svg(s)
31
+ convert(s, mime: 'image/svg+xml')
70
32
  end
71
33
  end
data/lib/iruby/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module IRuby
2
- VERSION = '0.1.11'
2
+ VERSION = '0.1.12'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Damián Silvani
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-07-08 00:00:00.000000000 Z
15
+ date: 2014-08-01 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rake
@@ -106,6 +106,7 @@ files:
106
106
  - lib/iruby/backend.rb
107
107
  - lib/iruby/command.rb
108
108
  - lib/iruby/display.rb
109
+ - lib/iruby/formatter.rb
109
110
  - lib/iruby/kernel.rb
110
111
  - lib/iruby/ostream.rb
111
112
  - lib/iruby/session.rb