lxl 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/CHANGES +9 -0
  2. data/VERSION +1 -1
  3. data/lib/lxl.rb +37 -27
  4. data/test/lxl_test.rb +2 -1
  5. metadata +2 -1
data/CHANGES ADDED
@@ -0,0 +1,9 @@
1
+ 0.1.1
2
+
3
+ - String tokens s/S => '/"
4
+ - :SYMBOL recognition (s token)
5
+ - register_constant, register_function
6
+
7
+ 0.1.0
8
+
9
+ - Initial release
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
data/lib/lxl.rb CHANGED
@@ -43,17 +43,19 @@
43
43
  #
44
44
  # * The number zero is interpereted as FALSE
45
45
  # * Return multiple results in an array by separating formulas with a semi-colon (;)
46
+ # * A :SYMBOL token is recognized as a ruby symbol
46
47
  #
47
48
  # =Lexical Types
48
49
  #
49
50
  # w Whitespace (includes Commas)
50
51
  # ; Semi-Colon (statement separator)
51
52
  # o Operator
52
- # i Integer
53
53
  # f Float
54
+ # i Integer
55
+ # ' String (single quoted)
56
+ # " String (double quoted)
57
+ # s Symbol
54
58
  # t Token
55
- # s String (single quoted)
56
- # S String (double quoted)
57
59
  # ( Open (
58
60
  # ) Close )
59
61
  # C Constant
@@ -89,26 +91,25 @@ class LXL::Parser
89
91
  def initialize
90
92
 
91
93
  # Constants
92
- @constants = {
93
- :TRUE => true,
94
- :FALSE => false,
95
- :NULL => nil,
96
- }
94
+ @constants = Hash.new
95
+ register_constant(:TRUE, true)
96
+ register_constant(:FALSE, false)
97
+ register_constant(:NULL, nil)
97
98
 
98
99
  # Functions
99
100
  @functions = Hash.new
