cartman 0.2.0 → 0.3.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/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Cartman
2
+ [![Build Status](https://secure.travis-ci.org/willcosgrove/cartman.png)](http://travis-ci.org/willcosgrove/cartman)
2
3
 
3
4
  ![](http://blog.brightcove.com/sites/all/uploads/eric_theodore_cartman_southpark.jpg)
4
5
 
@@ -26,19 +27,26 @@ Cartman has a few (read 3) configuration options you can set, most likely in an
26
27
  # config/initializers/cartman.rb
27
28
  Cartman.config do
28
29
  cart_expires_in 604800 # one week, in seconds. This is the default
29
- return_items_as :openstruct # vs a :hash
30
30
  cost_field :cost # for cart totaling
31
+ redis Redis.new # set the redis connection here
31
32
  end
32
33
  ```
33
34
 
34
35
  - 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
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
37
 
38
38
  ## Usage
39
39
 
40
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
41
 
42
+ The returned Items come back as `Cartman::Item` instances, which have a few special methods to be aware of:
43
+
44
+ - `remove` - which will remove the item from the cart
45
+ - `cart` - which will return the parent cart, think ActiveRecord association
46
+ - `_id` - which will return the id of the item, if you need that for whatever reason
47
+ - `_key` - which will return the redis key the data is stored in. Probably won't need that, but it's there.
48
+ - `#{attribute}=` - this is a setter defined for all of the items attributes that you gave it. It will instantly save to redis also, so no need to call `save` (which is why there isn't a `save`).
49
+
42
50
  Lets walk through an example implementation with a Rails app that has a User model and a Product model.
43
51
 
44
52
  ```ruby
data/lib/cartman.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "cartman/version"
2
2
  require "cartman/configuration"
3
3
  require "cartman/cart"
4
+ require "cartman/item"
4
5
  require 'redis'
5
6
  require 'ostruct'
6
7
 
@@ -10,7 +11,7 @@ module Cartman
10
11
  if block_given?
11
12
  @config = Configuration.new(&block)
12
13
  else
13
- @config
14
+ @config ||= Configuration.new
14
15
  end
15
16
  end
16
17
  end
data/lib/cartman/cart.rb CHANGED
@@ -18,23 +18,22 @@ module Cartman
18
18
  @@redis.expire item, Cartman::Configuration.cart_expires_in
19
19
  end
20
20
  end
21
+ get_item(line_item_id)
21
22
  end
22
23
 
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
24
+ def remove_item(item)
25
+ @@redis.del "cartman:line_item:#{item._id}"
26
+ @@redis.srem key, item._id
27
+ end
28
+
29
+ def items
30
+ items = line_item_ids.collect { |item_id|
31
+ get_item(item_id)
26
32
  }
27
- if return_as == :openstruct
28
- items.collect { |item|
29
- OpenStruct.new(item)
30
- }
31
- else
32
- items
33
- end
34
33
  end
35
34
 
36
35
  def total
37
- items(:openstruct).collect { |item|
36
+ items.collect { |item|
38
37
  (item.send(Cartman::Configuration.cost_field).to_f * 100).to_i
39
38
  }.inject{|sum,cost| sum += cost} / 100.0
40
39
  end
@@ -56,5 +55,9 @@ module Cartman
56
55
  def line_item_keys
57
56
  line_item_ids.collect{ |id| "cartman:line_item:#{id}" }
58
57
  end
58
+
59
+ def get_item(id)
60
+ Item.new(id, @uid, @@redis.hgetall("cartman:line_item:#{id}").inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo})
61
+ end
59
62
  end
60
63
  end
@@ -1,13 +1,15 @@
1
+ require 'redis'
2
+
1
3
  module Cartman
2
4
  class Configuration
3
5
  @@configuration = {
4
6
  cart_expires_in: 604800, # one week
5
- return_items_as: :openstruct, # vs a :hash
6
7
  cost_field: :cost, # for cart totaling
8
+ redis: Redis.new, # Redis connection
7
9
  }
8
10
 
9
11
  def initialize(&block)
10
- instance_eval &block
12
+ instance_eval &block if block_given?
11
13
  end
12
14
 
13
15
  def method_missing(method, *args, &block)
@@ -0,0 +1,34 @@
1
+ module Cartman
2
+ class Item
3
+ def initialize(item_id, cart_id, data)
4
+ @id = item_id
5
+ @cart_id = cart_id
6
+ @data = data
7
+ end
8
+
9
+ def _id
10
+ @id
11
+ end
12
+
13
+ def cart
14
+ @cart ||= Cart.new(@cart_id)
15
+ end
16
+
17
+ def remove
18
+ cart.remove_item(self)
19
+ end
20
+
21
+ def _key
22
+ "cartman:line_item:#{@id}"
23
+ end
24
+
25
+ def method_missing(method, *args, &block)
26
+ if method.to_s =~ /=\z/
27
+ Cartman::Configuration.redis.hset _key, method[0..-2], args[0].to_s
28
+ @data.store(method[0..-2].to_sym, args[0].to_s)
29
+ else
30
+ @data.fetch(method)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module Cartman
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/spec/cart_spec.rb CHANGED
@@ -4,12 +4,6 @@ describe Cartman do
4
4
  describe Cartman::Cart do
5
5
  let(:cart) { Cartman::Cart.new(1) }
6
6
 
7
- before(:all) do
8
- Cartman.config do
9
- redis Redis.new
10
- end
11
- end
12
-
13
7
  before(:each) do
14
8
  Cartman.config.redis.flushdb
15
9
  end
@@ -22,7 +16,7 @@ describe Cartman do
22
16
 
23
17
  describe "#add_item" do
24
18
  before(:each) do
25
- cart.add_item(id: 17, class: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
19
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
26
20
  end
27
21
 
28
22
  it "creates a line item key" do
@@ -37,29 +31,31 @@ describe Cartman do
37
31
  cart.ttl.should eq(Cartman.config.cart_expires_in)
38
32
  Cartman.config.redis.ttl("cartman:line_item:1").should eq(Cartman.config.cart_expires_in)
39
33
  end
34
+
35
+ it "should return an Item" do
36
+ item = cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
37
+ item.class.should eq(Cartman::Item)
38
+ end
40
39
  end
41
40
 
42
- describe "#items" do
43
- before(:each) do
44
- cart.add_item(id: 17, class: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
45
- cart.add_item(id: 34, class: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
41
+ describe "#remove_item" do
42
+ it "should remove the id from the set, and delete the line_item key" do
43
+ item = cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
44
+ item_id = item._id
45
+ cart.remove_item(item)
46
+ Cartman.config.redis.sismember(cart.send(:key), item_id).should be_false
47
+ Cartman.config.redis.exists("cartman:line_item:#{item_id}").should be_false
46
48
  end
49
+ end
47
50
 
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
52
- cart.items.class.should eq(Array)
53
- cart.items.first.class.should eq(Hash)
54
- cart.items.size.should eq(2)
55
- cart.items.first[:id].should eq("17")
51
+ describe "#items" do
52
+ before(:each) do
53
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
54
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
56
55
  end
57
56
 
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)
57
+ it "should return an array of Items" do
58
+ cart.items.first.class.should eq(Cartman::Item)
63
59
  cart.items.first.id.should eq("17")
64
60
  cart.items.first.name.should eq("Bordeux")
65
61
  end
@@ -67,8 +63,8 @@ describe Cartman do
67
63
 
68
64
  describe "#total" do
69
65
  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)
66
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2)
67
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost: 184.24, quantity: 2)
72
68
  cart.total.should eq(368.48)
73
69
  end
74
70
 
@@ -76,8 +72,8 @@ describe Cartman do
76
72
  Cartman.config do
77
73
  cost_field :cost_in_cents
78
74
  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)
75
+ cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
76
+ cart.add_item(id: 34, type: "Bottle", name: "Cabernet", unit_cost: 92.12, cost_in_cents: 18424, quantity: 2)
81
77
  cart.total.should eq(36848)
82
78
  end
83
79
  end
data/spec/item_spec.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cartman do
4
+ describe Cartman::Item do
5
+ let(:cart) { Cartman::Cart.new(1) }
6
+ let(:item) { cart.add_item(id: 17, type: "Bottle", name: "Bordeux", unit_cost: 92.12, cost: 184.24, quantity: 2) }
7
+
8
+ describe "data getters and setters" do
9
+ it "should let me get data stored for the item" do
10
+ item.id.should eq("17")
11
+ item.type.should eq("Bottle")
12
+ item.cost.should eq("184.24")
13
+ end
14
+
15
+ it "should let me modify data stored for the item" do
16
+ item.quantity.should eq("2")
17
+ item.quantity = 3
18
+ item.quantity.should eq("3")
19
+ end
20
+
21
+ it "should immediately save data back to redis" do
22
+ item.quantity.should eq("2")
23
+ item.quantity = 3
24
+ new_item = cart.send(:get_item, item._id)
25
+ new_item.quantity.should eq("3")
26
+ end
27
+ end
28
+
29
+ describe "#remove" do
30
+ it "should remove the item from the cart" do
31
+ item_id = item._id
32
+ item.remove
33
+ Cartman.config.redis.sismember(cart.send(:key), item_id).should be_false
34
+ Cartman.config.redis.exists("cartman:line_item:#{item_id}").should be_false
35
+ end
36
+ end
37
+
38
+ end
39
+ 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.2.0
4
+ version: 0.3.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-21 00:00:00.000000000 Z
12
+ date: 2012-10-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -51,6 +51,7 @@ extensions: []
51
51
  extra_rdoc_files: []
52
52
  files:
53
53
  - .gitignore
54
+ - .travis.yml
54
55
  - Gemfile
55
56
  - LICENSE.txt
56
57
  - README.md
@@ -59,8 +60,10 @@ files:
59
60
  - lib/cartman.rb
60
61
  - lib/cartman/cart.rb
61
62
  - lib/cartman/configuration.rb
63
+ - lib/cartman/item.rb
62
64
  - lib/cartman/version.rb
63
65
  - spec/cart_spec.rb
66
+ - spec/item_spec.rb
64
67
  - spec/spec_helper.rb
65
68
  homepage: http://github.com/willcosgrove/cartman
66
69
  licenses: []
@@ -76,7 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
79
  version: '0'
77
80
  segments:
78
81
  - 0
79
- hash: 1736743105413686891
82
+ hash: 3094534765024072547
80
83
  required_rubygems_version: !ruby/object:Gem::Requirement
81
84
  none: false
82
85
  requirements:
@@ -85,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
88
  version: '0'
86
89
  segments:
87
90
  - 0
88
- hash: 1736743105413686891
91
+ hash: 3094534765024072547
89
92
  requirements: []
90
93
  rubyforge_project:
91
94
  rubygems_version: 1.8.23
@@ -94,4 +97,5 @@ specification_version: 3
94
97
  summary: Doing shopping carts like a boss since 2012
95
98
  test_files:
96
99
  - spec/cart_spec.rb
100
+ - spec/item_spec.rb
97
101
  - spec/spec_helper.rb