diff --git a/app/controllers/ingredients_controller.rb b/app/controllers/ingredients_controller.rb index 18ca0b2..c54d949 100644 --- a/app/controllers/ingredients_controller.rb +++ b/app/controllers/ingredients_controller.rb @@ -201,68 +201,25 @@ class IngredientsController < ApplicationController def prepare_nutrients @quantities = @project.quantities.where(primary: true) - ingredients, nutrients = compute_nutrients(filter_ingredients, @quantities) + nutrients = filter_ingredients.compute_nutrients(@quantities) @nutrients = {} @extra_nutrients = {} - ingredients.each do |i| + nutrients.each do |i, requested_n, extra_n| @nutrients[i] = [] - @extra_nutrients[i] = {} - @quantities.each do |q| - @nutrients[i] << [q.name, "%d [%s]" % nutrients[i][q.name]] - #@extra_nutrients[i][n.quantity.name] = "#{n.amount} [#{n.unit.shortname}]" + requested_n.each do |q_name, value| + amount, unitname = value + @nutrients[i] << [q_name, "#{amount || '-'} [#{unitname || '-'}]"] + end + + @extra_nutrients[i] = [] + extra_n.each do |q_name, value| + amount, unitname = value + @extra_nutrients[i] << [q_name, "#{amount || '-'} [#{unitname || '-'}]"] end end end - def compute_nutrients(ingredients, requested_q) - unchecked_q = requested_q.map { |q| [q, nil] } - - nutrients = Hash.new { |h,k| h[k] = {} } - Nutrient.where(ingredient: ingredients).includes(:quantity, :unit) - .pluck('quantities.name', :ingredient_id, :amount, 'units.shortname') - .each { |q_name, i_id, a, u_id| nutrients[q_name][i_id] = [a, u_id] } - - completed_q = {} - # FIXME: loop should finish unless there is circular dependency in formulas - # for now we don't guard against that - while !unchecked_q.empty? - q, deps = unchecked_q.shift - - if q.formula.blank? || (nutrients[q.name].length == ingredients.length) - completed_q[q.name] = nutrients.delete(q.name) - next - end - - if deps.nil? || !deps.empty? - deps ||= q.formula_quantities - deps.reject! { |q| completed_q.has_key?(q.name) } - deps.each { |q| unchecked_q << [q, nil] unless unchecked_q.index { |u| u[0] == q } } - end - - if deps.empty? - input_q = q.formula_quantities - ingredients.each do |i| - next if !nutrients[q.name][i.id].nil? - inputs = input_q.map do |i_q| - default_data = [nil, nil] - nutrient_data = (completed_q[i_q.name] || nutrients[i_q.name])[i.id] - [i_q.name, (nutrient_data || default_data)[0]] - end - nutrients[q.name][i.id] = q.calculate(inputs) - end - unchecked_q.unshift([q, deps]) - else - unchecked_q << [q, deps] - end - end - - all_q = nutrients.merge!(completed_q) - results = Hash.new { |h,k| h[k] = {} } - requested_q.each { |q| ingredients.each { |i| results[i][q.name] = all_q[q.name][i.id] } } - [ingredients, results] - end - def filter_ingredients filters = session[:filters] || {} ingredients = @project.ingredients diff --git a/app/models/ingredient.rb b/app/models/ingredient.rb index 038823b..b441797 100644 --- a/app/models/ingredient.rb +++ b/app/models/ingredient.rb @@ -35,4 +35,62 @@ class Ingredient < ActiveRecord::Base end end + def self.compute_nutrients(requested_q) + ingredients = all + unchecked_q = requested_q.map { |q| [q, nil] } + + nutrients = Hash.new { |h,k| h[k] = {} } + Nutrient.where(ingredient: ingredients).includes(:quantity, :unit) + .order('quantities.lft') + .pluck('quantities.name', :ingredient_id, :amount, 'units.shortname') + .each { |q_name, i_id, a, u_id| nutrients[q_name][i_id] = [a, u_id] } + + extra_q = nutrients.keys - requested_q.pluck(:name) + + completed_q = {} + # FIXME: loop should finish unless there is circular dependency in formulas + # for now we don't guard against that + while !unchecked_q.empty? + q, deps = unchecked_q.shift + + if q.formula.blank? || (nutrients[q.name].length == ingredients.count) + completed_q[q.name] = nutrients.delete(q.name) + next + end + + if deps.nil? || !deps.empty? + deps ||= q.formula_quantities + deps.reject! { |q| completed_q.has_key?(q.name) } + deps.each { |q| unchecked_q << [q, nil] unless unchecked_q.index { |u| u[0] == q } } + end + + if deps.empty? + input_q = q.formula_quantities + ingredients.each do |i| + next if !nutrients[q.name][i.id].nil? + inputs = input_q.map do |i_q| + default_input = [nil, nil] + nutrient_data = (completed_q[i_q.name] || nutrients[i_q.name])[i.id] + [i_q.name, (nutrient_data || [nil, nil])[0]] + end + nutrients[q.name][i.id] = q.calculate(inputs) + end + unchecked_q.unshift([q, deps]) + else + unchecked_q << [q, deps] + end + end + + all_q = nutrients.merge(completed_q) + results = [] + ingredients.each do |i| + results << [i, + requested_q.map { |q| [q.name, all_q[q.name][i.id]] }, + extra_q.map do |q_name| + [q_name, all_q[q_name][i.id]] if all_q[q_name][i.id] + end.compact + ] + end + results + end end diff --git a/app/models/quantity.rb b/app/models/quantity.rb index f2ad00f..40fee40 100644 --- a/app/models/quantity.rb +++ b/app/models/quantity.rb @@ -63,7 +63,7 @@ class Quantity < ActiveRecord::Base end def formula_quantities - q_names = Ripper.lex(formula).each do |*, ttype, token| + q_names = Ripper.lex(formula).map do |*, ttype, token| token if QUANTITY_TTYPES.include?(ttype) end.compact self.project.quantities.where(name: q_names).to_a diff --git a/app/views/ingredients/_list_nutrients.html.erb b/app/views/ingredients/_list_nutrients.html.erb index c9fbd5b..6bfdfa0 100644 --- a/app/views/ingredients/_list_nutrients.html.erb +++ b/app/views/ingredients/_list_nutrients.html.erb @@ -18,10 +18,8 @@ <%= i.name %> - <% @quantities.each do |q| %> - - <%= values[q.id] || '-' %> - + <% values.each do |*, value| %> + <%= value %> <% end %> @@ -29,43 +27,35 @@ <%= i.name %> - <% @quantities.each do |q| %> - - <%= q.name %> - + <% values.each do |q_name, *| %> + <%= q_name %> <% end %> - <% @quantities.each do |q| %> - - <%= values[q.id] || '-' %> - + <% values.each do |*, value| %> + <%= value %> <% end %> - <% extras = @extra_nutrients[i].keys %> - <% extras.each_slice(@quantities.length).with_index do |names, index| %> + <% extras = @extra_nutrients[i] %> + <% extras.each_slice(@quantities.length).with_index do |values, index| %> - <% names.each do |name| %> - - <%= name %> - + <% values.each do |q_name, *| %> + <%= q_name %> <% end %> - <% if @quantities.length > names.length %> - + <% if @quantities.length > values.length %> + <% end %> - <% names.each do |name| %> - - <%= @extra_nutrients[i][name] %> - + <% values.each do |*, value| %> + <%= value %> <% end %> - <% if @quantities.length > names.length %> - + <% if @quantities.length > values.length %> + <% end %> <% end %> diff --git a/app/views/ingredients/_options.html.erb b/app/views/ingredients/_options.html.erb index 41fa820..645cbd0 100644 --- a/app/views/ingredients/_options.html.erb +++ b/app/views/ingredients/_options.html.erb @@ -18,9 +18,9 @@ - <% total_width = 3 + @primary_quantities.length %> + <% total_width = 3 + @quantities.length %> - <% @primary_quantities.each do |q| %> + <% @quantities.each do |q| %>
<%= link_to l(:button_hide), toggle_nutrient_column_project_ingredients_path(@project, id: q.id),