cartman 0.1.0 → 0.2.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 +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
|
+

|
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
|