Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit b072e0050ab6a900814ad7e91d148f859cb61bfd 0 parents
@jamespjh jamespjh authored
Showing with 814 additions and 0 deletions.
  1. +4 −0 CHANGELOG
  2. +19 −0 COPYING
  3. +1 −0  README
  4. +31 −0 Rakefile
  5. +22 −0 amee-data-abstraction.gemspec
  6. +27 −0 examples/_calculator_form.erb
  7. +16 −0 examples/calculation_controller.rb
  8. +1 −0  init.rb
  9. +18 −0 lib/amee-data-abstraction.rb
  10. +67 −0 lib/amee-data-abstraction/calculation.rb
  11. +18 −0 lib/amee-data-abstraction/calculation_set.rb
  12. +24 −0 lib/amee-data-abstraction/drill.rb
  13. +46 −0 lib/amee-data-abstraction/input.rb
  14. +157 −0 lib/amee-data-abstraction/ongoing_calculation.rb
  15. +6 −0 lib/amee-data-abstraction/output.rb
  16. +6 −0 lib/amee-data-abstraction/profile.rb
  17. +48 −0 lib/amee-data-abstraction/prototype_calculation.rb
  18. +56 −0 lib/amee-data-abstraction/term.rb
  19. +10 −0 lib/amee-data-abstraction/version.rb
  20. +10 −0 lib/core-extensions/class.rb
  21. +8 −0 lib/core-extensions/ordered_hash.rb
  22. +12 −0 rails/init.rb
  23. +1 −0  spec/amee-data-abstraction/calculation_set_spec.rb
  24. +18 −0 spec/amee-data-abstraction/calculation_spec.rb
  25. +1 −0  spec/amee-data-abstraction/drill_spec.rb
  26. +77 −0 spec/amee-data-abstraction/ongoing_calculation_spec.rb
  27. +7 −0 spec/amee-data-abstraction/prototype_calculation_spec.rb
  28. +1 −0  spec/amee-data-abstraction/term_spec.rb
  29. +35 −0 spec/fixtures/electricity.rb
  30. +21 −0 spec/fixtures/electricity_and_transport.rb
  31. +26 −0 spec/fixtures/transport.rb
  32. +2 −0  spec/spec.opts
  33. +18 −0 spec/spec_helper.rb
