html2doc 0.8.7 → 0.8.8

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
  SHA256:
3
- metadata.gz: 8b4a4257cfea9d3621715b98d906f8eb0ffdc7ce49f38b732dc2aada2e7bf122
4
- data.tar.gz: a767085867c7dc1eb105e90eeb221ba4c89383dad79a61615df7e03615f890fb
3
+ metadata.gz: c88de00bdeb2cbb88460c403e03cd10d623fb1152371129a6b9cf90c2f664a02
4
+ data.tar.gz: 0c61af5fa5eb93dcc4730328055b0914dfe03de8794909779c6d99e1308a0a22
5
5
  SHA512:
6
- metadata.gz: 0d47018c5d6c3d9432f860485994462cfc6634d487de4a72375df7974b9af51d0409c5ac0bdc1ffcac585c51fc329b5d39cb4c1e6810821ba6489dfbd4b4e557
7
- data.tar.gz: 5067f79bb2dca4836021d960d807a9ec81a97b5ec3545588fe60120e98d2d46f26665f7a5ac0c6ffd5bed50e7f858017f1fd6677edd8e10958240afae11c23bc
6
+ metadata.gz: 73ddb8e6c7e4505df3127737c4302a364c1ade83b18c55274c7e0bc34a3640cbc5e4d02cd94eca0cd72eb6f2c505ee6b701388eaadbb1b45969d543df15b778d
7
+ data.tar.gz: 15556cf840a5fe4de804e5de8d0eb0f23d470d1a7e620814e8e0a15239e8efba761be31601ea5d1a30cf806c9740eabe2ac9a8ae1382ebad158562a7c1081420
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- html2doc (0.8.7)
5
- asciimath
4
+ html2doc (0.8.8)
5
+ asciimath (~> 1.0.7)
6
6
  htmlentities (~> 4.3.4)
7
7
  image_size
8
8
  mime-types
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency "thread_safe"
33
33
  spec.add_dependency "uuidtools"
34
34
  spec.add_dependency "ruby-xslt"
35
- spec.add_dependency "asciimath"
35
+ spec.add_dependency "asciimath", "~> 1.0.7"
36
36
 
37
37
  spec.add_development_dependency "bundler", "~> 2.0.1"
38
38
  spec.add_development_dependency "byebug", "~> 9.1"
@@ -88,6 +88,7 @@ module Html2Doc
88
88
  next unless i.element? && %w(img v:imagedata).include?(i.name)
89
89
  warnsvg(i["src"])
90
90
  next if /^http/.match i["src"]
91
+ next if %r{^data:image/[^;]+;base64}.match i["src"]
91
92
  local_filename = File.join(localdir, i["src"])
92
93
  new_filename = "#{mkuuid}#{File.extname(i["src"])}"
93
94
  FileUtils.cp local_filename, File.join(dir, new_filename)
@@ -106,7 +107,8 @@ module Html2Doc
106
107
  end
107
108
 
108
109
  def self.header_image_cleanup1(a, dir, filename, localdir)
