cartman 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -27,14 +27,16 @@ Cartman has a few (read 3) configuration options you can set, most likely in an
27
27
  # config/initializers/cartman.rb
28
28
  Cartman.config do
29
29
  cart_expires_in 604800 # one week, in seconds. This is the default
30
- cost_field :cost # for cart totaling
30
+ unit_cost_field :unit_cost # for cart totaling
31
31
  quantity_field :quantity # for quantity totaling
32
32
  redis Redis.new # set the redis connection here
33
33
  end
34
34
  ```
35
35
 
36
36
  - The `cart_expires_in` setting will let you set how long a cart should live. If no items are added to the cart before the time expires, the cart will be cleared. If you want to disable cart expiration, set this to `-1`.
37
- - `cost_field` lets you tell Cartman where you're storing the "cost" of each item, so that when you call `cart.total` it knows which values to sum.
37
+ - `unit_cost_field` lets you tell Cartman where you're storing the unit_cost of each item, so that you can use the `cost` method on the item, and the `total` method on `Cart`.
38
+ - `quantity_field` lets you tell Cartman where you're storing the quantity of each item. The `Item#cost` method uses this along with the `unit_cost` field to determine the cost.
39
+ - `redis` lets you set the redis connection you want to use. Note that this is not redis connection options, this is an actual instance of `Redis`.
38
40
 
39
41
  ## Usage
40
42
 
@@ -42,7 +44,8 @@ To create a new shopping cart, just call `Cartman::Cart.new(user.id)`. The para
42
44
 
43
45
  The returned Items come back as `Cartman::Item` instances, which have a few special methods to be aware of:
44
46
 
45
- - `remove` - which will remove the item from the cart
47
+ - `cost` - which will return the `:unit_cost` multiplied by the `:quantity`.
48
+ - `destroy` - which will remove the item from the cart
46
49
  - `cart` - which will return the parent cart, think ActiveRecord association
47
50
  - `_id` - which will return the id of the item, if you need that for whatever reason
48
51
  - `_key` - which will return the redis key the data is stored in. Probably won't need that, but it's there.
@@ -51,17 +54,21 @@ The returned Items come back as `Cartman::Item` instances, which have a few spec
51
54
  The `Cart` object also has some handy methods that you should be aware of:
52
55
 
53
56
  - `add_item(data)` - which is the life blood of Cartman. This method takes a hash of data you would like to store with the item. Here's a few suggestions of keys you may want in your hash:
54
- - `:id` - to store the ID of the product you're adding
55
- - `:type` - to store the class of the product you're adding. Useful if you have multiple models that can go in the cart.
56
- - `:cost` - which if you use will let you use the `Cart#total` method without any extra configuration
57
- - `:quantity` - which if you use will let you use the `Cart#quantity` method without any extra configuration
58
- - `remove_item(item) - which, you guessed it, removes an item. This method takes an Item object, not a hash.
57
+ - `:id` - (*required*) to store the ID of the model you're adding
58
+ - `:type` - (*required*) to store the class of the model you're adding.
59
+ - `:unit_cost` - This field is required if you want to take advantage of the `Item#cost` method, and the `Cart#total` method.
60
+ - `:quantity` - which if you use will let you use the `Cart#quantity` and `Cart#total` methods without any extra configuration.
61
+ - `remove_item(item)` - which, you guessed it, removes an item. This method takes an Item object, not a hash.
59
62
  - `contains?(Product)` - This is a biggie. It will tell you if a certain item is in the cart. And the way it works is you pass it an object, like an instance of a Product model, and it will examine the class, and the id, and look to see if it's in the cart already. This method only works if the `:id` and `:type` keys are set in the item's data hash.
63
+ - `find(Product)` - This will return the `Item` object that represents the object passed in. It works like `contains?` and uses class, and id. It only works if the `:id` and `:type` keys are set in the item's data hash.
64
+ - `items` - this returns a magic array of all the items. I call it magic because you can call on it:
65
+ - `each_with_object` - which will act like a regular `each` call, but the block will yield the `Item` and the object it represents by using the `:type` and `:id` keys.
66
+ - `total` - will sum all of the `cost` return values of all of the items in the cart. For this to work, the `:unit_cost` and `:quantity` fields need to be set for all items.
60
67
  - `count` - which will give you the total number of items in the cart. Faster than `cart.items.size` because it doesn't load all of the item data from redis.
