devise_paypal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +4 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.markdown +125 -0
  5. data/Rakefile +2 -0
  6. data/app/controllers/devise/paypal_authable_controller.rb +24 -0
  7. data/app/controllers/devise/paypal_permissions_authable_controller.rb +25 -0
  8. data/config/locales/en.yml +7 -0
  9. data/devise_paypal.gemspec +23 -0
  10. data/features/paypal_authable.feature +30 -0
  11. data/features/paypal_permissions_authable.feature +40 -0
  12. data/features/step_definitions/extended_web_steps.rb +12 -0
  13. data/features/step_definitions/paypal_authable_steps.rb +11 -0
  14. data/features/step_definitions/paypal_authentication_steps.rb +25 -0
  15. data/features/step_definitions/paypal_permissions_authable_steps.rb +22 -0
  16. data/features/step_definitions/pickle_steps.rb +100 -0
  17. data/features/step_definitions/web_steps.rb +219 -0
  18. data/features/support/env.rb +58 -0
  19. data/features/support/fakeweb.rb +3 -0
  20. data/features/support/hooks.rb +10 -0
  21. data/features/support/paths.rb +46 -0
  22. data/features/support/paypal_response_helpers.rb +14 -0
  23. data/features/support/pickle.rb +24 -0
  24. data/lib/devise_paypal.rb +18 -0
  25. data/lib/devise_paypal/controllers/internal_helpers.rb +58 -0
  26. data/lib/devise_paypal/controllers/url_helpers.rb +16 -0
  27. data/lib/devise_paypal/models/paypal_authable.rb +22 -0
  28. data/lib/devise_paypal/models/paypal_permissions_authable.rb +22 -0
  29. data/lib/devise_paypal/rails.rb +21 -0
  30. data/lib/devise_paypal/rails/routes.rb +39 -0
  31. data/lib/devise_paypal/version.rb +3 -0
  32. data/lib/generators/devise_paypal/install_generator.rb +18 -0
  33. data/lib/generators/templates/README +20 -0
  34. data/test/rails_app/.gitignore +4 -0
  35. data/test/rails_app/Gemfile +21 -0
  36. data/test/rails_app/Gemfile.lock +169 -0
  37. data/test/rails_app/Rakefile +7 -0
  38. data/test/rails_app/app/controllers/application_controller.rb +3 -0
  39. data/test/rails_app/app/controllers/welcome_controller.rb +5 -0
  40. data/test/rails_app/app/models/user.rb +26 -0
  41. data/test/rails_app/app/views/layouts/application.html.erb +16 -0
  42. data/test/rails_app/app/views/welcome/index.html.erb +11 -0
  43. data/test/rails_app/config.ru +4 -0
  44. data/test/rails_app/config/application.rb +42 -0
  45. data/test/rails_app/config/boot.rb +13 -0
  46. data/test/rails_app/config/cucumber.yml +8 -0
  47. data/test/rails_app/config/database.yml +25 -0
  48. data/test/rails_app/config/environment.rb +5 -0
  49. data/test/rails_app/config/environments/development.rb +28 -0
  50. data/test/rails_app/config/environments/production.rb +49 -0
  51. data/test/rails_app/config/environments/test.rb +35 -0
  52. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  53. data/test/rails_app/config/initializers/devise.rb +168 -0
  54. data/test/rails_app/config/initializers/inflections.rb +10 -0
  55. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  56. data/test/rails_app/config/initializers/paypal.rb +7 -0
  57. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  58. data/test/rails_app/config/initializers/session_store.rb +8 -0
  59. data/test/rails_app/config/locales/devise.en.yml +43 -0
  60. data/test/rails_app/config/locales/en.yml +5 -0
  61. data/test/rails_app/config/routes.rb +5 -0
  62. data/test/rails_app/db/migrate/20101102105924_devise_create_users.rb +26 -0
  63. data/test/rails_app/db/schema.rb +34 -0
  64. data/test/rails_app/db/seeds.rb +7 -0
  65. data/test/rails_app/lib/tasks/.gitkeep +0 -0
  66. data/test/rails_app/lib/tasks/cucumber.rake +53 -0
  67. data/test/rails_app/public/404.html +26 -0
  68. data/test/rails_app/public/422.html +26 -0
  69. data/test/rails_app/public/500.html +26 -0
  70. data/test/rails_app/public/favicon.ico +0 -0
  71. data/test/rails_app/public/images/rails.png +0 -0
  72. data/test/rails_app/public/javascripts/application.js +2 -0
  73. data/test/rails_app/public/javascripts/controls.js +965 -0
  74. data/test/rails_app/public/javascripts/dragdrop.js +974 -0
  75. data/test/rails_app/public/javascripts/effects.js +1123 -0
  76. data/test/rails_app/public/javascripts/prototype.js +6001 -0
  77. data/test/rails_app/public/javascripts/rails.js +175 -0
  78. data/test/rails_app/public/robots.txt +5 -0
  79. data/test/rails_app/public/stylesheets/.gitkeep +0 -0
  80. data/test/rails_app/script/cucumber +10 -0
  81. data/test/rails_app/script/rails +6 -0
  82. metadata +159 -0
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in devise_paypal.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2010 David Wilkie
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,125 @@
1
+ # devise_paypal
2
+
3
+ devise_paypal is [Devise](http://github.com/plataformatec/devise) extension that allows you to authenticate users using the the [Paypal Permissions API](https://www.x.com/community/ppx/permissions) or the [Paypal Authentication API](https://www.x.com/community/ppx/authentication) through Devise.
4
+
5
+ ## Installation
6
+
7
+ Add devise_paypal to your Gemfile and make sure your using Devise from the git repository or at least version: "1.2.rc"
8
+
9
+ gem "devise", :git => "git://github.com/plataformatec/devise.git" # "1.2.rc"
10
+ gem "devise_paypal" #, :git => "git://github.com/dwilkie/devise_paypal.git" # for the latest and greatest
11
+
12
+ Ensure your bundle is installed and run the generator
13
+ bundle
14
+ rails g devise_paypal:install
15
+
16
+ As the generator instructs, you need to also add paypal-ipn to your gemfile then run its generator
17
+
18
+ gem 'paypal-ipn', :require => 'paypal' #, :git => "git://github.com/dwilkie/paypal.git" # for the latest and greatest
19
+
20
+ bundle
21
+ rails g paypal:initializer
22
+
23
+ This will create a configuration file where you can put your paypal api credentials.
24
+
25
+ Note: to enable the Paypal Permissions API you must file a ticket [here](https://www.paypal.com/mts). See this [page](https://www.x.com/community/ppx/permissions) for further details.
26
+
27
+ ## Usage
28
+
29
+ ### Model Configuration
30
+
31
+ Using the `devise` method, add `:paypal_authable` and/or `:paypal_permissions_authable` to your model.
32
+
33
+ class User < ActiveRecord::Base
34
+ devise paypal_authable, :paypal_permissions_authable
35
+ end
36
+
37
+ ### Views
38
+
39
+ If you have chosen a model named User and `devise_for :users` is already added to your config/routes.rb, devise_paypal will create the following url methods:
40
+
41
+ new_user_paypal_authable
42
+ new_user_paypal_permissions_authable
43
+
44
+ Then you only need to add them to your layouts in order to provide Paypal authentication:
45
+
46
+ <%= link_to "Sign in with Paypal Authable", new_user_paypal_authable_path %>
47
+ <%= link_to "Sign in with Paypal Permissions Authable", new_user_paypal_permissions_authable_path %>
48
+
49
+ By clicking on these links, the user will be redirected to Paypal. Then after entering their credentials, they'll be redirected back to your application.
50
+
51
+ ### Model Callback Method
52
+
53
+ Implement a class method in your model called `find_for_paypal_auth` which accepts a single params hash argument. The params hash contains the information returned from Paypal in the following format:
54
+
55
+ :email => "johnny@example.com",
56
+ :first_name => "Johnny",
57
+ :last_name => "Walker",
58
+ :permissions => {
59
+ :mass_pay => true
60
+ }
61
+
62
+ The method should return a single record which will be used to sign in the user. A simple implementation may look like this:
63
+
64
+ class User < ActiveRecord::Base
65
+ def self.find_for_paypal_auth(params)
66
+ if params
67
+ user = self.find_or_initialize_by_email(params[:email])
68
+ if user.new_record?
69
+ stubbed_password = Devise.friendly_token[0..password_length.max-1]
70
+ user.password = stubbed_password
71
+ user.password_confirmation = stubbed_password
72
+ user.save
73
+ end
74
+ else
75
+ user = self.new
76
+ end
77
+ user
78
+ end
79
+ end
80
+
81
+ See [user.rb](https://github.com/dwilkie/devise_paypal/blob/master/test/rails_app/app/models/user.rb) in the [sample rails app](https://github.com/dwilkie/devise_paypal/tree/master/test/rails_app) for more details.
82
+
83
+ ### Overriding Defaults
84
+
85
+ Say you want to request permission to access a Paypal API on behalf of a user. You can do this by overriding the devise_for call in your routes.rb file.
86
+
87
+ # routes.rb
88
+ devise_for :users, :controllers => {
89
+ :paypal_permissions_authable => "paypal_registrations"
90
+ }
91
+
92
+ Then creating your own controller inheriting from: `Devise::PaypalPermisssionsAuthableController`
93
+
94
+ # app/controllers/paypal_registrations_controller.rb
95
+ class PaypalRegistrationsController < Devise::PaypalPermissionsAuthableController
96
+ def new
97
+ @permissions = {:mass_pay => true}
98
+ super
99
+ end
100
+ end
101
+
102
+ In this case be sure to remember to modify the keys for your locale file:
103
+ # config/locales/devise_paypal.en.yml
104
+ en:
105
+ devise:
106
+ paypal_registrations:
107
+ success: "Successfully authorized from paypal account."
108
+
109
+ By default, if a non-persisted record is returned by your model callback method, the user will be rendered the new registrations page from `devise :registrations`
110
+
111
+ To change this behavior simply override `render_for_paypal` in your controller
112
+
113
+ # app/controllers/paypal_registrations_controller.rb
114
+ class PaypalRegistrationsController < Devise::PaypalPermissionsAuthableController
115
+ private
116
+
117
+ def render_for_paypal
118
+ render "welcome#index"
119
+ end
120
+ end
121
+
122
+ For more details check out the [source](https://github.com/dwilkie/devise_paypal/tree/master/lib/devise_paypal/)
123
+
124
+ Copyright (c) 2010 David Wilkie, released under the MIT license
125
+
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,24 @@
1
+ class Devise::PaypalAuthableController < ApplicationController
2
+ prepend_before_filter :require_no_authentication, :only => :new
3
+ include Devise::Controllers::InternalHelpers
4
+ include DevisePaypal::Controllers::InternalHelpers
5
+ include Paypal::Authentication
6
+
7
+ # GET /resource/paypal_authorize_without_permissions
8
+ def new
9
+ callback_url = paypal_authable_callback_uri
10
+ redirect_to authenticate_with_paypal_url(callback_url)
11
+ end
12
+
13
+ # GET /resource/paypal_authable/callback
14
+ def callback_action
15
+ paypal_user_details = get_auth_details(params[:token]) if params[:token]
16
+ handle_callback_action(paypal_user_details)
17
+ end
18
+
19
+ private
20
+ def paypal_authable_callback_uri #:nodoc:
21
+ paypal_authable_callback_url(resource_name)
22
+ end
23
+ end
24
+
@@ -0,0 +1,25 @@
1
+ class Devise::PaypalPermissionsAuthableController < ApplicationController
2
+ prepend_before_filter :require_no_authentication, :only => :new
3
+ include Devise::Controllers::InternalHelpers
4
+ include DevisePaypal::Controllers::InternalHelpers
5
+ include Paypal::Permissions
6
+
7
+ # GET /resource/paypal_authorize_with_permissions
8
+ def new
9
+ @permissions ||= {}
10
+ callback_url = paypal_permissions_authable_callback_uri
11
+ redirect_to set_paypal_permissions_url(callback_url, @permissions)
12
+ end
13
+
14
+ # GET /resource/paypal_permissions_authable/callback
15
+ def callback_action
16
+ paypal_user_details = get_paypal_permissions(params[:token]) if params[:token]
17
+ handle_callback_action(paypal_user_details)
18
+ end
19
+
20
+ private
21
+ def paypal_permissions_authable_callback_uri #:nodoc:
22
+ paypal_permissions_authable_callback_url(resource_name)
23
+ end
24
+ end
25
+
@@ -0,0 +1,7 @@
1
+ en:
2
+ devise:
3
+ paypal_permissions_authable:
4
+ success: "Successfully authorized from Paypal account."
5
+ paypal_authable:
6
+ success: "Successfully authorized from Paypal account."
7
+
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "devise_paypal/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "devise_paypal"
7
+ s.version = DevisePaypal::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["David Wilkie"]
10
+ s.email = ["dwilkie@gmail.com"]
11
+ s.homepage = "http://github.com/dwilkie/devise_paypal"
12
+ s.summary = %q{Signup or login using Paypal}
13
+ s.description = %q{Signup or login using Paypal's Authorization or Permissions api's}
14
+
15
+ s.rubyforge_project = "devise_paypal"
16
+ s.add_runtime_dependency "paypal-ipn", ">0.0.1"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
23
+
@@ -0,0 +1,30 @@
1
+ @paypal_authentication_request
2
+ Feature: Authenticate using Paypal Authable
3
+ In order to signup or login using by logging into paypal
4
+ As a user
5
+ I want to be able to authenticate using the Paypal authable api
6
+
7
+ Scenario: I authenticate with Paypal authable
8
+ When I go to the authenticate with paypal authable page
9
+
10
+ Then I should be redirected to sign in with paypal
11
+ And I should be requested to grant access to my name and email address
12
+
13
+ Scenario: I sign into paypal
14
+ Given I have a paypal account with email: "mara@example.com"
15
+ And I sign into paypal through paypal authable
16
+
17
+ When I am redirected back to the application from paypal after an authentication request
18
+
19
+ Then a user should exist with email: "mara@example.com"
20
+ And I should be on the home page
21
+ And I should see "Successfully authorized from Paypal account."
22
+
23
+ Scenario: I do not sign into paypal
24
+ Given I have a paypal account with email: "mara@example.com"
25
+ But I do not sign into paypal
26
+
27
+ When I am redirected back to the application from paypal after an authentication request
28
+
29
+ Then a user should not exist with email: "mara@example.com"
30
+
@@ -0,0 +1,40 @@
1
+ @paypal_authentication_request
2
+ Feature: Authenticate using Paypal Permissions Authable
3
+ In order to signup or login using Paypal and grant requested permissions
4
+ As a user
5
+ I want to be able to authenticate using the Paypal permissions api
6
+
7
+ Scenario: I authenticate with Paypal permissions authable
8
+ When I go to the authenticate with paypal permissions page
9
+
10
+ Then I should be redirected to sign in with paypal
11
+ And I should be requested to grant the required permissions
12
+
13
+ Scenario: I grant the required permissions
14
+ Given I have a paypal account with email: "mara@example.com"
15
+ And I sign into paypal through paypal permissions authable
16
+ And I grant the required permissions
17
+
18
+ When I am redirected back to the application from paypal after a permissions request
19
+
20
+ Then a user should exist with email: "mara@example.com"
21
+ And I should be on the home page
22
+ And I should see "Successfully authorized from Paypal account."
23
+
24
+ Scenario: I do not grant the required permissions
25
+ Given I have a paypal account with email: "mara@example.com"
26
+ And I sign into paypal through paypal permissions authable
27
+ But I do not grant the required permissions
28
+
29
+ When I am redirected back to the application from paypal after a permissions request
30
+
31
+ Then a user should not exist with email: "mara@example.com"
32
+
33
+ Scenario: I do not sign into paypal
34
+ Given I have a paypal account with email: "mara@example.com"
35
+ But I do not sign into paypal
36
+
37
+ When I am redirected back to the application from paypal after a permissions request
38
+
39
+ Then a user should not exist with email: "mara@example.com"
40
+
@@ -0,0 +1,12 @@
1
+ Then /^(?:|I )should be at "([^"]*)"$/ do |url|
2
+ current_uri = URI.parse(current_url)
3
+ current_uri.query = nil
4
+ current_uri.path = "" if current_uri.path == "/"
5
+ current_uri = current_uri.to_s
6
+ if current_uri.respond_to? :should
7
+ current_uri.should == url
8
+ else
9
+ assert_equal url, current_uri
10
+ end
11
+ end
12
+
@@ -0,0 +1,11 @@
1
+ Given /^I sign into paypal through paypal authable$/ do
2
+ register_get_user_details_response
3
+ end
4
+
5
+ Then /^I should be requested to grant access to my name and email address$/ do
6
+ Then %{I should have the following query string:}, table(%{
7
+ | cmd | _account-authenticate-login |
8
+ | token | HA-DJW3X5Y99KRR4 |
9
+ })
10
+ end
11
+
@@ -0,0 +1,25 @@
1
+ Given /^I have a paypal account(?: with #{capture_fields})?$/ do |fields|
2
+ @paypal_user_details = parse_fields(fields)
3
+ parsed_paypal_user_details = {}
4
+ @paypal_user_details.each do |key, value|
5
+ parsed_paypal_user_details[key.classify.upcase] = value
6
+ end
7
+ @paypal_user_details = parsed_paypal_user_details
8
+ end
9
+
10
+ Given /^I do not sign into paypal$/ do
11
+ # this step is intentionally blank
12
+ end
13
+
14
+ When /^I am redirected back to the application from paypal after a permissions request$/ do
15
+ When "I go to the paypal permissions callback page"
16
+ end
17
+
18
+ When /^I am redirected back to the application from paypal after an authentication request$/ do
19
+ When "I go to the paypal authable callback page"
20
+ end
21
+
22
+ Then /^I should be redirected to sign in with paypal$/ do
23
+ Then %{I should be at "#{Paypal.uri}"}
24
+ end
25
+
@@ -0,0 +1,22 @@
1
+ Given /^I sign into paypal through paypal permissions authable$/ do
2
+ # this step is intentionally blank
3
+ end
4
+
5
+ Given /^I grant the required permissions$/ do
6
+ register_get_user_details_response
7
+ end
8
+
9
+ Given /^I do not grant the required permissions$/ do
10
+ body = "TIMESTAMP=2010%2d10%2d08T11%3a35%3a41Z&CORRELATIONID=d41ee44136721&ACK=Failure&VERSION=2%2e3&BUILD=1545724&L_ERRORCODE0=11622&L_SHORTMESSAGE0=User%20Does%20Not%20Exist%2e&L_LONGMESSAGE0=User%20may%20not%20have%20logged%20in%20using%20this%20token%2e&L_SEVERITYCODE0=Error"
11
+ FakeWeb.register_uri(
12
+ :post, Paypal.nvp_uri, :body => body
13
+ )
14
+ end
15
+
16
+ Then /^I should be requested to grant the required permissions$/ do
17
+ Then %{I should have the following query string:}, table(%{
18
+ | cmd | _access-permission-login |
19
+ | token | HA-DJW3X5Y99KRR4 |
20
+ })
21
+ end
22
+
@@ -0,0 +1,100 @@
1
+ # this file generated by script/generate pickle
2
+
3
+ # create a model
4
+ Given(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|
5
+ create_model(name, fields)
6
+ end
7
+
8
+ # create n models
9
+ Given(/^(\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
10
+ count.to_i.times { create_model(plural_factory.singularize, fields) }
11
+ end
12
+
13
+ # create models from a table
14
+ Given(/^the following #{capture_plural_factory} exists?:?$/) do |plural_factory, table|
15
+ create_models_from_table(plural_factory, table)
16
+ end
17
+
18
+ # find a model
19
+ Then(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|
20
+ find_model!(name, fields)
21
+ end
22
+
23
+ # not find a model
24
+ Then(/^#{capture_model} should not exist(?: with #{capture_fields})?$/) do |name, fields|
25
+ find_model(name, fields).should be_nil
26
+ end
27
+
28
+ # find models with a table
29
+ Then(/^the following #{capture_plural_factory} should exists?:?$/) do |plural_factory, table|
30
+ find_models_from_table(plural_factory, table).should_not be_any(&:nil?)
31
+ end
32
+
33
+ # find exactly n models
34
+ Then(/^(\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
35
+ find_models(plural_factory.singularize, fields).size.should == count.to_i
36
+ end
37
+
38
+ # assert equality of models
39
+ Then(/^#{capture_model} should be #{capture_model}$/) do |a, b|
40
+ model!(a).should == model!(b)
41
+ end
42
+
43
+ # assert model is in another model's has_many assoc
44
+ Then(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
45
+ model!(owner).send(association).should include(model!(target))
46
+ end
47
+
48
+ # assert model is not in another model's has_many assoc
49
+ Then(/^#{capture_model} should not be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
50
+ model!(owner).send(association).should_not include(model!(target))
51
+ end
52
+
53
+ # assert model is another model's has_one/belongs_to assoc
54
+ Then(/^#{capture_model} should be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
55
+ model!(owner).send(association).should == model!(target)
56
+ end
57
+
58
+ # assert model is not another model's has_one/belongs_to assoc
59
+ Then(/^#{capture_model} should not be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
60
+ model!(owner).send(association).should_not == model!(target)
61
+ end
62
+
63
+ # assert model.predicate?
64
+ Then(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
65
+ if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
66
+ model!(name).should send("have_#{predicate.gsub(' ', '_')}")
67
+ else
68
+ model!(name).should send("be_#{predicate.gsub(' ', '_')}")
69
+ end
70
+ end
71
+
72
+ # assert not model.predicate?
73
+ Then(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
74
+ if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
75
+ model!(name).should_not send("have_#{predicate.gsub(' ', '_')}")
76
+ else
77
+ model!(name).should_not send("be_#{predicate.gsub(' ', '_')}")
78
+ end
79
+ end
80
+
81
+ # model.attribute.should eql(value)
82
+ # model.attribute.should_not eql(value)
83
+ Then(/^#{capture_model}'s (\w+) (should(?: not)?) be #{capture_value}$/) do |name, attribute, expectation, expected|
84
+ actual_value = model(name).send(attribute)
85
+ expectation = expectation.gsub(' ', '_')
86
+
87
+ case expected
88
+ when 'nil', 'true', 'false'
89
+ actual_value.send(expectation, send("be_#{expected}"))
90
+ when /^[+-]?[0-9_]+(\.\d+)?$/
91
+ actual_value.send(expectation, eql(expected.to_f))
92
+ else
93
+ actual_value.to_s.send(expectation, eql(eval(expected)))
94
+ end
95
+ end
96
+
97
+ # assert size of association
98
+ Then /^#{capture_model} should have (\d+) (\w+)$/ do |name, size, association|
99
+ model!(name).send(association).size.should == size.to_i
100
+ end