109
- if a.size == 2 && !(/ src="https?:/.match a[1])
110
+ if a.size == 2 && !(/ src="https?:/.match a[1]) &&
111
+ !(%r{ src="data:image/[^;]+;base64}.match a[1])
110
112
  m = / src=['"](?<src>[^"']+)['"]/.match a[1]
111
113
  warnsvg(m[:src])
112
114
  m2 = /\.(?<suffix>\S+)$/.match m[:src]
@@ -1,3 +1,3 @@
1
1
  module Html2Doc
2
- VERSION = "0.8.7".freeze
2
+ VERSION = "0.8.8".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html2doc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.7
4
+ version: 0.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -112,16 +112,16 @@ dependencies:
112
112
  name: asciimath
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ">="
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0'
117
+ version: 1.0.7
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ">="
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0'
124
+ version: 1.0.7
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: bundler
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -306,11 +306,6 @@ files:
306
306
  - bin/rspec
307
307
  - bin/setup
308
308
  - html2doc.gemspec
309
- - lib/asciimath/cli.rb
310
- - lib/asciimath/html.rb
311
- - lib/asciimath/mathml.rb
312
- - lib/asciimath/parser.rb
313
- - lib/asciimath/version.rb
314
309
  - lib/html2doc.rb
315
310
  - lib/html2doc/base.rb
316
311
  - lib/html2doc/lists.rb
@@ -1,18 +0,0 @@
1
- require_relative 'parser'
2
- require_relative 'mathml'
3
- require_relative 'html'
4
-
5
- module AsciiMath
6
- module CLI
7
- def self.run(args)
8
- asciimath = args.last
9
- output = ''
10
- if args.length == 1 || args.first == "mathml"
11
- output = AsciiMath.parse(asciimath).to_mathml
12
- elsif args.first == "html"
13
- output = AsciiMath.parse(asciimath).to_html
14
- end
15
- puts output
16
- end
17
- end
18
- end
@@ -1,222 +0,0 @@
1
- module AsciiMath
2
- class HTMLBuilder
3
- def initialize(prefix)
4
- @prefix = prefix
5
- @html = ''
6
- end
7
-
8
- def to_s
9
- @html
10
- end
11
-
12
- def append_expression(expression, inline, attrs = {})
13
- if inline
14
- inline('', attrs) do
15
- append(expression, :single_child => true)
16
- end
17
- else
18
- block('', attrs) do
19
- append(expression, :single_child => true)
20
- end
21
- end
22
- end
23
-
24
- private
25
-
26
- ZWJ = "\u8205"
27
-
28
- def append(expression, opts = {})
29
- case expression
30
- when Array
31
- row do
32
- expression.each { |e| append(e) }
33
- end
34
- when Hash
35
- case expression[:type]
36
- when :operator
37
- operator(expression[:c])
38
- when :identifier
39
- identifier(expression[:c])
40
- when :number
41
- number(expression[:c])
42
- when :text
43
- text(expression[:c])
44
- when :paren
45
- paren = !opts[:strip_paren]
46
- if paren
47
- if opts[:single_child]
48
- brace(expression[:lparen]) if expression[:lparen]
49
- append(expression[:e], :single_child => true)
50
- brace(expression[:rparen]) if expression[:rparen]
51
- else
52
- row do
53
- brace(expression[:lparen]) if expression[:lparen]
54
- append(expression[:e], :single_child => true)
55
- brace(expression[:rparen]) if expression[:rparen]
56
- end
57
- end
58
- else
59
- append(expression[:e])
60
- end
61
- when :font
62
- #TODO - currently ignored
63
- when :unary
64
- operator = expression[:operator]
65
- tag(operator) do
66
- append(expression[:s], :single_child => true, :strip_paren => true)
67
- end
68
- when :binary
69
- operator = expression[:operator]
70
- if operator == :frac
71
- append_fraction(expression[:s1],expression[:s2])
72
- elsif operator == :sub
73
- append_subsup(expression[:s1],expression[:s2],nil)
74
- elsif operator == :sup
75
- append_subsup(expression[:s1],nil,expression[:s2])
76
- elsif operator == :under
77
- append_underover(expression[:s1],expression[:s2],nil)
78
- elsif operator == :over
79
- append_underover(expression[:s1],nil,expression[:s2])
80
- else
81
- tag(operator) do
82
- append(expression[:s1], :strip_paren => true)
83
- append(expression[:s2], :strip_paren => true)
84
- end
85
- end
86
- when :ternary
87
- operator = expression[:operator]
88
- if operator == :subsup
89
- append_subsup(expression[:s1],expression[:s2],expression[:s3])
90
- elsif operator == :underover
91
- # TODO: Handle over/under braces in some way? SVG maybe?
92
- append_underover(expression[:s1],expression[:s2],expression[:s3])
93
- end
94
- when :matrix
95
- row do
96
- # Figures out a font size for the braces, based on the height of the matrix.
97
- # NOTE: This does not currently consider the size of each element within the matrix.
98
- brace_height = "font-size: " + expression[:rows].length.to_s + "00%;"
99
-
100
- if expression[:lparen]
101
- brace(expression[:lparen], {:style => brace_height})
102
- else
103
- blank(ZWJ)
104
- end
105
- matrix_width = "grid-template-columns:repeat(" + expression[:rows][0].length.to_s + ",1fr);"
106
- matrix_height = "grid-template-rows:repeat(" + expression[:rows].length.to_s + ",1fr);"
107
-
108
- matrix({:style => (matrix_width + matrix_height)}) do
109
- expression[:rows].each do |row|
110
- row.each do |col|
111
- row do
112
- append(col)
113
- end
114
- end
115
- end
116
- end
117
- if expression[:rparen]
118
- brace(expression[:rparen], {:style => brace_height})
119
- else
120
- blank(ZWJ)
121
- end
122
- end
123
- end
124
- end
125
- end
126
-
127
- def append_subsup(base, sub, sup)
128
- append(base)
129
- subsup do
130
- if sup
131
- smaller do
132
- append(sup, :strip_paren => true)
133
- end
134
- else
135
- smaller(ZWJ)
136
- end
137
- if sub
138
- smaller do
139
- append(sub, :strip_paren => true)
140
- end
141
- else
142
- smaller(ZWJ)
143
- end
144
- end
145
- end
146
-
147
- def append_underover(base, under, over)
148
- blank(ZWJ)
149
- underover do
150
- smaller do
151
- if over
152
- append(over, :strip_paren => true)
153
- else
154
- blank(ZWJ)
155
- end
156
- end
157
- append(base)
158
- smaller do
159
- if under
160
- append(under, :strip_paren => true)
161
- else
162
- blank(ZWJ)
163
- end
164
- end
165
- end
166
- end
167
-
168
- def append_fraction(numerator, denominator)
169
- blank(ZWJ)
170
- fraction do
171
- fraction_row do
172
- fraction_cell do
173
- smaller do
174
- row do
175
- append(numerator, :strip_paren => true)
176
- end
177
- end
178
- end
179
- end
180
- fraction_row do
181
- fraction_cell do
182
- smaller do
183
- row do
184
- append(denominator, :strip_paren => true)
185
- end
186
- end
187
- end
188
- end
189
- end
190
- end
191
-
192
- def method_missing(meth, *args, &block)
193
- tag(meth, *args, &block)
194
- end
195
-
196
- def tag(tag, *args)
197
- attrs = args.last.is_a?(Hash) ? args.pop : {}
198
- text = args.last.is_a?(String) ? args.pop : ''
199
-
200
- @html << '<span class="math-' << @prefix << tag.to_s << '"'
201
-
202
- attrs.each_pair do |key, value|
203
- @html << ' ' << key.to_s << '="' << value.to_s << '"'
204
- end
205
-
206
- if block_given? || text
207
- @html << '>'
208
- @html << text.encode(Encoding::US_ASCII, :xml => :text) if text
209
- yield if block_given?
210
- @html << '</span>'
211
- else
212
- @html << '/>'
213
- end
214
- end
215
- end
216
-
217
- class Expression
218
- def to_html(prefix = "", inline = true, attrs = {})
219
- HTMLBuilder.new(prefix).append_expression(@parsed_expression, inline, attrs).to_s
220
- end
221
- end
222
- end
@@ -1,131 +0,0 @@
1
- module AsciiMath
2
- class MathMLBuilder
3
- def initialize(prefix)
4
- @prefix = prefix
5
- @mathml = ''
6
- end
7
-
8
- def to_s
9
- @mathml
10
- end
11
-
12
- def append_expression(expression, attrs = {})
13
- math('', attrs) do
14
- append(expression, :single_child => true)
15
- end
16
- end
17
-
18
- private
19
-
20
- def append(expression, opts = {})
21
- case expression
22
- when Array
23
- if expression.length <= 1 || opts[:single_child]
24
- expression.each { |e| append(e) }
25
- else
26
- mrow do
27
- expression.each { |e| append(e) }
28
- end
29
- end
30
- when Hash
31
- case expression[:type]
32
- when :operator
33
- mo(expression[:c])
34
- when :identifier
35
- mi(expression[:c])
36
- when :number
37
- mn(expression[:c])
38
- when :text
39
- mtext(expression[:c])
40
- when :paren
41
- paren = !opts[:strip_paren]
42
- if paren
43
- if opts[:single_child]
44
- mo(expression[:lparen]) if expression[:lparen]
45
- append(expression[:e], :single_child => true)
46
- mo(expression[:rparen]) if expression[:rparen]
47
- else
48
- mrow do
49
- mo(expression[:lparen]) if expression[:lparen]
50
- append(expression[:e], :single_child => true)
51
- mo(expression[:rparen]) if expression[:rparen]
52
- end
53
- end
54
- else
55
- append(expression[:e])
56
- end
57
- when :font
58
- style = expression[:operator]
59
- tag("mstyle", :mathvariant => style.to_s.gsub('_', '-')) do
60
- append(expression[:s], :single_child => true, :strip_paren => true)
61
- end
62
- when :unary
63
- operator = expression[:operator]
64
- tag("m#{operator}") do
65
- append(expression[:s], :single_child => true, :strip_paren => true)
66
- end
67
- when :binary
68
- operator = expression[:operator]
69
- tag("m#{operator}") do
70
- append(expression[:s1], :strip_paren => (operator != :sub && operator != :sup))
71
- append(expression[:s2], :strip_paren => true)
72
- end
73
- when :ternary
74
- operator = expression[:operator]
75
- tag("m#{operator}") do
76
- append(expression[:s1])
77
- append(expression[:s2], :strip_paren => true)
78
- append(expression[:s3], :strip_paren => true)
79
- end
80
- when :matrix
81
- mrow do
82
- mo(expression[:lparen]) if expression[:lparen]
83
- mtable do
84
- expression[:rows].each do |row|
85
- mtr do
86
- row.each do |col|
87
- mtd do
88
- append(col)
89
- end
90
- end
91
- end
92
- end
93
- end
94
- mo(expression[:rparen]) if expression[:rparen]
95
- end
96
- end
97
- end
98
- end
99
-
100
- def method_missing(meth, *args, &block)
101
- tag(meth, *args, &block)
102
- end
103
-
104
- def tag(tag, *args)
105
- attrs = args.last.is_a?(Hash) ? args.pop : {}
106
- text = args.last.is_a?(String) ? args.pop : ''
107
-
108
- @mathml << '<' << @prefix << tag.to_s
109
-
110
- attrs.each_pair do |key, value|
111
- @mathml << ' ' << key.to_s << '="' << value.to_s << '"'
112
- end
113
-
114
-
115
- if block_given? || text
116
- @mathml << '>'
117
- @mathml << text.encode(Encoding::US_ASCII, :xml => :text) if text
118
- yield self if block_given?
119
- @mathml << '</' << @prefix << tag.to_s << '>'
120
- else
121
- @mathml << '/>'
122
- end
123
- end
124
- end
125
-
126
- class Expression
127
- def to_mathml(prefix = "", attrs = {})
128
- MathMLBuilder.new(prefix).append_expression(@parsed_expression, attrs).to_s
129
- end
130
- end
131
- end
@@ -1,591 +0,0 @@
1
- require 'strscan'
2
-
3
- # Parser for ASCIIMath expressions.
4
- #
5
- # The syntax for ASCIIMath in EBNF style notation is
6
- #
7
- # expr = ( simp ( fraction | sub | super ) )+
8
- # simp = constant | paren_expr | unary_expr | binary_expr | text
9
- # fraction = '/' simp
10
- # super = '^' simp
11
- # sub = '_' simp super?
12
- # paren_expr = lparen expr rparen
13
- # lparen = '(' | '[' | '{' | '(:' | '{:'
14
- # rparen = ')' | ']' | '}' | ':)' | ':}'
15
- # unary_expr = unary_op simp
16
- # unary_op = 'sqrt' | 'text'
17
- # binary_expr = binary_op simp simp
18
- # binary_op = 'frac' | 'root' | 'stackrel'
19
- # text = '"' [^"]* '"'
20
- # constant = number | symbol | identifier
21
- # number = '-'? [0-9]+ ( '.' [0-9]+ )?
22
- # symbol = /* any string in the symbol table */
23
- # identifier = [A-z]
24
- #
25
- # ASCIIMath is parsed left to right without any form of operator precedence.
26
- # When parsing the 'constant' the parser will try to find the longest matching string in the symbol
27
- # table starting at the current position of the parser. If no matching string can be found the
28
- # character at the current position of the parser is interpreted as an identifier instead.
29
- module AsciiMath
30
- # Internal: Splits an ASCIIMath expression into a sequence of tokens.
31
- # Each token is represented as a Hash containing the keys :value and :type.
32
- # The :value key is used to store the text associated with each token.
33
- # The :type key indicates the semantics of the token. The value for :type will be one
34
- # of the following symbols:
35
- #
36
- # - :identifier a symbolic name or a bit of text without any further semantics
37
- # - :text a bit of arbitrary text
38
- # - :number a number
39
- # - :operator a mathematical operator symbol
40
- # - :unary a unary operator (e.g., sqrt, text, ...)
41
- # - :font a unary font command (e.g., bb, cc, ...)
42
- # - :infix an infix operator (e.g, /, _, ^, ...)
43
- # - :binary a binary operator (e.g., frac, root, ...)
44
- # - :accent an accent character
45
- # - :eof indicates no more tokens are available
46
- #
47
- # Each token type may also have an :underover modifier. When present and set to true
48
- # sub- and superscript expressions associated with the token will be rendered as
49
- # under- and overscriptabove and below rather than as sub- or superscript.
50
- #
51
- # :accent tokens additionally have a :postion value which is set to either :over or :under.
52
- # This determines if the accent should be rendered over or under the expression to which
53
- # it applies.
54
- #
55
- class Tokenizer
56
- WHITESPACE = /^\s+/
57
- NUMBER = /-?[0-9]+(?:\.[0-9]+)?/
58
- QUOTED_TEXT = /"[^"]*"/
59
- TEX_TEXT = /text\([^)]*\)/
60
-
61
- # Public: Initializes an ASCIIMath tokenizer.
62
- #
63
- # string - The ASCIIMath expression to tokenize
64
- # symbols - The symbol table to use while tokenizing
65
- def initialize(string, symbols)
66
- @string = StringScanner.new(string)
67
- @symbols = symbols
68
- lookahead = @symbols.keys.map { |k| k.length }.max
69
- @symbol_regexp = /([^\s0-9]{1,#{lookahead}})/
70
- @push_back = nil
71
- end
72
-
73
- # Public: Read the next token from the ASCIIMath expression and move the tokenizer
74
- # ahead by one token.
75
- #
76
- # Returns the next token as a Hash
77
- def next_token
78
- if @push_back
79
- t = @push_back
80
- @push_back = nil
81
- return t
82
- end
83
-
84
- @string.scan(WHITESPACE)
85
-
86
- return {:value => nil, :type => :eof} if @string.eos?
87
-
88
- case @string.peek(1)
89
- when '"'
90
- read_quoted_text
91
- when 't'
92
- case @string.peek(5)
93
- when 'text('
94
- read_tex_text
95
- else
96
- read_symbol
97
- end
98
- when '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
99
- read_number || read_symbol
100
- else
101
- read_symbol
102
- end
103
- end
104
-
105
- # Public: Pushes the given token back to the tokenizer. A subsequent call to next_token
106
- # will return the given token rather than generating a new one. At most one
107
- # token can be pushed back.
108
- #
109
- # token - The token to push back
110
- def push_back(token)
111
- @push_back = token unless token[:type] == :eof
112
- end
113
-
114
- private
115
-
116
- # Private: Reads a text token from the input string
117
- #
118
- # Returns the text token or nil if a text token could not be matched at
119
- # the current position
120
- def read_quoted_text
121
- read_value(QUOTED_TEXT) do |text|
122
- {:value => text[1..-2], :type => :text}
123
- end
124
- end
125
-
126
- # Private: Reads a text token from the input string
127
- #
128
- # Returns the text token or nil if a text token could not be matched at
129
- # the current position
130
- def read_tex_text
131
- read_value(TEX_TEXT) do |text|
132
- {:value => text[5..-2], :type => :text}
133
- end
134
- end
135
-
136
- # Private: Reads a number token from the input string
137
- #
138
- # Returns the number token or nil if a number token could not be matched at
139
- # the current position
140
- def read_number
141
- read_value(NUMBER) do |number|
142
- {:value => number, :type => :number}
143
- end
144
- end
145
-
146
- if String.method_defined?(:bytesize)
147
- def bytesize(s)
148
- s.bytesize
149
- end
150
- else
151
- def bytesize(s)
152
- s.length
153
- end
154
- end
155
-
156
-
157
- # Private: Reads a symbol token from the input string. This method first creates
158
- # a String from the input String starting from the current position with a length
159
- # that matches that of the longest key in the symbol table. It then looks up that
160
- # substring in the symbol table. If the substring is present in the symbol table, the
161
- # associated value is returned and the position is moved ahead by the length of the
162
- # substring. Otherwise this method chops one character off the end of the substring
163
- # and repeats the symbol lookup. This continues until a single character is left.
164
- # If that character can still not be found in the symbol table, then an identifier
165
- # token is returned whose value is the remaining single character string.
166
- #
167
- # Returns the token that was read or nil if a token could not be matched at
168
- # the current position
169
- def read_symbol
170
- position = @string.pos
171
- read_value(@symbol_regexp) do |s|
172
- until s.length == 1 || @symbols.include?(s)
173
- s.chop!
174
- end
175
- @string.pos = position + bytesize(s)
176
- @symbols[s] || {:value => s, :type => :identifier}
177
- end
178
- end
179
-
180
- # Private: Reads a String from the input String that matches the given RegExp
181
- #
182
- # regexp - a RegExp that will be used to match the token
183
- # block - if a block is provided the matched token will be passed to the block
184
- #
185
- # Returns the matched String or the value returned by the block if one was given
186
- def read_value(regexp)
187
- s = @string.scan(regexp)
188
- if s
189
- yield s
190
- else
191
- s
192
- end
193
- end
194
-
195
- if String.respond_to?(:byte_size)
196
- def byte_size(s)
197
- s.byte_size
198
- end
199
- end
200
- end
201
-
202
- class Parser
203
- SYMBOLS = {
204
- # Operation symbols
205
- '+' => {:value => '+', :type => :operator},
206
- '-' => {:value => "\u2212", :type => :operator},
207
- '*' => {:value => "\u22C5", :type => :operator},
208
- '**' => {:value => "\u002A", :type => :operator},
209
- '***' => {:value => "\u22C6", :type => :operator},
210
- '//' => {:value => '/', :type => :operator},
211
- '\\\\' => {:value => '\\', :type => :operator},
212
- 'xx' => {:value => "\u00D7", :type => :operator},
213
- '-:' => {:value => "\u00F7", :type => :operator},
214
- '|><' => {:value => "\u22C9", :type => :operator},
215
- '><|' => {:value => "\u22CA", :type => :operator},
216
- '|><|' => {:value => "\u22C8", :type => :operator},
217
- '@' => {:value => "\u26AC", :type => :operator},
218
- 'o+' => {:value => "\u2295", :type => :operator},
219
- 'ox' => {:value => "\u2297", :type => :operator},
220
- 'o.' => {:value => "\u2299", :type => :operator},
221
- 'sum' => {:value => "\u2211", :type => :operator, :underover => true},
222
- 'prod' => {:value => "\u220F", :type => :operator, :underover => true},
223
- '^^' => {:value => "\u2227", :type => :operator},
224
- '^^^' => {:value => "\u22C0", :type => :operator, :underover => true},
225
- 'vv' => {:value => "\u2228", :type => :operator},
226
- 'vvv' => {:value => "\u22C1", :type => :operator, :underover => true},
227
- 'nn' => {:value => "\u2229", :type => :operator},
228
- 'nnn' => {:value => "\u22C2", :type => :operator, :underover => true},
229
- 'uu' => {:value => "\u222A", :type => :operator},
230
- 'uuu' => {:value => "\u22C3", :type => :operator, :underover => true},
231
-
232
- # Relation symbols
233
- '=' => {:value => '=', :type => :operator},
234
- '!=' => {:value => "\u2260", :type => :operator},
235
- ':=' => {:value => ':=', :type => :operator},
236
- '<' => {:value => "\u003C", :type => :operator},
237
- 'lt' => {:value => "\u003C", :type => :operator},
238
- '>' => {:value => "\u003E", :type => :operator},
239
- 'gt' => {:value => "\u003E", :type => :operator},
240
- '<=' => {:value => "\u2264", :type => :operator},
241
- 'le' => {:value => "\u2264", :type => :operator},
242
- '>=' => {:value => "\u2265", :type => :operator},
243
- 'ge' => {:value => "\u2265", :type => :operator},
244
- '-<' => {:value => "\u227A", :type => :operator},
245
- '>-' => {:value => "\u227B", :type => :operator},
246
- '-<=' => {:value => "\u2AAF", :type => :operator},
247
- '>-=' => {:value => "\u2AB0", :type => :operator},
248
- 'in' => {:value => "\u2208", :type => :operator},
249
- '!in' => {:value => "\u2209", :type => :operator},
250
- 'sub' => {:value => "\u2282", :type => :operator},
251
- 'sup' => {:value => "\u2283", :type => :operator},
252
- 'sube' => {:value => "\u2286", :type => :operator},
253
- 'supe' => {:value => "\u2287", :type => :operator},
254
- '-=' => {:value => "\u2261", :type => :operator},
255
- '~=' => {:value => "\u2245", :type => :operator},
256
- '~~' => {:value => "\u2248", :type => :operator},
257
- 'prop' => {:value => "\u221D", :type => :operator},
258
-
259
- # Logical symbols
260
- 'and' => {:value => 'and', :type => :text},
261
- 'or' => {:value => 'or', :type => :text},
262
- 'not' => {:value => "\u00AC", :type => :operator},
263
- '=>' => {:value => "\u21D2", :type => :operator},
264
- 'if' => {:value => 'if', :type => :operator},
265
- '<=>' => {:value => "\u21D4", :type => :operator},
266
- 'AA' => {:value => "\u2200", :type => :operator},
267
- 'EE' => {:value => "\u2203", :type => :operator},
268
- '_|_' => {:value => "\u22A5", :type => :operator},
269
- 'TT' => {:value => "\u22A4", :type => :operator},
270
- '|--' => {:value => "\u22A2", :type => :operator},
271
- '|==' => {:value => "\u22A8", :type => :operator},
272
-
273
- # Grouping brackets
274
- '(' => {:value => '(', :type => :lparen},
275
- ')' => {:value => ')', :type => :rparen},
276
- '[' => {:value => '[', :type => :lparen},
277
- ']' => {:value => ']', :type => :rparen},
278
- '{' => {:value => '{', :type => :lparen},
279
- '}' => {:value => '}', :type => :rparen},
280
- '(:' => {:value => "\u2329", :type => :lparen},
281
- ':)' => {:value => "\u232A", :type => :rparen},
282
- '<<' => {:value => "\u2329", :type => :lparen},
283
- '>>' => {:value => "\u232A", :type => :rparen},
284
- '|' => {:value => '|', :type => :lrparen},
285
- '||' => {:value => '||', :type => :lrparen},
286
- '{:' => {:value => nil, :type => :lparen},
287
- ':}' => {:value => nil, :type => :rparen},
288
-
289
- # Miscellaneous symbols
290
- 'int' => {:value => "\u222B", :type => :operator},
291
- 'dx' => {:value => 'dx', :type => :identifier},
292
- 'dy' => {:value => 'dy', :type => :identifier},
293
- 'dz' => {:value => 'dz', :type => :identifier},
294
- 'dt' => {:value => 'dt', :type => :identifier},
295
- 'oint' => {:value => "\u222E", :type => :operator},
296
- 'del' => {:value => "\u2202", :type => :operator},
297
- 'grad' => {:value => "\u2207", :type => :operator},
298
- '+-' => {:value => "\u00B1", :type => :operator},
299
- 'O/' => {:value => "\u2205", :type => :operator},
300
- 'oo' => {:value => "\u221E", :type => :operator},
301
- 'aleph' => {:value => "\u2135", :type => :operator},
302
- '...' => {:value => '...', :type => :operator},
303
- ':.' => {:value => "\u2234", :type => :operator},
304
- '/_' => {:value => "\u2220", :type => :operator},
305
- '\\ ' => {:value => "\u00A0", :type => :operator},
306
- 'quad' => {:value => '\u00A0\u00A0', :type => :operator},
307
- 'qquad' => {:value => '\u00A0\u00A0\u00A0\u00A0', :type => :operator},
308
- 'cdots' => {:value => "\u22EF", :type => :operator},
309
- 'vdots' => {:value => "\u22EE", :type => :operator},
310
- 'ddots' => {:value => "\u22F1", :type => :operator},
311
- 'diamond' => {:value => "\u22C4", :type => :operator},
312
- 'square' => {:value => "\u25A1", :type => :operator},
313
- '|__' => {:value => "\u230A", :type => :operator},
314
- '__|' => {:value => "\u230B", :type => :operator},
315
- '|~' => {:value => "\u2308", :type => :operator},
316
- '~|' => {:value => "\u2309", :type => :operator},
317
- 'CC' => {:value => "\u2102", :type => :operator},
318
- 'NN' => {:value => "\u2115", :type => :operator},
319
- 'QQ' => {:value => "\u211A", :type => :operator},
320
- 'RR' => {:value => "\u211D", :type => :operator},
321
- 'ZZ' => {:value => "\u2124", :type => :operator},
322
-
323
- 'lim' => {:value => 'lim', :type => :operator, :underover => true},
324
- 'Lim' => {:value => 'Lim', :type => :operator, :underover => true},
325
-
326
- # Standard functions
327
- 'sin' => {:value => 'sin', :type => :identifier},
328
- 'cos' => {:value => 'cos', :type => :identifier},
329
- 'tan' => {:value => 'tan', :type => :identifier},
330
- 'sec' => {:value => 'sec', :type => :identifier},
331
- 'csc' => {:value => 'csc', :type => :identifier},
332
- 'cot' => {:value => 'cot', :type => :identifier},
333
- 'arcsin' => {:value => 'arcsin', :type => :identifier},
334
- 'arccos' => {:value => 'arccos', :type => :identifier},
335
- 'arctan' => {:value => 'arctan', :type => :identifier},
336
- 'sinh' => {:value => 'sinh', :type => :identifier},
337
- 'cosh' => {:value => 'cosh', :type => :identifier},
338
- 'tanh' => {:value => 'tanh', :type => :identifier},
339
- 'sech' => {:value => 'sech', :type => :identifier},
340
- 'csch' => {:value => 'csch', :type => :identifier},
341
- 'coth' => {:value => 'coth', :type => :identifier},
342
- 'exp' => {:value => 'exp', :type => :identifier},
343
- 'log' => {:value => 'log', :type => :identifier},
344
- 'ln' => {:value => 'ln', :type => :identifier},
345
- 'det' => {:value => 'det', :type => :identifier},
346
- 'dim' => {:value => 'dim', :type => :identifier},
347
- 'mod' => {:value => 'mod', :type => :identifier},
348
- 'gcd' => {:value => 'gcd', :type => :identifier},
349
- 'lcm' => {:value => 'lcm', :type => :identifier},
350
- 'lub' => {:value => 'lub', :type => :identifier},
351
- 'glb' => {:value => 'glb', :type => :identifier},
352
- 'min' => {:value => 'min', :type => :identifier, :underover => true},
353
- 'max' => {:value => 'max', :type => :identifier, :underover => true},
354
- 'f' => {:value => 'f', :type => :identifier},
355
- 'g' => {:value => 'g', :type => :identifier},
356
-
357
- # Accents
358
- 'hat' => {:value => "\u005E", :type => :accent, :position => :over},
359
- 'bar' => {:value => "\u00AF", :type => :accent, :position => :over},
360
- 'ul' => {:value => '_', :type => :accent, :position => :under},
361
- 'vec' => {:value => "\u2192", :type => :accent, :position => :over},
362
- 'dot' => {:value => '.', :type => :accent, :position => :over},
363
- 'ddot' => {:value => '..', :type => :accent, :position => :over},
364
- 'obrace' => {:value => "\u23DE", :type => :accent, :position => :over},
365
- 'ubrace' => {:value => "\u23DF", :type => :accent, :position => :under},
366
-
367
- # Arrows
368
- 'uarr' => {:value => "\u2191", :type => :operator},
369
- 'darr' => {:value => "\u2193", :type => :operator},
370
- 'rarr' => {:value => "\u2192", :type => :operator},
371
- '->' => {:value => "\u2192", :type => :operator},
372
- '>->' => {:value => "\u21A3", :type => :operator},
373
- '->>' => {:value => "\u21A0", :type => :operator},
374
- '>->>' => {:value => "\u2916", :type => :operator},
375
- '|->' => {:value => "\u21A6", :type => :operator},
376
- 'larr' => {:value => "\u2190", :type => :operator},
377
- 'harr' => {:value => "\u2194", :type => :operator},
378
- 'rArr' => {:value => "\u21D2", :type => :operator},
379
- 'lArr' => {:value => "\u21D0", :type => :operator},
380
- 'hArr' => {:value => "\u21D4", :type => :operator},
381
-
382
- # Other
383
- 'sqrt' => {:value => :sqrt, :type => :unary},
384
- 'text' => {:value => :text, :type => :unary},
385
- 'bb' => {:value => :bold, :type => :font},
386
- 'bbb' => {:value => :double_struck, :type => :font},
387
- 'ii' => {:value => :italic, :type => :font},
388
- 'bii' => {:value => :bold_italic, :type => :font},
389
- 'cc' => {:value => :script, :type => :font},
390
- 'bcc' => {:value => :bold_script, :type => :font},
391
- 'tt' => {:value => :monospace, :type => :font},
392
- 'fr' => {:value => :fraktur, :type => :font},
393
- 'bfr' => {:value => :bold_fraktur, :type => :font},
394
- 'sf' => {:value => :sans_serif, :type => :font},
395
- 'bsf' => {:value => :bold_sans_serif, :type => :font},
396
- 'sfi' => {:value => :sans_serif_italic, :type => :font},
397
- 'sfbi' => {:value => :sans_serif_bold_italic, :type => :font},
398
- 'frac' => {:value => :frac, :type => :binary},
399
- 'root' => {:value => :root, :type => :binary},
400
- 'stackrel' => {:value => :over, :type => :binary},
401
- '/' => {:value => :frac, :type => :infix},
402
- '_' => {:value => :sub, :type => :infix},
403
- '^' => {:value => :sup, :type => :infix},
404
-
405
- # Greek letters
406
- 'alpha' => {:value => "\u03b1", :type => :identifier},
407
- 'Alpha' => {:value => "\u0391", :type => :identifier},
408
- 'beta' => {:value => "\u03b2", :type => :identifier},
409
- 'Beta' => {:value => "\u0392", :type => :identifier},
410
- 'gamma' => {:value => "\u03b3", :type => :identifier},
411
- 'Gamma' => {:value => "\u0393", :type => :operator},
412
- 'delta' => {:value => "\u03b4", :type => :identifier},
413
- 'Delta' => {:value => "\u0394", :type => :operator},
414
- 'epsilon' => {:value => "\u03b5", :type => :identifier},
415
- 'Epsilon' => {:value => "\u0395", :type => :identifier},
416
- 'varepsilon' => {:value => "\u025b", :type => :identifier},
417
- 'zeta' => {:value => "\u03b6", :type => :identifier},
418
- 'Zeta' => {:value => "\u0396", :type => :identifier},
419
- 'eta' => {:value => "\u03b7", :type => :identifier},
420
- 'Eta' => {:value => "\u0397", :type => :identifier},
421
- 'theta' => {:value => "\u03b8", :type => :identifier},
422
- 'Theta' => {:value => "\u0398", :type => :operator},
423
- 'vartheta' => {:value => "\u03d1", :type => :identifier},
424
- 'iota' => {:value => "\u03b9", :type => :identifier},
425
- 'Iota' => {:value => "\u0399", :type => :identifier},
426
- 'kappa' => {:value => "\u03ba", :type => :identifier},
427
- 'Kappa' => {:value => "\u039a", :type => :identifier},
428
- 'lambda' => {:value => "\u03bb", :type => :identifier},
429
- 'Lambda' => {:value => "\u039b", :type => :operator},
430
- 'mu' => {:value => "\u03bc", :type => :identifier},
431
- 'Mu' => {:value => "\u039c", :type => :identifier},
432
- 'nu' => {:value => "\u03bd", :type => :identifier},
433
- 'Nu' => {:value => "\u039d", :type => :identifier},
434
- 'xi' => {:value => "\u03be", :type => :identifier},
435
- 'Xi' => {:value => "\u039e", :type => :operator},
436
- 'omicron' => {:value => "\u03bf", :type => :identifier},
437
- 'Omicron' => {:value => "\u039f", :type => :identifier},
438
- 'pi' => {:value => "\u03c0", :type => :identifier},
439
- 'Pi' => {:value => "\u03a0", :type => :operator},
440
- 'rho' => {:value => "\u03c1", :type => :identifier},
441
- 'Rho' => {:value => "\u03a1", :type => :identifier},
442
- 'sigma' => {:value => "\u03c3", :type => :identifier},
443
- 'Sigma' => {:value => "\u03a3", :type => :operator},
444
- 'tau' => {:value => "\u03c4", :type => :identifier},
445
- 'Tau' => {:value => "\u03a4", :type => :identifier},
446
- 'upsilon' => {:value => "\u03c5", :type => :identifier},
447
- 'Upsilon' => {:value => "\u03a5", :type => :identifier},
448
- 'phi' => {:value => "\u03c6", :type => :identifier},
449
- 'Phi' => {:value => "\u03a6", :type => :identifier},
450
- 'varphi' => {:value => "\u03d5", :type => :identifier},
451
- 'chi' => {:value => '\u03b3c7', :type => :identifier},
452
- 'Chi' => {:value => '\u0393a7', :type => :identifier},
453
- 'psi' => {:value => "\u03c8", :type => :identifier},
454
- 'Psi' => {:value => "\u03a8", :type => :identifier},
455
- 'omega' => {:value => "\u03c9", :type => :identifier},
456
- 'Omega' => {:value => "\u03a9", :type => :operator},
457
- }
458
-
459
- def parse(input)
460
- Expression.new(
461
- input,
462
- parse_expression(Tokenizer.new(input, SYMBOLS), 0)
463
- )
464
- end
465
-
466
- private
467
- def parse_expression(tok, depth)
468
- e = []
469
-
470
- while (s1 = parse_simple_expression(tok, depth))
471
- t1 = tok.next_token
472
-
473
- if t1[:type] == :infix
474
- s2 = parse_simple_expression(tok, depth)
475
- t2 = tok.next_token
476
- if t1[:value] == :sub && t2[:value] == :sup
477
- s3 = parse_simple_expression(tok, depth)
478
- operator = s1[:underover] ? :underover : :subsup
479
- e << {:type => :ternary, :operator => operator, :s1 => s1, :s2 => s2, :s3 => s3}
480
- else
481
- operator = s1[:underover] ? (t1[:value] == :sub ? :under : :over) : t1[:value]
482
- e << {:type => :binary, :operator => operator, :s1 => s1, :s2 => s2}
483
- tok.push_back(t2)
484
- if (t2[:type] == :lrparen || t2[:type] == :rparen) && depth > 0
485
- break
486
- end
487
- end
488
- elsif t1[:type] == :eof
489
- e << s1
490
- break
491
- else
492
- e << s1
493
- tok.push_back(t1)
494
- if (t1[:type] == :lrparen || t1[:type] == :rparen) && depth > 0
495
- break
496
- end
497
- end
498
- end
499
-
500
- e
501
- end
502
-
503
- def parse_simple_expression(tok, depth)
504
- t1 = tok.next_token
505
-
506
- case t1[:type]
507
- when :lparen, :lrparen
508
- t2 = tok.next_token
509
- case t2[:type]
510
- when :rparen, :lrparen
511
- {:type => :paren, :e => nil, :lparen => t1[:value], :rparen => t2[:value]}
512
- else
513
- tok.push_back(t2)
514
-
515
- e = parse_expression(tok, depth + 1)
516
-
517
- t2 = tok.next_token
518
- case t2[:type]
519
- when :rparen, :lrparen
520
- convert_to_matrix({:type => :paren, :e => e, :lparen => t1[:value], :rparen => t2[:value]})
521
- else
522
- tok.push_back(t2)
523
- {:type => :paren, :e => e, :lparen => t1[:value]}
524
- end
525
- end
526
- when :accent
527
- s = parse_simple_expression(tok, depth)
528
- {:type => :binary, :s1 => s, :s2 => {:type => :operator, :c => t1[:value]}, :operator => t1[:position]}
529
- when :unary, :font
530
- s = parse_simple_expression(tok, depth)
531
- {:type => t1[:type], :s => s, :operator => t1[:value]}
532
- when :binary
533
- s1 = parse_simple_expression(tok, depth)
534
- s2 = parse_simple_expression(tok, depth)
535
- {:type => :binary, :s1 => s1, :s2 => s2, :operator => t1[:value]}
536
- when :eof
537
- nil
538
- else
539
- {:type => t1[:type], :c => t1[:value], :underover => t1[:underover]}
540
- end
541
- end
542
-
543
- def convert_to_matrix(expression)
544
- return expression unless matrix? expression
545
-
546
- rows = expression[:e].select.with_index { |obj, i| i.even? }.map do |row|
547
- row[:e].select.with_index { |obj, i| i.even? }
548
- end
549
-
550
- {:type => :matrix, :rows => rows, :lparen => expression[:lparen], :rparen => expression[:rparen]}
551
- end
552
-
553
- def matrix?(expression)
554
- return false unless expression.is_a?(Hash) && expression[:type] == :paren
555
-
556
- rows, separators = expression[:e].partition.with_index { |obj, i| i.even? }
557
-
558
- rows.length > 1 &&
559
- rows.length > separators.length &&
560
- separators.all? { |item| item[:type] == :identifier && item[:c] == ',' } &&
561
- (rows.all? { |item| item[:type] == :paren && item[:lparen] == '(' && item[:rparen] == ')' } ||
562
- rows.all? { |item| item[:type] == :paren && item[:lparen] == '[' && item[:rparen] == ']' }) &&
563
- rows.all? { |item| item[:e].length == rows[0][:e].length } &&
564
- rows.all? { |item| matrix_cols?(item[:e]) }
565
- end
566
-
567
- def matrix_cols?(expression)
568
- return false unless expression.is_a?(Array)
569
-
570
- cols, separators = expression.partition.with_index { |obj, i| i.even? }
571
-
572
- cols.all? { |item| item[:type] != :identifier || item[:c] != ',' } &&
573
- separators.all? { |item| item[:type] == :identifier && item[:c] == ',' }
574
- end
575
- end
576
-
577
- class Expression
578
- def initialize(asciimath, parsed_expression)
579
- @asciimath = asciimath
580
- @parsed_expression = parsed_expression
581
- end
582
-
583
- def to_s
584
- @asciimath
585
- end
586
- end
587
-
588
- def self.parse(asciimath)
589
- Parser.new.parse(asciimath)
590
- end
591
- end
@@ -1,3 +0,0 @@
1
- module AsciiMath
2
- VERSION = "1.0.7.pre1"
3
- end