cartman 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +51 -2
- data/lib/cartman/cart.rb +35 -4
- data/lib/cartman/configuration.rb +6 -1
- data/lib/cartman/version.rb +1 -1
- data/lib/cartman.rb +1 -0
- data/spec/cart_spec.rb +37 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Cartman
|
2
2
|
|
3
|
-
|
3
|
+
![](http://blog.brightcove.com/sites/all/uploads/eric_theodore_cartman_southpark.jpg)
|
4
|
+
|
5
|
+
Cartman is a framework agnostic, redis backed, cart system. It is not a POS, or a full fledged ecommerce system. Just the cart, man.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -16,9 +18,56 @@ Or install it yourself as:
|
|
16
18
|
|
17
19
|
$ gem install cartman
|
18
20
|
|
21
|
+
## Setup
|
22
|
+
|
23
|
+
Cartman has a few (read 3) configuration options you can set, most likely in an initializer file. Here's an example configuration:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
# config/initializers/cartman.rb
|
27
|
+
Cartman.config do
|
28
|
+
cart_expires_in 604800 # one week, in seconds. This is the default
|
29
|
+
return_items_as :openstruct # vs a :hash
|
30
|
+
cost_field :cost # for cart totaling
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
- 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`.
|
35
|
+
- `return_items_as` lets you set how you want Cartman to return your items as. You can choose either an `OpenStruct` or a `Hash`.
|
36
|
+
- `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
|
+
|
19
38
|
## Usage
|
20
39
|
|
21
|
-
|
40
|
+
To create a new shopping cart, just call `Cartman::Cart.new(user.id)`. The parameter for `Cart.new()` is a unique id. If you don't want a user to have more than one cart at a time, it's generally best to set this to the user's id. Then to add an item to the cart, just call `cart.add_item(data)` which takes a hash of data that you want to store. Then to retrieve the items, you just call `cart.items` which will give you an array of all the items they've added.
|
41
|
+
|
42
|
+
Lets walk through an example implementation with a Rails app that has a User model and a Product model.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# app/models/user.rb
|
46
|
+
class User < ActiveRecord::Base
|
47
|
+
#...
|
48
|
+
def cart
|
49
|
+
Cartman::Cart.new(id)
|
50
|
+
end
|
51
|
+
#...
|
52
|
+
end
|
53
|
+
|
54
|
+
# app/controllers/products_controller.rb
|
55
|
+
class ProductsController < ApplicationController
|
56
|
+
#...
|
57
|
+
# /products/:id/add_to_cart
|
58
|
+
def add_to_cart
|
59
|
+
@product = Product.find(params[:id])
|
60
|
+
current_user.cart.add_item(id: @product.id, name: @product.name, unit_cost: @product.cost, cost: @product.cost * params[:quantity], quantity: params[:quantity])
|
61
|
+
end
|
62
|
+
#...
|
63
|
+
end
|
64
|
+
|
65
|
+
# app/view/cart/show.html.haml
|
66
|
+
%h1 Cart - Total: #{@cart.total}
|
67
|
+
%ul
|
68
|
+
- @cart.items.each do |item|
|
69
|
+
%li #{item.name} - #{item.cost}
|
70
|
+
```
|
22
71
|
|
23
72
|
## Contributing
|
24
73
|
|
data/lib/cartman/cart.rb
CHANGED
@@ -11,13 +11,36 @@ module Cartman
|
|
11
11
|
line_item_id = @@redis.incr CART_LINE_ITEM_ID_KEY
|
12
12
|
@@redis.mapped_hmset("cartman:line_item:#{line_item_id}", options)
|
13
13
|
@@redis.sadd key, line_item_id
|
14
|
+
keys_to_expire = line_item_keys
|
15
|
+
keys_to_expire << key
|
16
|
+
@@redis.pipelined do
|
17
|
+
keys_to_expire.each do |item|
|
18
|
+
@@redis.expire item, Cartman::Configuration.cart_expires_in
|
19
|
+
end
|
20
|
+
end
|
14
21
|
end
|
15
22
|
|
16
|
-
def items
|
17
|
-
|
18
|
-
|
19
|
-
@@redis.hgetall "cartman:line_item:#{id}"
|
23
|
+
def items(return_as=Cartman::Configuration.return_items_as)
|
24
|
+
items = line_item_keys.collect { |item_key|
|
25
|
+
@@redis.hgetall(item_key).inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} # symbolize keys
|
20
26
|
}
|
27
|
+
if return_as == :openstruct
|
28
|
+
items.collect { |item|
|
29
|
+
OpenStruct.new(item)
|
30
|
+
}
|
31
|
+
else
|
32
|
+
items
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def total
|
37
|
+
items(:openstruct).collect { |item|
|
38
|
+
(item.send(Cartman::Configuration.cost_field).to_f * 100).to_i
|
39
|
+
}.inject{|sum,cost| sum += cost} / 100.0
|
40
|
+
end
|
41
|
+
|
42
|
+
def ttl
|
43
|
+
@@redis.ttl key
|
21
44
|
end
|
22
45
|
|
23
46
|
private
|
@@ -25,5 +48,13 @@ module Cartman
|
|
25
48
|
def key
|
26
49
|
"cartman:cart:#{@uid}"
|
27
50
|
end
|
51
|
+
|
52
|
+
def line_item_ids
|
53
|
+
@@redis.smembers key
|
54
|
+
end
|
55
|
+
|
56
|
+
def line_item_keys
|
57
|
+
line_item_ids.collect{ |id| "cartman:line_item:#{id}" }
|
58
|
+
end
|
28
59
|
end
|
29
60
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module Cartman
|
2
2
|
class Configuration
|
3
|
-
@@configuration = {
|
3
|
+
@@configuration = {
|
4
|
+
cart_expires_in: 604800, # one week
|
5
|
+
return_items_as: :openstruct, # vs a :hash
|
6
|
+
cost_field: :cost, # for cart totaling
|
7
|
+
}
|
8
|
+
|
4
9
|
def initialize(&block)
|
5
10
|
instance_eval &block
|
6
11
|
end
|
data/lib/cartman/version.rb
CHANGED
data/lib/cartman.rb
CHANGED
data/spec/cart_spec.rb
CHANGED
@@ -28,9 +28,15 @@ describe Cartman do
|
|
28
28
|
it "creates a line item key" do
|
29
29
|
Cartman.config.redis.exists("cartman:line_item:1").should be_true
|
30
30
|
end
|
31
|
+
|
31
32
|
it "adds that line item key's id to the cart set" do
|
32
33
|
Cartman.config.redis.sismember(cart.send(:key), 1).should be_true
|
33
34
|
end
|
35
|
+
|
36
|
+
it "should expire the line_item_keys in the amount of time specified" do
|
37
|
+
cart.ttl.should eq(Cartman.config.cart_expires_in)
|
38
|
+
Cartman.config.redis.ttl("cartman:line_item:1").should eq(Cartman.config.cart_expires_in)
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
42
|
describe "#items" do
|
@@ -39,10 +45,40 @@ describe Cartman do
|
|
39
45
|
cart.add_item(id: 34, class: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
|
40
46
|
end
|
41
47
|
|
42
|
-
it "should return an array of hashes" do
|
48
|
+
it "should return an array of hashes if config hashes is set" do
|
49
|
+
Cartman.config do
|
50
|
+
return_items_as :hash
|
51
|
+
end
|
43
52
|
cart.items.class.should eq(Array)
|
44
53
|
cart.items.first.class.should eq(Hash)
|
45
54
|
cart.items.size.should eq(2)
|
55
|
+
cart.items.first[:id].should eq("17")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should return an array of openstructs if no return type is set" do
|
59
|
+
Cartman.config do
|
60
|
+
return_items_as :openstruct
|
61
|
+
end
|
62
|
+
cart.items.first.class.should eq(OpenStruct)
|
63
|
+
cart.items.first.id.should eq("17")
|
64
|
+
cart.items.first.name.should eq("Bordeux")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#total" do
|
69
|
+
it "should total the default costs field" do
|
70
|
+
cart.add_item(id: 17, class: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
|
71
|
+
cart.add_item(id: 34, class: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
|
72
|
+
cart.total.should eq(368.48)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should total whatever cost field the user sets" do
|
76
|
+
Cartman.config do
|
77
|
+
cost_field :cost_in_cents
|
78
|
+
end
|
79
|
+
cart.add_item(id: 17, class: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
|
80
|
+
cart.add_item(id: 34, class: "Bottle", name: "Cabernet", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
|
81
|
+
cart.total.should eq(36848)
|
46
82
|
end
|
47
83
|
end
|
48
84
|
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
|
+
version: 0.2.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-
|
12
|
+
date: 2012-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: redis
|
@@ -76,7 +76,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
76
|
version: '0'
|
77
77
|
segments:
|
78
78
|
- 0
|
79
|
-
hash:
|
79
|
+
hash: 1736743105413686891
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
85
|
version: '0'
|
86
86
|
segments:
|
87
87
|
- 0
|
88
|
-
hash:
|
88
|
+
hash: 1736743105413686891
|
89
89
|
requirements: []
|
90
90
|
rubyforge_project:
|
91
91
|
rubygems_version: 1.8.23
|