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 CHANGED
@@ -1,6 +1,8 @@
1
1
  # Cartman
2
2
 
3
- TODO: Write a gem description
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
- TODO: Write usage instructions here
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
- line_item_ids = @@redis.smembers key
18
- line_item_ids.collect { |id|
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
@@ -1,3 +1,3 @@
1
1
  module Cartman
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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 'redis'
5
+ require 'ostruct'
5
6
 
6
7
  module Cartman
7
8
  module_function
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.1.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-19 00:00:00.000000000 Z
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: -2349574205203334648
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: -2349574205203334648
88
+ hash: 1736743105413686891
89
89
  requirements: []
90
90
  rubyforge_project:
91
91
  rubygems_version: 1.8.23