active_cart 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +5 -6
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/lib/active_cart/acts_as_cart.rb +206 -0
- data/lib/active_cart/order_total.rb +0 -10
- data/lib/active_cart.rb +1 -0
- data/test/blueprints.rb +20 -0
- data/test/fixtures/cart.rb +3 -0
- data/test/fixtures/cart_item.rb +3 -0
- data/test/fixtures/order_total.rb +3 -0
- data/test/mocks/test_order_total.rb +3 -2
- data/test/schema.rb +24 -0
- data/test/test_helper.rb +32 -2
- data/test/unit/acts_as_cart_test.rb +354 -0
- data/test/unit/cart_storage_test.rb +1 -1
- data/test/unit/cart_test.rb +5 -5
- data/test/unit/item_test.rb +1 -1
- data/test/unit/order_total_collection_test.rb +5 -5
- metadata +35 -2
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -2,11 +2,14 @@
|
|
2
2
|
|
3
3
|
ActiveCart is a Shopping Cart framework, it's not a fullyfledged cart, so you will need to do some stuff to get it to work.
|
4
4
|
|
5
|
-
The cart system has a storage engine, which means you aren't bound to a particular database
|
5
|
+
The cart system has a storage engine, which means you aren't bound to a particular database. So far, there is a an ActiveModel storage engine, called acts_as_cart, but the
|
6
|
+
gem isn't just for Rails, by writing other engines, you could target any datastore.
|
6
7
|
|
7
8
|
== Installation
|
8
9
|
gem install active_cart
|
9
10
|
|
11
|
+
== Usage
|
12
|
+
|
10
13
|
require 'rubygems'
|
11
14
|
require 'active_cart'
|
12
15
|
|
@@ -38,8 +41,4 @@ For information about the API and interfase, checkout the documentation: http://
|
|
38
41
|
>> c.total
|
39
42
|
=> 20
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
Write an ActiveMerchant acts_as_ plugin. Write an interface to MondoDB or CouchDB (or both). Write a reference rails engine that implements a working shopping cart site
|
44
|
-
|
45
|
-
Copyright (c) 2010 Myles Eftos (myles@madpilot.com.au), released under the MIT license
|
44
|
+
Copyright (c) 2010 Myles Eftos http://www.madpilot.com.au/contact, released under the MIT license
|
data/Rakefile
CHANGED
@@ -20,6 +20,8 @@ begin
|
|
20
20
|
gem.add_development_dependency 'redgreen'
|
21
21
|
gem.add_development_dependency 'shoulda'
|
22
22
|
gem.add_development_dependency 'mocha'
|
23
|
+
gem.add_development_dependency 'machinist'
|
24
|
+
gem.add_development_dependency 'faker'
|
23
25
|
end
|
24
26
|
Jeweler::GemcutterTasks.new
|
25
27
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'aasm'
|
3
|
+
#require 'aasm/persistence/active_record_persistence'
|
4
|
+
|
5
|
+
module ActiveCart
|
6
|
+
module Acts
|
7
|
+
module Cart
|
8
|
+
#:nodoc
|
9
|
+
def self.included(mod)
|
10
|
+
mod.extend(ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# acts_as_cart - Turns an ActiveRecord model in to a cart. It can take a hash of options
|
15
|
+
#
|
16
|
+
# state_column: The database column that stores the persistent state machine state. Default: state
|
17
|
+
# invoice_id_column: The column that stores the invoice id. Default: invoice_id
|
18
|
+
# cart_items: The model that represents the items for this cart. Is associated as a has_many. Default: cart_items
|
19
|
+
# order_totals: The model that represents order totals for this cart. It is associated as a has_many. Default: order_totals
|
20
|
+
#
|
21
|
+
# class Cart < ActiveModel::Base
|
22
|
+
# acts_as_cart
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# The only two columns that are required for a cart model are the state_column and invoice_id_column
|
26
|
+
#
|
27
|
+
# You can create custom acts_as_state_machine (aasm) states and events after declaring acts_as_cart
|
28
|
+
#
|
29
|
+
def acts_as_cart(options = {})
|
30
|
+
cattr_accessor :aac_config
|
31
|
+
|
32
|
+
self.aac_config = {
|
33
|
+
:state_column => :state,
|
34
|
+
:invoice_id_column => :invoice_id,
|
35
|
+
:cart_items => :cart_items,
|
36
|
+
:order_totals => :order_totals
|
37
|
+
}
|
38
|
+
|
39
|
+
self.aac_config.merge!(options)
|
40
|
+
|
41
|
+
class_eval do
|
42
|
+
#include AASM::Persistence::ActiveRecordPersistence
|
43
|
+
include ActiveCart::CartStorage
|
44
|
+
|
45
|
+
def invoice_id
|
46
|
+
read_attribute(self.aac_config[:invoice_id_column])
|
47
|
+
end
|
48
|
+
|
49
|
+
def state
|
50
|
+
read_attribute(self.aac_config[:state_column])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
aasm_column self.aac_config[:state_column]
|
55
|
+
|
56
|
+
has_many self.aac_config[:cart_items]
|
57
|
+
has_many self.aac_config[:order_totals]
|
58
|
+
|
59
|
+
extend Forwardable
|
60
|
+
def_delegators self.aac_config[:cart_items], :[], :<<, :[]=, :at, :clear, :collect, :map, :delete, :delete_at, :each, :each_index, :empty?, :eql?, :first, :include?, :index, :inject, :last, :length, :pop, :push, :shift, :size, :unshift
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module Item
|
66
|
+
#:nodoc
|
67
|
+
def self.included(mod)
|
68
|
+
mod.extend(ClassMethods)
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
# acts_as_cart_item - Sets up an ActiveModel as an cart item.
|
73
|
+
#
|
74
|
+
# Cart Items are slightly different to regular items (that may be created in a backend somewhere). When building shopping carts, one of the problems when building
|
75
|
+
# shopping carts is how to store the items associated with a particular invoice. One method is to serialize Items and storing them as a blob. This causes problem if
|
76
|
+
# the object signature changes, as you won't be able to deserialize an object at a later date. The other option is to duplicate the item into another model
|
77
|
+
# which is the option acts_as_cart takes (ActiveCart itself can do either, by using a storage engine that supports the serialization option). As such, carts based
|
78
|
+
# on act_as_cart will need two tables, most likely named items and cart_items. In theory, cart_items only needs the fields required to fulfill the requirements of
|
79
|
+
# rendering an invoice (or general display), but it's probably easier to just duplicate the fields. The cart_items will also require a cart_id and a quantity field
|
80
|
+
# acts_as_cart uses the 'original' polymorphic attribute to store a reference to the original Item object. The compound attribute gets nullified if the original Item gets
|
81
|
+
# deleted.
|
82
|
+
#
|
83
|
+
# For complex carts with multiple item types, you will probably need to use STI, as it's basically impossible to use a polymorphic relationship (If someone can
|
84
|
+
# suggest a better way, I'm all ears). That said, there is no easy way to model complex carts, so I'll leave this as an exercise for the reader.
|
85
|
+
#
|
86
|
+
# Options:
|
87
|
+
#
|
88
|
+
# cart: The cart model. Association as a belongs_to. Default: cart
|
89
|
+
# quantity_column: The column that stores the quantity of this item stored in the cart. Default: quantity
|
90
|
+
# name_column: The column that stores the name of the item. Default: name
|
91
|
+
# price_column: The column that stores the price of the item. Default: price
|
92
|
+
# foreign_key: The column that stores the reference to the cart. Default: [cart]_id (Where cart is the value of the cart option)
|
93
|
+
#
|
94
|
+
# Example
|
95
|
+
#
|
96
|
+
# class Item < ActiveModel::Base
|
97
|
+
# acts_as_item
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
def acts_as_cart_item(options = {})
|
101
|
+
cattr_accessor :aaci_config
|
102
|
+
|
103
|
+
self.aaci_config = {
|
104
|
+
:cart => :cart,
|
105
|
+
:quantity_column => :quantity,
|
106
|
+
:name_column => :name,
|
107
|
+
:price_column => :price
|
108
|
+
}
|
109
|
+
self.aaci_config.merge!(options)
|
110
|
+
self.aaci_config[:foreign_key] = (self.aaci_config[:cart].to_s + "_id").to_sym unless options[:foreign_key]
|
111
|
+
|
112
|
+
class_eval do
|
113
|
+
include ActiveCart::Item
|
114
|
+
|
115
|
+
def id
|
116
|
+
read_attribute(:id)
|
117
|
+
end
|
118
|
+
|
119
|
+
def name
|
120
|
+
read_attribute(self.aaci_config[:name_column])
|
121
|
+
end
|
122
|
+
|
123
|
+
def quantity
|
124
|
+
read_attribute(self.aaci_config[:quantity_column])
|
125
|
+
end
|
126
|
+
|
127
|
+
def quantity=(quantity)
|
128
|
+
write_attribute(self.aaci_config[:quantity_column], quantity)
|
129
|
+
end
|
130
|
+
|
131
|
+
def price
|
132
|
+
read_attribute(self.aaci_config[:price_column])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
belongs_to self.aaci_config[:cart], :foreign_key => self.aaci_config[:foreign_key]
|
137
|
+
belongs_to :original, :polymorphic => true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
module OrderTotal
|
143
|
+
#:nodoc
|
144
|
+
def self.included(mod)
|
145
|
+
mod.extend(ClassMethods)
|
146
|
+
end
|
147
|
+
|
148
|
+
module ClassMethods
|
149
|
+
# acts_as_order_total - Turns an ActiveModel into an order_total store.
|
150
|
+
#
|
151
|
+
# In the same way there is a seperation between items and cart_items, there is a difference between concrete order_total objects and this order_total store.
|
152
|
+
# This model acts as a way of archiving the order total results for a given cart, so an invoice can be retrieved later. It doesn't matter if the concrete order_total
|
153
|
+
# object is an ActiveModel class or not, as long as it matches the api
|
154
|
+
#
|
155
|
+
# Options:
|
156
|
+
#
|
157
|
+
# cart: The cart model. Association as a belongs_to. Default: cart
|
158
|
+
# name_column: The column that stores the name of the item. Default: name
|
159
|
+
# price_column: The column that stores the price of the item. Default: price
|
160
|
+
# foreign_key: The column that stores the reference to the cart. Default: [cart]_id (Where cart is the value of the cart option)
|
161
|
+
#
|
162
|
+
# Example
|
163
|
+
#
|
164
|
+
# class OrderTotal < ActiveModel::Base
|
165
|
+
# acts_as_order_total
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
def acts_as_order_total(options = {})
|
169
|
+
cattr_accessor :aaot_config
|
170
|
+
|
171
|
+
self.aaot_config = {
|
172
|
+
:cart => :cart,
|
173
|
+
:name_column => :name,
|
174
|
+
:price_column => :price
|
175
|
+
}
|
176
|
+
self.aaot_config.merge!(options)
|
177
|
+
self.aaot_config[:foreign_key] = (self.aaot_config[:cart].to_s + "_id").to_sym unless options[:foreign_key]
|
178
|
+
|
179
|
+
class_eval do
|
180
|
+
include ActiveCart::Item
|
181
|
+
|
182
|
+
def id
|
183
|
+
read_attribute(:id)
|
184
|
+
end
|
185
|
+
|
186
|
+
def name
|
187
|
+
read_attribute(self.aaot_config[:name_column])
|
188
|
+
end
|
189
|
+
|
190
|
+
def price
|
191
|
+
read_attribute(self.aaot_config[:price_column])
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
belongs_to self.aaot_config[:cart], :foreign_key => self.aaot_config[:foreign_key]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
ActiveRecord::Base.class_eval do
|
203
|
+
include ActiveCart::Acts::Cart
|
204
|
+
include ActiveCart::Acts::Item
|
205
|
+
include ActiveCart::Acts::OrderTotal
|
206
|
+
end
|
@@ -44,15 +44,5 @@ module ActiveCart
|
|
44
44
|
def name
|
45
45
|
raise NotImplementedError
|
46
46
|
end
|
47
|
-
|
48
|
-
# Returns a short description of the order total. Can be used for display (Such as on an invoices etc)
|
49
|
-
#
|
50
|
-
# This must be overriden in the mixee class, otherwise it will throw a NotImplementedError
|
51
|
-
#
|
52
|
-
# @order.description # => "This example order class doesn't do much"
|
53
|
-
#
|
54
|
-
def description
|
55
|
-
raise NotImplementedError
|
56
|
-
end
|
57
47
|
end
|
58
48
|
end
|
data/lib/active_cart.rb
CHANGED
@@ -9,6 +9,7 @@ require 'cart_storage'
|
|
9
9
|
require 'order_total'
|
10
10
|
require 'order_total_collection'
|
11
11
|
require 'cart'
|
12
|
+
require 'acts_as_cart' if (Kernel.const_defined?('RAILS_ENV') || Kernel.const_defined?('Rails'))
|
12
13
|
|
13
14
|
require 'storage_engines/memory'
|
14
15
|
require 'items/memory_item'
|
data/test/blueprints.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'machinist/active_record'
|
2
|
+
require 'sham'
|
3
|
+
require 'faker'
|
4
|
+
|
5
|
+
Cart.blueprint do
|
6
|
+
state { 'shopping' }
|
7
|
+
end
|
8
|
+
|
9
|
+
CartItem.blueprint do
|
10
|
+
cart { Cart.make }
|
11
|
+
name { Faker::Lorem.words(2).join(' ') }
|
12
|
+
quantity { rand(10).to_i }
|
13
|
+
price { (rand(9999) + 1).to_i / 100 }
|
14
|
+
end
|
15
|
+
|
16
|
+
OrderTotal.blueprint do
|
17
|
+
cart { Cart.make }
|
18
|
+
name { Faker::Lorem.words(2).join(' ') }
|
19
|
+
total { (rand(9999) + 1).to_i / 100 }
|
20
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
ActiveRecord::Schema.define :version => 0 do
|
2
|
+
create_table :carts, :force => true do |t|
|
3
|
+
t.string :invoice_id
|
4
|
+
t.string :state
|
5
|
+
t.string :dummy # Not needed in real carts - used sa a dummy field for testing
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :cart_items, :force => true do |t|
|
9
|
+
t.integer :cart_id
|
10
|
+
t.string :name
|
11
|
+
t.integer :quantity
|
12
|
+
t.float :price
|
13
|
+
t.integer :original_id
|
14
|
+
t.string :original_type
|
15
|
+
t.string :dummy # Not needed in real carts - used sa a dummy field for testing
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :order_totals, :force => true do |t|
|
19
|
+
t.integer :cart_id
|
20
|
+
t.string :name
|
21
|
+
t.float :total
|
22
|
+
t.string :dummy # Not needed in real carts - used sa a dummy field for testing
|
23
|
+
end
|
24
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
1
|
$:.unshift(File.join(File.dirname(__FILE__)))
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'fixtures'))
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
4
|
|
4
5
|
require 'rubygems'
|
5
6
|
require 'redgreen'
|
@@ -12,5 +13,34 @@ require 'mocks/test_cart_storage'
|
|
12
13
|
require 'mocks/test_item'
|
13
14
|
require 'mocks/test_order_total'
|
14
15
|
|
15
|
-
|
16
|
+
require 'active_record'
|
17
|
+
require 'active_record/fixtures'
|
18
|
+
|
19
|
+
# Mock out the required environment variables.
|
20
|
+
RAILS_ENV = 'test'
|
21
|
+
RAILS_ROOT = Dir.pwd
|
22
|
+
|
23
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/log/test.log')
|
24
|
+
ActiveRecord::Base.configurations = YAML::load <<-YAML
|
25
|
+
sqlite3:
|
26
|
+
:adapter: sqlite3
|
27
|
+
:database: ':memory:'
|
28
|
+
YAML
|
29
|
+
ActiveRecord::Base.establish_connection('sqlite3')
|
30
|
+
|
31
|
+
require 'active_cart/acts_as_cart'
|
32
|
+
|
33
|
+
# Load Schema
|
34
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
35
|
+
|
36
|
+
require 'fixtures/cart'
|
37
|
+
require 'fixtures/cart_item'
|
38
|
+
require 'fixtures/order_total'
|
39
|
+
require 'blueprints'
|
40
|
+
|
41
|
+
class ActiveSupport::TestCase
|
42
|
+
include ActiveRecord::TestFixtures
|
43
|
+
self.fixture_path = File.dirname(__FILE__) + '/fixtures/'
|
44
|
+
self.use_transactional_fixtures = true
|
45
|
+
self.use_instantiated_fixtures = false
|
16
46
|
end
|
@@ -0,0 +1,354 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActsAsCartTest < ActiveSupport::TestCase
|
4
|
+
context '' do
|
5
|
+
setup do
|
6
|
+
Cart.acts_as_cart
|
7
|
+
@cart = Cart.make
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'acts_as_cart' do
|
11
|
+
context 'configuration' do
|
12
|
+
should 'set defaults' do
|
13
|
+
Cart.expects(:aasm_column).with(:state)
|
14
|
+
Cart.expects(:has_many).with(:cart_items)
|
15
|
+
Cart.expects(:has_many).with(:order_totals)
|
16
|
+
|
17
|
+
Cart.acts_as_cart
|
18
|
+
|
19
|
+
assert_equal :state, Cart.aac_config[:state_column]
|
20
|
+
assert_equal :invoice_id , Cart.aac_config[:invoice_id_column]
|
21
|
+
assert_equal :cart_items , Cart.aac_config[:cart_items]
|
22
|
+
assert_equal :order_totals , Cart.aac_config[:order_totals]
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'override' do
|
27
|
+
should 'change state' do
|
28
|
+
Cart.expects(:aasm_column).with(:dummy)
|
29
|
+
Cart.expects(:has_many).with(:cart_items)
|
30
|
+
Cart.expects(:has_many).with(:order_totals)
|
31
|
+
|
32
|
+
Cart.acts_as_cart :state_column => :dummy
|
33
|
+
|
34
|
+
assert_equal :dummy, Cart.aac_config[:state_column]
|
35
|
+
assert_equal :invoice_id , Cart.aac_config[:invoice_id_column]
|
36
|
+
assert_equal :cart_items , Cart.aac_config[:cart_items]
|
37
|
+
assert_equal :order_totals , Cart.aac_config[:order_totals]
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'change state getter' do
|
41
|
+
Cart.acts_as_cart :state_column => :dummy
|
42
|
+
@cart = Cart.make
|
43
|
+
@cart.expects(:read_attribute).with(:dummy).returns(:shopping)
|
44
|
+
assert :shopping, @cart.state
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'change invoice_id getter' do
|
48
|
+
Cart.acts_as_cart :invoice_id_column => :dummy
|
49
|
+
@cart = Cart.make
|
50
|
+
@cart.expects(:read_attribute).with(:dummy)
|
51
|
+
assert :shopping, @cart.invoice_id
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'change cart_items' do
|
55
|
+
Cart.expects(:aasm_column).with(:state)
|
56
|
+
Cart.expects(:has_many).with(:test)
|
57
|
+
Cart.expects(:has_many).with(:order_totals)
|
58
|
+
|
59
|
+
Cart.acts_as_cart :cart_items => :test
|
60
|
+
|
61
|
+
assert_equal :state, Cart.aac_config[:state_column]
|
62
|
+
assert_equal :invoice_id , Cart.aac_config[:invoice_id_column]
|
63
|
+
assert_equal :test , Cart.aac_config[:cart_items]
|
64
|
+
assert_equal :order_totals , Cart.aac_config[:order_totals]
|
65
|
+
end
|
66
|
+
|
67
|
+
should 'change order_totals' do
|
68
|
+
Cart.expects(:aasm_column).with(:state)
|
69
|
+
Cart.expects(:has_many).with(:cart_items)
|
70
|
+
Cart.expects(:has_many).with(:test)
|
71
|
+
|
72
|
+
Cart.acts_as_cart :order_totals => :test
|
73
|
+
|
74
|
+
assert_equal :state, Cart.aac_config[:state_column]
|
75
|
+
assert_equal :invoice_id , Cart.aac_config[:invoice_id_column]
|
76
|
+
assert_equal :cart_items , Cart.aac_config[:cart_items]
|
77
|
+
assert_equal :test , Cart.aac_config[:order_totals]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'state' do
|
83
|
+
should 'be persistent' do
|
84
|
+
@cart.checkout!
|
85
|
+
@cart.save!
|
86
|
+
@cart = Cart.find(@cart.id)
|
87
|
+
assert_equal 'checkout', @cart.state
|
88
|
+
assert_nothing_raised do
|
89
|
+
@cart.check_payment!
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'cart storage' do
|
95
|
+
should 'acts as a array' do
|
96
|
+
item = CartItem.make_unsaved(:cart => nil, :quantity => 1)
|
97
|
+
assert_nothing_raised do
|
98
|
+
@cart << item
|
99
|
+
end
|
100
|
+
|
101
|
+
@cart.save!
|
102
|
+
assert_equal 1, @cart.size
|
103
|
+
assert_equal 1, @cart.quantity
|
104
|
+
assert_equal item, @cart[0]
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'delegate to item' do
|
108
|
+
setup do
|
109
|
+
@cart << CartItem.make
|
110
|
+
@cart.save!
|
111
|
+
end
|
112
|
+
|
113
|
+
should 'delegate []' do
|
114
|
+
@cart.cart_items.expects(:[]).with(0)
|
115
|
+
@cart[0]
|
116
|
+
end
|
117
|
+
|
118
|
+
should 'delegate <<' do
|
119
|
+
test = CartItem.make
|
120
|
+
@cart.cart_items.expects(:<<).with(test)
|
121
|
+
@cart << test
|
122
|
+
end
|
123
|
+
|
124
|
+
should 'delegate []=' do
|
125
|
+
test = CartItem.make
|
126
|
+
@cart.cart_items.expects(:[]=).with(0, test)
|
127
|
+
@cart[0] = test
|
128
|
+
end
|
129
|
+
|
130
|
+
should 'delegate :at' do
|
131
|
+
@cart.cart_items.expects(:at).with(1)
|
132
|
+
@cart.at(1)
|
133
|
+
end
|
134
|
+
|
135
|
+
should 'delegate :clear' do
|
136
|
+
@cart.cart_items.expects(:clear)
|
137
|
+
@cart.clear
|
138
|
+
end
|
139
|
+
|
140
|
+
should 'delegate :collect' do
|
141
|
+
@cart.cart_items.expects(:collect)
|
142
|
+
@cart.collect
|
143
|
+
end
|
144
|
+
|
145
|
+
should 'delegate :map' do
|
146
|
+
@cart.cart_items.expects(:map)
|
147
|
+
@cart.map
|
148
|
+
end
|
149
|
+
|
150
|
+
should 'delegate :delete' do
|
151
|
+
test = CartItem.make
|
152
|
+
@cart.cart_items.expects(:delete).with(test)
|
153
|
+
@cart.delete(test)
|
154
|
+
end
|
155
|
+
|
156
|
+
should 'delegate :delete_at' do
|
157
|
+
@cart.cart_items.expects(:delete_at).with(3)
|
158
|
+
@cart.delete_at(3)
|
159
|
+
end
|
160
|
+
|
161
|
+
should 'delegate :each' do
|
162
|
+
@cart.cart_items.expects(:each)
|
163
|
+
@cart.each
|
164
|
+
end
|
165
|
+
|
166
|
+
should 'delegate :each_index' do
|
167
|
+
@cart.cart_items.expects(:each_index)
|
168
|
+
@cart.each_index
|
169
|
+
end
|
170
|
+
|
171
|
+
should 'delegate :empty' do
|
172
|
+
@cart.cart_items.expects(:empty?)
|
173
|
+
@cart.empty?
|
174
|
+
end
|
175
|
+
|
176
|
+
should 'delegate :eql?' do
|
177
|
+
@cart.cart_items.expects(:eql?)
|
178
|
+
@cart.eql?
|
179
|
+
end
|
180
|
+
|
181
|
+
should 'delegate :first' do
|
182
|
+
@cart.cart_items.expects(:first)
|
183
|
+
@cart.first
|
184
|
+
end
|
185
|
+
|
186
|
+
should 'delegate :include?' do
|
187
|
+
item = CartItem.make
|
188
|
+
@cart.cart_items.expects(:include?).with(CartItem.make)
|
189
|
+
@cart.include?(item)
|
190
|
+
end
|
191
|
+
|
192
|
+
should 'delegate :index' do
|
193
|
+
@cart.cart_items.expects(:index)
|
194
|
+
@cart.index
|
195
|
+
end
|
196
|
+
|
197
|
+
should 'delegate :inject' do
|
198
|
+
@cart.cart_items.expects(:inject)
|
199
|
+
@cart.inject
|
200
|
+
end
|
201
|
+
|
202
|
+
should 'delegate :last' do
|
203
|
+
@cart.cart_items.expects(:last)
|
204
|
+
@cart.last
|
205
|
+
end
|
206
|
+
|
207
|
+
should 'delegate :length' do
|
208
|
+
@cart.cart_items.expects(:length)
|
209
|
+
@cart.length
|
210
|
+
end
|
211
|
+
|
212
|
+
should 'delegate :pop' do
|
213
|
+
@cart.cart_items.expects(:pop)
|
214
|
+
@cart.pop
|
215
|
+
end
|
216
|
+
|
217
|
+
should 'delegate :push' do
|
218
|
+
item = CartItem.make
|
219
|
+
@cart.cart_items.expects(:push).with(item)
|
220
|
+
@cart.push(item)
|
221
|
+
end
|
222
|
+
|
223
|
+
should 'delegate :shift' do
|
224
|
+
@cart.cart_items.expects(:shift)
|
225
|
+
@cart.shift
|
226
|
+
end
|
227
|
+
|
228
|
+
should 'delegate :size' do
|
229
|
+
@cart.cart_items.expects(:size)
|
230
|
+
@cart.size
|
231
|
+
end
|
232
|
+
|
233
|
+
should 'delegate :unshift' do
|
234
|
+
@cart.cart_items.expects(:unshift)
|
235
|
+
@cart.unshift
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'acts_as_cart_item' do
|
242
|
+
context 'configuration' do
|
243
|
+
should 'set defaults' do
|
244
|
+
CartItem.acts_as_cart_item
|
245
|
+
|
246
|
+
assert_equal :cart, CartItem.aaci_config[:cart]
|
247
|
+
assert_equal :quantity , CartItem.aaci_config[:quantity_column]
|
248
|
+
assert_equal :name , CartItem.aaci_config[:name_column]
|
249
|
+
assert_equal :price , CartItem.aaci_config[:price_column]
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'override' do
|
253
|
+
should 'change quantity column' do
|
254
|
+
CartItem.acts_as_cart_item :quantity_column => :dummy
|
255
|
+
@cart = CartItem.make
|
256
|
+
@cart.expects(:read_attribute).with(:dummy)
|
257
|
+
@cart.quantity
|
258
|
+
end
|
259
|
+
|
260
|
+
should 'change name column' do
|
261
|
+
CartItem.acts_as_cart_item :name_column => :dummy
|
262
|
+
@cart = CartItem.make
|
263
|
+
@cart.expects(:read_attribute).with(:dummy)
|
264
|
+
@cart.name
|
265
|
+
end
|
266
|
+
|
267
|
+
should 'change price column' do
|
268
|
+
CartItem.acts_as_cart_item :price_column => :dummy
|
269
|
+
@cart = CartItem.make
|
270
|
+
@cart.expects(:read_attribute).with(:dummy)
|
271
|
+
@cart.price
|
272
|
+
end
|
273
|
+
|
274
|
+
should 'change cart_items' do
|
275
|
+
CartItem.acts_as_cart_item :cart => :test
|
276
|
+
|
277
|
+
assert_equal :test, CartItem.aaci_config[:cart]
|
278
|
+
assert_equal :quantity , CartItem.aaci_config[:quantity_column]
|
279
|
+
assert_equal :name , CartItem.aaci_config[:name_column]
|
280
|
+
assert_equal :price , CartItem.aaci_config[:price_column]
|
281
|
+
end
|
282
|
+
|
283
|
+
should 'change the foreign_key' do
|
284
|
+
CartItem.acts_as_cart_item :foreign_key => :test_id
|
285
|
+
|
286
|
+
assert_equal :cart, CartItem.aaci_config[:cart]
|
287
|
+
assert_equal :name , CartItem.aaci_config[:name_column]
|
288
|
+
assert_equal :price , CartItem.aaci_config[:price_column]
|
289
|
+
assert_equal :test_id, CartItem.aaci_config[:foreign_key]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
context 'acts_as_order_total' do
|
296
|
+
context 'configuration' do
|
297
|
+
should 'set defaults' do
|
298
|
+
OrderTotal.acts_as_order_total
|
299
|
+
|
300
|
+
assert_equal :cart, OrderTotal.aaot_config[:cart]
|
301
|
+
assert_equal :name , OrderTotal.aaot_config[:name_column]
|
302
|
+
assert_equal :price , OrderTotal.aaot_config[:price_column]
|
303
|
+
assert_equal :cart_id, OrderTotal.aaot_config[:foreign_key]
|
304
|
+
end
|
305
|
+
|
306
|
+
context 'override' do
|
307
|
+
should 'change name column' do
|
308
|
+
OrderTotal.acts_as_order_total :name_column => :dummy
|
309
|
+
@order_total = OrderTotal.make
|
310
|
+
@order_total.expects(:read_attribute).with(:dummy)
|
311
|
+
@order_total.name
|
312
|
+
end
|
313
|
+
|
314
|
+
should 'change price column' do
|
315
|
+
OrderTotal.acts_as_order_total :price_column => :dummy
|
316
|
+
@order_total = OrderTotal.make
|
317
|
+
@order_total.expects(:read_attribute).with(:dummy)
|
318
|
+
@order_total.price
|
319
|
+
end
|
320
|
+
|
321
|
+
should 'change the foreign_key' do
|
322
|
+
OrderTotal.acts_as_order_total :foreign_key => :test_id
|
323
|
+
|
324
|
+
assert_equal :cart, OrderTotal.aaot_config[:cart]
|
325
|
+
assert_equal :name , OrderTotal.aaot_config[:name_column]
|
326
|
+
assert_equal :price , OrderTotal.aaot_config[:price_column]
|
327
|
+
assert_equal :test_id, OrderTotal.aaot_config[:foreign_key]
|
328
|
+
end
|
329
|
+
|
330
|
+
should 'change cart_items' do
|
331
|
+
OrderTotal.acts_as_order_total :cart => :test
|
332
|
+
|
333
|
+
assert_equal :test, OrderTotal.aaot_config[:cart]
|
334
|
+
assert_equal :name , OrderTotal.aaot_config[:name_column]
|
335
|
+
assert_equal :price , OrderTotal.aaot_config[:price_column]
|
336
|
+
assert_equal :test_id, OrderTotal.aaot_config[:foreign_key]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
context 'state' do
|
342
|
+
should 'be persistent' do
|
343
|
+
@cart.checkout!
|
344
|
+
@cart.save!
|
345
|
+
@cart = Cart.find(@cart.id)
|
346
|
+
assert_equal 'checkout', @cart.state
|
347
|
+
assert_nothing_raised do
|
348
|
+
@cart.check_payment!
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
data/test/unit/cart_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class CartTest <
|
3
|
+
class CartTest < ActiveSupport::TestCase
|
4
4
|
context '' do
|
5
5
|
context 'after setup' do
|
6
6
|
setup do
|
@@ -219,8 +219,8 @@ class CartTest < Test::Unit::TestCase
|
|
219
219
|
|
220
220
|
context 'setup' do
|
221
221
|
should 'take a block to add order_totals' do
|
222
|
-
@total_1 = TestOrderTotal.new(10, true)
|
223
|
-
@total_2 = TestOrderTotal.new(20, true)
|
222
|
+
@total_1 = TestOrderTotal.new('Total 1', 10, true)
|
223
|
+
@total_2 = TestOrderTotal.new('Total 2', 20, true)
|
224
224
|
|
225
225
|
@cart_storage_engine = TestCartStorage.new
|
226
226
|
@cart = ActiveCart::Cart.new(@cart_storage_engine) do |o|
|
@@ -239,8 +239,8 @@ class CartTest < Test::Unit::TestCase
|
|
239
239
|
@item_2.price = 20
|
240
240
|
@item_3 = TestItem.new(3)
|
241
241
|
@item_3.price = 30
|
242
|
-
@total_1 = TestOrderTotal.new(10, true)
|
243
|
-
@total_2 = TestOrderTotal.new(20, true)
|
242
|
+
@total_1 = TestOrderTotal.new('Total 1', 10, true)
|
243
|
+
@total_2 = TestOrderTotal.new('Total 2', 20, true)
|
244
244
|
|
245
245
|
@cart.order_total_calculators += [ @total_1, @total_2 ]
|
246
246
|
@cart.add_to_cart(@item_1)
|
data/test/unit/item_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class OrderTotalCollectionTest <
|
3
|
+
class OrderTotalCollectionTest < ActiveSupport::TestCase
|
4
4
|
context '' do
|
5
5
|
setup do
|
6
6
|
@cart_storage_engine = TestCartStorage.new
|
@@ -72,10 +72,10 @@ class OrderTotalCollectionTest < Test::Unit::TestCase
|
|
72
72
|
|
73
73
|
context 'total' do
|
74
74
|
setup do
|
75
|
-
@total_1 = TestOrderTotal.new(10, true)
|
76
|
-
@total_2 = TestOrderTotal.new(5, false)
|
77
|
-
@total_3 = TestOrderTotal.new(2, true)
|
78
|
-
@total_4 = TestOrderTotal.new(14, true)
|
75
|
+
@total_1 = TestOrderTotal.new('Total 1', 10, true)
|
76
|
+
@total_2 = TestOrderTotal.new('Total 2', 5, false)
|
77
|
+
@total_3 = TestOrderTotal.new('Total 3', 2, true)
|
78
|
+
@total_4 = TestOrderTotal.new('Total 4', 14, true)
|
79
79
|
end
|
80
80
|
|
81
81
|
should 'call price on each order_total item that are active' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_cart
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Myles Eftos
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-02-
|
12
|
+
date: 2010-02-28 00:00:00 +08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,26 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: "0"
|
54
54
|
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: machinist
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: faker
|
67
|
+
type: :development
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
55
75
|
description: You can use active_cart as the basis of a shopping cart system. It's not a shopping cart application - it's a shopping cart framework.
|
56
76
|
email: myles@madpilot.com.au
|
57
77
|
executables: []
|
@@ -67,6 +87,7 @@ files:
|
|
67
87
|
- VERSION
|
68
88
|
- install.rb
|
69
89
|
- lib/active_cart.rb
|
90
|
+
- lib/active_cart/acts_as_cart.rb
|
70
91
|
- lib/active_cart/cart.rb
|
71
92
|
- lib/active_cart/cart_storage.rb
|
72
93
|
- lib/active_cart/item.rb
|
@@ -74,11 +95,17 @@ files:
|
|
74
95
|
- lib/active_cart/order_total.rb
|
75
96
|
- lib/active_cart/order_total_collection.rb
|
76
97
|
- lib/active_cart/storage_engines/memory.rb
|
98
|
+
- test/blueprints.rb
|
99
|
+
- test/fixtures/cart.rb
|
100
|
+
- test/fixtures/cart_item.rb
|
101
|
+
- test/fixtures/order_total.rb
|
77
102
|
- test/mocks/test_cart_storage.rb
|
78
103
|
- test/mocks/test_item.rb
|
79
104
|
- test/mocks/test_order_total.rb
|
80
105
|
- test/performance/browsing_test.rb
|
106
|
+
- test/schema.rb
|
81
107
|
- test/test_helper.rb
|
108
|
+
- test/unit/acts_as_cart_test.rb
|
82
109
|
- test/unit/cart_storage_test.rb
|
83
110
|
- test/unit/cart_test.rb
|
84
111
|
- test/unit/item_test.rb
|
@@ -116,9 +143,15 @@ test_files:
|
|
116
143
|
- test/unit/order_total_collection_test.rb
|
117
144
|
- test/unit/cart_storage_test.rb
|
118
145
|
- test/unit/cart_test.rb
|
146
|
+
- test/unit/acts_as_cart_test.rb
|
119
147
|
- test/unit/item_test.rb
|
120
148
|
- test/mocks/test_cart_storage.rb
|
121
149
|
- test/mocks/test_order_total.rb
|
122
150
|
- test/mocks/test_item.rb
|
151
|
+
- test/schema.rb
|
152
|
+
- test/fixtures/cart_item.rb
|
153
|
+
- test/fixtures/order_total.rb
|
154
|
+
- test/fixtures/cart.rb
|
155
|
+
- test/blueprints.rb
|
123
156
|
- test/test_helper.rb
|
124
157
|
- test/performance/browsing_test.rb
|