61
- - `quantity` - which will return the total quantity of all the items. The quantity field is set in the config block, by default it's :quantity
62
- - `ttl` - will tell you how many seconds until the cart expires. It will return -1 if the cart will never expire
63
- - `touch` - which will reset the ttl back to whatever expiration length is set in the config. Touch is automatically called after `add_item` and `remove_item`
64
- - `destroy!` - which will delete the cart, and all the line_items out of it
68
+ - `quantity` - which will return the total quantity of all the items. The quantity field is set in the config block, by default it's `:quantity`
69
+ - `ttl` - will tell you how many seconds until the cart expires. It will return -1 if the cart will never expire.
70
+ - `touch` - which will reset the ttl back to whatever expiration length is set in the config. Touch is automatically called after `add_item` and `remove_item`.
71
+ - `destroy!` - which will delete the cart, and all the line_items out of it.
65
72
  - `reassign(id)` - this method will reassign the cart's unique identifier. So to access this cart at a later time after reassigning, you would put `Cart.new(reassigned_id)`. This is useful for having a cart for an unsigned in user. You can use their session ID while they're unauthenticated, and then when they sign in, you can reassign the cart to the user's ID. NOTE: Reassigning will overwrite any cart in it's way.
66
73
 
67
74
  Lets walk through an example implementation with a Rails app that has a User model and a Product model.
data/lib/cartman.rb CHANGED
@@ -2,6 +2,7 @@ require "cartman/version"
2
2
  require "cartman/configuration"
3
3
  require "cartman/cart"
4
4
  require "cartman/item"
5
+ require "cartman/item_collection"
5
6
  require 'redis'
6
7
 
7
8
  module Cartman
data/lib/cartman/cart.rb CHANGED
@@ -8,11 +8,13 @@ module Cartman
8
8
  end
9
9
 
10
10
  def add_item(options)
11
+ raise "Must specify both :id and :type" unless options.has_key?(:id) && options.has_key?(:type)
11
12
  line_item_id = @@redis.incr CART_LINE_ITEM_ID_KEY
12
- @@redis.mapped_hmset("cartman:line_item:#{line_item_id}", options)
13
- @@redis.sadd key, line_item_id
14
- if options.has_key?(:id) && options.has_key?(:type)
13
+ @@redis.pipelined do
14
+ @@redis.mapped_hmset("cartman:line_item:#{line_item_id}", options)
15
+ @@redis.sadd key, line_item_id
15
16
  @@redis.sadd index_key, "#{options[:type]}:#{options[:id]}"
17
+ @@redis.set index_key_for(options), line_item_id
16
18
  end
17
19
  touch
18
20
  get_item(line_item_id)
@@ -21,23 +23,28 @@ module Cartman
21
23
  def remove_item(item)
22
24
  @@redis.del "cartman:line_item:#{item._id}"
23
25
  @@redis.srem key, item._id
24
- begin
25
- @@redis.srem index_key, "#{item.type}:#{item.id}"
26
- rescue KeyError
26
+ @@redis.srem index_key, "#{item.type}:#{item.id}"
27
+ @@redis.del index_key_for(item)
28
+ index_keys.each do |key|
29
+ @@redis.del key
27
30
  end
28
31
  touch
29
32
  end
30
33
 
31
34
  def items
32
- items = line_item_ids.collect { |item_id|
33
- get_item(item_id)
34
- }
35
+ ItemCollection.new(line_item_ids.collect{ |item_id| get_item(item_id)})
35
36
  end
36
37
 
37
38
  def contains?(object)
38
39
  @@redis.sismember index_key, "#{object.class}:#{object.id}"
39
40
  end
40
41
 
