Skip to content

Instantly share code, notes, and snippets.

@kigster
Created September 22, 2015 21:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kigster/a643dba924596a9d3c9d to your computer and use it in GitHub Desktop.
Save kigster/a643dba924596a9d3c9d to your computer and use it in GitHub Desktop.
Compacted using some meta-programming to avoid repeated code
require 'rspec'
require 'ostruct'
require 'Money'
I18n.enforce_available_locales = false
class Order < OpenStruct
end
module Api
class OrderSummaryItem < ::Struct.new(:id, :display_name, :value_cents, :display_value)
end
class OrderSummaryService < ::Struct.new(:order)
class << self
def add item_type, lambda
define_method item_type do
display_name, value, value_format = lambda.call(self.order)
if display_name.nil?
nil
else
value, value_format = [value.cents, value.format] if value.respond_to?(:cents)
id = item_type.to_s.gsub(/_item/, '')
OrderSummaryItem.new(id, display_name, value, value_format)
end
end
@items ||= []
@items << item_type
end
end
def items
items_types.map{|i| self.send(i) }.compact
end
add :subtotal_item, -> (order) { ['Cost', order.sub_total] }
add :shipping_item, -> (order) { ['Shipping', [order.shipping.cents, order.shipping.cents == 0 ? 'Free' : order.shipping.format]] }
add :tax_item, -> (order) { ['Tax', order.tax] }
add :service_fee_item, -> (order) { [(order.service_fee.cents > 0 ? 'Processing Fee' : nil), order.service_fee] }
add :user_credit_item, -> (order) { [(order.user_credit_total.cents > 0 ? 'Wanelo Credit' : nil), Money.new(0, order.user_credit_total.currency) - order.user_credit_total] }
add :total_item, -> (order) { ['Total', order.total] }
private
def items_types
self.class.instance_variable_get(:@items)
end
end
end
RSpec.describe 'Api::OrderSummaryService' do
let(:order) { o = Order.new
o.subtotal = Money.new(1014)
o.tax = Money.new(247)
o.shipping = Money.new(0)
o.user_credit_total = Money.new(0)
o.service_fee = Money.new(20)
o }
let(:order_summary_service) { Api::OrderSummaryService.new(order) }
let(:tax_item) { Api::OrderSummaryItem.new('tax', 'Tax', order.tax.cents, order.tax.format) }
it "responds to class method :add" do
expect(Api::OrderSummaryService).to respond_to(:add)
end
it "should be able create an instance of the class" do
expect(order_summary_service.class).to be(Api::OrderSummaryService)
end
it "should have a #items method" do
expect(order_summary_service).to respond_to(:items)
end
it "#items_types to return items" do
expect(order_summary_service.send(:items_types)).to_not be_empty
expect(order_summary_service.send(:items_types)).to include(:tax_item)
expect(order_summary_service.send(:items_types)).to_not include(:some_other_item)
expect(order_summary_service.send(:items_types).size).to be(6)
end
it "#items to return actual OrderItems" do
expect(order_summary_service.items).to_not be_empty
expect(order_summary_service.items.first).to be_kind_of(Api::OrderSummaryItem)
expect(order_summary_service.items).to include(tax_item)
expect(order_summary_service.items.size).to be(5)
end
it "properly sets up properties of a tax item" do
tax_item = order_summary_service.items.find { |i| i.id.eql?('tax') }
expect(tax_item).to_not be_nil
expect(tax_item.id).to eql('tax')
expect(tax_item.display_name).to eql('Tax')
expect(tax_item.value_cents).to eql(247)
expect(tax_item.display_value).to eql("$2.47")
end
end
RSpec::Core::Runner.invoke
@kigster
Copy link
Author

kigster commented Sep 22, 2015

You can run this like this on command line from any directory where the file is dropped:

gem install money rspec --no-ri --no-rdoc
ruby order_summary_service.rb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment