carter 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NThkMmFjYWZkYzc4ZjBjNWU1YjYzOThlMzI1MmE2ZjgyZDM5ZmVmZg==
5
+ data.tar.gz: !binary |-
6
+ YzAxYjU4MjViYWUyMmUwNjcxNWRhMGIwZDBkZDRmMzA2NWY3MjMzYQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZWE2YzliNzNkNWJlNmZmYzI4YjkyYzRjNzZlMjEyZDZiNDNlOTk5OWVjYWNi
10
+ MWY2NzdkYTYwMjBkZTMwNGE4NjBhZWVhOWI3ZjQ4ZWVhZWY5MjBmNWEyNDAz
11
+ NDk1Y2E2ZjJhN2EwODY5MmUzNWFhYWRjYjY1MGM5ODYxYjVjYmM=
12
+ data.tar.gz: !binary |-
13
+ NjA5NTMyNTEwZDBjOTVmMzk5ODQ4NDA1OWMzODI0OWNiOWVjYmI4ZTIzN2Ni
14
+ ODQ3Zjk0NDgzNTI1ZTQyYmY1NzUwOTRkNzc2ZTBiYTM5MGRhMGNjYmRjMjUz
15
+ YzNhMmUyNzYwYzNmOWExMjhjZGMyMjBiNDFhODVjNDQwMzdhM2Y=
data/README.md CHANGED
@@ -2,13 +2,36 @@
2
2
 
3
3
  A simple shopping cart for ruby.
4
4
 
5
- [Carter]("http://en.wikipedia.org/wiki/Carter_(name)/") - "transports goods by cart"
5
+ [Carter]("http://en.wikipedia.org/wiki/Carter_\(name\)/") - "transports goods by cart"
6
6
 
7
7
  * Anything can be added to the cart using
8
8
  `acts_as_cartable`
9
9
  * Any page can load a cart from session.
10
10
  * Can be included without a need for a complete e-commerce solution.
11
11
 
12
+ ## Install
13
+
14
+ Add to the Gemfile
15
+
16
+ ```ruby
17
+ gem 'carter'
18
+ ```
19
+
20
+ Copy migration file
21
+
22
+ ```console
23
+ rails generate carter:migration
24
+ ```
25
+
26
+ Copy carter files to your project to extend (optional)
27
+ ```console
28
+ rails generate carter:install
29
+ ```
30
+
31
+ ## Support
32
+
33
+ This gem supports Rails 4.0, if you need Rails 2.3 and Rails 3+ support, please install carter 0.7.
34
+
12
35
  ## Contributing to carter
13
36
 
14
37
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
@@ -1,15 +1,14 @@
1
1
  class CartItemsController < ApplicationController
2
- load_cart_and_cartable
2
+
3
3
  before_filter :find_cart_item, :only => [:update, :destroy]
4
4
 
5
- # RESTful equiv of add
6
5
  def create
7
6
  persist_cart if @cart.new_record?
8
7
  @cart.add_item(find_cartable)
9
8
  end
10
9
 
11
10
  def update
12
- if @cart_item.update_attributes(params[:cart_item])
11
+ if @cart_item.update_attributes(cart_item_params)
13
12
  flash[:notice] = t(:cart_updated)
14
13
  redirect_to cart_path(cart)
15
14
  else
@@ -28,7 +27,14 @@ class CartItemsController < ApplicationController
28
27
 
29
28
  protected
30
29
 
31
- def find_cart_item
32
- @cart_item = @cart.cart_items.find(params[:id])
33
- end
30
+ def find_cart_item
31
+ @cart_item = @cart.cart_items.find(params[:id])
32
+ end
33
+
34
+ private
35
+
36
+ def cart_item_params
37
+ params.require(:cart_item).permit!
38
+ end
39
+
34
40
  end
@@ -1,5 +1,4 @@
1
1
  class CartsController < ApplicationController
2
- load_cart_and_cartable
3
2
 
4
3
  def show
5
4
 
@@ -1,4 +1,4 @@
1
1
  Rails.application.routes.draw do
2
- resources :carts
3
- resources :cart_items
2
+ resources :carts, only: [:show, :destroy]
3
+ resources :cart_items, only: [:create, :update, :destroy]
4
4
  end
@@ -5,6 +5,10 @@ module Carter
5
5
  base.send :include, InstanceMethods
6
6
  base.send :include, Carter::StateMachine::Cart
