active_cart 0.0.4 → 0.0.5
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/.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
|