42
+ def find(object)
43
+ if contains?(object)
44
+ get_item(@@redis.get(index_key_for(object)).to_i)
45
+ end
46
+ end
47
+
41
48
  def count
42
49
  @@redis.scard key
43
50
  end
@@ -50,7 +57,7 @@ module Cartman
50
57
 
51
58
  def total
52
59
  items.collect { |item|
53
- (item.send(Cartman::Configuration.cost_field).to_f * 100).to_i
60
+ (item.cost * 100).to_i
54
61
  }.inject{|sum,cost| sum += cost} / 100.0
55
62
  end
56
63
 
@@ -62,6 +69,8 @@ module Cartman
62
69
  keys = line_item_keys
63
70
  keys << key
64
71
  keys << index_key
72
+ keys << index_keys
73
+ keys.flatten!
65
74
  @@redis.pipelined do
66
75
  keys.each do |key|
67
76
  @@redis.del key
@@ -72,7 +81,11 @@ module Cartman
72
81
  def touch
73
82
  keys_to_expire = line_item_keys
74
83
  keys_to_expire << key
75
- keys_to_expire << index_key
84
+ if @@redis.exists index_key
85
+ keys_to_expire << index_key
86
+ keys_to_expire << index_keys
87
+ keys_to_expire.flatten!
88
+ end
76
89
  @@redis.pipelined do
77
90
  keys_to_expire.each do |item|
78
91
  @@redis.expire item, Cartman::Configuration.cart_expires_in
@@ -82,10 +95,14 @@ module Cartman
82
95
 
83
96
  def reassign(new_id)
84
97
  if @@redis.exists key
98
+ new_index_keys = items.collect { |item|
99
+ index_key_for(item, new_id)
100
+ }
85
101
  @@redis.rename key, key(new_id)
86
- end
87
- if @@redis.exists index_key
88
102
  @@redis.rename index_key, index_key(new_id)
103
+ index_keys.zip(new_index_keys).each do |key, value|
104
+ @@redis.rename key, value
105
+ end
89
106
  end
90
107
  @uid = new_id
91
108
  end
@@ -100,6 +117,21 @@ module Cartman
100
117
  key(id) + ":index"
101
118
  end
102
119
 
120
+ def index_keys(id=@uid)
121
+ @@redis.keys "#{index_key(id)}:*"
122
+ end
123
+
124
+ def index_key_for(object, id=@uid)
125
+ case object
126
+ when Hash
127
+ index_key(id) + ":#{object[:type]}:#{object[:id]}"
128
+ when Item
129
+ index_key(id) + ":#{object.type}:#{object.id}"
130
+ else
131
+ index_key(id) + ":#{object.class}:#{object.id}"
132
+ end
133
+ end
134
+
103
135
  def line_item_ids
104
136
  @@redis.smembers key
105
137
  end
@@ -109,7 +141,7 @@ module Cartman
109
141
  end
110
142
 
111
143
  def get_item(id)
112
- Item.new(id, @uid, @@redis.hgetall("cartman:line_item:#{id}").inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo})
144
+ Item.new(id, @uid, @@redis.hgetall("cartman:line_item:#{id}").inject({}){|hash,(k,v)| hash[k.to_sym] = v; hash})
113
145
  end
114
146
  end
115
147
  end
@@ -4,7 +4,7 @@ module Cartman
4
4
  class Configuration
5
5
  @@configuration = {
6
6
  cart_expires_in: 604800, # one week
7
- cost_field: :cost, # for cart totaling
7
+ unit_cost_field: :unit_cost, # for cart totaling and costing
8
8
  quantity_field: :quantity, # for cart totaling
9
9
  redis: Redis.new, # Redis connection
10
10
  }
data/lib/cartman/item.rb CHANGED
@@ -10,14 +10,24 @@ module Cartman
10
10
  @id
11
11
  end
12
12
 
13
+ def cost
14
+ unit_cost = (@data.fetch(Cartman::Configuration.unit_cost_field).to_f * 100).to_i
15
+ quantity = @data.fetch(Cartman::Configuration.quantity_field).to_i
16
+ (unit_cost * quantity) / 100.0
17
+ end
18
+
13
19
  def cart