4 CHANGELOG
@@ -0,0 +1,4 @@
+= Changelog
+
+== 0.1.0
+Abstracted from DA prototype, with Calculation torn apart into three classes.
19 COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2011 AMEE UK Ltd (help@amee.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
1  README
@@ -0,0 +1 @@
+== TBD
31 Rakefile
@@ -0,0 +1,31 @@
+require 'rake'
+require 'spec'
+require 'spec/rake/spectask'
+require 'rake/rdoctask'
+require 'rubygems/specification'
+require 'rake/gempackagetask'
+
+task :default => [:spec]
+
+Spec::Rake::SpecTask.new do |t|
+ t.spec_opts = ['--options', "spec/spec.opts"]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+ t.rcov = true
+ t.rcov_opts = ['--exclude', 'spec,/usr,/Library']
+end
+
+Rake::RDocTask.new { |rdoc|
+ rdoc.rdoc_dir = 'doc'
+ rdoc.title = "AMEE-Data-Abstraction - RDoc documentation"
+ rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.rdoc_files.include('README', 'COPYING')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+}
+
+# Gem build task - load gemspec from file
+gemspec = File.read('amee-data-abstraction.gemspec')
+spec = eval("#{gemspec}")
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+end
22 amee-data-abstraction.gemspec
@@ -0,0 +1,22 @@
+require './lib/amee-data-abstraction/version.rb'
+require 'rake'
+
+Gem::Specification.new do |s|
+ s.name = "amee"
+ s.version = AMEE::DataAbstraction::VERSION::STRING
+ s.date = "2010-11-08"
+ s.summary = "Calculation and form building tool hiding details of AMEE API"
+ s.email = "help@amee.com"
+ s.homepage = "http://github.com/AMEE/data-abstraction"
+ s.has_rdoc = true
+ s.authors = ["James Smith"]
+ s.files = ["README", "COPYING", "CHANGELOG"]
+ s.files += FileList.new('lib/**/*.rb')
+ s.files += ['init.rb', 'rails/init.rb']
+ s.files += [] #bin/executable
+ s.files += FileList.new('examples/**/*.rb')
+ s.files += ['init.rb', 'rails/init.rb']
+ s.executables = []
+ s.add_dependency("amee", ">= 2.6.0", "< 3.0")
+ s.add_dependency("amee-internal", ">= 2.6.0", "< 3.0")
+end
27 examples/_calculator_form.erb
@@ -0,0 +1,27 @@
+<% form_id = "drill-form-#{rand(1e8)}" %>
+<% form_tag({:action=>nil},{:id=>form_id}) do%>
+ <%= hidden_field_tag 'form_id', form_id %>
+ <table>
+ <%@calculation.drills.each_value do |input|%>
+ <tr>
+ <td><%=label :entry,input.label,input.name%></td>
+ <td>
+ <%= select_tag "entry[#{input.label}]",
+ options_for_select(input.options_for_select,input.set? ? input.value : nil),:disabled=>input.disabled?%>
+ </td>
+ </tr>
+ <%end%>
+ <%@calculation.profiles.each_value do |input|%>
+ <tr><td><%=label :entry,input.label,input.name%></td><td><%= text_field :entry, input.label, "size" => 20, :value => input.value_if_given %></td></tr>
+ <%end%>
+ <%@calculation.chosen_outputs.each_value do |result|%>
+ <tr><td><%=label :entry,result.label,result.name%></td><td><%= result.value_if_given %></td></tr>
+ <%end%>
+ </table>
+<%end%>
+<%= observe_form form_id, :url => {:action => 'result'}%>
+<% javascript_tag do %>
+ $('#<%=form_id%>').submit(function() {
+ return false;
+ });
+<%end%>
16 examples/calculation_controller.rb
@@ -0,0 +1,16 @@
+class CalculationController < ApplicationController
+ def index
+ @calculations=Calculations.calculations.values
+ end
+
+ def enter
+ @calculation=Calculations[params[:calculation]]
+ end
+
+ def result
+ @calculation=Calculations[params[:calculation]].clone
+ @calculation.choose!(params['entry'])
+ @calculation.calculate!
+ end
+
+end
1  init.rb
@@ -0,0 +1 @@
+require File.dirname(__FILE__) + "/rails/init"
18 lib/amee-data-abstraction.rb
@@ -0,0 +1,18 @@
+require 'amee'
+require 'amee-internal'
+
+require File.dirname(__FILE__) + '/core-extensions/class'
+require File.dirname(__FILE__) + '/core-extensions/ordered_hash'
+require File.dirname(__FILE__) + '/amee-data-abstraction/calculation'
+require File.dirname(__FILE__) + '/amee-data-abstraction/ongoing_calculation'
+require File.dirname(__FILE__) + '/amee-data-abstraction/prototype_calculation'
+require File.dirname(__FILE__) + '/amee-data-abstraction/calculation_set'
+require File.dirname(__FILE__) + '/amee-data-abstraction/term'
+require File.dirname(__FILE__) + '/amee-data-abstraction/input'
+require File.dirname(__FILE__) + '/amee-data-abstraction/drill'
+require File.dirname(__FILE__) + '/amee-data-abstraction/profile'
+require File.dirname(__FILE__) + '/amee-data-abstraction/output'
+
+module AMEE::DataAbstraction
+ mattr_accessor :connection
+end
67 lib/amee-data-abstraction/calculation.rb
@@ -0,0 +1,67 @@
+module AMEE
+ module DataAbstraction
+ class Calculation
+
+ public
+
+ attr_property :label,:name,:path
+
+ def [](sym)
+ @terms[sym.to_sym]
+ end
+
+ def inputs
+ terms AMEE::DataAbstraction::Input
+ end
+
+
+ def outputs
+ terms AMEE::DataAbstraction::Output
+ end
+
+ def inspect
+ "#{label} : [#{terms.values.map{|x| x.inspect}.join(',')}]"
+ end
+
+ def initialize_copy(source)
+ super
+ @terms=ActiveSupport::OrderedHash.new
+ source.terms.each do |k,v|
+ @terms[k]=v.clone
+ @terms[k].parent=self
+ end
+ end
+
+ def terms(klass=nil)
+ return @terms unless klass
+ ActiveSupport::OrderedHash[@terms.stable_select{|k,v| v.is_a? klass}]
+ end
+
+ protected
+
+ def initialize
+ @terms=ActiveSupport::OrderedHash.new
+ end
+
+ private
+
+ def by_path(path)
+ @terms.values.detect { |v| v.path==path }
+ end
+
+ def drill_by_path(path)
+ drills.values.detect { |v| v.path==path }
+ end
+
+ def profiles
+ terms AMEE::DataAbstraction::Profile
+ end
+
+ def drills
+ terms AMEE::DataAbstraction::Drill
+ end
+
+
+ end
+ end
+end
18 lib/amee-data-abstraction/calculation_set.rb
@@ -0,0 +1,18 @@
+module AMEE
+ module DataAbstraction
+ class CalculationSet
+ def initialize(options={},&block)
+ @calculations={}
+ instance_eval(&block) if block
+ end
+ attr_accessor :calculations
+ def [](sym)
+ @calculations[sym.to_sym]
+ end
+ def calculation(options={},&block)
+ new_content=PrototypeCalculation.new(options,&block)
+ @calculations[new_content.label]=new_content
+ end
+ end
+ end
+end
24 lib/amee-data-abstraction/drill.rb
@@ -0,0 +1,24 @@
+module AMEE
+ module DataAbstraction
+ class Drill < Input
+ public
+
+ def choices
+ c=calculation_with_only_earlier.send(:amee_drill).choices
+ c.length==1 ? [value] : c #Intention is to get autodrilled, drill will result in a UID
+ end
+
+ def valid_choice?
+ (choices.include? value) && (choices.length > 1)
+ end
+
+ def options_for_select
+ [nil]+choices
+ end
+
+ private
+
+ end
+ end
+end
+
46 lib/amee-data-abstraction/input.rb
@@ -0,0 +1,46 @@
+module AMEE
+ module DataAbstraction
+ class Input < Term
+ def choices
+ raise NotImplementedError
+ end
+
+ def options_for_select
+ raise NotImplementedError
+ end
+
+
+ #DSL-----
+ def fixed val
+ value val
+ @fixed=true
+ end
+ #------
+
+ def fixed?
+ @fixed
+ end
+
+ def disabled?
+ fixed? || (!set? && !next?)
+ end
+
+ def next?
+ label==unset_siblings.values.first.label
+ end
+
+ protected
+
+ def valid_choice?
+ raise NotImplementedError
+ end
+
+ def calculation_with_only_earlier
+ res=parent.clone
+ res.retreat!(self.label)
+ return res
+ end
+
+ end
+ end
+end
157 lib/amee-data-abstraction/ongoing_calculation.rb
@@ -0,0 +1,157 @@
+module AMEE
+ module DataAbstraction
+ class OngoingCalculation < Calculation
+
+ public
+
+
+
+ def unset_inputs
+ unset_terms AMEE::DataAbstraction::Input
+ end
+
+ def chosen_inputs
+ chosen_terms AMEE::DataAbstraction::Input
+ end
+
+ def unset_outputs
+ unset_terms AMEE::DataAbstraction::Output
+ end
+
+ def chosen_outputs
+ chosen_terms AMEE::DataAbstraction::Output
+ end
+
+ def choose!(choice)
+
+ choice.each do |k,v|
+ self[k].value v unless v.blank?
+ end
+
+ drills.each_value do |d|
+ d.value nil unless d.valid_choice?
+ end
+
+ autodrill!
+ end
+
+ def retreat!(label)
+ found=false
+ terms.each_value do |x|
+ found||=(x.label==label)
+ next unless found
+ x.value nil
+ end
+ end
+
+ def calculate!(profile=nil)
+ return unless satisfied?
+ profile ||= AMEE::Profile::ProfileList.new(connection).first
+ profile ||= AMEE::Profile::Profile.create(connection)
+ location = AMEE::Profile::Item.create(profile_category(profile),amee_drill.data_item_uid,
+ profile_options.merge(:get_item=>false,:name=>UUIDTools::UUID.timestamp_create))
+ item=AMEE::Profile::Item.get(connection, location, get_options)
+ # Extract default result
+ unset_outputs.values.each do |output|
+ res=nil
+ if output.path==:default
+ res= item.amounts.find{|x| x[:default] == true}
+ else
+ res= item.amounts.find{|x| x[:type] == output.path}
+ end
+ output.value res[:value] if res
+ end
+ return self
+ ensure
+ # Tidy up
+ if location
+ AMEE::Profile::Item.delete(connection,location)
+ end
+ end
+
+ def satisfied?
+ unset_drills.values.empty? && unset_profiles.values.empty?
+ end
+
+ # Friend constructor for PrototypeCalculation ONLY
+ def initialize
+ super
+ end
+
+ private
+
+ def chosen_terms(klass=nil)
+ ActiveSupport::OrderedHash[terms(klass).stable_select{|k,v|!v.value.nil?}]
+ end
+
+ def unset_terms(klass=nil)
+ ActiveSupport::OrderedHash[terms(klass).stable_select{|k,v|v.value.nil?}]
+ end
+
+
+ def unset_profiles
+ unset_terms AMEE::DataAbstraction::Profile
+ end
+
+ def unset_drills
+ unset_terms AMEE::DataAbstraction::Drill
+ end
+
+ def chosen_profiles
+ chosen_terms AMEE::DataAbstraction::Profile
+ end
+
+ def chosen_drills
+ chosen_terms AMEE::DataAbstraction::Drill
+ end
+
+
+ def drill_options
+ chosen_drills.values.map{|x| "#{CGI.escape(x.path)}=#{CGI.escape(x.value)}"}.join("&")
+ end
+ def profile_options
+ result={}
+ chosen_profiles.values.each do |piv|
+ result[piv.path]=piv.value
+ end
+ return result
+ end
+ def get_options
+ # Specify unit options here based on the contents
+ #getopts={}
+ #getopts[:returnUnit] = params[:unit] if params[:unit]
+ #getopts[:returnPerUnit] = params[:perUnit] if params[:perUnit]
+ return {}
+ end
+ def amee_drill
+ AMEE::Data::DrillDown.get(connection,"/data#{path}/drill?#{drill_options}")
+ end
+ def profile_category(profile)
+ AMEE::Profile::Category.get(connection, "/profiles/#{profile.uid}#{path}")
+ end
+
+ def connection
+ AMEE::DataAbstraction.connection
+ end
+
+ def autodrill!
+ #Sometimes when a bunch of drills are specified,
+ #this is enough to specify values for some more of them
+ # list drills given in params, merged with values autopicked by amee driller
+ picks=amee_drill.selections
+ picks.each do |path,value|
+ drill_by_path(path).value value
+ end
+ end
+
+ def next_drill
+ unset_drills.values.first
+ end
+
+ def future_drills
+ unset_drills.values[1..-1] || []
+ end
+
+ end
+ end
+end
6 lib/amee-data-abstraction/output.rb
@@ -0,0 +1,6 @@
+module AMEE
+ module DataAbstraction
+ class Output < Term
+ end
+ end
+end
6 lib/amee-data-abstraction/profile.rb
@@ -0,0 +1,6 @@
+module AMEE
+ module DataAbstraction
+ class Profile < Input
+ end
+ end
+end
48 lib/amee-data-abstraction/prototype_calculation.rb
@@ -0,0 +1,48 @@
+module AMEE
+ module DataAbstraction
+ class PrototypeCalculation < Calculation
+
+ public
+
+ def initialize(options={},&block)
+ super()
+ instance_eval(&block) if block
+ end
+
+ #DSL-----------------
+
+ def profile(options={},&block)
+ construct(Profile,options,&block)
+ end
+ def drill(options={},&block)
+ construct(Drill,options,&block)
+ end
+ def output(options={},&block)
+ construct(Output,options,&block)
+ end
+
+ #--------------------
+
+ def begin_calculation
+ result=OngoingCalculation.new
+ terms.each do |k,v|
+ result.terms[k]=v.clone
+ result.terms[k].parent=result
+ end
+ result.path path
+ result.name name
+ result.label label
+ result
+ end
+
+ private
+
+
+ def construct(klass,options={},&block)
+ new_content=klass.new(options.merge(:parent=>self),&block)
+ @terms[new_content.label]=new_content
+ end
+
+ end
+ end
+end
56 lib/amee-data-abstraction/term.rb
@@ -0,0 +1,56 @@
+module AMEE
+ module DataAbstraction
+ class Term
+
+ public
+
+ #DSL----
+
+ attr_property :label,:name,:path,:value,:type,:validation,:unit,:other_acceptable_units,:default
+
+
+ #-------
+
+ attr_accessor :parent
+
+ def initialize(options={},&block)
+ @parent=options[:parent]
+ @value=nil
+ instance_eval(&block) if block
+ end
+
+ def set?
+ !value.nil?
+ end
+
+ def value_if_given
+ set? ? value : nil
+ end
+
+ def inspect
+ "[#{self.class} #{label} : #{value}]"
+ end
+
+ private
+
+ def siblings
+ parent.terms_class(self.class)
+ end
+ def chosen_siblings
+ parent.chosen_terms_class(self.class)
+ end
+ def unset_siblings
+ parent.unset_terms_class(self.class)
+ end
+ def earlier_siblings
+ parent.earlier_terms_class(self.class)
+ end
+
+ def unset_others
+ ActiveSupport::OrderedHash[parent.unset_terms_class(self.class).reject{|k,v|
+ k==label
+ }]
+ end
+ end
+ end
+end
10 lib/amee-data-abstraction/version.rb
@@ -0,0 +1,10 @@
+module AMEE
+ module DataAbstraction
+ module VERSION #:nodoc:
+ MAJOR = 0
+ MINOR = 1
+ TINY = 0
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+ end
+end
10 lib/core-extensions/class.rb
@@ -0,0 +1,10 @@
+class Class
+ def attr_property(*accessors)
+ accessors.each do |m|
+ define_method(m) do |*val|
+ instance_variable_set("@#{m}",val.first) unless val.empty? #Array Hack to avoid warning
+ instance_variable_get("@#{m}")
+ end
+ end
+ end
+end
8 lib/core-extensions/ordered_hash.rb
@@ -0,0 +1,8 @@
+module ActiveSupport
+ class OrderedHash
+ def stable_select(&block)
+ #Annoyingly, default ordered hash select is not stable
+ self.map{|k,v| block.call(k,v) ? [k,v] : nil}.compact
+ end
+ end
+end
12 rails/init.rb
@@ -0,0 +1,12 @@
+require 'amee'
+require 'amee/rails'
+
+# Load config/amee.yml
+amee_config = "#{RAILS_ROOT}/config/amee.yml"
+if File.exist?(amee_config)
+ # Load config
+ $AMEE_CONFIG = YAML.load_file(amee_config)[RAILS_ENV]
+end
+
+# Add AMEE extensions into ActiveRecord::Base
+ActiveRecord::Base.class_eval { include AMEE::Rails } if Object.const_defined?("ActiveRecord")
1  spec/amee-data-abstraction/calculation_set_spec.rb
@@ -0,0 +1 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
18 spec/amee-data-abstraction/calculation_spec.rb
@@ -0,0 +1,18 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
+describe AMEE::DataAbstraction::Calculation do
+
+ it 'can create an instance' do
+ Transport.should be_a AMEE::DataAbstraction::Calculation
+ end
+ it 'should have ordered terms, with labels' do
+ Transport.terms.values.map(&:label).should eql [:fuel,:size,:distance,:co2]
+ end
+ it 'should have amee paths for the terms' do
+ Transport.terms.values.map(&:path).should eql ['fuel','size','distance',:default]
+ end
+ it 'should have human names for the terms' do
+ Transport.terms.values.map(&:name).
+ should eql ['Fuel Type','Vehicle Size','Distance Driven','Carbon Dioxide']
+ end
+end
+
1  spec/amee-data-abstraction/drill_spec.rb
@@ -0,0 +1 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
77 spec/amee-data-abstraction/ongoing_calculation_spec.rb
@@ -0,0 +1,77 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
+describe AMEE::DataAbstraction::Calculation do
+ before :all do
+ @c=Electricity
+ @t=Transport
+ end
+ it 'can have values chosen' do
+ flexmock(AMEE::Data::DrillDown).
+ should_receive(:get).
+ with(AMEE::DataAbstraction.connection,
+ '/data/business/energy/electricity/grid/drill?').
+ and_return(flexmock(:choices=>[],:selections=>{'country'=>'Argentina'}))
+ @c.inputs.values.map(&:label).should eql [:country,:energy_used]
+ @c.inputs[:energy_used].path.should eql 'energyPerTime'
+ @c.inputs[:energy_used].value.should eql nil
+
+ @c[:energy_used].value.should eql nil
+ d=@c.begin_calculation
+
+ d.choose!(:energy_used=>5)
+ d.chosen_inputs.values.map(&:value).should eql ['Argentina',5]
+ d.unset_inputs.values.should be_empty
+ d.inputs[:energy_used].path.should eql 'energyPerTime'
+ d.inputs[:energy_used].value.should eql 5
+
+ # Original should be unaffected by the choosing - clone generates a deep copy instance
+ @c.inputs[:energy_used].path.should eql 'energyPerTime'
+ @c.inputs[:energy_used].value.should eql nil
+ end
+ it 'knows when it is satisfied' do
+ flexmock(AMEE::Data::DrillDown).
+ should_receive(:get).
+ with(AMEE::DataAbstraction.connection,
+ '/data/business/energy/electricity/grid/drill?').
+ and_return(flexmock(:choices=>[],:selections=>{'country'=>'Argentina'}))
+ d=@c.begin_calculation
+ d.satisfied?.should be_false
+ d.choose!(:energy_used=>5)
+ d.satisfied?.should be_true
+ end
+ it 'knows when its drills are satisfied' do
+ flexmock(AMEE::Data::DrillDown).
+ should_receive(:get).
+ with(AMEE::DataAbstraction.connection,
+ '/data/transport/car/generic/drill?').
+ and_return(flexmock(:choices=>['diesel','petrol'],:selections=>{}))
+ flexmock(AMEE::Data::DrillDown).
+ should_receive(:get).
+ with(AMEE::DataAbstraction.connection,
+ '/data/transport/car/generic/drill?fuel=diesel').
+ and_return(flexmock(:choices=>['large','small'],:selections=>{'fuel'=>'diesel'}))
+ flexmock(AMEE::Data::DrillDown).
+ should_receive(:get).
+ with(AMEE::DataAbstraction.connection,
+ '/data/transport/car/generic/drill?fuel=diesel&size=large').
+ and_return(flexmock(:choices=>[],:selections=>{'fuel'=>'diesel','size'=>'large'}))
+ @t.terms.values.map(&:label).should eql [:fuel,:size,:distance,:co2]
+ t=@t.begin_calculation
+ t.terms.values.map(&:label).should eql [:fuel,:size,:distance,:co2]
+ t.satisfied?.should be_false
+ t.choose!('fuel'=>'diesel')
+ t.chosen_inputs.values.map(&:label).should eql [:fuel]
+ t.unset_inputs.values.map(&:label).should eql [:size,:distance]
+ t.satisfied?.should be_false
+ t2=@t.begin_calculation
+ t2.choose!('fuel'=>'diesel','size'=>'large')
+ t2.chosen_inputs.values.map(&:label).should eql [:fuel,:size]
+ t2.unset_inputs.values.map(&:label).should eql [:distance]
+ t2.satisfied?.should be_false
+ t3=@t.begin_calculation
+ t3.choose!('fuel'=>'diesel','size'=>'large','distance'=>5)
+ t3.chosen_inputs.values.map(&:label).should eql [:fuel,:size,:distance]
+ t3.unset_inputs.values.map(&:label).should eql []
+ t3.satisfied?.should be_true
+ end
+end
+
7 spec/amee-data-abstraction/prototype_calculation_spec.rb
@@ -0,0 +1,7 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
+describe AMEE::DataAbstraction::Calculation do
+ it 'can create an instance' do
+ Transport.should be_a AMEE::DataAbstraction::PrototypeCalculation
+ end
+end
+
1  spec/amee-data-abstraction/term_spec.rb
@@ -0,0 +1 @@
+require File.dirname(File.dirname(__FILE__)) + '/spec_helper.rb'
35 spec/fixtures/electricity.rb
@@ -0,0 +1,35 @@
+Electricity=AMEE::DataAbstraction::PrototypeCalculation.new { # The application has support for an electricity calculation. :electricity is the internal label used to refer to it
+ label :electricity
+ name "Electricity Consumption"
+ path '/business/energy/electricity/grid'
+
+ drill {
+ value 'argentina' #Not to be unset, value pre-given
+ label :country #Name will default to label.humanize if not given
+ path 'country' #Some of the fields on the form are drill-downs, but the application doesn't need to display these differently
+ #type :autocompleting_text_box #default for a drill with entries is probably a dropdown
+ }
+
+ profile {
+ label :energy_used
+ # Symbol provided here is used in generating html ids for elements etc
+ path 'energyPerTime' #The amee profile item value corresponding to the field
+ name "Energy Used" #The display name used on the form
+ unit "kWh" #Default unit choice
+ type :text_box #Probably not needed, as likely to be the default for profile item value unsets
+ validation :float #Probably not needed, as default can be deduced from PIV TYPE in API. Here as illustrative of potential override Can be a symbol for standard validation or regexp
+ other_acceptable_units :any #A dropdown should appear allowing choice of energy unit - without this line only kWh allowed
+ }
+
+ # Alternatively, the drill might be fixed
+ #permanent :country {
+ # drill_path 'country'
+ # value 'Argentina'
+
+ output { #A marv output value
+ label :co2
+ path :default #It's not a marv, use the default output
+ name "Carbon Dioxide"
+ }
+}
+
21 spec/fixtures/electricity_and_transport.rb
@@ -0,0 +1,21 @@
+ElectricityAndTransport=AMEE::DataAbstraction::CalculationSet.new {
+ calculation{
+ name 'electricity'
+ label :electricity
+ path '/business/energy/electricity/grid'
+ profile {
+ label :usage
+ name 'Electricity Used'
+ path 'energyPerTime'
+ }
+ drill {
+ label :country
+ path 'country'
+ value 'Argentina'
+ }
+ output {
+ label :co2
+ path :default
+ }
+ }
+}
26 spec/fixtures/transport.rb
@@ -0,0 +1,26 @@
+Transport=AMEE::DataAbstraction::PrototypeCalculation.new{
+ name 'transport'
+ label :transport
+ path '/transport/car/generic'
+
+ drill {
+ path 'fuel'
+ label :fuel
+ name 'Fuel Type'
+ }
+ drill {
+ path 'size'
+ label :size
+ name 'Vehicle Size'
+ }
+ profile {
+ path 'distance'
+ label :distance
+ name 'Distance Driven'
+ }
+ output {
+ label :co2
+ path :default
+ name 'Carbon Dioxide'
+ }
+}
2  spec/spec.opts
@@ -0,0 +1,2 @@
+--colour
+--format RspecSpinner::Bar
18 spec/spec_helper.rb
@@ -0,0 +1,18 @@
+require 'rubygems'
+require 'spec'
+require 'rspec_spinner'
+require 'flexmock'
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+require 'amee'
+require 'amee-internal'
+require 'amee-data-abstraction'
+
+Spec::Runner.configure do |config|
+ config.mock_with :flexmock
+end
+
+AMEE::DataAbstraction.connection=FlexMock.new('connection') #Global connection mock, shouldn't receive anything, as we mock the individual amee-ruby calls in the tests
+
+Dir.glob(File.dirname(__FILE__) + '/fixtures/*') do |filename|
+ require filename
+end
Please sign in to comment.
Something went wrong with that request. Please try again.