100
- register(:AND) { |a,b| to_b(a) && to_b(b) }
101
- register(:OR) { |a,b| to_b(a) || to_b(b) }
102
- register(:IF) { |v,a,b| to_b(v) ? a : b }
103
- register(:LIST) { |*args| args }
104
- register(:IN) { |n,h| h.respond_to?(:include?) ? h.include?(n) : false }
105
- register(:TODAY) { Date.today.ajd.to_f }
106
- register(:NOW) { DateTime.now.ajd.to_f }
107
- register(:DATE) { |y,m,d| Date.new(y,m,d).ajd.to_f }
108
- register(:TIME) { |h,m,s|
101
+ register_function(:AND) { |a,b| to_b(a) && to_b(b) }
102
+ register_function(:OR) { |a,b| to_b(a) || to_b(b) }
103
+ register_function(:IF) { |v,a,b| to_b(v) ? a : b }
104
+ register_function(:LIST) { |*args| args }
105
+ register_function(:IN) { |n,h| h.respond_to?(:include?) ? h.include?(n) : false }
106
+ register_function(:TODAY) { Date.today.ajd.to_f }
107
+ register_function(:NOW) { DateTime.now.ajd.to_f }
108
+ register_function(:DATE) { |y,m,d| Date.new(y,m,d).ajd.to_f }
109
+ register_function(:DATETIME) { |value| DateTime.parse(value).ajd.to_f }
110
+ register_function(:TIME) { |h,m,s|
109
111
  DateTime.valid_time?(h,m,s) ? DateTime.valid_time?(h,m,s).to_f : raise(ArgumentError, 'invalid time')
110
112
  }
111
- register(:DATETIME) { |value| DateTime.parse(value).ajd.to_f }
112
113
 
113
114
  # Lexer
114
115
  ops = EXCEL_OPERATORS.collect { |v| Regexp.quote(v) }.join('|')
@@ -119,8 +120,9 @@ class LXL::Parser
119
120
  [/\A(#{ops})/,?o], # Operator
120
121
  [/\A[0-9]+\.[0-9]+/,?f], # Float
121
122
  [/\A[0-9]+/,?i], # Integer
122
- [/\A("[^\"]*")/m,?s], # String (single quoted)
123
- [/\A('[^\']*')/m,?S], # String (double quoted)
123
+ [/\A("[^\"]*")/m,?'], # String (single quoted)
124
+ [/\A('[^\']*')/m,?"], # String (double quoted)
125
+ [/\A:\w+/,?s], # Symbol
124
126
  [/\A\w+/,?t], # Token
125
127
  [/\A\(/,?(], # Open (
126
128
  [/\A\)/,?)], # Close )
@@ -153,12 +155,20 @@ class LXL::Parser
153
155
 
154
156
  protected
155
157
 
158
+ # Register a constant
159
+ #
160
+ # * Converts name to symbol
161
+ #
162
+ def register_constant(name, value)
163
+ @constants[name.to_sym] = value
164
+ end
165
+
156
166
  # Register a function
157
167
  #
158
168
  # * Converts name to symbol
159
169
  # * Wraps function with a debugging procedure
160
170
  #
161
- def register(name, &block)
171
+ def register_function(name, &block)
162
172
  @functions[name.to_sym] = debug(name.to_sym, &block)
163
173
  end
164
174
 
@@ -166,13 +176,13 @@ class LXL::Parser
166
176
  #
167
177
  # * Raise an error unless given the correct number of arguments
168
178
  #
169
- def debug(name, &func)
179
+ def debug(name, &block)
170
180
  raise ArgumentError, 'block not given to debug' unless block_given?
171
181
  Proc.new { |*args|
172
- if func.arity >= 0 and func.arity != args.size
173
- raise ArgumentError, "wrong number of arguments (#{args.size} for #{func.arity}) for #{name}"
182
+ if block.arity >= 0 and block.arity != args.size
183
+ raise ArgumentError, "wrong number of arguments (#{args.size} for #{block.arity}) for #{name}"
174
184
  end
175
- func.call(*args)
185
+ block.call(*args)
176
186
  }
177
187
  end
178
188
 
@@ -185,12 +195,13 @@ class LXL::Parser
185
195
  types, @tokens = @lexer.scan(formula)
186
196
  @types = types.split(//)
187
197
  raise SyntaxError, 'unbalanced parentheses' unless balanced?
188
-
198
+
189
199
  # Parse tokens
190
200
  @tokens.each_index do |i|
191
201
  type, token = @types[i], @tokens[i]
192
202
  token = token.to_i if type == 'i'
193
203
  token = token.to_f if type == 'f'
204
+ token = token.to_sym if type == 's'
194
205
  if type == 't'
195
206
  token = token.to_sym
196
207
  if @functions.key?(token)
@@ -300,7 +311,6 @@ if $0 == __FILE__
300
311
  IF(1+1=2, "yes", "no");
301
312
  }
302
313
 
303
- # single formula
304
314
  puts LXL.eval('5+5').inspect # => 10
305
315
 
306
316
  # multiple formulas separated by semi-colon
data/test/lxl_test.rb CHANGED
@@ -10,6 +10,7 @@ class LXLTest < Test::Unit::TestCase
10
10
 
11
11
  def test_multiple_formula
12
12
  formulas = %{
13
+ :SYMBOL;
13
14
  ((1+2)*(10-6))/2;
14
15
  DATETIME("2004-11-22 11:11:00")=DATE(2004,11,22)+TIME(11,11,00);
15
16
  IN(" is ", "this is a string");
@@ -19,7 +20,7 @@ class LXLTest < Test::Unit::TestCase
19
20
  OR(TRUE, FALSE);
20
21
  IF(1+1=2, "yes", "no");
21
22
  }
22
- expected = [6, true, true, [1, "two", 3.0], true, false, true, "yes"]
23
+ expected = [:SYMBOL, 6, true, true, [1, "two", 3.0], true, false, true, "yes"]
23
24
  results = LXL.eval(formulas)
24
25
  expected.each_index { |i| assert_equal(expected[i], results[i]) }
25
26
  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.1.0
6
+ version: 0.1.1
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:
@@ -29,6 +29,7 @@ authors:
29
29
  files:
30
30
  - lib
31
31
  - test
32
+ - CHANGES
32
33
  - README
33
34
  - VERSION
34
35
  - lib/lxl.rb