14
20
  @cart ||= Cart.new(@cart_id)
15
21
  end
16
22
 
17
- def remove
23
+ def destroy
18
24
  cart.remove_item(self)
19
25
  end
20
26
 
27
+ def ==(item)
28
+ @id == item._id
29
+ end
30
+
21
31
  def _key
22
32
  "cartman:line_item:#{@id}"
23
33
  end
@@ -0,0 +1,19 @@
1
+ require 'delegate'
2
+
3
+ module Cartman
4
+ class ItemCollection < DelegateClass(Array)
5
+ include Enumerable
6
+
7
+ def initialize(array)
8
+ @results = array
9
+ super(@results)
10
+ end
11
+
12
+ def each_with_object
13
+ @results.each do |result|
14
+ yield result, eval(result.type).send(:find, result.id)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Cartman
2
- VERSION = "0.4.0"
2
+ VERSION = "1.0.0"
3
3
  end
data/spec/cart_spec.rb CHANGED
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Cartman do
4
4
  describe Cartman::Cart do
5
+ let(:Bottle) { Struct.new(:id) }
5
6
  let(:cart) { Cartman::Cart.new(1) }
6
7
 
7
8
  before(:each) do
@@ -16,7 +17,7 @@ describe Cartman do
16
17
 
17
18
  describe "#add_item" do
18
19
  before(:each) do
19
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
20
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
20
21
  end
21
22
 
22
23
  it "creates a line item key" do
@@ -37,21 +38,21 @@ describe Cartman do
37
38
  Cartman.config.redis.sismember("cartman:cart:1:index", "Bottle:17").should be_true
38
39
  end
39
40
 
40
- it "should not add an index key if type and ID are not set" do
41
- cart.add_item(id: 18, name: "Cordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
42
- Cartman.config.redis.sismember("cartman:cart:1:index", "Bottle:18").should be_false
43
- Cartman.config.redis.scard("cartman:cart:1:index").should eq(1)
41
+ it "should squack if type and/or ID are not set" do
42
+ expect { cart.add_item(id: 18, name: "Cordeux", unit_cost: 92.12, quantity: 2) }.to raise_error("Must specify both :id and :type")
43
+ expect { cart.add_item(type: "Bottle", name: "Cordeux", unit_cost: 92.12, quantity: 2) }.to raise_error("Must specify both :id and :type")
44
+ expect { cart.add_item(name: "Cordeux", unit_cost: 92.12, quantity: 2) }.to raise_error("Must specify both :id and :type")
44
45
  end
45
46
 
46
47
  it "should return an Item" do
47
- item = cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
48
+ item = cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
48
49
  item.class.should eq(Cartman::Item)
49
50
  end
50
51
  end
51
52
 
52
53
  describe "#remove_item" do
53
54
  it "should remove the id from the set, and delete the line_item key" do
54
- item = cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
55
+ item = cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
55
56
  item_id = item._id
56
57
  cart.remove_item(item)
57
58
  Cartman.config.redis.sismember(cart.send(:key), item_id).should be_false
@@ -61,12 +62,13 @@ describe Cartman do
61
62
 
62
63
  describe "#items" do
63
64
  before(:each) do
64
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
65
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
65
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
66
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
66
67
  end
67
68
 
68
- it "should return an array of Items" do
69
- cart.items.first.class.should eq(Cartman::Item)
69
+ it "should return an ItemCollection of Items" do
70
+ cart.items.class.should be(Cartman::ItemCollection)
71
+ cart.items.first.class.should be(Cartman::Item)
70
72
  cart.items.first.id.should eq("17")
71
73
  cart.items.first.name.should eq("Bordeux")
72
74
  end
@@ -78,8 +80,8 @@ describe Cartman do
78
80
  end
79
81
 
80
82
  before(:each) do
81
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
82
- cart.add_item(id: 34, name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
83
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
84
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
83
85
  end
84
86
 
85
87
  it "should be able to tell you that an item in the cart is present" do
@@ -98,18 +100,36 @@ describe Cartman do
98
100
  end
99
101
  end
100
102
 
103
+ describe "#find(item)" do
104
+
105
+ before(:each) do
106
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
107
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
108
+ end
109
+
110
+ it "should take some object, and return the Item that corresponds to it" do
111
+ cart.find(Bottle.new(17)).quantity.should eq("2")
112
+ cart.find(Bottle.new(17)).name.should eq("Bordeux")
113
+ cart.find(Bottle.new(34)).name.should eq("Cabernet")
114
+ end
115
+
116
+ it "should return nil if the Item is not in the cart" do
117
+ cart.find(Bottle.new(23)).should be(nil)
118
+ end
119
+ end
120
+
101
121
  describe "#count" do
102
122
  it "should return the number of items in the cart" do
103
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
104
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
123
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
124
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
105
125
  cart.count.should eq(2)
106
126
  end
107
127
  end
108
128
 
109
129
  describe "#quantity" do
110
130
  it "should return the sum of the default quantity field" do
111
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
112
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
131
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
132
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
113
133
  cart.quantity.should eq(4)
114
134
  end
115
135
 
@@ -117,26 +137,32 @@ describe Cartman do
117
137
  Cartman.config do
118
138
  quantity_field :qty
119
139
  end
120
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, qty: 2)
121
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, qty: 2)
140
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, qty: 2)
141
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, qty: 2)
122
142
  cart.quantity.should eq(4)
