lxl 0.2.0 → 0.2.2
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/CHANGES +7 -0
- data/VERSION +1 -1
- data/lib/lxl.rb +41 -44
- metadata +1 -1
data/CHANGES
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.2.2
|
2
|
+
|
3
|
+
- Seperated tokenize's text=>formula into tokenize_text
|
4
|
+
- LittleLexer returns types as [Symbol*] vs String (tokenize updated accordingly)
|
5
|
+
- F and C types removed (no need)
|
6
|
+
- General refactoring (code/doc cleanup)
|
7
|
+
|
1
8
|
0.2.0
|
2
9
|
|
3
10
|
- Double quotes only used to define strings.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/lib/lxl.rb
CHANGED
@@ -54,8 +54,6 @@
|
|
54
54
|
# t Token
|
55
55
|
# ( Open (
|
56
56
|
# ) Close )
|
57
|
-
# C Constant
|
58
|
-
# F Function
|
59
57
|
#
|
60
58
|
module LXL
|
61
59
|
|
@@ -111,29 +109,25 @@ class LXL::Parser
|
|
111
109
|
ops = EXCEL_OPERATORS.collect { |v| Regexp.quote(v) }.join('|')
|
112
110
|
#
|
113
111
|
@lexer = LXL::LittleLexer.new([
|
114
|
-
[/\A[\s,]
|
115
|
-
[/\A(#{ops})
|
116
|
-
[/\A[
|
117
|
-
[/\A[0-9]
|
118
|
-
[/\A
|
119
|
-
[/\A\w
|
120
|
-
[/\A\(
|
121
|
-
[/\A\)
|
112
|
+
[/\A[\s,]+/, ?w], # Whitespace (includes Commas)
|
113
|
+
[/\A(#{ops})/, ?o], # Operator
|
114
|
+
[/\A("([^"]|"")*")/m, ?s], # String
|
115
|
+
[/\A[0-9]+\.[0-9]+/, ?f], # Float
|
116
|
+
[/\A[0-9]+/, ?i], # Integer
|
117
|
+
[/\A\w+/, ?t], # Token
|
118
|
+
[/\A\(/, ?(], # Open (
|
119
|
+
[/\A\)/, ?)], # Close )
|
122
120
|
], false)
|
123
|
-
|
124
|
-
# Other
|
125
|
-
@tokens = Array.new
|
126
|
-
@types = Array.new
|
127
121
|
end
|
128
122
|
|
129
123
|
# Evaluate formula
|
130
124
|
#
|
131
125
|
def eval(formula)
|
132
126
|
formulas = formula.to_s.split(';').collect { |f| f.strip }.find_all { |f| ! f.empty? }
|
133
|
-
formulas.collect! { |f| Kernel.eval(
|
127
|
+
formulas.collect! { |f| Kernel.eval(tokenize_text(f).join, binding) }
|
134
128
|
formulas.size == 1 ? formulas.first : formulas
|
135
129
|
end
|
136
|
-
|
130
|
+
|
137
131
|
# Register a function
|
138
132
|
#
|
139
133
|
# * Converts name to symbol
|
@@ -181,44 +175,45 @@ class LXL::Parser
|
|
181
175
|
}
|
182
176
|
end
|
183
177
|
|
178
|
+
# Translates text to a formula before tokenizing
|
179
|
+
#
|
180
|
+
def tokenize_text(text)
|
181
|
+
formula = (text =~ /^=/) ? text : '="'+text.gsub('"','""')+'"'
|
182
|
+
tokenize(formula)
|
183
|
+
end
|
184
|
+
|
184
185
|
# Tokenize formula (String => Array)
|
185
186
|
#
|
186
187
|
def tokenize(formula)
|
187
188
|
ops = Hash[*EXCEL_OPERATORS.zip(RUBY_OPERATORS).flatten]
|
188
189
|
|
189
190
|
# Parse formula
|
190
|
-
formula = '="'+formula.gsub('"','""')+'"' unless formula =~ /^=/ # text to formula (text to ="quoted-text")
|
191
191
|
types, tokens = @lexer.scan(formula.gsub(/^=/,''))
|
192
|
-
types = types.split(//)
|
193
192
|
raise SyntaxError, 'unbalanced parentheses' unless balanced?(tokens)
|
194
193
|
|
195
194
|
# Parse tokens
|
196
195
|
tokens.each_index do |i|
|
197
196
|
type, token = types[i], tokens[i]
|
198
|
-
|
199
|
-
when
|
200
|
-
when
|
201
|
-
when
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
197
|
+
tokens[i] = case type
|
198
|
+
when :i then token.to_i
|
199
|
+
when :f then token.to_f
|
200
|
+
when :s then token.gsub(/([^\\])""/,'\1\"') # "" to \"
|
201
|
+
when :t then
|
202
|
+
name = name(token)
|
203
|
+
if @functions.key?(name)
|
204
|
+
if tokens[i+1] != '('
|
205
|
+
raise ArgumentError, "wrong number of arguments for #{token}"
|
206
|
+
else
|
207
|
+
"@functions[:#{name}].call"
|
208
|
+
end
|
209
|
+
elsif @constants.key?(name)
|
210
|
+
"@constants[:#{name}]"
|
209
211
|
else
|
210
|
-
|
211
|
-
token = '@functions['+token.inspect+'].call'
|
212
|
+
raise NameError, "unknown constant #{token}"
|
212
213
|
end
|
213
|
-
elsif @constants.key?(token)
|
214
|
-
types[i] = 'C'
|
215
|
-
token = '@constants['+token.inspect+']'
|
216
214
|
else
|
217
|
-
|
218
|
-
end
|
215
|
+
EXCEL_OPERATORS.include?(token) ? ops[token] : token
|
219
216
|
end
|
220
|
-
token = ops[token] if EXCEL_OPERATORS.include?(token)
|
221
|
-
tokens[i] = token
|
222
217
|
end
|
223
218
|
|
224
219
|
tokens
|
@@ -242,33 +237,34 @@ end
|
|
242
237
|
#
|
243
238
|
# http://www.rubyforge.org/projects/littlelexer
|
244
239
|
#
|
240
|
+
# CHANGE: types are returned as [Symbol*] vs String
|
241
|
+
#
|
245
242
|
class LXL::LittleLexer #:nodoc: all
|
246
243
|
|
247
244
|
class LexerJammed < Exception; end
|
248
245
|
|
249
|
-
def initialize(regex_to_char,skip_white_space
|
246
|
+
def initialize(regex_to_char,skip_white_space=true)
|
250
247
|
@skip_white_space = skip_white_space
|
251
248
|
@regex_to_char = regex_to_char
|
252
249
|
end
|
253
250
|
|
254
251
|
def scan(string,string_token_list=nil)
|
255
|
-
|
252
|
+
result_list = []
|
256
253
|
token_list = []
|
257
|
-
|
258
254
|
if string_token_list
|
259
255
|
next_token(string) do |t,token, tail|
|
260
|
-
|
256
|
+
result_list << t.chr.to_sym
|
261
257
|
token_list << [string_token_list[0...tail], string[0...tail]]
|
262
258
|
string = string[tail..-1]
|
263
259
|
string_token_list = string_token_list[tail..-1]
|
264
260
|
end
|
265
261
|
else
|
266
262
|
next_token(string) do |t,token, tail|
|
267
|
-
|
263
|
+
result_list << t.chr.to_sym
|
268
264
|
token_list << token
|
269
265
|
end
|
270
266
|
end
|
271
|
-
return
|
267
|
+
return result_list, token_list
|
272
268
|
end
|
273
269
|
|
274
270
|
private
|
@@ -317,4 +313,5 @@ if $0 == __FILE__
|
|
317
313
|
|
318
314
|
# multiple formulas separated by semi-colon
|
319
315
|
puts LXL.eval(formulas).inspect # => ["This is some text", "This is some \"quoted\" text", 6, true, true, [1, "two", 3.0], true, false, true, "yes"]
|
316
|
+
|
320
317
|
end
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.8.3
|
|
3
3
|
specification_version: 1
|
4
4
|
name: lxl
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
6
|
+
version: 0.2.2
|
7
7
|
date: 2005-02-08
|
8
8
|
summary: LXL (Like Excel) is a mini-language that mimics Microsoft Excel formulas. Easily extended with new constants and functions.
|
9
9
|
require_paths:
|