Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pastorius committed Oct 13, 2011
0 parents commit 784de95
Show file tree
Hide file tree
Showing 18 changed files with 217 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .autotest
@@ -0,0 +1,9 @@
require 'autotest/restart'

Autotest.add_hook :initialize do |at|
at.testlib = ".minitest.rb"
end

Autotest.add_hook :all_good do |at|
system "rake rcov_info"
end if ENV['RCOV']
2 changes: 2 additions & 0 deletions .minitest.rb
@@ -0,0 +1,2 @@
# gem "minitest"
require "minitest/autorun"
1 change: 1 addition & 0 deletions .rvmrc
@@ -0,0 +1 @@
rvm use 1.9.2@prixfixe
12 changes: 12 additions & 0 deletions doc/notes.txt
@@ -0,0 +1,12 @@
Static pricing models
--------
list price (price/unit)
product feature/customer segment - dependent (feature A enabled?)
volume dependent (list price, but tiered)

Dynamic pricing
------
negotiated
yield management (depends on inventory and/or time of purchase)
real-time (based on supply and demand)
auction (competitive bidding)
8 changes: 8 additions & 0 deletions lib/prixfixe.rb
@@ -0,0 +1,8 @@
module Prixfixe
require 'prixfixe/static_model'
require 'prixfixe/list_price'
require 'prixfixe/volume_price'
require 'prixfixe/conditional_price'
require 'prixfixe/minimum_price'
require 'prixfixe/unit_price'
end
12 changes: 12 additions & 0 deletions lib/prixfixe/conditional_price.rb
@@ -0,0 +1,12 @@
module Prixfixe
class ConditionalPrice < StaticModel
def initialize(proc, model)
@proc = proc
@model = model
end

def calculate(items)
@model.calculate(items.select {|item| @proc.call(item)})
end
end
end
15 changes: 15 additions & 0 deletions lib/prixfixe/list_price.rb
@@ -0,0 +1,15 @@
module Prixfixe
class ListPrice < StaticModel
def initialize(unit_price)
@unit_price = unit_price
end

def calculate(items)
if items.kind_of?(Enumerable)
items.size * @unit_price
else
items * @unit_price
end
end
end
end
13 changes: 13 additions & 0 deletions lib/prixfixe/minimum_price.rb
@@ -0,0 +1,13 @@
module Prixfixe
class MinimumPrice < StaticModel
def initialize(min, model)
@min = min
@model = model
end

def calculate(items)
calculated = @model.calculate(items)
calculated < @min ? @min : calculated
end
end
end
5 changes: 5 additions & 0 deletions lib/prixfixe/static_model.rb
@@ -0,0 +1,5 @@
module Prixfixe
class StaticModel
def calculate(items) 0; end
end
end
13 changes: 13 additions & 0 deletions lib/prixfixe/unit_price.rb
@@ -0,0 +1,13 @@
module Prixfixe
class UnitPrice < StaticModel
def initialize(attr, model)
@attr = attr
@model = model
end

def calculate(items)
total = items.inject(0) {|sum, item| sum + item.send(@attr.to_sym)}
@model.calculate(total)
end
end
end
30 changes: 30 additions & 0 deletions lib/prixfixe/volume_price.rb
@@ -0,0 +1,30 @@
module Prixfixe
class VolumePrice < StaticModel
def initialize(base_model)
@tiers = {0 => base_model}
end

def calculate(items)
sorted_keys.inject(0) do |sum, k|
current_tier = @tiers[k]
current_items = items[k..last_index(k)]
sum + current_tier.calculate(current_items)
end
end

def add_tier(tier, model)
@tiers[tier] = model
self
end

private
def sorted_keys
@tiers.keys.sort {|x, y| x <=> y}
end

def last_index(key)
min = sorted_keys.select {|k| k > key}.min
min.nil? ? -1 : min - 1
end
end
end
17 changes: 17 additions & 0 deletions test/conditional_price_test.rb
@@ -0,0 +1,17 @@
require 'test_helper'

class ConditionalPriceTest < MiniTest::Unit::TestCase
def setup
@items = [
OpenStruct.new({:enabled? => true}),
OpenStruct.new({:enabled? => false}),
OpenStruct.new,
]
end

def test_calculate_with_attribute
proc = Proc.new {|item| item.enabled?}
model = ConditionalPrice.new(proc, ListPrice.new(25))
assert_equal 25, model.calculate(@items)
end
end
7 changes: 7 additions & 0 deletions test/list_price_test.rb
@@ -0,0 +1,7 @@
require 'test_helper'

class ListPriceTest < MiniTest::Unit::TestCase
def test_calculate
assert_equal 100, ListPrice.new(50).calculate([0,1])
end
end
22 changes: 22 additions & 0 deletions test/minimum_price_test.rb
@@ -0,0 +1,22 @@
require 'test_helper'

class MinimumPriceTest < MiniTest::Unit::TestCase
def setup
@items = (0..19).to_a
end

def test_calculate_with_exact_match
model = MinimumPrice.new(20, ListPrice.new(1))
assert_equal 20, model.calculate(@items)
end

def test_calculate_under_min
model = MinimumPrice.new(21, ListPrice.new(1))
assert_equal 21, model.calculate(@items)
end

def test_calculate_over_min
model = MinimumPrice.new(10, ListPrice.new(1))
assert_equal 20, model.calculate(@items)
end
end
7 changes: 7 additions & 0 deletions test/static_model_test.rb
@@ -0,0 +1,7 @@
require 'test_helper'

class StaticModelTest < MiniTest::Unit::TestCase
def test_calculate
assert_equal 0, StaticModel.new.calculate([0,1])
end
end
4 changes: 4 additions & 0 deletions test/test_helper.rb
@@ -0,0 +1,4 @@
require 'prixfixe'
require 'ostruct'

include Prixfixe
16 changes: 16 additions & 0 deletions test/unit_price_test.rb
@@ -0,0 +1,16 @@
require 'test_helper'

class UnitPriceTestTest < MiniTest::Unit::TestCase
def setup
@items = [
OpenStruct.new({:recording_length => 10}),
OpenStruct.new({:recording_length => 10}),
OpenStruct.new({:recording_length => 0}),
]
end

def test_calculate
model = UnitPrice.new(:recording_length, ListPrice.new(1))
assert_equal 20, model.calculate(@items)
end
end
24 changes: 24 additions & 0 deletions test/volume_price_test.rb
@@ -0,0 +1,24 @@
require 'test_helper'

class VolumePriceTest < MiniTest::Unit::TestCase
def setup
@items = (0..49).to_a
end

def test_calculate_one_tier
model = VolumePrice.new(ListPrice.new(2))
assert_equal 100, model.calculate(@items)
end

def test_calculate_two_tiers
model = VolumePrice.new(ListPrice.new(2)).add_tier(25, ListPrice.new(1))
assert_equal 75, model.calculate(@items)
end

def test_calculate_three_tiers
model = VolumePrice.new(ListPrice.new(2)).
add_tier(20, ListPrice.new(1)).
add_tier(40, ListPrice.new(0))
assert_equal 60, model.calculate(@items)
end
end

0 comments on commit 784de95

Please sign in to comment.