javascript2latex 0.0.1
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.
- data/lib/javascript2latex.rb +268 -0
- metadata +45 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Utility class for creating a latex expression from a JavaScript expression.
|
|
3
|
+
#
|
|
4
|
+
# @author Juraj Masar <mail@jurajmasar.com> 1st May 2013
|
|
5
|
+
#
|
|
6
|
+
class Javascript2latex
|
|
7
|
+
#
|
|
8
|
+
# Node representation of a part of the mathematical expression used for
|
|
9
|
+
# transforming of the javascript expression into a latex expression.
|
|
10
|
+
#
|
|
11
|
+
class ExpressionNode
|
|
12
|
+
attr_accessor :type, :left, :right, :value
|
|
13
|
+
|
|
14
|
+
SQRT_EXPRESSION = 'Math.sqrt('
|
|
15
|
+
POWER_EXPRESSION = 'Math.pow('
|
|
16
|
+
LOG_EXPRESSION = 'Math.log('
|
|
17
|
+
|
|
18
|
+
ARGUMENT_EXCEPTION_MESSAGE = 'Argument is not a valid javascript expression'
|
|
19
|
+
|
|
20
|
+
def initialize(javascript_expression)
|
|
21
|
+
# validate parameters
|
|
22
|
+
raise ArgumentError, ARGUMENT_EXCEPTION_MESSAGE if javascript_expression.nil? or javascript_expression.empty?
|
|
23
|
+
|
|
24
|
+
# remove all whitespaces
|
|
25
|
+
javascript_expression.gsub!(/\s+/, '')
|
|
26
|
+
|
|
27
|
+
# remove enclosing brackets
|
|
28
|
+
#
|
|
29
|
+
is_enclosed_in_brackets = true
|
|
30
|
+
while is_enclosed_in_brackets and javascript_expression[0] == '(' and javascript_expression[-1,1] == ')'
|
|
31
|
+
# remember how many opening brackets have we encountered
|
|
32
|
+
bracket_level = 0
|
|
33
|
+
|
|
34
|
+
# iterate over expression and decide whether it is enclosed in brackets
|
|
35
|
+
# e.g. (a) is OK but (a)/(b) is not, although both pass the condition in while
|
|
36
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
37
|
+
bracket_level += 1 if char == '('
|
|
38
|
+
bracket_level -= 1 if char == ')'
|
|
39
|
+
|
|
40
|
+
if bracket_level == 0 and index != 0 and index != javascript_expression.length-1
|
|
41
|
+
is_enclosed_in_brackets = false
|
|
42
|
+
break
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# remove brackets if they are enclosing the entire expression
|
|
47
|
+
javascript_expression = javascript_expression[1,javascript_expression.length-2] if is_enclosed_in_brackets
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# check for equal sign
|
|
51
|
+
if !javascript_expression.index('=').nil?
|
|
52
|
+
index = javascript_expression.index('=')
|
|
53
|
+
@type = :equals
|
|
54
|
+
@left = ExpressionNode.new(javascript_expression[0, index])
|
|
55
|
+
@right = ExpressionNode.new(javascript_expression[index+1, javascript_expression.length-index-1])
|
|
56
|
+
return
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# check for square root
|
|
60
|
+
if javascript_expression[0,SQRT_EXPRESSION.length] == SQRT_EXPRESSION && javascript_expression[-1,1] == ')'
|
|
61
|
+
# remember how many opening brackets have we encountered
|
|
62
|
+
bracket_level = 0
|
|
63
|
+
is_enclosed_in_brackets = true
|
|
64
|
+
# iterate over expression and decide whether it is enclosed in brackets
|
|
65
|
+
# e.g. Math.sqrt(a) is OK but Math.sqrt(a)/(b) is not, although both pass the condition above
|
|
66
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
67
|
+
bracket_level += 1 if char == '('
|
|
68
|
+
bracket_level -= 1 if char == ')'
|
|
69
|
+
|
|
70
|
+
if bracket_level == 0 and index > SQRT_EXPRESSION.length-1 and index != javascript_expression.length-1
|
|
71
|
+
is_enclosed_in_brackets = false
|
|
72
|
+
break
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if is_enclosed_in_brackets
|
|
77
|
+
@type = :sqrt
|
|
78
|
+
@left = ExpressionNode.new(javascript_expression[SQRT_EXPRESSION.length,javascript_expression.length-SQRT_EXPRESSION.length-1])
|
|
79
|
+
return
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# check for logarithm
|
|
84
|
+
if javascript_expression[0,LOG_EXPRESSION.length] == LOG_EXPRESSION && javascript_expression[-1,1] == ')'
|
|
85
|
+
# remember how many opening brackets have we encountered
|
|
86
|
+
bracket_level = 0
|
|
87
|
+
is_enclosed_in_brackets = true
|
|
88
|
+
# iterate over expression and decide whether it is enclosed in brackets
|
|
89
|
+
# e.g. Math.log(a) is OK but Math.log(a)/(b) is not, although both pass the condition above
|
|
90
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
91
|
+
bracket_level += 1 if char == '('
|
|
92
|
+
bracket_level -= 1 if char == ')'
|
|
93
|
+
|
|
94
|
+
if bracket_level == 0 and index > LOG_EXPRESSION.length-1 and index != javascript_expression.length-1
|
|
95
|
+
is_enclosed_in_brackets = false
|
|
96
|
+
break
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if is_enclosed_in_brackets
|
|
101
|
+
@type = :log
|
|
102
|
+
@left = ExpressionNode.new(javascript_expression[LOG_EXPRESSION.length,javascript_expression.length-LOG_EXPRESSION.length-1])
|
|
103
|
+
return
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# check for power
|
|
108
|
+
if javascript_expression[0,POWER_EXPRESSION.length] == POWER_EXPRESSION && javascript_expression[-1,1] == ')'
|
|
109
|
+
# remember how many opening brackets have we encountered
|
|
110
|
+
bracket_level = 0
|
|
111
|
+
is_enclosed_in_brackets = true
|
|
112
|
+
|
|
113
|
+
# iterate over expression and decide whether it is enclosed in brackets
|
|
114
|
+
# e.g. Math.pow(a) is OK but Math.pow(a)/(b) is not, although both pass the condition above
|
|
115
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
116
|
+
bracket_level += 1 if char == '('
|
|
117
|
+
bracket_level -= 1 if char == ')'
|
|
118
|
+
|
|
119
|
+
if bracket_level == 0 and index > POWER_EXPRESSION.length-1 and index != javascript_expression.length-1
|
|
120
|
+
is_enclosed_in_brackets = false
|
|
121
|
+
break
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if is_enclosed_in_brackets
|
|
126
|
+
# iterate over inner expression in order to find comma
|
|
127
|
+
javascript_expression[POWER_EXPRESSION.length,javascript_expression.length-POWER_EXPRESSION.length-1].split('').each_with_index do |char, index|
|
|
128
|
+
bracket_level += 1 and next if char == '('
|
|
129
|
+
bracket_level -= 1 and next if char == ')'
|
|
130
|
+
|
|
131
|
+
if char == ',' and bracket_level == 0
|
|
132
|
+
@type = :power
|
|
133
|
+
@left = ExpressionNode.new(javascript_expression[POWER_EXPRESSION.length, index])
|
|
134
|
+
@right = ExpressionNode.new(javascript_expression[POWER_EXPRESSION.length+index+1, javascript_expression.length-POWER_EXPRESSION.length-index-2])
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# comma was not found, input is corrupted
|
|
140
|
+
raise ArgumentError, ARGUMENT_EXCEPTION_MESSAGE and return
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# check for + and - iterate over given expression
|
|
145
|
+
# remember how many open brackets have we encountered
|
|
146
|
+
bracket_level = 0
|
|
147
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
148
|
+
bracket_level += 1 and next if char == '('
|
|
149
|
+
bracket_level -= 1 and next if char == ')'
|
|
150
|
+
if (char == '+' or char == '-') and bracket_level == 0
|
|
151
|
+
@type = :addition if char == '+'
|
|
152
|
+
@type = :subtraction if char == '-'
|
|
153
|
+
@left = ExpressionNode.new(javascript_expression[0, index])
|
|
154
|
+
@right = ExpressionNode.new(javascript_expression[index+1, javascript_expression.length-index-1])
|
|
155
|
+
return
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# check for * and / iterate over given expression
|
|
160
|
+
# remember how many open brackets have we encountered
|
|
161
|
+
bracket_level = 0
|
|
162
|
+
javascript_expression.split('').each_with_index do |char, index|
|
|
163
|
+
bracket_level += 1 and next if char == '('
|
|
164
|
+
bracket_level -= 1 and next if char == ')'
|
|
165
|
+
if (char == '*' or char == '/') and bracket_level == 0
|
|
166
|
+
@type = :multiplication if char == '*'
|
|
167
|
+
@type = :division if char == '/'
|
|
168
|
+
@left = ExpressionNode.new(javascript_expression[0, index])
|
|
169
|
+
@right = ExpressionNode.new(javascript_expression[index+1, javascript_expression.length-index-1])
|
|
170
|
+
return
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# if the expression is non-empty alphanumeric string
|
|
175
|
+
if javascript_expression =~ /^[a-z0-9]+$/i
|
|
176
|
+
@type = :value
|
|
177
|
+
@value = javascript_expression
|
|
178
|
+
else
|
|
179
|
+
raise ArgumentError, ARGUMENT_EXCEPTION_MESSAGE and return
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
#
|
|
184
|
+
# Makes a latex expression from this node and all of its children.
|
|
185
|
+
#
|
|
186
|
+
# @return [String] latex expression
|
|
187
|
+
def to_s
|
|
188
|
+
case @type
|
|
189
|
+
when :equals
|
|
190
|
+
return "#{@left}=#{@right}"
|
|
191
|
+
when :sqrt
|
|
192
|
+
return "\\sqrt{#{@left}}"
|
|
193
|
+
when :log
|
|
194
|
+
body = @left.to_s
|
|
195
|
+
|
|
196
|
+
# enclose body in brackets if it is a composite expression
|
|
197
|
+
body = "(#{body})" if body !~ /^[a-z0-9]+$/i
|
|
198
|
+
|
|
199
|
+
return "\\log{#{body}}"
|
|
200
|
+
when :power
|
|
201
|
+
base = @left.to_s
|
|
202
|
+
exponent = @right.to_s
|
|
203
|
+
|
|
204
|
+
# enclose base in brackets if it is a composite expression
|
|
205
|
+
base = "(#{base})" if base !~ /^[a-z0-9]+$/i
|
|
206
|
+
|
|
207
|
+
return "#{base}^{#{exponent}}"
|
|
208
|
+
when :addition
|
|
209
|
+
return "#{@left}+#{@right}"
|
|
210
|
+
when :subtraction
|
|
211
|
+
return "#{@left}-#{@right}"
|
|
212
|
+
when :multiplication
|
|
213
|
+
left = @left.to_s
|
|
214
|
+
# check for + and - iterate over given expression
|
|
215
|
+
has_to_be_enclosed_in_brackets = false
|
|
216
|
+
# remember how many open brackets have we encountered
|
|
217
|
+
bracket_level = 0
|
|
218
|
+
left.split('').each_with_index do |char, index|
|
|
219
|
+
bracket_level += 1 and next if char == '('
|
|
220
|
+
bracket_level -= 1 and next if char == ')'
|
|
221
|
+
if (char == '+' or char == '-') and bracket_level == 0
|
|
222
|
+
has_to_be_enclosed_in_brackets = true
|
|
223
|
+
break
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
# enclose multiples in brackets if they are a composite expression
|
|
227
|
+
left = "(#{left})" if has_to_be_enclosed_in_brackets
|
|
228
|
+
|
|
229
|
+
right = @right.to_s
|
|
230
|
+
# check for + and - iterate over given expression
|
|
231
|
+
has_to_be_enclosed_in_brackets = false
|
|
232
|
+
# remember how many open brackets have we encountered
|
|
233
|
+
bracket_level = 0
|
|
234
|
+
right.split('').each_with_index do |char, index|
|
|
235
|
+
bracket_level += 1 and next if char == '('
|
|
236
|
+
bracket_level -= 1 and next if char == ')'
|
|
237
|
+
if (char == '+' or char == '-') and bracket_level == 0
|
|
238
|
+
has_to_be_enclosed_in_brackets = true
|
|
239
|
+
break
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
right = "(#{right})" if has_to_be_enclosed_in_brackets
|
|
244
|
+
|
|
245
|
+
return "#{left} \\times #{right}"
|
|
246
|
+
when :division
|
|
247
|
+
return "\\frac{#{@left}}{#{@right}}"
|
|
248
|
+
when :value
|
|
249
|
+
return @value
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
#
|
|
255
|
+
# Converts the given mathematical expression written in JavaScript into latex syntax.
|
|
256
|
+
#
|
|
257
|
+
# @param [string] javascript_expression
|
|
258
|
+
# @return [string] latex_expression
|
|
259
|
+
def self.make_tex(javascript_expression)
|
|
260
|
+
begin
|
|
261
|
+
root = ExpressionNode.new(javascript_expression)
|
|
262
|
+
return "$#{root}$"
|
|
263
|
+
rescue
|
|
264
|
+
return '$$'
|
|
265
|
+
Rails.logger.error 'Invalid JavaScript expression'
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: javascript2latex
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Juraj Masar
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-05-02 00:00:00.000000000 Z
|
|
13
|
+
dependencies: []
|
|
14
|
+
description: Gem for creating a LaTeX expressions from JavaScript ones.
|
|
15
|
+
email: mail@jurajmasar.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- lib/javascript2latex.rb
|
|
21
|
+
homepage: http://rubygems.org/gems/javascript2latex
|
|
22
|
+
licenses: []
|
|
23
|
+
post_install_message:
|
|
24
|
+
rdoc_options: []
|
|
25
|
+
require_paths:
|
|
26
|
+
- lib
|
|
27
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - ! '>='
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
34
|
+
none: false
|
|
35
|
+
requirements:
|
|
36
|
+
- - ! '>='
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubyforge_project:
|
|
41
|
+
rubygems_version: 1.8.25
|
|
42
|
+
signing_key:
|
|
43
|
+
specification_version: 3
|
|
44
|
+
summary: Initial version.
|
|
45
|
+
test_files: []
|