carter 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
-