soroban 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,7 +6,6 @@ group :development do
6
6
  gem "rubyXL", "~> 1.2.7"
7
7
  gem "nokogiri", ">= 1.4.4"
8
8
  gem "rubyzip", ">= 0.9.4"
9
- gem "awesome_print"
10
9
  end
11
10
 
12
11
  group :test do
@@ -1,7 +1,6 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- awesome_print (1.1.0)
5
4
  diff-lcs (1.1.3)
6
5
  git (1.2.5)
7
6
  jeweler (1.8.4)
@@ -35,7 +34,6 @@ PLATFORMS
35
34
  ruby
36
35
 
37
36
  DEPENDENCIES
38
- awesome_print
39
37
  jeweler (~> 1.8.3)
40
38
  nokogiri (>= 1.4.4)
41
39
  rake
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Agworld Pty. Ltd.
1
+ Copyright (c) 2014 Agworld Pty. Ltd.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -147,13 +147,6 @@ s.g = "=FOO(10, 20)"
147
147
  puts s.g # => 17
148
148
  ```
149
149
 
150
- Compilation
151
- -----------
152
-
153
- Rather than interact with a `Soroban::Sheet` object at runtime, you can compile
154
- the sheet into a Ruby or JavaScript class which you can then either save out to
155
- a file or evaluate directly. This is slightly less flexible, but more efficient.
156
-
157
150
  Contributing to Soroban
158
151
  -----------------------
159
152
 
@@ -168,4 +161,4 @@ Contributing to Soroban
168
161
  Copyright
169
162
  ---------
170
163
 
171
- Copyright (c) 2013 Agworld Pty. Ltd. See LICENSE.txt for further details.
164
+ Copyright (c) 2014 Agworld Pty. Ltd. See LICENSE.txt for further details.
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "soroban"
8
- s.version = "0.7.2"
8
+ s.version = "0.7.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jason Hutchens"]
12
- s.date = "2013-09-03"
12
+ s.date = "2014-03-20"
13
13
  s.description = "Soroban makes it easy to extract and execute formulas from Excel spreadsheets. It rewrites Excel formulas as Ruby expressions, and allows you to bind named variables to spreadsheet cells to easily manipulate inputs and capture outputs."
14
14
  s.email = "jason.hutchens@agworld.com.au"
15
15
  s.extra_rdoc_files = [
@@ -55,7 +55,6 @@ Gem::Specification.new do |s|
55
55
  "lib/soroban/parser/nodes.rb",
56
56
  "lib/soroban/parser/rewrite.rb",
57
57
  "lib/soroban/sheet.rb",
58
- "lib/soroban/tabulator.rb",
59
58
  "lib/soroban/value_walker.rb",
60
59
  "spec/documentation_spec.rb",
61
60
  "spec/import_spec.rb",
@@ -76,20 +75,17 @@ Gem::Specification.new do |s|
76
75
  s.add_development_dependency(%q<rubyXL>, ["~> 1.2.7"])
77
76
  s.add_development_dependency(%q<nokogiri>, [">= 1.4.4"])
78
77
  s.add_development_dependency(%q<rubyzip>, [">= 0.9.4"])
79
- s.add_development_dependency(%q<awesome_print>, [">= 0"])
80
78
  else
81
79
  s.add_dependency(%q<treetop>, ["~> 1.4.10"])
82
80
  s.add_dependency(%q<rubyXL>, ["~> 1.2.7"])
83
81
  s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
84
82
  s.add_dependency(%q<rubyzip>, [">= 0.9.4"])
85
- s.add_dependency(%q<awesome_print>, [">= 0"])
86
83
  end
87
84
  else
88
85
  s.add_dependency(%q<treetop>, ["~> 1.4.10"])
89
86
  s.add_dependency(%q<rubyXL>, ["~> 1.2.7"])
90
87
  s.add_dependency(%q<nokogiri>, [">= 1.4.4"])
91
88
  s.add_dependency(%q<rubyzip>, [">= 0.9.4"])
92
- s.add_dependency(%q<awesome_print>, [">= 0"])
93
89
  end
94
90
  end
95
91
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.2
1
+ 0.7.3
@@ -7,7 +7,7 @@ module Soroban
7
7
  # representation of its contents, and the executable Ruby version of same, as
8
8
  # generated via a rewrite grammar. Cells also store their dependencies.
9
9
  class Cell
10
- attr_reader :excel, :javascript, :dependencies
10
+ attr_reader :excel, :dependencies
11
11
 
12
12
  # Cells are initialised with a binding to allow formulas to be executed
13
13
  # within the context of the sheet which owns the cell.
@@ -18,10 +18,6 @@ module Soroban
18
18
  @value = nil
19
19
  end
20
20
 
21
- def to_compiled_ruby
22
- @tree.to_compiled_ruby
23
- end
24
-
25
21
  # Set the contents of a cell, and store the executable Ruby version.
26
22
  def set(contents)
27
23
  contents = contents.to_s
@@ -30,7 +26,7 @@ module Soroban
30
26
  @excel = contents
31
27
  @tree = Soroban::parser.parse(@excel)
32
28
  raise Soroban::ParseError, Soroban::parser.failure_reason if @tree.nil?
33
- @ruby = _to_ruby
29
+ @ruby = @tree.to_ruby(@dependencies.clear)
34
30
  end
35
31
 
36
32
  # Clear the cached value of a cell to force it to be recalculated
@@ -49,17 +45,6 @@ module Soroban
49
45
  ensure
50
46
  @touched = false
51
47
  end
52
-
53
- private
54
-
55
- def _to_ruby
56
- @tree.to_ruby(@dependencies.clear)
57
- end
58
-
59
- def _to_javascript
60
- @tree.to_javascript(@dependencies.clear)
61
- end
62
-
63
48
  end
64
49
 
65
50
  end
@@ -4,16 +4,12 @@ module Soroban
4
4
  def rewrite_ruby(value)
5
5
  value.gsub(/^= */, '')
6
6
  end
7
- alias :compile_ruby :rewrite_ruby
8
7
  end
9
8
 
10
9
  class Identifier < Treetop::Runtime::SyntaxNode
11
10
  def rewrite_ruby(value)
12
11
  "@#{value}.get"
13
12
  end
14
- def compile_ruby(value)
15
- "@cells[:#{value}].call"
16
- end
17
13
  def extract(value)
18
14
  value.to_sym
19
15
  end
@@ -23,14 +19,12 @@ module Soroban
23
19
  def rewrite_ruby(value)
24
20
  "#{value.to_f}"
25
21
  end
26
- alias :compile_ruby :rewrite_ruby
27
22
  end
28
23
 
29
24
  class FloatValue < Treetop::Runtime::SyntaxNode
30
25
  def rewrite_ruby(value)
31
26
  "#{value.to_f}"
32
27
  end
33
- alias :compile_ruby :rewrite_ruby
34
28
  end
35
29
 
36
30
  class Function < Treetop::Runtime::SyntaxNode
@@ -38,66 +32,36 @@ module Soroban
38
32
  match = /^([^(]*)(.*)$/.match(value)
39
33
  "func_#{match[1].downcase}#{match[2]}"
40
34
  end
41
- def compile_ruby(value)
42
- match = /^([A-Z]+)\((.*)\)$/.match(value)
43
- name, args = match[1], match[2].split(',')
44
- case name
45
- when 'VLOOKUP'
46
- find, table, column, _ = args
47
- table = table[1...-1]
48
- column = column.to_i
49
- table_key = "'#{table}_#{column}'"
50
- code = []
51
- code << "begin"
52
- code << " @cache[#{table_key}] ||= {"
53
- cols = Tabulator.new(table).get
54
- lookup = Hash[cols[0].zip(cols[column-1])]
55
- code << lookup.map do |key, val|
56
- " @cells[:#{key}].call => @cells[:#{val}].call"
57
- end.join(",\n")
58
- code << " }"
59
- code << " @cache[#{table_key}][#{find}] || 0.0"
60
- code << " end"
61
- code.join("\n")
62
- else
63
- value
64
- end
65
- end
66
35
  end
67
36
 
68
37
  class Pow < Treetop::Runtime::SyntaxNode
69
38
  def rewrite_ruby(value)
70
39
  "**"
71
40
  end
72
- alias :compile_ruby :rewrite_ruby
73
41
  end
74
42
 
75
43
  class Equal < Treetop::Runtime::SyntaxNode
76
44
  def rewrite_ruby(value)
77
45
  "=="
78
46
  end
79
- alias :compile_ruby :rewrite_ruby
80
47
  end
81
48
 
82
49
  class NotEqual < Treetop::Runtime::SyntaxNode
83
50
  def rewrite_ruby(value)
84
51
  "!="
85
52
  end
86
- alias :compile_ruby :rewrite_ruby
87
53
  end
88
54
 
89
55
  class Label < Treetop::Runtime::SyntaxNode
90
56
  def rewrite_ruby(value)
91
57
  value.gsub('$', '')
92
58
  end
93
- alias :compile_ruby :rewrite_ruby
94
59
  end
95
60
 
96
61
  class Range < Treetop::Runtime::SyntaxNode
97
62
  def rewrite_ruby(value)
98
63
  "'#{value}'"
99
64
  end
100
- alias :compile_ruby :rewrite_ruby
101
65
  def extract(value)
102
66
  LabelWalker.new(value).map { |label| "#{label}".to_sym }
103
67
  end
@@ -14,40 +14,10 @@ module Treetop
14
14
  end
15
15
  end
16
16
 
17
- def to_compiled_ruby
18
- if nonterminal?
19
- value = ""
20
- elements.each { |element| value << element.to_compiled_ruby }
21
- compile_ruby(value)
22
- else
23
- compile_ruby(text_value)
24
- end
25
- end
26
-
27
- def to_javascript(dependencies)
28
- if nonterminal?
29
- value = ""
30
- elements.each { |element| value << element.to_javascript(dependencies) }
31
- _add_dependency(dependencies, extract(value))
32
- rewrite_javascript(value)
33
- else
34
- _add_dependency(dependencies, extract(text_value))
35
- rewrite_javascript(text_value)
36
- end
37
- end
38
-
39
- def compile_ruby(value)
40
- value
41
- end
42
-
43
17
  def rewrite_ruby(value)
44
18
  value
45
19
  end
46
20
 
47
- def rewrite_javascript(value)
48
- value
49
- end
50
-
51
21
  def extract(value)
52
22
  end
53
23
 
@@ -2,7 +2,6 @@ require 'soroban/helpers'
2
2
  require 'soroban/functions'
3
3
  require 'soroban/label_walker'
4
4
  require 'soroban/value_walker'
5
- require 'soroban/tabulator'
6
5
  require 'soroban/cell'
7
6
 
8
7
  require 'set'
@@ -17,62 +16,10 @@ module Soroban
17
16
  def initialize(logger=nil)
18
17
  @logger = logger
19
18
  @cells = {}
20
- @compiled = {}
21
19
  @changes = Hash.new{ |h, k| h[k] = Set.new }
22
20
  @bindings = {}
23
21
  end
24
22
 
25
- def factory(name)
26
- eval(self.to_ruby(name), TOPLEVEL_BINDING)
27
- Object::const_get('Soroban').const_get('Model').const_get(name).new
28
- end
29
-
30
- # Return a string containing a ruby class that implements the sheet. You can
31
- # call eval() on this string to create the class, which you can then
32
- # instantiate. Set inputs on the instance and read outputs off.
33
- def to_ruby(class_name)
34
- data = []
35
- data << "module Soroban"
36
- data << "module Model"
37
- data << "class #{class_name}"
38
- data << " def initialize"
39
- data << " @binds = {"
40
- data << bindings.map do |name, cell|
41
- " '#{name}' => :#{cell}"
42
- end.join(",\n")
43
- data << " }"
44
- data << " @cache = {}"
45
- data << " @cells = {"
46
- data << @compiled.map do |label, cell|
47
- " :#{label} => lambda { @cache[:#{label}] ||= #{cell.to_compiled_ruby} }"
48
- end.join(",\n")
49
- data << " }"
50
- data << " end"
51
- data << " def clear"
52
- data << " @cache.clear"
53
- data << " end"
54
- data << " def get(name)"
55
- data << " @cells[@binds[name]].call"
56
- data << " end"
57
- data << " def set(name, value)"
58
- data << " self.clear"
59
- data << " @cells[@binds[name]] = lambda { @cache[@binds[name]] ||= value }"
60
- data << " end"
61
- bindings.each do |name, cell|
62
- data << " def #{name}"
63
- data << " get('#{name}')"
64
- data << " end"
65
- data << " def #{name}=(value)"
66
- data << " set('#{name}', value)"
67
- data << " end"
68
- end
69
- data << "end"
70
- data << "end"
71
- data << "end"
72
- puts data.join("\n")
73
- data.join("\n")
74
- end
75
-
76
23
  # Used for calling dynamically defined functions, and for creating new
77
24
  # cells (via `label=`).
78
25
  def method_missing(method, *args, &block)
@@ -180,7 +127,6 @@ module Soroban
180
127
  internal = "@#{label}"
181
128
  _expose(internal, label)
182
129
  cell = Cell.new(binding)
183
- @compiled[label] = cell
184
130
  _set(label, cell, contents)
185
131
  instance_variable_set(internal, cell)
186
132
  end
@@ -28,47 +28,6 @@ describe "Documentation", :if => has_rubyxl do
28
28
  puts s.force # => 710.044826106394
29
29
  s.force.should be_within(0.01).of(710.04)
30
30
 
31
- require 'benchmark'
32
-
33
- i_time = Benchmark.realtime do
34
- 1000.times do
35
- s.planet = 'Earth'
36
- s.mass = 80
37
- s.force
38
- s.planet = 'Venus'
39
- s.mass = 80
40
- s.force
41
- end
42
- end
43
-
44
- puts "Interpreted Time: #{i_time}"
45
-
46
- eval(s.to_ruby("Test"))
47
- model = Soroban::Model::Test.new
48
-
49
- model.planet = 'Earth'
50
- model.mass = 80
51
- model.force.should be_within(0.01).of(783.46)
52
-
53
- model.planet = 'Venus'
54
- model.mass = 80
55
- model.force.should be_within(0.01).of(710.04)
56
-
57
- c_time = Benchmark.realtime do
58
- 1000.times do
59
- model.planet = 'Earth'
60
- model.mass = 80
61
- model.force
62
- model.planet = 'Venus'
63
- model.mass = 80
64
- model.force
65
- end
66
- end
67
-
68
- puts "Compiled Time: #{c_time}"
69
-
70
- (10.0 * c_time).should be < i_time
71
-
72
31
  end
73
32
 
74
33
  end
@@ -61,12 +61,6 @@ describe "Soroban" do
61
61
  sheet.bindings.keys.should include :output
62
62
  sheet.bindings.values.should include :A1
63
63
  sheet.bindings.values.should include :A2
64
-
65
- model = sheet.factory('Test')
66
- model.input = 5
67
- model.output.should eq(25)
68
- model.input = 4
69
- model.output.should eq(16)
70
64
  end
71
65
 
72
66
  it "can bind variables to ranges" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soroban
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 7
9
- - 2
10
- version: 0.7.2
9
+ - 3
10
+ version: 0.7.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jason Hutchens
@@ -15,10 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-09-03 00:00:00 Z
18
+ date: 2014-03-20 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- requirement: &id001 !ruby/object:Gem::Requirement
21
+ name: treetop
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
23
  none: false
23
24
  requirements:
24
25
  - - ~>
@@ -29,12 +30,12 @@ dependencies:
29
30
  - 4
30
31
  - 10
31
32
  version: 1.4.10
32
- type: :runtime
33
- version_requirements: *id001
34
- name: treetop
35
33
  prerelease: false
34
+ type: :runtime
35
+ requirement: *id001
36
36
  - !ruby/object:Gem::Dependency
37
- requirement: &id002 !ruby/object:Gem::Requirement
37
+ name: rubyXL
38
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
39
  none: false
39
40
  requirements:
40
41
  - - ~>
@@ -45,12 +46,12 @@ dependencies:
45
46
  - 2
46
47
  - 7
47
48
  version: 1.2.7
48
- type: :development
49
- version_requirements: *id002
50
- name: rubyXL
51
49
  prerelease: false
50
+ type: :development
51
+ requirement: *id002
52
52
  - !ruby/object:Gem::Dependency
53
- requirement: &id003 !ruby/object:Gem::Requirement
53
+ name: nokogiri
54
+ version_requirements: &id003 !ruby/object:Gem::Requirement
54
55
  none: false
55
56
  requirements:
56
57
  - - ">="
@@ -61,12 +62,12 @@ dependencies:
61
62
  - 4
62
63
  - 4
63
64
  version: 1.4.4
64
- type: :development
65
- version_requirements: *id003
66
- name: nokogiri
67
65
  prerelease: false
66
+ type: :development
67
+ requirement: *id003
68
68
  - !ruby/object:Gem::Dependency
69
- requirement: &id004 !ruby/object:Gem::Requirement
69
+ name: rubyzip
70
+ version_requirements: &id004 !ruby/object:Gem::Requirement
70
71
  none: false
71
72
  requirements:
72
73
  - - ">="
@@ -77,24 +78,9 @@ dependencies:
77
78
  - 9
78
79
  - 4
79
80
  version: 0.9.4
80
- type: :development
81
- version_requirements: *id004
82
- name: rubyzip
83
81
  prerelease: false
84
- - !ruby/object:Gem::Dependency
85
- requirement: &id005 !ruby/object:Gem::Requirement
86
- none: false
87
- requirements:
88
- - - ">="
89
- - !ruby/object:Gem::Version
90
- hash: 3
91
- segments:
92
- - 0
93
- version: "0"
94
82
  type: :development
95
- version_requirements: *id005
96
- name: awesome_print
97
- prerelease: false
83
+ requirement: *id004
98
84
  description: Soroban makes it easy to extract and execute formulas from Excel spreadsheets. It rewrites Excel formulas as Ruby expressions, and allows you to bind named variables to spreadsheet cells to easily manipulate inputs and capture outputs.
99
85
  email: jason.hutchens@agworld.com.au
100
86
  executables: []
@@ -143,7 +129,6 @@ files:
143
129
  - lib/soroban/parser/nodes.rb
144
130
  - lib/soroban/parser/rewrite.rb
145
131
  - lib/soroban/sheet.rb
146
- - lib/soroban/tabulator.rb
147
132
  - lib/soroban/value_walker.rb
148
133
  - spec/documentation_spec.rb
149
134
  - spec/import_spec.rb
@@ -1,34 +0,0 @@
1
- module Soroban
2
-
3
- # An enumerable that splits a range of cells into an nxm array
4
- class Tabulator
5
-
6
- include Enumerable
7
-
8
- # Create a new walker from a supplied range.
9
- def initialize(range)
10
- @fc, @fr, @tc, @tr = Soroban::getRange(range)
11
- end
12
-
13
- def get
14
- row = []
15
- cols = [row]
16
- col_ref, row_ref = @fc, @fr
17
- while true do
18
- row << "#{col_ref}#{row_ref}".to_sym
19
- break if row_ref == @tr && col_ref == @tc
20
- if row_ref == @tr
21
- row = []
22
- cols << row
23
- row_ref = @fr
24
- col_ref = col_ref.next
25
- else
26
- row_ref = row_ref.next
27
- end
28
- end
29
- cols
30
- end
31
-
32
- end
33
-
34
- end