7
7
  base.extend ClassMethods
8
+
9
+ base.class_eval do
10
+ scope :expired, lambda { |expiry_date = Time.now| where("updated_at < ?", expiry_date) }
11
+ end
8
12
  end
9
13
 
10
14
  module InstanceMethods
@@ -50,9 +54,11 @@ module Carter
50
54
  def remove_carts(days=7, state=:active)
51
55
  expiry_date = (Time.now.midnight - days.days.to_i)
52
56
  count = 0
53
- self.with_state(state).find_in_batches(:conditions => ["updated_at < ?", expiry_date]) do |batch|
57
+
58
+ self.with_state(state).expired(expiry_date).find_in_batches do |batch|
54
59
  count += self.delete(batch.map &:id)
55
60
  end
61
+
56
62
  count
57
63
  end
58
64
 
@@ -1,10 +1,6 @@
1
1
  if defined?(Rails)
2
2
  ActiveRecord::Base.extend Carter::ActiveRecord::Cartable if defined?(ActiveRecord)
3
- if Rails::VERSION::MAJOR == 3
4
- require 'carter/engine'
5
- else
6
- require 'carter/routing'
7
- ActionController::Routing::RouteSet::Mapper.send :include, Carter::Routing::MapperExtensions
8
- end
3
+
4
+ require 'carter/engine'
9
5
  end
10
6
 
@@ -0,0 +1,27 @@
1
+ require 'rails/generators/base'
2
+
3
+ module Carter
4
+ module Generators
5
+ class InstallGenerator < Rails::Generators::Base
6
+
7
+ source_root File.expand_path('../../../../', __FILE__)
8
+
9
+ def copy_controller_file
10
+ copy_file "app/controllers/cart_items_controller.rb", "app/controllers/cart_items_controller.rb"
11
+ copy_file "app/controllers/carts_controller.rb", "app/controllers/carts_controller.rb"
12
+ end
13
+
14
+ def copy_view_file
15
+ copy_file "app/views/carts/show.html.erb", "app/views/carts/show.html.erb"
16
+ end
17
+
18
+ protected
19
+
20
+ def add_options!(opt)
21
+ opt.separator ''
22
+ opt.separator 'Options:'
23
+ opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ require 'rails/generators'
2
+ require "rails/generators/active_record"
3
+
4
+ module Carter
5
+ module Generators
6
+ class MigrationGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ desc "Generates a migration for cart and cart_item models"
10
+
11
+ source_root File.expand_path("../templates", __FILE__)
12
+
13
+ def self.next_migration_number(path)
14
+ ::ActiveRecord::Generators::Base.next_migration_number(path)
15
+ end
16
+
17
+ def copy_migration
18
+ migration_template "migration.rb", "db/migrate/create_carter.rb"
19
+ end
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,165 +1,169 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: carter
3
- version: !ruby/object:Gem::Version
4
- hash: 7
5
- prerelease:
6
- segments:
7
- - 0
8
- - 7
9
- - 2
10
- version: 0.7.2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Louis Gillies
14
8
  autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
-
18
- date: 2012-02-29 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
- none: false
23
- requirements:
24
- - - ~>
25
- - !ruby/object:Gem::Version
26
- hash: 3
27
- segments:
28
- - 2
29
- - 3
30
- - 0
31
- version: 2.3.0
32
- requirement: *id001
33
- prerelease: false
34
- name: rspec
35
- type: :development
36
- - !ruby/object:Gem::Dependency
37
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
11
+ date: 2014-01-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: yard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
40
17
  - - ~>
41
- - !ruby/object:Gem::Version
42
- hash: 7
43
- segments:
44
- - 0
45
- - 6
46
- - 0
18
+ - !ruby/object:Gem::Version
47
19
  version: 0.6.0
48
- requirement: *id002
49
- prerelease: false
50
- name: yard
51
20
  type: :development
52
- - !ruby/object:Gem::Dependency
53
- version_requirements: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 0
61
- version: "0"
62
- requirement: *id003
63
21
  prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.0
27
+ - !ruby/object:Gem::Dependency
64
28
  name: cucumber
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
65
34
  type: :development
66
- - !ruby/object:Gem::Dependency
67
- version_requirements: &id004 !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
70
- - - ~>
71
- - !ruby/object:Gem::Version
72
- hash: 23
73
- segments:
74
- - 1
75
- - 0
76
- - 0
77
- version: 1.0.0
78
- requirement: *id004
79
35
  prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
