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.
Files changed (2) hide show
  1. data/lib/javascript2latex.rb +268 -0
  2. 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: []