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