mathematical 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 020b6daf960edb5a9e5436aef6fa8c406188896c
4
- data.tar.gz: ac15939f237b1086ed76ab8cd36fd55b7cb261e5
3
+ metadata.gz: f7920616d037c8cdab3ade36bceda055362a6de9
4
+ data.tar.gz: a6d2688b1275203704cf01146a952ee7391c4d76
5
5
  SHA512:
6
- metadata.gz: 9f73b02d173514430ff94664fa28e2b2d7cdfd863556796b399c3ee590a97a1904ab9f119b13ea617a677a47bde1351d7c5a4bbcd069d8732ffa097b46a418f9
7
- data.tar.gz: 773a25ece459f013a69554c33018f2be6530ffc0e31d6b821a89690d5a652d84286e51697037b69887c09a682c50669927ff0ee4252cbf29fda3dad301a939df
6
+ metadata.gz: 54a36429dd2a1bd98712ee5a194ef07396a8b76404894d9d3260ca0597b46896a86c97ab6f6664887c15c101dac1c49417880745c55c97ded3672e61390dbb2c
7
+ data.tar.gz: 51fdd320022dd0555be2a3141b7a2de65d5c7c076bd441565da36a61e3ba2a77f172e479e104367b268c3983cd362e170f7dda48a1624971d95bc0ff30b94890
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Quickly convert math equations into beautiful SVGs (or PNGs/MathML).
4
4
 
