asciimath 1.0.9 → 2.0.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 +5 -5
- data/AST.adoc +457 -0
- data/CHANGELOG.adoc +12 -0
- data/Gemfile.lock +39 -0
- data/README.adoc +27 -3
- data/asciimath.gemspec +9 -5
- data/lib/asciimath.rb +5 -4
- data/lib/asciimath/ast.rb +456 -0
- data/lib/asciimath/cli.rb +4 -1
- data/lib/asciimath/color_table.rb +21 -0
- data/lib/asciimath/html.rb +126 -111
- data/lib/asciimath/latex.rb +386 -0
- data/lib/asciimath/markup.rb +478 -0
- data/lib/asciimath/mathml.rb +189 -87
- data/lib/asciimath/parser.rb +498 -343
- data/lib/asciimath/symbol_table.rb +25 -0
- data/lib/asciimath/version.rb +1 -1
- data/spec/ast.rb +144 -0
- data/spec/parser_spec.rb +592 -165
- data/spec/schema/mathml2/common/common-attribs.xsd +41 -0
- data/spec/schema/mathml2/common/math.xsd +126 -0
- data/spec/schema/mathml2/common/xlink-href.xsd +20 -0
- data/spec/schema/mathml2/content/arith.xsd +90 -0
- data/spec/schema/mathml2/content/calculus.xsd +146 -0
- data/spec/schema/mathml2/content/common-attrib.xsd +30 -0
- data/spec/schema/mathml2/content/constants.xsd +83 -0
- data/spec/schema/mathml2/content/constructs.xsd +260 -0
- data/spec/schema/mathml2/content/elementary-functions.xsd +117 -0
- data/spec/schema/mathml2/content/functions.xsd +73 -0
- data/spec/schema/mathml2/content/linear-algebra.xsd +173 -0
- data/spec/schema/mathml2/content/logic.xsd +53 -0
- data/spec/schema/mathml2/content/relations.xsd +55 -0
- data/spec/schema/mathml2/content/semantics.xsd +85 -0
- data/spec/schema/mathml2/content/sets.xsd +236 -0
- data/spec/schema/mathml2/content/statistics.xsd +136 -0
- data/spec/schema/mathml2/content/tokens.xsd +120 -0
- data/spec/schema/mathml2/content/vector-calculus.xsd +88 -0
- data/spec/schema/mathml2/mathml2.xsd +59 -0
- data/spec/schema/mathml2/presentation/action.xsd +44 -0
- data/spec/schema/mathml2/presentation/characters.xsd +37 -0
- data/spec/schema/mathml2/presentation/common-attribs.xsd +113 -0
- data/spec/schema/mathml2/presentation/common-types.xsd +103 -0
- data/spec/schema/mathml2/presentation/error.xsd +40 -0
- data/spec/schema/mathml2/presentation/layout.xsd +195 -0
- data/spec/schema/mathml2/presentation/scripts.xsd +186 -0
- data/spec/schema/mathml2/presentation/space.xsd +52 -0
- data/spec/schema/mathml2/presentation/style.xsd +69 -0
- data/spec/schema/mathml2/presentation/table.xsd +216 -0
- data/spec/schema/mathml2/presentation/tokens.xsd +124 -0
- data/spec/schema/mathml3/mathml3-common.xsd +99 -0
- data/spec/schema/mathml3/mathml3-content.xsd +684 -0
- data/spec/schema/mathml3/mathml3-presentation.xsd +2151 -0
- data/spec/schema/mathml3/mathml3-strict-content.xsd +186 -0
- data/spec/schema/mathml3/mathml3.xsd +9 -0
- metadata +102 -10
- data/.gitignore +0 -16
- data/.travis.yml +0 -18
data/CHANGELOG.adoc
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
= Asciimath Changelog
|
2
2
|
|
3
|
+
== 2.0.0
|
4
|
+
|
5
|
+
Enhancements::
|
6
|
+
|
7
|
+
* The AsciiMath parser has been significantly improved and should now have reached feature parity with the original Javascript implementation.
|
8
|
+
* Issue #16: add initial LaTeX output support (@GarkGarcia)
|
9
|
+
* Issue #26: avoid generating `<mfenced>` tags in MathML output
|
10
|
+
|
11
|
+
Bug fixes::
|
12
|
+
|
13
|
+
* Issue #14: add support for additional symbols and functions that are supported by Asciimath JS
|
14
|
+
|
3
15
|
== 1.0.9
|
4
16
|
|
5
17
|
Bug fixes::
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
asciimath (2.0.0.next1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.3)
|
10
|
+
mini_portile2 (2.4.0)
|
11
|
+
nokogiri (1.10.9)
|
12
|
+
mini_portile2 (~> 2.4.0)
|
13
|
+
rake (13.0.1)
|
14
|
+
rspec (3.9.0)
|
15
|
+
rspec-core (~> 3.9.0)
|
16
|
+
rspec-expectations (~> 3.9.0)
|
17
|
+
rspec-mocks (~> 3.9.0)
|
18
|
+
rspec-core (3.9.2)
|
19
|
+
rspec-support (~> 3.9.3)
|
20
|
+
rspec-expectations (3.9.1)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.9.0)
|
23
|
+
rspec-mocks (3.9.1)
|
24
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
25
|
+
rspec-support (~> 3.9.0)
|
26
|
+
rspec-support (3.9.3)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
asciimath!
|
33
|
+
bundler (> 0)
|
34
|
+
nokogiri (~> 1.10.9)
|
35
|
+
rake (~> 13.0.0)
|
36
|
+
rspec (~> 3.9.0)
|
37
|
+
|
38
|
+
BUNDLED WITH
|
39
|
+
1.17.2
|
data/README.adoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# AsciiMath
|
2
2
|
ifndef::env-site[:status:]
|
3
3
|
|
4
|
-
An http://asciimath.org[AsciiMath] parser and MathML generator written in pure Ruby.
|
4
|
+
An http://asciimath.org[AsciiMath] parser and MathML/LaTeX generator written in pure Ruby.
|
5
5
|
|
6
6
|
ifdef::status[]
|
7
7
|
[discrete]
|
@@ -48,15 +48,16 @@ parsed_expression = AsciiMath.parse(asciimath)
|
|
48
48
|
|
49
49
|
The parsed expression is a set of nested Array and Hash objects.
|
50
50
|
|
51
|
-
This expression can then be converted to MathML
|
51
|
+
This expression can then be converted to MathML, HTML (experimental) or LaTeX.
|
52
52
|
|
53
53
|
[source,ruby]
|
54
54
|
----
|
55
55
|
math_ml = parsed_expression.to_mathml
|
56
56
|
html = parsed_expression.to_html
|
57
|
+
latex = parsed_expression.to_latex
|
57
58
|
----
|
58
59
|
|
59
|
-
The MathML or
|
60
|
+
The MathML, HTML or LaTeX code is returned as a String.
|
60
61
|
|
61
62
|
### Command line
|
62
63
|
|
@@ -78,6 +79,12 @@ asciimath mathml "an asciimath string"
|
|
78
79
|
asciimath html "an asciimath string"
|
79
80
|
----
|
80
81
|
|
82
|
+
.LaTeX Generation
|
83
|
+
[source]
|
84
|
+
----
|
85
|
+
asciimath latex "an asciimath string"
|
86
|
+
----
|
87
|
+
|
81
88
|
This command will print out the generated code on stdout.
|
82
89
|
|
83
90
|
|
@@ -95,6 +102,23 @@ Known issues are as follows:
|
|
95
102
|
Rendering the HTML output correctly requires the inclusion of `style/math.css` in the html document.
|
96
103
|
There is currently no specific required font for this output, it simply selects a `serif` font family - change the `@font-family` attribute in the `.math-inline` class to select something specific.
|
97
104
|
|
105
|
+
## Notes on the LaTeX Output
|
106
|
+
|
107
|
+
All LaTeX commands and environments used in the output are coverved by
|
108
|
+
https://ctan.org/pkg/amsmath[`amsmath`] and `amssymb`, with a few exceptions:
|
109
|
+
|
110
|
+
* `\color`
|
111
|
+
* `\cancel`
|
112
|
+
* `\mathscr`
|
113
|
+
* `\twoheadrightarrowtail`
|
114
|
+
|
115
|
+
The `\color` command is supported by the
|
116
|
+
https://www.ctan.org/pkg/xcolor[`xcolor`] package, which is included in most
|
117
|
+
LaTeX distributions. The `\cancel` command is supported by the
|
118
|
+
https://www.ctan.org/pkg/cancel[cancel] package, also included in most LaTeX
|
119
|
+
distributions. The other commands are supported by the
|
120
|
+
https://ctan.org/pkg/stix[`stix`] package.
|
121
|
+
|
98
122
|
## Contributing
|
99
123
|
|
100
124
|
. Fork it (https://github.com/pepijnve/asciimath/fork)
|
data/asciimath.gemspec
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
4
5
|
require 'asciimath/version'
|
6
|
+
require 'rake/file_list'
|
5
7
|
|
6
8
|
Gem::Specification.new do |spec|
|
7
9
|
spec.name = "asciimath"
|
8
10
|
spec.version = AsciiMath::VERSION
|
9
|
-
spec.authors = ["Pepijn Van Eeckhoudt"]
|
10
|
-
spec.email = ["pepijn@vaneeckhoudt.net"]
|
11
|
+
spec.authors = ["Pepijn Van Eeckhoudt", "Gark Garcia"]
|
12
|
+
spec.email = ["pepijn@vaneeckhoudt.net", "pablo-ecobar@riseup.net"]
|
11
13
|
spec.summary = %q{AsciiMath parser and converter}
|
12
14
|
spec.description = %q{A pure Ruby AsciiMath parsing and conversion library.}
|
13
15
|
spec.homepage = ""
|
14
16
|
spec.license = "MIT"
|
15
17
|
|
16
|
-
spec.files =
|
18
|
+
spec.files = Rake::FileList['**/*'].exclude(*File.read('.gitignore').split)
|
19
|
+
.exclude('dump_symbol_table.rb')
|
17
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
22
|
spec.require_paths = ["lib"]
|
20
23
|
|
21
24
|
spec.add_development_dependency "bundler", "> 0"
|
22
|
-
spec.add_development_dependency "rake", "~>
|
23
|
-
spec.add_development_dependency "rspec", "~> 3.
|
25
|
+
spec.add_development_dependency "rake", "~> 13.0.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.9.0"
|
27
|
+
spec.add_development_dependency "nokogiri", "~> 1.10.9"
|
24
28
|
end
|
data/lib/asciimath.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require_relative 'asciimath/version'
|
2
|
+
require_relative 'asciimath/parser'
|
3
|
+
require_relative 'asciimath/mathml'
|
4
|
+
require_relative 'asciimath/html'
|
5
|
+
require_relative 'asciimath/latex'
|
@@ -0,0 +1,456 @@
|
|
1
|
+
module AsciiMath
|
2
|
+
module AST
|
3
|
+
def expression(*e)
|
4
|
+
case e.length
|
5
|
+
when 0
|
6
|
+
nil
|
7
|
+
when 1
|
8
|
+
e[0]
|
9
|
+
else
|
10
|
+
Sequence.new(e)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def paren(lparen, e, rparen)
|
15
|
+
Paren.new(lparen, e, rparen)
|
16
|
+
end
|
17
|
+
|
18
|
+
def group(lparen, e, rparen)
|
19
|
+
Group.new(lparen, e, rparen)
|
20
|
+
end
|
21
|
+
|
22
|
+
def subsup(e, sub, sup)
|
23
|
+
SubSup.new(e, sub, sup)
|
24
|
+
end
|
25
|
+
|
26
|
+
def sub(e, sub)
|
27
|
+
SubSup.new(e, sub, nil)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sup(e, sup)
|
31
|
+
SubSup.new(e, nil, sup)
|
32
|
+
end
|
33
|
+
|
34
|
+
def unary(operator, e)
|
35
|
+
UnaryOp.new(operator, e)
|
36
|
+
end
|
37
|
+
|
38
|
+
def binary(operator, e1, e2)
|
39
|
+
BinaryOp.new(operator, e1, e2)
|
40
|
+
end
|
41
|
+
|
42
|
+
def infix(e1, operator, e2)
|
43
|
+
InfixOp.new(operator, e1, e2)
|
44
|
+
end
|
45
|
+
|
46
|
+
def text(value)
|
47
|
+
Text.new(value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def number(value)
|
51
|
+
Number.new(value)
|
52
|
+
end
|
53
|
+
|
54
|
+
def symbol(symbol, text)
|
55
|
+
Symbol.new(symbol, text)
|
56
|
+
end
|
57
|
+
|
58
|
+
def identifier(value)
|
59
|
+
Identifier.new(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def matrix(lparen, rows, rparen)
|
63
|
+
Matrix.new(lparen, rows, rparen)
|
64
|
+
end
|
65
|
+
|
66
|
+
def color(r, g, b, text)
|
67
|
+
Color.new(r, g, b, text)
|
68
|
+
end
|
69
|
+
|
70
|
+
class Node
|
71
|
+
attr_reader :parent
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@parent = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
attr_writer :parent
|
80
|
+
end
|
81
|
+
|
82
|
+
class InnerNode < Node
|
83
|
+
include Enumerable
|
84
|
+
|
85
|
+
def initialize
|
86
|
+
super
|
87
|
+
@children = []
|
88
|
+
end
|
89
|
+
|
90
|
+
def [](*args)
|
91
|
+
@children[*args]
|
92
|
+
end
|
93
|
+
|
94
|
+
def length
|
95
|
+
@children.length
|
96
|
+
end
|
97
|
+
|
98
|
+
def each(&block)
|
99
|
+
@children.each(&block)
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def child_nodes
|
105
|
+
@children
|
106
|
+
end
|
107
|
+
|
108
|
+
def add(node)
|
109
|
+
node.parent.remove(node) if node.parent
|
110
|
+
node.parent = self
|
111
|
+
child_nodes << node
|
112
|
+
end
|
113
|
+
|
114
|
+
def remove(node)
|
115
|
+
node.parent = nil
|
116
|
+
child_nodes.delete(node)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Sequence < InnerNode
|
121
|
+
def initialize(nodes)
|
122
|
+
super()
|
123
|
+
nodes.each { |node| add(node) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
child_nodes.map { |node| node.to_s }.join(" ")
|
128
|
+
end
|
129
|
+
|
130
|
+
def ==(o)
|
131
|
+
o.class == self.class && o.child_nodes == child_nodes
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class Paren < InnerNode
|
136
|
+
attr_reader :lparen
|
137
|
+
attr_reader :rparen
|
138
|
+
|
139
|
+
def initialize(lparen, e, rparen)
|
140
|
+
super()
|
141
|
+
@lparen = lparen
|
142
|
+
@rparen = rparen
|
143
|
+
add(e) if e
|
144
|
+
end
|
145
|
+
|
146
|
+
def expression
|
147
|
+
child_nodes[0]
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_s
|
151
|
+
"#{lparen.nil? ? '' : lparen.text}#{expression}#{rparen.nil? ? '' : rparen.text}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def ==(o)
|
155
|
+
o.class == self.class && o.lparen == lparen && o.expression == expression && o.rparen == rparen
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class Group < InnerNode
|
160
|
+
attr_reader :lparen
|
161
|
+
attr_reader :rparen
|
162
|
+
|
163
|
+
def initialize(lparen, e, rparen)
|
164
|
+
super()
|
165
|
+
@lparen = lparen
|
166
|
+
@rparen = rparen
|
167
|
+
add(e) if e
|
168
|
+
end
|
169
|
+
|
170
|
+
def expression
|
171
|
+
child_nodes[0]
|
172
|
+
end
|
173
|
+
|
174
|
+
def to_s
|
175
|
+
"#{lparen.nil? ? '' : lparen.text}#{expression}#{rparen.nil? ? '' : rparen.text}"
|
176
|
+
end
|
177
|
+
|
178
|
+
def ==(o)
|
179
|
+
o.class == self.class && o.lparen == lparen && o.expression == expression && o.rparen == rparen
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
class SubSup < InnerNode
|
184
|
+
def initialize(e, sub, sup)
|
185
|
+
super()
|
186
|
+
add(e)
|
187
|
+
add(sub || Empty.new)
|
188
|
+
add(sup || Empty.new)
|
189
|
+
end
|
190
|
+
|
191
|
+
def base_expression
|
192
|
+
child_nodes[0]
|
193
|
+
end
|
194
|
+
|
195
|
+
def sub_expression
|
196
|
+
child = child_nodes[1]
|
197
|
+
child.is_a?(Empty) ? nil : child
|
198
|
+
end
|
199
|
+
|
200
|
+
def sup_expression
|
201
|
+
child = child_nodes[2]
|
202
|
+
child.is_a?(Empty) ? nil : child
|
203
|
+
end
|
204
|
+
|
205
|
+
def to_s
|
206
|
+
s = ""
|
207
|
+
s << base_expression.to_s
|
208
|
+
sub = sub_expression
|
209
|
+
if sub
|
210
|
+
s << "_" << sub.to_s
|
211
|
+
end
|
212
|
+
sup = sup_expression
|
213
|
+
if sup
|
214
|
+
s << "^" << sup.to_s
|
215
|
+
end
|
216
|
+
s
|
217
|
+
end
|
218
|
+
|
219
|
+
def ==(o)
|
220
|
+
o.class == self.class && o.base_expression == base_expression && o.sub_expression == sub_expression && o.sup_expression == sup_expression
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
class UnaryOp < InnerNode
|
225
|
+
def initialize(operator, e)
|
226
|
+
super()
|
227
|
+
add(operator)
|
228
|
+
add(e)
|
229
|
+
end
|
230
|
+
|
231
|
+
def operator
|
232
|
+
child_nodes[0]
|
233
|
+
end
|
234
|
+
|
235
|
+
def operand
|
236
|
+
child_nodes[1]
|
237
|
+
end
|
238
|
+
|
239
|
+
def to_s
|
240
|
+
"#{operator} #{operand}"
|
241
|
+
end
|
242
|
+
|
243
|
+
def ==(o)
|
244
|
+
o.class == self.class && o.operator == operator && o.operand == operand
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
class BinaryOp < InnerNode
|
249
|
+
def initialize(operator, e1, e2)
|
250
|
+
super()
|
251
|
+
add(operator)
|
252
|
+
add(e1)
|
253
|
+
add(e2)
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
def operator
|
258
|
+
child_nodes[0]
|
259
|
+
end
|
260
|
+
|
261
|
+
def operand1
|
262
|
+
child_nodes[1]
|
263
|
+
end
|
264
|
+
|
265
|
+
def operand2
|
266
|
+
child_nodes[2]
|
267
|
+
end
|
268
|
+
|
269
|
+
def to_s
|
270
|
+
"#{operator} #{operand1} #{operand2}"
|
271
|
+
end
|
272
|
+
|
273
|
+
def ==(o)
|
274
|
+
o.class == self.class && o.operator == operator && o.operand1 == operand1 && o.operand2 == operand2
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class InfixOp < InnerNode
|
279
|
+
def initialize(operator, e1, e2)
|
280
|
+
super()
|
281
|
+
add(operator)
|
282
|
+
add(e1)
|
283
|
+
add(e2)
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
def operator
|
288
|
+
child_nodes[0]
|
289
|
+
end
|
290
|
+
|
291
|
+
def operand1
|
292
|
+
child_nodes[1]
|
293
|
+
end
|
294
|
+
|
295
|
+
def operand2
|
296
|
+
child_nodes[2]
|
297
|
+
end
|
298
|
+
|
299
|
+
def to_s
|
300
|
+
"#{operand1} #{operator} #{operand2}"
|
301
|
+
end
|
302
|
+
|
303
|
+
def ==(o)
|
304
|
+
o.class == self.class && o.operator == operator && o.operand1 == operand1 && o.operand2 == operand2
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
class ValueNode < Node
|
309
|
+
attr_reader :value
|
310
|
+
|
311
|
+
def initialize(value)
|
312
|
+
super()
|
313
|
+
@value = value
|
314
|
+
end
|
315
|
+
|
316
|
+
def to_s
|
317
|
+
value.to_s
|
318
|
+
end
|
319
|
+
|
320
|
+
def ==(o)
|
321
|
+
o.class == self.class && o.value == value
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class Text < ValueNode
|
326
|
+
def initialize(value)
|
327
|
+
super(value.dup.freeze)
|
328
|
+
end
|
329
|
+
|
330
|
+
def to_s
|
331
|
+
'"' + super + '"'
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
class Number < ValueNode
|
336
|
+
def initialize(value)
|
337
|
+
super(value.dup.freeze)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
class Symbol < ValueNode
|
342
|
+
attr_reader :text
|
343
|
+
|
344
|
+
def initialize(value, text)
|
345
|
+
super(value)
|
346
|
+
@text = text.dup.freeze
|
347
|
+
end
|
348
|
+
|
349
|
+
def ==(o)
|
350
|
+
super && o.text == text
|
351
|
+
end
|
352
|
+
|
353
|
+
def to_s
|
354
|
+
text
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
class Identifier < ValueNode
|
359
|
+
def initialize(value)
|
360
|
+
super(value.dup.freeze)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
class Color < ValueNode
|
365
|
+
attr_reader :text
|
366
|
+
|
367
|
+
def initialize(r, g, b, text)
|
368
|
+
super({:r => r, :g => g, :b => b}.freeze)
|
369
|
+
@text = text.dup.freeze
|
370
|
+
end
|
371
|
+
|
372
|
+
def red
|
373
|
+
value[:r]
|
374
|
+
end
|
375
|
+
|
376
|
+
def green
|
377
|
+
value[:g]
|
378
|
+
end
|
379
|
+
|
380
|
+
def blue
|
381
|
+
value[:b]
|
382
|
+
end
|
383
|
+
|
384
|
+
def ==(o)
|
385
|
+
o.class == self.class &&
|
386
|
+
o.red == red &&
|
387
|
+
o.green == green &&
|
388
|
+
o.blue == blue &&
|
389
|
+
o.text == text
|
390
|
+
end
|
391
|
+
|
392
|
+
def to_hex_rgb
|
393
|
+
sprintf('#%02x%02x%02x', red, green, blue)
|
394
|
+
end
|
395
|
+
|
396
|
+
def to_s
|
397
|
+
text
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
class Matrix < InnerNode
|
402
|
+
attr_reader :lparen
|
403
|
+
attr_reader :rparen
|
404
|
+
|
405
|
+
def initialize(lparen, rows, rparen)
|
406
|
+
super()
|
407
|
+
@lparen = lparen
|
408
|
+
@rparen = rparen
|
409
|
+
rows.map { |row| MatrixRow.new(row) }.each { |row_seq| add(row_seq) }
|
410
|
+
end
|
411
|
+
|
412
|
+
def to_s
|
413
|
+
s = ""
|
414
|
+
s << (lparen.nil? ? '{:' : lparen.text)
|
415
|
+
s << child_nodes.map { |node| node.to_s }.join(",")
|
416
|
+
s << (rparen.nil? ? ':}' : rparen.text)
|
417
|
+
end
|
418
|
+
|
419
|
+
def ==(o)
|
420
|
+
o.class == self.class &&
|
421
|
+
o.lparen == lparen &&
|
422
|
+
o.child_nodes == child_nodes &&
|
423
|
+
o.rparen == rparen
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
class MatrixRow < InnerNode
|
428
|
+
def initialize(nodes)
|
429
|
+
super()
|
430
|
+
nodes.each { |node| add(node || Empty.new) }
|
431
|
+
end
|
432
|
+
|
433
|
+
def to_s
|
434
|
+
"(" + child_nodes.map { |node| node.to_s }.join(",") + ")"
|
435
|
+
end
|
436
|
+
|
437
|
+
def ==(o)
|
438
|
+
o.class == self.class && o.child_nodes == child_nodes
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
class Empty < Node
|
443
|
+
def initialize()
|
444
|
+
super
|
445
|
+
end
|
446
|
+
|
447
|
+
def to_s
|
448
|
+
''
|
449
|
+
end
|
450
|
+
|
451
|
+
def ==(o)
|
452
|
+
o.class == self.class
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|