iruby 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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