5
- [![Build Status](https://travis-ci.org/gjtorikian/mathematical.svg?branch=master)](https://travis-ci.org/gjtorikian/mathematical)
5
+ [![Build Status](https://travis-ci.org/gjtorikian/mathematical.svg?branch=master)](https://travis-ci.org/gjtorikian/mathematical) [![Gem Version](https://badge.fury.io/rb/mathematical.svg)](http://badge.fury.io/rb/mathematical)
6
6
 
7
7
  ![Mathematical](https://i.imgur.com/JC7HT32.gif)
8
8
 
@@ -35,15 +35,18 @@ Mathematical.new.render(string_with_math)
35
35
  The output will be a hash, with keys that depend on the format you want:
36
36
 
37
37
  * If you asked for an SVG, you'll get:
38
- * `width`: the width of the resulting image
39
- * `height`: the height of the resulting image
40
- * `svg`: the actual string of SVG
38
+ * `:width`: the width of the resulting image
39
+ * `:height`: the height of the resulting image
40
+ * `:data`: the actual string of SVG
41
41
  * If you asked for a PNG, you'll get:
42
- * `width`: the width of the resulting image
43
- * `height`: the height of the resulting image
44
- * `png`: the PNG data
42
+ * `:width`: the width of the resulting image
43
+ * `:height`: the height of the resulting image
44
+ * `:data`: the PNG data
45
45
  * If you asked for MathML, you'll get:
46
- * `mathml`: the MathML data
46
+ * `:data`: the MathML data
47
+ * If you pass in invalid LaTeX, you'll get:
48
+ * `:data`: the original invalid LaTeX
49
+ * `:error`: the error class (with message)
47
50
 
48
51
  **Note**: If you pass in invalid LaTeX, an error is not raised, but a message *is* printed to STDERR, and the original string is returned (not a hash).
49
52
 
@@ -60,10 +63,7 @@ inputs << '$c$'
60
63
  Mathematical.new.render(inputs)
61
64
  ```
62
65
 
63
- This returns an array of hashes, possessing the same keys as above.
64
-
65
- **Note**: With an array, it is possible to receive elements that are not hashes. For example, given the following input:
66
-
66
+ This returns an array of hashes, possessing the same keys as above. For example:
67
67
  ```
68
68
  array = ['$foof$', '$not__thisisnotreal$', '$poof$']
69
69
  ```
@@ -72,10 +72,10 @@ You will receive the following output:
72
72
 
73
73
  ```
74
74
  Mathematical.new.render(array)
75
- [ {:svg => "...", :width => ... }, '$not__thisisnotreal$', {:svg => "...", :width => ... }]
75
+ [ {:data => "...", :width => ... }, { :data => '$not__thisisnotreal$', :error => "...", {:data => "...", :width => ... }]
76
76
  ```
77
77
 
78
- That is, while the first and last elements are valid LaTeX math, the middle one is not, so the same string is returned. As with a single string, a message is also printed to STDERR.
78
+ That is, while the first and last elements are valid LaTeX math, the middle one is not, so the same string is returned. As with single strings, a message is also printed to STDERR.
79
79
 
80
80
  ### Options
81
81
 
@@ -76,10 +76,20 @@ void print_and_raise(VALUE error_type, const char* format, ...)
76
76
  va_end(args);
77
77
  }
78
78
 
79
+ static VALUE process_rescue(VALUE args, VALUE exception_object)
80
+ {
81
+ VALUE rescue_hash = rb_hash_new();
82
+
83
+ rb_hash_aset (rescue_hash, CSTR2SYM ("data"), args);
84
+ rb_hash_aset (rescue_hash, CSTR2SYM ("exception"), exception_object);
85
+
86
+ return rescue_hash;
87
+ }
88
+
79
89
  VALUE process(VALUE self, unsigned long maxsize, const char *latex_code, unsigned long latex_size)
80
90
  {
81
91
  if (latex_size > maxsize) {
82
- print_and_raise(rb_eMaxsizeError, "Size of latex string (%lu) is greater than the maxsize (%lu)!", latex_size, maxsize);
92
+ print_and_raise(rb_eMaxsizeError, "Size of latex string is greater than the maxsize");
83
93
  }
84
94
 
85
95
  VALUE result_hash = rb_hash_new();
@@ -87,7 +97,7 @@ VALUE process(VALUE self, unsigned long maxsize, const char *latex_code, unsigne
87
97
 
88
98
  // convert the LaTeX math to MathML
89
99
  char * mathml = lsm_mtex_to_mathml(latex_code, latex_size, global_start);
90
- if (mathml == NULL) { print_and_raise(rb_eParseError, "Failed to parse mtex: %s", latex_code); }
100
+ if (mathml == NULL) { print_and_raise(rb_eParseError, "Failed to parse mtex"); }
91
101
 
92
102
  // basically, only update the next equation counter if the last math had a numbered equation
93
103
  if (strstr(mathml, "<mlabeledtr>") != NULL) {
@@ -95,7 +105,7 @@ VALUE process(VALUE self, unsigned long maxsize, const char *latex_code, unsigne
95
105
  }
96
106
 
97
107
  if (format == FORMAT_MATHML) {
98
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("mathml"), rb_str_new2(mathml));
108
+ rb_hash_aset (result_hash, CSTR2SYM ("data"), rb_str_new2(mathml));
99
109
  mtex2MML_free_string(mathml);
100
110
  return result_hash;
101
111
  }
@@ -157,12 +167,12 @@ VALUE process(VALUE self, unsigned long maxsize, const char *latex_code, unsigne
157
167
  switch (format) {
158
168
  case FORMAT_SVG: {
159
169
  if (rb_iv_get(self, "@svg") == Qnil) { print_and_raise(rb_eDocumentReadError, "Failed to read SVG contents"); }
160
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("svg"), rb_iv_get(self, "@svg"));
170
+ rb_hash_aset (result_hash, CSTR2SYM ("data"), rb_iv_get(self, "@svg"));
161
171
  break;
162
172
  }
163
173
  case FORMAT_PNG: {
164
174
  if (rb_iv_get(self, "@png") == Qnil) { print_and_raise(rb_eDocumentReadError, "Failed to read PNG contents"); }
165
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("png"), rb_iv_get(self, "@png"));
175
+ rb_hash_aset (result_hash, CSTR2SYM ("data"), rb_iv_get(self, "@png"));
166
176
  break;
167
177
  }
168
178
  default: {
@@ -172,8 +182,8 @@ VALUE process(VALUE self, unsigned long maxsize, const char *latex_code, unsigne
172
182
  }
173
183
  }
174
184
 
175
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("width"), INT2FIX(width_pt));
176
- rb_hash_aset (result_hash, rb_tainted_str_new2 ("height"), INT2FIX(height_pt));
185
+ rb_hash_aset (result_hash, CSTR2SYM ("width"), INT2FIX(width_pt));
186
+ rb_hash_aset (result_hash, CSTR2SYM ("height"), INT2FIX(height_pt));
177
187
 
178
188
  // we need to clear out this key when attempting multiple calls. See http://git.io/i1hblQ
179
189
  rb_iv_set(self, "@svg", Qnil);
@@ -189,11 +199,6 @@ static VALUE process_helper(VALUE data)
189
199
  return process(args[0], NUM2ULONG(args[1]), StringValueCStr(args[2]), NUM2ULONG(args[3]));
190
200
  }
191
201
 
192
- static VALUE process_failed(void)
193
- {
194
- return Qnil;
195
- }
196
-
197
202
  static VALUE MATHEMATICAL_process(VALUE self, VALUE rb_Input)
198
203
  {
199
204
  unsigned long maxsize = (unsigned long) FIX2INT(rb_iv_get(self, "@maxsize"));
@@ -241,14 +246,9 @@ static VALUE MATHEMATICAL_process(VALUE self, VALUE rb_Input)
241
246
  args[1] = ULONG2NUM(maxsize);
242
247
  args[2] = math;
243
248
  args[3] = ULONG2NUM(latex_size);
244
- hash = rb_rescue(process_helper, args, process_failed, 0);
245
-
246
- // the call errored; just store the same string
247
- if (hash == Qnil) {
248
- rb_ary_store(output, i, math);
249
- } else {
250
- rb_ary_store(output, i, hash);
251
- }
249
+ hash = rb_rescue(process_helper, args, process_rescue, math);
250
+
251
+ rb_ary_store(output, i, hash);
252
252
  }
253
253
  break;
254
254
  }
data/lib/mathematical.rb CHANGED
@@ -34,13 +34,13 @@ class Mathematical
34
34
  maths = validate_content(maths)
35
35
 
36
36
  begin
37
- data = @processer.process(maths)
38
- fail RuntimeError if data.nil? || (!data.is_a?(Hash) && !data.is_a?(Array))
37
+ result_data = @processer.process(maths)
38
+ fail RuntimeError if result_data.nil? || (!result_data.is_a?(Hash) && !result_data.is_a?(Array))
39
39
 
40
- if data.is_a? Array
41
- data.map { |d| format_data(d) }
40
+ if result_data.is_a? Array
41
+ result_data.map { |d| format_data(d) }
42
42
  else
43
- format_data(data)
43
+ format_data(result_data)
44
44
  end
45
45
  rescue ParseError, DocumentCreationError, DocumentReadError => e
46
46
  # an error in the C code, probably a bad TeX parse
@@ -96,19 +96,19 @@ class Mathematical
96
96
  maths =~ /\A\${1,2}/
97
97
  end
98
98
 
99
- def format_data(data)
99
+ def format_data(result_hash)
100
100
  # we passed in an array of math, and found an unprocessable element
101
- return data unless data.is_a? Hash
101
+ return result_hash if result_hash[:exception]
102
102
 
103
103
  case @config[:format]
104
104
  when :svg
105
105
  # remove starting <?xml...> tag
106
- data['svg'] = data['svg'][XML_HEADER.length..-1]
107
- data['svg'] = svg_to_base64(data['svg']) if @config[:base64]
106
+ result_hash[:data] = result_hash[:data][XML_HEADER.length..-1]
107
+ result_hash[:data] = svg_to_base64(result_hash[:data]) if @config[:base64]
108
108
 
109
- data
109
+ result_hash
110
110
  when :png, :mathml # do nothing with these...for now?
111
- data
111
+ result_hash
112
112
  end
113
113
  end
114
114
 
@@ -1,3 +1,3 @@
1
1
  class Mathematical
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -9,7 +9,7 @@ class Mathematical::BasicTest < Test::Unit::TestCase
9
9
  def test_multiple_calls
10
10
  render = Mathematical.new
11
11
  render.render('$\pi$')
12
- output = render.render('$\pi$')['svg']
12
+ output = render.render('$\pi$')[:data]
13
13
  assert_equal 1, output.scan(/<svg/).size, 'should only contain one svg'
14
14
  end
15
15
 
@@ -18,14 +18,14 @@ class Mathematical::FixturesTest < Test::Unit::TestCase
18
18
  svg_content = Mathematical.new(:base64 => false).render(eq)
19
19
  # remove \ and $, remove whitespace, keep alphanums, remove extraneous - and trailing -
20
20
  filename = eq.gsub(/[\$\\]*/, '').gsub(/\s+/, '-').gsub(/[^a-zA-Z\d]/, '-').gsub(/-{2,}/, '-').gsub(/-$/, '')
21
- File.open("samples/fixtures/#{filename}.svg", 'w') { |file| file.write svg_content['svg'] }
21
+ File.open("samples/fixtures/#{filename}.svg", 'w') { |file| file.write svg_content[:data] }
22
22
  end
23
23
  end
24
24
 
25
25
  actual = MathToItex(source).convert do |eq, type|
26
26
  svg_content = Mathematical.new(:base64 => true).render(eq)
27
27
 
28
- %|<img class="#{type.to_s}-math" data-math-type="#{type.to_s}-math" src="#{svg_content['svg']}"/>|
28
+ %(<img class="#{type}-math" data-math-type="#{type}-math" src="#{svg_content[:data]}"/>)
29
29
  end.rstrip
30
30
 
31
31
  expected_file = before.sub(/before/, 'after').sub(/text/, 'html')
@@ -34,7 +34,7 @@ class Mathematical::FixturesTest < Test::Unit::TestCase
34
34
 
35
35
  expected = File.read(expected_file)
36
36
 
37
- expected = (MathToItex(expected).convert {|string| Mathematical.new.render(string)}).rstrip
37
+ expected = (MathToItex(expected).convert { |string| Mathematical.new.render(string) }).rstrip
38
38
 
39
39
  # Travis and OS X each render SVGs differently. For now, let's just be happy
40
40
  # that something renders at all.
@@ -109,8 +109,30 @@ class Mathematical::MaliciousnessTest < Test::Unit::TestCase
109
109
  assert_equal 3, output.length
110
110
  assert_equal Hash, output.first.class
111
111
  assert_equal Hash, output.last.class
112
- assert_equal '$/this___istotallyfake$', output[1]
113
- # array errors output to STDERR
114
- assert_match /Failed to parse mtex: \$\/this___istotallyfake\$/, err
112
+
113
+ assert_equal '$/this___istotallyfake$', output[1][:data]
114
+ assert_equal Mathematical::ParseError, output[1][:exception].class
115
+ assert_match 'Failed to parse mtex', output[1][:exception].message
116
+
117
+ # array errors also output to STDERR
118
+ assert_match /Failed to parse mtex/, err
119
+ end
120
+
121
+ def test_it_passes_a_legible_error_for_maxsize
122
+ output = nil
123
+ render = Mathematical.new({:maxsize => 2})
124
+
125
+ _, err = capture_subprocess_io do
126
+ output = render.render(['$a \ne b$'])
127
+ end
128
+
129
+ assert_equal 1, output.length
130
+
131
+ assert_equal '$a \ne b$', output[0][:data]
132
+ assert_equal Mathematical::MaxsizeError, output[0][:exception].class
133
+ assert_match 'Size of latex string is greater than the maxsize', output[0][:exception].message
134
+
135
+ # array errors also output to STDERR
136
+ assert_match /Size of latex string is greater than the maxsize/, err
115
137
  end
116
138
  end
@@ -16,7 +16,7 @@ class Mathematical::MathJaxTest < Test::Unit::TestCase
16
16
  assert_nothing_raised { data = render_svg.render(tex_contents) }
17
17
 
18
18
  # assert the SVG actually rendered
19
- doc = Nokogiri::HTML(data['svg'])
19
+ doc = Nokogiri::HTML(data[:data])
20
20
  assert_empty doc.search(%(//svg[@width='0pt']))
21
21
  assert_empty doc.search(%(//svg[@height='0pt']))
22
22
  end
@@ -14,7 +14,7 @@ class Mathematical::MathMLTest < Test::Unit::TestCase
14
14
  $$
15
15
  '''
16
16
  render = Mathematical.new({:format => :mathml})
17
- mathml = render.render(string)['mathml']
17
+ mathml = render.render(string)[:data]
18
18
 
19
19
  assert_match %r{<math xmlns='http://www.w3.org/1998/Math/MathML' display='block'><semantics><mrow><mrow><mo>\(}, mathml
20
20
  end
@@ -16,7 +16,7 @@ $$
16
16
  '''
17
17
 
18
18
  output = @render.render([string])
19
- svg = output.first['svg']
19
+ svg = output.first[:data]
20
20
 
21
21
  assert_equal 1, svg.scan(/svg\+xml;/).size, 'should only contain one svg'
22
22
  assert_match 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My', svg
@@ -38,13 +38,13 @@ $$
38
38
  output = @render.render(inputs)
39
39
  assert_equal 1000, output.length
40
40
  output.each do |data|
41
- assert_match 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My', data['svg']
41
+ assert_match 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My', data[:data]
42
42
  end
43
43
  end
44
44
 
45
45
  def test_it_properly_accounts_for_equations
46
46
  inputs = []
47
- [1, 2].each do |i|
47
+ (1..2).each do |i|
48
48
  string = """
49
49
  $$
50
50
  \\begin{equation}
@@ -60,8 +60,8 @@ $$
60
60
  output = render.render(inputs)
61
61
  assert_equal 3, output.length
62
62
  output.each_with_index do |data_hash, i|
63
- header = data_hash['png'].unpack('H*').first.slice(0, 18)
64
- File.open("#{fixtures_dir}/png/numeric_test_#{i + 1}.png", 'w') { |f| f.write(data_hash['png'])}
63
+ header = data_hash[:data].unpack('H*').first.slice(0, 18)
64
+ File.open("#{fixtures_dir}/png/numeric_test_#{i + 1}.png", 'w') { |f| f.write(data_hash[:data])}
65
65
  assert_equal header, '89504e470d0a1a0a00'
66
66
  end
67
67
  end
@@ -18,8 +18,8 @@ $$
18
18
  '''
19
19
  render = Mathematical.new({:format => :png})
20
20
  data_hash = render.render(string)
21
- header = data_hash['png'].unpack('H*').first.slice(0, 18)
22
- File.open("#{fixtures_dir}/png/pmatrix.png", 'w') { |f| f.write(data_hash['png'])}
21
+ header = data_hash[:data].unpack('H*').first.slice(0, 18)
22
+ File.open("#{fixtures_dir}/png/pmatrix.png", 'w') { |f| f.write(data_hash[:data])}
23
23
  assert_equal header, '89504e470d0a1a0a00'
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mathematical
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian