Extra conversion options

This commit is contained in:
Dan Elbert 2016-02-27 20:12:41 -06:00
parent a86c5afae2
commit dd493a09d5
8 changed files with 266 additions and 16 deletions

View File

@ -1,6 +1,6 @@
class RecipesController < ApplicationController
before_action :set_recipe, only: [:show, :edit, :update, :destroy, :scale]
before_action :set_recipe, only: [:show, :edit, :update, :destroy]
before_filter :ensure_valid_user, except: [:show, :scale, :index]
@ -12,6 +12,31 @@ class RecipesController < ApplicationController
# GET /recipes/1
# GET /recipes/1.json
def show
if params[:scale].present?
@scale = params[:scale]
@recipe.scale(params[:scale], true)
end
if params[:system].present?
@system = params[:system]
case @system
when 'metric'
@recipe.convert_to_metric
when 'standard'
@recipe.convert_to_standard
end
end
if params[:unit].present?
@unit = params[:unit]
case @unit
when 'mass'
@recipe.convert_to_mass
when 'volume'
@recipe.convert_to_volume
end
end
end
# GET /recipes/1

View File

@ -30,6 +30,30 @@ class Recipe < ActiveRecord::Base
end
end
def convert_to_metric
recipe_ingredients.each do |ri|
ri.to_metric
end
end
def convert_to_standard
recipe_ingredients.each do |ri|
ri.to_standard
end
end
def convert_to_mass
recipe_ingredients.each do |ri|
ri.to_mass
end
end
def convert_to_volume
recipe_ingredients.each do |ri|
ri.to_volume
end
end
def nutrition_data(recalculate = false)
if recalculate || @nutrition_data.nil?
@nutrition_data = calculate_nutrition_data

View File

@ -34,6 +34,52 @@ class RecipeIngredient < ActiveRecord::Base
end
end
def to_metric
return unless self.quantity.present?
value_unit = UnitConversion.parse(self.quantity, self.units)
value_unit = value_unit.to_metric
self.quantity = value_unit.pretty_value
self.units = value_unit.unit.to_s
end
def to_standard
return unless self.quantity.present?
value_unit = UnitConversion.parse(self.quantity, self.units)
value_unit = value_unit.to_standard
self.quantity = value_unit.pretty_value
self.units = value_unit.unit.to_s
end
def to_volume
return unless self.quantity.present?
if ingredient && ingredient.density
density = UnitConversion.parse(ingredient.density)
if density.density?
value_unit = UnitConversion.parse(self.quantity, self.units)
value_unit = value_unit.to_volume(density)
self.quantity = value_unit.pretty_value
self.units = value_unit.unit.to_s
end
end
end
def to_mass
return unless self.quantity.present?
if ingredient && ingredient.density
density = UnitConversion.parse(ingredient.density)
if density.density?
value_unit = UnitConversion.parse(self.quantity, self.units)
value_unit = value_unit.to_mass(density)
self.quantity = value_unit.pretty_value
self.units = value_unit.unit.to_s
end
end
end
def can_convert_to_grams?
if self.quantity.present? && self.units.present?
value_unit = UnitConversion.parse(self.quantity, self.units)

View File

@ -46,19 +46,9 @@
<div class="row">
<h3 class="panel-title col-xs-7">Ingredients</h3>
<div class="dropdown col-xs-5">
<button id="scaleLabel" type="button" class="pull-right btn btn-xs btn-default" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Scale
<span class="caret"></span>
<button id="scaleLabel" type="button" class="pull-right btn btn-xs btn-default" data-toggle="modal" data-target="#translate_modal">
Translate
</button>
<ul class="dropdown-menu" aria-labelledby="scaleLabel">
<% ['1/4', '1/3', '1/2', '2/3', '3/4', '1', '1 1/2', '2', '3', '4'].each do |scale| %>
<% if scale == '1' %>
<li><%= link_to scale, @recipe %></li>
<% else %>
<li><%= link_to scale, scale_recipe_path(@recipe, scale) %></li>
<% end %>
<% end %>
</ul>
</div>
</div>
@ -152,4 +142,79 @@
<%= link_to 'Back', recipes_path, class: 'btn btn-default' %>
</div>
</div>
<div class="modal fade" id="translate_modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Recipe Translation</h4>
</div>
<div class="modal-body">
<%= form_tag(recipe_path(@recipe), method: :get, authenticity_token: false, enforce_utf8: false, id: 'translate_form') do %>
<div class="row">
<div class="col-xs-12">
<div class="form-group form-group">
<%= label_tag :scale, 'Scale', class: "control-label" %>
<%= select_tag :scale, options_for_select(['1/4', '1/3', '1/2', '2/3', '3/4', '1', '1 1/2', '2', '3', '4'], '1'), class: 'form-control' %>
</div>
<div class="well">
<div class="radio">
<label>
<input type="radio" name="system" id="system_none" value="" checked>
No System Translation
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="system" id="system_standard" value="standard">
Convert to Standard Units
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="system" id="system_metric" value="metric">
Convert to Metric Units
</label>
</div>
</div>
<div class="well">
<div class="radio">
<label>
<input type="radio" name="unit" id="unit_none" value="" checked>
No Unit Translation
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="unit" id="unit_mass" value="mass">
Convert to Mass Units
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="unit" id="unit_volume" value="volume">
Convert to Volume Units
</label>
</div>
</div>
</div>
</div>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" form="translate_form">Convert</button>
</div>
</div>
</div>
</div>

View File

@ -1,9 +1,7 @@
Rails.application.routes.draw do
resources :recipes do
member do
get 'scale/:factor', action: :scale, as: :scale
end
end
resources :ingredients, except: [:show] do

View File

@ -80,4 +80,64 @@ module UnitConversion
end
end
class MetricUnitConversion < Conversion
def convert(value_unit)
if value_unit.unit && !value_unit.unit.metric?
if value_unit.mass?
value_unit = value_unit.convert('g').auto_unit
elsif value_unit.volume?
value_unit = value_unit.convert('ml').auto_unit
end
end
value_unit
end
end
class StandardUnitConversion < Conversion
def convert(value_unit)
if value_unit.unit && value_unit.unit.metric?
if value_unit.mass?
value_unit = value_unit.convert('oz').auto_unit
elsif value_unit.volume?
value_unit = value_unit.convert('cup').auto_unit
end
end
value_unit
end
end
class VolumeUnitConversion < Conversion
def initialize(density_unit_value)
raise UnknownUnitError, "#{density_unit_value} is not a density" if !density_unit_value.density?
@density = density_unit_value
end
def convert(value_unit)
if value_unit.mass?
unit = value_unit.unit.metric? ? 'ml' : 'cup'
value_unit.convert(unit, @density).auto_unit
else
value_unit
end
end
end
class MassUnitConversion < Conversion
def initialize(density_unit_value)
raise UnknownUnitError, "#{density_unit_value} is not a density" if !density_unit_value.density?
@density = density_unit_value
end
def convert(value_unit)
if value_unit.volume?
unit = value_unit.unit.metric? ? 'g' : 'oz'
value_unit.convert(unit, @density).auto_unit
else
value_unit
end
end
end
end

View File

@ -4,6 +4,10 @@ module UnitConversion
def self.for(value_string, unit_string = nil, formatter = nil)
raise UnparseableUnitError, "value is empty" if value_string.blank?
if ValueUnit === value_string
return value_string
end
if String === value_string && unit_string.nil?
value_string, unit_string = parse_single_string(value_string)
end
@ -97,6 +101,24 @@ module UnitConversion
AutoUnitConversion.new.convert(self)
end
def to_metric
MetricUnitConversion.new.convert(self)
end
def to_standard
StandardUnitConversion.new.convert(self)
end
def to_mass(density)
parsed_density = ValueUnit.for(density)
MassUnitConversion.new(parsed_density).convert(self)
end
def to_volume(density)
parsed_density = ValueUnit.for(density)
VolumeUnitConversion.new(parsed_density).convert(self)
end
def density?
unit.density?
end

View File

@ -26,6 +26,16 @@ RSpec.describe UnitConversion::Conversion do
end
end
describe UnitConversion::MetricUnitConversion do
it 'converts standard units' do
expect(UnitConversion::MetricUnitConversion.new.convert(get_value_unit(1, 'cup')).unit.to_s).to eq 'milliliter'
expect(UnitConversion::MetricUnitConversion.new.convert(get_value_unit(1, 'cup')).pretty_value).to eq '236.588'
expect(UnitConversion::MetricUnitConversion.new.convert(get_value_unit(1, 'gallon')).unit.to_s).to eq 'liter'
expect(UnitConversion::MetricUnitConversion.new.convert(get_value_unit(1, 'gallon')).pretty_value).to eq '3.785'
end
end
describe UnitConversion::ConvertConversion do
it 'converts standard units' do
expect(UnitConversion::ConvertConversion.new(get_unit('tbsp')).convert(get_value_unit(1, 'cups')).raw_value).to eq 16