80
42
  name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
81
48
  type: :development
82
- - !ruby/object:Gem::Dependency
83
- version_requirements: &id005 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
86
- - - ~>
87
- - !ruby/object:Gem::Version
88
- hash: 7
89
- segments:
90
- - 1
91
- - 5
92
- - 2
93
- version: 1.5.2
94
- requirement: *id005
95
49
  prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
96
56
  name: jeweler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
97
62
  type: :development
98
- - !ruby/object:Gem::Dependency
99
- version_requirements: &id006 !ruby/object:Gem::Requirement
100
- none: false
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 3
105
- segments:
106
- - 0
107
- version: "0"
108
- requirement: *id006
109
63
  prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.0
69
+ - !ruby/object:Gem::Dependency
110
70
  name: rcov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
111
76
  type: :development
112
- - !ruby/object:Gem::Dependency
113
- version_requirements: &id007 !ruby/object:Gem::Requirement
114
- none: false
115
- requirements:
116
- - - "="
117
- - !ruby/object:Gem::Version
118
- hash: 19
119
- segments:
120
- - 1
121
- - 0
122
- - 2
123
- version: 1.0.2
124
- requirement: *id007
125
77
  prerelease: false
126
- name: state_machine
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: money
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 3.1.5
127
90
  type: :development
128
- - !ruby/object:Gem::Dependency
129
- version_requirements: &id008 !ruby/object:Gem::Requirement
130
- none: false
131
- requirements:
132
- - - "="
133
- - !ruby/object:Gem::Version
134
- hash: 9
135
- segments:
136
- - 3
137
- - 1
138
- - 5
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
139
96
  version: 3.1.5
140
- requirement: *id008
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 1.3.8
104
+ type: :development
141
105
  prerelease: false
142
- name: money
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 1.3.8
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 2.13.0
143
118
  type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 2.13.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: 4.0.0
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: 4.0.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: state_machine
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: 1.2.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: 1.2.0
144
153
  description: A really simple shopping cart implementation for rails.
145
154
  email: louisgillies@ygmail.com
146
155
  executables: []
147
-
148
156
  extensions: []
149
-
150
- extra_rdoc_files:
157
+ extra_rdoc_files:
151
158
  - LICENSE.txt
152
159
  - README.md
153
- files:
160
+ files:
154
161
  - app/controllers/cart_items_controller.rb
155
162
  - app/controllers/carts_controller.rb
156
163
  - app/models/cart.rb
157
164
  - app/models/cart_item.rb
158
165
  - app/views/carts/show.html.erb
159
166
  - config/routes.rb
160
- - generators/carter_generator.rb
161
- - generators/carter_install_generator.rb
162
- - generators/templates/migration.rb
163
167
  - lib/carter.rb
164
168
  - lib/carter/active_record/extensions.rb
165
169
  - lib/carter/cart.rb
@@ -172,60 +176,35 @@ files:
172
176
  - lib/carter/errors/setup_error.rb
173
177
  - lib/carter/initializer.rb
174
178
  - lib/carter/rails/init.rb
175
- - lib/carter/routing.rb
176
179
  - lib/carter/state_machine.rb
180
+ - lib/generators/carter/install_generator.rb
181
+ - lib/generators/carter/migration_generator.rb
182
+ - lib/generators/carter/templates/migration.rb
177
183
  - lib/tasks/carter.rake
178
184
  - LICENSE.txt
179
185
  - README.md
180
- - spec/active_record/cart_item_spec.rb
181
- - spec/active_record/cart_spec.rb
182
- - spec/active_record/cartable_spec.rb
183
- - spec/app/controllers/cart_items_controller_spec.rb
184
- - spec/carter_spec.rb
185
- - spec/spec_helper.rb
186
- - spec/state_machine_spec.rb
187
- - spec/support/active_record_helper.rb
188
- - spec/support/factories.rb
189
186
  homepage: http://github.com/gillies-dunlop/carter
190
- licenses:
187
+ licenses:
191
188
  - MIT
189
+ metadata: {}
192
190
  post_install_message:
193
191
  rdoc_options: []
194
-
195
- require_paths:
192
+ require_paths:
196
193
  - lib