143
+ Cartman.config do
144
+ quantity_field :quantity
145
+ end
123
146
  end
124
147
  end
125
148
 
126
149
  describe "#total" do
127
150
  it "should total the default costs field" do
128
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
129
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
151
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2)
152
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, quantity: 2)
130
153
  cart.total.should eq(368.48)
131
154
  end
132
155
 
133
156
  it "should total whatever cost field the user sets" do
134
157
  Cartman.config do
135
- cost_field :cost_in_cents
158
+ unit_cost_field :unit_cost_in_cents
136
159
  end
137
- cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
138
- cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
160
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost_in_cents: 9212, quantity: 2)
161
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost_in_cents: 9212, quantity: 2)
139
162
  cart.total.should eq(36848)
163
+ Cartman.config do
164
+ unit_cost_field :unit_cost
165
+ end
140
166
  end
141
167
  end
142
168
 
@@ -149,6 +175,7 @@ describe Cartman do
149
175
  Cartman.config.redis.exists("cartman:line_item:1").should be_false
150
176
  Cartman.config.redis.exists("cartman:line_item:2").should be_false
151
177
  Cartman.config.redis.exists("cartman:cart:1:index").should be_false
178
+ Cartman.config.redis.exists("cartman:cart:1:index:Bottle:17").should be_false
152
179
  end
153
180
  end
154
181
 
@@ -157,6 +184,8 @@ describe Cartman do
157
184
  cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
158
185
  cart.touch
159
186
  cart.ttl.should eq(Cartman.config.cart_expires_in)
187
+ Cartman.config.redis.ttl("cartman:cart:1:index").should eq(Cartman.config.cart_expires_in)
188
+ Cartman.config.redis.ttl("cartman:cart:1:index:Bottle:17").should eq(Cartman.config.cart_expires_in)
160
189
  end
161
190
  end
162
191
 
@@ -167,12 +196,14 @@ describe Cartman do
167
196
  end
168
197
 
169
198
  it "should rename the key, and index_key if it exists" do
