formula_eval 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/lib/formula_eval.rb +168 -0
- data/lib/formula_eval/calculating_collection.rb +55 -0
- data/lib/formula_eval/multi_eval.rb +56 -0
- data/lib/formula_eval/wrapper.rb +111 -0
- data/lib/spec.opts +1 -0
- data/spec/calculating_collection_spec.rb +26 -0
- data/spec/formula_eval_spec.rb +60 -0
- data/spec/spec_helper.rb +9 -0
- metadata +91 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Mike Harris
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= formula_eval
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Note on Patches/Pull Requests
|
6
|
+
|
7
|
+
* Fork the project.
|
8
|
+
* Make your feature addition or bug fix.
|
9
|
+
* Add tests for it. This is important so I don't break it in a
|
10
|
+
future version unintentionally.
|
11
|
+
* Commit, do not mess with rakefile, version, or history.
|
12
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
+
* Send me a pull request. Bonus points for topic branches.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 Mike Harris. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "formula_eval"
|
8
|
+
gem.summary = %Q{formula_eval}
|
9
|
+
gem.description = %Q{formula_eval}
|
10
|
+
gem.email = "mharris717@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/mharris717/formula_eval"
|
12
|
+
gem.authors = ["Mike Harris"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "formula_eval #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/formula_eval.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'mharris_ext'
|
2
|
+
require 'active_support'
|
3
|
+
|
4
|
+
class Object
|
5
|
+
attr_accessor :calculating_formula
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
class FormulaEval
|
12
|
+
attr_accessor :row, :formula, :row_index, :rows
|
13
|
+
include FromHash
|
14
|
+
def current_user
|
15
|
+
$current_user
|
16
|
+
end
|
17
|
+
def wrapped_row
|
18
|
+
Wrapper.new(row)
|
19
|
+
end
|
20
|
+
def method_missing(sym,*args,&b)
|
21
|
+
res = 'errored'
|
22
|
+
res = if row.respond_to?(sym)
|
23
|
+
wrapped_row.send(sym,*args,&b)
|
24
|
+
elsif row.respond_to?('[]')
|
25
|
+
wrapped_row[sym.to_s]
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
# puts "Formula mm #{sym} #{args.inspect} #{res.inspect}"
|
31
|
+
end
|
32
|
+
def safe_eval_result
|
33
|
+
instance_eval(formula).to_unwrapped
|
34
|
+
# rescue => exp
|
35
|
+
# t = exp.backtrace.join("\n").gsub("/Users/mharris/.rvm/gems/ruby-1.9.1-p378/gems","gems").gsub("/Users/mharris/Code/smartlist/vendor/mongo_ui","mongo_ui")
|
36
|
+
# t = t.gsub("/Users/mharris/Code/smartlist","smartlist")
|
37
|
+
# mylog "formula_eval", :formula => formula, :row => row, :message => exp.message, :trace => t
|
38
|
+
# "Error #{exp.message}"
|
39
|
+
rescue => exp
|
40
|
+
# puts "error evaling #{formula} against #{row.inspect}, #{exp.message}"
|
41
|
+
raise exp
|
42
|
+
end
|
43
|
+
def result
|
44
|
+
self.formula = formula[1..-1] if formula[0..0] == '='
|
45
|
+
res = safe_eval_result
|
46
|
+
eat_exceptions { res.calculating_formula = formula }
|
47
|
+
res
|
48
|
+
end
|
49
|
+
def call(row)
|
50
|
+
self.row = row
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class FormulaEval
|
56
|
+
def next_row
|
57
|
+
res = rows[row_index+1] || {}
|
58
|
+
HashWrapper.new(:hash => res)
|
59
|
+
end
|
60
|
+
def prev_row_inner
|
61
|
+
return {} if row_index == 0
|
62
|
+
rows[row_index-1] || {}
|
63
|
+
end
|
64
|
+
def prev_row
|
65
|
+
HashWrapper.new(:hash => prev_row_inner)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
load File.dirname(__FILE__) + "/formula_eval/wrapper.rb"
|
70
|
+
load File.dirname(__FILE__) + "/formula_eval/calculating_collection.rb"
|
71
|
+
load File.dirname(__FILE__) + "/formula_eval/multi_eval.rb"
|
72
|
+
|
73
|
+
def mylog(*args)
|
74
|
+
yield if block_given?
|
75
|
+
#puts args.inspect if args.first == 'enriched_doc' or args.first == 'dot_set'
|
76
|
+
end
|
77
|
+
|
78
|
+
class Object
|
79
|
+
def klass
|
80
|
+
self.class
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Object
|
85
|
+
def blank?
|
86
|
+
to_s.strip == ''
|
87
|
+
end
|
88
|
+
def present?
|
89
|
+
!blank?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class Object
|
94
|
+
def dot_get(str)
|
95
|
+
str = str.split(".") if str.is_a?(String)
|
96
|
+
res = self
|
97
|
+
last_f = last_res = nil
|
98
|
+
str.each do |f|
|
99
|
+
if f.num? && !res.kind_of?(Array)
|
100
|
+
last_res[last_f] = res = []
|
101
|
+
end
|
102
|
+
last_res = res
|
103
|
+
if res.kind_of?(Array)
|
104
|
+
temp = res[f.safe_to_i]
|
105
|
+
if !temp
|
106
|
+
res << {}
|
107
|
+
temp = res.last
|
108
|
+
raise "can only add new row at end" unless res.size-1 == f.safe_to_i
|
109
|
+
end
|
110
|
+
res = temp
|
111
|
+
else
|
112
|
+
res = res[f]
|
113
|
+
end
|
114
|
+
last_f = f
|
115
|
+
end
|
116
|
+
res
|
117
|
+
end
|
118
|
+
def dot_set(str,val)
|
119
|
+
mylog 'dot_set', :str => str, :val => val, :self => self do
|
120
|
+
return self[str] = val if str.split(".").size == 1
|
121
|
+
strs = str.split(".")[0..-2]
|
122
|
+
lst = str.split(".")[-1]
|
123
|
+
obj = dot_get(strs)
|
124
|
+
return obj unless obj
|
125
|
+
#puts "dot_set, obj is #{obj.inspect}, str is #{str}, val is #{val}, lst is #{lst}"
|
126
|
+
obj.nested_set(lst,val)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Object
|
132
|
+
def nested_set(k,v)
|
133
|
+
self[k] = v
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Array
|
138
|
+
def nested_set(k,v)
|
139
|
+
mylog 'dot_set', :context => 'nested', :klass => klass, :self => self, :k => k, :v => v do
|
140
|
+
each { |x| x.nested_set(k,v) }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class String
|
146
|
+
def num?
|
147
|
+
size > 0 && self =~ /^[\d\.]*$/
|
148
|
+
end
|
149
|
+
def date?
|
150
|
+
matches = (self =~ /\/\d+\//) || (self =~ /-\d+-/)
|
151
|
+
matches2 = self =~ /^[ \d\-\/:]+$/
|
152
|
+
!!(matches && matches2 && Time.parse(self))
|
153
|
+
rescue
|
154
|
+
return false
|
155
|
+
end
|
156
|
+
def to_time
|
157
|
+
Time.parse(self)
|
158
|
+
end
|
159
|
+
def tmo
|
160
|
+
if num?
|
161
|
+
to_f.tmo
|
162
|
+
elsif blank?
|
163
|
+
nil
|
164
|
+
else
|
165
|
+
self
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class CalculatingCollection
|
2
|
+
attr_accessor :coll
|
3
|
+
include FromHash
|
4
|
+
fattr(:column_hash) do
|
5
|
+
res = {}
|
6
|
+
res[:zzz] = lambda { |doc| (doc['abc']||0).to_i + 7 }
|
7
|
+
res[:xyz] = FormulaEval.new(:formula => '=(abc||0)+8')
|
8
|
+
res[:percs] = FormulaEval.new(:formula => '=pension.perc')
|
9
|
+
res[:percs2] = FormulaEval.new(:formula => '=pension.perc * 2.0')
|
10
|
+
res['pension.just_perc'] = FormulaEval.new(:formula => '=perc')
|
11
|
+
res['pension.just_perc_plus'] = FormulaEval.new(:formula => '=perc+1')
|
12
|
+
res['pension.perc_plus_salary'] = FormulaEval.new(:formula => '=perc+salary')
|
13
|
+
res
|
14
|
+
end
|
15
|
+
def enriched_doc(doc)
|
16
|
+
column_hash.each do |col,blk|
|
17
|
+
# mylog 'enriched_doc', :col => col, :blk_class => blk.class, :doc => doc
|
18
|
+
if col.to_s.split('.').size == 1
|
19
|
+
val = blk.call(doc)
|
20
|
+
mylog 'dot_set',:col => col, :val => val, :doc => doc
|
21
|
+
doc.dot_set(col.to_s,val)
|
22
|
+
else
|
23
|
+
base = col.to_s.split('.')[0..-2].join(".")
|
24
|
+
obj = MultiEval.get_nested(doc,base)
|
25
|
+
val = blk.call(obj)
|
26
|
+
mylog 'dot_set',:col => col, :val => val, :doc => doc, :obj => obj
|
27
|
+
doc.dot_set(col.to_s,val)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
doc.to_unwrapped
|
31
|
+
end
|
32
|
+
def save(doc,ops={})
|
33
|
+
mylog 'calc_save', :doc => doc, :doc_class => doc.class, :unwrapped => doc.to_unwrapped.class
|
34
|
+
coll.save(enriched_doc(doc),ops)
|
35
|
+
end
|
36
|
+
def update_calcs!
|
37
|
+
find({},{:limit => 9999}).each do |row|
|
38
|
+
save(row)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
def update_row(row_id,fields)
|
42
|
+
row = (row_id == 'NEW') ? {} : find_by_id(row_id)
|
43
|
+
raise "can't find row #{row_id} #{row_id.class} in coll #{name}. Count is #{find.count} IDs are "+find.to_a.map { |x| x['_id'] }.inspect + "Trying to update with #{fields.inspect}" unless row
|
44
|
+
fields.each do |k,v|
|
45
|
+
row.dot_set(k,mongo_value(v))
|
46
|
+
row.delete(k) if v.blank?
|
47
|
+
end
|
48
|
+
row = enriched_doc(row)
|
49
|
+
save(row)
|
50
|
+
row
|
51
|
+
end
|
52
|
+
def method_missing(sym,*args,&b)
|
53
|
+
coll.send(sym,*args,&b)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class MultiEval
|
2
|
+
attr_accessor :objs
|
3
|
+
include FromHash
|
4
|
+
def methodf_missing(sym,*args,&b)
|
5
|
+
# puts "multi_eval mm #{sym}"
|
6
|
+
objs.each do |obj|
|
7
|
+
begin
|
8
|
+
res = obj.send(sym,*args,&b)
|
9
|
+
if res
|
10
|
+
#other = objs - [obj]
|
11
|
+
# puts "success sending #{sym} to #{obj}"
|
12
|
+
return MultiEval.new(:objs => [res])
|
13
|
+
end
|
14
|
+
rescue => exp
|
15
|
+
# puts "error sending #{sym} to #{obj} #{exp.message}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
objs.first.send(sym,*args,&b)
|
19
|
+
end
|
20
|
+
def without_obj(obj)
|
21
|
+
res = objs.reject { |x| x == obj }
|
22
|
+
raise "didn't find" unless objs.size == res.size+1
|
23
|
+
res
|
24
|
+
rescue => exp
|
25
|
+
puts "#{objs.inspect} #{obj.inspect}"
|
26
|
+
raise exp
|
27
|
+
end
|
28
|
+
def method_missing(sym,*args,&b)
|
29
|
+
objs.each do |obj|
|
30
|
+
if obj.respond_to?(sym)
|
31
|
+
res = obj.send(sym,*args,&b)
|
32
|
+
return MultiEval.new(:objs => [res]+without_obj(obj)) if res
|
33
|
+
end
|
34
|
+
end
|
35
|
+
raise 'none respond'
|
36
|
+
objs.first.send(sym,*args,&b)
|
37
|
+
end
|
38
|
+
def respond_to?(sym)
|
39
|
+
objs.any? { |x| x.respond_to?(sym) }
|
40
|
+
end
|
41
|
+
def coerce(x)
|
42
|
+
objs.first.coerce(x)
|
43
|
+
end
|
44
|
+
def +(x)
|
45
|
+
objs.first + x
|
46
|
+
end
|
47
|
+
def *(x)
|
48
|
+
objs.first * x
|
49
|
+
end
|
50
|
+
def self.get_nested(obj,method_str)
|
51
|
+
other = obj.instance_eval(method_str)
|
52
|
+
mylog 'get_nested', :obj => obj, :method_str => method_str, :other => other
|
53
|
+
arr = [other,obj]
|
54
|
+
new(:objs => arr)
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# class Wrapper
|
2
|
+
# attr_accessor :obj
|
3
|
+
# include FromHash
|
4
|
+
# def method_missing(sym,*args,&b)
|
5
|
+
# obj.send(sym,*args,&b).to_wrapped
|
6
|
+
# end
|
7
|
+
# end
|
8
|
+
|
9
|
+
class Wrapper
|
10
|
+
def respond_to?(sym)
|
11
|
+
obj.respond_to?(sym)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class HashWrapper
|
16
|
+
attr_accessor :hash
|
17
|
+
include FromHash
|
18
|
+
def method_missing(sym,*args,&b)
|
19
|
+
if obj.keys.include?(sym.to_s)
|
20
|
+
self[sym.to_s]
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
def [](x)
|
26
|
+
raise 'dot_set' if x.to_s == 'dot_set'
|
27
|
+
res = hash[x.to_s]
|
28
|
+
res = nil if res.blank?
|
29
|
+
# raise "nil key #{x}" unless res
|
30
|
+
res.to_wrapped
|
31
|
+
end
|
32
|
+
def []=(k,v)
|
33
|
+
obj[k.to_s] = v
|
34
|
+
end
|
35
|
+
def obj; hash; end
|
36
|
+
def to_unwrapped
|
37
|
+
hash.to_unwrapped
|
38
|
+
end
|
39
|
+
def respond_to?(sym)
|
40
|
+
obj.keys.include?(sym.to_s)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ArrayWrapper
|
45
|
+
attr_accessor :obj
|
46
|
+
include FromHash
|
47
|
+
def hash_mm(sym)
|
48
|
+
map { |h| h[sym.to_s] }.select { |x| x }.flatten.to_wrapped
|
49
|
+
end
|
50
|
+
def method_missing(sym,*args,&b)
|
51
|
+
if obj.respond_to?(sym)
|
52
|
+
obj.send(sym,*args,&b).to_wrapped
|
53
|
+
elsif contains_all_hashes?
|
54
|
+
hash_mm(sym)
|
55
|
+
else
|
56
|
+
obj.send(sym,*args,&b).to_wrapped
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def *(arg)
|
60
|
+
map { |x| x * arg }
|
61
|
+
end
|
62
|
+
def to_unwrapped
|
63
|
+
obj.to_unwrapped
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Array
|
68
|
+
def to_unwrapped
|
69
|
+
map { |x| x.to_unwrapped }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Hash
|
74
|
+
def to_unwrapped
|
75
|
+
map_value { |v| v.to_unwrapped }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Wrapper
|
80
|
+
def self.new_inner(obj)
|
81
|
+
if obj.kind_of?(Array)
|
82
|
+
ArrayWrapper.new(:obj => obj)
|
83
|
+
elsif obj.kind_of?(Hash)
|
84
|
+
HashWrapper.new(:hash => obj)
|
85
|
+
else
|
86
|
+
obj
|
87
|
+
end
|
88
|
+
end
|
89
|
+
def self.new(obj)
|
90
|
+
new_inner(obj).tap { |x| mylog 'wrapper', :obj => obj, :wrapper_class => x.class }
|
91
|
+
end
|
92
|
+
def self.wrapped?(obj)
|
93
|
+
[ArrayWrapper,HashWrapper].any? { |cls| obj.kind_of?(cls) }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Object
|
98
|
+
def to_wrapped
|
99
|
+
Wrapper.new(self)
|
100
|
+
end
|
101
|
+
def to_unwrapped_inner
|
102
|
+
if Wrapper.wrapped?(self)
|
103
|
+
obj.to_unwrapped
|
104
|
+
else
|
105
|
+
self
|
106
|
+
end
|
107
|
+
end
|
108
|
+
def to_unwrapped
|
109
|
+
to_unwrapped_inner.tap { |x| mylog 'unwrap', :klass => self.klass, :unwrapped => x.class }
|
110
|
+
end
|
111
|
+
end
|
data/lib/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "CalculatingCollection" do
|
4
|
+
fattr(:row) { {'pension' => {'year' => 2025, 'perc' => 0.65}, 'salary' => 42000, 'year' => 2010} }
|
5
|
+
fattr(:wrapped_row) { Wrapper.new(row) }
|
6
|
+
fattr(:formula) { FormulaEval.new(:row => row) }
|
7
|
+
fattr(:column) { 'pension.perc_plus_salary' }
|
8
|
+
fattr(:str) { '=perc*salary' }
|
9
|
+
fattr(:calc) do
|
10
|
+
CalculatingCollection.new(:column_hash => {column => FormulaEval.new(:formula => str)})
|
11
|
+
end
|
12
|
+
fattr(:enriched) do
|
13
|
+
calc.enriched_doc(wrapped_row)
|
14
|
+
end
|
15
|
+
it 'enriched' do
|
16
|
+
enriched['pension'].should == {'year' => 2025, 'perc' => 0.65, 'perc_plus_salary' => 42000.0*0.65}
|
17
|
+
end
|
18
|
+
it 'enriched 2' do
|
19
|
+
calc.column_hash['double_year'] = FormulaEval.new(:formula => '=year*2')
|
20
|
+
enriched['double_year'].should == 4020
|
21
|
+
end
|
22
|
+
it 'uses sub first' do
|
23
|
+
self.str = '=year+1'
|
24
|
+
enriched['pension']['perc_plus_salary'].should == 2026
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
class A
|
4
|
+
def a
|
5
|
+
1
|
6
|
+
end
|
7
|
+
def [](k)
|
8
|
+
#puts "sending #{k} to #{self}"
|
9
|
+
send(k)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class B
|
14
|
+
def b
|
15
|
+
2
|
16
|
+
end
|
17
|
+
def [](k)
|
18
|
+
#puts "sending #{k} to #{self}"
|
19
|
+
send(k)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def bt
|
24
|
+
raise 'foo'
|
25
|
+
rescue => exp
|
26
|
+
puts exp.message
|
27
|
+
puts exp.backtrace.join("\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "FormulaEval" do
|
31
|
+
fattr(:str) { '=2+2' }
|
32
|
+
fattr(:row) { {'year' => 2010} }
|
33
|
+
fattr(:formula) { FormulaEval.new(:row => row, :formula => str) }
|
34
|
+
it '2+2' do
|
35
|
+
formula.result.should == 4
|
36
|
+
end
|
37
|
+
it 'double_year' do
|
38
|
+
self.str = '=year*2'
|
39
|
+
formula.result.should == 4020
|
40
|
+
end
|
41
|
+
it 'nested' do
|
42
|
+
|
43
|
+
end
|
44
|
+
it 'double' do
|
45
|
+
self.row = MultiEval.new(:objs => [A.new,B.new])
|
46
|
+
self.str = '=a+b'
|
47
|
+
formula.result.should == 3
|
48
|
+
end
|
49
|
+
it 'double 2' do
|
50
|
+
hash = {'year' => 2010, 'pension' => {'start_year' => 2025, 'perc' => 0.65}}
|
51
|
+
self.row = MultiEval.get_nested(Wrapper.new(hash),'pension')
|
52
|
+
self.str = '=perc*year + perc*year'
|
53
|
+
formula.result.should == 0.65 * 2010 * 2
|
54
|
+
end
|
55
|
+
it 'with hash' do
|
56
|
+
self.row = {'year' => 2010, 'pension' => {'start_year' => 2025, 'perc' => 0.65}}
|
57
|
+
self.str = '=year'
|
58
|
+
formula.result.should == 2010
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: formula_eval
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Mike Harris
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-20 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
31
|
+
version: 1.2.9
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
description: formula_eval
|
35
|
+
email: mharris717@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- LICENSE
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- .document
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
50
|
+
- lib/formula_eval.rb
|
51
|
+
- lib/formula_eval/calculating_collection.rb
|
52
|
+
- lib/formula_eval/multi_eval.rb
|
53
|
+
- lib/formula_eval/wrapper.rb
|
54
|
+
- lib/spec.opts
|
55
|
+
- spec/calculating_collection_spec.rb
|
56
|
+
- spec/formula_eval_spec.rb
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/mharris717/formula_eval
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.6
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: formula_eval
|
88
|
+
test_files:
|
89
|
+
- spec/calculating_collection_spec.rb
|
90
|
+
- spec/formula_eval_spec.rb
|
91
|
+
- spec/spec_helper.rb
|