cartman 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -9
- data/lib/cartman.rb +4 -8
- data/lib/cartman/cart.rb +36 -31
- data/lib/cartman/configuration.rb +9 -25
- data/lib/cartman/item.rb +10 -4
- data/lib/cartman/version.rb +1 -1
- data/spec/cart_spec.rb +16 -13
- metadata +3 -8
data/README.md
CHANGED
@@ -25,18 +25,18 @@ Cartman has a few (read 3) configuration options you can set, most likely in an
|
|
25
25
|
|
26
26
|
```ruby
|
27
27
|
# config/initializers/cartman.rb
|
28
|
-
Cartman.config do
|
29
|
-
cart_expires_in 604800 # one week, in seconds. This is the default
|
30
|
-
unit_cost_field :unit_cost # for cart totaling
|
31
|
-
quantity_field :quantity # for quantity totaling
|
32
|
-
redis Redis.new # set the redis connection here
|
28
|
+
Cartman.config do |c|
|
29
|
+
c.cart_expires_in = 604800 # one week, in seconds. This is the default
|
30
|
+
c.unit_cost_field = :unit_cost # for cart totaling
|
31
|
+
c.quantity_field = :quantity # for quantity totaling
|
32
|
+
c.redis = Redis.new # set the redis connection here
|
33
33
|
end
|
34
34
|
```
|
35
35
|
|
36
|
-
- The `cart_expires_in
|
37
|
-
- `unit_cost_field
|
38
|
-
- `quantity_field
|
39
|
-
- `redis
|
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
|
+
- `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`.
|
40
40
|
|
41
41
|
## Usage
|
42
42
|
|
data/lib/cartman.rb
CHANGED
@@ -3,15 +3,11 @@ require "cartman/configuration"
|
|
3
3
|
require "cartman/cart"
|
4
4
|
require "cartman/item"
|
5
5
|
require "cartman/item_collection"
|
6
|
-
require 'redis'
|
7
6
|
|
8
7
|
module Cartman
|
9
|
-
|
10
|
-
|
11
|
-
if block_given?
|
12
|
-
|
13
|
-
else
|
14
|
-
@config ||= Configuration.new
|
15
|
-
end
|
8
|
+
def self.config
|
9
|
+
@config ||= Configuration.new
|
10
|
+
yield @config if block_given?
|
11
|
+
@config
|
16
12
|
end
|
17
13
|
end
|
data/lib/cartman/cart.rb
CHANGED
@@ -4,28 +4,27 @@ module Cartman
|
|
4
4
|
|
5
5
|
def initialize(uid)
|
6
6
|
@uid = uid
|
7
|
-
@@redis = Cartman::Configuration.redis
|
8
7
|
end
|
9
8
|
|
10
9
|
def add_item(options)
|
11
10
|
raise "Must specify both :id and :type" unless options.has_key?(:id) && options.has_key?(:type)
|
12
|
-
line_item_id =
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
line_item_id = redis.incr CART_LINE_ITEM_ID_KEY
|
12
|
+
redis.pipelined do
|
13
|
+
redis.mapped_hmset("cartman:line_item:#{line_item_id}", options)
|
14
|
+
redis.hincrby("cartman:line_item:#{line_item_id}", :_version, 1)
|
15
|
+
redis.sadd key, line_item_id
|
16
|
+
redis.sadd index_key, "#{options[:type]}:#{options[:id]}"
|
17
|
+
redis.set index_key_for(options), line_item_id
|
19
18
|
end
|
20
19
|
touch
|
21
20
|
get_item(line_item_id)
|
22
21
|
end
|
23
22
|
|
24
23
|
def remove_item(item)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
redis.del "cartman:line_item:#{item._id}"
|
25
|
+
redis.srem key, item._id
|
26
|
+
redis.srem index_key, "#{item.type}:#{item.id}"
|
27
|
+
redis.del index_key_for(item)
|
29
28
|
touch
|
30
29
|
end
|
31
30
|
|
@@ -34,22 +33,22 @@ module Cartman
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def contains?(object)
|
37
|
-
|
36
|
+
redis.sismember index_key, "#{object.class}:#{object.id}"
|
38
37
|
end
|
39
38
|
|
40
39
|
def find(object)
|
41
40
|
if contains?(object)
|
42
|
-
get_item(
|
41
|
+
get_item(redis.get(index_key_for(object)).to_i)
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
45
|
def count
|
47
|
-
|
46
|
+
redis.scard key
|
48
47
|
end
|
49
48
|
|
50
49
|
def quantity
|
51
50
|
line_item_keys.collect { |item_key|
|
52
|
-
|
51
|
+
redis.hget item_key, Cartman.config.quantity_field
|
53
52
|
}.inject(0){|sum,quantity| sum += quantity.to_i}
|
54
53
|
end
|
55
54
|
|
@@ -60,7 +59,7 @@ module Cartman
|
|
60
59
|
end
|
61
60
|
|
62
61
|
def ttl
|
63
|
-
|
62
|
+
redis.ttl key
|
64
63
|
end
|
65
64
|
|
66
65
|
def destroy!
|
@@ -69,9 +68,9 @@ module Cartman
|
|
69
68
|
keys << index_key
|
70
69
|
keys << index_keys
|
71
70
|
keys.flatten!
|
72
|
-
|
71
|
+
redis.pipelined do
|
73
72
|
keys.each do |key|
|
74
|
-
|
73
|
+
redis.del key
|
75
74
|
end
|
76
75
|
end
|
77
76
|
end
|
@@ -79,32 +78,32 @@ module Cartman
|
|
79
78
|
def touch
|
80
79
|
keys_to_expire = line_item_keys
|
81
80
|
keys_to_expire << key
|
82
|
-
if
|
81
|
+
if redis.exists index_key
|
83
82
|
keys_to_expire << index_key
|
84
83
|
keys_to_expire << index_keys
|
85
84
|
keys_to_expire.flatten!
|
86
85
|
end
|
87
|
-
|
86
|
+
redis.pipelined do
|
88
87
|
keys_to_expire.each do |item|
|
89
|
-
|
88
|
+
redis.expire item, Cartman.config.cart_expires_in
|
90
89
|
end
|
91
90
|
end
|
92
|
-
|
91
|
+
redis.hincrby self.class.versions_key, version_key, 1
|
93
92
|
end
|
94
93
|
|
95
94
|
def version
|
96
|
-
|
95
|
+
redis.hget(self.class.versions_key, version_key).to_i
|
97
96
|
end
|
98
97
|
|
99
98
|
def reassign(new_id)
|
100
|
-
if
|
99
|
+
if redis.exists key
|
101
100
|
new_index_keys = items.collect { |item|
|
102
101
|
index_key_for(item, new_id)
|
103
102
|
}
|
104
|
-
|
105
|
-
|
103
|
+
redis.rename key, key(new_id)
|
104
|
+
redis.rename index_key, index_key(new_id)
|
106
105
|
index_keys.zip(new_index_keys).each do |key, value|
|
107
|
-
|
106
|
+
redis.rename key, value
|
108
107
|
end
|
109
108
|
end
|
110
109
|
@uid = new_id
|
@@ -133,7 +132,7 @@ module Cartman
|
|
133
132
|
end
|
134
133
|
|
135
134
|
def index_keys(id=@uid)
|
136
|
-
|
135
|
+
redis.keys "#{index_key(id)}:*"
|
137
136
|
end
|
138
137
|
|
139
138
|
def index_key_for(object, id=@uid)
|
@@ -148,7 +147,7 @@ module Cartman
|
|
148
147
|
end
|
149
148
|
|
150
149
|
def line_item_ids
|
151
|
-
|
150
|
+
redis.smembers key
|
152
151
|
end
|
153
152
|
|
154
153
|
def line_item_keys
|
@@ -156,7 +155,13 @@ module Cartman
|
|
156
155
|
end
|
157
156
|
|
158
157
|
def get_item(id)
|
159
|
-
Item.new(id, @uid,
|
158
|
+
Item.new(id, @uid, redis.hgetall("cartman:line_item:#{id}").inject({}){|hash,(k,v)| hash[k.to_sym] = v; hash})
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def redis
|
164
|
+
Cartman.config.redis
|
160
165
|
end
|
161
166
|
end
|
162
167
|
end
|
@@ -1,34 +1,18 @@
|
|
1
|
-
require
|
1
|
+
require "redis"
|
2
2
|
|
3
3
|
module Cartman
|
4
4
|
class Configuration
|
5
|
-
|
6
|
-
|
7
|
-
unit_cost_field: :unit_cost, # for cart totaling and costing
|
8
|
-
quantity_field: :quantity, # for cart totaling
|
9
|
-
redis: Redis.new, # Redis connection
|
10
|
-
}
|
5
|
+
attr_accessor :cart_expires_in, :unit_cost_field, :quantity_field
|
6
|
+
attr_writer :redis
|
11
7
|
|
12
|
-
def initialize
|
13
|
-
|
8
|
+
def initialize
|
9
|
+
@cart_expires_in = 604800
|
10
|
+
@unit_cost_field = :unit_cost
|
11
|
+
@quantity_field = :quantity
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
18
|
-
@@configuration.store(method, *args)
|
19
|
-
else
|
20
|
-
@@configuration.fetch(method)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class << self
|
25
|
-
def method_missing(method, *args, &block)
|
26
|
-
if !args.empty?
|
27
|
-
@@configuration.store(method, args[0])
|
28
|
-
else
|
29
|
-
@@configuration.fetch(method)
|
30
|
-
end
|
31
|
-
end
|
14
|
+
def redis
|
15
|
+
@redis ||= Redis.new
|
32
16
|
end
|
33
17
|
end
|
34
18
|
end
|
data/lib/cartman/item.rb
CHANGED
@@ -11,8 +11,8 @@ module Cartman
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def cost
|
14
|
-
unit_cost = (@data.fetch(Cartman
|
15
|
-
quantity = @data.fetch(Cartman
|
14
|
+
unit_cost = (@data.fetch(Cartman.config.unit_cost_field).to_f * 100).to_i
|
15
|
+
quantity = @data.fetch(Cartman.config.quantity_field).to_i
|
16
16
|
(unit_cost * quantity) / 100.0
|
17
17
|
end
|
18
18
|
|
@@ -30,7 +30,7 @@ module Cartman
|
|
30
30
|
|
31
31
|
def touch
|
32
32
|
cart.touch
|
33
|
-
|
33
|
+
redis.hincrby _key, :_version, 1
|
34
34
|
end
|
35
35
|
|
36
36
|
def _key
|
@@ -47,7 +47,7 @@ module Cartman
|
|
47
47
|
|
48
48
|
def method_missing(method, *args, &block)
|
49
49
|
if method.to_s =~ /=\z/
|
50
|
-
|
50
|
+
redis.hset _key, method[0..-2], args[0].to_s
|
51
51
|
@data.store(method[0..-2].to_sym, args[0].to_s)
|
52
52
|
version = touch
|
53
53
|
@data.store(:_version, version)
|
@@ -55,5 +55,11 @@ module Cartman
|
|
55
55
|
@data.fetch(method)
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def redis
|
62
|
+
Cartman.config.redis
|
63
|
+
end
|
58
64
|
end
|
59
65
|
end
|
data/lib/cartman/version.rb
CHANGED
data/spec/cart_spec.rb
CHANGED
@@ -144,14 +144,14 @@ describe Cartman do
|
|
144
144
|
end
|
145
145
|
|
146
146
|
it "should return the sum of the defined quantity field" do
|
147
|
-
Cartman.config do
|
148
|
-
quantity_field :qty
|
147
|
+
Cartman.config do |c|
|
148
|
+
c.quantity_field = :qty
|
149
149
|
end
|
150
150
|
cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, qty: 2)
|
151
151
|
cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, qty: 2)
|
152
152
|
cart.quantity.should eq(4)
|
153
|
-
Cartman.config do
|
154
|
-
quantity_field :quantity
|
153
|
+
Cartman.config do |c|
|
154
|
+
c.quantity_field = :quantity
|
155
155
|
end
|
156
156
|
end
|
157
157
|
end
|
@@ -164,14 +164,14 @@ describe Cartman do
|
|
164
164
|
end
|
165
165
|
|
166
166
|
it "should total whatever cost field the user sets" do
|
167
|
-
Cartman.config do
|
168
|
-
unit_cost_field :unit_cost_in_cents
|
167
|
+
Cartman.config do |c|
|
168
|
+
c.unit_cost_field = :unit_cost_in_cents
|
169
169
|
end
|
170
170
|
cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost_in_cents: 9212, quantity: 2)
|
171
171
|
cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost_in_cents: 9212, quantity: 2)
|
172
172
|
cart.total.should eq(36848)
|
173
|
-
Cartman.config do
|
174
|
-
unit_cost_field :unit_cost
|
173
|
+
Cartman.config do |c|
|
174
|
+
c.unit_cost_field = :unit_cost
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
@@ -197,7 +197,7 @@ describe Cartman do
|
|
197
197
|
Cartman.config.redis.ttl("cartman:cart:1:index").should eq(Cartman.config.cart_expires_in)
|
198
198
|
Cartman.config.redis.ttl("cartman:cart:1:index:Bottle:17").should eq(Cartman.config.cart_expires_in)
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
201
|
it "should record that the cart was updated" do
|
202
202
|
cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
|
203
203
|
cart.touch
|
@@ -212,9 +212,12 @@ describe Cartman do
|
|
212
212
|
end
|
213
213
|
|
214
214
|
it "should rename the key, and index_key if it exists" do
|
215
|
-
cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity:
|
215
|
+
cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 1)
|
216
|
+
cart.add_item(id: 18, type: "Bottle", name: "Merlot", unit_cost: 92.12, cost_in_cents: 18424, quantity: 3)
|
217
|
+
cart.quantity.should be(4)
|
216
218
|
cart.reassign(2)
|
217
|
-
cart.items.size.should be(
|
219
|
+
cart.items.size.should be(2)
|
220
|
+
Cartman::Cart.new(2).quantity.should be(4)
|
218
221
|
Cartman.config.redis.exists("cartman:cart:1").should be_false
|
219
222
|
Cartman.config.redis.exists("cartman:cart:1:index").should be_false
|
220
223
|
Cartman.config.redis.exists("cartman:cart:1:index:Bottle:17").should be_false
|
@@ -222,9 +225,9 @@ describe Cartman do
|
|
222
225
|
Cartman.config.redis.exists("cartman:cart:2:index").should be_true
|
223
226
|
Cartman.config.redis.exists("cartman:cart:2:index:Bottle:17").should be_true
|
224
227
|
cart.send(:key)[-1].should eq("2")
|
225
|
-
cart.add_item(id:
|
228
|
+
cart.add_item(id: 19, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
|
226
229
|
cart.reassign(1)
|
227
|
-
cart.items.size.should be(
|
230
|
+
cart.items.size.should be(3)
|
228
231
|
Cartman.config.redis.exists("cartman:cart:2").should be_false
|
229
232
|
Cartman.config.redis.exists("cartman:cart:2:index").should be_false
|
230
233
|
Cartman.config.redis.exists("cartman:cart:1").should be_true
|
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:
|
4
|
+
version: 2.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:
|
12
|
+
date: 2013-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -79,18 +79,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
79
|
- - ! '>='
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: '0'
|
82
|
-
segments:
|
83
|
-
- 0
|
84
|
-
hash: -738931914198852373
|
85
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
83
|
none: false
|
87
84
|
requirements:
|
88
85
|
- - ! '>='
|
89
86
|
- !ruby/object:Gem::Version
|
90
87
|
version: '0'
|
91
|
-
segments:
|
92
|
-
- 0
|
93
|
-
hash: -738931914198852373
|
94
88
|
requirements: []
|
95
89
|
rubyforge_project:
|
96
90
|
rubygems_version: 1.8.23
|
@@ -102,3 +96,4 @@ test_files:
|
|
102
96
|
- spec/item_collection_spec.rb
|
103
97
|
- spec/item_spec.rb
|
104
98
|
- spec/spec_helper.rb
|
99
|
+
has_rdoc:
|