cart 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jakub Stastny aka Botanicus
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ h1. About
2
+
3
+ Cart is framework agnostic solution for shopping cart. There are two existing imlementations. First is *Cart::Simple* which is just basic cart which can store only ID of products without any metadata. The second is *Cart::Advanced* and it is good when you have not just product, but also some metadata as size or color of product etc.
4
+
5
+ h1. Initialization
6
+
7
+ h2. Cart::Simple
8
+
9
+ <pre>
10
+ require "cart/simple"
11
+ Cart.product_model = Product
12
+ </pre>
13
+
14
+ h2. Cart::Advanced
15
+
16
+ <pre>
17
+ require "cart/advanced"
18
+ Cart.metadata_model = OrderItem
19
+ </pre>
20
+
21
+ Metadata model must respond to serialize object method and deserialize class method for storing and restoring data:
22
+
23
+ <pre>
24
+ class OrderItem
25
+ include DataMapper::Resource
26
+ class << self
27
+ def deserialize(data)
28
+ self.new(YAML::load(data))
29
+ end
30
+ end
31
+
32
+ def serialize
33
+ {:size => self.size, :product_id => self.product.id}.to_yaml
34
+ end
35
+ end
36
+ </pre>
37
+
38
+ h2. Logger
39
+
40
+ Cart is just simple API for your favorite framework, so it haven't any logger itself and it just use the logger of your framework. The only thing you need is setup it:
41
+
42
+ <pre>
43
+ # whatever what respond to debug method
44
+ Cart.logger = Merb.logger
45
+ </pre>
46
+
47
+ Maybe you would like to hook the logger, for example add information that the message comes from cart or maybe you just use framework which hasn't any logger at all. In this case you can set logger to lambda or whatever callable object:
48
+
49
+ <pre>
50
+ # or whatever what respond to to_proc method
51
+ Cart.logger = method(:puts)
52
+ Cart.logger = lambda { |msg| puts(msg) }
53
+ </pre>
54
+
55
+ h1. Usage
56
+
57
+ <pre>
58
+ class Application < Merb::Controller
59
+ # it must be deserialized in each request,
60
+ # even with memory session store
61
+ before :initialize_cart
62
+
63
+ def initialize_cart
64
+ @cart = cookies[:cart] ? Cart.load(cookies[:cart]) : Cart.new
65
+ end
66
+
67
+ def save_cart
68
+ cookies[:cart] = @cart.save
69
+ end
70
+
71
+ def reset_cart
72
+ cookies.delete(:cart)
73
+ @cart = Cart.new
74
+ end
75
+
76
+ def add_to_cart(order_item)
77
+ self.initialize_cart unless @cart
78
+ @cart.add(order_item)
79
+ self.save_cart
80
+ end
81
+
82
+ # Remove all the items with responding product and inverted values from cart
83
+ def remove_from_cart(order_item)
84
+ @cart.remove(order_item)
85
+ self.save_cart
86
+ end
87
+ end
88
+ </pre>
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ GEM_NAME = "cart"
5
+ AUTHOR = "Jakub Stastny aka Botanicus"
6
+ EMAIL = "knava.bestvinensis@gmail.com"
7
+ HOMEPAGE = "http://101Ideas.cz/"
8
+ SUMMARY = "Framework agnostic cart solution"
9
+ GEM_VERSION = "0.0.1"
10
+
11
+ spec = Gem::Specification.new do |s|
12
+ s.name = GEM_NAME
13
+ s.version = GEM_VERSION
14
+ s.platform = Gem::Platform::RUBY
15
+ s.has_rdoc = true
16
+ s.extra_rdoc_files = ["README.textile", "LICENSE"]
17
+ s.summary = SUMMARY
18
+ s.description = s.summary
19
+ s.author = AUTHOR
20
+ s.email = EMAIL
21
+ s.homepage = HOMEPAGE
22
+ s.require_path = 'lib'
23
+ s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib,spec,app,public,stubs}/**/*")
24
+ end
25
+
26
+ Rake::GemPackageTask.new(spec) do |pkg|
27
+ pkg.gem_spec = spec
28
+ end
29
+
30
+ desc "Create a gemspec file"
31
+ task :gemspec do
32
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
33
+ file.puts spec.to_ruby
34
+ end
35
+ end
36
+
37
+ def sudo_gem(cmd)
38
+ sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
39
+ end
40
+
41
+ desc "Install #{GEM_NAME} #{GEM_VERSION}"
42
+ task :install => [ :package ] do
43
+ sudo_gem "install --local pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
44
+ end
45
+
46
+ desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
47
+ task :uninstall => [ :clobber ] do
48
+ sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -Ix"
49
+ end
50
+
51
+ require 'spec/rake/spectask'
52
+ desc 'Default: run spec examples'
53
+ task :default => 'spec'
data/TODO ADDED
@@ -0,0 +1,7 @@
1
+ - spec advanced and simple carts (other stuff should work)
2
+ - simple and advanced carts should have same interface
3
+ - it should works without logger
4
+ - move all the stuff into model (Cart::Simple.new etc)
5
+ - config should take strings as well (Cart.product_model = "Product")
6
+ - config should have default values (Product, OrderItem)
7
+ - standalone configuration class (maybe something like configatron?) => easier testing
@@ -0,0 +1,21 @@
1
+ begin
2
+ require "rubygems/specification"
3
+ rescue SecurityError
4
+ # http://gems.github.com
5
+ end
6
+
7
+ VERSION = "0.0.1"
8
+ SPECIFICATION = ::Gem::Specification.new do |s|
9
+ s.name = "cart"
10
+ s.version = VERSION
11
+ s.authors = ["Jakub Šťastný aka Botanicus"]
12
+ s.homepage = "http://github.com/botanicus/cart"
13
+ s.summary = "Cart is framework agnostic solution for shopping cart."
14
+ s.description = "Cart is framework agnostic solution for shopping cart. There are two existing imlementations. First is *Cart::Simple* which is just basic cart which can store only ID of products without any metadata. The second is *Cart::Advanced* and it is good when you have not just product, but also some metadata as size or color of product etc."
15
+ s.cert_chain = nil
16
+ s.email = ["knava.bestvinensis", "gmail.com"].join("@")
17
+ s.files = Dir.glob("**/*") - Dir.glob("pkg/*")
18
+ s.require_paths = ["lib"]
19
+ # s.required_ruby_version = ::Gem::Requirement.new(">= 1.9.1")
20
+ # s.rubyforge_project = "cart"
21
+ end
@@ -0,0 +1,108 @@
1
+ require "cart/config"
2
+
3
+ class Cart
4
+ def self.load(data)
5
+ # return new cart if nil or empty string is given
6
+ return self.new if data.nil? or data.empty?
7
+ data = data.split(";")
8
+ # compact output array, self.metadata_model.deserialize could return nil
9
+ items = data.map { |item| self.metadata_model.deserialize(item) }.compact
10
+ return self.new(*items)
11
+ end
12
+
13
+ attr_reader :items
14
+
15
+ def initialize(*items)
16
+ # raise ArgumentError unless items.all? { |item| item.is_a?(@config.metadata_model) || item.nil? }
17
+ @items = items
18
+ @config = self.class
19
+ @config.logger.debug("Cart initialized: #{self.inspect}")
20
+ end
21
+
22
+ # takes array of products
23
+ def items=(items)
24
+ raise ArgumentError if not items.respond_to?(:each) # not just arrays
25
+ raise ArgumentError if not items.all? { |product| product.kind_of?(@config.metadata_model) }
26
+ @items = items
27
+ end
28
+
29
+ # params_list must be list of hashes or list of @config.metadata_model instances
30
+ def add(*params_list)
31
+ params_list.each do |params|
32
+ if params.is_a?(Hash)
33
+ new_item = @config.metadata_model.new(params)
34
+ else
35
+ new_item = params
36
+ end
37
+ @items.map do |item|
38
+ if items_equal?(item, new_item)
39
+ item.count += new_item.count
40
+ @config.logger.debug("Item #{item.inspect} count was increased to #{item.count} (by #{new_item.count})")
41
+ return # important
42
+ end
43
+ end
44
+ @items.push(new_item)
45
+ @config.logger.debug("Item #{new_item.inspect} was added to cart")
46
+ return new_item.product
47
+ end
48
+ end
49
+
50
+ def items_equal?(old, new)
51
+ # this is important, we must compare all the properties exclude count
52
+ old = old.dup.tap { |old| old.count = 1 }
53
+ new = new.dup.tap { |new| new.count = 1 }
54
+ # from form empty values goes as "", but deserialized empty items are nil
55
+ properties = new.class.properties.map(&:name)
56
+ properties.each do |property|
57
+ value = new.send(property)
58
+ new.send("#{property}=", nil) if value.respond_to?(:empty?) && value.empty?
59
+ end
60
+ new.eql?(old)
61
+ end
62
+
63
+ def remove(params)
64
+ raise ArgumentError unless params.is_a?(Hash)
65
+ item_to_remove = @config.metadata_model.new(params)
66
+ p [item_to_remove], @items ####
67
+ pre = @items.dup
68
+ @items.delete_if { |item| items_equal?(item, item_to_remove) }
69
+ removed = pre - @items
70
+ if removed.first
71
+ @config.logger.debug("Item #{removed.first.inspect} was removed from cart")
72
+ else
73
+ @config.logger.debug("Any item matched")
74
+ end
75
+ end
76
+
77
+ def price
78
+ @items.map { |item| item.price }.inject(:+)
79
+ end
80
+
81
+ def vat
82
+ @items.map { |item| item.vat }.inject(:+)
83
+ end
84
+
85
+ def price_without_vat
86
+ @items.map { |item| item.price_without_vat }.inject(:+)
87
+ end
88
+
89
+ def save
90
+ data = @items.map { |item| item.serialize }.join(";")
91
+ @config.logger.debug("Cart saved: #{data.inspect}")
92
+ return data
93
+ end
94
+
95
+ def each(&block)
96
+ @items.each do |item|
97
+ block.call(item)
98
+ end
99
+ end
100
+
101
+ def empty?
102
+ @items.empty?
103
+ end
104
+
105
+ def count
106
+ @items.length
107
+ end
108
+ end
@@ -0,0 +1,30 @@
1
+ require "cart/logger_stub"
2
+
3
+ class NotInitializedError < StandardError ; end
4
+
5
+ class Cart
6
+ class << self
7
+ attr_writer :product_model, :metadata_model
8
+ def product_model
9
+ @product_model || raise(NotInitializedError)
10
+ end
11
+
12
+ def metadata_model
13
+ @metadata_model || raise(NotInitializedError)
14
+ end
15
+
16
+ def logger
17
+ @logger || raise(NotInitializedError)
18
+ end
19
+
20
+ def logger=(logger)
21
+ if logger.respond_to?(:to_proc)
22
+ @logger = LoggerStub.new(logger)
23
+ elsif logger.respond_to?(:debug)
24
+ @logger = logger
25
+ else
26
+ raise "Given logger must be callable object (Proc or Method for example) or an object with debug method."
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ # This class is just a wrapper which give you
2
+ # chance to give callable object instead of logger.
3
+ # See README file for more informations.
4
+
5
+ # LoggerStub.new lambda { |message| puts message }
6
+ # LoggerStub.new(method(:puts))
7
+ class LoggerStub
8
+ def initialize(callable)
9
+ @callable = callable
10
+ end
11
+
12
+ def debug(message)
13
+ @callable.call(message)
14
+ end
15
+ end
@@ -0,0 +1,78 @@
1
+ require "ostruct"
2
+ require "cart/config"
3
+
4
+ class CartItem < OpenStruct
5
+ undef :id
6
+ end
7
+
8
+ # NOTE: all public methods works with products, not with their IDs
9
+ class Cart
10
+ def self.load(data)
11
+ cart = Cart.new
12
+ unless data.nil?
13
+ data = YAML::load(data)
14
+ cart.items = data.map { |id| @config.product_model.get(id) }
15
+ end
16
+ return cart
17
+ end
18
+
19
+ # returns array of products
20
+ def items
21
+ @items.map { |item| @config.product_model.get(item) }
22
+ end
23
+
24
+ def inspect
25
+ %{<cart @items=#{@config.product_model}#{@items.map { |i| i.id }.inspect}>}
26
+ end
27
+
28
+ # takes array of products
29
+ def items=(products)
30
+ raise ArgumentError if not products.respond_to?(:each) # not just arrays
31
+ raise ArgumentError if not products.all? { |product| product.kind_of?(@config.product_model) }
32
+ @items = products.to_a
33
+ end
34
+
35
+ def initialize
36
+ @items = Array.new
37
+ @config = self.class
38
+ end
39
+
40
+ def save
41
+ @items.map { |product| product.id }.to_yaml
42
+ end
43
+
44
+ def add(product, count = 1)
45
+ raise ArgumentError unless product.kind_of(@config.product_model)
46
+ if item = find(product)
47
+ item.count += count
48
+ else
49
+ struct = CartItem.new
50
+ struct.id = id
51
+ struct.count = count
52
+ @items.push(struct)
53
+ end
54
+ end
55
+
56
+ # remove all products with id 1
57
+ # cart.remove(1)
58
+ # remove 2 products with id 1
59
+ # cart.remove(1, 2)
60
+ def remove(product, count = nil)
61
+ if item = find(product)
62
+ if count.nil? || item.count <= count
63
+ @items.delete(item)
64
+ elsif item.count > count
65
+ item.count = (item.count - count)
66
+ end
67
+ end
68
+ end
69
+
70
+ def empty?
71
+ @items.empty?
72
+ end
73
+
74
+ protected
75
+ def find(product)
76
+ @items.find { |item| item.id.eql?(product.id) }
77
+ end
78
+ end
@@ -0,0 +1,135 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "cart/advanced"
3
+
4
+ Cart.metadata_model = OrderItem
5
+ Cart.logger = lambda { }
6
+
7
+ describe Cart do
8
+ before(:each) do
9
+ items = 10.of { OrderItem.make(:saved_products) }
10
+ # we need to save all the products otherwise we can't
11
+ # serialize the cart (we need to know product ID)
12
+ @cart = Cart.new(*items)
13
+ end
14
+
15
+ describe ".load" do
16
+ it "should load serialized items" do
17
+ loaded_cart = Cart.load(@cart.save)
18
+ loaded_cart.items.should eql(@cart.items)
19
+ end
20
+
21
+ it "should return empty cart if first (and only) argument is nil" do
22
+ Cart.load(nil).items.should eql(Array.new)
23
+ end
24
+
25
+ it "should return empty cart if first (and only) argument is empty string" do
26
+ Cart.load(String.new).items.should eql(Array.new)
27
+ end
28
+ end
29
+
30
+ describe "#items" do
31
+ it "should create new cart with empty items" do
32
+ Cart.new.items.should be_empty
33
+ end
34
+
35
+ it "should be array of order items" do
36
+ @cart.items.all? { |item| item.kind_of?(OrderItem) }.should be_true
37
+ end
38
+ end
39
+
40
+ describe "#items=" do
41
+ it "should raise ArgumentError if first (and only) argument isn't collection" do
42
+ lambda { @cart.items = 1 }.should raise_error(ArgumentError)
43
+ end
44
+
45
+ it "should raise ArgumentError if some of items isn't integer" do
46
+ lambda { @cart.items = [1, "foo"] }.should raise_error(ArgumentError)
47
+ end
48
+ end
49
+
50
+ describe "#save" do
51
+ it "should serialize items" do
52
+ @cart.save.should be_kind_of(String)
53
+ end
54
+
55
+ it "should be in valid format" do
56
+ pattern = 10.of {'\d+,\d,\d+'}.join(";")
57
+ @cart.save.should match(/^#{pattern}$/)
58
+ end
59
+ end
60
+
61
+ describe "#add" do
62
+ before do
63
+ # NOTE: when inspecting @item, u can see that
64
+ # product_id is nil althought we set the product.
65
+ # It is OK, product_id is set when product is saving
66
+ @item = OrderItem.make
67
+ @cart = Cart.new(@item)
68
+ @item.product.category = Category.generate(:standalone)
69
+ @item.product.save
70
+ @params = {:product => @item.product, :inverted => @item.inverted}
71
+ end
72
+
73
+ it "should add one order item into cart's items by default" do
74
+ lambda { @cart.add(@params) }.should_not change { @cart.count }
75
+ end
76
+
77
+ it "should increase count of order item if product and inverted are same" do
78
+ item = @cart.items.find { |item| item.product.eql?(@item.product) }
79
+ lambda { @cart.add(@params) }.should change { item.count }.by(1)
80
+ end
81
+
82
+ it "should add more order items into cart's items if product is different" do
83
+ another = Product.generate(:standalone)
84
+ params = @params.merge(:product => another)
85
+ lambda { @cart.add(params) }.should change { @cart.count }.by(1)
86
+ end
87
+
88
+ it "should add more order items into cart's items if product is same, but inverted is different" do
89
+ params = @params.merge(:inverted => (not @item.inverted))
90
+ lambda { @cart.add(params) }.should change { @cart.count }.by(1)
91
+ end
92
+
93
+ it "should raise error if params are not hash" do
94
+ lambda { @cart.add(@item) }.should raise_error(ArgumentError)
95
+ end
96
+ end
97
+
98
+ describe "#remove" do
99
+ before do
100
+ # NOTE: when inspecting @item, u can see that
101
+ # product_id is nil althought we set the product.
102
+ # It is OK, product_id is set when product is saving
103
+ @item = OrderItem.make
104
+ @cart = Cart.new(@item)
105
+ @item.product.category = Category.generate(:standalone)
106
+ @item.product.save
107
+ @params = {:product => @item.product, :inverted => @item.inverted}
108
+ end
109
+
110
+ it "should remove order item with coresponding product and inverted options from cart's items" do
111
+ lambda { @cart.remove(@params) }.should change { @cart.count }.by(-1)
112
+ end
113
+
114
+ it "should raise error if params are not hash" do
115
+ lambda { @cart.remove(@item) }.should raise_error(ArgumentError)
116
+ end
117
+ end
118
+
119
+ describe "#empty?" do
120
+ it "should returns true if there aren't any items" do
121
+ Cart.new.should be_empty
122
+ end
123
+
124
+ it "should returns false if there aren't any items" do
125
+ @cart.should_not be_empty
126
+ end
127
+ end
128
+
129
+ describe "#count" do
130
+ it "should returns count of items" do
131
+ Cart.new.count.should eql(0)
132
+ @cart.count.should eql(10)
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "cart/config"
3
+
4
+ class Logger
5
+ def debug(message)
6
+ puts(message)
7
+ end
8
+ end
9
+
10
+ describe Cart do
11
+ describe "#product_model & #product_model=" do
12
+ it "should returns given model if configured" do
13
+ Cart.product_model = Product
14
+ Cart.product_model.should eql(Product)
15
+ end
16
+
17
+ it "should raise an exception unless configured" do
18
+ Cart.product_model = nil
19
+ lambda { Cart.product_model }.should raise_error(NotInitializedError)
20
+ end
21
+ end
22
+
23
+ describe "#metadata_model & #metadata_model=" do
24
+ it "should returns given model if configured" do
25
+ Cart.metadata_model = Product
26
+ Cart.metadata_model.should eql(Product)
27
+ end
28
+
29
+ it "should raise an exception unless configured" do
30
+ Cart.metadata_model = nil
31
+ lambda { Cart.metadata_model }.should raise_error(NotInitializedError)
32
+ end
33
+ end
34
+
35
+ describe "#logger & #logger=" do
36
+ it "should works with lambdas" do
37
+ Cart.logger = Logger.new
38
+ Cart.logger.should be_kind_of(Logger)
39
+ end
40
+
41
+ it "should raise exception when object is not callable and not respond to debug method" do
42
+ lambda { Cart.logger = Class.new }.should raise_error
43
+ end
44
+
45
+ it "should works with lambdas" do
46
+ Cart.logger = lambda { |msg| puts(msg) }
47
+ Cart.logger.should be_kind_of(LoggerStub)
48
+ end
49
+
50
+ it "should works with references to method" do
51
+ Cart.logger = method(:puts)
52
+ Cart.logger.should be_kind_of(LoggerStub)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "cart/logger_stub"
3
+
4
+ describe LoggerStub do
5
+ it "should works with lambdas" do
6
+ # just return the message
7
+ proc = lambda { |message| message }
8
+ logger = LoggerStub.new(proc)
9
+ logger.debug("Hey, it works!").should eql("Hey, it works!")
10
+ end
11
+
12
+ it "should works with methods" do
13
+ # just return the message
14
+ def just_return(message) ; message ; end
15
+ logger = LoggerStub.new(method(:just_return))
16
+ logger.debug("Hey, it works!").should eql("Hey, it works!")
17
+ end
18
+ end
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(__FILE__), '..', "spec_helper")
2
+ require "cart/simple"
3
+
4
+ Cart.product_model = Product
5
+ Cart.logger = lambda { }
6
+
7
+ describe Cart do
8
+ before(:each) do
9
+ @cart = Cart.new
10
+ 10.times { Product.create }
11
+ @cart.items = Product.all
12
+ end
13
+
14
+ describe ".load" do
15
+ it "should load serialized items" do
16
+ pending "works, but this spec do not"
17
+ loaded_cart = Cart.load(@cart.save)
18
+ loaded_cart.items.should eql(@cart.items)
19
+ end
20
+
21
+ it "should return empty cart if first (and only) argument is nil" do
22
+ Cart.load(nil).items.should eql(Array.new)
23
+ end
24
+ end
25
+
26
+ describe "#items" do
27
+ it "should create new cart with empty items" do
28
+ Cart.new.items.should be_empty
29
+ end
30
+
31
+ it "should be array of products" do
32
+ pending "works, but this spec do not"
33
+ @cart.items.all? { |item| item.kind_of?(Product) }.should be_true
34
+ end
35
+ end
36
+
37
+ describe "#items=" do
38
+ it "should raise ArgumentError if first (and only) argument isn't collection" do
39
+ lambda { @cart.items = 1 }.should raise_error(ArgumentError)
40
+ end
41
+
42
+ it "should raise ArgumentError if some of items isn't integer" do
43
+ lambda { @cart.items = [1, "foo"] }.should raise_error(ArgumentError)
44
+ end
45
+ end
46
+
47
+ describe "#inspect" do
48
+ it "should show id of products in items"
49
+ end
50
+
51
+ describe "#save" do
52
+ it "should serialize items" do
53
+ @cart.save.should be_kind_of(String)
54
+ end
55
+
56
+ it "should be regular YAML" do
57
+ lambda { YAML::load(@cart.save) }.should_not raise_error
58
+ end
59
+ end
60
+
61
+ describe "#add" do
62
+ it "should add one product into cart's items by default"
63
+ it "should add more product into cart's items when optional argument given"
64
+ end
65
+
66
+ describe "#remove" do
67
+ it "should remove one product into cart's items by default"
68
+ it "should remove more product into cart's items when optional argument given"
69
+ end
70
+
71
+ describe "#empty?" do
72
+ it "should returns true if there aren't any items" do
73
+ Cart.new.should be_empty
74
+ end
75
+
76
+ it "should returns false if there aren't any items" do
77
+ @cart.should_not be_empty
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,22 @@
1
+ class Product
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ end
5
+
6
+ class OrderItem
7
+ include DataMapper::Resource
8
+ property :id, Serial
9
+ property :size, Enum["10x20", "20x30", "25x40"]
10
+ property :inverted, Boolean
11
+
12
+ def serialize
13
+ end
14
+
15
+ class << self
16
+ def restore(data)
17
+ end
18
+
19
+ def fixture(params = Hash.new)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
@@ -0,0 +1,13 @@
1
+ $: << File.dirname(__FILE__) + "/../lib"
2
+
3
+ require "dm-core"
4
+ require "dm-types"
5
+ require File.dirname(__FILE__) + "/factories"
6
+
7
+ DataMapper.setup(:default, "sqlite3::memory")
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.before(:each) do
11
+ DataMapper.auto_migrate!
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cart
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - "Jakub \xC5\xA0\xC5\xA5astn\xC3\xBD aka Botanicus"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ date: 2009-11-26 00:00:00 +00:00
12
+ default_executable:
13
+ dependencies: []
14
+
15
+ description: Cart is framework agnostic solution for shopping cart. There are two existing imlementations. First is *Cart::Simple* which is just basic cart which can store only ID of products without any metadata. The second is *Cart::Advanced* and it is good when you have not just product, but also some metadata as size or color of product etc.
16
+ email: knava.bestvinensis@gmail.com
17
+ executables: []
18
+
19
+ extensions: []
20
+
21
+ extra_rdoc_files: []
22
+
23
+ files:
24
+ - cart.gemspec
25
+ - lib/cart/advanced.rb
26
+ - lib/cart/config.rb
27
+ - lib/cart/logger_stub.rb
28
+ - lib/cart/simple.rb
29
+ - LICENSE
30
+ - Rakefile
31
+ - README.textile
32
+ - spec/cart/advanced_spec.rb
33
+ - spec/cart/config_spec.rb
34
+ - spec/cart/logger_stub_spec.rb
35
+ - spec/cart/simple_spec.rb
36
+ - spec/factories.rb
37
+ - spec/spec.opts
38
+ - spec/spec_helper.rb
39
+ - TODO
40
+ has_rdoc: true
41
+ homepage: http://github.com/botanicus/cart
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Cart is framework agnostic solution for shopping cart.
68
+ test_files: []
69
+