1
0

Updated Formula::calculate to use FormulaBuilder

This commit is contained in:
cryptogopher 2020-01-27 00:59:33 +01:00
parent 98207fc980
commit df8703ba3c
4 changed files with 44 additions and 22 deletions

View File

@ -29,6 +29,24 @@ class Quantity < ActiveRecord::Base
if new_record? if new_record?
self.domain ||= :diet self.domain ||= :diet
end end
@formula = Formula.new(self.project, self.formula)
end
def formula=(value)
@formula = Formula.new(self.project, value)
super(value)
end
def formula_valid?
@formula.valid?
end
def formula_quantities
@formula.get_quantities
end
def calculate(inputs)
@formula.calculate(inputs)
end end
def movable?(direction) def movable?(direction)
@ -47,14 +65,6 @@ class Quantity < ActiveRecord::Base
end end
end end
def formula_quantities
Formula.new(self.project, self.formula).get_quantities
end
def calculate(inputs)
Formula.new(self.project, self.formula).calculate(inputs)
end
def self.filter(project, filters) def self.filter(project, filters)
quantities = all quantities = all

View File

@ -43,7 +43,7 @@
</td> </td>
<td class="domain"><%= q.domain %></td> <td class="domain"><%= q.domain %></td>
<td class="description"><%= q.description %></td> <td class="description"><%= q.description %></td>
<td class="formula"><%= checked_image q.formula.present? %></td> <td class="formula"><%= checked_image q.formula? %></td>
<td class="action unwrappable"> <td class="action unwrappable">
<%= link_to l(:button_edit), edit_quantity_path(q), { <%= link_to l(:button_edit), edit_quantity_path(q), {
remote: true, remote: true,

View File

@ -4,6 +4,7 @@ module BodyTracking
require 'set' require 'set'
class InvalidFormula < RuntimeError; end class InvalidFormula < RuntimeError; end
class InvalidInputs < RuntimeError; end
class Formula class Formula
def initialize(project, formula) def initialize(project, formula)
@ -33,28 +34,36 @@ module BodyTracking
end end
def get_quantities def get_quantities
raise RuntimeError, 'Invalid formula' unless self.valid? raise(InvalidFormula, 'Invalid formula') unless self.valid?
@quantities.to_a @quantities.to_a
end end
#"params.values.first.each_with_index.map { |*, _index| #{@paramed_formula} }"
def calculate(inputs) def calculate(inputs)
raise RuntimeError, 'Invalid formula' unless self.valid? byebug
params = inputs.map { |q, v| [q.name, v.transpose[0]] }.to_h
length = params.values.first.length
values = inputs.map { |q, v| [q.name, v.transpose[0]] }.to_h raise(InvalidFormula, 'Invalid formula') unless self.valid?
puts values.inspect raise InvalidInputs unless params.values.all? { |v| v.length == length }
begin
get_binding(values).eval(@paramed_formula).map { |x| [x, nil] } args = []
@parts.each do |p|
args << get_binding(params, length)
.eval(
p[:type] == :indexed ? "length.times.map { |_index| #{p[:content]} }" :
p[:content]
)
end
args.last.map { |v| [v, nil] }
rescue Exception => e rescue Exception => e
puts e.message puts e.message
[[nil, nil]] * inputs.values.first.length [[nil, nil]] * length
end
end end
private private
def get_binding(params) def get_binding(params, _length)
binding binding
end end
end end
@ -73,6 +82,8 @@ module BodyTracking
end end
# List of events with parameter count:
# https://github.com/racker/ruby-1.9.3-lucid/blob/master/ext/ripper/eventids1.c
class FormulaBuilder < Ripper::SexpBuilder class FormulaBuilder < Ripper::SexpBuilder
def initialize(*args) def initialize(*args)
super(*args) super(*args)
@ -109,7 +120,7 @@ module BodyTracking
def on_program(stmts) def on_program(stmts)
@parts << {type: :indexed, content: join_stmts(stmts)} @parts << {type: :indexed, content: join_stmts(stmts)}
[@identifiers, @parts] [@identifiers.to_a, @parts]
end end
def on_string_content def on_string_content

View File

@ -67,7 +67,7 @@ module BodyTracking
q, deps = unchecked_q.shift q, deps = unchecked_q.shift
# quantity not computable (no formula) or not requiring calculation/computed # quantity not computable (no formula) or not requiring calculation/computed
if q.formula.blank? || (subitems[q.name].length == items.count) if !q.formula? || !q.formula_valid? || (subitems[q.name].length == items.count)
completed_q[q.name] = subitems.delete(q.name) { {} } completed_q[q.name] = subitems.delete(q.name) { {} }
completed_q[q.name].default = [nil, nil] completed_q[q.name].default = [nil, nil]
next next
@ -83,6 +83,7 @@ module BodyTracking
# quantity with formula has all dependencies satisfied, requires calculation # quantity with formula has all dependencies satisfied, requires calculation
if deps.empty? if deps.empty?
output_ids = items.select { |i| subitems[q.name][i.id].nil? }.map(&:id) output_ids = items.select { |i| subitems[q.name][i.id].nil? }.map(&:id)
byebug
input_q = q.formula_quantities input_q = q.formula_quantities
inputs = input_q.map { |i_q| [i_q, completed_q[i_q.name].values_at(*output_ids)] } inputs = input_q.map { |i_q| [i_q, completed_q[i_q.name].values_at(*output_ids)] }
q.calculate(inputs.to_h).each_with_index do |result, index| q.calculate(inputs.to_h).each_with_index do |result, index|