cartman 1.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|