170
- cart.add_item(id: 17, name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
199
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
171
200
  cart.reassign(2)
172
201
  Cartman.config.redis.exists("cartman:cart:1").should be_false
173
202
  Cartman.config.redis.exists("cartman:cart:1:index").should be_false
203
+ Cartman.config.redis.exists("cartman:cart:1:index:Bottle:17").should be_false
174
204
  Cartman.config.redis.exists("cartman:cart:2").should be_true
175
- Cartman.config.redis.exists("cartman:cart:2:index").should be_false
205
+ Cartman.config.redis.exists("cartman:cart:2:index").should be_true
206
+ Cartman.config.redis.exists("cartman:cart:2:index:Bottle:17").should be_true
176
207
  cart.send(:key)[-1].should eq("2")
177
208
  cart.add_item(id: 18, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
178
209
  cart.reassign(1)
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cartman do
4
+ describe Cartman::ItemCollection do
5
+ before(:all) do
6
+ end
7
+
8
+ before(:each) do
9
+ Cartman.config.redis.flushdb
10
+ Object.send(:remove_const, :Bottle) if defined?(Bottle)
11
+ Bottle = double
12
+ Bottle.stub(:find).and_return(bottle)
13
+ end
14
+
15
+ describe "#each_with_object" do
16
+ let(:bottle) { double("Bottle") }
17
+ it "should be magical" do
18
+ cart = Cartman::Cart.new(1)
19
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
20
+ expect { |b| cart.items.each_with_object(&b)}.to yield_successive_args([cart.items.first, bottle])
21
+ end
22
+ end
23
+ end
24
+ end
data/spec/item_spec.rb CHANGED
@@ -3,13 +3,13 @@ require 'spec_helper'
3
3
  describe Cartman do
4
4
  describe Cartman::Item do
5
5
  let(:cart) { Cartman::Cart.new(1) }
6
- let(:item) { cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2) }
6
+ let(:item) { cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, quantity: 2) }
7
7
 
8
8
  describe "data getters and setters" do
9
9
  it "should let me get data stored for the item" do
10
10
  item.id.should eq("17")
11
11
  item.type.should eq("Bottle")
12
- item.cost.should eq("184.24")
12
+ item.cost.should eq(184.24)
13
13
  end
14
14
 
15
15
  it "should let me modify data stored for the item" do
@@ -26,10 +26,18 @@ describe Cartman do
26
26
  end
27
27
  end
28
28
 
29
- describe "#remove" do
29
+ describe "#cost" do
30
+ it "should be equal to the unit_cost multiplied by the quantity" do
31
+ item.cost.should eq(184.24)
32
+ item.quantity = 3
33
+ item.cost.should eq(276.36)
34
+ end
35
+ end
36
+
37
+ describe "#destroy" do
30
38
  it "should remove the item from the cart" do
31
39
  item_id = item._id
32
- item.remove
40
+ item.destroy
33
41
  Cartman.config.redis.sismember(cart.send(:key), item_id).should be_false
34
42
  Cartman.config.redis.exists("cartman:line_item:#{item_id}").should be_false
35
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cartman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-24 00:00:00.000000000 Z
12
+ date: 2012-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -61,8 +61,10 @@ files:
61
61
  - lib/cartman/cart.rb
62
62
  - lib/cartman/configuration.rb
63
63
  - lib/cartman/item.rb
64
+ - lib/cartman/item_collection.rb
64
65
  - lib/cartman/version.rb
65
66
  - spec/cart_spec.rb
67
+ - spec/item_collection_spec.rb
66
68
  - spec/item_spec.rb
67
69
  - spec/spec_helper.rb
68
70
  homepage: http://github.com/willcosgrove/cartman
@@ -79,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
81
  version: '0'
80
82
  segments:
81
83
  - 0
82
- hash: 1475251034207197325
84
+ hash: -4477531500718157343
83
85
  required_rubygems_version: !ruby/object:Gem::Requirement
84
86
  none: false
85
87
  requirements:
@@ -88,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
90
  version: '0'
89
91
  segments:
90
92
  - 0
91
- hash: 1475251034207197325
93
+ hash: -4477531500718157343
92
94
  requirements: []
93
95
  rubyforge_project:
94
96
  rubygems_version: 1.8.23
@@ -97,5 +99,6 @@ specification_version: 3
97
99
  summary: Doing shopping carts like a boss since 2012
98
100
  test_files:
99
101
  - spec/cart_spec.rb
102
+ - spec/item_collection_spec.rb
100
103
  - spec/item_spec.rb
101
104
  - spec/spec_helper.rb