197
- required_ruby_version: !ruby/object:Gem::Requirement
198
- none: false
199
- requirements:
200
- - - ">="
201
- - !ruby/object:Gem::Version
202
- hash: 3
203
- segments:
204
- - 0
205
- version: "0"
206
- required_rubygems_version: !ruby/object:Gem::Requirement
207
- none: false
208
- requirements:
209
- - - ">="
210
- - !ruby/object:Gem::Version
211
- hash: 3
212
- segments:
213
- - 0
214
- version: "0"
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
215
204
  requirements: []
216
-
217
205
  rubyforge_project:
218
- rubygems_version: 1.8.11
206
+ rubygems_version: 2.0.7
219
207
  signing_key:
220
- specification_version: 3
208
+ specification_version: 4
221
209
  summary: A really simple shopping cart implementation for rails.
222
- test_files:
223
- - spec/active_record/cart_item_spec.rb
224
- - spec/active_record/cart_spec.rb
225
- - spec/active_record/cartable_spec.rb
226
- - spec/app/controllers/cart_items_controller_spec.rb
227
- - spec/carter_spec.rb
228
- - spec/spec_helper.rb
229
- - spec/state_machine_spec.rb
230
- - spec/support/active_record_helper.rb
231
- - spec/support/factories.rb
210
+ test_files: []
@@ -1,21 +0,0 @@
1
- class CarterGenerator < Rails::Generator::Base
2
- default_options :skip_migration => false
3
-
4
- def manifest
5
- record do |m|
6
- if !options[:skip_migration] && defined?(ActiveRecord)
7
- m.migration_template "migration.rb", 'db/migrate',
8
- :migration_file_name => "create_carter"
9
- end
10
- end
11
- end
12
-
13
- protected
14
-
15
- def add_options!(opt)
16
- opt.separator ''
17
- opt.separator 'Options:'
18
- opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
19
- end
20
-
21
- end
@@ -1,20 +0,0 @@
1
- class CarterInstallGenerator < Rails::Generator::Base
2
- default_options :skip_migration => false
3
-
4
- def copy_controller_file
5
- copy_file "cart_items_controller.rb", "app/controllers"
6
- copy_file "carts_controller.rb", "app/controllers"
7
- end
8
-
9
- def copy_view_file
10
- copy_file "carts/show.html.erb", "app/views/carts"
11
- end
12
- protected
13
-
14
- def add_options!(opt)
15
- opt.separator ''
16
- opt.separator 'Options:'
17
- opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
18
- end
19
-
20
- end
@@ -1,11 +0,0 @@
1
- module Carter #:nodoc:
2
- module Routing #:nodoc:
3
- module MapperExtensions
4
- def carter_routes(options={})
5
- self.resources :carts
6
- self.resources :cart_items
7
-
8
- end
9
- end
10
- end
11
- end
@@ -1,97 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CartItem do
4
- before(){ Product.acts_as_cartable }
5
- it {should belong_to :cart}
6
- it {should belong_to :cartable }
7
- it {should belong_to :owner }
8
-
9
- describe "named scopes" do
10
- let(:owner_1) { Factory(:user) }
11
- let(:product_1){ Factory(:product) }
12
- let(:product_2){ Factory(:product) }
13
- let(:cart) { Factory(:cart) }
14
-
15
- before(:each){
16
- cart.add_item(product_1)
17
- cart.add_item(product_1, 1, owner_1)
18
- cart.add_item(product_2, 1, owner_1)
19
- }
20
-
21
- it "should find the cart_item by product and owner" do
22
- cart.cart_items.for_cartable_and_owner(product_2, owner_1).size.should == 1
23
- cart.cart_items.for_cartable_and_owner(product_2, owner_1).first.cartable.should == product_2
24
- cart.cart_items.for_cartable_and_owner(product_2, owner_1).first.owner.should == owner_1
25
- end
26
-
27
- it "should find the cart_item by product and owner is blank" do
28
- cart.cart_items.for_cartable_and_owner(product_2, nil).size.should == 0
29
- cart.cart_items.for_cartable_and_owner(product_1, nil).size.should == 1
30
- cart.cart_items.for_cartable_and_owner(product_1, nil).first.cartable.should == product_1
31
- cart.cart_items.for_cartable_and_owner(product_1, nil).first.owner.should == nil
32
- end
33
-
34
- it "should find the cart_items by product" do
35
- cart.cart_items.for_cartable(product_1).size.should == 2
36
- cart.cart_items.for_cartable(product_1).first.cartable.should == product_1
37
- cart.cart_items.for_cartable(product_1).last.cartable.should == product_1
38
- end
39
- end
40
-
41
- describe "an instance" do
42
- let(:cart){ Factory(:cart) }
43
- let(:cart_item) {Factory(:cart_item, :cart => cart ) }
44
- it "should respond to shopper" do
45
- cart_item.should respond_to :shopper
46
- end
47
-
48
- it "should delegate shopper to the cart" do
49
- cart_item.shopper.should == cart.shopper
50
- end
51
- end
52
-
53
- describe "adding to a cart" do
54
- let(:cart) {Factory(:cart)}
55
- let(:cartable) {Factory(:product)}
56
-
57
- it "should respond to add_item" do
58
- cart.should respond_to :add_item
59
- end
60
-
61
- it "should increment cart items by one" do
62
- proc{ cart.add_item(cartable) }.should change(cart.cart_items, :size).by(1)
63
- end
64
-
65
- it "should bump the quatity value of an exisitng item if the cart_item already exists" do
66
- cart.add_item(cartable)
67
- cart.cart_items.size.should == 1
68
- proc{ cart.add_item(cartable) }.should_not change(cart.cart_items, :size)
69
- cart.total.should == (cartable.price * 2)
70
- end
71
-
72
- it "should remove the item if the quantity is 0" do
73
- cart.add_item(cartable)
74
- cart_item = cart.cart_items.first
75
- lambda{ cart_item.update_attributes(:quantity => 0) }.should change(cart.cart_items, :size).from(1).to(0)
76
- end
77
-
78
- it "should remove the item if the quantity is less than zero" do
79
- cart.add_item(cartable)
80
- cart_item = cart.cart_items.first
81
- lambda{ cart_item.update_attributes(:quantity => -1) }.should change(cart.cart_items, :size).from(1).to(0)
82
- end
83
-
84
- describe "cart totals" do
85
- before do
86
- cart.add_item(cartable, 2)
87
- end
88
-
89
- it "should return the total price of the cart" do
90
- cart.total.should == (2 * cartable.price)
91
- cart.add_item(cartable)
92
- cart.total.should == (3 * cartable.price)
93
- end
94
- end
95
-
96
- end
97
- end
@@ -1,103 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Cart do
4
- before(){ Product.acts_as_cartable }
5
- it {should have_many :cart_items}
6
- it {should belong_to :shopper }
7
-
8
- describe "removing carts" do
9
- let(:cartable) {Factory(:product)}
10
- before do
11
- Cart.destroy_all
12
- @one_day_old = Factory(:cart, :updated_at => Time.now - 2.day)
13
- @one_week_old = Factory(:cart, :updated_at => Time.now - 8.days)
14
- @cart_item_one = Factory(:cart_item, :cart_id => @one_day_old.id)
15
- end
16
-
17
- it "should remove carts a week old" do
18
- d = (Time.now.midnight - 7.to_i.days)
19
- scoped_carts = mock("carts")
20
- scoped_carts.should_receive(:find_in_batches).with(:conditions => ["updated_at < ?", d])
21
- Cart.should_receive(:with_state).with(:active).and_return(scoped_carts)
22
- Cart.remove_carts
23
- end
24
-
25
- it "should remove carts a 2 days old" do
26
- d = (Time.now.midnight - 2.to_i.days)
27
- scoped_carts = mock("carts")
28
- scoped_carts.should_receive(:find_in_batches).with(:conditions => ["updated_at < ?", d])
29
- Cart.should_receive(:with_state).with(:active).and_return(scoped_carts)
30
- Cart.remove_carts(2)
31
- end
32
-
33
- it "should delete the carts over a week old" do
34
- proc{ Cart.remove_carts() }.should change(Cart, :count).by(-1)
35
- end
36
-
37
- it "should delete the carts over a day old" do
38
- proc{ Cart.remove_carts(1) }.should change(Cart, :count).by(-2)
39
- end
40
-
41
- it "should not delete the any carts when not old enough" do
42
- proc{ Cart.remove_carts(14) }.should_not change(Cart, :count)
43
- end
44
-
45
- it "should return the number of deleted carts" do
46
- Cart.remove_carts(1).should == 2
47
- end
48
-
49
- it "should remove carts with another state" do
50
- d = (Time.now.midnight - 2.to_i.days)
51
- scoped_carts = mock("carts")
52
- scoped_carts.should_receive(:find_in_batches).with(:conditions => ["updated_at < ?", d])
53
- Cart.should_receive(:with_state).with(:failed).and_return(scoped_carts)
54
- Cart.remove_carts(2, :failed)
55
- end
56
- end
57
-
58
- describe "adding to a cart" do
59
- let(:cart) {Factory(:cart)}
60
- let(:cartable) {Factory(:product)}
61
-
62
- it "should respond to add_item" do
63
- cart.should respond_to :add_item
64
- end
65
-
66
- it "should respond to empty?" do
67
- cart.should respond_to :empty?
68
- end
69
-
70
- it "should be empty" do
71
- cart.should be_empty
72
- end
73
-
74
- it "should increment cart items by one" do
75
- proc{ cart.add_item(cartable) }.should change(cart.cart_items, :size).by(1)
76
- end
77
-
78
- describe "cart totals" do
79
- before do
80
- cart.add_item(cartable, 2)
81
- end
82
-
83
- it "should not be empty" do
84
- cart.should_not be_empty
85
- end
86
-
87
- it "should return the total price of the cart" do
88
- cart.total.should == (2 * cartable.price)
89
- cart.add_item(cartable)
90
- cart.total.should == (3 * cartable.price)
91
- end
92
-
93
- # it "should have many cartables" do
94
- # cart.cartables.should include(cartable)
95
- # end
96
-
97
- # it "should have many products" do
98
- # cart.should respond_to(:products)
99
- # end
100
- end
101
-
102
- end
103
- end
@@ -1,116 +0,0 @@
1
- require 'spec_helper'
2
-
3
-
4
-
5
-
6
- describe Carter::ActiveRecord::Cartable do
7
-
8
- describe "configuration" do
9
- it "should add the thing class to the Carter config" do
10
- Thing.acts_as_cartable
11
- Carter.settings.cartables.should include(Thing.name)
12
- end
13
- end
14
-
15
- let(:cartable){Factory(:product)}
16
- it "should load the schema for testing" do
17
- Product.all.should be_a Array
18
- end
19
-
20
- it "should add acts_as_cartable method to product" do
21
- Product.should respond_to(:acts_as_cartable)
22
- end
23
-
24
- describe "Product.acts_as_cartable" do
25
- context "default settings" do
26
- before(){ Product.acts_as_cartable }
27
-
28
- it "should add the product class to the Carter config" do
29
- Carter.settings.cartables.should include(Product.name)
30
- end
31
-
32
- it {cartable.should have_many(:cart_items)}
33
- it {cartable.should have_many(:carts) }
34
- it "should set the default name column" do
35
- Product.cartable_configuration[:name].should == "name"
36
- end
37
-
38
- it "should set the default price column" do
39
- Product.cartable_configuration[:price].should == "price"
40
- end
41
-
42
- it "should return the price" do
43
- cartable.price.should == cartable.cartable_price
44
- end
45
- it "should return the name" do
46
- cartable.name.should == cartable.cartable_name
47
- end
48
- end
49
-
50
- context "finding carts on a cartable" do
51
- let(:cart){ Factory(:cart) }
52
- let(:thing){ Factory(:thing) }
53
- before do
54
- cart.add_item(cartable, 2)
55
- cart.add_item(thing)
56
- end
57
-
58
- it 'should find the cart from the cartable' do
59
- cartable.carts.should be_include(cart)
60
- thing.carts.should be_include(cart)
61
- end
62
-
63
- it "a cartable should be in cart" do
64
- cartable.in_cart?(cart).should be_true
65
- end
66
- end
67
-
68
- context "custom settings" do
69
- before(){ Product.acts_as_cartable(:name => "ping", :price => "pong") }
70
-
71
- it "should set the name column" do
72
- Product.cartable_configuration[:name].should == "ping"
73
- end
74
-
75
- it "should set the price column" do
76
- Product.cartable_configuration[:price].should == "pong"
77
- end
78
- end
79
-
80
- describe "unique cart_items" do
81
- let(:cart){ Factory(:cart) }
82
- let(:product){ Factory(:product) }
83
- let(:thing){ Factory(:thing) }
84
- let(:owner) { Factory(:user) }
85
-
86
- before() do
87
- Product.acts_as_cartable(:unique => true)
88
- Thing.acts_as_cartable(:unique => true)
89
- end
90
-
91
- it "should not allow multiple cart_items in the cart of this cartable" do
92
- cartable.allow_multiples?.should be_false
93
- end
94
-
95
- it "should raise an error if an item of the same type is added to the cart" do
96
- cart.add_item(product)
97
- cart.cart_items.size.should == 1
98
- lambda{ cart.add_item(product) }.should raise_error(Carter::MultipleCartItemsNotAllowed, /is already in your basket/)
99
- end
100
-
101
- it "should not raise an error if an item of same type is added to the cart but with a different owner" do
102
- cart.add_item(product)
103
- cart.cart_items.size.should == 1
104
- lambda{ cart.add_item(product, 1, owner) }.should_not raise_error(Carter::MultipleCartItemsNotAllowed, /is already in your basket/)
105
- cart.cart_items.size.should == 2
106
- end
107
-
108
- it "should not raise an error if an item of different type is added to the cart" do
109
- cart.add_item(product)
110
- cart.cart_items.size.should == 1
111
- lambda{ cart.add_item(thing) }.should_not raise_error(Carter::MultipleCartItemsNotAllowed, /is already in your basket/)
112
- cart.cart_items.size.should == 2
113
- end
114
- end
115
- end
116
- end
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
- #
3
- # describe CartItemsController do
4
- #
5
- # describe "adding to the cart" do
6
- #
7
- # before do
8
- #
9
- # end
10
- #
11
- # it "should be successful" do
12
- # Product.should_receive(:find_by_id).with("1").and_return(mock_model(Product))
13
- # post :create, :cartable_type => "product", :cartable_id => "1"
14
- # response.should be_success
15
- # end
16
- #
17
- #
18
- # end
19
- # end
@@ -1,5 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "Carter" do
4
-
5
- end
@@ -1,36 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
-
11
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'app'))
13
- $LOAD_PATH.unshift(File.dirname(__FILE__))
14
- require 'rubygems'
15
- require 'rspec'
16
- require 'shoulda'
17
- require 'carter'
18
- require 'factory_girl'
19
- require 'action_pack'
20
- require 'state_machine'
21
- require 'money'
22
- require 'active_support'
23
- require 'active_support/test_case'
24
-
25
- Carter::Initializer.setup
26
- # Requires supporting files with custom matchers and macros, etc,
27
- # in ./support/ and its subdirectories.
28
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
29
-
30
-
31
- RSpec.configure do |config|
32
-
33
- end
34
-
35
-
36
- load_schema
@@ -1,100 +0,0 @@
1
- describe Carter::StateMachine::Cart do
2
-
3
- let(:cart){Factory(:cart) }
4
- let(:product){ Factory(:product) }
5
-
6
- describe "the states" do
7
- [:active, :processing, :failure, :success, :expired].each do |state|
8
- it "should have the state #{state}" do
9
- cart.should respond_to("#{state}?")
10
- end
11
- end
12
- end
13
-
14
- describe "the transitions" do
15
- [:checkout, :succeeded, :failed, :expire].each do |transition|
16
- it "should have the transition event #{transition}" do
17
- cart.should respond_to("#{transition}")
18
- end
19
- end
20
- end
21
-
22
- describe "the lifecycle" do
23
- it "should have an initial state of active" do
24
- cart.active?.should be_true
25
- end
26
-
27
- describe "without a on_checkout proc defined" do
28
- it "should transition to processing on checkout" do
29
- expect { cart.checkout }.to change(cart, :state).from("active").to("processing")
30
- end
31
- end
32
-
33
- describe "with a on_checkout proc defined" do
34
- before(:each) do
35
- @gateway = mock()
36
- Carter.settings.on_checkout = Proc.new() do |record|
37
- if @gateway.status == :success
38
- record.succeeded
39
- else
40
- record.failed
41
- end
42
- end
43
- end
44
-
45
- describe "a successful payment" do
46
- before(:each) do
47
- Product.acts_as_cartable :after_purchase_method => :yippee_shiny_product_is_mine
48
- @gateway.should_receive(:status).and_return(:success)
49
- end
50
-
51
- it "should transition to paid on success " do
52
- expect { cart.checkout}.to change(cart, :state).from("active").to("success")
53
- end
54
-
55
- it "should trigger the on success method" do
56
- cart.should_receive(:on_success)
57
- cart.checkout
58
- end
59
-
60
- context "with cart_items" do
61
- before(:each) do
62
- product.stub!(:yippee_shiny_product_is_mine)
63
- end
64
-
65
- it "should trigger the add_to_owner method for each cart_item" do
66
- cart.add_item(product)
67
- cart.cart_items.each{|cart_item|
68
- cart_item.should_receive(:add_to_owner)
69
- }
70
- cart.checkout
71
- end
72
-
73
- it "should call the on purchase method for the cartable product" do
74
- cart.add_item(product)
75
- cart.cart_items.each{|cart_item|
76
- cart_item.stub!(:cartable).and_return(product)
77
- }
78
- product.should_receive(:yippee_shiny_product_is_mine)
79
- cart.checkout
80
- end
81
- end
82
- end
83
- describe "a failed payment" do
84
- before(:each) do
85
- Product.acts_as_cartable :after_purchase_method => :yippee_shiny_product_is_mine
86
- @gateway.should_receive(:status).and_return(:failed)
87
- end
88
-
89
- it "should transition to failure on success " do
90
- expect { cart.checkout}.to change(cart, :state).from("active").to("failure")
91
- end
92
-
93
- it "should trigger the on_failure method" do
94
- cart.should_receive(:on_failed)
95
- cart.checkout
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,79 +0,0 @@
1
-
2
- require 'active_record'
3
- ActiveRecord::Base.extend Carter::ActiveRecord::Cartable if defined?(ActiveRecord)
4
-
5
- Dir["app/models/*.rb"].each {|f| require f}
6
-
7
- class User < ActiveRecord::Base
8
- end
9
-
10
- class Product < ActiveRecord::Base
11
-
12
- end
13
- class Thing < ActiveRecord::Base
14
-
15
- end
16
- def load_schema
17
-
18
- config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
19
- # ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
20
-
21
- db_adapter = ENV['DB']
22
-
23
- # no db passed, try one of these fine config-free DBs before bombing.
24
- db_adapter ||=
25
- begin
26
- require 'sqlite'
27
- 'sqlite'
28
- rescue MissingSourceFile
29
- begin
30
- require 'sqlite3'
31
- 'sqlite3'
32
- rescue MissingSourceFile
33
- end
34
- end
35
-
36
- if db_adapter.nil?
37
- raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
38
- end
39
-
40
-
41
- ActiveRecord::Base.establish_connection(config[db_adapter])
42
- ActiveRecord::Schema.define(:version => 0) do
43
- create_table "users", :force => true do |t|
44
- t.string :name
45
- t.timestamps
46
- end
47
- create_table "things", :force => true do |t|
48
- t.string :name
49
- t.float :price
50
- t.timestamps
51
- end
52
- create_table "products", :force => true do |t|
53
- t.string :name
54
- t.float :price
55
- t.timestamps
56
- end
57
-
58
- create_table "cart_items", :force => true do |t|
59
- t.string :name
60
- t.string :state
61
- t.belongs_to :owner, :polymorphic => true
62
- t.belongs_to :cartable, :polymorphic => true
63
- t.belongs_to :cart
64
- t.column :price, :float
65
- t.column :quantity, :integer
66
- t.timestamps
67
- end
68
-
69
- create_table "carts", :force => true do |t|
70
- t.string :session_id
71
- t.string :state
72
- t.belongs_to :shopper, :polymorphic => true
73
- t.timestamps
74
- end
75
- end
76
-
77
-
78
- end
79
-
@@ -1,43 +0,0 @@
1
-
2
- FactoryGirl.define do
3
- sequence :name do |n|
4
- "name_#{n}"
5
- end
6
-
7
- factory :product do
8
- Factory.next(:name) {|n| "name#{n}" }
9
- price 2.00
10
- end
11
- end
12
-
13
- FactoryGirl.define do
14
- factory :thing do
15
- Factory.next(:name) {|n| "name#{n}" }
16
- price 4.00
17
- end
18
- end
19
-
20
- FactoryGirl.define do
21
- factory :user do
22
- Factory.next(:name) {|n| "name#{n}" }
23
- end
24
- end
25
-
26
- FactoryGirl.define do
27
-
28
- factory :cart do
29
- shopper {|a| a.association(:user) }
30
- state "active"
31
- after_create {|cart_item| cart_item.send(:initialize_state_machines, :dynamic => :force)}
32
- end
33
- end
34
-
35
- FactoryGirl.define do
36
-
37
- factory :cart_item do
38
- state "in_cart"
39
- cart {|a| a.association(:cart) }
40
- after_create {|cart_item| cart_item.send(:initialize_state_machines, :dynamic => :force)}
41
- end
42
- end
43
-