diff -Nru ruby-shoulda-matchers-1.0.0~beta2/Appraisals ruby-shoulda-matchers-2.8.0/Appraisals --- ruby-shoulda-matchers-1.0.0~beta2/Appraisals 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/Appraisals 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,128 @@ +ruby_version = Gem::Version.new(RUBY_VERSION + '') + +spring = proc do + gem 'spring' + gem 'spring-commands-rspec' +end + +rails_3 = proc do + gem 'strong_parameters' + gem 'rspec-rails', '2.99.0' + gem 'minitest', '~> 4.0' + gem 'minitest-reporters' +end + +rails_3_1 = proc do + instance_eval(&rails_3) + gem 'rails', '~> 3.1.8' + gem 'bcrypt-ruby', '~> 3.0.0' + gem 'jquery-rails' + gem 'sass-rails', '~> 3.1.5' + gem 'coffee-rails', '~> 3.1.1' + gem 'uglifier', '>= 1.0.3' + gem 'rspec-rails', '2.99.0' + gem 'minitest', '~> 4.0' + gem 'minitest-reporters' +end + +rails_3_2 = proc do + instance_eval(&rails_3) + gem 'rails', '~> 3.2.13' + gem 'bcrypt-ruby', '~> 3.0.0' + gem 'jquery-rails' + gem 'sass-rails', '~> 3.2.3' + gem 'coffee-rails', '~> 3.2.1' + gem 'uglifier', '>= 1.0.3' + gem 'minitest', '~> 4.0' + gem 'minitest-reporters' +end + +rails_4 = proc do + instance_eval(&spring) + gem 'uglifier', '>= 1.3.0' + gem 'coffee-rails', '~> 4.0.0' + gem 'jquery-rails' + gem 'turbolinks' + gem 'sdoc' + gem 'activeresource', '4.0.0' + gem 'rspec-rails', '~> 3.0.1' + # Test suite makes heavy use of attr_accessible + gem 'protected_attributes' + gem 'minitest-reporters' +end + +#--- + +if Gem::Requirement.new('< 2').satisfied_by?(ruby_version) + appraise '3.0' do + instance_eval(&rails_3) + gem 'rails', '~> 3.0.17' + end + + if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version) + appraise '3.1-1.9.2' do + instance_eval(&rails_3_1) + gem 'turn', '0.8.2' + end + else + appraise '3.1' do + instance_eval(&rails_3_1) + gem 'turn', '~> 0.8.3' + end + end +end + +if Gem::Requirement.new('= 1.9.2').satisfied_by?(ruby_version) + appraise '3.2-1.9.2' do + instance_eval(&rails_3_2) + end +else + appraise '3.2' do + instance_eval(&rails_3_2) + instance_eval(&spring) + end +end + +if Gem::Requirement.new('> 1.9.2').satisfied_by?(ruby_version) + appraise '4.0.0' do + instance_eval(&rails_4) + gem 'rails', '4.0.0' + gem 'jbuilder', '~> 1.2' + gem 'sass-rails', '~> 4.0.0' + gem 'bcrypt-ruby', '~> 3.0.0' + end + + appraise '4.0.1' do + instance_eval(&rails_4) + gem 'rails', '4.0.1' + gem 'jbuilder', '~> 1.2' + gem 'sass-rails', '~> 4.0.0' + gem 'bcrypt-ruby', '~> 3.1.2' + gem 'rspec-rails', '2.99.0' + end + + appraise '4.1' do + instance_eval(&rails_4) + gem 'rails', '~> 4.1.0' + gem 'jbuilder', '~> 2.0' + gem 'sass-rails', '~> 4.0.3' + gem 'sdoc', '~> 0.4.0' + gem 'bcrypt', '~> 3.1.7' + gem 'protected_attributes', "~> 1.0.6" + gem 'spring' + end + + appraise '4.2' do + instance_eval(&rails_4) + gem 'rails', '~> 4.2.0' + gem 'sass-rails', '~> 5.0' + gem 'coffee-rails', '~> 4.1.0' + gem 'jbuilder', '~> 2.0' + gem 'sdoc', '~> 0.4.0' + gem 'bcrypt', '~> 3.1.7' + gem 'byebug' + gem 'web-console', '~> 2.0' + gem 'spring' + gem 'protected_attributes', "~> 1.0.6" + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.autotest ruby-shoulda-matchers-2.8.0/.autotest --- ruby-shoulda-matchers-1.0.0~beta2/.autotest 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.autotest 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -Autotest.add_hook :initialize do |at| - at.add_mapping(%r{^lib/\w.*\.rb}) do - at.files_matching(%r{^test/*/\w.*_test\.rb}) - end - - at.add_mapping(%r{^test/rails_root/\w.*}) do - at.files_matching(%r{^test/*/\w.*_test\.rb}) - end - - at.add_exception(%r{.svn}) - at.add_exception(%r{.log$}) - at.add_exception(%r{^.autotest$}) -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/CONTRIBUTING.md ruby-shoulda-matchers-2.8.0/CONTRIBUTING.md --- ruby-shoulda-matchers-1.0.0~beta2/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/CONTRIBUTING.md 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,25 @@ +We love contributions from the community! Here's a quick guide to making a pull +request: + +1. Fork the repo. + +2. Run the tests. We only take pull requests with passing tests, and it's great +to know that you have a clean slate: `bundle && bundle exec rake` + +3. If you're adding functionality or fixing a bug, add a failing test for the +issue first. + +4. Make the test pass. + +5. If you're adding a new feature, ensure that the documentation is up to date +(see the README for instructions on previewing documentation live). + +6. Finally, push to your fork and submit a pull request. + +At this point you're waiting on us. We try to respond to issues and pull +requests within a few business days. We may suggest some changes to make to your +code to fit with our [code style] or the project style, or discuss alternate +ways of addressing the issue in question. When we're happy with everything, +we'll bring your changes into master. Now you're a contributor! + +[code style]: https://github.com/thoughtbot/guides/tree/master/style diff -Nru ruby-shoulda-matchers-1.0.0~beta2/CONTRIBUTION_GUIDELINES.rdoc ruby-shoulda-matchers-2.8.0/CONTRIBUTION_GUIDELINES.rdoc --- ruby-shoulda-matchers-1.0.0~beta2/CONTRIBUTION_GUIDELINES.rdoc 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/CONTRIBUTION_GUIDELINES.rdoc 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -We're using GitHub[http://github.com/thoughtbot/shoulda/tree/master], and we've been getting any combination of github pull requests, tickets, patches, emails, etc. We need to normalize this workflow to make sure we don't miss any fixes. - -* Make sure you're accessing the source from the {official repository}[http://github.com/thoughtbot/shoulda/tree/master]. -* We prefer git branches over patches, but we can take either. -* If you're using git, please make a branch for each separate contribution. We can cherry pick your commits, but pulling from a branch is easier. -* If you're submitting patches, please cut each fix or feature into a separate patch. -* There should be an issue[http://github.com/thoughtbot/shoulda/issues] for any submission. If you've found a bug and want to fix it, open a new ticket at the same time. -* Please don't send pull requests Just update the issue with the url for your fix (or attach the patch) when it's ready. The github pull requests pretty much get dropped on the floor until someone with commit rights notices them in the mailbox. -* Contributions without tests won't be accepted. The file /test/README explains the testing system pretty thoroughly. - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/cucumber.yml ruby-shoulda-matchers-2.8.0/cucumber.yml --- ruby-shoulda-matchers-1.0.0~beta2/cucumber.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/cucumber.yml 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1 @@ +without_spring: --tags ~@spring diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/changelog ruby-shoulda-matchers-2.8.0/debian/changelog --- ruby-shoulda-matchers-1.0.0~beta2/debian/changelog 2014-04-30 12:06:09.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/changelog 2016-07-15 00:44:31.000000000 +0000 @@ -1,8 +1,30 @@ -ruby-shoulda-matchers (1.0.0~beta2-1build1) utopic; urgency=medium +ruby-shoulda-matchers (2.8.0-1) unstable; urgency=low - * No-change rebuild to update the Ruby-Version attribute. + [ Antonio Terceiro] + * New upstream release (Closes: #709431) + - cannot update to 3.x as ruby-shoulda needs a version strictly smaller + than 3.0 + * Update package with a new `dh-make-ruby -w` run + * Rebuilding makes the binary package provide the needed Rubygems metadata + (Closes: #829691) - -- Matthias Klose Wed, 30 Apr 2014 12:06:09 +0000 + [ Cédric Boutillier ] + * copyright: change to a working url in Format: field + * debian/control: remove obsolete DM-Upload-Allowed flag + * use canonical URI in Vcs-* fields + * debian/copyright: use DEP5 copyright-format/1.0 official URL for Format + field + + [ Praveen Arimbrathodiyil ] + * clean log directory too + + [ Cédric Boutillier ] + * Bump debhelper compatibility level to 9 + * Remove version in the gem2deb build-dependency + * Use https:// in Vcs-* fields + * Run wrap-and-sort on packaging files + + -- Antonio Terceiro Thu, 14 Jul 2016 21:44:25 -0300 ruby-shoulda-matchers (1.0.0~beta2-1) unstable; urgency=low diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/compat ruby-shoulda-matchers-2.8.0/debian/compat --- ruby-shoulda-matchers-1.0.0~beta2/debian/compat 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/compat 2016-07-15 00:44:31.000000000 +0000 @@ -1 +1 @@ -7 +9 diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/control ruby-shoulda-matchers-2.8.0/debian/control --- ruby-shoulda-matchers-1.0.0~beta2/debian/control 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/control 2016-07-15 00:44:31.000000000 +0000 @@ -2,20 +2,26 @@ Section: ruby Priority: optional Maintainer: Debian Ruby Extras Maintainers -Uploaders: Antonio Terceiro -DM-Upload-Allowed: yes -Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.2.3), rake -Standards-Version: 3.9.2 -Vcs-Git: git://git.debian.org/pkg-ruby-extras/ruby-shoulda-matchers.git -Vcs-Browser: http://git.debian.org/?p=pkg-ruby-extras/ruby-shoulda-matchers.git;a=summary +Uploaders: Antonio Terceiro +Build-Depends: debhelper (>= 9~), + gem2deb, + rake, + ruby-activesupport (>= 2:3.0.0), + ruby-rspec +Standards-Version: 3.9.8 +Vcs-Git: https://anonscm.debian.org/git/pkg-ruby-extras/ruby-shoulda-matchers.git +Vcs-Browser: https://anonscm.debian.org/cgit/pkg-ruby-extras/ruby-shoulda-matchers.git Homepage: https://github.com/thoughtbot/shoulda-matchers +Testsuite: autopkgtest-pkg-ruby XS-Ruby-Versions: all Package: ruby-shoulda-matchers Architecture: all XB-Ruby-Versions: ${ruby:Versions} -Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter -Conflicts: libshoulda-ruby (<< 3.0.0~beta2-1~), libshoulda-ruby1.8 (<< 3.0.0~beta2-1~) +Depends: ruby | ruby-interpreter, + ruby-activesupport (>= 2:3.0.0), + ${misc:Depends}, + ${shlibs:Depends} Description: Test helpers for Rails applications, compatible with Test::Unit and RSpec Test::Unit- and RSpec-compatible one-liners that test common Rails functionality. These tests would otherwise be much longer, more complex, and diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/copyright ruby-shoulda-matchers-2.8.0/debian/copyright --- ruby-shoulda-matchers-1.0.0~beta2/debian/copyright 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/copyright 2016-07-15 00:44:31.000000000 +0000 @@ -1,12 +1,18 @@ -Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=173 +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: shoulda-matchers Source: https://github.com/thoughtbot/shoulda-matchers +Files-Excluded: doc_config Files: * Copyright: - © 2007, Tammer Saleh, Thoughtbot, Inc. - © 2006-2010 thoughtbot, inc. -License: MIT + © 2006-2014 thoughtbot, Thoughtbot, Inc. +License: Expat + +Files: debian/* +Copyright: Copyright © 2011-2016 Antonio Terceiro +License: Expat + +License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without @@ -27,70 +33,3 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Files: - spec/rails3_root/public/javascripts/controls.js - spec/rails3_root/public/javascripts/dragdrop.js - spec/rails3_root/public/javascripts/effects.js -Copyright: - © 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) - © 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan) - © 2005-2009 Jon Tirsen (http://www.tirsen.com) -License: MIT - script.aculo.us is freely distributable under the terms of an mit-style license. - for details, see the script.aculo.us web site: http://script.aculo.us/ -Comment: - The website (http://script.aculo.us/) points to - http://madrobby.github.com/scriptaculous/license/, which as of June 9th, 2011, - reads: - . - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - “Software”), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - . - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - . - THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Files: - spec/rails3_root/public/javascripts/prototype.js -Copyright: - © 2005-2009 Sam Stephenson -License: MIT - Prototype is freely distributable under the terms of an MIT-style license. - For details, see the Prototype web site: http://www.prototypejs.org/ -Comment: - The website at http://www.prototypejs.org/ points at - https://raw.github.com/sstephenson/prototype/master/LICENSE, which as of Juen - 9th, 2011, reads: - . - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - . - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - -Files: debian/* -Copyright: Copyright © 2011 Antonio Terceiro -License: - The same as the original package. diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/ruby-shoulda-matchers.docs ruby-shoulda-matchers-2.8.0/debian/ruby-shoulda-matchers.docs --- ruby-shoulda-matchers-1.0.0~beta2/debian/ruby-shoulda-matchers.docs 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/ruby-shoulda-matchers.docs 2016-07-15 00:44:31.000000000 +0000 @@ -1 +1,2 @@ -README.rdoc +CONTRIBUTING.md +README.md diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/ruby-tests.rake ruby-shoulda-matchers-2.8.0/debian/ruby-tests.rake --- ruby-shoulda-matchers-1.0.0~beta2/debian/ruby-tests.rake 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/ruby-tests.rake 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -task :default do - puts "FIXME: tests not running because of missing dependencies" -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/debian/rules ruby-shoulda-matchers-2.8.0/debian/rules --- ruby-shoulda-matchers-1.0.0~beta2/debian/rules 2011-06-09 18:28:28.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/debian/rules 2016-07-15 00:44:31.000000000 +0000 @@ -1,4 +1,10 @@ #!/usr/bin/make -f +export GEM2DEB_TEST_RUNNER = --check-dependencies + %: dh $@ --buildsystem=ruby --with ruby + +clean: + dh clean --buildsystem=ruby --with ruby + rm -rf tmp log diff -Nru ruby-shoulda-matchers-1.0.0~beta2/docs.watchr ruby-shoulda-matchers-2.8.0/docs.watchr --- ruby-shoulda-matchers-1.0.0~beta2/docs.watchr 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/docs.watchr 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,5 @@ +watch('README.md') { system('bundle exec yard doc') } +watch('doc_config/yard/.*') { system('bundle exec yard doc') } +watch('lib/.*\.rb') { system('bundle exec yard doc') } + +# vi: ft=ruby diff -Nru ruby-shoulda-matchers-1.0.0~beta2/features/rails_integration.feature ruby-shoulda-matchers-2.8.0/features/rails_integration.feature --- ruby-shoulda-matchers-1.0.0~beta2/features/rails_integration.feature 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/features/rails_integration.feature 1970-01-01 00:00:00.000000000 +0000 @@ -1,88 +0,0 @@ -@disable-bundler -Feature: integrate with Rails - - Background: - When I generate a new rails application - And I write to "db/migrate/1_create_users.rb" with: - """ - class CreateUsers < ActiveRecord::Migration - def self.up - create_table :users do |t| - t.string :name - end - end - end - """ - When I successfully run "rake db:migrate --trace" - And I write to "app/models/user.rb" with: - """ - class User < ActiveRecord::Base - validates_presence_of :name - end - """ - When I write to "app/controllers/examples_controller.rb" with: - """ - class ExamplesController < ApplicationController - def show - @example = 'hello' - render :nothing => true - end - end - """ - When I configure a wildcard route - - Scenario: generate a rails application and use matchers in Test::Unit - When I configure the application to use shoulda-context - And I configure the application to use "shoulda-matchers" from this project - And I write to "test/unit/user_test.rb" with: - """ - require 'test_helper' - - class UserTest < ActiveSupport::TestCase - should validate_presence_of(:name) - end - """ - When I write to "test/functional/examples_controller_test.rb" with: - """ - require 'test_helper' - - class ExamplesControllerTest < ActionController::TestCase - def setup - get :show - end - - should respond_with(:success) - should assign_to(:example) - end - """ - When I successfully run "rake test TESTOPTS=-v --trace" - Then the output should contain "1 tests, 1 assertions, 0 failures, 0 errors" - And the output should contain "2 tests, 2 assertions, 0 failures, 0 errors" - And the output should contain "User should require name to be set" - And the output should contain "ExamplesController should assign @example" - - Scenario: generate a rails application and use matchers in Rspec - When I configure the application to use rspec-rails - And I configure the application to use "shoulda-matchers" from this project - And I run the rspec generator - And I write to "spec/models/user_spec.rb" with: - """ - require 'spec_helper' - - describe User do - it { should validate_presence_of(:name) } - end - """ - When I write to "spec/controllers/examples_controller_spec.rb" with: - """ - require 'spec_helper' - - describe ExamplesController, "show" do - before { get :show } - it { should assign_to(:example) } - end - """ - When I successfully run "rake spec SPEC_OPTS=-fs --trace" - Then the output should contain "2 examples, 0 failures" - And the output should contain "should require name to be set" - And the output should contain "should assign @example" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/features/step_definitions/rails_steps.rb ruby-shoulda-matchers-2.8.0/features/step_definitions/rails_steps.rb --- ruby-shoulda-matchers-1.0.0~beta2/features/step_definitions/rails_steps.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/features/step_definitions/rails_steps.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze -APP_NAME = 'testapp'.freeze - -When /^I generate a new rails application$/ do - steps %{ - When I run "rails _3.0.3_ new #{APP_NAME}" - And I cd to "#{APP_NAME}" - And I write to "Gemfile" with: - """ - source "http://rubygems.org" - gem 'rails', '3.0.3' - gem 'sqlite3-ruby', :require => 'sqlite3' - """ - And I successfully run "bundle install --local" - } -end - -When /^I configure the application to use "([^\"]+)" from this project$/ do |name| - append_to_gemfile "gem '#{name}', :path => '#{PROJECT_ROOT}'" - steps %{And I run "bundle install --local"} -end - -When /^I run the rspec generator$/ do - steps %{ - When I successfully run "rails generate rspec:install" - } -end - -When /^I configure the application to use rspec\-rails$/ do - append_to_gemfile "gem 'rspec-rails'" - steps %{And I run "bundle install --local"} -end - -When /^I configure the application to use shoulda-context$/ do - append_to_gemfile "gem 'shoulda-context', :git => 'git@github.com:thoughtbot/shoulda-context.git'" - steps %{And I run "bundle install --local"} -end - -When /^I configure a wildcard route$/ do - steps %{ - When I write to "config/routes.rb" with: - """ - Rails.application.routes.draw do - match ':controller(/:action(/:id(.:format)))' - end - """ - } -end - -module AppendHelpers - def append_to(path, contents) - in_current_dir do - File.open(path, "a") do |file| - file.puts - file.puts contents - end - end - end - - def append_to_gemfile(contents) - append_to('Gemfile', contents) - end -end - -World(AppendHelpers) diff -Nru ruby-shoulda-matchers-1.0.0~beta2/features/support/env.rb ruby-shoulda-matchers-2.8.0/features/support/env.rb --- ruby-shoulda-matchers-1.0.0~beta2/features/support/env.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/features/support/env.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -require 'aruba/cucumber' - -Before do - @aruba_timeout_seconds = 15 -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/Gemfile ruby-shoulda-matchers-2.8.0/Gemfile --- ruby-shoulda-matchers-1.0.0~beta2/Gemfile 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/Gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -1,4 +1,28 @@ -source 'http://rubygems.org' +source 'https://rubygems.org' -gemspec +gem 'appraisal', '~> 1.0' +gem 'aruba' +gem 'bourne', '~> 1.3' +gem 'bundler', '~> 1.1' +gem 'pry-nav' +gem 'rails', '~> 3.0' +gem 'rake', '>= 0.9.2' +gem 'rspec-rails', '>= 2.99.0' +# YARD +gem 'yard' +gem 'redcarpet' +gem 'pygments.rb' +gem 'watchr' + +# For test Rails application +gem 'shoulda-context', '~> 1.2.0' +gem 'sqlite3', :platform => :ruby + +# Can't wrap in platform :jruby do...end block because appraisal doesn't +# support it +gem 'activerecord-jdbc-adapter', :platform => :jruby +gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby +gem 'jdbc-sqlite3', :platform => :jruby +gem 'jruby-openssl', :platform => :jruby +gem 'therubyrhino', :platform => :jruby diff -Nru ruby-shoulda-matchers-1.0.0~beta2/Gemfile.lock ruby-shoulda-matchers-2.8.0/Gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/Gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/Gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,164 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.16) + actionpack (= 3.2.16) + mail (~> 2.5.4) + actionpack (3.2.16) + activemodel (= 3.2.16) + activesupport (= 3.2.16) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.5) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.16) + activesupport (= 3.2.16) + builder (~> 3.0.0) + activerecord (3.2.16) + activemodel (= 3.2.16) + activesupport (= 3.2.16) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.16) + activemodel (= 3.2.16) + activesupport (= 3.2.16) + activesupport (3.2.16) + i18n (~> 0.6, >= 0.6.4) + multi_json (~> 1.0) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (3.0.3) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.0.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hike (1.2.3) + i18n (0.6.11) + journey (1.0.4) + json (1.8.1) + mail (2.5.4) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.25.1) + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.3.7) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.4.5) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.4) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.16) + actionmailer (= 3.2.16) + actionpack (= 3.2.16) + activerecord (= 3.2.16) + activeresource (= 3.2.16) + activesupport (= 3.2.16) + bundler (~> 1.0) + railties (= 3.2.16) + railties (3.2.16) + actionpack (= 3.2.16) + activesupport (= 3.2.16) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.0.0) + rspec-core (3.0.3) + rspec-support (~> 3.0.0) + rspec-expectations (3.0.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.0.0) + rspec-mocks (3.0.3) + rspec-support (~> 3.0.0) + rspec-rails (3.0.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.0.0) + rspec-expectations (~> 3.0.0) + rspec-mocks (~> 3.0.0) + rspec-support (~> 3.0.0) + rspec-support (3.0.3) + shoulda-context (1.2.0) + slop (3.6.0) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.8) + thor (0.19.1) + tilt (1.4.1) + treetop (1.4.15) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.38) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bourne (~> 1.3) + bundler (~> 1.1) + jdbc-sqlite3 + jruby-openssl + pry-nav + pygments.rb + rails (~> 3.0) + rake (>= 0.9.2) + redcarpet + rspec-rails (>= 2.99.0) + shoulda-context (~> 1.2.0) + sqlite3 + therubyrhino + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.0.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.0.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,26 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 3.0.17" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "strong_parameters" +gem "minitest", "~> 4.0" +gem "minitest-reporters" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.0.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.0.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,173 @@ +GEM + remote: https://rubygems.org/ + specs: + abstract (1.0.0) + actionmailer (3.0.20) + actionpack (= 3.0.20) + mail (~> 2.2.19) + actionpack (3.0.20) + activemodel (= 3.0.20) + activesupport (= 3.0.20) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.5.0) + rack (~> 1.2.5) + rack-mount (~> 0.6.14) + rack-test (~> 0.5.7) + tzinfo (~> 0.3.23) + activemodel (3.0.20) + activesupport (= 3.0.20) + builder (~> 2.1.2) + i18n (~> 0.5.0) + activerecord (3.0.20) + activemodel (= 3.0.20) + activesupport (= 3.0.20) + arel (~> 2.0.10) + tzinfo (~> 0.3.23) + activeresource (3.0.20) + activemodel (= 3.0.20) + activesupport (= 3.0.20) + activesupport (3.0.20) + ansi (1.4.3) + appraisal (1.0.0) + bundler + rake + thor (>= 0.14.0) + arel (2.0.10) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bourne (1.4.0) + mocha (~> 0.13.2) + builder (2.1.2) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.6.6) + abstract (>= 1.0.0) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + i18n (0.5.4) + json (1.8.1) + mail (2.2.19) + activesupport (>= 2.3.6) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.21) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.13.3) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.2.8) + rack-mount (0.6.14) + rack (>= 1.0.0) + rack-test (0.5.7) + rack (>= 1.0) + rails (3.0.20) + actionmailer (= 3.0.20) + actionpack (= 3.0.20) + activerecord (= 3.0.20) + activeresource (= 3.0.20) + activesupport (= 3.0.20) + bundler (~> 1.0) + railties (= 3.0.20) + railties (3.0.20) + actionpack (= 3.0.20) + activesupport (= 3.0.20) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.4) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + shoulda-context (1.2.0) + slop (3.6.0) + sqlite3 (1.3.7) + strong_parameters (0.2.0) + actionpack (~> 3.0) + activemodel (~> 3.0) + railties (~> 3.0) + thor (0.14.6) + treetop (1.4.12) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.41) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bourne (~> 1.3) + bundler (~> 1.1) + jdbc-sqlite3 + jruby-openssl + minitest (~> 4.0) + minitest-reporters + pry-nav + pygments.rb + rails (~> 3.0.17) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + shoulda-context (~> 1.2.0) + sqlite3 + strong_parameters + therubyrhino + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1_1.9.2.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1_1.9.2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,32 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 3.1.8" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "strong_parameters" +gem "minitest", "~> 4.0" +gem "minitest-reporters" +gem "bcrypt-ruby", "~> 3.0.0" +gem "jquery-rails" +gem "sass-rails", "~> 3.1.5" +gem "coffee-rails", "~> 3.1.1" +gem "uglifier", ">= 1.0.3" +gem "turn", "0.8.2" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1_1.9.2.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1_1.9.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.1_1.9.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,212 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.1.11) + actionpack (= 3.1.11) + mail (~> 2.3.3) + actionpack (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + builder (~> 3.0.0) + erubis (~> 2.7.0) + i18n (~> 0.6) + rack (~> 1.3.6) + rack-cache (~> 1.2) + rack-mount (~> 0.8.2) + rack-test (~> 0.6.1) + sprockets (~> 2.0.4) + activemodel (3.1.11) + activesupport (= 3.1.11) + builder (~> 3.0.0) + i18n (~> 0.6) + activerecord (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + arel (~> 2.2.3) + tzinfo (~> 0.3.29) + activeresource (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + activesupport (3.1.11) + multi_json (~> 1.0) + ansi (1.4.3) + appraisal (1.0.0) + bundler + rake + thor (>= 0.14.0) + arel (2.2.3) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.0.1) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.0.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (3.1.1) + coffee-script (>= 2.2.0) + railties (~> 3.1.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.11) + jquery-rails (2.2.1) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.3.3) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.25.1) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.3.10) + rack-cache (1.2) + rack (>= 0.4) + rack-mount (0.8.3) + rack (>= 1.0.0) + rack-ssl (1.3.4) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.1.11) + actionmailer (= 3.1.11) + actionpack (= 3.1.11) + activerecord (= 3.1.11) + activeresource (= 3.1.11) + activesupport (= 3.1.11) + bundler (~> 1.0) + railties (= 3.1.11) + railties (3.1.11) + actionpack (= 3.1.11) + activesupport (= 3.1.11) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.6) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + sass (3.2.12) + sass-rails (3.1.6) + actionpack (~> 3.1.0) + railties (~> 3.1.0) + sass (>= 3.1.10) + tilt (~> 1.3.2) + shoulda-context (1.2.0) + slop (3.6.0) + sprockets (2.0.4) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.8) + strong_parameters (0.2.0) + actionpack (~> 3.0) + activemodel (~> 3.0) + railties (~> 3.0) + thor (0.14.6) + tilt (1.3.7) + treetop (1.4.15) + polyglot + polyglot (>= 0.3.1) + turn (0.8.2) + ansi (>= 1.2.2) + tzinfo (0.3.38) + uglifier (2.5.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.0.0) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 3.1.1) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest (~> 4.0) + minitest-reporters + pry-nav + pygments.rb + rails (~> 3.1.8) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + sass-rails (~> 3.1.5) + shoulda-context (~> 1.2.0) + sqlite3 + strong_parameters + therubyrhino + turn (= 0.8.2) + uglifier (>= 1.0.3) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,32 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 3.1.8" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "strong_parameters" +gem "minitest", "~> 4.0" +gem "minitest-reporters" +gem "bcrypt-ruby", "~> 3.0.0" +gem "jquery-rails" +gem "sass-rails", "~> 3.1.5" +gem "coffee-rails", "~> 3.1.1" +gem "uglifier", ">= 1.0.3" +gem "turn", "~> 0.8.3" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,212 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.1.11) + actionpack (= 3.1.11) + mail (~> 2.3.3) + actionpack (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + builder (~> 3.0.0) + erubis (~> 2.7.0) + i18n (~> 0.6) + rack (~> 1.3.6) + rack-cache (~> 1.2) + rack-mount (~> 0.8.2) + rack-test (~> 0.6.1) + sprockets (~> 2.0.4) + activemodel (3.1.11) + activesupport (= 3.1.11) + builder (~> 3.0.0) + i18n (~> 0.6) + activerecord (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + arel (~> 2.2.3) + tzinfo (~> 0.3.29) + activeresource (3.1.11) + activemodel (= 3.1.11) + activesupport (= 3.1.11) + activesupport (3.1.11) + multi_json (~> 1.0) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (2.2.3) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.0.1) + bourne (1.4.0) + mocha (~> 0.13.2) + builder (3.0.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (3.1.1) + coffee-script (>= 2.2.0) + railties (~> 3.1.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.11) + jquery-rails (2.2.1) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.3.3) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.21) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.13.3) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.3.10) + rack-cache (1.2) + rack (>= 0.4) + rack-mount (0.8.3) + rack (>= 1.0.0) + rack-ssl (1.3.4) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.1.11) + actionmailer (= 3.1.11) + actionpack (= 3.1.11) + activerecord (= 3.1.11) + activeresource (= 3.1.11) + activesupport (= 3.1.11) + bundler (~> 1.0) + railties (= 3.1.11) + railties (3.1.11) + actionpack (= 3.1.11) + activesupport (= 3.1.11) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (~> 0.14.6) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + sass (3.2.7) + sass-rails (3.1.6) + actionpack (~> 3.1.0) + railties (~> 3.1.0) + sass (>= 3.1.10) + tilt (~> 1.3.2) + shoulda-context (1.2.0) + slop (3.6.0) + sprockets (2.0.4) + hike (~> 1.2) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.7) + strong_parameters (0.2.0) + actionpack (~> 3.0) + activemodel (~> 3.0) + railties (~> 3.0) + thor (0.14.6) + tilt (1.3.7) + treetop (1.4.12) + polyglot + polyglot (>= 0.3.1) + turn (0.8.3) + ansi + tzinfo (0.3.37) + uglifier (2.2.1) + execjs (>= 0.3.0) + multi_json (~> 1.0, >= 1.0.2) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.0.0) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 3.1.1) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest (~> 4.0) + minitest-reporters + pry-nav + pygments.rb + rails (~> 3.1.8) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + sass-rails (~> 3.1.5) + shoulda-context (~> 1.2.0) + sqlite3 + strong_parameters + therubyrhino + turn (~> 0.8.3) + uglifier (>= 1.0.3) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2_1.9.2.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2_1.9.2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,31 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 3.2.13" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "strong_parameters" +gem "minitest", "~> 4.0" +gem "minitest-reporters" +gem "bcrypt-ruby", "~> 3.0.0" +gem "jquery-rails" +gem "sass-rails", "~> 3.2.3" +gem "coffee-rails", "~> 3.2.1" +gem "uglifier", ">= 1.0.3" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2_1.9.2.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2_1.9.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.2_1.9.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,207 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.18) + actionpack (= 3.2.18) + mail (~> 2.5.4) + actionpack (3.2.18) + activemodel (= 3.2.18) + activesupport (= 3.2.18) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.5) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.18) + activesupport (= 3.2.18) + builder (~> 3.0.0) + activerecord (3.2.18) + activemodel (= 3.2.18) + activesupport (= 3.2.18) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.18) + activemodel (= 3.2.18) + activesupport (= 3.2.18) + activesupport (3.2.18) + i18n (~> 0.6, >= 0.6.4) + multi_json (~> 1.0) + ansi (1.4.3) + appraisal (1.0.0) + bundler + rake + thor (>= 0.14.0) + arel (3.0.3) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.0.1) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.0.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.2.0) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.11) + journey (1.0.4) + jquery-rails (3.1.0) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.5.4) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.4) + method_source (0.8.2) + mime-types (1.25.1) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.5) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.4.5) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.4) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.18) + actionmailer (= 3.2.18) + actionpack (= 3.2.18) + activerecord (= 3.2.18) + activeresource (= 3.2.18) + activesupport (= 3.2.18) + bundler (~> 1.0) + railties (= 3.2.18) + railties (3.2.18) + actionpack (= 3.2.18) + activesupport (= 3.2.18) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + sass (3.3.8) + sass-rails (3.2.6) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + shoulda-context (1.2.1) + slop (3.6.0) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.9) + strong_parameters (0.2.3) + actionpack (~> 3.0) + activemodel (~> 3.0) + activesupport (~> 3.0) + railties (~> 3.0) + thor (0.19.1) + tilt (1.4.1) + treetop (1.4.15) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.39) + uglifier (2.5.1) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.4) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.0.0) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 3.2.1) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest (~> 4.0) + minitest-reporters + pry-nav + pygments.rb + rails (~> 3.2.13) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + sass-rails (~> 3.2.3) + shoulda-context (~> 1.2.0) + sqlite3 + strong_parameters + therubyrhino + uglifier (>= 1.0.3) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,33 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 3.2.13" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "strong_parameters" +gem "minitest", "~> 4.0" +gem "minitest-reporters" +gem "bcrypt-ruby", "~> 3.0.0" +gem "jquery-rails" +gem "sass-rails", "~> 3.2.3" +gem "coffee-rails", "~> 3.2.1" +gem "uglifier", ">= 1.0.3" +gem "spring" +gem "spring-commands-rspec" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/3.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/3.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,212 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.13) + actionpack (= 3.2.13) + mail (~> 2.5.3) + actionpack (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.5) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + activerecord (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + activesupport (3.2.13) + i18n (= 0.6.1) + multi_json (~> 1.0) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (3.0.2) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.0.1) + bourne (1.4.0) + mocha (~> 0.13.2) + builder (3.0.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (3.2.2) + coffee-script (>= 2.2.0) + railties (~> 3.2.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.1) + journey (1.0.4) + jquery-rails (2.2.1) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.5.3) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.21) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.13.3) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.4.5) + rack-cache (1.2) + rack (>= 0.4) + rack-ssl (1.3.4) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.13) + actionmailer (= 3.2.13) + actionpack (= 3.2.13) + activerecord (= 3.2.13) + activeresource (= 3.2.13) + activesupport (= 3.2.13) + bundler (~> 1.0) + railties (= 3.2.13) + railties (3.2.13) + actionpack (= 3.2.13) + activesupport (= 3.2.13) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.3.2) + rdoc (3.12.2) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + sass (3.2.7) + sass-rails (3.2.6) + railties (~> 3.2.0) + sass (>= 3.1.10) + tilt (~> 1.3) + shoulda-context (1.2.0) + slop (3.6.0) + spring (1.1.3) + spring-commands-rspec (1.0.2) + spring (>= 0.9.1) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.7) + strong_parameters (0.2.0) + actionpack (~> 3.0) + activemodel (~> 3.0) + railties (~> 3.0) + thor (0.19.1) + tilt (1.4.1) + treetop (1.4.12) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.37) + uglifier (2.2.1) + execjs (>= 0.3.0) + multi_json (~> 1.0, >= 1.0.2) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.0.0) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 3.2.1) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest (~> 4.0) + minitest-reporters + pry-nav + pygments.rb + rails (~> 3.2.13) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + sass-rails (~> 3.2.3) + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 + strong_parameters + therubyrhino + uglifier (>= 1.0.3) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.0.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.0.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "4.0.0" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "~> 3.0.1" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "spring" +gem "spring-commands-rspec" +gem "uglifier", ">= 1.3.0" +gem "coffee-rails", "~> 4.0.0" +gem "jquery-rails" +gem "turbolinks" +gem "sdoc" +gem "activeresource", "4.0.0" +gem "protected_attributes" +gem "minitest-reporters" +gem "jbuilder", "~> 1.2" +gem "sass-rails", "~> 4.0.0" +gem "bcrypt-ruby", "~> 3.0.0" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.0.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.0.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.0.0.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,223 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.0.0) + actionpack (= 4.0.0) + mail (~> 2.5.3) + actionpack (4.0.0) + activesupport (= 4.0.0) + builder (~> 3.1.0) + erubis (~> 2.7.0) + rack (~> 1.5.2) + rack-test (~> 0.6.2) + activemodel (4.0.0) + activesupport (= 4.0.0) + builder (~> 3.1.0) + activerecord (4.0.0) + activemodel (= 4.0.0) + activerecord-deprecated_finders (~> 1.0.2) + activesupport (= 4.0.0) + arel (~> 4.0.0) + activerecord-deprecated_finders (1.0.3) + activeresource (4.0.0) + activemodel (~> 4.0) + activesupport (~> 4.0) + rails-observers (~> 0.1.1) + activesupport (4.0.0) + i18n (~> 0.6, >= 0.6.4) + minitest (~> 4.2) + multi_json (~> 1.3) + thread_safe (~> 0.1) + tzinfo (~> 0.3.37) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (4.0.2) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.0.1) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.1.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (4.0.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.11) + jbuilder (1.5.3) + activesupport (>= 3.0.0) + multi_json (>= 1.2.0) + jquery-rails (3.0.4) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.5.4) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.25.1) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.5) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + protected_attributes (1.0.3) + activemodel (>= 4.0.0, < 5.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.5.2) + rack-test (0.6.2) + rack (>= 1.0) + rails (4.0.0) + actionmailer (= 4.0.0) + actionpack (= 4.0.0) + activerecord (= 4.0.0) + activesupport (= 4.0.0) + bundler (>= 1.3.0, < 2.0) + railties (= 4.0.0) + sprockets-rails (~> 2.0.0) + rails-observers (0.1.2) + activemodel (~> 4.0) + railties (4.0.0) + actionpack (= 4.0.0) + activesupport (= 4.0.0) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (10.3.2) + rdoc (4.1.1) + json (~> 1.4) + redcarpet (3.1.2) + rspec-core (3.0.3) + rspec-support (~> 3.0.0) + rspec-expectations (3.0.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.0.0) + rspec-mocks (3.0.3) + rspec-support (~> 3.0.0) + rspec-rails (3.0.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.0.0) + rspec-expectations (~> 3.0.0) + rspec-mocks (~> 3.0.0) + rspec-support (~> 3.0.0) + rspec-support (3.0.3) + sass (3.2.19) + sass-rails (4.0.3) + railties (>= 4.0.0, < 5.0) + sass (~> 3.2.0) + sprockets (~> 2.8, <= 2.11.0) + sprockets-rails (~> 2.0) + sdoc (0.4.0) + json (~> 1.8) + rdoc (~> 4.0, < 5.0) + shoulda-context (1.2.0) + slop (3.6.0) + spring (1.1.3) + spring-commands-rspec (1.0.2) + spring (>= 0.9.1) + sprockets (2.11.0) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-rails (2.0.1) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (~> 2.8) + sqlite3 (1.3.8) + thor (0.19.1) + thread_safe (0.3.4) + tilt (1.4.1) + treetop (1.4.15) + polyglot + polyglot (>= 0.3.1) + turbolinks (2.2.2) + coffee-rails + tzinfo (0.3.41) + uglifier (2.5.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + activeresource (= 4.0.0) + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.0.0) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 4.0.0) + jbuilder (~> 1.2) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest-reporters + protected_attributes + pry-nav + pygments.rb + rails (= 4.0.0) + rake (>= 0.9.2) + redcarpet + rspec-rails (~> 3.0.1) + sass-rails (~> 4.0.0) + sdoc + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 + therubyrhino + turbolinks + uglifier (>= 1.3.0) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.1.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.1.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "4.0.1" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "2.99.0" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "spring" +gem "spring-commands-rspec" +gem "uglifier", ">= 1.3.0" +gem "coffee-rails", "~> 4.0.0" +gem "jquery-rails" +gem "turbolinks" +gem "sdoc" +gem "activeresource", "4.0.0" +gem "protected_attributes" +gem "minitest-reporters" +gem "jbuilder", "~> 1.2" +gem "sass-rails", "~> 4.0.0" +gem "bcrypt-ruby", "~> 3.1.2" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.1.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.0.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.0.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,221 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.0.1) + actionpack (= 4.0.1) + mail (~> 2.5.4) + actionpack (4.0.1) + activesupport (= 4.0.1) + builder (~> 3.1.0) + erubis (~> 2.7.0) + rack (~> 1.5.2) + rack-test (~> 0.6.2) + activemodel (4.0.1) + activesupport (= 4.0.1) + builder (~> 3.1.0) + activerecord (4.0.1) + activemodel (= 4.0.1) + activerecord-deprecated_finders (~> 1.0.2) + activesupport (= 4.0.1) + arel (~> 4.0.0) + activerecord-deprecated_finders (1.0.3) + activeresource (4.0.0) + activemodel (~> 4.0) + activesupport (~> 4.0) + rails-observers (~> 0.1.1) + activesupport (4.0.1) + i18n (~> 0.6, >= 0.6.4) + minitest (~> 4.2) + multi_json (~> 1.3) + thread_safe (~> 0.1) + tzinfo (~> 0.3.37) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (4.0.1) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt-ruby (3.1.2) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.1.4) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (4.0.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hashie (3.3.1) + hike (1.2.3) + i18n (0.6.11) + jbuilder (1.5.3) + activesupport (>= 3.0.0) + multi_json (>= 1.2.0) + jquery-rails (3.0.4) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.5.4) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + method_source (0.8.2) + mime-types (1.25.1) + minitest (4.7.5) + minitest-reporters (0.14.24) + ansi + builder + minitest (>= 2.12, < 5.0) + powerbar + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + polyglot (0.3.3) + posix-spawn (0.3.8) + powerbar (1.0.11) + ansi (~> 1.4.0) + hashie (>= 1.1.0) + protected_attributes (1.0.5) + activemodel (>= 4.0.1, < 5.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.5.2) + rack-test (0.6.2) + rack (>= 1.0) + rails (4.0.1) + actionmailer (= 4.0.1) + actionpack (= 4.0.1) + activerecord (= 4.0.1) + activesupport (= 4.0.1) + bundler (>= 1.3.0, < 2.0) + railties (= 4.0.1) + sprockets-rails (~> 2.0.0) + rails-observers (0.1.2) + activemodel (~> 4.0) + railties (4.0.1) + actionpack (= 4.0.1) + activesupport (= 4.0.1) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (10.3.2) + rdoc (4.1.1) + json (~> 1.4) + redcarpet (3.1.2) + rspec-collection_matchers (1.0.0) + rspec-expectations (>= 2.99.0.beta1) + rspec-core (2.99.1) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-rails (2.99.0) + actionpack (>= 3.0) + activemodel (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-collection_matchers + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + sass (3.2.12) + sass-rails (4.0.1) + railties (>= 4.0.0, < 5.0) + sass (>= 3.1.10) + sprockets-rails (~> 2.0.0) + sdoc (0.4.0) + json (~> 1.8) + rdoc (~> 4.0, < 5.0) + shoulda-context (1.2.0) + slop (3.6.0) + spring (1.1.3) + spring-commands-rspec (1.0.2) + spring (>= 0.9.1) + sprockets (2.10.1) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-rails (2.0.1) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (~> 2.8) + sqlite3 (1.3.8) + thor (0.19.1) + thread_safe (0.3.4) + tilt (1.4.1) + treetop (1.4.15) + polyglot + polyglot (>= 0.3.1) + turbolinks (2.2.2) + coffee-rails + tzinfo (0.3.41) + uglifier (2.5.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + activeresource (= 4.0.0) + appraisal (~> 1.0) + aruba + bcrypt-ruby (~> 3.1.2) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 4.0.0) + jbuilder (~> 1.2) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest-reporters + protected_attributes + pry-nav + pygments.rb + rails (= 4.0.1) + rake (>= 0.9.2) + redcarpet + rspec-rails (= 2.99.0) + sass-rails (~> 4.0.0) + sdoc + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 + therubyrhino + turbolinks + uglifier (>= 1.3.0) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.1.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.1.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 4.1.0" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "~> 3.0.1" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "spring" +gem "spring-commands-rspec" +gem "uglifier", ">= 1.3.0" +gem "coffee-rails", "~> 4.0.0" +gem "jquery-rails" +gem "turbolinks" +gem "sdoc", "~> 0.4.0" +gem "activeresource", "4.0.0" +gem "protected_attributes", "~> 1.0.6" +gem "minitest-reporters" +gem "jbuilder", "~> 2.0" +gem "sass-rails", "~> 4.0.3" +gem "bcrypt", "~> 3.1.7" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.1.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.1.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.1.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,220 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.1.7) + actionpack (= 4.1.7) + actionview (= 4.1.7) + mail (~> 2.5, >= 2.5.4) + actionpack (4.1.7) + actionview (= 4.1.7) + activesupport (= 4.1.7) + rack (~> 1.5.2) + rack-test (~> 0.6.2) + actionview (4.1.7) + activesupport (= 4.1.7) + builder (~> 3.1) + erubis (~> 2.7.0) + activemodel (4.1.7) + activesupport (= 4.1.7) + builder (~> 3.1) + activerecord (4.1.7) + activemodel (= 4.1.7) + activesupport (= 4.1.7) + arel (~> 5.0.0) + activeresource (4.0.0) + activemodel (~> 4.0) + activesupport (~> 4.0) + rails-observers (~> 0.1.1) + activesupport (4.1.7) + i18n (~> 0.6, >= 0.6.9) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.1) + tzinfo (~> 1.1) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (5.0.1.20140414130214) + aruba (0.6.0) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt (3.1.7) + bourne (1.5.0) + mocha (>= 0.13.2, < 0.15) + builder (3.2.2) + childprocess (0.5.3) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (4.0.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.0) + coffee-script (2.2.0) + coffee-script-source + execjs + coffee-script-source (1.7.0) + cucumber (1.3.16) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.0.2) + ffi (1.9.3) + gherkin (2.12.2) + multi_json (~> 1.3) + hike (1.2.3) + i18n (0.6.11) + jbuilder (2.0.6) + activesupport (>= 3.0.0, < 5) + multi_json (~> 1.2) + jquery-rails (3.1.0) + railties (>= 3.0, < 5.0) + thor (>= 0.14, < 2.0) + json (1.8.1) + mail (2.6.3) + mime-types (>= 1.16, < 3) + metaclass (0.0.2) + method_source (0.8.2) + mime-types (2.4.3) + minitest (5.4.2) + minitest-reporters (1.0.5) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + mocha (0.14.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + posix-spawn (0.3.8) + protected_attributes (1.0.7) + activemodel (>= 4.0.1, < 5.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.5.2) + rack-test (0.6.2) + rack (>= 1.0) + rails (4.1.7) + actionmailer (= 4.1.7) + actionpack (= 4.1.7) + actionview (= 4.1.7) + activemodel (= 4.1.7) + activerecord (= 4.1.7) + activesupport (= 4.1.7) + bundler (>= 1.3.0, < 2.0) + railties (= 4.1.7) + sprockets-rails (~> 2.0) + rails-observers (0.1.2) + activemodel (~> 4.0) + railties (4.1.7) + actionpack (= 4.1.7) + activesupport (= 4.1.7) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (10.3.2) + rdoc (4.1.1) + json (~> 1.4) + redcarpet (3.1.2) + rspec-core (3.0.3) + rspec-support (~> 3.0.0) + rspec-expectations (3.0.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.0.0) + rspec-mocks (3.0.3) + rspec-support (~> 3.0.0) + rspec-rails (3.0.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.0.0) + rspec-expectations (~> 3.0.0) + rspec-mocks (~> 3.0.0) + rspec-support (~> 3.0.0) + rspec-support (3.0.3) + ruby-progressbar (1.5.1) + sass (3.2.19) + sass-rails (4.0.3) + railties (>= 4.0.0, < 5.0) + sass (~> 3.2.0) + sprockets (~> 2.8, <= 2.11.0) + sprockets-rails (~> 2.0) + sdoc (0.4.0) + json (~> 1.8) + rdoc (~> 4.0, < 5.0) + shoulda-context (1.2.0) + slop (3.6.0) + spring (1.1.2) + spring-commands-rspec (1.0.2) + spring (>= 0.9.1) + sprockets (2.11.0) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-rails (2.2.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (>= 2.8, < 4.0) + sqlite3 (1.3.9) + thor (0.19.1) + thread_safe (0.3.4) + tilt (1.4.1) + turbolinks (2.2.2) + coffee-rails + tzinfo (1.2.2) + thread_safe (~> 0.1) + uglifier (2.5.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + yajl-ruby (1.1.0) + yard (0.8.7.3) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + activeresource (= 4.0.0) + appraisal (~> 1.0) + aruba + bcrypt (~> 3.1.7) + bourne (~> 1.3) + bundler (~> 1.1) + coffee-rails (~> 4.0.0) + jbuilder (~> 2.0) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest-reporters + protected_attributes (~> 1.0.6) + pry-nav + pygments.rb + rails (~> 4.1.0) + rake (>= 0.9.2) + redcarpet + rspec-rails (~> 3.0.1) + sass-rails (~> 4.0.3) + sdoc (~> 0.4.0) + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 + therubyrhino + turbolinks + uglifier (>= 1.3.0) + watchr + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.2.gemfile ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.2.gemfile 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,38 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "~> 1.0" +gem "aruba" +gem "bourne", "~> 1.3" +gem "bundler", "~> 1.1" +gem "pry-nav" +gem "rails", "~> 4.2.0" +gem "rake", ">= 0.9.2" +gem "rspec-rails", "~> 3.0.1" +gem "yard" +gem "redcarpet" +gem "pygments.rb" +gem "watchr" +gem "shoulda-context", "~> 1.2.0" +gem "sqlite3", :platform => :ruby +gem "activerecord-jdbc-adapter", :platform => :jruby +gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby +gem "jdbc-sqlite3", :platform => :jruby +gem "jruby-openssl", :platform => :jruby +gem "therubyrhino", :platform => :jruby +gem "spring" +gem "spring-commands-rspec" +gem "uglifier", ">= 1.3.0" +gem "coffee-rails", "~> 4.1.0" +gem "jquery-rails" +gem "turbolinks" +gem "sdoc", "~> 0.4.0" +gem "activeresource", "4.0.0" +gem "protected_attributes", "~> 1.0.6" +gem "minitest-reporters" +gem "sass-rails", "~> 5.0" +gem "jbuilder", "~> 2.0" +gem "bcrypt", "~> 3.1.7" +gem "byebug" +gem "web-console", "~> 2.0" diff -Nru ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.2.gemfile.lock ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile.lock --- ruby-shoulda-matchers-1.0.0~beta2/gemfiles/4.2.gemfile.lock 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/gemfiles/4.2.gemfile.lock 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,263 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (4.2.0) + actionpack (= 4.2.0) + actionview (= 4.2.0) + activejob (= 4.2.0) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.0) + actionview (= 4.2.0) + activesupport (= 4.2.0) + rack (~> 1.6.0) + rack-test (~> 0.6.2) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.1) + actionview (4.2.0) + activesupport (= 4.2.0) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.1) + activejob (4.2.0) + activesupport (= 4.2.0) + globalid (>= 0.3.0) + activemodel (4.2.0) + activesupport (= 4.2.0) + builder (~> 3.1) + activerecord (4.2.0) + activemodel (= 4.2.0) + activesupport (= 4.2.0) + arel (~> 6.0) + activeresource (4.0.0) + activemodel (~> 4.0) + activesupport (~> 4.0) + rails-observers (~> 0.1.1) + activesupport (4.2.0) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + ansi (1.4.3) + appraisal (1.0.2) + bundler + rake + thor (>= 0.14.0) + arel (6.0.0) + aruba (0.6.1) + childprocess (>= 0.3.6) + cucumber (>= 1.1.1) + rspec-expectations (>= 2.7.0) + bcrypt (3.1.9) + binding_of_caller (0.7.2) + debug_inspector (>= 0.0.1) + bourne (1.6.0) + mocha (~> 1.1) + builder (3.2.2) + byebug (3.5.1) + columnize (~> 0.8) + debugger-linecache (~> 1.2) + slop (~> 3.6) + childprocess (0.5.5) + ffi (~> 1.0, >= 1.0.11) + coderay (1.1.0) + coffee-rails (4.1.0) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.0) + coffee-script (2.3.0) + coffee-script-source + execjs + coffee-script-source (1.8.0) + columnize (0.9.0) + cucumber (1.3.17) + builder (>= 2.1.2) + diff-lcs (>= 1.1.3) + gherkin (~> 2.12) + multi_json (>= 1.7.5, < 2.0) + multi_test (>= 0.1.1) + debug_inspector (0.0.2) + debugger-linecache (1.2.0) + diff-lcs (1.2.5) + erubis (2.7.0) + execjs (2.2.2) + ffi (1.9.6) + gherkin (2.12.2) + multi_json (~> 1.3) + globalid (0.3.0) + activesupport (>= 4.1.0) + hike (1.2.3) + i18n (0.7.0) + jbuilder (2.2.6) + activesupport (>= 3.0.0, < 5) + multi_json (~> 1.2) + jquery-rails (4.0.2) + rails-dom-testing (~> 1.0) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + json (1.8.2) + loofah (2.0.1) + nokogiri (>= 1.5.9) + mail (2.6.3) + mime-types (>= 1.16, < 3) + metaclass (0.0.4) + method_source (0.8.2) + mime-types (2.4.3) + mini_portile (0.6.2) + minitest (5.5.1) + minitest-reporters (1.0.8) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + mocha (1.1.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + multi_test (0.1.1) + nokogiri (1.6.6.1) + mini_portile (~> 0.6.0) + posix-spawn (0.3.9) + protected_attributes (1.0.8) + activemodel (>= 4.0.1, < 5.0) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-nav (0.2.4) + pry (>= 0.9.10, < 0.11.0) + pygments.rb (0.6.0) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rack (1.6.0) + rack-test (0.6.3) + rack (>= 1.0) + rails (4.2.0) + actionmailer (= 4.2.0) + actionpack (= 4.2.0) + actionview (= 4.2.0) + activejob (= 4.2.0) + activemodel (= 4.2.0) + activerecord (= 4.2.0) + activesupport (= 4.2.0) + bundler (>= 1.3.0, < 2.0) + railties (= 4.2.0) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.5) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6.0) + rails-deprecated_sanitizer (>= 1.0.1) + rails-html-sanitizer (1.0.1) + loofah (~> 2.0) + rails-observers (0.1.2) + activemodel (~> 4.0) + railties (4.2.0) + actionpack (= 4.2.0) + activesupport (= 4.2.0) + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (10.4.2) + rdoc (4.2.0) + json (~> 1.4) + redcarpet (3.2.2) + rspec-core (3.0.4) + rspec-support (~> 3.0.0) + rspec-expectations (3.0.4) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.0.0) + rspec-mocks (3.0.4) + rspec-support (~> 3.0.0) + rspec-rails (3.0.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + railties (>= 3.0) + rspec-core (~> 3.0.0) + rspec-expectations (~> 3.0.0) + rspec-mocks (~> 3.0.0) + rspec-support (~> 3.0.0) + rspec-support (3.0.4) + ruby-progressbar (1.7.1) + sass (3.4.9) + sass-rails (5.0.0) + railties (>= 4.0.0, < 5.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (~> 1.1) + sdoc (0.4.1) + json (~> 1.7, >= 1.7.7) + rdoc (~> 4.0) + shoulda-context (1.2.1) + slop (3.6.0) + spring (1.2.0) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + sprockets (2.12.3) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-rails (2.2.2) + actionpack (>= 3.0) + activesupport (>= 3.0) + sprockets (>= 2.8, < 4.0) + sqlite3 (1.3.10) + thor (0.19.1) + thread_safe (0.3.4) + tilt (1.4.1) + turbolinks (2.5.3) + coffee-rails + tzinfo (1.2.2) + thread_safe (~> 0.1) + uglifier (2.6.0) + execjs (>= 0.3.0) + json (>= 1.8.0) + watchr (0.7) + web-console (2.0.0) + activemodel (~> 4.0) + binding_of_caller (>= 0.7.2) + railties (~> 4.0) + sprockets-rails (>= 2.0, < 4.0) + yajl-ruby (1.1.0) + yard (0.8.7.6) + +PLATFORMS + ruby + +DEPENDENCIES + activerecord-jdbc-adapter + activerecord-jdbcsqlite3-adapter + activeresource (= 4.0.0) + appraisal (~> 1.0) + aruba + bcrypt (~> 3.1.7) + bourne (~> 1.3) + bundler (~> 1.1) + byebug + coffee-rails (~> 4.1.0) + jbuilder (~> 2.0) + jdbc-sqlite3 + jquery-rails + jruby-openssl + minitest-reporters + protected_attributes (~> 1.0.6) + pry-nav + pygments.rb + rails (~> 4.2.0) + rake (>= 0.9.2) + redcarpet + rspec-rails (~> 3.0.1) + sass-rails (~> 5.0) + sdoc (~> 0.4.0) + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + sqlite3 + therubyrhino + turbolinks + uglifier (>= 1.3.0) + watchr + web-console (~> 2.0) + yard diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.gitignore ruby-shoulda-matchers-2.8.0/.gitignore --- ruby-shoulda-matchers-1.0.0~beta2/.gitignore 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.gitignore 2015-02-25 02:12:36.000000000 +0000 @@ -1,11 +1,11 @@ -test/*/log/*.log -doc +.bundle +.gh-pages +.thoughtbot-gh-pages +.mcmire-gh-pages +.yardoc coverage -.svn/ +build +doc pkg -*.swp -*.swo -tags +source tmp -.bundle -Gemfile.lock diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.hound_config/ruby.yml ruby-shoulda-matchers-2.8.0/.hound_config/ruby.yml --- ruby-shoulda-matchers-1.0.0~beta2/.hound_config/ruby.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.hound_config/ruby.yml 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,5 @@ +StringLiterals: + EnforcedStyle: single_quotes + +AlignParameters: + EnforcedStyle: with_fixed_indentation diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.hound.yml ruby-shoulda-matchers-2.8.0/.hound.yml --- ruby-shoulda-matchers-1.0.0~beta2/.hound.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.hound.yml 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,3 @@ +ruby: + enabled: true + config_file: .hound_config/ruby.yml diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/assign_to_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/assign_to_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/assign_to_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/assign_to_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActionController # :nodoc: - - # Ensures that the controller assigned to the named instance variable. - # - # Options: - # * with_kind_of - The expected class of the instance variable - # being checked. - # * with - The value that should be assigned. - # - # Example: - # - # it { should assign_to(:user) } - # it { should_not assign_to(:user) } - # it { should assign_to(:user).with_kind_of(User) } - # it { should assign_to(:user).with(@user) } - def assign_to(variable) - AssignToMatcher.new(variable) - end - - class AssignToMatcher # :nodoc: - - def initialize(variable) - @variable = variable.to_s - @check_value = false - end - - def with_kind_of(expected_class) - @expected_class = expected_class - self - end - - def with(expected_value = nil, &block) - @check_value = true - @expected_value = expected_value - @expectation_block = block - self - end - - def matches?(controller) - @controller = controller - @expected_value = @context.instance_eval(&@expectation_block) if @expectation_block - assigned_value? && kind_of_expected_class? && equal_to_expected_value? - end - - attr_reader :failure_message, :negative_failure_message - - def description - description = "assign @#{@variable}" - description << " with a kind of #{@expected_class}" if @expected_class - description - end - - def in_context(context) - @context = context - self - end - - private - - def assigned_value? - if !@controller.instance_variables.map(&:to_s).include?("@#{@variable}") - @failure_message = - "Expected action to assign a value for @#{@variable}" - false - else - @negative_failure_message = - "Didn't expect action to assign a value for @#{@variable}, " << - "but it was assigned to #{assigned_value.inspect}" - true - end - end - - def kind_of_expected_class? - return true unless @expected_class - if assigned_value.kind_of?(@expected_class) - @negative_failure_message = - "Didn't expect action to assign a kind of #{@expected_class} " << - "for #{@variable}, but got one anyway" - true - else - @failure_message = - "Expected action to assign a kind of #{@expected_class} " << - "for #{@variable}, but got #{@variable.inspect} " << - "(#{@variable.class.name})" - false - end - end - - def equal_to_expected_value? - return true unless @check_value - if @expected_value == assigned_value - @negative_failure_message = - "Didn't expect action to assign #{@expected_value.inspect} " << - "for #{@variable}, but got it anyway" - true - else - @failure_message = - "Expected action to assign #{@expected_value.inspect} " << - "for #{@variable}, but got #{assigned_value.inspect}" - false - end - end - - def assigned_value - @controller.instance_variable_get("@#{@variable}") - end - - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/callback_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/callback_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/callback_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/callback_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,196 @@ +module Shoulda + module Matchers + module ActionController + # The `use_before_filter` matcher is used to test that a before_filter + # callback is defined within your controller. + # + # class UsersController < ApplicationController + # before_filter :authenticate_user! + # end + # + # # RSpec + # describe UsersController do + # it { should use_before_filter(:authenticate_user!) } + # it { should_not use_before_filter(:prevent_ssl) } + # end + # + # # Test::Unit + # class UsersControllerTest < ActionController::TestCase + # should use_before_filter(:authenticate_user!) + # should_not use_before_filter(:prevent_ssl) + # end + # + # @return [CallbackMatcher] + # + def use_before_filter(callback) + CallbackMatcher.new(callback, :before, :filter) + end + + # The `use_after_filter` matcher is used to test that an after_filter + # callback is defined within your controller. + # + # class IssuesController < ApplicationController + # after_filter :log_activity + # end + # + # # RSpec + # describe IssuesController do + # it { should use_after_filter(:log_activity) } + # it { should_not use_after_filter(:destroy_user) } + # end + # + # # Test::Unit + # class IssuesControllerTest < ActionController::TestCase + # should use_after_filter(:log_activity) + # should_not use_after_filter(:destroy_user) + # end + # + # @return [CallbackMatcher] + # + def use_after_filter(callback) + CallbackMatcher.new(callback, :after, :filter) + end + + # The `use_before_action` matcher is used to test that a before_action + # callback is defined within your controller. + # + # class UsersController < ApplicationController + # before_action :authenticate_user! + # end + # + # # RSpec + # describe UsersController do + # it { should use_before_action(:authenticate_user!) } + # it { should_not use_before_action(:prevent_ssl) } + # end + # + # # Test::Unit + # class UsersControllerTest < ActionController::TestCase + # should use_before_action(:authenticate_user!) + # should_not use_before_action(:prevent_ssl) + # end + # + # @return [CallbackMatcher] + # + def use_before_action(callback) + CallbackMatcher.new(callback, :before, :action) + end + + # The `use_after_action` matcher is used to test that an after_action + # callback is defined within your controller. + # + # class IssuesController < ApplicationController + # after_action :log_activity + # end + # + # # RSpec + # describe IssuesController do + # it { should use_after_action(:log_activity) } + # it { should_not use_after_action(:destroy_user) } + # end + # + # # Test::Unit + # class IssuesControllerTest < ActionController::TestCase + # should use_after_action(:log_activity) + # should_not use_after_action(:destroy_user) + # end + # + # @return [CallbackMatcher] + # + def use_after_action(callback) + CallbackMatcher.new(callback, :after, :action) + end + + # The `use_around_filter` matcher is used to test that an around_filter + # callback is defined within your controller. + # + # class ChangesController < ApplicationController + # around_filter :wrap_in_transaction + # end + # + # # RSpec + # describe ChangesController do + # it { should use_around_filter(:wrap_in_transaction) } + # it { should_not use_around_filter(:save_view_context) } + # end + # + # # Test::Unit + # class ChangesControllerTest < ActionController::TestCase + # should use_around_filter(:wrap_in_transaction) + # should_not use_around_filter(:save_view_context) + # end + # + # @return [CallbackMatcher] + # + def use_around_filter(callback) + CallbackMatcher.new(callback, :around, :filter) + end + + # The `use_around_action` matcher is used to test that an around_action + # callback is defined within your controller. + # + # class ChangesController < ApplicationController + # around_action :wrap_in_transaction + # end + # + # # RSpec + # describe ChangesController do + # it { should use_around_action(:wrap_in_transaction) } + # it { should_not use_around_action(:save_view_context) } + # end + # + # # Test::Unit + # class ChangesControllerTest < ActionController::TestCase + # should use_around_action(:wrap_in_transaction) + # should_not use_around_action(:save_view_context) + # end + # + # @return [CallbackMatcher] + # + def use_around_action(callback) + CallbackMatcher.new(callback, :around, :action) + end + + # @private + class CallbackMatcher + def initialize(method_name, kind, callback_type) + @method_name = method_name + @kind = kind + @callback_type = callback_type + end + + def matches?(controller) + @controller = controller + @controller_class = controller.class + + callbacks.map(&:filter).include?(method_name) + end + + def failure_message + "Expected that #{controller_class.name} would have :#{method_name} as a #{kind}_#{callback_type}" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Expected that #{controller_class.name} would not have :#{method_name} as a #{kind}_#{callback_type}" + end + alias failure_message_for_should_not failure_message_when_negated + + def description + "have :#{method_name} as a #{kind}_#{callback_type}" + end + + protected + + def callbacks + controller_class._process_action_callbacks.select do |callback| + callback.kind == kind + end + end + + attr_reader :method_name, :controller, :controller_class, :kind, + :callback_type + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/filter_param_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/filter_param_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/filter_param_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,34 +1,49 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures that filter_parameter_logging is set for the specified key. + module ActionController + # The `filter_param` matcher is used to test parameter filtering + # configuration. Specifically, it asserts that the given parameter is + # present in `config.filter_parameters`. + # + # class MyApplication < Rails::Application + # config.filter_parameters << :secret_key + # end + # + # # RSpec + # describe ApplicationController do + # it { should filter_param(:secret_key) } + # end # - # Example: + # # Test::Unit + # class ApplicationControllerTest < ActionController::TestCase + # should filter_param(:secret_key) + # end + # + # @return [FilterParamMatcher] # - # it { should filter_param(:password) } def filter_param(key) FilterParamMatcher.new(key) end - class FilterParamMatcher # :nodoc: - + # @private + class FilterParamMatcher def initialize(key) - @key = key.to_s + @key = key end def matches?(controller) - @controller = controller filters_key? end def failure_message "Expected #{@key} to be filtered; filtered keys: #{filtered_keys.join(', ')}" end + alias failure_message_for_should failure_message - def negative_failure_message + def failure_message_when_negated "Did not expect #{@key} to be filtered" end + alias failure_message_for_should_not failure_message_when_negated def description "filter #{@key}" @@ -37,14 +52,20 @@ private def filters_key? - filtered_keys.include?(@key) + filtered_keys.any? do |filter| + case filter + when Regexp + filter =~ @key + else + filter == @key + end + end end def filtered_keys - Rails.application.config.filter_parameters.map { |filter| filter.to_s } + Rails.application.config.filter_parameters end end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,28 +1,64 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures a controller redirected to the given url. + module ActionController + # The `redirect_to` matcher tests that an action redirects to a certain + # location. In a test suite using RSpec, it is very similar to + # rspec-rails's `redirect_to` matcher. In a test suite using Test::Unit / + # Shoulda, it provides a more expressive syntax over + # `assert_redirected_to`. + # + # class PostsController < ApplicationController + # def show + # redirect_to :index + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #show' do + # before { get :show } + # + # it { should redirect_to(posts_path) } + # it { should redirect_to(action: :index) } + # end + # end # - # Example: + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #show' do + # setup { get :show } + # + # should redirect_to { posts_path } + # should redirect_to(action: :index) + # end + # end + # + # @return [RedirectToMatcher] # - # it { should redirect_to('http://somewhere.com') } - # it { should redirect_to(users_path) } def redirect_to(url_or_description, &block) RedirectToMatcher.new(url_or_description, self, &block) end - class RedirectToMatcher # :nodoc: + # @private + class RedirectToMatcher + attr_reader :failure_message, :failure_message_when_negated + + alias failure_message_for_should failure_message + alias failure_message_for_should_not failure_message_when_negated def initialize(url_or_description, context, &block) + @url_block = nil + @url = nil + @context = context + @failure_message = nil + @failure_message_when_negated = nil + if block @url_block = block @location = url_or_description else - @url = url_or_description - @location = @url + @location = @url = url_or_description end - @context = context end def in_context(context) @@ -35,19 +71,16 @@ redirects_to_url? end - attr_reader :failure_message, :negative_failure_message - def description - "redirect to #{@location}" + "redirect to #{@location.inspect}" end private def redirects_to_url? - @url = @context.instance_eval(&@url_block) if @url_block begin - @context.send(:assert_redirected_to, @url) - @negative_failure_message = "Didn't expect to redirect to #{@url}" + @context.__send__(:assert_redirected_to, url) + @failure_message_when_negated = "Didn't expect to redirect to #{url}" true rescue Shoulda::Matchers::AssertionError => error @failure_message = error.message @@ -55,8 +88,14 @@ end end + def url + if @url_block + @context.instance_eval(&@url_block) + else + @url + end + end end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/render_template_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/render_template_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_template_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,21 +1,62 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures a controller rendered the given template. + module ActionController + # The `render_template` matcher tests that an action renders a template + # or partial. In RSpec, it is very similar to rspec-rails's + # `render_template` matcher. In Test::Unit, it provides a more expressive + # syntax over `assert_template`. + # + # class PostsController < ApplicationController + # def show + # end + # end + # + # # app/views/posts/show.html.erb + # <%= render 'sidebar' %> + # + # # RSpec + # describe PostsController do + # describe 'GET #show' do + # before { get :show } + # + # it { should render_template('show') } + # it { should render_template(partial: 'sidebar') } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #show' do + # setup { get :show } + # + # should render_template('show') + # should render_template(partial: 'sidebar') + # end + # end # - # Example: + # # - # it { should render_template(:show) } - def render_template(template) - RenderTemplateMatcher.new(template, self) + # @return [RenderTemplateMatcher] + # + def render_template(options = {}, message = nil) + RenderTemplateMatcher.new(options, message, self) end - class RenderTemplateMatcher # :nodoc: - - def initialize(template, context) - @template = template.to_s - @context = context + # @private + class RenderTemplateMatcher + attr_reader :failure_message, :failure_message_when_negated + + alias failure_message_for_should failure_message + alias failure_message_for_should_not failure_message_when_negated + + def initialize(options, message, context) + @options = options + @message = message + @template = options.is_a?(Hash) ? options[:partial] : options + @context = context + @controller = nil + @failure_message = nil + @failure_message_when_negated = nil end def matches?(controller) @@ -23,8 +64,6 @@ renders_template? end - attr_reader :failure_message, :negative_failure_message - def description "render template #{@template}" end @@ -38,17 +77,15 @@ def renders_template? begin - @context.send(:assert_template, @template) - @negative_failure_message = "Didn't expect to render #{@template}" + @context.__send__(:assert_template, @options, @message) + @failure_message_when_negated = "Didn't expect to render #{@template}" true rescue Shoulda::Matchers::AssertionError => error @failure_message = error.message false end end - end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,22 +1,76 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures that the controller rendered with the given layout. + module ActionController + # The `render_with_layout` matcher asserts that an action is rendered with + # a particular layout. + # + # class PostsController < ApplicationController + # def show + # render layout: 'posts' + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #show' do + # before { get :show } + # + # it { should render_with_layout('posts') } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #show' do + # setup { get :show } + # + # should render_with_layout('posts') + # end + # end + # + # It can also be used to assert that the action is not rendered with a + # layout at all: + # + # class PostsController < ApplicationController + # def sidebar + # render layout: false + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #sidebar' do + # before { get :sidebar } + # + # it { should_not render_with_layout } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #sidebar' do + # setup { get :sidebar } + # + # should_not render_with_layout + # end + # end # - # Example: + # @return [RenderWithLayoutMatcher] # - # it { should render_with_layout } - # it { should render_with_layout(:special) } - # it { should_not render_with_layout } def render_with_layout(expected_layout = nil) RenderWithLayoutMatcher.new(expected_layout).in_context(self) end - class RenderWithLayoutMatcher # :nodoc: - + # @private + class RenderWithLayoutMatcher def initialize(expected_layout) - @expected_layout = expected_layout.to_s unless expected_layout.nil? + if expected_layout + @expected_layout = expected_layout.to_s + else + @expected_layout = nil + end + + @controller = nil end # Used to provide access to layouts recorded by @@ -34,15 +88,17 @@ def failure_message "Expected #{expectation}, but #{result}" end + alias failure_message_for_should failure_message - def negative_failure_message + def failure_message_when_negated "Did not expect #{expectation}, but #{result}" end + alias failure_message_for_should_not failure_message_when_negated def description - description = "render with " + description = 'render with ' if @expected_layout.nil? - description << "a layout" + description << 'a layout' else description << "the #{@expected_layout.inspect} layout" end @@ -56,26 +112,22 @@ end def rendered_with_expected_layout? - return true if @expected_layout.nil? - rendered_layouts.include?(@expected_layout) + if @expected_layout.nil? + true + else + rendered_layouts.include?(@expected_layout) + end end def rendered_layouts - if recorded_layouts - recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') } - else - layout = @controller.response.layout - if layout.nil? - [] - else - [layout.split('/').last] - end - end + recorded_layouts.keys.compact.map { |layout| layout.sub(%r{^layouts/}, '') } end def recorded_layouts if @context - @context.instance_variable_get('@layouts') + @context.instance_variable_get(Shoulda::Matchers::RailsShim.layouts_ivar) + else + {} end end @@ -85,15 +137,12 @@ def result if rendered_with_layout? - "rendered with " << - rendered_layouts.map { |layout| layout.inspect }.join(", ") + 'rendered with ' + rendered_layouts.map(&:inspect).join(', ') else - "rendered without a layout" + 'rendered without a layout' end end - end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,116 @@ +module Shoulda + module Matchers + module ActionController + # The `rescue_from` matcher tests usage of the `rescue_from` macro. It + # asserts that an exception and method are present in the list of + # exception handlers, and that the handler method exists. + # + # class ApplicationController < ActionController::Base + # rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found + # + # private + # + # def handle_not_found + # # ... + # end + # end + # + # # RSpec + # describe ApplicationController do + # it do + # should rescue_from(ActiveRecord::RecordNotFound). + # with(:handle_not_found) + # end + # end + # + # # Test::Unit + # class ApplicationControllerTest < ActionController::TestCase + # should rescue_from(ActiveRecord::RecordNotFound). + # with(:handle_not_found) + # end + # + # @return [RescueFromMatcher] + # + def rescue_from(exception) + RescueFromMatcher.new exception + end + + # @private + class RescueFromMatcher + def initialize(exception) + @exception = exception + @expected_method = nil + @controller = nil + end + + def with(method) + @expected_method = method + self + end + + def matches?(controller) + @controller = controller + rescues_from_exception? && method_name_matches? && handler_exists? + end + + def description + description = "rescues from #{exception}" + description << " with ##{expected_method}" if expected_method + description + end + + def failure_message + "Expected #{expectation}" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias failure_message_for_should_not failure_message_when_negated + + protected + + attr_reader :controller, :exception, :expected_method, :handlers + + def expectation + expectation = "#{controller} to rescue from #{exception}" + + if expected_method && !method_name_matches? + expectation << " with ##{expected_method}" + end + + unless handler_exists? + expectation << " but #{controller} does not respond to #{expected_method}" + end + expectation + end + + def rescues_from_exception? + @handlers = controller.rescue_handlers.select do |handler| + handler.first == exception.to_s + end + handlers.any? + end + + def method_name_matches? + if expected_method.present? + handlers.any? do |handler| + handler.last == expected_method + end + else + true + end + end + + def handler_exists? + if expected_method.present? + controller.respond_to? expected_method, true + else + true + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_content_type_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActionController # :nodoc: - - # Ensures a controller responded with expected 'response' content type. - # - # You can pass an explicit content type such as 'application/rss+xml' - # or its symbolic equivalent :rss - # or a regular expression such as /rss/ - # - # Example: - # - # it { should respond_with_content_type(:xml) } - # it { should respond_with_content_type(:csv) } - # it { should respond_with_content_type(:atom) } - # it { should respond_with_content_type(:yaml) } - # it { should respond_with_content_type(:text) } - # it { should respond_with_content_type('application/rss+xml') } - # it { should respond_with_content_type(/json/) } - def respond_with_content_type(content_type) - RespondWithContentTypeMatcher.new(content_type) - end - - class RespondWithContentTypeMatcher # :nodoc: - - def initialize(content_type) - @content_type = if content_type.is_a?(Symbol) - lookup_by_extension(content_type) - else - content_type - end - end - - def description - "respond with content type of #{@content_type}" - end - - def matches?(controller) - @controller = controller - if @content_type.is_a?(Regexp) - response_content_type =~ @content_type - else - response_content_type == @content_type - end - end - - def failure_message - "Expected #{expectation}" - end - - def negative_failure_message - "Did not expect #{expectation}" - end - - protected - - def response_content_type - @controller.response.content_type.to_s - end - - def lookup_by_extension(extension) - Mime::Type.lookup_by_extension(extension.to_s).to_s - end - - def expectation - "content type to be #{@content_type}, " << - "but was #{response_content_type}" - end - - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/respond_with_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/respond_with_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/respond_with_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,26 +1,95 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures a controller responded with expected 'response' status code. + module ActionController + # The `respond_with` matcher tests that an action responds with a certain + # status code. + # + # You can specify that the status should be a number: + # + # class PostsController < ApplicationController + # def index + # render status: 403 + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should respond_with(403) } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :index } + # + # should respond_with(403) + # end + # end + # + # You can specify that the status should be within a range of numbers: + # + # class PostsController < ApplicationController + # def destroy + # render status: 508 + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'DELETE #destroy' do + # before { delete :destroy } + # + # it { should respond_with(500..600) } + # end + # end # - # You can pass an explicit status number like 200, 301, 404, 500 - # or its symbolic equivalent :success, :redirect, :missing, :error. - # See ActionController::StatusCodes for a full list. + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'DELETE #destroy' do + # setup { delete :destroy } # - # Example: + # should respond_with(500..600) + # end + # end + # + # Finally, you can specify that the status should be a symbol: + # + # class PostsController < ApplicationController + # def show + # render status: :locked + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #show' do + # before { get :show } + # + # it { should respond_with(:locked) } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #show' do + # setup { get :show } + # + # should respond_with(:locked) + # end + # end + # + # @return [RespondWithMatcher] # - # it { should respond_with(:success) } - # it { should respond_with(:redirect) } - # it { should respond_with(:missing) } - # it { should respond_with(:error) } - # it { should respond_with(501) } def respond_with(status) RespondWithMatcher.new(status) end - class RespondWithMatcher # :nodoc: - + # @private + class RespondWithMatcher def initialize(status) @status = symbol_to_status_code(status) end @@ -33,10 +102,12 @@ def failure_message "Expected #{expectation}" end + alias failure_message_for_should failure_message - def negative_failure_message + def failure_message_when_negated "Did not expect #{expectation}" end + alias failure_message_for_should_not failure_message_when_negated def description "respond with #{@status}" @@ -77,9 +148,7 @@ def expectation "response to be a #{@status}, but was #{response_code}" end - end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/route_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/route_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,42 +1,105 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures that requesting +path+ using +method+ routes to +options+. + module ActionController + # The `route` matcher tests that a route resolves to a controller, + # action, and params; and that the controller, action, and params + # generates the same route. For an RSpec suite, this is like using a + # combination of `route_to` and `be_routable`. For a Test::Unit suite, it + # provides a more expressive syntax over `assert_routing`. + # + # You can use this matcher either in a controller test case or in a + # routing test case. For instance, given these routes: + # + # My::Application.routes.draw do + # get '/posts', controller: 'posts', action: 'index' + # get '/posts/:id' => 'posts#show' + # end + # + # You could choose to write tests for these routes alongside other tests + # for PostsController: + # + # class PostsController < ApplicationController + # # ... + # end + # + # # RSpec + # describe PostsController do + # it { should route(:get, '/posts').to(action: :index) } + # it { should route(:get, '/posts/1').to(action: :show, id: 1) } + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # should route(:get, '/posts').to(action: 'index') + # should route(:get, '/posts/1').to(action: :show, id: 1) + # end + # + # Or you could place the tests along with other route tests: + # + # # RSpec + # describe 'Routing' do + # it do + # should route(:get, '/posts'). + # to(controller: :posts, action: :index) + # end + # + # it do + # should route(:get, '/posts/1'). + # to('posts#show', id: 1) + # end + # end + # + # # Test::Unit + # class RoutesTest < ActionController::IntegrationTest + # should route(:get, '/posts'). + # to(controller: :posts, action: :index) + # + # should route(:get, '/posts/1'). + # to('posts#show', id: 1) + # end + # + # Notice that in the former case, as we are inside of a test case for + # PostsController, we do not have to specify that the routes resolve to + # this controller. In the latter case we specify this using the + # `controller` key passed to the `to` qualifier. # - # If you don't specify a controller, it will use the controller from the - # example group. + # #### Qualifiers # - # +to_param+ is called on the +options+ given. + # ##### to + # + # Use `to` to specify the action (along with the controller, if needed) + # that the route resolves to. + # + # # Three ways of saying the same thing (using the example above) + # route(:get, '/posts').to(action: index) + # route(:get, '/posts').to(controller: :posts, action: index) + # route(:get, '/posts').to('posts#index') + # + # If there are parameters in your route, then specify those too: + # + # route(:get, '/posts/1').to('posts#show', id: 1) + # + # @return [RouteMatcher] # - # Examples: - # - # it { should route(:get, "/posts"). - # to(:controller => :posts, :action => :index) } - # it { should route(:get, "/posts/new").to(:action => :new) } - # it { should route(:post, "/posts").to(:action => :create) } - # it { should route(:get, "/posts/1").to(:action => :show, :id => 1) } - # it { should route(:edit, "/posts/1").to(:action => :show, :id => 1) } - # it { should route(:put, "/posts/1").to(:action => :update, :id => 1) } - # it { should route(:delete, "/posts/1"). - # to(:action => :destroy, :id => 1) } - # it { should route(:get, "/users/1/posts/1"). - # to(:action => :show, :id => 1, :user_id => 1) } def route(method, path) RouteMatcher.new(method, path, self) end - class RouteMatcher # :nodoc: - + # @private + class RouteMatcher def initialize(method, path, context) @method = method @path = path @context = context end - def to(params) - @params = params - stringify_params! + attr_reader :failure_message, :failure_message_when_negated + + alias failure_message_for_should failure_message + alias failure_message_for_should_not failure_message_when_negated + + def to(*args) + @params = RouteParams.new(args).normalize self end @@ -46,36 +109,28 @@ end def matches?(controller) - @controller = controller - guess_controller! + guess_controller!(controller) route_recognized? end - attr_reader :failure_message, :negative_failure_message - def description "route #{@method.to_s.upcase} #{@path} to/from #{@params.inspect}" end private - def guess_controller! - @params[:controller] ||= @controller.controller_path + def guess_controller!(controller) + @params[:controller] ||= controller.controller_path end - def stringify_params! - @params.each do |key, value| - @params[key] = value.is_a?(Array) ? value.collect {|v| v.to_param } : value.to_param - end - end def route_recognized? begin - @context.send(:assert_routing, - { :method => @method, :path => @path }, + @context.__send__(:assert_routing, + { method: @method, path: @path }, @params) - @negative_failure_message = "Didn't expect to #{description}" + @failure_message_when_negated = "Didn't expect to #{description}" true rescue ::ActionController::RoutingError => error @failure_message = error.message @@ -85,9 +140,7 @@ false end end - end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/route_params.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_params.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/route_params.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/route_params.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,53 @@ +module Shoulda + module Matchers + module ActionController + # @private + class RouteParams + def initialize(args) + @args = args + end + + def normalize + if controller_and_action_given_as_string? + extract_params_from_string + else + stringify_params + end + end + + protected + + attr_reader :args + + def controller_and_action_given_as_string? + args[0].is_a?(String) + end + + def extract_params_from_string + controller, action = args[0].split('#') + params = (args[1] || {}).merge(controller: controller, action: action) + stringify_values(params) + end + + def stringify_params + stringify_values(args[0]) + end + + def stringify_values(hash) + hash.inject({}) do |hash_copy, (key, value)| + hash_copy[key] = stringify(value) + hash_copy + end + end + + def stringify(value) + if value.is_a?(Array) + value.map(&:to_param) + else + value.to_param + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/set_flash_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/set_flash_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_flash_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,308 @@ +module Shoulda + module Matchers + module ActionController + # The `set_flash` matcher is used to make assertions about the + # `flash` hash. + # + # class PostsController < ApplicationController + # def index + # flash[:foo] = 'A candy bar' + # end + # + # def destroy + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_flash } + # end + # + # describe 'DELETE #destroy' do + # before { delete :destroy } + # + # it { should_not set_flash } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :index } + # + # should set_flash + # end + # + # context 'DELETE #destroy' do + # setup { delete :destroy } + # + # should_not set_flash + # end + # end + # + # #### Qualifiers + # + # ##### [] + # + # Use `[]` to narrow the scope of the matcher to a particular key. + # + # class PostsController < ApplicationController + # def index + # flash[:foo] = 'A candy bar' + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_flash[:foo] } + # it { should_not set_flash[:bar] } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :show } + # + # should set_flash[:foo] + # should_not set_flash[:bar] + # end + # end + # + # ##### to + # + # Use `to` to assert that some key was set to a particular value, or that + # some key matches a particular regex. + # + # class PostsController < ApplicationController + # def index + # flash[:foo] = 'A candy bar' + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_flash.to('A candy bar') } + # it { should set_flash.to(/bar/) } + # it { should set_flash[:foo].to('bar') } + # it { should_not set_flash[:foo].to('something else') } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :show } + # + # should set_flash.to('A candy bar') + # should set_flash.to(/bar/) + # should set_flash[:foo].to('bar') + # should_not set_flash[:foo].to('something else') + # end + # end + # + # ##### now + # + # Use `now` to change the scope of the matcher to use the "now" hash + # instead of the usual "future" hash. + # + # class PostsController < ApplicationController + # def show + # flash.now[:foo] = 'bar' + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #show' do + # before { get :show } + # + # it { should set_flash.now } + # it { should set_flash[:foo].now } + # it { should set_flash[:foo].to('bar').now } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :show } + # + # should set_flash.now + # should set_flash[:foo].now + # should set_flash[:foo].to('bar').now + # end + # end + # + # @return [SetFlashMatcher] + # + def set_flash + SetFlashMatcher.new + end + + # @deprecated Use {#set_flash} instead. + # @return [SetFlashMatcher] + def set_the_flash + Shoulda::Matchers.warn_about_deprecated_method( + :set_the_flash, + :set_flash + ) + set_flash + end + + # @private + class SetFlashMatcher + def initialize + @options = {} + @value = nil + end + + def to(value) + if !value.is_a?(String) && !value.is_a?(Regexp) + raise "cannot match against #{value.inspect}" + end + @value = value + self + end + + def now + @options[:now] = true + self + end + + def [](key) + @options[:key] = key + self + end + + def matches?(controller) + @controller = controller + sets_the_flash? && string_value_matches? && regexp_value_matches? + end + + def description + description = "set the #{expected_flash_invocation}" + description << " to #{@value.inspect}" unless @value.nil? + description + end + + def failure_message + "Expected #{expectation}" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias failure_message_for_should_not failure_message_when_negated + + private + + def sets_the_flash? + flash_values.any? + end + + def string_value_matches? + if @value.is_a?(String) + flash_values.any? {|value| value == @value } + else + true + end + end + + def regexp_value_matches? + if @value.is_a?(Regexp) + flash_values.any? {|value| value =~ @value } + else + true + end + end + + def flash_values + if @options.key?(:key) + flash_hash = HashWithIndifferentAccess.new(flash.to_hash) + [flash_hash[@options[:key]]] + else + flash.to_hash.values + end + end + + def flash + @flash ||= copy_of_flash_from_controller + end + + def copy_of_flash_from_controller + @controller.flash.dup.tap do |flash| + copy_flashes(@controller.flash, flash) + copy_discard_if_necessary(@controller.flash, flash) + sweep_flash_if_necessary(flash) + end + end + + def copy_flashes(original_flash, new_flash) + flashes_ivar = Shoulda::Matchers::RailsShim.flashes_ivar + flashes = original_flash.instance_variable_get(flashes_ivar).dup + new_flash.instance_variable_set(flashes_ivar, flashes) + end + + def copy_discard_if_necessary(original_flash, new_flash) + discard_ivar = :@discard + if original_flash.instance_variable_defined?(discard_ivar) + discard = original_flash.instance_variable_get(discard_ivar).dup + new_flash.instance_variable_set(discard_ivar, discard) + end + end + + def sweep_flash_if_necessary(flash) + unless @options[:now] + flash.sweep + end + end + + def expectation + expectation = "the #{expected_flash_invocation} to be set" + expectation << " to #{@value.inspect}" unless @value.nil? + expectation << ", but #{flash_description}" + expectation + end + + def flash_description + if flash.blank? + 'no flash was set' + else + "was #{flash.inspect}" + end + end + + def expected_flash_invocation + "flash#{pretty_now}#{pretty_key}" + end + + def pretty_now + if @options[:now] + '.now' + else + '' + end + end + + def pretty_key + if @options[:key] + "[:#{@options[:key]}]" + else + '' + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/set_session_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_controller/set_session_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_controller/set_session_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,22 +1,138 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActionController # :nodoc: - - # Ensures that a session key was set to the expected value. + module ActionController + # The `set_session` matcher is used to make assertions about the + # `session` hash. + # + # class PostsController < ApplicationController + # def index + # session[:foo] = 'A candy bar' + # end + # + # def destroy + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_session } + # end + # + # describe 'DELETE #destroy' do + # before { delete :destroy } + # + # it { should_not set_session } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :index } + # + # should set_session + # end + # + # context 'DELETE #destroy' do + # setup { delete :destroy } + # + # should_not set_session + # end + # end + # + # #### Qualifiers + # + # ##### [] + # + # Use `[]` to narrow the scope of the matcher to a particular key. # - # Example: + # class PostsController < ApplicationController + # def index + # session[:foo] = 'A candy bar' + # end + # end # - # it { should set_session(:message) } - # it { should set_session(:user_id).to(@user.id) } - # it { should_not set_session(:user_id) } - def set_session(key) + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_session[:foo] } + # it { should_not set_session[:bar] } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :show } + # + # should set_session[:foo] + # should_not set_session[:bar] + # end + # end + # + # ##### to + # + # Use `to` to assert that some key was set to a particular value, or that + # some key matches a particular regex. + # + # class PostsController < ApplicationController + # def index + # session[:foo] = 'A candy bar' + # end + # end + # + # # RSpec + # describe PostsController do + # describe 'GET #index' do + # before { get :index } + # + # it { should set_session.to('A candy bar') } + # it { should set_session.to(/bar/) } + # it { should set_session[:foo].to('bar') } + # it { should_not set_session[:foo].to('something else') } + # end + # end + # + # # Test::Unit + # class PostsControllerTest < ActionController::TestCase + # context 'GET #index' do + # setup { get :show } + # + # should set_session.to('A candy bar') + # should set_session.to(/bar/) + # should set_session[:foo].to('bar') + # should_not set_session[:foo].to('something else') + # end + # end + # + # @return [SetSessionMatcher] + # + def set_session(key = nil) SetSessionMatcher.new(key) end - class SetSessionMatcher # :nodoc: - + # @private + class SetSessionMatcher def initialize(key) + if key + Shoulda::Matchers.warn < User.first.to_param - # end - # - # it { should assign_to(:user) } - # it { should respond_with(:success) } - # it { should render_template(:show) } - # it { should not_set_the_flash) } - # - # it "should do something else really cool" do - # assigns[:user].id.should == 1 - # end - # end - # - # Would produce 5 tests for the show action module ActionController end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_mailer/have_sent_email.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_mailer/have_sent_email.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_mailer/have_sent_email.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_mailer/have_sent_email.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActionMailer # :nodoc: - - # The right email is sent. - # - # it { should have_sent_email.with_subject(/is spam$/) } - # it { should have_sent_email.from('do-not-reply@example.com') } - # it { should have_sent_email.with_body(/is spam\./) } - # it { should have_sent_email.to('myself@me.com') } - # it { should have_sent_email.with_subject(/spam/). - # from('do-not-reply@example.com'). - # with_body(/spam/). - # to('myself@me.com') } - def have_sent_email - HaveSentEmailMatcher.new - end - - class HaveSentEmailMatcher # :nodoc: - - def initialize - end - - def with_subject(email_subject) - @email_subject = email_subject - self - end - - def from(sender) - @sender = sender - self - end - - def with_body(body) - @body = body - self - end - - def to(recipient) - @recipient = recipient - self - end - - def matches?(subject) - ::ActionMailer::Base.deliveries.each do |mail| - @subject_failed = !regexp_or_string_match(mail.subject, @email_subject) if @email_subject - @body_failed = !regexp_or_string_match(mail.body, @body) if @body - @sender_failed = !regexp_or_string_match_in_array(mail.from, @sender) if @sender - @recipient_failed = !regexp_or_string_match_in_array(mail.to, @recipient) if @recipient - return true unless anything_failed? - end - - false - end - - def failure_message - "Expected #{expectation}" - end - - def negative_failure_message - "Did not expect #{expectation}" - end - - def description - description = "send an email" - description << " with a subject of #{@email_subject.inspect}" if @email_subject - description << " containing #{@body.inspect}" if @body - description << " from #{@sender.inspect}" if @sender - description << " to #{@recipient.inspect}" if @recipient - description - end - - private - - def expectation - expectation = "sent email" - expectation << " with subject #{@email_subject.inspect}" if @subject_failed - expectation << " with body #{@body.inspect}" if @body_failed - expectation << " from #{@sender.inspect}" if @sender_failed - expectation << " to #{@recipient.inspect}" if @recipient_failed - expectation << "\nDeliveries:\n#{inspect_deliveries}" - end - - def inspect_deliveries - ::ActionMailer::Base.deliveries.map do |delivery| - "#{delivery.subject.inspect} to #{delivery.to.inspect}" - end.join("\n") - end - - def anything_failed? - @subject_failed || @body_failed || @sender_failed || @recipient_failed - end - - def regexp_or_string_match(a_string, a_regexp_or_string) - case a_regexp_or_string - when Regexp - a_string =~ a_regexp_or_string - when String - a_string == a_regexp_or_string - end - end - - def regexp_or_string_match_in_array(an_array, a_regexp_or_string) - case a_regexp_or_string - when Regexp - an_array.any? { |string| string =~ a_regexp_or_string } - when String - an_array.include?(a_regexp_or_string) - end - end - end - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_mailer.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_mailer.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/action_mailer.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/action_mailer.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -require 'shoulda/matchers/action_mailer/have_sent_email' - -module Shoulda - module Matchers - # = Matchers for your mailers - # - # This matcher will test that email is sent properly - # - # describe User do - # it { should have_sent_email.with_subject(/is spam$/) } - # it { should have_sent_email.from('do-not-reply@example.com') } - # it { should have_sent_email.with_body(/is spam\./) } - # it { should have_sent_email.to('myself@me.com') } - # it { should have_sent_email.with_subject(/spam/). - # from('do-not-reply@example.com'). - # with_body(/spam/). - # to('myself@me.com') } - # end - module ActionMailer - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,173 @@ +module Shoulda + module Matchers + module ActiveModel + # The `allow_mass_assignment_of` matcher tests usage of Rails 3's + # `attr_accessible` and `attr_protected` macros, asserting that an + # attribute in your model is contained in either the whitelist or + # blacklist and thus can or cannot be set via mass assignment. + # + # class Post + # include ActiveModel::Model + # include ActiveModel::MassAssignmentSecurity + # attr_accessor :title + # + # attr_accessible :title + # end + # + # class User + # include ActiveModel::Model + # include ActiveModel::MassAssignmentSecurity + # attr_accessor :encrypted_password + # + # attr_protected :encrypted_password + # end + # + # # RSpec + # describe Post do + # it { should allow_mass_assignment_of(:title) } + # end + # + # describe User do + # it { should_not allow_mass_assignment_of(:encrypted_password) } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should allow_mass_assignment_of(:title) + # end + # + # class UserTest < ActiveSupport::TestCase + # should_not allow_mass_assignment_of(:encrypted_password) + # end + # + # #### Optional qualifiers + # + # ##### as + # + # Use `as` if your mass-assignment rules apply only under a certain role + # *(Rails >= 3.1 only)*. + # + # class Post + # include ActiveModel::Model + # include ActiveModel::MassAssignmentSecurity + # attr_accessor :title + # + # attr_accessible :title, as: :admin + # end + # + # # RSpec + # describe Post do + # it { should allow_mass_assignment_of(:title).as(:admin) } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should allow_mass_assignment_of(:title).as(:admin) + # end + # + # @return [AllowMassAssignmentOfMatcher] + # + def allow_mass_assignment_of(value) + AllowMassAssignmentOfMatcher.new(value) + end + + # @private + class AllowMassAssignmentOfMatcher + attr_reader :failure_message, :failure_message_when_negated + + alias failure_message_for_should failure_message + alias failure_message_for_should_not failure_message_when_negated + + def initialize(attribute) + @attribute = attribute.to_s + @options = {} + end + + def as(role) + if active_model_less_than_3_1? + raise 'You can specify role only in Rails 3.1 or greater' + end + @options[:role] = role + self + end + + def matches?(subject) + @subject = subject + if attr_mass_assignable? + if whitelisting? + @failure_message_when_negated = "#{@attribute} was made accessible" + else + if protected_attributes.empty? + @failure_message_when_negated = 'no attributes were protected' + else + @failure_message_when_negated = "#{class_name} is protecting " << + "#{protected_attributes.to_a.to_sentence}, " << + "but not #{@attribute}." + end + end + true + else + if whitelisting? + @failure_message = "Expected #{@attribute} to be accessible" + else + @failure_message = "Did not expect #{@attribute} to be protected" + end + false + end + end + + def description + [base_description, role_description].compact.join(' ') + end + + private + + def base_description + "allow mass assignment of #{@attribute}" + end + + def role_description + if role != :default + "as #{role}" + end + end + + def role + @options[:role] || :default + end + + def protected_attributes + @protected_attributes ||= (@subject.class.protected_attributes || []) + end + + def accessible_attributes + @accessible_attributes ||= (@subject.class.accessible_attributes || []) + end + + def whitelisting? + authorizer.kind_of?(::ActiveModel::MassAssignmentSecurity::WhiteList) + end + + def attr_mass_assignable? + !authorizer.deny?(@attribute) + end + + def authorizer + if active_model_less_than_3_1? + @subject.class.active_authorizer + else + @subject.class.active_authorizer[role] + end + end + + def class_name + @subject.class.name + end + + def active_model_less_than_3_1? + ::ActiveModel::VERSION::STRING.to_f < 3.1 + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/allow_value_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/allow_value_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,370 @@ +module Shoulda + module Matchers + module ActiveModel + # The `allow_value` matcher is used to test that an attribute of a model + # can or cannot be set to a particular value or values. It is most + # commonly used in conjunction with the `validates_format_of` validation. + # + # #### should + # + # In the positive form, `allow_value` asserts that an attribute can be + # set to one or more values, succeeding if none of the values cause the + # record to be invalid: + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :website_url + # + # validates_format_of :website_url, with: URI.regexp + # end + # + # # RSpec + # describe UserProfile do + # it do + # should allow_value('http://foo.com', 'http://bar.com/baz'). + # for(:website_url) + # end + # end + # + # # Test::Unit + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('http://foo.com', 'http://bar.com/baz'). + # for(:website_url) + # end + # + # #### should_not + # + # In the negative form, `allow_value` asserts that an attribute cannot be + # set to one or more values, succeeding if the *first* value causes the + # record to be invalid. + # + # **This can be surprising** so in this case if you need to check that + # *all* of the values are invalid, use separate assertions: + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :website_url + # + # validates_format_of :website_url, with: URI.regexp + # end + # + # describe UserProfile do + # # One assertion: 'buz' and 'bar' will not be tested + # it { should_not allow_value('fiz', 'buz', 'bar').for(:website_url) } + # + # # Three assertions, all tested separately + # it { should_not allow_value('fiz').for(:website_url) } + # it { should_not allow_value('buz').for(:website_url) } + # it { should_not allow_value('bar').for(:website_url) } + # end + # + # #### Qualifiers + # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :birthday_as_string + # + # validates_format_of :birthday_as_string, + # with: /^(\d+)-(\d+)-(\d+)$/, + # on: :create + # end + # + # # RSpec + # describe UserProfile do + # it do + # should allow_value('2013-01-01'). + # for(:birthday_as_string). + # on(:create) + # end + # end + # + # # Test::Unit + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('2013-01-01'). + # for(:birthday_as_string). + # on(:create) + # end + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :state + # + # validates_format_of :state, + # with: /^(open|closed)$/, + # message: 'State must be open or closed' + # end + # + # # RSpec + # describe UserProfile do + # it do + # should allow_value('open', 'closed'). + # for(:state). + # with_message('State must be open or closed') + # end + # end + # + # # Test::Unit + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('open', 'closed'). + # for(:state). + # with_message('State must be open or closed') + # end + # + # Use `with_message` with the `:against` option if the attribute the + # validation message is stored under is different from the attribute + # being validated. + # + # class UserProfile + # include ActiveModel::Model + # attr_accessor :sports_team + # + # validate :sports_team_must_be_valid + # + # private + # + # def sports_team_must_be_valid + # if sports_team !~ /^(Broncos|Titans)$/i + # self.errors.add :chosen_sports_team, + # 'Must be either a Broncos fan or a Titans fan' + # end + # end + # end + # + # # RSpec + # describe UserProfile do + # it do + # should allow_value('Broncos', 'Titans'). + # for(:sports_team). + # with_message('Must be either a Broncos or Titans fan', + # against: :chosen_sports_team + # ) + # end + # end + # + # # Test::Unit + # class UserProfileTest < ActiveSupport::TestCase + # should allow_value('Broncos', 'Titans'). + # for(:sports_team). + # with_message('Must be either a Broncos or Titans fan', + # against: :chosen_sports_team + # ) + # end + # + # @return [AllowValueMatcher] + # + def allow_value(*values) + if values.empty? + raise ArgumentError, 'need at least one argument' + else + AllowValueMatcher.new(*values) + end + end + + # @private + class AllowValueMatcher + include Helpers + + attr_accessor :attribute_with_message + attr_accessor :options + + def initialize(*values) + self.values_to_match = values + self.options = {} + self.after_setting_value_callback = -> {} + self.validator = Validator.new + end + + def for(attribute) + self.attribute_to_set = attribute + self.attribute_to_check_message_against = attribute + self + end + + def on(context) + validator.context = context + self + end + + def with_message(message, options={}) + self.options[:expected_message] = message + self.options[:expected_message_values] = options.fetch(:values, {}) + + if options.key?(:against) + self.attribute_to_check_message_against = options[:against] + end + + self + end + + def strict + validator.strict = true + self + end + + def _after_setting_value(&callback) + self.after_setting_value_callback = callback + end + + def matches?(instance) + self.instance = instance + validator.record = instance + + values_to_match.none? do |value| + validator.reset + self.value = value + set_attribute(value) + errors_match? || any_range_error_occurred? + end + end + + def failure_message + "Did not expect #{expectation},\ngot#{error_description}" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Expected #{expectation},\ngot#{error_description}" + end + alias failure_message_for_should_not failure_message_when_negated + + def description + validator.allow_description(allowed_values) + end + + protected + + attr_reader :attribute_to_check_message_against + attr_accessor :values_to_match, :instance, :attribute_to_set, :value, + :matched_error, :after_setting_value_callback, :validator + + def attribute_to_check_message_against=(attribute) + @attribute_to_check_message_against = attribute + validator.attribute = attribute + end + + def set_attribute(value) + set_attribute_ignoring_range_errors(value) + after_setting_value_callback.call + end + + def set_attribute_ignoring_range_errors(value) + instance.__send__("#{attribute_to_set}=", value) + rescue RangeError => exception + # Have to reset the attribute so that we don't get a RangeError the + # next time we attempt to write the attribute (ActiveRecord seems to + # set the attribute to the "bad" value anyway) + reset_attribute + validator.capture_range_error(exception) + end + + def reset_attribute + instance.send(:raw_write_attribute, attribute_to_set, nil) + end + + def errors_match? + has_messages? && errors_for_attribute_match? + end + + def has_messages? + validator.has_messages? + end + + def errors_for_attribute_match? + if expected_message + self.matched_error = errors_match_regexp? || errors_match_string? + else + errors_for_attribute.compact.any? + end + end + + def errors_for_attribute + validator.formatted_messages + end + + def errors_match_regexp? + if Regexp === expected_message + errors_for_attribute.detect { |e| e =~ expected_message } + end + end + + def errors_match_string? + if errors_for_attribute.include?(expected_message) + expected_message + end + end + + def any_range_error_occurred? + validator.captured_range_error? + end + + def expectation + parts = [ + expected_messages_description, + "when #{attribute_to_set} is set to #{value.inspect}" + ] + + parts.join(' ').squeeze(' ') + end + + def expected_messages_description + validator.expected_messages_description(expected_message) + end + + def error_description + validator.messages_description + end + + def allowed_values + if values_to_match.length > 1 + "any of [#{values_to_match.map(&:inspect).join(', ')}]" + else + values_to_match.first.inspect + end + end + + def expected_message + if options.key?(:expected_message) + if Symbol === options[:expected_message] + default_expected_message + else + options[:expected_message] + end + end + end + + def default_expected_message + validator.expected_message_from(default_attribute_message) + end + + def default_attribute_message + default_error_message( + options[:expected_message], + default_attribute_message_values + ) + end + + def default_attribute_message_values + defaults = { + model_name: model_name, + instance: instance, + attribute: attribute_to_check_message_against, + } + + defaults.merge(options[:expected_message_values]) + end + + def model_name + instance.class.to_s.underscore + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/disallow_value_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/disallow_value_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/disallow_value_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,55 @@ +require 'forwardable' + +module Shoulda + module Matchers + module ActiveModel + # @private + class DisallowValueMatcher + extend Forwardable + + def_delegators :allow_matcher, :_after_setting_value + def initialize(value) + @allow_matcher = AllowValueMatcher.new(value) + end + + def matches?(subject) + !@allow_matcher.matches?(subject) + end + + def for(attribute) + @allow_matcher.for(attribute) + self + end + + def on(context) + @allow_matcher.on(context) + self + end + + def with_message(message, options={}) + @allow_matcher.with_message(message, options) + self + end + + def failure_message + @allow_matcher.failure_message_when_negated + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + @allow_matcher.failure_message + end + alias failure_message_for_should_not failure_message_when_negated + + def strict + @allow_matcher.strict + self + end + + protected + + attr_reader :allow_matcher + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/errors.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/errors.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/errors.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/errors.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,52 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + class CouldNotDetermineValueOutsideOfArray < RuntimeError; end + + # @private + class NonNullableBooleanError < Shoulda::Matchers::Error + def self.create(attribute) + super(attribute: attribute) + end + + attr_accessor :attribute + + def message + <<-EOT.strip +You have specified that your model's #{attribute} should ensure inclusion of nil. +However, #{attribute} is a boolean column which does not allow null values. +Hence, this test will fail and there is no way to make it pass. + EOT + end + end + + # @private + class CouldNotSetPasswordError < Shoulda::Matchers::Error + def self.create(model) + super(model: model) + end + + attr_accessor :model + + def message + <<-EOT.strip +The validation failed because your #{model_name} model declares `has_secure_password`, and +`validate_presence_of` was called on a #{record_name} which has `password` already set to a value. +Please use a #{record_name} with an empty `password` instead. + EOT + end + + private + + def model_name + model.name + end + + def record_name + model_name.humanize.downcase + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,94 @@ +module Shoulda + module Matchers + module ActiveModel + # The `have_secure_password` matcher tests usage of the + # `has_secure_password` macro. + # + # #### Example + # + # class User + # include ActiveModel::Model + # include ActiveModel::SecurePassword + # attr_accessor :password + # + # has_secure_password + # end + # + # # RSpec + # describe User do + # it { should have_secure_password } + # end + # + # # Test::Unit + # class UserTest < ActiveSupport::TestCase + # should have_secure_password + # end + # + # @return [HaveSecurePasswordMatcher] + # + def have_secure_password + HaveSecurePasswordMatcher.new + end + + # @private + class HaveSecurePasswordMatcher + attr_reader :failure_message + + alias failure_message_for_should failure_message + + CORRECT_PASSWORD = "aBcDe12345" + INCORRECT_PASSWORD = "password" + + EXPECTED_METHODS = [ + :authenticate, + :password=, + :password_confirmation=, + :password_digest, + :password_digest=, + ] + + MESSAGES = { + authenticated_incorrect_password: "expected %{subject} to not authenticate an incorrect password", + did_not_authenticate_correct_password: "expected %{subject} to authenticate the correct password", + method_not_found: "expected %{subject} to respond to %{methods}" + } + + def description + "have a secure password" + end + + def matches?(subject) + @subject = subject + + if failure = validate + key, params = failure + @failure_message = MESSAGES[key] % { subject: subject.class }.merge(params) + end + + failure.nil? + end + + protected + + attr_reader :subject + + def validate + missing_methods = EXPECTED_METHODS.select {|m| !subject.respond_to?(m) } + + if missing_methods.present? + [:method_not_found, { methods: missing_methods.to_sentence }] + else + subject.password = CORRECT_PASSWORD + subject.password_confirmation = CORRECT_PASSWORD + + if not subject.authenticate(CORRECT_PASSWORD) + [:did_not_authenticate_correct_password, {}] + elsif subject.authenticate(INCORRECT_PASSWORD) + [:authenticated_incorrect_password, {}] + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/helpers.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,43 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module Helpers + def pretty_error_messages(obj) + obj.errors.map do |attribute, message| + full_message = message.dup.inspect + parenthetical_parts = [] + + unless attribute.to_sym == :base + parenthetical_parts << "attribute: #{attribute}" + + if obj.respond_to?(attribute) + parenthetical_parts << "value: #{obj.__send__(attribute).inspect}" + end + end + + if parenthetical_parts.any? + full_message << " (#{parenthetical_parts.join(', ')})" + end + + "* " + full_message + end.join("\n") + end + + def default_error_message(type, options = {}) + model_name = options.delete(:model_name) + attribute = options.delete(:attribute) + instance = options.delete(:instance) + + RailsShim.generate_validation_message( + instance, + attribute.to_sym, + type, + model_name, + options + ) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,134 @@ +module Shoulda + module Matchers + module ActiveModel + module NumericalityMatchers + # @private + class ComparisonMatcher < ValidationMatcher + ERROR_MESSAGES = { + :> => :greater_than, + :>= => :greater_than_or_equal_to, + :< => :less_than, + :<= => :less_than_or_equal_to, + :== => :equal_to + } + + def initialize(numericality_matcher, value, operator) + unless numericality_matcher.respond_to? :diff_to_compare + raise ArgumentError, 'numericality_matcher is invalid' + end + @numericality_matcher = numericality_matcher + @value = value + @operator = operator + @message = ERROR_MESSAGES[operator] + @comparison_combos = comparison_combos + @strict = false + end + + def for(attribute) + @attribute = attribute + self + end + + def matches?(subject) + @subject = subject + all_bounds_correct? + end + + def with_message(message) + @message = message + end + + def comparison_description + "#{expectation} #{@value}" + end + + def failure_message + last_failing_submatcher.failure_message + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + last_failing_submatcher.failure_message_when_negated + end + alias failure_message_for_should_not failure_message_when_negated + + private + + def all_bounds_correct? + failing_submatchers.empty? + end + + def failing_submatchers + submatchers_and_results. + select { |x| !x[:matched] }. + map { |x| x[:matcher] } + end + + def last_failing_submatcher + failing_submatchers.last + end + + def submatchers + @_submatchers ||= + comparison_combos.map do |diff, submatcher_method_name| + matcher = __send__(submatcher_method_name, @value + diff, nil) + matcher.with_message(@message, values: { count: @value }) + matcher + end + end + + def submatchers_and_results + @_submatchers_and_results ||= + submatchers.map do |matcher| + { matcher: matcher, matched: matcher.matches?(@subject) } + end + end + + def comparison_combos + diffs_to_compare.zip(submatcher_method_names) + end + + def submatcher_method_names + assertions.map do |value| + if value + :allow_value_matcher + else + :disallow_value_matcher + end + end + end + + def assertions + case @operator + when :> + [false, false, true] + when :>= + [false, true, true] + when :== + [false, true, false] + when :< + [true, false, false] + when :<= + [true, true, false] + end + end + + def diffs_to_compare + diff = @numericality_matcher.diff_to_compare + [-diff, 0, diff] + end + + def expectation + case @operator + when :> then "greater than" + when :>= then "greater than or equal to" + when :== then "equal to" + when :< then "less than" + when :<= then "less than or equal to" + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,27 @@ +module Shoulda + module Matchers + module ActiveModel + module NumericalityMatchers + # @private + class EvenNumberMatcher < NumericTypeMatcher + NON_EVEN_NUMBER_VALUE = 1 + + def initialize(attribute, options = {}) + @attribute = attribute + @disallow_value_matcher = DisallowValueMatcher.new(NON_EVEN_NUMBER_VALUE). + for(@attribute). + with_message(:even) + end + + def allowed_type + 'even numbers' + end + + def diff_to_compare + 2 + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +module Shoulda + module Matchers + module ActiveModel + module NumericalityMatchers + # @private + class NumericTypeMatcher + def initialize + raise NotImplementedError + end + + def matches?(subject) + @disallow_value_matcher.matches?(subject) + end + + def with_message(message) + @disallow_value_matcher.with_message(message) + self + end + + def allowed_type + raise NotImplementedError + end + + def diff_to_compare + raise NotImplementedError + end + + def failure_message + @disallow_value_matcher.failure_message + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + @disallow_value_matcher.failure_message_when_negated + end + alias failure_message_for_should_not failure_message_when_negated + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,27 @@ +module Shoulda + module Matchers + module ActiveModel + module NumericalityMatchers + # @private + class OddNumberMatcher < NumericTypeMatcher + NON_ODD_NUMBER_VALUE = 2 + + def initialize(attribute, options = {}) + @attribute = attribute + @disallow_value_matcher = DisallowValueMatcher.new(NON_ODD_NUMBER_VALUE). + for(@attribute). + with_message(:odd) + end + + def allowed_type + 'odd numbers' + end + + def diff_to_compare + 2 + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,26 @@ +module Shoulda + module Matchers + module ActiveModel + module NumericalityMatchers + # @private + class OnlyIntegerMatcher < NumericTypeMatcher + NON_INTEGER_VALUE = 0.1 + def initialize(attribute) + @attribute = attribute + @disallow_value_matcher = DisallowValueMatcher.new(NON_INTEGER_VALUE). + for(attribute). + with_message(:not_an_integer) + end + + def allowed_type + 'integers' + end + + def diff_to_compare + 1 + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/numericality_matchers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/numericality_matchers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,9 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module NumericalityMatchers + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/strict_validator.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/strict_validator.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/strict_validator.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/strict_validator.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,51 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module StrictValidator + def allow_description(allowed_values) + "doesn't raise when #{attribute} is set to #{allowed_values}" + end + + def expected_message_from(attribute_message) + "#{human_attribute_name} #{attribute_message}" + end + + def formatted_messages + [messages.first.message] + end + + def messages_description + if has_messages? + ': ' + messages.first.message.inspect + else + ' no exception' + end + end + + def expected_messages_description(expected_message) + if expected_message + "exception to include #{expected_message.inspect}" + else + 'an exception to have been raised' + end + end + + protected + + def collect_messages + validation_exceptions + end + + private + + def validation_exceptions + record.valid?(context) + [] + rescue ::ActiveModel::StrictValidationFailed => exception + [exception] + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,117 @@ +module Shoulda + module Matchers + module ActiveModel + # The `validate_absence_of` matcher tests the usage of the + # `validates_absence_of` validation. + # + # class Artillery + # include ActiveModel::Model + # attr_accessor :arms + # + # validates_absence_of :arms + # end + # + # # RSpec + # describe Artillery do + # it { should validate_absence_of(:arms) } + # end + # + # # Test::Unit + # class ArtilleryTest < ActiveSupport::TestCase + # should validate_absence_of(:arms) + # end + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Artillery + # include ActiveModel::Model + # attr_accessor :arms + # + # validates_absence_of :arms, + # message: "We're fresh outta arms here, soldier!" + # end + # + # # RSpec + # describe Artillery do + # it do + # should validate_absence_of(:arms). + # with_message("We're fresh outta arms here, soldier!") + # end + # end + # + # # Test::Unit + # class ArtilleryTest < ActiveSupport::TestCase + # should validate_absence_of(:arms). + # with_message("We're fresh outta arms here, soldier!") + # end + # + # @return [ValidateAbsenceOfMatcher} + # + def validate_absence_of(attr) + ValidateAbsenceOfMatcher.new(attr) + end + + # @private + class ValidateAbsenceOfMatcher < ValidationMatcher + def with_message(message) + @expected_message = message + self + end + + def matches?(subject) + super(subject) + @expected_message ||= :present + disallows_value_of(value, @expected_message) + end + + def description + "require #{@attribute} to not be set" + end + + private + + def value + if reflection + obj = reflection.klass.new + if collection? + [ obj ] + else + obj + end + elsif [Fixnum, Float].include?(attribute_class) + 1 + elsif attribute_class == BigDecimal + BigDecimal.new(1, 0) + elsif !attribute_class || attribute_class == String + 'an arbitrary value' + else + attribute_class.new + end + end + + def attribute_class + @subject.class.respond_to?(:columns_hash) && + @subject.class.columns_hash[@attribute.to_s].respond_to?(:klass) && + @subject.class.columns_hash[@attribute.to_s].klass + end + + def collection? + if reflection + [:has_many, :has_and_belongs_to_many].include?(reflection.macro) + else + false + end + end + + def reflection + @subject.class.respond_to?(:reflect_on_association) && + @subject.class.reflect_on_association(@attribute) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,79 @@ +module Shoulda + module Matchers + module ActiveModel + # The `validate_acceptance_of` matcher tests usage of the + # `validates_acceptance_of` validation. + # + # class Registration + # include ActiveModel::Model + # attr_accessor :eula + # + # validates_acceptance_of :eula + # end + # + # # RSpec + # describe Registration do + # it { should validate_acceptance_of(:eula) } + # end + # + # # Test::Unit + # class RegistrationTest < ActiveSupport::TestCase + # should validate_acceptance_of(:eula) + # end + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Registration + # include ActiveModel::Model + # attr_accessor :terms_of_service + # + # validates_acceptance_of :terms_of_service, + # message: 'You must accept the terms of service' + # end + # + # # RSpec + # describe Registration do + # it do + # should validate_acceptance_of(:terms_of_service). + # with_message('You must accept the terms of service') + # end + # end + # + # # Test::Unit + # class RegistrationTest < ActiveSupport::TestCase + # should validate_acceptance_of(:terms_of_service). + # with_message('You must accept the terms of service') + # end + # + # @return [ValidateAcceptanceOfMatcher] + # + def validate_acceptance_of(attr) + ValidateAcceptanceOfMatcher.new(attr) + end + + # @private + class ValidateAcceptanceOfMatcher < ValidationMatcher + def with_message(message) + if message + @expected_message = message + end + self + end + + def matches?(subject) + super(subject) + @expected_message ||= :accepted + disallows_value_of(false, @expected_message) + end + + def description + "require #{@attribute} to be accepted" + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,130 @@ +module Shoulda + module Matchers + module ActiveModel + # The `validate_confirmation_of` matcher tests usage of the + # `validates_confirmation_of` validation. + # + # class User + # include ActiveModel::Model + # attr_accessor :email + # + # validates_confirmation_of :email + # end + # + # # RSpec + # describe User do + # it { should validate_confirmation_of(:email) } + # end + # + # # Test::Unit + # class UserTest < ActiveSupport::TestCase + # should validate_confirmation_of(:email) + # end + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class User + # include ActiveModel::Model + # attr_accessor :password + # + # validates_confirmation_of :password, + # message: 'Please re-enter your password' + # end + # + # # RSpec + # describe User do + # it do + # should validate_confirmation_of(:password). + # with_message('Please re-enter your password') + # end + # end + # + # # Test::Unit + # class UserTest < ActiveSupport::TestCase + # should validate_confirmation_of(:password). + # with_message('Please re-enter your password') + # end + # + # @return [ValidateConfirmationOfMatcher] + # + def validate_confirmation_of(attr) + ValidateConfirmationOfMatcher.new(attr) + end + + # @private + class ValidateConfirmationOfMatcher < ValidationMatcher + include Helpers + + attr_reader :attribute, :confirmation_attribute + + def initialize(attribute) + super(attribute) + @confirmation_attribute = "#{attribute}_confirmation" + end + + def with_message(message) + @message = message if message + self + end + + def description + "require #{@confirmation_attribute} to match #{@attribute}" + end + + def matches?(subject) + super(subject) + @message ||= :confirmation + + disallows_different_value && + allows_same_value && + allows_missing_confirmation + end + + private + + def disallows_different_value + set_confirmation('some value') + disallows_value_of('different value') do |matcher| + qualify_matcher(matcher) + end + end + + def allows_same_value + set_confirmation('same value') + allows_value_of('same value') do |matcher| + qualify_matcher(matcher) + end + end + + def allows_missing_confirmation + set_confirmation(nil) + allows_value_of('any value') do |matcher| + qualify_matcher(matcher) + end + end + + def qualify_matcher(matcher) + matcher.with_message(@message, + against: error_attribute, + values: { attribute: attribute } + ) + end + + def set_confirmation(val) + setter = :"#{@confirmation_attribute}=" + if @subject.respond_to?(setter) + @subject.__send__(setter, val) + end + end + + def error_attribute + RailsShim.validates_confirmation_of_error_attribute(self) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,183 @@ +module Shoulda + module Matchers + module ActiveModel + # The `validate_exclusion_of` matcher tests usage of the + # `validates_exclusion_of` validation, asserting that an attribute cannot + # take a blacklist of values, and inversely, can take values outside of + # this list. + # + # If your blacklist is an array of values, use `in_array`: + # + # class Game + # include ActiveModel::Model + # attr_accessor :supported_os + # + # validates_exclusion_of :supported_os, in: ['Mac', 'Linux'] + # end + # + # # RSpec + # describe Game do + # it do + # should validate_exclusion_of(:supported_os). + # in_array(['Mac', 'Linux']) + # end + # end + # + # # Test::Unit + # class GameTest < ActiveSupport::TestCase + # should validate_exclusion_of(:supported_os). + # in_array(['Mac', 'Linux']) + # end + # + # If your blacklist is a range of values, use `in_range`: + # + # class Game + # include ActiveModel::Model + # attr_accessor :supported_os + # + # validates_exclusion_of :supported_os, in: ['Mac', 'Linux'] + # end + # + # # RSpec + # describe Game do + # it do + # should validate_exclusion_of(:floors_with_enemies). + # in_range(5..8) + # end + # end + # + # # Test::Unit + # class GameTest < ActiveSupport::TestCase + # should validate_exclusion_of(:floors_with_enemies). + # in_range(5..8) + # end + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Game + # include ActiveModel::Model + # attr_accessor :weapon + # + # validates_exclusion_of :weapon, + # in: ['pistol', 'paintball gun', 'stick'], + # message: 'You chose a puny weapon' + # end + # + # # RSpec + # describe Game do + # it do + # should validate_exclusion_of(:weapon). + # in_array(['pistol', 'paintball gun', 'stick']). + # with_message('You chose a puny weapon') + # end + # end + # + # # Test::Unit + # class GameTest < ActiveSupport::TestCase + # should validate_exclusion_of(:weapon). + # in_array(['pistol', 'paintball gun', 'stick']). + # with_message('You chose a puny weapon') + # end + # + # @return [ValidateExclusionOfMatcher] + # + def validate_exclusion_of(attr) + ValidateExclusionOfMatcher.new(attr) + end + + # @deprecated Use {#validate_exclusion_of} instead. + # @return [ValidateExclusionOfMatcher] + def ensure_exclusion_of(attr) + Shoulda::Matchers.warn_about_deprecated_method( + :ensure_exclusion_of, + :validate_exclusion_of + ) + validate_exclusion_of(attr) + end + + # @private + class ValidateExclusionOfMatcher < ValidationMatcher + def initialize(attribute) + super(attribute) + @array = nil + @range = nil + @expected_message = nil + end + + def in_array(array) + @array = array + self + end + + def in_range(range) + @range = range + @minimum = range.first + @maximum = range.max + self + end + + def with_message(message) + @expected_message = message if message + self + end + + def description + "ensure exclusion of #{@attribute} in #{inspect_message}" + end + + def matches?(subject) + super(subject) + + if @range + allows_lower_value && + disallows_minimum_value && + allows_higher_value && + disallows_maximum_value + elsif @array + disallows_all_values_in_array? + end + end + + private + + def disallows_all_values_in_array? + @array.all? do |value| + disallows_value_of(value, expected_message) + end + end + + def allows_lower_value + @minimum == 0 || allows_value_of(@minimum - 1, expected_message) + end + + def allows_higher_value + allows_value_of(@maximum + 1, expected_message) + end + + def disallows_minimum_value + disallows_value_of(@minimum, expected_message) + end + + def disallows_maximum_value + disallows_value_of(@maximum, expected_message) + end + + def expected_message + @expected_message || :exclusion + end + + def inspect_message + if @range + @range.inspect + else + @array.inspect + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,495 @@ +require 'bigdecimal' + +module Shoulda + module Matchers + module ActiveModel + # The `validate_inclusion_of` matcher tests usage of the + # `validates_inclusion_of` validation, asserting that an attribute can + # take a whitelist of values and cannot take values outside of this list. + # + # If your whitelist is an array of values, use `in_array`: + # + # class Issue + # include ActiveModel::Model + # attr_accessor :state + # + # validates_inclusion_of :state, in: %w(open resolved unresolved) + # end + # + # # RSpec + # describe Issue do + # it do + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)) + # end + # end + # + # # Test::Unit + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)) + # end + # + # If your whitelist is a range of values, use `in_range`: + # + # class Issue + # include ActiveModel::Model + # attr_accessor :priority + # + # validates_inclusion_of :priority, in: 1..5 + # end + # + # # RSpec + # describe Issue do + # it { should validate_inclusion_of(:state).in_range(1..5) } + # end + # + # # Test::Unit + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:state).in_range(1..5) + # end + # + # #### Caveats + # + # We discourage using `validate_inclusion_of` with boolean columns. In + # fact, there is never a case where a boolean column will be anything but + # true, false, or nil, as ActiveRecord will type-cast an incoming value to + # one of these three values. That means there isn't any way we can refute + # this logic in a test. Hence, this will produce a warning: + # + # it { should validate_inclusion_of(:imported).in_array([true, false]) } + # + # The only case where `validate_inclusion_of` *could* be appropriate is + # for ensuring that a boolean column accepts nil, but we recommend + # using `allow_value` instead, like this: + # + # it { should allow_value(nil).for(:imported) } + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Issue + # include ActiveModel::Model + # attr_accessor :severity + # + # validates_inclusion_of :severity, + # in: %w(low medium high), + # message: 'Severity must be low, medium, or high' + # end + # + # # RSpec + # describe Issue do + # it do + # should validate_inclusion_of(:severity). + # in_array(%w(low medium high)). + # with_message('Severity must be low, medium, or high') + # end + # end + # + # # Test::Unit + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:severity). + # in_array(%w(low medium high)). + # with_message('Severity must be low, medium, or high') + # end + # + # ##### with_low_message + # + # Use `with_low_message` if you have a custom validation message for when + # a given value is too low. + # + # class Person + # include ActiveModel::Model + # attr_accessor :age + # + # validate :age_must_be_valid + # + # private + # + # def age_must_be_valid + # if age < 65 + # self.errors.add :age, 'You do not receive any benefits' + # end + # end + # end + # + # # RSpec + # describe Person do + # it do + # should validate_inclusion_of(:age). + # in_range(0..65). + # with_low_message('You do not receive any benefits') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should validate_inclusion_of(:age). + # in_range(0..65). + # with_low_message('You do not receive any benefits') + # end + # + # ##### with_high_message + # + # Use `with_high_message` if you have a custom validation message for + # when a given value is too high. + # + # class Person + # include ActiveModel::Model + # attr_accessor :age + # + # validate :age_must_be_valid + # + # private + # + # def age_must_be_valid + # if age > 21 + # self.errors.add :age, "You're too old for this stuff" + # end + # end + # end + # + # # RSpec + # describe Person do + # it do + # should validate_inclusion_of(:age). + # in_range(0..21). + # with_high_message("You're too old for this stuff") + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should validate_inclusion_of(:age). + # in_range(0..21). + # with_high_message("You're too old for this stuff") + # end + # + # ##### allow_nil + # + # Use `allow_nil` to assert that the attribute allows nil. + # + # class Issue + # include ActiveModel::Model + # attr_accessor :state + # + # validates_presence_of :state + # validates_inclusion_of :state, + # in: %w(open resolved unresolved), + # allow_nil: true + # end + # + # # RSpec + # describe Issue do + # it do + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)). + # allow_nil + # end + # end + # + # # Test::Unit + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)). + # allow_nil + # end + # + # ##### allow_blank + # + # Use `allow_blank` to assert that the attribute allows blank. + # + # class Issue + # include ActiveModel::Model + # attr_accessor :state + # + # validates_presence_of :state + # validates_inclusion_of :state, + # in: %w(open resolved unresolved), + # allow_blank: true + # end + # + # # RSpec + # describe Issue do + # it do + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)). + # allow_blank + # end + # end + # + # # Test::Unit + # class IssueTest < ActiveSupport::TestCase + # should validate_inclusion_of(:state). + # in_array(%w(open resolved unresolved)). + # allow_blank + # end + # + # @return [ValidateInclusionOfMatcher] + # + def validate_inclusion_of(attr) + ValidateInclusionOfMatcher.new(attr) + end + + # @deprecated Use {#validate_inclusion_of} instead. + # @return [ValidateInclusionOfMatcher] + def ensure_inclusion_of(attr) + Shoulda::Matchers.warn_about_deprecated_method( + :ensure_inclusion_of, + :validate_inclusion_of + ) + validate_inclusion_of(attr) + end + + # @private + class ValidateInclusionOfMatcher < ValidationMatcher + ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring' + ARBITRARY_OUTSIDE_FIXNUM = 123456789 + ARBITRARY_OUTSIDE_DECIMAL = BigDecimal.new('0.123456789') + BOOLEAN_ALLOWS_BOOLEAN_MESSAGE = <).for(@attribute)) + self + end + + def is_greater_than_or_equal_to(value) + prepare_submatcher(comparison_matcher_for(value, :>=).for(@attribute)) + self + end + + def is_equal_to(value) + prepare_submatcher(comparison_matcher_for(value, :==).for(@attribute)) + self + end + + def is_less_than(value) + prepare_submatcher(comparison_matcher_for(value, :<).for(@attribute)) + self + end + + def is_less_than_or_equal_to(value) + prepare_submatcher(comparison_matcher_for(value, :<=).for(@attribute)) + self + end + + def with_message(message) + @submatchers.each { |matcher| matcher.with_message(message) } + self + end + + def matches?(subject) + @subject = subject + failing_submatchers.empty? + end + + def description + "only allow #{allowed_types} for #{@attribute}#{comparison_descriptions}" + end + + def failure_message + last_failing_submatcher.failure_message + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + last_failing_submatcher.failure_message_when_negated + end + alias failure_message_for_should_not failure_message_when_negated + + private + + def add_disallow_value_matcher + disallow_value_matcher = DisallowValueMatcher.new(NON_NUMERIC_VALUE). + for(@attribute). + with_message(:not_a_number) + + add_submatcher(disallow_value_matcher) + end + + def prepare_submatcher(submatcher) + add_submatcher(submatcher) + if submatcher.respond_to?(:diff_to_compare) + update_diff_to_compare(submatcher) + end + end + + def comparison_matcher_for(value, operator) + NumericalityMatchers::ComparisonMatcher + .new(self, value, operator) + .for(@attribute) + end + + def add_submatcher(submatcher) + @submatchers << submatcher + end + + def update_diff_to_compare(matcher) + @diff_to_compare = [@diff_to_compare, matcher.diff_to_compare].max + end + + def submatchers_and_results + @_submatchers_and_results ||= + @submatchers.map do |matcher| + { matcher: matcher, matched: matcher.matches?(@subject) } + end + end + + def failing_submatchers + submatchers_and_results. + select { |x| !x[:matched] }. + map { |x| x[:matcher] } + end + + def last_failing_submatcher + failing_submatchers.last + end + + def allowed_types + allowed_array = submatcher_allowed_types + allowed_array.empty? ? NUMERIC_NAME : allowed_array.join(', ') + end + + def submatcher_allowed_types + @submatchers.inject([]){|m, s| m << s.allowed_type if s.respond_to?(:allowed_type); m } + end + + def comparison_descriptions + description_array = submatcher_comparison_descriptions + description_array.empty? ? '' : ' which are ' + submatcher_comparison_descriptions.join(' and ') + end + + def submatcher_comparison_descriptions + @submatchers.inject([]) do |arr, submatcher| + if submatcher.respond_to? :comparison_description + arr << submatcher.comparison_description + end + arr + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,179 @@ +module Shoulda + module Matchers + module ActiveModel + # The `validate_presence_of` matcher tests usage of the + # `validates_presence_of` validation. + # + # class Robot + # include ActiveModel::Model + # attr_accessor :arms + # + # validates_presence_of :arms + # end + # + # # RSpec + # describe Robot do + # it { should validate_presence_of(:arms) } + # end + # + # # Test::Unit + # class RobotTest < ActiveSupport::TestCase + # should validate_presence_of(:arms) + # end + # + # #### Caveats + # + # Under Rails 4 and greater, if your model `has_secure_password` and you + # are validating presence of the password using a record whose password + # has already been set prior to calling the matcher, you will be + # instructed to use a record whose password is empty instead. + # + # For example, given this scenario: + # + # class User < ActiveRecord::Base + # has_secure_password validations: false + # + # validates_presence_of :password + # end + # + # describe User do + # subject { User.new(password: '123456') } + # + # it { should validate_presence_of(:password) } + # end + # + # the above test will raise an error like this: + # + # The validation failed because your User model declares + # `has_secure_password`, and `validate_presence_of` was called on a + # user which has `password` already set to a value. Please use a user + # with an empty `password` instead. + # + # This happens because `has_secure_password` itself overrides your model + # so that it is impossible to set `password` to nil. This means that it is + # impossible to test that setting `password` to nil places your model in + # an invalid state (which in turn means that the validation itself is + # unnecessary). + # + # #### Qualifiers + # + # ##### on + # + # Use `on` if your validation applies only under a certain context. + # + # class Robot + # include ActiveModel::Model + # attr_accessor :arms + # + # validates_presence_of :arms, on: :create + # end + # + # # RSpec + # describe Robot do + # it { should validate_presence_of(:arms).on(:create) } + # end + # + # # Test::Unit + # class RobotTest < ActiveSupport::TestCase + # should validate_presence_of(:arms).on(:create) + # end + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Robot + # include ActiveModel::Model + # attr_accessor :legs + # + # validates_presence_of :legs, message: 'Robot has no legs' + # end + # + # # RSpec + # describe Robot do + # it do + # should validate_presence_of(:legs). + # with_message('Robot has no legs') + # end + # end + # + # # Test::Unit + # class RobotTest < ActiveSupport::TestCase + # should validate_presence_of(:legs). + # with_message('Robot has no legs') + # end + # + # @return [ValidatePresenceOfMatcher] + # + def validate_presence_of(attr) + ValidatePresenceOfMatcher.new(attr) + end + + # @private + class ValidatePresenceOfMatcher < ValidationMatcher + def with_message(message) + @expected_message = message if message + self + end + + def matches?(subject) + super(subject) + @expected_message ||= :blank + + if secure_password_being_validated? + disallows_and_double_checks_value_of!(blank_value, @expected_message) + else + disallows_value_of(blank_value, @expected_message) + end + end + + def description + "require #{@attribute} to be set" + end + + private + + def secure_password_being_validated? + defined?(::ActiveModel::SecurePassword) && + @subject.class.ancestors.include?(::ActiveModel::SecurePassword::InstanceMethodsOnActivation) && + @attribute == :password + end + + def disallows_and_double_checks_value_of!(value, message) + error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError + + disallows_value_of(value, message) do |matcher| + matcher._after_setting_value do + actual_value = @subject.__send__(@attribute) + + if !actual_value.nil? + raise error_class.create(@subject.class) + end + end + end + end + + def blank_value + if collection? + [] + else + nil + end + end + + def collection? + if reflection + [:has_many, :has_and_belongs_to_many].include?(reflection.macro) + else + false + end + end + + def reflection + @subject.class.respond_to?(:reflect_on_association) && + @subject.class.reflect_on_association(@attribute) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validation_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validation_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validation_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,101 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + class ValidationMatcher + attr_reader :failure_message + + alias failure_message_for_should failure_message + + def initialize(attribute) + @attribute = attribute + @strict = false + @failure_message = nil + @failure_message_when_negated = nil + end + + def on(context) + @context = context + self + end + + def strict + @strict = true + self + end + + def failure_message_when_negated + @failure_message_when_negated || @failure_message + end + alias failure_message_for_should_not failure_message_when_negated + + def matches?(subject) + @subject = subject + false + end + + private + + def allows_value_of(value, message = nil, &block) + allow = allow_value_matcher(value, message) + yield allow if block_given? + + if allow.matches?(@subject) + @failure_message_when_negated = allow.failure_message_when_negated + true + else + @failure_message = allow.failure_message + false + end + end + + def disallows_value_of(value, message = nil, &block) + disallow = disallow_value_matcher(value, message) + yield disallow if block_given? + + if disallow.matches?(@subject) + @failure_message_when_negated = disallow.failure_message_when_negated + true + else + @failure_message = disallow.failure_message + false + end + end + + def allow_value_matcher(value, message) + matcher = AllowValueMatcher.new(value).for(@attribute). + with_message(message) + + if defined?(@context) + matcher.on(@context) + end + + if strict? + matcher.strict + end + + matcher + end + + def disallow_value_matcher(value, message) + matcher = DisallowValueMatcher.new(value).for(@attribute). + with_message(message) + + if defined?(@context) + matcher.on(@context) + end + + if strict? + matcher.strict + end + + matcher + end + + def strict? + @strict + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validator.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validator.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,113 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + class Validator + include Helpers + + attr_writer :attribute, :context, :record + + def initialize + reset + end + + def reset + @messages = nil + end + + def strict=(strict) + @strict = strict + + if strict + extend StrictValidator + end + end + + def capture_range_error(exception) + @captured_range_error = exception + extend ValidatorWithCapturedRangeError + end + + def allow_description(allowed_values) + "allow #{attribute} to be set to #{allowed_values}" + end + + def expected_message_from(attribute_message) + attribute_message + end + + def messages + @messages ||= collect_messages + end + + def formatted_messages + messages + end + + def has_messages? + messages.any? + end + + def messages_description + if has_messages? + " errors:\n#{pretty_error_messages(record)}" + else + ' no errors' + end + end + + def expected_messages_description(expected_message) + if expected_message + "errors to include #{expected_message.inspect}" + else + 'errors' + end + end + + def captured_range_error? + !!captured_range_error + end + + protected + + attr_reader :attribute, :context, :strict, :record, + :captured_range_error + + def collect_messages + validation_errors + end + + private + + def strict? + !!@strict + end + + def collect_errors_or_exceptions + collect_messages + rescue RangeError => exception + capture_range_error(exception) + [] + end + + def validation_errors + if context + record.valid?(context) + else + record.valid? + end + + if record.errors.respond_to?(:[]) + record.errors[attribute] + else + record.errors.on(attribute) + end + end + + def human_attribute_name + record.class.human_attribute_name(attribute) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,12 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module ValidatorWithCapturedRangeError + def messages_description + ' RangeError: ' + captured_range_error.message.inspect + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_model.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_model.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,30 @@ +require 'shoulda/matchers/active_model/helpers' +require 'shoulda/matchers/active_model/validation_matcher' +require 'shoulda/matchers/active_model/validator' +require 'shoulda/matchers/active_model/strict_validator' +require 'shoulda/matchers/active_model/validator_with_captured_range_error' +require 'shoulda/matchers/active_model/allow_value_matcher' +require 'shoulda/matchers/active_model/disallow_value_matcher' +require 'shoulda/matchers/active_model/validate_length_of_matcher' +require 'shoulda/matchers/active_model/validate_inclusion_of_matcher' +require 'shoulda/matchers/active_model/validate_exclusion_of_matcher' +require 'shoulda/matchers/active_model/validate_absence_of_matcher' +require 'shoulda/matchers/active_model/validate_presence_of_matcher' +require 'shoulda/matchers/active_model/validate_acceptance_of_matcher' +require 'shoulda/matchers/active_model/validate_confirmation_of_matcher' +require 'shoulda/matchers/active_model/validate_numericality_of_matcher' +require 'shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher' +require 'shoulda/matchers/active_model/numericality_matchers/comparison_matcher' +require 'shoulda/matchers/active_model/numericality_matchers/odd_number_matcher' +require 'shoulda/matchers/active_model/numericality_matchers/even_number_matcher' +require 'shoulda/matchers/active_model/numericality_matchers/only_integer_matcher' +require 'shoulda/matchers/active_model/allow_mass_assignment_of_matcher' +require 'shoulda/matchers/active_model/errors' +require 'shoulda/matchers/active_model/have_secure_password_matcher' + +module Shoulda + module Matchers + module ActiveModel + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,216 @@ +module Shoulda + module Matchers + module ActiveRecord + # The `accept_nested_attributes_for` matcher tests usage of the + # `accepts_nested_attributes_for` macro. + # + # class Car < ActiveRecord::Base + # accepts_nested_attributes_for :doors + # end + # + # # RSpec + # describe Car do + # it { should accept_nested_attributes_for(:doors) } + # end + # + # # Test::Unit (using Shoulda) + # class CarTest < ActiveSupport::TestCase + # should accept_nested_attributes_for(:doors) + # end + # + # #### Qualifiers + # + # ##### allow_destroy + # + # Use `allow_destroy` to assert that the `:allow_destroy` option was + # specified. + # + # class Car < ActiveRecord::Base + # accepts_nested_attributes_for :mirrors, allow_destroy: true + # end + # + # # RSpec + # describe Car do + # it do + # should accept_nested_attributes_for(:mirrors). + # allow_destroy(true) + # end + # end + # + # # Test::Unit + # class CarTest < ActiveSupport::TestCase + # should accept_nested_attributes_for(:mirrors). + # allow_destroy(true) + # end + # + # ##### limit + # + # Use `limit` to assert that the `:limit` option was specified. + # + # class Car < ActiveRecord::Base + # accepts_nested_attributes_for :windows, limit: 3 + # end + # + # # RSpec + # describe Car do + # it do + # should accept_nested_attributes_for(:windows). + # limit(3) + # end + # end + # + # # Test::Unit + # class CarTest < ActiveSupport::TestCase + # should accept_nested_attributes_for(:windows). + # limit(3) + # end + # + # ##### update_only + # + # Use `update_only` to assert that the `:update_only` option was + # specified. + # + # class Car < ActiveRecord::Base + # accepts_nested_attributes_for :engine, update_only: true + # end + # + # # RSpec + # describe Car do + # it do + # should accept_nested_attributes_for(:engine). + # update_only(true) + # end + # end + # + # # Test::Unit + # class CarTest < ActiveSupport::TestCase + # should accept_nested_attributes_for(:engine). + # update_only(true) + # end + # + # @return [AcceptNestedAttributesForMatcher] + # + def accept_nested_attributes_for(name) + AcceptNestedAttributesForMatcher.new(name) + end + + # @private + class AcceptNestedAttributesForMatcher + def initialize(name) + @name = name + @options = {} + end + + def allow_destroy(allow_destroy) + @options[:allow_destroy] = allow_destroy + self + end + + def limit(limit) + @options[:limit] = limit + self + end + + def update_only(update_only) + @options[:update_only] = update_only + self + end + + def matches?(subject) + @subject = subject + exists? && + allow_destroy_correct? && + limit_correct? && + update_only_correct? + end + + def failure_message + "Expected #{expectation} (#{@problem})" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias failure_message_for_should_not failure_message_when_negated + + def description + description = "accepts_nested_attributes_for :#{@name}" + if @options.key?(:allow_destroy) + description += " allow_destroy => #{@options[:allow_destroy]}" + end + if @options.key?(:limit) + description += " limit => #{@options[:limit]}" + end + if @options.key?(:update_only) + description += " update_only => #{@options[:update_only]}" + end + description + end + + protected + + def exists? + if config + true + else + @problem = 'is not declared' + false + end + end + + def allow_destroy_correct? + failure_message = "#{should_or_should_not(@options[:allow_destroy])} allow destroy" + verify_option_is_correct(:allow_destroy, failure_message) + end + + def limit_correct? + failure_message = "limit should be #{@options[:limit]}, got #{config[:limit]}" + verify_option_is_correct(:limit, failure_message) + end + + def update_only_correct? + failure_message = "#{should_or_should_not(@options[:update_only])} be update only" + verify_option_is_correct(:update_only, failure_message) + end + + def verify_option_is_correct(option, failure_message) + if @options.key?(option) + if @options[option] == config[option] + true + else + @problem = failure_message + false + end + else + true + end + end + + def config + model_config[@name] + end + + def model_config + model_class.nested_attributes_options + end + + def model_class + @subject.class + end + + def expectation + "#{model_class.name} to accept nested attributes for #{@name}" + end + + def should_or_should_not(value) + if value + 'should' + else + 'should not' + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/allow_mass_assignment_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the attribute can be set on mass update. - # - # it { should_not allow_mass_assignment_of(:password) } - # it { should allow_mass_assignment_of(:first_name) } - # - def allow_mass_assignment_of(value) - AllowMassAssignmentOfMatcher.new(value) - end - - class AllowMassAssignmentOfMatcher # :nodoc: - - def initialize(attribute) - @attribute = attribute.to_s - end - - def matches?(subject) - @subject = subject - if attr_mass_assignable? - if whitelisting? - @negative_failure_message = "#{@attribute} was made accessible" - else - if protected_attributes.empty? - @negative_failure_message = "no attributes were protected" - else - @negative_failure_message = "#{class_name} is protecting " << - "#{protected_attributes.to_a.to_sentence}, " << - "but not #{@attribute}." - end - end - true - else - if whitelisting? - @failure_message = - "Expected #{@attribute} to be accessible" - else - @failure_message = - "Did not expect #{@attribute} to be protected" - end - false - end - end - - attr_reader :failure_message, :negative_failure_message - - def description - "allow mass assignment of #{@attribute}" - end - - private - - def protected_attributes - @protected_attributes ||= (@subject.class.protected_attributes || []) - end - - def accessible_attributes - @accessible_attributes ||= (@subject.class.accessible_attributes || []) - end - - def whitelisting? - !accessible_attributes.empty? - end - - def attr_mass_assignable? - if whitelisting? - accessible_attributes.include?(@attribute) - else - !protected_attributes.include?(@attribute) - end - end - - def class_name - @subject.class.name - end - - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/allow_value_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/allow_value_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/allow_value_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/allow_value_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,110 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the attribute can be set to the given value. - # - # Options: - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. If omitted, - # the test looks for any errors in errors.on(:attribute). - # - # Example: - # it { should_not allow_value('bad').for(:isbn) } - # it { should allow_value("isbn 1 2345 6789 0").for(:isbn) } - # - def allow_value(value) - AllowValueMatcher.new(value) - end - - class AllowValueMatcher # :nodoc: - include Helpers - - def initialize(value) - @value = value - end - - def for(attribute) - @attribute = attribute - self - end - - def with_message(message) - @expected_message = message if message - self - end - - def matches?(instance) - @instance = instance - if Symbol === @expected_message - @expected_message = default_error_message(@expected_message) - end - @instance.send("#{@attribute}=", @value) - !errors_match? - end - - def failure_message - "Did not expect #{expectation}, got error: #{@matched_error}" - end - - def negative_failure_message - "Expected #{expectation}, got #{error_description}" - end - - def description - "allow #{@attribute} to be set to #{@value.inspect}" - end - - private - - def errors_match? - @instance.valid? - @errors = errors_for_attribute(@instance, @attribute) - @errors = [@errors] unless @errors.is_a?(Array) - @expected_message ? (errors_match_regexp? || errors_match_string?) : (@errors.compact.any?) - end - - def errors_for_attribute(instance, attribute) - if instance.errors.respond_to?(:[]) - instance.errors[attribute] - else - instance.errors.on(attribute) - end - end - - def errors_match_regexp? - if Regexp === @expected_message - @matched_error = @errors.detect { |e| e =~ @expected_message } - !@matched_error.nil? - else - false - end - end - - def errors_match_string? - if @errors.include?(@expected_message) - @matched_error = @expected_message - true - else - false - end - end - - def expectation - "errors " << - (@expected_message ? "to include #{@expected_message.inspect} " : "") << - "when #{@attribute} is set to #{@value.inspect}" - end - - def error_description - if @instance.errors.empty? - "no errors" - else - "errors: #{pretty_error_messages(@instance)}" - end - end - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,103 +1,997 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: +require 'active_support/core_ext/module/delegation' - # Ensure that the belongs_to relationship exists. +module Shoulda + module Matchers + module ActiveRecord + # The `belong_to` matcher is used to ensure that a `belong_to` association + # exists on your model. + # + # class Person < ActiveRecord::Base + # belongs_to :organization + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:organization) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization) + # end + # + # Note that polymorphic associations are automatically detected and do not + # need any qualifiers: + # + # class Comment < ActiveRecord::Base + # belongs_to :commentable, polymorphic: true + # end + # + # # RSpec + # describe Comment do + # it { should belong_to(:commentable) } + # end + # + # # Test::Unit + # class CommentTest < ActiveSupport::TestCase + # should belong_to(:commentable) + # end + # + # #### Qualifiers + # + # ##### conditions + # + # Use `conditions` if your association is defined with a scope that sets + # the `where` clause. + # + # class Person < ActiveRecord::Base + # belongs_to :family, -> { where(everyone_is_perfect: false) } + # end + # + # # RSpec + # describe Person do + # it do + # should belong_to(:family). + # conditions(everyone_is_perfect: false) + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:family). + # conditions(everyone_is_perfect: false) + # end + # + # ##### order + # + # Use `order` if your association is defined with a scope that sets the + # `order` clause. + # + # class Person < ActiveRecord::Base + # belongs_to :previous_company, -> { order('hired_on desc') } + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:previous_company).order('hired_on desc') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:previous_company).order('hired_on desc') + # end + # + # ##### class_name + # + # Use `class_name` to test usage of the `:class_name` option. This + # asserts that the model you're referring to actually exists. + # + # class Person < ActiveRecord::Base + # belongs_to :ancient_city, class_name: 'City' + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:ancient_city).class_name('City') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:ancient_city).class_name('City') + # end + # + # ##### with_primary_key + # + # Use `with_primary_key` to test usage of the `:primary_key` option. + # + # class Person < ActiveRecord::Base + # belongs_to :great_country, primary_key: 'country_id' + # end + # + # # RSpec + # describe Person do + # it do + # should belong_to(:great_country). + # with_primary_key('country_id') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:great_country). + # with_primary_key('country_id') + # end + # + # ##### with_foreign_key + # + # Use `with_foreign_key` to test usage of the `:foreign_key` option. + # + # class Person < ActiveRecord::Base + # belongs_to :great_country, foreign_key: 'country_id' + # end + # + # # RSpec + # describe Person do + # it do + # should belong_to(:great_country). + # with_foreign_key('country_id') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:great_country). + # with_foreign_key('country_id') + # end + # + # ##### dependent + # + # Use `dependent` to assert that the `:dependent` option was specified. + # + # class Person < ActiveRecord::Base + # belongs_to :world, dependent: :destroy + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:world).dependent(:destroy) } + # end # - # it { should belong_to(:parent) } + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:world).dependent(:destroy) + # end + # + # To assert that *any* `:dependent` option was specified, use `true`: + # + # # RSpec + # describe Person do + # it { should belong_to(:world).dependent(true) } + # end + # + # To assert that *no* `:dependent` option was specified, use `false`: + # + # class Person < ActiveRecord::Base + # belongs_to :company + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:company).dependent(false) } + # end + # + # ##### counter_cache + # + # Use `counter_cache` to assert that the `:counter_cache` option was + # specified. + # + # class Person < ActiveRecord::Base + # belongs_to :organization, counter_cache: true + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:organization).counter_cache(true) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).counter_cache(true) + # end + # + # ##### touch + # + # Use `touch` to assert that the `:touch` option was specified. + # + # class Person < ActiveRecord::Base + # belongs_to :organization, touch: true + # end + # + # # RSpec + # describe Person do + # it { should belong_to(:organization).touch(true) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).touch(true) + # end + # + # #### autosave + # + # Use `autosave` to assert that the `:autosave` option was specified. + # + # class Account < ActiveRecord::Base + # belongs_to :bank, autosave: true + # end + # + # # RSpec + # describe Account do + # it { should belong_to(:bank).autosave(true) } + # end + # + # # Test::Unit + # class AccountTest < ActiveSupport::TestCase + # should belong_to(:bank).autosave(true) + # end + # + # ##### inverse_of + # + # Use `inverse_of` to assert that the `:inverse_of` option was specified. + # + # class Person < ActiveRecord::Base + # belongs_to :organization, inverse_of: :employees + # end + # + # # RSpec + # describe Person + # it { should belong_to(:organization).inverse_of(:employees) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should belong_to(:organization).inverse_of(:employees) + # end + # + # @return [AssociationMatcher] # def belong_to(name) AssociationMatcher.new(:belongs_to, name) end - # Ensures that the has_many relationship exists. Will also test that the - # associated table has the required columns. Works with polymorphic - # associations. - # - # Options: - # * through - association name for has_many :through - # * dependent - tests that the association makes use of the - # dependent option. - # - # Example: - # it { should have_many(:friends) } - # it { should have_many(:enemies).through(:friends) } - # it { should have_many(:enemies).dependent(:destroy) } + # The `have_many` matcher is used to test that a `has_many` or `has_many + # :through` association exists on your model. + # + # class Person < ActiveRecord::Base + # has_many :friends + # end + # + # # RSpec + # describe Person do + # it { should have_many(:friends) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:friends) + # end + # + # #### Qualifiers + # + # ##### conditions + # + # Use `conditions` if your association is defined with a scope that sets + # the `where` clause. + # + # class Person < ActiveRecord::Base + # has_many :coins, -> { where(quality: 'mint') } + # end + # + # # RSpec + # describe Person do + # it { should have_many(:coins).conditions(quality: 'mint') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:coins).conditions(quality: 'mint') + # end + # + # ##### order + # + # Use `order` if your association is defined with a scope that sets the + # `order` clause. + # + # class Person < ActiveRecord::Base + # has_many :shirts, -> { order('color') } + # end + # + # # RSpec + # describe Person do + # it { should have_many(:shirts).order('color') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:shirts).order('color') + # end + # + # ##### class_name + # + # Use `class_name` to test usage of the `:class_name` option. This + # asserts that the model you're referring to actually exists. + # + # class Person < ActiveRecord::Base + # has_many :hopes, class_name: 'Dream' + # end + # + # # RSpec + # describe Person do + # it { should have_many(:hopes).class_name('Dream') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:hopes).class_name('Dream') + # end + # + # ##### with_primary_key + # + # Use `with_primary_key` to test usage of the `:primary_key` option. + # + # class Person < ActiveRecord::Base + # has_many :worries, primary_key: 'worrier_id' + # end + # + # # RSpec + # describe Person do + # it { should have_many(:worries).with_primary_key('worrier_id') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:worries).with_primary_key('worrier_id') + # end + # + # ##### with_foreign_key + # + # Use `with_foreign_key` to test usage of the `:foreign_key` option. + # + # class Person < ActiveRecord::Base + # has_many :worries, foreign_key: 'worrier_id' + # end + # + # # RSpec + # describe Person do + # it { should have_many(:worries).with_foreign_key('worrier_id') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:worries).with_foreign_key('worrier_id') + # end + # + # ##### dependent + # + # Use `dependent` to assert that the `:dependent` option was specified. + # + # class Person < ActiveRecord::Base + # has_many :secret_documents, dependent: :destroy + # end + # + # # RSpec + # describe Person do + # it { should have_many(:secret_documents).dependent(:destroy) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:secret_documents).dependent(:destroy) + # end + # + # ##### through + # + # Use `through` to test usage of the `:through` option. This asserts that + # the association you are going through actually exists. + # + # class Person < ActiveRecord::Base + # has_many :acquaintances, through: :friends + # end + # + # # RSpec + # describe Person do + # it { should have_many(:acquaintances).through(:friends) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:acquaintances).through(:friends) + # end + # + # ##### source + # + # Use `source` to test usage of the `:source` option on a `:through` + # association. + # + # class Person < ActiveRecord::Base + # has_many :job_offers, through: :friends, source: :opportunities + # end + # + # # RSpec + # describe Person do + # it do + # should have_many(:job_offers). + # through(:friends). + # source(:opportunities) + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:job_offers). + # through(:friends). + # source(:opportunities) + # end + # + # ##### validate + # + # Use `validate` to assert that the `:validate` option was specified. + # + # class Person < ActiveRecord::Base + # has_many :ideas, validate: false + # end + # + # # RSpec + # describe Person do + # it { should have_many(:ideas).validate(false) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_many(:ideas).validate(false) + # end + # + # #### autosave + # + # Use `autosave` to assert that the `:autosave` option was specified. + # + # class Player < ActiveRecord::Base + # has_many :games, autosave: true + # end + # + # # RSpec + # describe Player do + # it { should have_many(:games).autosave(true) } + # end + # + # # Test::Unit + # class PlayerTest < ActiveSupport::TestCase + # should have_many(:games).autosave(true) + # end + # + # @return [AssociationMatcher] # def have_many(name) AssociationMatcher.new(:has_many, name) end - # Ensure that the has_one relationship exists. Will also test that the - # associated table has the required columns. Works with polymorphic - # associations. - # - # Options: - # * :dependent - tests that the association makes use of the - # dependent option. + # The `have_one` matcher is used to test that a `has_one` or `has_one + # :through` association exists on your model. + # + # class Person < ActiveRecord::Base + # has_one :partner + # end + # + # # RSpec + # describe Person do + # it { should have_one(:partner) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:partner) + # end + # + # #### Qualifiers + # + # ##### conditions + # + # Use `conditions` if your association is defined with a scope that sets + # the `where` clause. + # + # class Person < ActiveRecord::Base + # has_one :pet, -> { where('weight < 80') } + # end + # + # # RSpec + # describe Person do + # it { should have_one(:pet).conditions('weight < 80') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:pet).conditions('weight < 80') + # end + # + # ##### order + # + # Use `order` if your association is defined with a scope that sets the + # `order` clause. + # + # class Person < ActiveRecord::Base + # has_one :focus, -> { order('priority desc') } + # end + # + # # RSpec + # describe Person do + # it { should have_one(:focus).order('priority desc') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:focus).order('priority desc') + # end + # + # ##### class_name + # + # Use `class_name` to test usage of the `:class_name` option. This + # asserts that the model you're referring to actually exists. + # + # class Person < ActiveRecord::Base + # has_one :chance, class_name: 'Opportunity' + # end + # + # # RSpec + # describe Person do + # it { should have_one(:chance).class_name('Opportunity') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:chance).class_name('Opportunity') + # end + # + # ##### dependent + # + # Use `dependent` to test that the `:dependent` option was specified. + # + # class Person < ActiveRecord::Base + # has_one :contract, dependent: :nullify + # end + # + # # RSpec + # describe Person do + # it { should have_one(:contract).dependent(:nullify) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:contract).dependent(:nullify) + # end + # + # ##### with_primary_key + # + # Use `with_primary_key` to test usage of the `:primary_key` option. + # + # class Person < ActiveRecord::Base + # has_one :job, primary_key: 'worker_id' + # end + # + # # RSpec + # describe Person do + # it { should have_one(:job).with_primary_key('worker_id') } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:job).with_primary_key('worker_id') + # end + # + # ##### with_foreign_key + # + # Use `with_foreign_key` to test usage of the `:foreign_key` option. + # + # class Person < ActiveRecord::Base + # has_one :job, foreign_key: 'worker_id' + # end + # + # # RSpec + # describe Person do + # it { should have_one(:job).with_foreign_key('worker_id') } + # end # - # Example: - # it { should have_one(:god) } # unless hindu + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:job).with_foreign_key('worker_id') + # end + # + # ##### through + # + # Use `through` to test usage of the `:through` option. This asserts that + # the association you are going through actually exists. + # + # class Person < ActiveRecord::Base + # has_one :life, through: :partner + # end + # + # # RSpec + # describe Person do + # it { should have_one(:life).through(:partner) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:life).through(:partner) + # end + # + # ##### source + # + # Use `source` to test usage of the `:source` option on a `:through` + # association. + # + # class Person < ActiveRecord::Base + # has_one :car, through: :partner, source: :vehicle + # end + # + # # RSpec + # describe Person do + # it { should have_one(:car).through(:partner).source(:vehicle) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:car).through(:partner).source(:vehicle) + # end + # + # ##### validate + # + # Use `validate` to assert that the the `:validate` option was specified. + # + # class Person < ActiveRecord::Base + # has_one :parking_card, validate: false + # end + # + # # RSpec + # describe Person do + # it { should have_one(:parking_card).validate(false) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_one(:parking_card).validate(false) + # end + # + # #### autosave + # + # Use `autosave` to assert that the `:autosave` option was specified. + # + # class Account < ActiveRecord::Base + # has_one :bank, autosave: true + # end + # + # # RSpec + # describe Account do + # it { should have_one(:bank).autosave(true) } + # end + # + # # Test::Unit + # class AccountTest < ActiveSupport::TestCase + # should have_one(:bank).autosave(true) + # end + # + # @return [AssociationMatcher] # def have_one(name) AssociationMatcher.new(:has_one, name) end - # Ensures that the has_and_belongs_to_many relationship exists, and that - # the join table is in place. + # The `have_and_belong_to_many` matcher is used to test that a + # `has_and_belongs_to_many` association exists on your model and that the + # join table exists in the database. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :awards + # end + # + # # RSpec + # describe Person do + # it { should have_and_belong_to_many(:awards) } + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:awards) + # end + # + # #### Qualifiers + # + # ##### conditions + # + # Use `conditions` if your association is defined with a scope that sets + # the `where` clause. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :issues, -> { where(difficulty: 'hard') } + # end + # + # # RSpec + # describe Person do + # it do + # should have_and_belong_to_many(:issues). + # conditions(difficulty: 'hard') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:issues). + # conditions(difficulty: 'hard') + # end + # + # ##### order + # + # Use `order` if your association is defined with a scope that sets the + # `order` clause. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :projects, -> { order('time_spent') } + # end + # + # # RSpec + # describe Person do + # it do + # should have_and_belong_to_many(:projects). + # order('time_spent') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:projects). + # order('time_spent') + # end + # + # ##### class_name + # + # Use `class_name` to test usage of the `:class_name` option. This + # asserts that the model you're referring to actually exists. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :places_visited, class_name: 'City' + # end # - # it { should have_and_belong_to_many(:posts) } + # # RSpec + # describe Person do + # it do + # should have_and_belong_to_many(:places_visited). + # class_name('City') + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:places_visited). + # class_name('City') + # end + # + # ##### validate + # + # Use `validate` to test that the `:validate` option was specified. + # + # class Person < ActiveRecord::Base + # has_and_belongs_to_many :interviews, validate: false + # end + # + # # RSpec + # describe Person do + # it do + # should have_and_belong_to_many(:interviews). + # validate(false) + # end + # end + # + # # Test::Unit + # class PersonTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:interviews). + # validate(false) + # end + # + # #### autosave + # + # Use `autosave` to assert that the `:autosave` option was specified. + # + # class Publisher < ActiveRecord::Base + # has_and_belongs_to_many :advertisers, autosave: true + # end + # + # # RSpec + # describe Publisher do + # it { should have_and_belong_to_many(:advertisers).autosave(true) } + # end + # + # # Test::Unit + # class AccountTest < ActiveSupport::TestCase + # should have_and_belong_to_many(:advertisers).autosave(true) + # end + # + # @return [AssociationMatcher] # def have_and_belong_to_many(name) AssociationMatcher.new(:has_and_belongs_to_many, name) end - class AssociationMatcher # :nodoc: + # @private + class AssociationMatcher + delegate :reflection, :model_class, :associated_class, :through?, + :join_table, :polymorphic?, to: :reflector + def initialize(macro, name) @macro = macro - @name = name + @name = name + @options = {} + @submatchers = [] + @missing = '' end def through(through) - @through = through + through_matcher = AssociationMatchers::ThroughMatcher.new(through, name) + add_submatcher(through_matcher) self end def dependent(dependent) - @dependent = dependent + dependent_matcher = AssociationMatchers::DependentMatcher.new(dependent, name) + add_submatcher(dependent_matcher) + self + end + + def order(order) + order_matcher = AssociationMatchers::OrderMatcher.new(order, name) + add_submatcher(order_matcher) + self + end + + def counter_cache(counter_cache = true) + counter_cache_matcher = AssociationMatchers::CounterCacheMatcher.new(counter_cache, name) + add_submatcher(counter_cache_matcher) + self + end + + def inverse_of(inverse_of) + inverse_of_matcher = + AssociationMatchers::InverseOfMatcher.new(inverse_of, name) + add_submatcher(inverse_of_matcher) + self + end + + def source(source) + source_matcher = AssociationMatchers::SourceMatcher.new(source, name) + add_submatcher(source_matcher) + self + end + + def conditions(conditions) + @options[:conditions] = conditions + self + end + + def autosave(autosave) + @options[:autosave] = autosave + self + end + + def class_name(class_name) + @options[:class_name] = class_name + self + end + + def with_foreign_key(foreign_key) + @options[:foreign_key] = foreign_key + self + end + + def with_primary_key(primary_key) + @options[:primary_key] = primary_key + self + end + + def validate(validate = true) + @options[:validate] = validate self end + def touch(touch = true) + @options[:touch] = touch + self + end + + def description + description = "#{macro_description} #{name}" + description += " class_name => #{options[:class_name]}" if options.key?(:class_name) + [description, submatchers.map(&:description)].flatten.join(' ') + end + + def failure_message + "Expected #{expectation} (#{missing_options})" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias failure_message_for_should_not failure_message_when_negated + def matches?(subject) @subject = subject association_exists? && macro_correct? && + (polymorphic? || class_exists?) && foreign_key_exists? && - through_association_valid? && - dependent_correct? && - join_table_exists? + primary_key_exists? && + class_name_correct? && + join_table_correct? && + autosave_correct? && + conditions_correct? && + validate_correct? && + touch_correct? && + submatchers_match? end - def failure_message - "Expected #{expectation} (#{@missing})" + protected + + attr_reader :submatchers, :missing, :subject, :macro, :name, :options + + def reflector + @reflector ||= AssociationMatchers::ModelReflector.new(subject, name) end - def negative_failure_message - "Did not expect #{expectation}" + def option_verifier + @option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector) end - def description - description = "#{macro_description} #{@name}" - description += " through #{@through}" if @through - description += " dependent => #{@dependent}" if @dependent - description + def add_submatcher(matcher) + @submatchers << matcher end - protected + def macro_description + case macro.to_s + when 'belongs_to' + 'belong to' + when 'has_many' + 'have many' + when 'has_one' + 'have one' + when 'has_and_belongs_to_many' + 'have and belong to many' + end + end + + def expectation + "#{model_class.name} to have a #{macro} association called #{name}" + end + + def missing_options + missing_options = [missing, missing_options_for_failing_submatchers] + missing_options.flatten.compact.join(', ') + end + + def failing_submatchers + @failing_submatchers ||= submatchers.reject do |matcher| + matcher.matches?(subject) + end + end + + def missing_options_for_failing_submatchers + if defined?(@failing_submatchers) + @failing_submatchers.map(&:missing_option) + else + [] + end + end def association_exists? if reflection.nil? - @missing = "no association called #{@name}" + @missing = "no association called #{name}" false else true @@ -105,122 +999,167 @@ end def macro_correct? - if reflection.macro == @macro + if reflection.macro == macro true + elsif reflection.macro == :has_many + macro == :has_and_belongs_to_many && + reflection.name == @name else @missing = "actual association type was #{reflection.macro}" false end end + def macro_supports_primary_key? + macro == :belongs_to || + ([:has_many, :has_one].include?(macro) && !through?) + end + def foreign_key_exists? !(belongs_foreign_key_missing? || has_foreign_key_missing?) end + def primary_key_exists? + !macro_supports_primary_key? || primary_key_correct?(model_class) + end + def belongs_foreign_key_missing? - @macro == :belongs_to && !class_has_foreign_key?(model_class) + macro == :belongs_to && !class_has_foreign_key?(model_class) end def has_foreign_key_missing? - [:has_many, :has_one].include?(@macro) && + [:has_many, :has_one].include?(macro) && !through? && !class_has_foreign_key?(associated_class) end - def through_association_valid? - @through.nil? || (through_association_exists? && through_association_correct?) - end - - def through_association_exists? - if through_reflection.nil? - @missing = "#{model_class.name} does not have any relationship to #{@through}" - false + def class_name_correct? + if options.key?(:class_name) + if option_verifier.correct_for_constant?(:class_name, options[:class_name]) + true + else + @missing = "#{name} should resolve to #{options[:class_name]} for class_name" + false + end else true end end - def through_association_correct? - if @through == reflection.options[:through] + def join_table_correct? + if macro != :has_and_belongs_to_many || join_table_matcher.matches?(@subject) true else - @missing = "Expected #{model_class.name} to have #{@name} through #{@through}, " << - "but got it through #{reflection.options[:through]}" + @missing = join_table_matcher.failure_message false end end - def dependent_correct? - if @dependent.nil? || @dependent.to_s == reflection.options[:dependent].to_s + def join_table_matcher + @join_table_matcher ||= + AssociationMatchers::JoinTableMatcher.new(self, reflector) + end + + def class_exists? + associated_class + true + rescue NameError + @missing = "#{reflection.class_name} does not exist" + false + end + + def autosave_correct? + if options.key?(:autosave) + if option_verifier.correct_for_boolean?(:autosave, options[:autosave]) + true + else + @missing = "#{name} should have autosave set to #{options[:autosave]}" + false + end + else true + end + end + + def conditions_correct? + if options.key?(:conditions) + if option_verifier.correct_for_relation_clause?(:conditions, options[:conditions]) + true + else + @missing = "#{name} should have the following conditions: #{options[:conditions]}" + false + end else - @missing = "#{@name} should have #{@dependent} dependency" - false + true end end - def join_table_exists? - if @macro != :has_and_belongs_to_many || - ::ActiveRecord::Base.connection.tables.include?(join_table.to_s) + def validate_correct? + if option_verifier.correct_for_boolean?(:validate, options[:validate]) true else - @missing = "join table #{join_table} doesn't exist" + @missing = "#{name} should have validate: #{options[:validate]}" false end end - def class_has_foreign_key?(klass) - if klass.column_names.include?(foreign_key.to_s) + def touch_correct? + if option_verifier.correct_for_boolean?(:touch, options[:touch]) true else - @missing = "#{klass} does not have a #{foreign_key} foreign key." + @missing = "#{name} should have touch: #{options[:touch]}" false end end - def model_class - @subject.class - end - - def join_table - reflection.options[:join_table] + def class_has_foreign_key?(klass) + if options.key?(:foreign_key) + option_verifier.correct_for_string?(:foreign_key, options[:foreign_key]) + else + if klass.column_names.include?(foreign_key) + true + else + @missing = "#{klass} does not have a #{foreign_key} foreign key." + false + end + end end - def associated_class - reflection.klass + def primary_key_correct?(klass) + if options.key?(:primary_key) + if option_verifier.correct_for_string?(:primary_key, options[:primary_key]) + true + else + @missing = "#{klass} does not have a #{options[:primary_key]} primary key" + false + end + else + true + end end def foreign_key - reflection.primary_key_name - end - - def through? - reflection.options[:through] - end - - def reflection - @reflection ||= model_class.reflect_on_association(@name) - end - - def through_reflection - @through_reflection ||= model_class.reflect_on_association(@through) + if foreign_key_reflection + if foreign_key_reflection.respond_to?(:foreign_key) + foreign_key_reflection.foreign_key.to_s + else + foreign_key_reflection.primary_key_name.to_s + end + end end - def expectation - "#{model_class.name} to have a #{@macro} association called #{@name}" + def foreign_key_reflection + if [:has_one, :has_many].include?(macro) && reflection.options.include?(:inverse_of) + associated_class.reflect_on_association(reflection.options[:inverse_of]) + else + reflection + end end - def macro_description - case @macro.to_s - when 'belongs_to' then 'belong to' - when 'has_many' then 'have many' - when 'has_one' then 'have one' - when 'has_and_belongs_to_many' then - 'have and belong to many' - end + def submatchers_match? + failing_submatchers.empty? end end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class CounterCacheMatcher + attr_accessor :missing_option + + def initialize(counter_cache, name) + @counter_cache = counter_cache + @name = name + @missing_option = '' + end + + def description + "counter_cache => #{counter_cache}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + + if option_verifier.correct_for_string?(:counter_cache, counter_cache) + true + else + self.missing_option = "#{name} should have #{description}" + false + end + end + + protected + + attr_accessor :subject, :counter_cache, :name + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,62 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class DependentMatcher + attr_accessor :missing_option + + def initialize(dependent, name) + @dependent = dependent + @name = name + @missing_option = '' + end + + def description + "dependent => #{dependent}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + + if option_matches? + true + else + self.missing_option = generate_missing_option + false + end + end + + protected + + attr_accessor :subject, :dependent, :name + + private + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + + def option_matches? + option_verifier.correct_for?(option_type, :dependent, dependent) + end + + def option_type + case dependent + when true, false then :boolean + else :string + end + end + + def generate_missing_option + [ + "#{name} should have", + (dependent == true ? 'a' : dependent), + 'dependency' + ].join(' ') + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class InverseOfMatcher + attr_accessor :missing_option + + def initialize(inverse_of, name) + @inverse_of = inverse_of + @name = name + @missing_option = '' + end + + def description + "inverse_of => #{inverse_of}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + + if option_verifier.correct_for_string?(:inverse_of, inverse_of) + true + else + self.missing_option = "#{name} should have #{description}" + false + end + end + + protected + + attr_accessor :subject, :inverse_of, :name + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,86 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class JoinTableMatcher + attr_reader :failure_message + + alias :missing_option :failure_message + + delegate :model_class, :join_table, :associated_class, + to: :association_matcher + + delegate :connection, to: :model_class + + def initialize(association_matcher, reflector) + @association_matcher = association_matcher + @reflector = reflector + end + + def matches?(subject) + join_table_exists? && + join_table_has_correct_columns? + end + + def join_table_exists? + if connection.tables.include?(join_table) + true + else + @failure_message = missing_table_message + false + end + end + + def join_table_has_correct_columns? + if missing_columns.empty? + true + else + @failure_message = missing_columns_message + false + end + end + + protected + + attr_reader :association_matcher, :reflector + + private + + delegate :foreign_key, :association_foreign_key, to: :reflector + + def missing_columns + @missing_columns ||= expected_join_table_columns.select do |key| + !actual_join_table_columns.include?(key.to_s) + end + end + + def expected_join_table_columns + [foreign_key, association_foreign_key] + end + + def actual_join_table_columns + connection.columns(join_table).map(&:name) + end + + def missing_table_message + "join table #{join_table} doesn't exist" + end + + def missing_columns_message + missing = missing_columns.join(', ') + "join table #{join_table} missing #{column_label}: #{missing}" + end + + def column_label + if missing_columns.count > 1 + 'columns' + else + 'column' + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,123 @@ +require 'delegate' + +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class ModelReflection < SimpleDelegator + def initialize(reflection) + super(reflection) + @reflection = reflection + @subject = reflection.active_record + end + + def associated_class + reflection.klass + end + + def polymorphic? + reflection.options[:polymorphic] + end + + def through? + reflection.options[:through] + end + + def join_table + join_table = + if has_and_belongs_to_many_name_table_name + has_and_belongs_to_many_name_table_name + elsif reflection.respond_to?(:join_table) + reflection.join_table + else + reflection.options[:join_table] + end + + join_table.to_s + end + + def association_relation + if reflection.respond_to?(:scope) + convert_scope_to_relation(reflection.scope) + else + convert_options_to_relation(reflection.options) + end + end + + def foreign_key + if has_and_belongs_to_many_reflection + has_and_belongs_to_many_reflection.foreign_key + elsif reflection.respond_to?(:foreign_key) + reflection.foreign_key + else + reflection.primary_key_name + end + end + + def association_foreign_key + if has_and_belongs_to_many_reflection + join_model = has_and_belongs_to_many_reflection.options[:class] + join_model.right_reflection.foreign_key + else + reflection.association_foreign_key + end + end + + protected + + attr_reader :reflection, :subject + + def convert_scope_to_relation(scope) + relation = associated_class.all + + if scope + # Source: AR::Associations::AssociationScope#eval_scope + relation.instance_exec(subject, &scope) + else + relation + end + end + + def convert_options_to_relation(options) + relation = associated_class.scoped + relation = extend_relation_with(relation, :where, options[:conditions]) + relation = extend_relation_with(relation, :includes, options[:include]) + relation = extend_relation_with(relation, :order, options[:order]) + relation = extend_relation_with(relation, :group, options[:group]) + relation = extend_relation_with(relation, :having, options[:having]) + relation = extend_relation_with(relation, :limit, options[:limit]) + relation = extend_relation_with(relation, :offset, options[:offset]) + relation = extend_relation_with(relation, :select, options[:select]) + relation + end + + def extend_relation_with(relation, method_name, value) + if value + relation.__send__(method_name, value) + else + relation + end + end + + def has_and_belongs_to_many_name + reflection.options[:through] + end + + def has_and_belongs_to_many_name_table_name + if has_and_belongs_to_many_reflection + has_and_belongs_to_many_reflection.table_name + end + end + + def has_and_belongs_to_many_reflection + @_has_and_belongs_to_many_reflection ||= + if has_and_belongs_to_many_name + @subject.reflect_on_association(has_and_belongs_to_many_name) + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,66 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class ModelReflector + delegate :associated_class, :through?, :join_table, + :association_relation, :polymorphic?, :foreign_key, + :association_foreign_key, to: :reflection + + def initialize(subject, name) + @subject = subject + @name = name + end + + def reflection + @reflection ||= reflect_on_association(name) + end + + def reflect_on_association(name) + reflection = model_class.reflect_on_association(name) + + if reflection + ModelReflection.new(reflection) + end + end + + def model_class + subject.class + end + + def build_relation_with_clause(name, value) + case name + when :conditions then associated_class.where(value) + when :order then associated_class.order(value) + else raise ArgumentError, "Unknown clause '#{name}'" + end + end + + def extract_relation_clause_from(relation, name) + case name + when :conditions + relation.where_values_hash + when :order + relation.order_values.map { |value| value_as_sql(value) }.join(', ') + else + raise ArgumentError, "Unknown clause '#{name}'" + end + end + + protected + + attr_reader :subject, :name + + def value_as_sql(value) + if value.respond_to?(:to_sql) + value.to_sql + else + value + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,115 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class OptionVerifier + delegate :reflection, to: :reflector + + RELATION_OPTIONS = [:conditions, :order] + + def initialize(reflector) + @reflector = reflector + end + + def correct_for_string?(name, expected_value) + correct_for?(:string, name, expected_value) + end + + def correct_for_boolean?(name, expected_value) + correct_for?(:boolean, name, expected_value) + end + + def correct_for_hash?(name, expected_value) + correct_for?(:hash, name, expected_value) + end + + def correct_for_constant?(name, expected_unresolved_value) + correct_for?(:constant, name, expected_unresolved_value) + end + + def correct_for_relation_clause?(name, expected_value) + correct_for?(:relation_clause, name, expected_value) + end + + def correct_for?(*args) + expected_value, name, type = args.reverse + if expected_value.nil? + true + else + expected_value = type_cast( + type, + expected_value_for(type, name, expected_value) + ) + actual_value = type_cast(type, actual_value_for(name)) + expected_value == actual_value + end + end + + def actual_value_for(name) + if RELATION_OPTIONS.include?(name) + actual_value_for_relation_clause(name) + else + method_name = "actual_value_for_#{name}" + if respond_to?(method_name, true) + __send__(method_name) + else + reflection.options[name] + end + end + end + + protected + + attr_reader :reflector + + def type_cast(type, value) + case type + when :string, :relation_clause then value.to_s + when :boolean then !!value + when :hash then Hash(value).stringify_keys + else value + end + end + + def expected_value_for(type, name, value) + if RELATION_OPTIONS.include?(name) + expected_value_for_relation_clause(name, value) + elsif type == :constant + expected_value_for_constant(value) + else + value + end + end + + def expected_value_for_relation_clause(name, value) + relation = reflector.build_relation_with_clause(name, value) + reflector.extract_relation_clause_from(relation, name) + end + + def expected_value_for_constant(name) + namespace = Shoulda::Matchers::Util.deconstantize( + reflector.model_class.to_s + ) + + ["#{namespace}::#{name}", name].each do |path| + constant = Shoulda::Matchers::Util.safe_constantize(path) + + if constant + return constant + end + end + end + + def actual_value_for_relation_clause(name) + reflector.extract_relation_clause_from(reflector.association_relation, name) + end + + def actual_value_for_class_name + reflector.associated_class + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class OrderMatcher + attr_accessor :missing_option + + def initialize(order, name) + @order = order + @name = name + @missing_option = '' + end + + def description + "order => #{order}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + + if option_verifier.correct_for_relation_clause?(:order, order) + true + else + self.missing_option = "#{name} should be ordered by #{order}" + false + end + end + + protected + + attr_accessor :subject, :order, :name + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class SourceMatcher + attr_accessor :missing_option + + def initialize(source, name) + @source = source + @name = name + @missing_option = '' + end + + def description + "source => #{source}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + + if option_verifier.correct_for_string?(:source, source) + true + else + self.missing_option = "#{name} should have #{source} as source option" + false + end + end + + protected + + attr_accessor :subject, :source, :name + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,63 @@ +module Shoulda + module Matchers + module ActiveRecord + module AssociationMatchers + # @private + class ThroughMatcher + attr_accessor :missing_option + + def initialize(through, name) + @through = through + @name = name + @missing_option = '' + end + + def description + "through #{through}" + end + + def matches?(subject) + self.subject = ModelReflector.new(subject, name) + through.nil? || association_set_properly? + end + + def association_set_properly? + through_association_exists? && through_association_correct? + end + + def through_association_exists? + if through_reflection.present? + true + else + self.missing_option = "#{name} does not have any relationship to #{through}" + false + end + end + + def through_reflection + @through_reflection ||= subject.reflect_on_association(through) + end + + def through_association_correct? + if option_verifier.correct_for_string?(:through, through) + true + else + self.missing_option = + "Expected #{name} to have #{name} through #{through}, " + + "but got it through #{option_verifier.actual_value_for(:through)}" + false + end + end + + protected + + attr_accessor :through, :name, :subject + + def option_verifier + @option_verifier ||= OptionVerifier.new(subject) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/association_matchers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/association_matchers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,9 @@ +module Shoulda + module Matchers + module ActiveRecord + # @private + module AssociationMatchers + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,138 @@ +module Shoulda + module Matchers + module ActiveRecord + # The `define_enum_for` matcher is used to test that the `enum` macro has + # been used to decorate an attribute with enum methods. + # + # class Process < ActiveRecord::Base + # enum status: [:running, :stopped, :suspended] + # end + # + # # RSpec + # describe Process do + # it { should define_enum_for(:status) } + # end + # end + # + # # Test::Unit + # class ProcessTest < ActiveSupport::TestCase + # should define_enum_for(:status) + # end + # + # #### Qualifiers + # + # ##### with + # + # Use `with` to test that the enum has been defined with a certain set of + # known values. + # + # class Process < ActiveRecord::Base + # enum status: [:running, :stopped, :suspended] + # end + # + # # RSpec + # describe Process do + # it do + # should define_enum_for(:status). + # with([:running, :stopped, :suspended]) + # end + # end + # + # # Test::Unit + # class ProcessTest < ActiveSupport::TestCase + # should define_enum_for(:status). + # with([:running, :stopped, :suspended]) + # end + # + # @return [DefineEnumForMatcher] + # + def define_enum_for(attribute_name) + DefineEnumForMatcher.new(attribute_name) + end + + # @private + class DefineEnumForMatcher + def initialize(attribute_name) + @attribute_name = attribute_name + @options = {} + end + + def with(expected_enum_values) + options[:expected_enum_values] = expected_enum_values + self + end + + def matches?(subject) + @model = subject + enum_defined? && enum_values_match? + end + + def failure_message + "Expected #{expectation}" + end + alias :failure_message_for_should :failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias :failure_message_for_should_not :failure_message_when_negated + + def description + desc = "define :#{attribute_name} as an enum" + + if options[:expected_enum_values] + desc << " with #{options[:expected_enum_values]}" + end + + desc + end + + protected + + attr_reader :model, :attribute_name, :options + + def expectation + "#{model.class.name} to #{description}" + end + + def expected_enum_values + hashify(options[:expected_enum_values]).with_indifferent_access + end + + def enum_method + attribute_name.to_s.pluralize + end + + def actual_enum_values + model.class.send(enum_method) + end + + def enum_defined? + model.class.respond_to?(enum_method) + end + + def enum_values_match? + expected_enum_values.empty? || actual_enum_values == expected_enum_values + end + + def hashify(value) + if value.nil? + return {} + end + + if value.is_a?(Array) + new_value = {} + + value.each_with_index do |v, i| + new_value[v] = i + end + + new_value + else + value + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/ensure_inclusion_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensure that the attribute's value is in the range specified - # - # Options: - # * in_range - the range of allowed values for this attribute - # * with_low_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :inclusion. - # * with_high_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :inclusion. - # - # Example: - # it { should ensure_inclusion_of(:age).in_range(0..100) } - # - def ensure_inclusion_of(attr) - EnsureInclusionOfMatcher.new(attr) - end - - class EnsureInclusionOfMatcher < ValidationMatcher # :nodoc: - - def in_range(range) - @range = range - @minimum = range.first - @maximum = range.last - self - end - - def with_message(message) - if message - @low_message = message - @high_message = message - end - self - end - - def with_low_message(message) - @low_message = message if message - self - end - - def with_high_message(message) - @high_message = message if message - self - end - - def description - "ensure inclusion of #{@attribute} in #{@range.inspect}" - end - - def matches?(subject) - super(subject) - - @low_message ||= :inclusion - @high_message ||= :inclusion - - disallows_lower_value && - allows_minimum_value && - disallows_higher_value && - allows_maximum_value - end - - private - - def disallows_lower_value - @minimum == 0 || disallows_value_of(@minimum - 1, @low_message) - end - - def disallows_higher_value - disallows_value_of(@maximum + 1, @high_message) - end - - def allows_minimum_value - allows_value_of(@minimum, @low_message) - end - - def allows_maximum_value - allows_value_of(@maximum, @high_message) - end - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/ensure_length_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the length of the attribute is validated. - # - # Options: - # * is_at_least - minimum length of this attribute - # * is_at_most - maximum length of this attribute - # * is_equal_to - exact requred length of this attribute - # * with_short_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :too_short. - # * with_long_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :too_long. - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :wrong_length. Used in conjunction with - # is_equal_to. - # - # Examples: - # it { should ensure_length_of(:password). - # is_at_least(6). - # is_at_most(20) } - # it { should ensure_length_of(:name). - # is_at_least(3). - # with_short_message(/not long enough/) } - # it { should ensure_length_of(:ssn). - # is_equal_to(9). - # with_message(/is invalid/) } - def ensure_length_of(attr) - EnsureLengthOfMatcher.new(attr) - end - - class EnsureLengthOfMatcher < ValidationMatcher # :nodoc: - include Helpers - - def is_at_least(length) - @minimum = length - @short_message ||= :too_short - self - end - - def is_at_most(length) - @maximum = length - @long_message ||= :too_long - self - end - - def is_equal_to(length) - @minimum = length - @maximum = length - @short_message ||= :wrong_length - self - end - - def with_short_message(message) - @short_message = message if message - self - end - alias_method :with_message, :with_short_message - - def with_long_message(message) - @long_message = message if message - self - end - - def description - description = "ensure #{@attribute} has a length " - if @minimum && @maximum - if @minimum == @maximum - description << "of exactly #{@minimum}" - else - description << "between #{@minimum} and #{@maximum}" - end - else - description << "of at least #{@minimum}" if @minimum - description << "of at most #{@maximum}" if @maximum - end - description - end - - def matches?(subject) - super(subject) - translate_messages! - disallows_lower_length && - allows_minimum_length && - ((@minimum == @maximum) || - (disallows_higher_length && - allows_maximum_length)) - end - - private - - def translate_messages! - if Symbol === @short_message - @short_message = default_error_message(@short_message, - :count => @minimum) - end - - if Symbol === @long_message - @long_message = default_error_message(@long_message, - :count => @maximum) - end - end - - def disallows_lower_length - @minimum == 0 || - @minimum.nil? || - disallows_length_of(@minimum - 1, @short_message) - end - - def disallows_higher_length - @maximum.nil? || disallows_length_of(@maximum + 1, @long_message) - end - - def allows_minimum_length - allows_length_of(@minimum, @short_message) - end - - def allows_maximum_length - allows_length_of(@maximum, @long_message) - end - - def allows_length_of(length, message) - length.nil? || allows_value_of(string_of_length(length), message) - end - - def disallows_length_of(length, message) - length.nil? || disallows_value_of(string_of_length(length), message) - end - - def string_of_length(length) - 'x' * length - end - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_db_column_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_db_column_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_column_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,41 +1,105 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActiveRecord # :nodoc: - - # Ensures the database column exists. + module ActiveRecord + # The `have_db_column` matcher tests that the table that backs your model + # has a specific column. + # + # class CreatePhones < ActiveRecord::Migration + # def change + # create_table :phones do |t| + # t.string :supported_ios_version + # end + # end + # end + # + # # RSpec + # describe Phone do + # it { should have_db_column(:supported_ios_version) } + # end + # + # # Test::Unit + # class PhoneTest < ActiveSupport::TestCase + # should have_db_column(:supported_ios_version) + # end + # + # #### Qualifiers + # + # ##### of_type + # + # Use `of_type` to assert that a column is defined as a certain type. + # + # class CreatePhones < ActiveRecord::Migration + # def change + # create_table :phones do |t| + # t.decimal :camera_aperture + # end + # end + # end + # + # # RSpec + # describe Phone do + # it do + # should have_db_column(:camera_aperture).of_type(:decimal) + # end + # end + # + # # Test::Unit + # class PhoneTest < ActiveSupport::TestCase + # should have_db_column(:camera_aperture).of_type(:decimal) + # end + # + # ##### with_options + # + # Use `with_options` to assert that a column has been defined with + # certain options (`:precision`, `:limit`, `:default`, `:null`, `:scale`, + # or `:primary`). # - # Options: - # * of_type - db column type (:integer, :string, etc.) - # * with_options - same options available in migrations - # (:default, :null, :limit, :precision, :scale) - # - # Examples: - # it { should_not have_db_column(:admin).of_type(:boolean) } - # it { should have_db_column(:salary). - # of_type(:decimal). - # with_options(:precision => 10, :scale => 2) } + # class CreatePhones < ActiveRecord::Migration + # def change + # create_table :phones do |t| + # t.decimal :camera_aperture, precision: 1, null: false + # end + # end + # end + # + # # RSpec + # describe Phone do + # it do + # should have_db_column(:camera_aperture). + # with_options(precision: 1, null: false) + # end + # end + # + # # Test::Unit + # class PhoneTest < ActiveSupport::TestCase + # should have_db_column(:camera_aperture). + # with_options(precision: 1, null: false) + # end + # + # @return [HaveDbColumnMatcher] # def have_db_column(column) - HaveDbColumnMatcher.new(:have_db_column, column) + HaveDbColumnMatcher.new(column) end - class HaveDbColumnMatcher # :nodoc: - def initialize(macro, column) - @macro = macro + # @private + class HaveDbColumnMatcher + def initialize(column) @column = column + @options = {} end def of_type(column_type) - @column_type = column_type + @options[:column_type] = column_type self end def with_options(opts = {}) - @precision = opts[:precision] - @limit = opts[:limit] - @default = opts[:default] - @null = opts[:null] - @scale = opts[:scale] + %w(precision limit default null scale primary).each do |attribute| + if opts.key?(attribute.to_sym) + @options[attribute.to_sym] = opts[attribute.to_sym] + end + end self end @@ -47,26 +111,29 @@ correct_limit? && correct_default? && correct_null? && - correct_scale? + correct_scale? && + correct_primary? end def failure_message "Expected #{expectation} (#{@missing})" end + alias failure_message_for_should failure_message - def negative_failure_message + def failure_message_when_negated "Did not expect #{expectation}" end + alias failure_message_for_should_not failure_message_when_negated def description desc = "have db column named #{@column}" - desc << " of type #{@column_type}" unless @column_type.nil? - desc << " of precision #{@precision}" unless @precision.nil? - desc << " of limit #{@limit}" unless @limit.nil? - desc << " of default #{@default}" unless @default.nil? - desc << " of null #{@null}" unless @null.nil? - desc << " of primary #{@primary}" unless @primary.nil? - desc << " of scale #{@scale}" unless @scale.nil? + desc << " of type #{@options[:column_type]}" if @options.key?(:column_type) + desc << " of precision #{@options[:precision]}" if @options.key?(:precision) + desc << " of limit #{@options[:limit]}" if @options.key?(:limit) + desc << " of default #{@options[:default]}" if @options.key?(:default) + desc << " of null #{@options[:null]}" if @options.key?(:null) + desc << " of primary #{@options[:primary]}" if @options.key?(:primary) + desc << " of scale #{@options[:scale]}" if @options.key?(:scale) desc end @@ -82,88 +149,140 @@ end def correct_column_type? - return true if @column_type.nil? - if matched_column.type.to_s == @column_type.to_s + return true unless @options.key?(:column_type) + + if matched_column.type.to_s == @options[:column_type].to_s true else @missing = "#{model_class} has a db column named #{@column} " << - "of type #{matched_column.type}, not #{@column_type}." + "of type #{matched_column.type}, not #{@options[:column_type]}." false end end def correct_precision? - return true if @precision.nil? - if matched_column.precision.to_s == @precision.to_s + return true unless @options.key?(:precision) + + if matched_column.precision.to_s == @options[:precision].to_s true else @missing = "#{model_class} has a db column named #{@column} " << "of precision #{matched_column.precision}, " << - "not #{@precision}." + "not #{@options[:precision]}." false end end def correct_limit? - return true if @limit.nil? - if matched_column.limit.to_s == @limit.to_s + return true unless @options.key?(:limit) + + if matched_column.limit.to_s == @options[:limit].to_s true else @missing = "#{model_class} has a db column named #{@column} " << "of limit #{matched_column.limit}, " << - "not #{@limit}." + "not #{@options[:limit]}." false end end def correct_default? - return true if @default.nil? - if matched_column.default.to_s == @default.to_s + return true unless @options.key?(:default) + + if matched_column.type_cast_default.to_s == @options[:default].to_s true else @missing = "#{model_class} has a db column named #{@column} " << - "of default #{matched_column.default}, " << - "not #{@default}." + "of default #{matched_column.type_cast_default}, " << + "not #{@options[:default]}." false end end def correct_null? - return true if @null.nil? - if matched_column.null.to_s == @null.to_s + return true unless @options.key?(:null) + + if matched_column.null.to_s == @options[:null].to_s true else @missing = "#{model_class} has a db column named #{@column} " << "of null #{matched_column.null}, " << - "not #{@null}." + "not #{@options[:null]}." false end end def correct_scale? - return true if @scale.nil? - if matched_column.scale.to_s == @scale.to_s + return true unless @options.key?(:scale) + + if actual_scale.to_s == @options[:scale].to_s true else - @missing = "#{model_class} has a db column named #{@column} " << - "of scale #{matched_column.scale}, not #{@scale}." + @missing = "#{model_class} has a db column named #{@column} " + @missing << "of scale #{actual_scale}, not #{@options[:scale]}." + false + end + end + + def correct_primary? + return true unless @options.key?(:primary) + + if matched_column.primary? == @options[:primary] + true + else + @missing = "#{model_class} has a db column named #{@column} " + if @options[:primary] + @missing << 'that is not primary, but should be' + else + @missing << 'that is primary, but should not be' + end false end end def matched_column - model_class.columns.detect { |each| each.name == @column.to_s } + @_matched_column ||= begin + column = model_class.columns.detect { |each| each.name == @column.to_s } + DecoratedColumn.new(model_class, column) + end end def model_class @subject.class end + def actual_scale + matched_column.scale + end + + def actual_primary? + model_class.primary_key == matched_column.name + end + def expectation - expected = "#{model_class.name} to #{description}" + "#{model_class.name} to #{description}" end - end + # @private + class DecoratedColumn < SimpleDelegator + def initialize(model, column) + @model = model + super(column) + end + + def type_cast_default + Shoulda::Matchers::RailsShim.type_cast_default_for(model, self) + end + + def primary? + model.primary_key == name + end + + protected + + attr_reader :model + end + end end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_db_index_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_db_index_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_db_index_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,35 +1,83 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActiveRecord # :nodoc: - - # Ensures that there are DB indices on the given columns or tuples of - # columns. + module ActiveRecord + # The `have_db_index` matcher tests that the table that backs your model + # has a index on a specific column. + # + # class CreateBlogs < ActiveRecord::Migration + # def change + # create_table :blogs do |t| + # t.integer :user_id + # end + # + # add_index :blogs, :user_id + # end + # end + # + # # RSpec + # describe Blog do + # it { should have_db_index(:user_id) } + # end + # + # # Test::Unit + # class BlogTest < ActiveSupport::TestCase + # should have_db_index(:user_id) + # end + # + # #### Qualifiers + # + # ##### unique + # + # Use `unique` to assert that the index is unique. + # + # class CreateBlogs < ActiveRecord::Migration + # def change + # create_table :blogs do |t| + # t.string :name + # end + # + # add_index :blogs, :name, unique: true + # end + # end + # + # # RSpec + # describe Blog do + # it { should have_db_index(:name).unique(true) } + # end + # + # # Test::Unit + # class BlogTest < ActiveSupport::TestCase + # should have_db_index(:name).unique(true) + # end + # + # Since it only ever makes since for `unique` to be `true`, you can also + # leave off the argument to save some keystrokes: + # + # # RSpec + # describe Blog do + # it { should have_db_index(:name).unique } + # end + # + # # Test::Unit + # class BlogTest < ActiveSupport::TestCase + # should have_db_index(:name).unique + # end # - # Options: - # * unique - whether or not the index has a unique - # constraint. Use true to explicitly test for a unique - # constraint. Use false to explicitly test for a non-unique - # constraint. Use nil if you don't care whether the index is - # unique or not. Default = nil - # - # Examples: - # - # it { should have_db_index(:age) } - # it { should have_db_index([:commentable_type, :commentable_id]) } - # it { should have_db_index(:ssn).unique(true) } + # @return [HaveDbIndexMatcher] # def have_db_index(columns) - HaveDbIndexMatcher.new(:have_index, columns) + HaveDbIndexMatcher.new(columns) end - class HaveDbIndexMatcher # :nodoc: - def initialize(macro, columns) - @macro = macro + # @private + class HaveDbIndexMatcher + def initialize(columns) @columns = normalize_columns_to_array(columns) + @options = {} end - def unique(unique) - @unique = unique + def unique(unique = true) + @options[:unique] = unique self end @@ -41,13 +89,19 @@ def failure_message "Expected #{expectation} (#{@missing})" end + alias failure_message_for_should failure_message - def negative_failure_message + def failure_message_when_negated "Did not expect #{expectation}" end + alias failure_message_for_should_not failure_message_when_negated def description - "have a #{index_type} index on columns #{@columns.join(' and ')}" + if @options.key?(:unique) + "have a #{index_type} index on columns #{@columns.join(' and ')}" + else + "have an index on columns #{@columns.join(' and ')}" + end end protected @@ -57,14 +111,18 @@ end def correct_unique? - return true if @unique.nil? - if matched_index.unique == @unique - true - else + return true unless @options.key?(:unique) + + is_unique = matched_index.unique + + is_unique = !is_unique unless @options[:unique] + + unless is_unique @missing = "#{table_name} has an index named #{matched_index.name} " << - "of unique #{matched_index.unique}, not #{@unique}." - false + "of unique #{matched_index.unique}, not #{@options[:unique]}." end + + is_unique end def matched_index @@ -84,29 +142,21 @@ end def expectation - expected = "#{model_class.name} to #{description}" + "#{model_class.name} to #{description}" end def index_type - case @unique - when nil - '' - when false - 'non-unique' - else + if @options[:unique] 'unique' + else + 'non-unique' end end def normalize_columns_to_array(columns) - if columns.class == Array - columns.collect { |each| each.to_s } - else - [columns.to_s] - end + Array.wrap(columns).map(&:to_s) end end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,32 +1,49 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the attribute cannot be changed once the record has been - # created. + module ActiveRecord + # The `have_readonly_attribute` matcher tests usage of the + # `attr_readonly` macro. + # + # class User < ActiveRecord::Base + # attr_readonly :password + # end + # + # # RSpec + # describe User do + # it { should have_readonly_attribute(:password) } + # end # - # it { should have_readonly_attributes(:password) } + # # Test::Unit + # class UserTest < ActiveSupport::TestCase + # should have_readonly_attribute(:password) + # end + # + # @return [HaveReadonlyAttributeMatcher] # def have_readonly_attribute(value) HaveReadonlyAttributeMatcher.new(value) end - class HaveReadonlyAttributeMatcher # :nodoc: - + # @private + class HaveReadonlyAttributeMatcher def initialize(attribute) @attribute = attribute.to_s end + attr_reader :failure_message, :failure_message_when_negated + + alias failure_message_for_should failure_message + alias failure_message_for_should_not failure_message_when_negated + def matches?(subject) @subject = subject if readonly_attributes.include?(@attribute) - @negative_failure_message = - "Did not expect #{@attribute} to be read-only" + @failure_message_when_negated = "Did not expect #{@attribute} to be read-only" true else if readonly_attributes.empty? @failure_message = "#{class_name} attribute #{@attribute} " << - "is not read-only" + 'is not read-only' else @failure_message = "#{class_name} is making " << "#{readonly_attributes.to_a.to_sentence} " << @@ -36,8 +53,6 @@ end end - attr_reader :failure_message, :negative_failure_message - def description "make #{@attribute} read-only" end @@ -51,9 +66,7 @@ def class_name @subject.class.name end - end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/helpers.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/helpers.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/helpers.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - module Helpers - def pretty_error_messages(obj) # :nodoc: - obj.errors.map do |a, m| - msg = "#{a} #{m}" - msg << " (#{obj.send(a).inspect})" unless a.to_sym == :base - end - end - - # Helper method that determines the default error message used by Active - # Record. Works for both existing Rails 2.1 and Rails 2.2 with the newly - # introduced I18n module used for localization. - # - # default_error_message(:blank) - # default_error_message(:too_short, :count => 5) - # default_error_message(:too_long, :count => 60) - def default_error_message(key, values = {}) - if Object.const_defined?(:I18n) # Rails >= 2.2 - I18n.translate(:"activerecord.errors.messages.#{key}", {:default => :"errors.messages.#{key}"}.merge(values)) - else # Rails <= 2.1.x - ::ActiveRecord::Errors.default_error_messages[key] % values[:count] - end - end - end - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/serialize_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/serialize_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/serialize_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/serialize_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,205 @@ +module Shoulda + module Matchers + module ActiveRecord + # The `serialize` matcher tests usage of the `serialize` macro. + # + # class Product < ActiveRecord::Base + # serialize :customizations + # end + # + # # RSpec + # describe Product do + # it { should serialize(:customizations) } + # end + # + # # Test::Unit + # class ProductTest < ActiveSupport::TestCase + # should serialize(:customizations) + # end + # + # #### Qualifiers + # + # ##### as + # + # Use `as` if you are using a custom serializer class. + # + # class ProductSpecsSerializer + # def load(string) + # # ... + # end + # + # def dump(options) + # # ... + # end + # end + # + # class Product < ActiveRecord::Base + # serialize :specifications, ProductSpecsSerializer + # end + # + # # RSpec + # describe Product do + # it do + # should serialize(:specifications). + # as(ProductSpecsSerializer) + # end + # end + # + # # Test::Unit + # class ProductTest < ActiveSupport::TestCase + # should serialize(:specifications). + # as(ProductSpecsSerializer) + # end + # + # ##### as_instance_of + # + # Use `as_instance_of` if you are using a custom serializer object. + # + # class ProductOptionsSerializer + # def load(string) + # # ... + # end + # + # def dump(options) + # # ... + # end + # end + # + # class Product < ActiveRecord::Base + # serialize :options, ProductOptionsSerializer.new + # end + # + # # RSpec + # describe Product do + # it do + # should serialize(:options). + # as_instance_of(ProductOptionsSerializer) + # end + # end + # + # # Test::Unit + # class ProductTest < ActiveSupport::TestCase + # should serialize(:options). + # as_instance_of(ProductOptionsSerializer) + # end + # + # @return [SerializeMatcher] + # + def serialize(name) + SerializeMatcher.new(name) + end + + # @private + class SerializeMatcher + def initialize(name) + @name = name.to_s + @options = {} + end + + def as(type) + @options[:type] = type + self + end + + def as_instance_of(type) + @options[:instance_type] = type + self + end + + def matches?(subject) + @subject = subject + serialization_valid? && type_valid? + end + + def failure_message + "Expected #{expectation} (#{@missing})" + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Did not expect #{expectation}" + end + alias failure_message_for_should_not failure_message_when_negated + + def description + description = "serialize :#{@name}" + description += " class_name => #{@options[:type]}" if @options.key?(:type) + description + end + + protected + + def serialization_valid? + if attribute_is_serialized? + true + else + @missing = "no serialized attribute called :#{@name}" + false + end + end + + def class_valid? + if @options[:type] + klass = serialization_coder + if klass == @options[:type] + true + else + if klass.respond_to?(:object_class) && klass.object_class == @options[:type] + true + else + @missing = ":#{@name} should be a type of #{@options[:type]}" + false + end + end + else + true + end + end + + def model_class + @subject.class + end + + def instance_class_valid? + if @options.key?(:instance_type) + if serialization_coder.is_a?(@options[:instance_type]) + true + else + @missing = ":#{@name} should be an instance of #{@options[:type]}" + false + end + else + true + end + end + + def type_valid? + class_valid? && instance_class_valid? + end + + def expectation + expectation = "#{model_class.name} to serialize the attribute called :#{@name}" + expectation += " with a type of #{@options[:type]}" if @options[:type] + expectation += " with an instance of #{@options[:instance_type]}" if @options[:instance_type] + expectation + end + + def attribute_is_serialized? + serialized_attributes.include?(@name) + end + + def serialization_coder + serialized_attributes[@name] + end + + def serialized_attributes + Shoulda::Matchers::RailsShim.serialized_attributes_for(model) + end + + def model + @subject.class + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/model.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/model.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/model.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/model.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,46 @@ +module Shoulda + module Matchers + module ActiveRecord + # @private + module Uniqueness + # @private + class Model + def self.next_unique_copy_of(model_name, namespace) + model = new(model_name, namespace) + + while model.already_exists? + model = model.next + end + + model + end + + def initialize(name, namespace) + @name = name + @namespace = namespace + end + + def already_exists? + namespace.has?(name) + end + + def next + Model.new(name.next, namespace) + end + + def symlink_to(parent) + namespace.set(name, parent.dup) + end + + def to_s + [namespace, name].join('::') + end + + protected + + attr_reader :name, :namespace + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/namespace.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/namespace.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/namespace.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/namespace.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,37 @@ +module Shoulda + module Matchers + module ActiveRecord + # @private + module Uniqueness + # @private + class Namespace + def initialize(constant) + @constant = constant + end + + def has?(name) + constant.const_defined?(name) + end + + def set(name, value) + constant.const_set(name, value) + end + + def clear + constant.constants.each do |child_constant| + constant.__send__(:remove_const, child_constant) + end + end + + def to_s + constant.to_s + end + + protected + + attr_reader :constant + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,51 @@ +require 'thread' + +module Shoulda + module Matchers + module ActiveRecord + # @private + module Uniqueness + # @private + class TestModelCreator + def self.create(model_name, namespace) + Mutex.new.synchronize do + new(model_name, namespace).create + end + end + + def initialize(model_name, namespace) + @model_name = model_name + @namespace = namespace + end + + def create + new_model.tap do |new_model| + new_model.symlink_to(existing_model) + end + end + + protected + + attr_reader :model_name, :namespace + + private + + def model_name_without_namespace + model_name.demodulize + end + + def new_model + @_new_model ||= Model.next_unique_copy_of( + model_name_without_namespace, + namespace + ) + end + + def existing_model + @_existing_model ||= model_name.constantize + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/test_models.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/test_models.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness/test_models.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness/test_models.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,25 @@ +require 'thread' + +module Shoulda + module Matchers + module ActiveRecord + # @private + module Uniqueness + # @private + module TestModels + def self.create(model_name) + TestModelCreator.create(model_name, root_namespace) + end + + def self.remove_all + root_namespace.clear + end + + def self.root_namespace + @_root_namespace ||= Namespace.new(self) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/uniqueness.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/uniqueness.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,14 @@ +module Shoulda + module Matchers + module ActiveModel + # @private + module Uniqueness + end + end + end +end + +require 'shoulda/matchers/active_record/uniqueness/model' +require 'shoulda/matchers/active_record/uniqueness/namespace' +require 'shoulda/matchers/active_record/uniqueness/test_model_creator' +require 'shoulda/matchers/active_record/uniqueness/test_models' diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_acceptance_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the model cannot be saved the given attribute is not - # accepted. - # - # Options: - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :accepted. - # - # Example: - # it { should validate_acceptance_of(:eula) } - # - def validate_acceptance_of(attr) - ValidateAcceptanceOfMatcher.new(attr) - end - - class ValidateAcceptanceOfMatcher < ValidationMatcher # :nodoc: - - def with_message(message) - @expected_message = message if message - self - end - - def matches?(subject) - super(subject) - @expected_message ||= :accepted - disallows_value_of(false, @expected_message) - end - - def description - "require #{@attribute} to be accepted" - end - - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_format_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the model is not valid if the given attribute is not - # formatted correctly. - # - # Options: - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or String. - # Defaults to the translation for :invalid. - # * with(string to test against) - # * not_with(string to test against) - # - # Examples: - # it { should validate_format_of(:name). - # with('12345'). - # with_message(/is not optional/) } - # it { should validate_format_of(:name). - # not_with('12D45'). - # with_message(/is not optional/) } - # - def validate_format_of(attr) - ValidateFormatOfMatcher.new(attr) - end - - class ValidateFormatOfMatcher < ValidationMatcher # :nodoc: - - def initialize(attribute) - super - end - - def with_message(message) - @expected_message = message if message - self - end - - def with(value) - raise "You may not call both with and not_with" if @value_to_fail - @value_to_pass = value - self - end - - def not_with(value) - raise "You may not call both with and not_with" if @value_to_pass - @value_to_fail = value - self - end - - def matches?(subject) - super(subject) - @expected_message ||= :invalid - return disallows_value_of(@value_to_fail, @expected_message) if @value_to_fail - allows_value_of(@value_to_pass, @expected_message) if @value_to_pass - end - - def description - "#{@attribute} have a valid format" - end - - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_numericality_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,39 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensure that the attribute is numeric - # - # Options: - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or string. Defaults to the - # translation for :not_a_number. - # - # Example: - # it { should validate_numericality_of(:age) } - # - def validate_numericality_of(attr) - ValidateNumericalityOfMatcher.new(attr) - end - - class ValidateNumericalityOfMatcher < ValidationMatcher # :nodoc: - - def with_message(message) - @expected_message = message if message - self - end - - def matches?(subject) - super(subject) - @expected_message ||= :not_a_number - disallows_value_of('abcd', @expected_message) - end - - def description - "only allow numeric values for #{@attribute}" - end - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_presence_of_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the model is not valid if the given attribute is not - # present. - # - # Options: - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or String. - # Defaults to the translation for :blank. - # - # Examples: - # it { should validate_presence_of(:name) } - # it { should validate_presence_of(:name). - # with_message(/is not optional/) } - # - def validate_presence_of(attr) - ValidatePresenceOfMatcher.new(attr) - end - - class ValidatePresenceOfMatcher < ValidationMatcher # :nodoc: - - def with_message(message) - @expected_message = message if message - self - end - - def matches?(subject) - super(subject) - @expected_message ||= :blank - disallows_value_of(blank_value, @expected_message) - end - - def description - "require #{@attribute} to be set" - end - - private - - def blank_value - if collection? - [] - else - nil - end - end - - def collection? - if @subject.class.respond_to?(:reflect_on_association) && - reflection = @subject.class.reflect_on_association(@attribute) - [:has_many, :has_and_belongs_to_many].include?(reflection.macro) - else - false - end - end - end - - end - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,48 +1,211 @@ -module Shoulda # :nodoc: +module Shoulda module Matchers - module ActiveRecord # :nodoc: - - # Ensures that the model is invalid if the given attribute is not unique. + module ActiveRecord + # The `validate_uniqueness_of` matcher tests usage of the + # `validates_uniqueness_of` validation. It first checks for an existing + # instance of your model in the database, creating one if necessary. It + # then takes a new instance of that model and asserts that it fails + # validation if the attribute or attributes you've specified in the + # validation are set to values which are the same as those of the + # pre-existing record (thereby failing the uniqueness check). + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :permalink + # end + # + # # RSpec + # describe Post do + # it { should validate_uniqueness_of(:permalink) } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:permalink) + # end + # + # #### Caveat + # + # This matcher works a bit differently than other matchers. As noted + # before, it will create an instance of your model if one doesn't already + # exist. Sometimes this step fails, especially if you have database-level + # restrictions on any attributes other than the one which is unique. In + # this case, the solution is to populate these attributes with values + # before you call `validate_uniqueness_of`. + # + # For example, say you have the following migration and model: + # + # class CreatePosts < ActiveRecord::Migration + # def change + # create_table :posts do |t| + # t.string :title + # t.text :content, null: false + # end + # end + # end + # + # class Post < ActiveRecord::Base + # validates :title, uniqueness: true + # end + # + # You may be tempted to test the model like this: + # + # describe Post do + # it { should validate_uniqueness_of(:title) } + # end + # + # However, running this test will fail with something like: + # + # Failures: + # + # 1) Post should require case sensitive unique value for title + # Failure/Error: it { should validate_uniqueness_of(:title) } + # ActiveRecord::StatementInvalid: + # SQLite3::ConstraintException: posts.content may not be NULL: INSERT INTO "posts" ("title") VALUES (?) + # + # This happens because `validate_uniqueness_of` tries to create a new post + # but cannot do so because of the `content` attribute: though unrelated to + # this test, it nevertheless needs to be filled in. The solution is to + # build a custom Post object ahead of time with `content` filled in: + # + # describe Post do + # describe "validations" do + # subject { Post.new(content: 'Here is the content') } + # it { should validate_uniqueness_of(:title) } + # end + # end + # + # Or, if you're using + # [FactoryGirl](http://github.com/thoughtbot/factory_girl) and you have a + # `post` factory defined which automatically fills in `content`, you can + # say: + # + # describe Post do + # describe "validations" do + # subject { FactoryGirl.build(:post) } + # it { should validate_uniqueness_of(:title) } + # end + # end + # + # #### Qualifiers + # + # ##### with_message + # + # Use `with_message` if you are using a custom validation message. + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :title, message: 'Please choose another title' + # end + # + # # RSpec + # describe Post do + # it do + # should validate_uniqueness_of(:title). + # with_message('Please choose another title') + # end + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:title). + # with_message('Please choose another title') + # end + # + # ##### scoped_to + # + # Use `scoped_to` to test usage of the `:scope` option. This asserts that + # a new record fails validation if not only the primary attribute is not + # unique, but the scoped attributes are not unique either. + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :slug, scope: :user_id + # end # - # Internally, this uses values from existing records to test validations, - # so this will always fail if you have not saved at least one record for - # the model being tested, like so: - # - # describe User do - # before(:each) { User.create!(:email => 'address@example.com') } - # it { should validate_uniqueness_of(:email) } - # end - # - # Options: - # - # * with_message - value the test expects to find in - # errors.on(:attribute). Regexp or String. - # Defaults to the translation for :taken. - # * scoped_to - field(s) to scope the uniqueness to. - # * case_insensitive - ensures that the validation does not - # check case. Off by default. Ignored by non-text attributes. - # - # Examples: - # it { should validate_uniqueness_of(:keyword) } - # it { should validate_uniqueness_of(:keyword).with_message(/dup/) } - # it { should validate_uniqueness_of(:email).scoped_to(:name) } - # it { should validate_uniqueness_of(:email). - # scoped_to(:first_name, :last_name) } - # it { should validate_uniqueness_of(:keyword).case_insensitive } + # # RSpec + # describe Post do + # it { should validate_uniqueness_of(:slug).scoped_to(:journal_id) } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:slug).scoped_to(:journal_id) + # end + # + # ##### case_insensitive + # + # Use `case_insensitive` to test usage of the `:case_sensitive` option + # with a false value. This asserts that the uniquable attributes fail + # validation even if their values are a different case than corresponding + # attributes in the pre-existing record. + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :key, case_sensitive: false + # end + # + # # RSpec + # describe Post do + # it { should validate_uniqueness_of(:key).case_insensitive } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:key).case_insensitive + # end + # + # ##### allow_nil + # + # Use `allow_nil` to assert that the attribute allows nil. + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :author_id, allow_nil: true + # end + # + # # RSpec + # describe Post do + # it { should validate_uniqueness_of(:author_id).allow_nil } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:author_id).allow_nil + # end + # + # @return [ValidateUniquenessOfMatcher] + # + # ##### allow_blank + # + # Use `allow_blank` to assert that the attribute allows a blank value. + # + # class Post < ActiveRecord::Base + # validates_uniqueness_of :author_id, allow_blank: true + # end + # + # # RSpec + # describe Post do + # it { should validate_uniqueness_of(:author_id).allow_blank } + # end + # + # # Test::Unit + # class PostTest < ActiveSupport::TestCase + # should validate_uniqueness_of(:author_id).allow_blank + # end + # + # @return [ValidateUniquenessOfMatcher] # def validate_uniqueness_of(attr) ValidateUniquenessOfMatcher.new(attr) end - class ValidateUniquenessOfMatcher < ValidationMatcher # :nodoc: - include Helpers + # @private + class ValidateUniquenessOfMatcher < ActiveModel::ValidationMatcher + include ActiveModel::Helpers def initialize(attribute) - @attribute = attribute + super(attribute) + @options = {} end def scoped_to(*scopes) - @scopes = [*scopes].flatten + @options[:scopes] = [*scopes].flatten self end @@ -52,76 +215,173 @@ end def case_insensitive - @case_insensitive = true + @options[:case_insensitive] = true + self + end + + def allow_nil + @options[:allow_nil] = true + self + end + + def allow_blank + @options[:allow_blank] = true self end def description result = "require " - result << "case sensitive " unless @case_insensitive + result << "case sensitive " unless @options[:case_insensitive] result << "unique value for #{@attribute}" - result << " scoped to #{@scopes.join(', ')}" unless @scopes.blank? + result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present? result end def matches?(subject) + @original_subject = subject @subject = subject.class.new @expected_message ||= :taken - find_existing && - set_scoped_attributes && - validate_attribute && - validate_after_scope_change + + set_scoped_attributes && + validate_everything_except_duplicate_nils_or_blanks? && + validate_after_scope_change? && + allows_nil? && + allows_blank? + ensure + Uniqueness::TestModels.remove_all end private - def find_existing - if @existing = @subject.class.find(:first) + def allows_nil? + if @options[:allow_nil] + ensure_nil_record_in_database + allows_value_of(nil, @expected_message) + else true + end + end + + def allows_blank? + if @options[:allow_blank] + ensure_blank_record_in_database + allows_value_of('', @expected_message) else - @failure_message = "Can't find first #{class_name}" - false + true + end + end + + def existing_record + @existing_record ||= first_instance + end + + def first_instance + @subject.class.first || create_record_in_database + end + + def ensure_nil_record_in_database + unless existing_record_is_nil? + create_record_in_database(nil_value: true) end end + def ensure_blank_record_in_database + unless existing_record_is_blank? + create_record_in_database(blank_value: true) + end + end + + def existing_record_is_nil? + @existing_record.present? && existing_value.nil? + end + + def existing_record_is_blank? + @existing_record.present? && existing_value.strip == '' + end + + def create_record_in_database(options = {}) + @original_subject.tap do |instance| + instance.__send__("#{@attribute}=", value_for_new_record(options)) + ensure_secure_password_set(instance) + instance.save(validate: false) + @created_record = instance + end + end + + def ensure_secure_password_set(instance) + if has_secure_password? + instance.password = "password" + instance.password_confirmation = "password" + end + end + + def value_for_new_record(options = {}) + case + when options[:nil_value] then nil + when options[:blank_value] then '' + else 'a' + end + end + + def has_secure_password? + @subject.class.ancestors.map(&:to_s).include?('ActiveModel::SecurePassword::InstanceMethodsOnActivation') + end + def set_scoped_attributes - unless @scopes.blank? - @scopes.each do |scope| + if @options[:scopes].present? + @options[:scopes].all? do |scope| setter = :"#{scope}=" - unless @subject.respond_to?(setter) - @failure_message = - "#{class_name} doesn't seem to have a #{scope} attribute." - return false + if @subject.respond_to?(setter) + @subject.__send__(setter, existing_record.__send__(scope)) + true + else + @failure_message = "#{class_name} doesn't seem to have a #{scope} attribute." + false end - @subject.send("#{scope}=", @existing.send(scope)) end + else + true end - true end - def validate_attribute + def validate_everything_except_duplicate_nils_or_blanks? + if (@options[:allow_nil] && existing_value.nil?) || + (@options[:allow_blank] && existing_value.blank?) + create_record_with_value + end + disallows_value_of(existing_value, @expected_message) end - # TODO: There is a chance that we could change the scoped field - # to a value that's already taken. An alternative implementation - # could actually find all values for scope and create a unique - def validate_after_scope_change - if @scopes.blank? + def create_record_with_value + @existing_record = create_record_in_database + end + + def model_class?(model_name) + model_name.constantize.ancestors.include?(::ActiveRecord::Base) + rescue NameError + false + end + + def validate_after_scope_change? + if @options[:scopes].blank? true else - @scopes.all? do |scope| - previous_value = @existing.send(scope) + all_records = @subject.class.all + @options[:scopes].all? do |scope| + previous_value = all_records.map(&scope).max # Assume the scope is a foreign key if the field is nil - previous_value ||= 0 + previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s]) - next_value = previous_value.next + next_value = next_value_for(scope, previous_value) - @subject.send("#{scope}=", next_value) + @subject.__send__("#{scope}=", next_value) if allows_value_of(existing_value, @expected_message) - @negative_failure_message << + @subject.__send__("#{scope}=", previous_value) + + @failure_message_when_negated << " (with different value of #{scope})" true else @@ -132,17 +392,51 @@ end end + def correct_type_for_column(column) + if column.type == :string + '0' + elsif column.type == :datetime + DateTime.now + elsif column.type == :uuid + SecureRandom.uuid + else + 0 + end + end + + def next_value_for(scope, previous_value) + if @subject.class.respond_to?(:defined_enums) && @subject.defined_enums[scope.to_s] + available_values = available_enum_values_for(scope, previous_value) + available_values.keys.last + elsif scope.to_s =~ /_type$/ && model_class?(previous_value) + Uniqueness::TestModels.create(previous_value).to_s + elsif previous_value.respond_to?(:next) + previous_value.next + elsif previous_value.respond_to?(:to_datetime) + previous_value.to_datetime.next + else + previous_value.to_s.next + end + end + + def available_enum_values_for(scope, previous_value) + @subject.defined_enums[scope.to_s].reject do |key, _| + key == previous_value + end + end + def class_name @subject.class.name end def existing_value - value = @existing.send(@attribute) - value.swapcase! if @case_insensitive && value.respond_to?(:swapcase!) + value = existing_record.__send__(@attribute) + if @options[:case_insensitive] && value.respond_to?(:swapcase!) + value.swapcase! + end value end end - end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validation_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validation_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record/validation_matcher.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record/validation_matcher.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -module Shoulda # :nodoc: - module Matchers - module ActiveRecord # :nodoc: - - class ValidationMatcher # :nodoc: - - attr_reader :failure_message - - def initialize(attribute) - @attribute = attribute - end - - def negative_failure_message - @negative_failure_message || @failure_message - end - - def matches?(subject) - @subject = subject - false - end - - private - - def allows_value_of(value, message = nil) - allow = AllowValueMatcher. - new(value). - for(@attribute). - with_message(message) - if allow.matches?(@subject) - @negative_failure_message = allow.failure_message - true - else - @failure_message = allow.negative_failure_message - false - end - end - - def disallows_value_of(value, message = nil) - disallow = AllowValueMatcher. - new(value). - for(@attribute). - with_message(message) - if disallow.matches?(@subject) - @failure_message = disallow.negative_failure_message - false - else - @negative_failure_message = disallow.failure_message - true - end - end - end - - end - end - - end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/active_record.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/active_record.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,41 +1,26 @@ -require 'shoulda/matchers/active_record/helpers' -require 'shoulda/matchers/active_record/validation_matcher' -require 'shoulda/matchers/active_record/allow_value_matcher' -require 'shoulda/matchers/active_record/ensure_length_of_matcher' -require 'shoulda/matchers/active_record/ensure_inclusion_of_matcher' -require 'shoulda/matchers/active_record/validate_presence_of_matcher' -require 'shoulda/matchers/active_record/validate_format_of_matcher' -require 'shoulda/matchers/active_record/validate_uniqueness_of_matcher' -require 'shoulda/matchers/active_record/validate_acceptance_of_matcher' -require 'shoulda/matchers/active_record/validate_numericality_of_matcher' -require 'shoulda/matchers/active_record/association_matcher' -require 'shoulda/matchers/active_record/have_db_column_matcher' -require 'shoulda/matchers/active_record/have_db_index_matcher' -require 'shoulda/matchers/active_record/have_readonly_attribute_matcher' -require 'shoulda/matchers/active_record/allow_mass_assignment_of_matcher' - +require "shoulda/matchers/active_record/association_matcher" +require "shoulda/matchers/active_record/association_matchers" +require "shoulda/matchers/active_record/association_matchers/counter_cache_matcher" +require "shoulda/matchers/active_record/association_matchers/inverse_of_matcher" +require "shoulda/matchers/active_record/association_matchers/join_table_matcher" +require "shoulda/matchers/active_record/association_matchers/order_matcher" +require "shoulda/matchers/active_record/association_matchers/through_matcher" +require "shoulda/matchers/active_record/association_matchers/dependent_matcher" +require "shoulda/matchers/active_record/association_matchers/source_matcher" +require "shoulda/matchers/active_record/association_matchers/model_reflector" +require "shoulda/matchers/active_record/association_matchers/model_reflection" +require "shoulda/matchers/active_record/association_matchers/option_verifier" +require "shoulda/matchers/active_record/have_db_column_matcher" +require "shoulda/matchers/active_record/have_db_index_matcher" +require "shoulda/matchers/active_record/have_readonly_attribute_matcher" +require "shoulda/matchers/active_record/serialize_matcher" +require "shoulda/matchers/active_record/accept_nested_attributes_for_matcher" +require "shoulda/matchers/active_record/define_enum_for_matcher" +require "shoulda/matchers/active_record/uniqueness" +require "shoulda/matchers/active_record/validate_uniqueness_of_matcher" module Shoulda module Matchers - # = Matchers for your active record models - # - # These matchers will test most of the validations and associations for your - # ActiveRecord models. - # - # describe User do - # it { should validate_presence_of(:name) } - # it { should validate_presence_of(:phone_number) } - # %w(abcd 1234).each do |value| - # it { should_not allow_value(value).for(:phone_number) } - # end - # it { should allow_value("(123) 456-7890").for(:phone_number) } - # it { should_not allow_mass_assignment_of(:password) } - # it { should have_one(:profile) } - # it { should have_many(:dogs) } - # it { should have_many(:messes).through(:dogs) } - # it { should belong_to(:lover) } - # end - # module ActiveRecord end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/assertion_error.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/assertion_error.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/assertion_error.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/assertion_error.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,11 +1,27 @@ module Shoulda module Matchers - if RUBY_VERSION > "1.9" - require 'minitest/unit' - AssertionError = MiniTest::Assertion - else - require 'test/unit/assertionfailederror' + if defined?(ActiveSupport::TestCase) + # @private + AssertionError = ActiveSupport::TestCase::Assertion + elsif Gem.ruby_version >= Gem::Version.new('1.8') && Gem.ruby_version < Gem::Version.new('1.9') + require 'test/unit' + # @private + AssertionError = Test::Unit::AssertionFailedError + elsif defined?(Test::Unit::AssertionFailedError) + # Test::Unit has been loaded already, so we use it + # @private AssertionError = Test::Unit::AssertionFailedError + elsif Gem.ruby_version >= Gem::Version.new("1.9") + begin + require 'minitest' + rescue LoadError + require 'minitest/unit' + ensure + # @private + AssertionError = MiniTest::Assertion + end + else + raise 'No unit test library available' end end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double_collection.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_collection.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double_collection.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_collection.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,55 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class DoubleCollection + def initialize(klass) + @klass = klass + @doubles_by_method_name = {} + end + + def register_stub(method_name) + register_double(method_name, :stub) + end + + def register_proxy(method_name) + register_double(method_name, :proxy) + end + + def activate + doubles_by_method_name.each do |method_name, double| + double.activate + end + end + + def deactivate + doubles_by_method_name.each do |method_name, double| + double.deactivate + end + end + + def calls_to(method_name) + double = doubles_by_method_name[method_name] + + if double + double.calls + else + [] + end + end + + protected + + attr_reader :klass, :doubles_by_method_name + + def register_double(method_name, implementation_type) + implementation = + DoubleImplementationRegistry.find(implementation_type) + double = Double.new(klass, method_name, implementation) + doubles_by_method_name[method_name] = double + double + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,28 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + module DoubleImplementationRegistry + class << self + REGISTRY = {} + + def find(type) + find_class!(type).create + end + + def register(klass, type) + REGISTRY[type] = klass + end + + private + + def find_class!(type) + REGISTRY.fetch(type) do + raise ArgumentError, "No double implementation class found for '#{type}'" + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/double.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/double.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,76 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class Double + attr_reader :calls + + def initialize(klass, method_name, implementation) + @klass = klass + @method_name = method_name + @implementation = implementation + @activated = false + @calls = [] + end + + def to_return(value = nil, &block) + if block + implementation.returns(&block) + else + implementation.returns(value) + end + end + + def activate + unless @activated + store_original_method + replace_method_with_double + @activated = true + end + end + + def deactivate + if @activated + restore_original_method + @activated = false + end + end + + def record_call(args, block) + calls << MethodCall.new(args, block) + end + + def call_original_method(object, args, block) + if original_method + original_method.bind(object).call(*args, &block) + end + end + + protected + + attr_reader :klass, :method_name, :implementation, :original_method + + def store_original_method + @original_method = klass.instance_method(method_name) + end + + def replace_method_with_double + implementation = @implementation + double = self + + klass.__send__(:define_method, method_name) do |*args, &block| + implementation.call(double, self, args, block) + end + end + + def restore_original_method + original_method = @original_method + klass.__send__(:remove_method, method_name) + klass.__send__(:define_method, method_name) do |*args, &block| + original_method.bind(self).call(*args, &block) + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/object_double.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/object_double.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/object_double.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/object_double.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,33 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class ObjectDouble < BasicObject + attr_reader :calls + + def initialize + @calls = [] + @calls_by_method_name = {} + end + + def calls_to(method_name) + @calls_by_method_name[method_name] || [] + end + + def respond_to?(name, include_private = nil) + true + end + + def method_missing(method_name, *args, &block) + calls << MethodCallWithName.new(method_name, args, block) + (calls_by_method_name[method_name] ||= []) << MethodCall.new(args, block) + nil + end + + protected + + attr_reader :calls_by_method_name + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/proxy_implementation.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/proxy_implementation.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/proxy_implementation.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,31 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class ProxyImplementation + extend Forwardable + + DoubleImplementationRegistry.register(self, :proxy) + + def_delegators :stub_implementation, :returns + + def self.create + new(StubImplementation.new) + end + + def initialize(stub_implementation) + @stub_implementation = stub_implementation + end + + def call(double, object, args, block) + stub_implementation.call(double, object, args, block) + double.call_original_method(object, args, block) + end + + protected + + attr_reader :stub_implementation + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/structs.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/structs.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/structs.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/structs.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,10 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + MethodCall = Struct.new(:args, :block) + # @private + MethodCallWithName = Struct.new(:method_name, :args, :block) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/stub_implementation.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/stub_implementation.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/stub_implementation.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,35 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class StubImplementation + DoubleImplementationRegistry.register(self, :stub) + + def self.create + new + end + + def initialize + @implementation = proc { nil } + end + + def returns(value = nil, &block) + if block + @implementation = block + else + @implementation = proc { value } + end + end + + def call(double, object, args, block) + double.record_call(args, block) + implementation.call(object, args, block) + end + + protected + + attr_reader :implementation + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/world.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/world.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak/world.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak/world.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,37 @@ +module Shoulda + module Matchers + module Doublespeak + # @private + class World + def double_collection_for(klass) + double_collections_by_class[klass] ||= DoubleCollection.new(klass) + end + + def with_doubles_activated + activate + yield + ensure + deactivate + end + + private + + def activate + double_collections_by_class.each do |klass, double_collection| + double_collection.activate + end + end + + def deactivate + double_collections_by_class.each do |klass, double_collection| + double_collection.deactivate + end + end + + def double_collections_by_class + @_double_collections_by_class ||= {} + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/doublespeak.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/doublespeak.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,28 @@ +require 'forwardable' + +module Shoulda + module Matchers + # @private + module Doublespeak + class << self + extend Forwardable + + def_delegators :world, :double_collection_for, + :with_doubles_activated + + def world + @_world ||= World.new + end + end + end + end +end + +require 'shoulda/matchers/doublespeak/double' +require 'shoulda/matchers/doublespeak/double_collection' +require 'shoulda/matchers/doublespeak/double_implementation_registry' +require 'shoulda/matchers/doublespeak/object_double' +require 'shoulda/matchers/doublespeak/proxy_implementation' +require 'shoulda/matchers/doublespeak/structs' +require 'shoulda/matchers/doublespeak/stub_implementation' +require 'shoulda/matchers/doublespeak/world' diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/error.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/error.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/error.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/error.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,25 @@ +module Shoulda + module Matchers + # @private + class Error < StandardError + def self.create(attributes) + allocate.tap do |error| + attributes.each do |name, value| + error.__send__("#{name}=", value) + end + + error.__send__(:initialize) + end + end + + def initialize(*args) + super + @message = message + end + + def message + "" + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,37 @@ +module Shoulda + module Matchers + module Independent + class DelegateMethodMatcher + # @private + class StubbedTarget + def initialize(method) + @received_method = false + @received_arguments = [] + stub_method(method) + end + + def has_received_method? + received_method + end + + def has_received_arguments?(*args) + args == received_arguments + end + + protected + + def stub_method(method) + class_eval do + define_method method do |*args| + @received_method = true + @received_arguments = args + end + end + end + + attr_reader :received_method, :received_arguments + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,15 @@ +module Shoulda + module Matchers + module Independent + class DelegateMethodMatcher + # @private + class DelegateObjectNotSpecified < StandardError + def message + 'Delegation needs a target. Use the #to method to define one, e.g. + `post_office.should delegate(:deliver_mail).to(:mailman)`'.squish + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent/delegate_method_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent/delegate_method_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,382 @@ +module Shoulda + module Matchers + module Independent + # The `delegate_method` matcher tests that an object forwards messages + # to other, internal objects by way of delegation. + # + # In this example, we test that Courier forwards a call to #deliver onto + # its PostOffice instance: + # + # require 'forwardable' + # + # class Courier + # extend Forwardable + # + # attr_reader :post_office + # + # def_delegators :post_office, :deliver + # + # def initialize + # @post_office = PostOffice.new + # end + # end + # + # # RSpec + # describe Courier do + # it { should delegate_method(:deliver).to(:post_office) } + # end + # + # # Test::Unit + # class CourierTest < Test::Unit::TestCase + # should delegate_method(:deliver).to(:post_office) + # end + # + # You can also use `delegate_method` with Rails's `delegate` macro: + # + # class Courier + # attr_reader :post_office + # delegate :deliver, to: :post_office + # + # def initialize + # @post_office = PostOffice.new + # end + # end + # + # describe Courier do + # it { should delegate_method(:deliver).to(:post_office) } + # end + # + # To employ some terminology, we would say that Courier's #deliver method + # is the *delegating method*, PostOffice is the *delegate object*, and + # PostOffice#deliver is the *delegate method*. + # + # #### Qualifiers + # + # ##### as + # + # Use `as` if the name of the delegate method is different from the name + # of the delegating method. + # + # Here, Courier has a #deliver method, but instead of calling #deliver on + # the PostOffice, it calls #ship: + # + # class Courier + # attr_reader :post_office + # + # def initialize + # @post_office = PostOffice.new + # end + # + # def deliver(package) + # post_office.ship(package) + # end + # end + # + # # RSpec + # describe Courier do + # it { should delegate_method(:deliver).to(:post_office).as(:ship) } + # end + # + # # Test::Unit + # class CourierTest < Test::Unit::TestCase + # should delegate_method(:deliver).to(:post_office).as(:ship) + # end + # + # ##### with_prefix + # + # Use `with_prefix` when using Rails's `delegate` helper along with the + # `:prefix` option. + # + # class Page < ActiveRecord::Base + # belongs_to :site + # delegate :name, to: :site, prefix: true + # delegate :title, to: :site, prefix: :root + # end + # + # # RSpec + # describe Page do + # it { should delegate_method(:name).to(:site).with_prefix } + # it { should delegate_method(:name).to(:site).with_prefix(true) } + # it { should delegate_method(:title).to(:site).with_prefix(:root) } + # end + # + # # Test::Unit + # class PageTest < Test::Unit::TestCase + # should delegate_method(:name).to(:site).with_prefix + # should delegate_method(:name).to(:site).with_prefix(true) + # should delegate_method(:title).to(:site).with_prefix(:root) + # end + # + # ##### with_arguments + # + # Use `with_arguments` to assert that the delegate method is called with + # certain arguments. Note that this qualifier can only be used when the + # delegating method takes no arguments; it does not support delegating + # or delegate methods that take arbitrary arguments. + # + # Here, when Courier#deliver_package calls PostOffice#deliver_package, it + # adds an options hash: + # + # class Courier + # attr_reader :post_office + # + # def initialize + # @post_office = PostOffice.new + # end + # + # def deliver_package + # post_office.deliver_package(expedited: true) + # end + # end + # + # # RSpec + # describe Courier do + # it do + # should delegate_method(:deliver_package). + # to(:post_office). + # with_arguments(expedited: true) + # end + # end + # + # # Test::Unit + # class CourierTest < Test::Unit::TestCase + # should delegate_method(:deliver_package). + # to(:post_office). + # with_arguments(expedited: true) + # end + # + # @return [DelegateMethodMatcher] + # + def delegate_method(delegating_method) + DelegateMethodMatcher.new(delegating_method).in_context(self) + end + + # @private + class DelegateMethodMatcher + def initialize(delegating_method) + @delegating_method = delegating_method + + @delegate_method = @delegating_method + @delegate_object = Doublespeak::ObjectDouble.new + + @delegated_arguments = [] + @delegate_object_reader_method = nil + @subject = nil + @subject_double_collection = nil + end + + def in_context(context) + @context = MatcherContext.new(context) + self + end + + def matches?(subject) + @subject = subject + + ensure_delegate_object_has_been_specified! + + subject_has_delegating_method? && + subject_has_delegate_object_reader_method? && + subject_delegates_to_delegate_object_correctly? + end + + def description + string = "delegate #{formatted_delegating_method_name} to " + + "#{formatted_delegate_object_reader_method_name} object" + + if delegated_arguments.any? + string << " passing arguments #{delegated_arguments.inspect}" + end + + if delegate_method != delegating_method + string << " as #{formatted_delegate_method}" + end + + string + end + + def to(delegate_object_reader_method) + @delegate_object_reader_method = delegate_object_reader_method + self + end + + def as(delegate_method) + @delegate_method = delegate_method + self + end + + def with_arguments(*arguments) + @delegated_arguments = arguments + self + end + + def with_prefix(prefix = nil) + @delegating_method = + :"#{build_delegating_method_prefix(prefix)}_#{delegate_method}" + delegate_method + self + end + + def build_delegating_method_prefix(prefix) + case prefix + when true, nil then delegate_object_reader_method + else prefix + end + end + + def failure_message + "Expected #{class_under_test} to #{description}\n" + + "Method calls sent to " + + "#{formatted_delegate_object_reader_method_name(include_module: true)}:" + + formatted_calls_on_delegate_object + end + alias failure_message_for_should failure_message + + def failure_message_when_negated + "Expected #{class_under_test} not to #{description}, but it did" + end + alias failure_message_for_should_not failure_message_when_negated + + protected + + attr_reader \ + :context, + :delegated_arguments, + :delegating_method, + :method, + :delegate_method, + :subject_double_collection, + :delegate_object, + :delegate_object_reader_method + + def subject + @subject + end + + def subject_is_a_class? + if @subject + @subject.is_a?(Class) + else + context.subject_is_a_class? + end + end + + def class_under_test + if subject_is_a_class? + subject + else + subject.class + end + end + + def formatted_delegate_method(options = {}) + formatted_method_name_for(delegate_method, options) + end + + def formatted_delegating_method_name(options = {}) + formatted_method_name_for(delegating_method, options) + end + + def formatted_delegate_object_reader_method_name(options = {}) + formatted_method_name_for(delegate_object_reader_method, options) + end + + def formatted_method_name_for(method_name, options) + possible_class_under_test(options) + + class_or_instance_method_indicator + + method_name.to_s + end + + def possible_class_under_test(options) + if options[:include_module] + class_under_test.to_s + else + "" + end + end + + def class_or_instance_method_indicator + if subject_is_a_class? + '.' + else + '#' + end + end + + def delegate_object_received_call? + calls_to_delegate_method.any? + end + + def delegate_object_received_call_with_delegated_arguments? + calls_to_delegate_method.any? do |call| + call.args == delegated_arguments + end + end + + def subject_has_delegating_method? + subject.respond_to?(delegating_method) + end + + def subject_has_delegate_object_reader_method? + subject.respond_to?(delegate_object_reader_method, true) + end + + def ensure_delegate_object_has_been_specified! + if delegate_object_reader_method.to_s.empty? + raise DelegateObjectNotSpecified + end + end + + def subject_delegates_to_delegate_object_correctly? + register_subject_double_collection + + Doublespeak.with_doubles_activated do + subject.public_send(delegating_method, *delegated_arguments) + end + + if delegated_arguments.any? + delegate_object_received_call_with_delegated_arguments? + else + delegate_object_received_call? + end + end + + def register_subject_double_collection + double_collection = + Doublespeak.double_collection_for(subject.singleton_class) + double_collection.register_stub(delegate_object_reader_method). + to_return(delegate_object) + + @subject_double_collection = double_collection + end + + def calls_to_delegate_method + delegate_object.calls_to(delegate_method) + end + + def calls_on_delegate_object + delegate_object.calls + end + + def formatted_calls_on_delegate_object + string = "" + + if calls_on_delegate_object.any? + string << "\n" + calls_on_delegate_object.each_with_index do |call, i| + name = call.method_name + args = call.args.map { |arg| arg.inspect }.join(', ') + string << "#{i+1}) #{name}(#{args})\n" + end + else + string << " (none)" + end + + string.rstrip! + + string + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/independent.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/independent.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,11 @@ +require 'shoulda/matchers/independent/delegate_method_matcher' +require 'shoulda/matchers/independent/delegate_method_matcher/stubbed_target' +require 'shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error' + +module Shoulda + module Matchers + # Matchers for non-Rails-dependent code. + module Independent + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,39 @@ +module Shoulda + module Matchers + # @private + module Integrations + # @private + module NUnitTestCaseDetection + def self.possible_test_case_constants + [ + -> { ActiveSupport::TestCase }, + -> { Minitest::Test }, + -> { MiniTest::Unit::TestCase }, + -> { Test::Unit::TestCase } + ] + end + + def self.resolve_constant(future_constant) + future_constant.call + rescue NameError + nil + end + + def self.detected_test_case_constants + possible_test_case_constants. + map { |future_constant| resolve_constant(future_constant) }. + compact + end + + def self.test_case_constants + @_test_case_constants ||= detected_test_case_constants + end + end + end + + # @private + def self.nunit_test_case_constants + Integrations::NUnitTestCaseDetection.test_case_constants + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/rspec.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rspec.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/rspec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/rspec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,31 +1,19 @@ # :enddoc: -if defined?(::ActiveRecord) - require 'shoulda/matchers/active_record' - module RSpec::Matchers - include Shoulda::Matchers::ActiveRecord - end -end +if RSpec.respond_to?(:configure) + RSpec.configure do |config| + config.include Shoulda::Matchers::Independent -if defined?(::ActionController) - require 'shoulda/matchers/action_controller' - module RSpec - module Rails - module ControllerExampleGroup - include Shoulda::Matchers::ActionController - end + if defined?(ActiveRecord) + config.include Shoulda::Matchers::ActiveRecord end - end -end -if defined?(::ActionMailer) - require 'shoulda/matchers/action_mailer' - module RSpec - module Rails - module MailerExampleGroup - include Shoulda::Matchers::ActionMailer - end + if defined?(ActiveModel) + config.include Shoulda::Matchers::ActiveModel + end + + if defined?(ActionController) + config.include Shoulda::Matchers::ActionController end end end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/test_unit.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_unit.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/integrations/test_unit.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/integrations/test_unit.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,9 +1,15 @@ # :enddoc: +require 'shoulda/matchers/integrations/nunit_test_case_detection' -if defined?(ActionController) - require 'shoulda/matchers/action_controller' +Shoulda::Matchers.nunit_test_case_constants.each do |constant| + constant.class_eval do + include Shoulda::Matchers::Independent + extend Shoulda::Matchers::Independent + end +end - class ActionController::TestCase +if defined?(ActionController::TestCase) + ActionController::TestCase.class_eval do include Shoulda::Matchers::ActionController extend Shoulda::Matchers::ActionController @@ -13,29 +19,16 @@ end end -if defined?(ActionMailer) - require 'shoulda/matchers/action_mailer' - - module Test - module Unit - class TestCase - include Shoulda::Matchers::ActionMailer - extend Shoulda::Matchers::ActionMailer - end +if defined?(ActiveSupport::TestCase) + ActiveSupport::TestCase.class_eval do + if defined?(Shoulda::Matchers::ActiveRecord) + include Shoulda::Matchers::ActiveRecord + extend Shoulda::Matchers::ActiveRecord end - end -end - -if defined?(ActiveRecord) - require 'shoulda/matchers/active_record' - module Test - module Unit - class TestCase - include Shoulda::Matchers::ActiveRecord - extend Shoulda::Matchers::ActiveRecord - end + if defined?(Shoulda::Matchers::ActiveModel) + include Shoulda::Matchers::ActiveModel + extend Shoulda::Matchers::ActiveModel end end end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/matcher_context.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/matcher_context.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/matcher_context.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/matcher_context.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +module Shoulda + module Matchers + # @private + class MatcherContext + def initialize(context) + @context = context + end + + def subject_is_a_class? + if inside_a_shoulda_context_project? && outside_a_should_block? + assume_that_subject_is_not_a_class + else + context.subject.is_a?(Class) + end + end + + protected + + attr_reader :context + + private + + def inside_a_shoulda_context_project? + defined?(Shoulda::Context) + end + + def outside_a_should_block? + context.is_a?(Class) + end + + def assume_that_subject_is_not_a_class + false + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/rails_shim.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/rails_shim.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/rails_shim.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/rails_shim.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,111 @@ +module Shoulda + module Matchers + # @private + class RailsShim + def self.layouts_ivar + if action_pack_major_version >= 4 + '@_layouts' + else + '@layouts' + end + end + + def self.flashes_ivar + if action_pack_major_version >= 4 + :@flashes + else + :@used + end + end + + def self.clean_scope(klass) + if active_record_major_version == 4 + klass.all + else + klass.scoped + end + end + + def self.validates_confirmation_of_error_attribute(matcher) + if active_model_major_version == 4 + matcher.confirmation_attribute + else + matcher.attribute + end + end + + def self.verb_for_update + if action_pack_gte_4_1? + :patch + else + :put + end + end + + def self.type_cast_default_for(model, column) + if model.respond_to?(:column_defaults) + # Rails 4.2 + model.column_defaults[column.name] + else + column.default + end + end + + def self.serialized_attributes_for(model) + if defined?(::ActiveRecord::Type::Serialized) + # Rails 5+ + model.columns.select do |column| + column.cast_type.is_a?(::ActiveRecord::Type::Serialized) + end.inject({}) do |hash, column| + hash[column.name.to_s] = column.cast_type.coder + hash + end + else + model.serialized_attributes + end + end + + def self.generate_validation_message(record, attribute, type, model_name, options) + if record && record.errors.respond_to?(:generate_message) + record.errors.generate_message(attribute.to_sym, type, options) + else + simply_generate_validation_message(attribute, type, model_name, options) + end + rescue RangeError + simply_generate_validation_message(attribute, type, model_name, options) + end + + def self.simply_generate_validation_message(attribute, type, model_name, options) + default_translation_keys = [ + :"activerecord.errors.models.#{model_name}.#{type}", + :"activerecord.errors.messages.#{type}", + :"errors.attributes.#{attribute}.#{type}", + :"errors.messages.#{type}" + ] + primary_translation_key = :"activerecord.errors.models.#{model_name}.attributes.#{attribute}.#{type}" + translate_options = { default: default_translation_keys }.merge(options) + I18n.translate(primary_translation_key, translate_options) + end + + def self.active_record_major_version + ::ActiveRecord::VERSION::MAJOR + end + + def self.active_model_major_version + ::ActiveModel::VERSION::MAJOR + end + + def self.action_pack_major_version + ::ActionPack::VERSION::MAJOR + end + + def self.action_pack_gte_4_1? + Gem::Requirement.new('>= 4.1').satisfied_by?(action_pack_version) + end + + def self.action_pack_version + Gem::Version.new(::ActionPack::VERSION::STRING) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/util.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/util.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/util.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,33 @@ +module Shoulda + module Matchers + # @private + module Util + def self.deconstantize(path) + if defined?(ActiveSupport::Inflector) && + ActiveSupport::Inflector.respond_to?(:deconstantize) + ActiveSupport::Inflector.deconstantize(path) + else + path.to_s[0...(path.to_s.rindex('::') || 0)] + end + end + + def self.safe_constantize(camel_cased_word) + if defined?(ActiveSupport::Inflector) && + ActiveSupport::Inflector.respond_to?(:safe_constantize) + ActiveSupport::Inflector.safe_constantize(camel_cased_word) + else + begin + camel_cased_word.constantize + rescue NameError + nil + end + end + end + + def self.indent(string, width) + indentation = ' ' * width + string.split(/[\n\r]/).map { |line| indentation + line }.join("\n") + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/version.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/version.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/version.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/version.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,5 +1,6 @@ module Shoulda module Matchers - VERSION = "1.0.0.beta2".dup + # @private + VERSION = '2.8.0'.freeze end end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/warn.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/warn.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers/warn.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers/warn.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +module Shoulda + module Matchers + TERMINAL_MAX_WIDTH = 72 + + # @private + def self.warn(message) + header = "Warning from shoulda-matchers:" + divider = "*" * TERMINAL_MAX_WIDTH + wrapped_message = word_wrap(message, TERMINAL_MAX_WIDTH) + full_message = [ + divider, + [header, wrapped_message.strip].join("\n\n"), + divider + ].join("\n") + + Kernel.warn(full_message) + end + + # @private + def self.warn_about_deprecated_method(old_method, new_method) + warn < + # @private + def self.word_wrap(text, width=80) + text. + gsub(/\n+/, " "). + gsub( /(\S{#{width}})(?=\S)/, '\1 ' ). + gsub( /(.{1,#{width}})(?:\s+|$)/, "\\1\n" ) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers.rb ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers.rb --- ruby-shoulda-matchers-1.0.0~beta2/lib/shoulda/matchers.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/lib/shoulda/matchers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -1,8 +1,28 @@ -require 'shoulda/matchers/version' require 'shoulda/matchers/assertion_error' +require 'shoulda/matchers/doublespeak' +require 'shoulda/matchers/error' +require 'shoulda/matchers/matcher_context' +require 'shoulda/matchers/rails_shim' +require 'shoulda/matchers/util' +require 'shoulda/matchers/version' +require 'shoulda/matchers/warn' + +require 'shoulda/matchers/independent' + +if defined?(ActiveModel) + require 'shoulda/matchers/active_model' +end + +if defined?(ActiveRecord) + require 'shoulda/matchers/active_record' +end + +if defined?(ActionController) + require 'shoulda/matchers/action_controller' +end if defined?(RSpec) require 'shoulda/matchers/integrations/rspec' -else - require 'shoulda/matchers/integrations/test_unit' end + +require 'shoulda/matchers/integrations/test_unit' diff -Nru ruby-shoulda-matchers-1.0.0~beta2/metadata.yml ruby-shoulda-matchers-2.8.0/metadata.yml --- ruby-shoulda-matchers-1.0.0~beta2/metadata.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/metadata.yml 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,419 @@ +--- !ruby/object:Gem::Specification +name: shoulda-matchers +version: !ruby/object:Gem::Version + version: 2.8.0 +platform: ruby +authors: +- Tammer Saleh +- Joe Ferris +- Ryan McGeary +- Dan Croak +- Matt Jankowski +- Stafford Brunk +- Elliot Winkler +autorequire: +bindir: bin +cert_chain: [] +date: 2015-01-30 00:00:00.000000000 Z +dependencies: +- !ruby/object:Gem::Dependency + name: activesupport + requirement: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 3.0.0 + type: :runtime + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 3.0.0 +description: Making tests easy on the fingers and eyes +email: support@thoughtbot.com +executables: [] +extensions: [] +extra_rdoc_files: [] +files: +- ".gitignore" +- ".hound.yml" +- ".hound_config/ruby.yml" +- ".travis.yml" +- ".yardopts" +- Appraisals +- CONTRIBUTING.md +- Gemfile +- Gemfile.lock +- MIT-LICENSE +- NEWS.md +- README.md +- Rakefile +- cucumber.yml +- doc_config/gh-pages/index.html.erb +- doc_config/yard/setup.rb +- doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +- doc_config/yard/templates/default/fulldoc/html/css/full_list.css +- doc_config/yard/templates/default/fulldoc/html/css/global.css +- doc_config/yard/templates/default/fulldoc/html/css/solarized.css +- doc_config/yard/templates/default/fulldoc/html/css/style.css +- doc_config/yard/templates/default/fulldoc/html/full_list.erb +- doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +- doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +- doc_config/yard/templates/default/fulldoc/html/js/app.js +- doc_config/yard/templates/default/fulldoc/html/js/full_list.js +- doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +- doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +- doc_config/yard/templates/default/fulldoc/html/setup.rb +- doc_config/yard/templates/default/layout/html/breadcrumb.erb +- doc_config/yard/templates/default/layout/html/fonts.erb +- doc_config/yard/templates/default/layout/html/layout.erb +- doc_config/yard/templates/default/layout/html/search.erb +- doc_config/yard/templates/default/layout/html/setup.rb +- doc_config/yard/templates/default/method_details/html/source.erb +- doc_config/yard/templates/default/module/html/box_info.erb +- docs.watchr +- gemfiles/3.0.gemfile +- gemfiles/3.0.gemfile.lock +- gemfiles/3.1.gemfile +- gemfiles/3.1.gemfile.lock +- gemfiles/3.1_1.9.2.gemfile +- gemfiles/3.1_1.9.2.gemfile.lock +- gemfiles/3.2.gemfile +- gemfiles/3.2.gemfile.lock +- gemfiles/3.2_1.9.2.gemfile +- gemfiles/3.2_1.9.2.gemfile.lock +- gemfiles/4.0.0.gemfile +- gemfiles/4.0.0.gemfile.lock +- gemfiles/4.0.1.gemfile +- gemfiles/4.0.1.gemfile.lock +- gemfiles/4.1.gemfile +- gemfiles/4.1.gemfile.lock +- gemfiles/4.2.gemfile +- gemfiles/4.2.gemfile.lock +- lib/shoulda-matchers.rb +- lib/shoulda/matchers.rb +- lib/shoulda/matchers/action_controller.rb +- lib/shoulda/matchers/action_controller/callback_matcher.rb +- lib/shoulda/matchers/action_controller/filter_param_matcher.rb +- lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +- lib/shoulda/matchers/action_controller/render_template_matcher.rb +- lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +- lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +- lib/shoulda/matchers/action_controller/respond_with_matcher.rb +- lib/shoulda/matchers/action_controller/route_matcher.rb +- lib/shoulda/matchers/action_controller/route_params.rb +- lib/shoulda/matchers/action_controller/set_flash_matcher.rb +- lib/shoulda/matchers/action_controller/set_session_matcher.rb +- lib/shoulda/matchers/action_controller/strong_parameters_matcher.rb +- lib/shoulda/matchers/active_model.rb +- lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +- lib/shoulda/matchers/active_model/allow_value_matcher.rb +- lib/shoulda/matchers/active_model/disallow_value_matcher.rb +- lib/shoulda/matchers/active_model/errors.rb +- lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +- lib/shoulda/matchers/active_model/helpers.rb +- lib/shoulda/matchers/active_model/numericality_matchers.rb +- lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +- lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +- lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +- lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +- lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +- lib/shoulda/matchers/active_model/strict_validator.rb +- lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +- lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +- lib/shoulda/matchers/active_model/validation_matcher.rb +- lib/shoulda/matchers/active_model/validator.rb +- lib/shoulda/matchers/active_model/validator_with_captured_range_error.rb +- lib/shoulda/matchers/active_record.rb +- lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +- lib/shoulda/matchers/active_record/association_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers.rb +- lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +- lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +- lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +- lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +- lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +- lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +- lib/shoulda/matchers/active_record/have_db_column_matcher.rb +- lib/shoulda/matchers/active_record/have_db_index_matcher.rb +- lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +- lib/shoulda/matchers/active_record/serialize_matcher.rb +- lib/shoulda/matchers/active_record/uniqueness.rb +- lib/shoulda/matchers/active_record/uniqueness/model.rb +- lib/shoulda/matchers/active_record/uniqueness/namespace.rb +- lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +- lib/shoulda/matchers/active_record/uniqueness/test_models.rb +- lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +- lib/shoulda/matchers/assertion_error.rb +- lib/shoulda/matchers/doublespeak.rb +- lib/shoulda/matchers/doublespeak/double.rb +- lib/shoulda/matchers/doublespeak/double_collection.rb +- lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +- lib/shoulda/matchers/doublespeak/object_double.rb +- lib/shoulda/matchers/doublespeak/proxy_implementation.rb +- lib/shoulda/matchers/doublespeak/structs.rb +- lib/shoulda/matchers/doublespeak/stub_implementation.rb +- lib/shoulda/matchers/doublespeak/world.rb +- lib/shoulda/matchers/error.rb +- lib/shoulda/matchers/independent.rb +- lib/shoulda/matchers/independent/delegate_method_matcher.rb +- lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +- lib/shoulda/matchers/independent/delegate_method_matcher/target_not_defined_error.rb +- lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +- lib/shoulda/matchers/integrations/rspec.rb +- lib/shoulda/matchers/integrations/test_unit.rb +- lib/shoulda/matchers/matcher_context.rb +- lib/shoulda/matchers/rails_shim.rb +- lib/shoulda/matchers/util.rb +- lib/shoulda/matchers/version.rb +- lib/shoulda/matchers/warn.rb +- script/SUPPORTED_VERSIONS +- script/install_gems_in_all_appraisals +- script/run_all_tests +- script/update_gem_in_all_appraisals +- shoulda-matchers.gemspec +- spec/acceptance/active_model_integration_spec.rb +- spec/acceptance/independent_matchers_spec.rb +- spec/acceptance/rails_integration_spec.rb +- spec/acceptance_spec_helper.rb +- spec/report_warnings.rb +- spec/support/acceptance/helpers.rb +- spec/support/acceptance/helpers/active_model_helpers.rb +- spec/support/acceptance/helpers/array_helpers.rb +- spec/support/acceptance/helpers/base_helpers.rb +- spec/support/acceptance/helpers/command_helpers.rb +- spec/support/acceptance/helpers/file_helpers.rb +- spec/support/acceptance/helpers/gem_helpers.rb +- spec/support/acceptance/helpers/minitest_helpers.rb +- spec/support/acceptance/helpers/pluralization_helpers.rb +- spec/support/acceptance/helpers/rails_version_helpers.rb +- spec/support/acceptance/helpers/rspec_helpers.rb +- spec/support/acceptance/helpers/ruby_version_helpers.rb +- spec/support/acceptance/helpers/step_helpers.rb +- spec/support/acceptance/matchers/have_output.rb +- spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +- spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +- spec/support/tests/bundle.rb +- spec/support/tests/command_runner.rb +- spec/support/tests/filesystem.rb +- spec/support/tests/version.rb +- spec/support/unit/capture.rb +- spec/support/unit/helpers/active_model_helpers.rb +- spec/support/unit/helpers/active_model_versions.rb +- spec/support/unit/helpers/active_record_versions.rb +- spec/support/unit/helpers/active_resource_builder.rb +- spec/support/unit/helpers/allow_value_matcher_helpers.rb +- spec/support/unit/helpers/class_builder.rb +- spec/support/unit/helpers/confirmation_matcher_helpers.rb +- spec/support/unit/helpers/controller_builder.rb +- spec/support/unit/helpers/i18n_faker.rb +- spec/support/unit/helpers/mailer_builder.rb +- spec/support/unit/helpers/model_builder.rb +- spec/support/unit/helpers/rails_versions.rb +- spec/support/unit/i18n.rb +- spec/support/unit/matchers/deprecate.rb +- spec/support/unit/matchers/fail_with_message_including_matcher.rb +- spec/support/unit/matchers/fail_with_message_matcher.rb +- spec/support/unit/matchers/print_warning_including.rb +- spec/support/unit/rails_application.rb +- spec/support/unit/record_builder_with_i18n_validation_message.rb +- spec/support/unit/record_validating_confirmation_builder.rb +- spec/support/unit/record_with_different_error_attribute_builder.rb +- spec/support/unit/shared_examples/numerical_submatcher.rb +- spec/support/unit/shared_examples/numerical_type_submatcher.rb +- spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +- spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/helpers_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +- spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_spec.rb +- spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +- spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +- spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +- spec/unit/shoulda/matchers/doublespeak/world_spec.rb +- spec/unit/shoulda/matchers/doublespeak_spec.rb +- spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +- spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +- spec/unit_spec_helper.rb +- spec/warnings_spy.rb +- spec/warnings_spy/filesystem.rb +- spec/warnings_spy/partitioner.rb +- spec/warnings_spy/reader.rb +- spec/warnings_spy/reporter.rb +- tasks/documentation.rb +homepage: http://thoughtbot.com/community/ +licenses: +- MIT +metadata: {} +post_install_message: +rdoc_options: [] +require_paths: +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: 1.9.2 +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: '0' +requirements: [] +rubyforge_project: +rubygems_version: 2.2.2 +signing_key: +specification_version: 4 +summary: Making tests easy on the fingers and eyes +test_files: +- spec/acceptance/active_model_integration_spec.rb +- spec/acceptance/independent_matchers_spec.rb +- spec/acceptance/rails_integration_spec.rb +- spec/acceptance_spec_helper.rb +- spec/report_warnings.rb +- spec/support/acceptance/helpers.rb +- spec/support/acceptance/helpers/active_model_helpers.rb +- spec/support/acceptance/helpers/array_helpers.rb +- spec/support/acceptance/helpers/base_helpers.rb +- spec/support/acceptance/helpers/command_helpers.rb +- spec/support/acceptance/helpers/file_helpers.rb +- spec/support/acceptance/helpers/gem_helpers.rb +- spec/support/acceptance/helpers/minitest_helpers.rb +- spec/support/acceptance/helpers/pluralization_helpers.rb +- spec/support/acceptance/helpers/rails_version_helpers.rb +- spec/support/acceptance/helpers/rspec_helpers.rb +- spec/support/acceptance/helpers/ruby_version_helpers.rb +- spec/support/acceptance/helpers/step_helpers.rb +- spec/support/acceptance/matchers/have_output.rb +- spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +- spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +- spec/support/tests/bundle.rb +- spec/support/tests/command_runner.rb +- spec/support/tests/filesystem.rb +- spec/support/tests/version.rb +- spec/support/unit/capture.rb +- spec/support/unit/helpers/active_model_helpers.rb +- spec/support/unit/helpers/active_model_versions.rb +- spec/support/unit/helpers/active_record_versions.rb +- spec/support/unit/helpers/active_resource_builder.rb +- spec/support/unit/helpers/allow_value_matcher_helpers.rb +- spec/support/unit/helpers/class_builder.rb +- spec/support/unit/helpers/confirmation_matcher_helpers.rb +- spec/support/unit/helpers/controller_builder.rb +- spec/support/unit/helpers/i18n_faker.rb +- spec/support/unit/helpers/mailer_builder.rb +- spec/support/unit/helpers/model_builder.rb +- spec/support/unit/helpers/rails_versions.rb +- spec/support/unit/i18n.rb +- spec/support/unit/matchers/deprecate.rb +- spec/support/unit/matchers/fail_with_message_including_matcher.rb +- spec/support/unit/matchers/fail_with_message_matcher.rb +- spec/support/unit/matchers/print_warning_including.rb +- spec/support/unit/rails_application.rb +- spec/support/unit/record_builder_with_i18n_validation_message.rb +- spec/support/unit/record_validating_confirmation_builder.rb +- spec/support/unit/record_with_different_error_attribute_builder.rb +- spec/support/unit/shared_examples/numerical_submatcher.rb +- spec/support/unit/shared_examples/numerical_type_submatcher.rb +- spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/route_params_spec.rb +- spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +- spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/helpers_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +- spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +- spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +- spec/unit/shoulda/matchers/doublespeak/double_spec.rb +- spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +- spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +- spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +- spec/unit/shoulda/matchers/doublespeak/world_spec.rb +- spec/unit/shoulda/matchers/doublespeak_spec.rb +- spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb +- spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb +- spec/unit_spec_helper.rb +- spec/warnings_spy.rb +- spec/warnings_spy/filesystem.rb +- spec/warnings_spy/partitioner.rb +- spec/warnings_spy/reader.rb +- spec/warnings_spy/reporter.rb +has_rdoc: diff -Nru ruby-shoulda-matchers-1.0.0~beta2/MIT-LICENSE ruby-shoulda-matchers-2.8.0/MIT-LICENSE --- ruby-shoulda-matchers-1.0.0~beta2/MIT-LICENSE 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/MIT-LICENSE 2015-02-25 02:12:36.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2007, Tammer Saleh, Thoughtbot, Inc. +Copyright (c) 2006-2014, Tammer Saleh, thoughtbot, inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff -Nru ruby-shoulda-matchers-1.0.0~beta2/NEWS.md ruby-shoulda-matchers-2.8.0/NEWS.md --- ruby-shoulda-matchers-1.0.0~beta2/NEWS.md 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/NEWS.md 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,552 @@ +# 2.8.0 + +### Deprecations + +* `ensure_length_of` has been renamed to `validate_length_of`. + `ensure_length_of` is deprecated and will be removed in 3.0.0. + +* `set_the_flash` has been renamed to `set_flash`. `set_the_flash` is + deprecated and will be removed in 3.0.0. + +* `set_session(:foo)` is deprecated in favor of `set_session[:foo]`. + `set_session(:foo)` will be invalid syntax in 3.0.0. + +* Using `should set_session[:key].to(nil)` to assert that that a value has not + been set is deprecated. Please use `should_not set_session[:key]` instead. + In 3.0.0, `should set_session[:key].to(nil)` will only pass if the value is + truly nil. + +### Bug fixes + +* Fix `delegate_method` so that it works again with shoulda-context. ([#591]) + +* Fix `validate_uniqueness_of` when used with `scoped_to` so that when one of + the scope attributes is a polymorphic `*_type` attribute and the model has + another validation on the same attribute, the matcher does not fail with an + error. ([#592]) + +* Fix `has_many` used with `through` so that when the association does not + exist, and the matcher fails, it does not raise an error when producing the + failure message. ([#588]) + +* Fix `have_and_belong_to_many` used with `join_table` so that it does not fail + when `foreign_key` and/or `association_foreign_key` was specified on the + association as a symbol instead of a string. ([#584]) + +* Fix `allow_value` when an i18n translation key is passed to `with_message` and + the `:against` option is used to specify an alternate attribute. A bug here + also happened to affect `validate_confirmation_of` when an i18n translation + key is passed to `with_message`. ([#593]) + +* Fix `class_name` qualifier for association matchers so that if the model being + referenced is namespaced, the matcher will correctly resolve the class before + checking it against the association's `class_name`. ([#537]) + +* Fix `validate_inclusion_of` used with `with_message` so that it fails if given + a message that does not match the message on the validation. ([#598]) + +* Fix `route` matcher so that when controller and action are specified in hash + notation (e.g. `posts#show`), route parameters such as `id` do not need to be + specified as a string but may be specified as a number as well. ([#602]) + +* Fix `allow_value`, `validate_numericality_of` and `validate_inclusion_of` so + that they handle RangeErrors emitted from ActiveRecord 4.2. These exceptions + arise whenever we attempt to set an attribute using a value that lies outside + the range of the column (assuming the column is an integer). RangeError is now + treated specially, failing the test instead of bubbling up as an error. + ([#634], [#637], [#642]) + +### Features + +* Add ability to test `:primary_key` option on associations. ([#597]) + +* Add `allow_blank` qualifier to `validate_uniqueness_of` to complement + the `allow_blank` option. ([#543]) + +* Change `set_session` so that #[] and #to qualifiers are optional, similar to + `set_flash`. That is, you can now say `should set_session` to assert that any + flash value has been set, or `should set_session.to('value')` to assert that + any value in the session is 'value'. + +* Change `set_session` so that its #to qualifier supports regexps, similar to + `set_flash`. + +* Add `with_prefix` qualifier to `delegate_method` to correspond to the `prefix` + option for Rails's `delegate` macro. ([#622]) + +* Add support for Rails 4.2, especially fixing `serialize` matcher to remove + warning about `serialized_attributes` being deprecated. ([#627]) + +* Update `dependent` qualifier on association matchers to support `:destroy`, + `:delete`, `:nullify`, `:restrict`, `:restrict_with_exception`, and + `:restrict_with_error`. You can also pass `true` or `false` to assert that + the association has (or has not) been declared with *any* dependent option. + ([#631]) + +### Improvements + +* Tweak `allow_value` failure message so that it reads a bit nicer when listing + existing errors. + +[#591]: https://github.com/thoughtbot/shoulda-matchers/pull/591 +[#592]: https://github.com/thoughtbot/shoulda-matchers/pull/592 +[#588]: https://github.com/thoughtbot/shoulda-matchers/pull/588 +[#584]: https://github.com/thoughtbot/shoulda-matchers/pull/584 +[#593]: https://github.com/thoughtbot/shoulda-matchers/pull/593 +[#597]: https://github.com/thoughtbot/shoulda-matchers/pull/597 +[#537]: https://github.com/thoughtbot/shoulda-matchers/pull/537 +[#598]: https://github.com/thoughtbot/shoulda-matchers/pull/598 +[#602]: https://github.com/thoughtbot/shoulda-matchers/pull/602 +[#543]: https://github.com/thoughtbot/shoulda-matchers/pull/543 +[#622]: https://github.com/thoughtbot/shoulda-matchers/pull/622 +[#627]: https://github.com/thoughtbot/shoulda-matchers/pull/627 +[#631]: https://github.com/thoughtbot/shoulda-matchers/pull/631 +[#634]: https://github.com/thoughtbot/shoulda-matchers/pull/634 +[#637]: https://github.com/thoughtbot/shoulda-matchers/pull/637 +[#642]: https://github.com/thoughtbot/shoulda-matchers/pull/642 + +# 2.7.0 + +### Deprecations + +* `ensure_inclusion_of` has been renamed to `validate_inclusion_of`. + `ensure_inclusion_of` is deprecated and will be removed in 3.0.0. + +* `ensure_exclusion_of` has been renamed to `validate_exclusion_of`. + `ensure_exclusion_of` is deprecated and will be removed in 3.0.0. + +### Bug fixes + +* Fix `delegate_method` so that it does not raise an error if the method that + returns the delegate object is private. + +* Warn when `ensure_inclusion_of` is chained with `.in_array([false, true])` + as well as with `.in_array([true, false])`. + +* Fix `set_session` so that the `to` qualifier if given nil checks that the + session variable in question was set to nil (previously this actually did + nothing). + +* Fix `filter_param` so that it works when `config.filter_parameters` contains + regexes. + +* Fix `delegate_method` so that it can be required independent of Active + Support. + +* Fix `validate_uniqueness_of`. When used against an unpersisted record whose + model contained a non-nullable column other than the one being validated, the + matcher would break. Even if the test set that column to a value beforehand, + the record had to be persisted in order for the matcher to work. Now this is + no longer the case and the record can remain unpersisted. + +* Fix `validate_absence_of`: it required that a string be passed as the + attribute name rather than a symbol (which is the usual and documented usage). + +### Features + +* Add new matcher `define_enum_for` to test usage of the `enum` macro introduced + in Rails 4.1. + +### Improvements + +* `have_and_belongs_to_many` now checks to make sure that the join table + contains the correct columns for the left- and right-hand side of the + association. + +* Reword failure message for `delegate_method` so that it's a little more + helpful. + +# 2.6.2 + +### Bug fixes + +* If you have a Rails >= 4.1 project and you are running tests using Spring, + matchers that depend on assertions within Rails' testing layer (e.g. + `render_template` and `route`) will no longer fail. + +* Fix `permit` so that it can be used more than once in the same test. + +* Revert change to `validate_uniqueness_of` made in 2.6.0 so that it no longer + provides default values for non-primary, non-nullable columns. This approach + was causing test failures because it makes the assumption that none of these + columns allow only specific values, which is not true. If you get an error + from `validate_uniqueness_of`, your best bet continues to be creating a record + manually and calling `validate_uniqueness_of` on that instead. + +* The majority of warnings that the gem produced have been removed. The gem + still produces warnings under Ruby 1.9.3; we will address this in a future + release. + +# 2.6.1 + +### Bug fixes + +* Revert changes to `validate_numericality_of` made in the last release, which + made it so that comparison qualifiers specified on the validation are tested + using a very small decimal number offset rather than a whole number by + default, except if the matcher was qualified with `only_integer`. This means + that prior to 2.6.0, if your validation specified `only_integer` and you did + not, then after 2.6.0 that test would fail. This is now fixed. + +* Fix regression in previous release where ActiveRecord matchers would not be + included when ActiveRecord wasn't defined (i.e. if you were using ActiveModel + only). + +* Revert the behavior of `allow_value` changed in 2.6.0 (it will no longer raise + CouldNotClearAttribute). This was originally done as a part of a fix for + `validate_presence_of` when used in conjunction with `has_secure_password`. + That fix has been updated so that it does not affect `allow_value`. + +* Fix callback matchers and correct test coverage. + +* Fix `permit` so that it does not interfere with different usages of `params` + in your controller action. Specifically, this will not raise an error: + `params.fetch(:foo, {}).permit(:bar, :baz)` (the `permit` will have no + problems recognizing that :bar and :baz are permitted params). + +* Fix `permit` on Rails 4.1 to use PATCH by default for #update instead of PUT. + Previously you had to specify this manually. + +* Fix `permit` so that it track multiple calls to #permit in your controller + action. Previously only the last usage of #permit would be considered in + determining whether the matcher matched. + +* Fix `permit` so that if the route for your action requires params (such as id) + then you can now specify those params: + `permit(:first_name, :last_name).for(:update, params: { id: 42 })`. + +* Fix `delegate_method` so that it does not stub the target method forever, + returning it to its original implementation after the match ends. + +* Fix `validate_uniqueness_of` to work with Rails 4.1 enum columns. + +### Features + +* Teach `with_message` qualifier on `allow_value` to accept a hash of i18n + interpolation values: + `allow_value('foo').for(:attr).with_message(:greater_than, values: { count: 20 })`. + +# 2.6.0 + +* The boolean argument to `have_db_index`'s `unique` option is now optional, for + consistency with other matchers. + +* Association matchers now test that the model being referred to (either + implicitly or explicitly, using `:class_name`) actually exists. + +* Add ability to test `:autosave` option on associations. + +* Fix `validate_uniqueness_of(...).allow_nil` so that it can be used against an + non-password attribute which is in a model that `has_secure_password`. Doing + so previously would result in a "Password digest missing on new record" error. + +* Fix description for `validate_numericality_of` so that if the matcher fails, + the error message reported does not say the matcher accepts integer values if + you didn't specify that. + +* Fix `ensure_inclusion_of` so that you can use it against a boolean column + (and pass boolean values to `in_array`). There are two caveats: + + * You should not test that your attribute allows both true and false + (`.in_array([true, false]`); there's no way to test that it doesn't accept + anything other than that. + * You cannot test that your attribute allows nil (`.in_array([nil])`) if + the column does not allow null values. + +* Change `validate_uniqueness_of(...)` so that it provides default values for + non-nullable attributes. + +* Running `rake` now installs Appraisals before running the test suite. + (Additionally, we now manage Appraisals using the `appraisal` executable in + Appraisal 1.0.0.) + +* Add `allow_nil` option to `validate_numericality_of` so that you can validate + that numeric values are validated only if a value is supplied. + +* Fix `validate_numericality_of` so that test fails when the value with + `greater_than`, `greater_than_or_equal_to`, `less_than`, `less_than_or_equal_ + to` or `equal_to` is not appropriate. + +* Change `validate_presence_of` under Rails 4 so that if you are using it with a + user whose model `has_secure_password` and whose password is set to a value, + you will be instructed to use a user whose password is blank instead. The + reason for this change is due to the fact that Rails 4's version of + `has_secure_password` defines #password= such that `nil` will be ignored, + which interferes with how `validate_presence_of` works. + +* Add ability to test `belongs_to` associations defined with `:inverse_of`. + +* Add back matchers that were removed in 2.0.0: `permit`, for testing strong + parameters, and `delegate_method`, for testing delegation. + +* Add new matchers for testing controller filters: `before_filter`, + `after_filter`, and `around_filter` (aliased to `before_action`, + `after_action` and `around_action` for Rails 4). + +* Fix `rescue_from` matcher so that it does not raise an error when testing + a method handler which has been marked as protected or private. + +* Fix compatibility issues with Rails 4.1: + * `set_the_flash` and `have_and_belongs_to_many` no longer raise errors + * Minitest no longer prints warnings whenever shoulda-matchers is required + +# v 2.5.0 + +* Fix Rails/Test::Unit integration to ensure that the test case classes we are + re-opening actually exist. + +* Fix `ensure_length_of` so that it uses the right message to validate when + `is_equal_to` is specified in conjunction with a custom message. + +* The `route` matcher now accepts specifying a controller/action pair as a + string instead of only a hash (e.g. `route(...).to('posts#index')` instead of + `route(...).to(controller: 'posts', action: 'index')`). + +* The `ensure_inclusion_of` matcher now works with a decimal column. + +* Under Rails 3, if you had an association matcher chained with the + the `order` submatcher -- e.g. `should have_many(:foos).order(:bar)` -- and + your association had an `:include` on it, using the matcher would raise an + error. This has been fixed. + +* Fix `validate_uniqueness_of` so it doesn't fail if the attribute under + test has a limit of fewer than 16 characters. + +* You can now test that your `has_many :through` or `has_one :through` + associations are defined with a `:source` option. + +* Add new matcher `validates_absence_of`. + +* Update matchers so that they use `failure_message` and + `failure_message_when_negated` to define error messages. These are new methods + in the upcoming RSpec 3 release which replace `failure_message_for_should` and + `failure_message_for_should_not`. We've kept backward compatibility so all of + your existing tests should still work -- this is just to make sure when RSpec + 3 is released you don't get a bunch of warnings. + +# v 2.4.0 + +* Fix a bug with the `validate_numericality_of` matcher that would not allow the + `with_message` option on certain submatchers. + +* Fix a regression with context-dependent validations in ActiveResource + +* shoulda-matchers is now fully compatible with Rails 4. + +* When not using RSpec, shoulda-matchers is now auto-included into + ActiveSupport::TestCase instead of Test::Unit::TestCase (in Rails 4 + the former no longer inherits from the latter). + +# v 2.3.0 + +* Fix a bug in `ensure_inclusion_of` that would cause issues with using + `in_array` with an integer value. + +* Add support for PostgreSQL UUID columns to `validates_uniqueness_of` (#334). + +* Fix `validates_numericality_of` so that `is_equal_to` submatcher works + correctly (#326). + +* Fix context support for validation matchers and disallowed values (#313). + +* Add a `counter_cache` submatcher for `belongs_to` associations (#311). + +* Add a `rescue_from` matcher for Rails controllers which checks that the + correct ActiveSupport call has been made and that the handlers exist without + actually throwing an exception (#287). + +* Changed the scope of AssociationMatcher methods from protected to private. + +* Extracted `#order`, `#through`, and `#dependent` from AssociationMatcher as + their own submatchers. + +# v 2.2.0 + +* Fix `have_and_belong_to_many` matcher issue for Rails 4. + +* Fix `validate_uniqueness_of.scoped_to` issue when the scoped field is already + taken (#207). + +* Add comparison submatchers to `validate_numericality_of` to correspond to the + comparison options you can give to `validates_numericality_of` (#244). + +# v 2.1.0 + +* Add missing `failure_message_for_should_not` implementations to +`validate_numericality_of` and its submatchers + +* Support validation contexts for testing validations `on: :create` and when + using custom contexts like `model.valid?(:my_context)`. + +* Fix a bug in validations with autosaved models. + +* Fix maximum value detection for the `ensure_inclusion_of` and +`ensure_exclusion_of` matchers. + +* Add `:odd` and `:even` options to the `validate_numericality_of` matcher. + +* Add `:touch` option to AssociationMatcher. + +* Ruby 2.0.0 is now officially supported. + +* Fix the issue where using `%{attribute}` or `%{model}` in I18n translations +raised exceptions. + +* Support datetime columns in `validate_uniqueness_of.scoped_to`. + +* Add `allow_nil` option to the `validate_uniqueness_of` matcher. + +# v 2.0.0 +* Remove the following matchers: + * `assign_to` + * `respond_with_content_type` + * `query_the_database` + * `validate_format_of` + * `have_sent_email` + * `permit` (strong parameters matcher) + * `delegate_method` + +* For more information about 2.0 changes, see: +http://robots.thoughtbot.com/post/47031676783/shoulda-matchers-2-0. + +# v 1.5.6 +* Revert previous change in AllowValueMatcher that added a check for a +properly-set attribute. + +# v 1.5.5 +* AllowValueMatcher checks that the right value is used for attempts at +setting the attribute with it. + * Please note that previously-passing tests might now fail. It is likely that + it's not a bug, but please make sure that the code you're testing is written + properly before submitting an issue. + +* Use DisallowValueMatcher for `disallows_value_of` method. + +* Assert `class_name` value on real class name for AssociationMatcher. + +* Correct the variable used for `validate_confirmation_of` matcher description. + +# v 1.5.4 +* Properly-released version of 1.5.3. + +# v 1.5.3 - yanked due to mis-release +* Alleviate the need to add `rspec` gem to your app. + +# v 1.5.1 +* Bump version dependency of Bourne to allow for Mocha upgrade. + +* Should fix incompatibility with MiniTest. + +# v 1.5.0 +* Deprecate the following matchers: + * `assign_to` + * `respond_with_content_type` + * `query_the_database` + * `validate_format_of` + * `have_sent_email` + * `permit` (strong parameters matcher) + * `delegate_method` + +* Use RSpec's native `configure.include` syntax for including matchers into + RSpec (#204). + +* Do not force MiniTest loading when test-unit is available (this was fixed + before 1.3.0 then reverted in 1.3.0). + +# v1.4.2 +* Add a new `delegate_method` matcher. + +# v1.4.1 +* Fix an issue when used with Test::Unit on the allow value matcher. + +* Fix an issue with using `ensure_inclusion_of(:attr)` given an array of true or false values. + +# v1.4.0 + +* Add `strict` option to validation matchers. + +* Verify that arguments to `set_the_flash` matcher are valid. + +* Fix issue in ValidateUniquenessMatcher that could cause an error on postgres. + +* You can now pass an array to `ensure_exclusion_of` using `in_array`. + +* Allow testing of `:foreign_key` option for `has_one` relationships using the association matcher. + +* Fix bug where `ensure_length_of` would pass if the given string was too long. + +* `allow_blank` will now allow values such as: ' ', '\n', and '\r'. + +* Test outside values for `ensure_inclusion_of` when given an array. + +* Fix the output of the `set_the_flash` matcher. + +# v1.3.0 + +* `validate_format_of` will accept `allow_blank(bool)` and `allow_nil(bool)`. + +* Prefer Test::Unit to MiniTest when loading integrations so that RubyMine is + happy (#88). + +* `validates_uniqueness_of` will now create a record if one does not exist. + Previously, users were required to create a record in the database before + using this matcher. + +* Fix an edge case when where the matchers weren't loaded into Test::Unit when + mixing RSpec and Test::Unit tests and also loading both the 'rspec-rails' gem + and 'shoulda-matchers' gem from the same Gemfile group, namely [:test, + :development]. + +* `controller.should_not render_partial` now correctly matches `render partial: "partial"`. + +# v1.2.0 + +* `ensure_inclusion_of` now has an `in_array` parameter: + `ensure_inclusion_of(:attr).in_array(['foo', 'bar'])`. It cannot be used with + the `.in_range` option. (vpereira) + +* `ensure_in_inclusion_of` with `in_array` will accept `allow_blank(bool)` and `allow_nil(false)` + +* Test against Rails 3.2. + +* Fix `ensure_length_of` to use all possible I18n error messages. + +* `have_db_index.unique(nil)` used to function exactly the same as + `have_db_index` with no unique option. It now functions the same as + `have_db_index.unique(false)`. + +* In 1.1.0, `have_sent_email` checked all emails to ensure they matched. It now + checks that only one email matches, which restores 1.0.0 behavior. + +# v1.1.0 + +* Add `only_integer` option to `validate_numericality_of`: + `should validate_numericality_of(:attribute).only_integer` + +* Add a `query_the_database` matcher: + + `it { should query_the_database(4.times).when_calling(:complicated_method) }` + `it { should query_the_database(4.times).or_less.when_calling(:complicated_method) }` + `it { should_not query_the_database.when_calling(:complicated_method) }` + +* Database columns are now correctly checked for primality. E.G., this works + now: `it { should have_db_column(:id).with_options(:primary => true) }` + +* The flash matcher can check specific flash keys using [], like so: + `it { should set_the_flash[:alert].to("Password doesn't match") }` + +* The `have_sent_email` matcher can check `reply_to`: + ` it { should have_sent_email.reply_to([user, other]) }` + +* Add `validates_confirmation_of` matcher: + `it { should validate_confirmation_of(:password) }` + +* Add `serialize` matcher: + `it { should serialize(:details).as(Hash).as_instance_of(Hash) }` + +* shoulda-matchers checks for all possible I18n keys, instead of just + e.g. `activerecord.errors.messages.blank` + +* Add `accept_nested_attributes` matcher + +* Our very first dependency: ActiveSupport >= 3.0.0 diff -Nru ruby-shoulda-matchers-1.0.0~beta2/Rakefile ruby-shoulda-matchers-2.8.0/Rakefile --- ruby-shoulda-matchers-1.0.0~beta2/Rakefile 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/Rakefile 2015-02-25 02:12:36.000000000 +0000 @@ -1,50 +1,36 @@ -require 'rubygems' require 'bundler/setup' -require 'rake' -require 'rake/rdoctask' -require 'rake/gempackagetask' +require 'bundler/gem_tasks' require 'rspec/core/rake_task' -require 'cucumber/rake/task' +require 'appraisal' +require_relative 'tasks/documentation' -$LOAD_PATH.unshift("lib") -require 'shoulda/matchers/version' - -Rake::RDocTask.new { |rdoc| - rdoc.rdoc_dir = 'doc' - rdoc.title = "Shoulda -- Making tests easy on the fingers and eyes" - rdoc.options << '--line-numbers' - rdoc.template = "#{ENV['template']}.rb" if ENV['template'] - rdoc.rdoc_files.include('README.rdoc', 'CONTRIBUTION_GUIDELINES.rdoc', 'lib/**/*.rb') -} - -RSpec::Core::RakeTask.new do |t| - t.pattern = "spec/**/*_spec.rb" +RSpec::Core::RakeTask.new('spec:unit') do |t| + t.ruby_opts = '-w -r ./spec/report_warnings' + t.pattern = "spec/unit/**/*_spec.rb" t.rspec_opts = '--color --format progress' t.verbose = false end -desc "Run code-coverage analysis using rcov" -RSpec::Core::RakeTask.new(:coverage) do |t| +RSpec::Core::RakeTask.new('spec:acceptance') do |t| + t.ruby_opts = '-w -r ./spec/report_warnings' + t.pattern = "spec/acceptance/**/*_spec.rb" t.rspec_opts = '--color --format progress' - t.rcov = true - t.rcov_opts = %{--exclude osx\/objc,spec,gems\/ --failure-threshold 100} - t.pattern = "spec/**/*_spec.rb" + t.verbose = false end -eval("$specification = begin; #{IO.read('shoulda-matchers.gemspec')}; end") -Rake::GemPackageTask.new $specification do |pkg| - pkg.need_tar = true - pkg.need_zip = true +task :default do + if ENV['BUNDLE_GEMFILE'] =~ /gemfiles/ + sh 'rake spec:unit' + sh 'rake spec:acceptance' + else + Rake::Task['appraise'].invoke + end end -desc "Clean files generated by rake tasks" -task :clobber => [:clobber_rdoc, :clobber_package] - -Cucumber::Rake::Task.new do |t| - t.fork = true - t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')] +task :appraise do + exec 'appraisal install && appraisal rake' end -desc 'Default: run specs and cucumber features' -task :default => [:spec, :cucumber] +Shoulda::Matchers::DocumentationTasks.create +task release: 'docs:publish_latest' diff -Nru ruby-shoulda-matchers-1.0.0~beta2/README.md ruby-shoulda-matchers-2.8.0/README.md --- ruby-shoulda-matchers-1.0.0~beta2/README.md 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/README.md 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,190 @@ +# shoulda-matchers [![Gem Version][version-badge]][rubygems] [![Build Status][travis-badge]][travis] ![Downloads][downloads-badge] + +[Official Documentation][rubydocs] + +shoulda-matchers provides Test::Unit- and RSpec-compatible one-liners that test +common Rails functionality. These tests would otherwise be much longer, more +complex, and error-prone. + +### ActiveModel Matchers + +* **[allow_mass_assignment_of](lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb)** + tests usage of Rails 3's `attr_accessible` and `attr_protected` macros. +* **[allow_value](lib/shoulda/matchers/active_model/allow_value_matcher.rb)** + tests usage of the `validates_format_of` validation. +* **[have_secure_password](lib/shoulda/matchers/active_model/have_secure_password_matcher.rb)** + tests usage of `has_secure_password`. +* **[validate_confirmation_of](lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb)** + tests usage of `validates_confirmation_of`. +* **[validate_exclusion_of](lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb)** + tests usage of `validates_exclusion_of`. +* **[validate_inclusion_of](lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb)** + tests usage of `validates_inclusion_of`. +* **[validate_length_of](lib/shoulda/matchers/active_model/validate_length_of_matcher.rb)** + tests usage of `validates_length_of`. +* **[validate_numericality_of](lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb)** + tests usage of `validates_numericality_of`. +* **[validate_presence_of](lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb)** + tests usage of `validates_presence_of`. + +### ActiveRecord Matchers + +* **[accept_nested_attributes_for](lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb)** + tests usage of the `accepts_nested_attributes_for` macro. +* **[belong_to](lib/shoulda/matchers/active_record/association_matcher.rb)** + tests your `belongs_to` associations. +* **[define_enum_for](lib/shoulda/matchers/active_record/define_enum_for_matcher.rb)** + tests usage of the `enum` macro. +* **[have_and_belong_to_many](lib/shoulda/matchers/active_record/association_matcher.rb)** + tests your `has_and_belongs_to_many` associations. +* **[have_db_column](lib/shoulda/matchers/active_record/have_db_column_matcher.rb)** + tests that the table that backs your model has a specific column. +* **[have_db_index](lib/shoulda/matchers/active_record/have_db_index_matcher.rb)** + tests that the table that backs your model has an index on a specific column. +* **[have_many](lib/shoulda/matchers/active_record/association_matcher.rb)** + tests your `has_many` associations. +* **[have_one](lib/shoulda/matchers/active_record/association_matcher.rb)** + tests your `has_one` associations. +* **[have_readonly_attribute](lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb)** + tests usage of the `attr_readonly` macro. +* **[serialize](lib/shoulda/matchers/active_record/serialize_matcher.rb)** tests + usage of the `serialize` macro. +* **[validate_uniqueness_of](lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb)** + tests usage of `validates_uniqueness_of`. + +### ActionController Matchers + +* **[filter_param](lib/shoulda/matchers/action_controller/filter_param_matcher.rb)** + tests parameter filtering configuration. +* **[redirect_to](lib/shoulda/matchers/action_controller/redirect_to_matcher.rb)** + tests that an action redirects to a certain location. +* **[render_template](lib/shoulda/matchers/action_controller/render_template_matcher.rb)** + tests that an action renders a template. +* **[render_with_layout](lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb)** + tests that an action is rendered with a certain layout. +* **[rescue_from](lib/shoulda/matchers/action_controller/rescue_from_matcher.rb)** + tests usage of the `rescue_from` macro. +* **[respond_with](lib/shoulda/matchers/action_controller/respond_with_matcher.rb)** + tests that an action responds with a certain status code. +* **[route](lib/shoulda/matchers/action_controller/route_matcher.rb)** tests + your routes. +* **[set_session](lib/shoulda/matchers/action_controller/set_session_matcher.rb)** + makes assertions on the `session` hash. +* **[set_flash](lib/shoulda/matchers/action_controller/set_flash_matcher.rb)** + makes assertions on the `flash` hash. +* **[use_after_action](lib/shoulda/matchers/action_controller/use_after_action.rb)** + tests that a `after_action` callback is defined in your controller. (Aliased + as *use_after_filter*.) +* **[use_around_action](lib/shoulda/matchers/action_controller/use_around_action.rb)** + tests that a `around_action` callback is defined in your controller. (Aliased + as *use_around_filter*.) +* **[use_before_action](lib/shoulda/matchers/action_controller/use_before_action.rb)** + tests that a `before_action` callback is defined in your controller. (Aliased + as *use_before_filter*.) + +### Independent Matchers + +* **[delegate_method](lib/shoulda/matchers/independent/delegate_method_matcher.rb)** + tests that an object forwards messages to other, internal objects by way of + delegation. + +## Installation + +### RSpec + +Include the gem in your Gemfile: + +``` ruby +group :test do + gem 'shoulda-matchers', require: false +end +``` + +Then require the gem following rspec-rails in your rails_helper (or spec_helper +if you're using RSpec 2.x): + +``` ruby +require 'rspec/rails' +require 'shoulda/matchers' +``` + +### Test::Unit + +shoulda-matchers was originally a component of [Shoulda][shoulda], a meta-gem +that also provides `should` and `context` syntax via +[shoulda-context][shoulda-context]. For this reason you'll want to include this +gem in your Gemfile instead: + +```ruby +group :test do + gem 'shoulda' +end +``` + +### Non-Rails apps + +Once it is loaded, shoulda-matchers automatically includes itself into your test +framework. It will mix in the appropriate matchers for ActiveRecord, +ActiveModel, and ActionController depending on the modules that are available at +runtime. For instance, in order to use the ActiveRecord matchers, ActiveRecord +must be present beforehand. + +If your application is written against Rails, everything should "just work", as +shoulda-matchers will most likely be declared after Rails in your Gemfile. If +your application is written against another framework such as Sinatra or +Padrino, you may have a different setup, so you will want to ensure that you are +requiring shoulda-matchers after the components of Rails you are using. For +instance, if you wanted to use and test against ActiveModel, you'd say: + +```ruby +gem 'activemodel' +gem 'shoulda-matchers' +``` + +and not: + +```ruby +gem 'shoulda-matchers' +gem 'activemodel' +``` + +## Generating documentation + +YARD is used to generate documentation, which can be viewed [online][rubydocs]. +You can preview changes you make to the documentation locally by running + + yard doc + +from this directory. Then, open `doc/index.html` in your browser. + +If you want to see a live preview as you work without having to run `yard` over +and over again, keep this command running in a separate terminal session: + + watchr docs.watchr + +## Versioning + +shoulda-matchers follows Semantic Versioning 2.0 as defined at +. + +## Credits + +shoulda-matchers is maintained and funded by [thoughtbot][community]. Thank you +to all the [contributors][contributors]. + +## License + +shoulda-matchers is copyright © 2006-2014 thoughtbot, inc. It is free software, +and may be redistributed under the terms specified in the +[MIT-LICENSE](MIT-LICENSE) file. + +[version-badge]: http://img.shields.io/gem/v/shoulda-matchers.svg +[rubygems]: http://rubygems.org/gems/shoulda-matchers +[travis-badge]: http://img.shields.io/travis/thoughtbot/shoulda-matchers/master.svg +[travis]: http://travis-ci.org/thoughtbot/shoulda-matchers +[downloads-badge]: http://img.shields.io/gem/dtv/shoulda-matchers.svg +[rubydocs]: http://matchers.shoulda.io/docs +[community]: http://thoughtbot.com/community +[contributors]: https://github.com/thoughtbot/shoulda-matchers/contributors +[shoulda]: http://github.com/thoughtbot/shoulda +[shoulda-context]: http://github.com/thoughtbot/shoulda-context diff -Nru ruby-shoulda-matchers-1.0.0~beta2/README.rdoc ruby-shoulda-matchers-2.8.0/README.rdoc --- ruby-shoulda-matchers-1.0.0~beta2/README.rdoc 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/README.rdoc 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -= shoulda-matchers - -{Official Documentation}[http://rubydoc.info/github/thoughtbot/shoulda-matchers/master/frames] - -Test::Unit- and RSpec-compatible one-liners that test common Rails functionality. -These tests would otherwise be much longer, more complex, and error-prone. - -Refer to the {shoulda}[https://github.com/thoughtbot/shoulda] gem if you want to know more -about using shoulda with Test::Unit. - -=== ActiveRecord Matchers - -Matchers to test associations and validations: - - describe Post do - it { should belong_to(:user) } - it { should have_many(:tags).through(:taggings) } - - it { should validate_uniqueness_of(:title) } - it { should validate_presence_of(:body).with_message(/wtf/) } - it { should validate_presence_of(:title) } - it { should validate_numericality_of(:user_id) } - end - - describe User do - it { should have_many(:posts) } - - it { should_not allow_value("blah").for(:email) } - it { should allow_value("a@b.com").for(:email) } - it { should ensure_inclusion_of(:age).in_range(1..100) } - it { should_not allow_mass_assignment_of(:password) } - end - -=== ActionController Matchers - -Matchers to test common patterns: - - describe PostsController, "#show" do - context "for a fictional user" do - before do - get :show, :id => 1 - end - - it { should assign_to(:user) } - it { should respond_with(:success) } - it { should render_template(:show) } - it { should_not set_the_flash } - end - end - -= Installation - -In Rails 3 and Bundler, add the following to your Gemfile: - - group :test do - gem "shoulda-matchers" - gem "rspec-rails" - end - -Shoulda will automatically include matchers into the appropriate example groups. - -= Credits - -Shoulda is maintained and funded by {thoughtbot}[http://thoughtbot.com/community]. -Thank you to all the {contributors}[https://github.com/thoughtbot/shoulda-matchers/contributors]. - -= License - -Shoulda is Copyright © 2006-2010 thoughtbot, inc. -It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file. diff -Nru ruby-shoulda-matchers-1.0.0~beta2/script/install_gems_in_all_appraisals ruby-shoulda-matchers-2.8.0/script/install_gems_in_all_appraisals --- ruby-shoulda-matchers-1.0.0~beta2/script/install_gems_in_all_appraisals 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/script/install_gems_in_all_appraisals 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,14 @@ +#!/bin/bash + +SUPPORTED_VERSIONS=$( - - -
- - -
- - - - -
-

Getting started

-

Here’s how to get rolling:

- -
    -
  1. -

    Use rails generate to create your models and controllers

    -

    To see all available options, run it without parameters.

    -
  2. - -
  3. -

    Set up a default route and remove or rename this file

    -

    Routes are set up in config/routes.rb.

    -
  4. - -
  5. -

    Create your database

    -

    Run rake db:migrate to create your database. If you're not using SQLite (the default), edit config/database.yml with your username and password.

    -
  6. -
-
-
- - -
- - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/application.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/application.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/application.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/application.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -// Place your application-specific JavaScript functions and classes here -// This file is automatically included by javascript_include_tag :defaults diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/controls.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/controls.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/controls.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/controls.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,965 +0,0 @@ -// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 - -// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005-2009 Jon Tirsen (http://www.tirsen.com) -// Contributors: -// Richard Livsey -// Rahul Bhargava -// Rob Wills -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// Autocompleter.Base handles all the autocompletion functionality -// that's independent of the data source for autocompletion. This -// includes drawing the autocompletion menu, observing keyboard -// and mouse events, and similar. -// -// Specific autocompleters need to provide, at the very least, -// a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method -// should get the text for which to provide autocompletion by -// invoking this.getToken(), NOT by directly accessing -// this.element.value. This is to allow incremental tokenized -// autocompletion. Specific auto-completion logic (AJAX, etc) -// belongs in getUpdatedChoices. -// -// Tokenized incremental autocompletion is enabled automatically -// when an autocompleter is instantiated with the 'tokens' option -// in the options parameter, e.g.: -// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -// will incrementally autocomplete with a comma as the token. -// Additionally, ',' in the above example can be replaced with -// a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most -// useful when one of the tokens is \n (a newline), as it -// allows smart autocompletion after linebreaks. - -if(typeof Effect == 'undefined') - throw("controls.js requires including script.aculo.us' effects.js library"); - -var Autocompleter = { }; -Autocompleter.Base = Class.create({ - baseInitialize: function(element, update, options) { - element = $(element); - this.element = element; - this.update = $(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - this.oldElementValue = this.element.value; - - if(this.setOptions) - this.setOptions(options); - else - this.options = options || { }; - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || - function(element, update){ - if(!update.style.position || update.style.position=='absolute') { - update.style.position = 'absolute'; - Position.clone(element, update, { - setHeight: false, - offsetTop: element.offsetHeight - }); - } - Effect.Appear(update,{duration:0.15}); - }; - this.options.onHide = this.options.onHide || - function(element, update){ new Effect.Fade(update,{duration:0.15}) }; - - if(typeof(this.options.tokens) == 'string') - this.options.tokens = new Array(this.options.tokens); - // Force carriage returns as token delimiters anyway - if (!this.options.tokens.include('\n')) - this.options.tokens.push('\n'); - - this.observer = null; - - this.element.setAttribute('autocomplete','off'); - - Element.hide(this.update); - - Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); - Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); - }, - - show: function() { - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); - if(!this.iefix && - (Prototype.Browser.IE) && - (Element.getStyle(this.update, 'position')=='absolute')) { - new Insertion.After(this.update, - ''); - this.iefix = $(this.update.id+'_iefix'); - } - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); - }, - - fixIEOverlapping: function() { - Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - }, - - hide: function() { - this.stopIndicator(); - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); - if(this.iefix) Element.hide(this.iefix); - }, - - startIndicator: function() { - if(this.options.indicator) Element.show(this.options.indicator); - }, - - stopIndicator: function() { - if(this.options.indicator) Element.hide(this.options.indicator); - }, - - onKeyPress: function(event) { - if(this.active) - switch(event.keyCode) { - case Event.KEY_TAB: - case Event.KEY_RETURN: - this.selectEntry(); - Event.stop(event); - case Event.KEY_ESC: - this.hide(); - this.active = false; - Event.stop(event); - return; - case Event.KEY_LEFT: - case Event.KEY_RIGHT: - return; - case Event.KEY_UP: - this.markPrevious(); - this.render(); - Event.stop(event); - return; - case Event.KEY_DOWN: - this.markNext(); - this.render(); - Event.stop(event); - return; - } - else - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || - (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; - - this.changed = true; - this.hasFocus = true; - - if(this.observer) clearTimeout(this.observer); - this.observer = - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); - }, - - activate: function() { - this.changed = false; - this.hasFocus = true; - this.getUpdatedChoices(); - }, - - onHover: function(event) { - var element = Event.findElement(event, 'LI'); - if(this.index != element.autocompleteIndex) - { - this.index = element.autocompleteIndex; - this.render(); - } - Event.stop(event); - }, - - onClick: function(event) { - var element = Event.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - - onBlur: function(event) { - // needed to make click events working - setTimeout(this.hide.bind(this), 250); - this.hasFocus = false; - this.active = false; - }, - - render: function() { - if(this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) - this.index==i ? - Element.addClassName(this.getEntry(i),"selected") : - Element.removeClassName(this.getEntry(i),"selected"); - if(this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - - markPrevious: function() { - if(this.index > 0) this.index--; - else this.index = this.entryCount-1; - this.getEntry(this.index).scrollIntoView(true); - }, - - markNext: function() { - if(this.index < this.entryCount-1) this.index++; - else this.index = 0; - this.getEntry(this.index).scrollIntoView(false); - }, - - getEntry: function(index) { - return this.update.firstChild.childNodes[index]; - }, - - getCurrentEntry: function() { - return this.getEntry(this.index); - }, - - selectEntry: function() { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - - updateElement: function(selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = $(selectedElement).select('.' + this.options.select) || []; - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); - } else - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - - var bounds = this.getTokenBounds(); - if (bounds[0] != -1) { - var newValue = this.element.value.substr(0, bounds[0]); - var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = newValue + value + this.element.value.substr(bounds[1]); - } else { - this.element.value = value; - } - this.oldElementValue = this.element.value; - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - }, - - updateChoices: function(choices) { - if(!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - Element.cleanWhitespace(this.update); - Element.cleanWhitespace(this.update.down()); - - if(this.update.firstChild && this.update.down().childNodes) { - this.entryCount = - this.update.down().childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - this.index = 0; - - if(this.entryCount==1 && this.options.autoSelect) { - this.selectEntry(); - this.hide(); - } else { - this.render(); - } - } - }, - - addObservers: function(element) { - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); - Event.observe(element, "click", this.onClick.bindAsEventListener(this)); - }, - - onObserverEvent: function() { - this.changed = false; - this.tokenBounds = null; - if(this.getToken().length>=this.options.minChars) { - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - this.oldElementValue = this.element.value; - }, - - getToken: function() { - var bounds = this.getTokenBounds(); - return this.element.value.substring(bounds[0], bounds[1]).strip(); - }, - - getTokenBounds: function() { - if (null != this.tokenBounds) return this.tokenBounds; - var value = this.element.value; - if (value.strip().empty()) return [-1, 0]; - var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); - var offset = (diff == this.oldElementValue.length ? 1 : 0); - var prevTokenPos = -1, nextTokenPos = value.length; - var tp; - for (var index = 0, l = this.options.tokens.length; index < l; ++index) { - tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); - if (tp > prevTokenPos) prevTokenPos = tp; - tp = value.indexOf(this.options.tokens[index], diff + offset); - if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; - } - return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); - } -}); - -Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { - var boundary = Math.min(newS.length, oldS.length); - for (var index = 0; index < boundary; ++index) - if (newS[index] != oldS[index]) - return index; - return boundary; -}; - -Ajax.Autocompleter = Class.create(Autocompleter.Base, { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - this.startIndicator(); - - var entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(Autocompleter.Base, { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
  • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
  • "); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { - partial.push("
  • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
  • "); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); - return "
      " + ret.join('') + "
    "; - } - }, options || { }); - } -}); - -// AJAX in-place editor and collection editor -// Full rewrite by Christophe Porteneuve (April 2007). - -// Use this if you notice weird scrolling problems on some browsers, -// the DOM might be a bit confused when this gets called so do this -// waits 1 ms (with setTimeout) until it does the activation -Field.scrollFreeActivate = function(field) { - setTimeout(function() { - Field.activate(field); - }, 1); -}; - -Ajax.InPlaceEditor = Class.create({ - initialize: function(element, url, options) { - this.url = url; - this.element = element = $(element); - this.prepareOptions(); - this._controls = { }; - arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! - Object.extend(this.options, options || { }); - if (!this.options.formId && this.element.id) { - this.options.formId = this.element.id + '-inplaceeditor'; - if ($(this.options.formId)) - this.options.formId = ''; - } - if (this.options.externalControl) - this.options.externalControl = $(this.options.externalControl); - if (!this.options.externalControl) - this.options.externalControlOnly = false; - this._originalBackground = this.element.getStyle('background-color') || 'transparent'; - this.element.title = this.options.clickToEditText; - this._boundCancelHandler = this.handleFormCancellation.bind(this); - this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); - this._boundFailureHandler = this.handleAJAXFailure.bind(this); - this._boundSubmitHandler = this.handleFormSubmission.bind(this); - this._boundWrapperHandler = this.wrapUp.bind(this); - this.registerListeners(); - }, - checkForEscapeOrReturn: function(e) { - if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; - if (Event.KEY_ESC == e.keyCode) - this.handleFormCancellation(e); - else if (Event.KEY_RETURN == e.keyCode) - this.handleFormSubmission(e); - }, - createControl: function(mode, handler, extraClasses) { - var control = this.options[mode + 'Control']; - var text = this.options[mode + 'Text']; - if ('button' == control) { - var btn = document.createElement('input'); - btn.type = 'submit'; - btn.value = text; - btn.className = 'editor_' + mode + '_button'; - if ('cancel' == mode) - btn.onclick = this._boundCancelHandler; - this._form.appendChild(btn); - this._controls[mode] = btn; - } else if ('link' == control) { - var link = document.createElement('a'); - link.href = '#'; - link.appendChild(document.createTextNode(text)); - link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; - link.className = 'editor_' + mode + '_link'; - if (extraClasses) - link.className += ' ' + extraClasses; - this._form.appendChild(link); - this._controls[mode] = link; - } - }, - createEditField: function() { - var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); - var fld; - if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { - fld = document.createElement('input'); - fld.type = 'text'; - var size = this.options.size || this.options.cols || 0; - if (0 < size) fld.size = size; - } else { - fld = document.createElement('textarea'); - fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); - fld.cols = this.options.cols || 40; - } - fld.name = this.options.paramName; - fld.value = text; // No HTML breaks conversion anymore - fld.className = 'editor_field'; - if (this.options.submitOnBlur) - fld.onblur = this._boundSubmitHandler; - this._controls.editor = fld; - if (this.options.loadTextURL) - this.loadExternalText(); - this._form.appendChild(this._controls.editor); - }, - createForm: function() { - var ipe = this; - function addText(mode, condition) { - var text = ipe.options['text' + mode + 'Controls']; - if (!text || condition === false) return; - ipe._form.appendChild(document.createTextNode(text)); - }; - this._form = $(document.createElement('form')); - this._form.id = this.options.formId; - this._form.addClassName(this.options.formClassName); - this._form.onsubmit = this._boundSubmitHandler; - this.createEditField(); - if ('textarea' == this._controls.editor.tagName.toLowerCase()) - this._form.appendChild(document.createElement('br')); - if (this.options.onFormCustomization) - this.options.onFormCustomization(this, this._form); - addText('Before', this.options.okControl || this.options.cancelControl); - this.createControl('ok', this._boundSubmitHandler); - addText('Between', this.options.okControl && this.options.cancelControl); - this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); - addText('After', this.options.okControl || this.options.cancelControl); - }, - destroy: function() { - if (this._oldInnerHTML) - this.element.innerHTML = this._oldInnerHTML; - this.leaveEditMode(); - this.unregisterListeners(); - }, - enterEditMode: function(e) { - if (this._saving || this._editing) return; - this._editing = true; - this.triggerCallback('onEnterEditMode'); - if (this.options.externalControl) - this.options.externalControl.hide(); - this.element.hide(); - this.createForm(); - this.element.parentNode.insertBefore(this._form, this.element); - if (!this.options.loadTextURL) - this.postProcessEditField(); - if (e) Event.stop(e); - }, - enterHover: function(e) { - if (this.options.hoverClassName) - this.element.addClassName(this.options.hoverClassName); - if (this._saving) return; - this.triggerCallback('onEnterHover'); - }, - getText: function() { - return this.element.innerHTML.unescapeHTML(); - }, - handleAJAXFailure: function(transport) { - this.triggerCallback('onFailure', transport); - if (this._oldInnerHTML) { - this.element.innerHTML = this._oldInnerHTML; - this._oldInnerHTML = null; - } - }, - handleFormCancellation: function(e) { - this.wrapUp(); - if (e) Event.stop(e); - }, - handleFormSubmission: function(e) { - var form = this._form; - var value = $F(this._controls.editor); - this.prepareSubmission(); - var params = this.options.callback(form, value) || ''; - if (Object.isString(params)) - params = params.toQueryParams(); - params.editorId = this.element.id; - if (this.options.htmlResponse) { - var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); - Object.extend(options, { - parameters: params, - onComplete: this._boundWrapperHandler, - onFailure: this._boundFailureHandler - }); - new Ajax.Updater({ success: this.element }, this.url, options); - } else { - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: params, - onComplete: this._boundWrapperHandler, - onFailure: this._boundFailureHandler - }); - new Ajax.Request(this.url, options); - } - if (e) Event.stop(e); - }, - leaveEditMode: function() { - this.element.removeClassName(this.options.savingClassName); - this.removeForm(); - this.leaveHover(); - this.element.style.backgroundColor = this._originalBackground; - this.element.show(); - if (this.options.externalControl) - this.options.externalControl.show(); - this._saving = false; - this._editing = false; - this._oldInnerHTML = null; - this.triggerCallback('onLeaveEditMode'); - }, - leaveHover: function(e) { - if (this.options.hoverClassName) - this.element.removeClassName(this.options.hoverClassName); - if (this._saving) return; - this.triggerCallback('onLeaveHover'); - }, - loadExternalText: function() { - this._form.addClassName(this.options.loadingClassName); - this._controls.editor.disabled = true; - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - this._form.removeClassName(this.options.loadingClassName); - var text = transport.responseText; - if (this.options.stripLoadedTextTags) - text = text.stripTags(); - this._controls.editor.value = text; - this._controls.editor.disabled = false; - this.postProcessEditField(); - }.bind(this), - onFailure: this._boundFailureHandler - }); - new Ajax.Request(this.options.loadTextURL, options); - }, - postProcessEditField: function() { - var fpc = this.options.fieldPostCreation; - if (fpc) - $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); - }, - prepareOptions: function() { - this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); - Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); - [this._extraDefaultOptions].flatten().compact().each(function(defs) { - Object.extend(this.options, defs); - }.bind(this)); - }, - prepareSubmission: function() { - this._saving = true; - this.removeForm(); - this.leaveHover(); - this.showSaving(); - }, - registerListeners: function() { - this._listeners = { }; - var listener; - $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { - listener = this[pair.value].bind(this); - this._listeners[pair.key] = listener; - if (!this.options.externalControlOnly) - this.element.observe(pair.key, listener); - if (this.options.externalControl) - this.options.externalControl.observe(pair.key, listener); - }.bind(this)); - }, - removeForm: function() { - if (!this._form) return; - this._form.remove(); - this._form = null; - this._controls = { }; - }, - showSaving: function() { - this._oldInnerHTML = this.element.innerHTML; - this.element.innerHTML = this.options.savingText; - this.element.addClassName(this.options.savingClassName); - this.element.style.backgroundColor = this._originalBackground; - this.element.show(); - }, - triggerCallback: function(cbName, arg) { - if ('function' == typeof this.options[cbName]) { - this.options[cbName](this, arg); - } - }, - unregisterListeners: function() { - $H(this._listeners).each(function(pair) { - if (!this.options.externalControlOnly) - this.element.stopObserving(pair.key, pair.value); - if (this.options.externalControl) - this.options.externalControl.stopObserving(pair.key, pair.value); - }.bind(this)); - }, - wrapUp: function(transport) { - this.leaveEditMode(); - // Can't use triggerCallback due to backward compatibility: requires - // binding + direct element - this._boundComplete(transport, this.element); - } -}); - -Object.extend(Ajax.InPlaceEditor.prototype, { - dispose: Ajax.InPlaceEditor.prototype.destroy -}); - -Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { - initialize: function($super, element, url, options) { - this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; - $super(element, url, options); - }, - - createEditField: function() { - var list = document.createElement('select'); - list.name = this.options.paramName; - list.size = 1; - this._controls.editor = list; - this._collection = this.options.collection || []; - if (this.options.loadCollectionURL) - this.loadCollection(); - else - this.checkForExternalText(); - this._form.appendChild(this._controls.editor); - }, - - loadCollection: function() { - this._form.addClassName(this.options.loadingClassName); - this.showLoadingText(this.options.loadingCollectionText); - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - var js = transport.responseText.strip(); - if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check - throw('Server returned an invalid collection representation.'); - this._collection = eval(js); - this.checkForExternalText(); - }.bind(this), - onFailure: this.onFailure - }); - new Ajax.Request(this.options.loadCollectionURL, options); - }, - - showLoadingText: function(text) { - this._controls.editor.disabled = true; - var tempOption = this._controls.editor.firstChild; - if (!tempOption) { - tempOption = document.createElement('option'); - tempOption.value = ''; - this._controls.editor.appendChild(tempOption); - tempOption.selected = true; - } - tempOption.update((text || '').stripScripts().stripTags()); - }, - - checkForExternalText: function() { - this._text = this.getText(); - if (this.options.loadTextURL) - this.loadExternalText(); - else - this.buildOptionList(); - }, - - loadExternalText: function() { - this.showLoadingText(this.options.loadingText); - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - this._text = transport.responseText.strip(); - this.buildOptionList(); - }.bind(this), - onFailure: this.onFailure - }); - new Ajax.Request(this.options.loadTextURL, options); - }, - - buildOptionList: function() { - this._form.removeClassName(this.options.loadingClassName); - this._collection = this._collection.map(function(entry) { - return 2 === entry.length ? entry : [entry, entry].flatten(); - }); - var marker = ('value' in this.options) ? this.options.value : this._text; - var textFound = this._collection.any(function(entry) { - return entry[0] == marker; - }.bind(this)); - this._controls.editor.update(''); - var option; - this._collection.each(function(entry, index) { - option = document.createElement('option'); - option.value = entry[0]; - option.selected = textFound ? entry[0] == marker : 0 == index; - option.appendChild(document.createTextNode(entry[1])); - this._controls.editor.appendChild(option); - }.bind(this)); - this._controls.editor.disabled = false; - Field.scrollFreeActivate(this._controls.editor); - } -}); - -//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** -//**** This only exists for a while, in order to let **** -//**** users adapt to the new API. Read up on the new **** -//**** API and convert your code to it ASAP! **** - -Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { - if (!options) return; - function fallback(name, expr) { - if (name in options || expr === undefined) return; - options[name] = expr; - }; - fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : - options.cancelLink == options.cancelButton == false ? false : undefined))); - fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : - options.okLink == options.okButton == false ? false : undefined))); - fallback('highlightColor', options.highlightcolor); - fallback('highlightEndColor', options.highlightendcolor); -}; - -Object.extend(Ajax.InPlaceEditor, { - DefaultOptions: { - ajaxOptions: { }, - autoRows: 3, // Use when multi-line w/ rows == 1 - cancelControl: 'link', // 'link'|'button'|false - cancelText: 'cancel', - clickToEditText: 'Click to edit', - externalControl: null, // id|elt - externalControlOnly: false, - fieldPostCreation: 'activate', // 'activate'|'focus'|false - formClassName: 'inplaceeditor-form', - formId: null, // id|elt - highlightColor: '#ffff99', - highlightEndColor: '#ffffff', - hoverClassName: '', - htmlResponse: true, - loadingClassName: 'inplaceeditor-loading', - loadingText: 'Loading...', - okControl: 'button', // 'link'|'button'|false - okText: 'ok', - paramName: 'value', - rows: 1, // If 1 and multi-line, uses autoRows - savingClassName: 'inplaceeditor-saving', - savingText: 'Saving...', - size: 0, - stripLoadedTextTags: false, - submitOnBlur: false, - textAfterControls: '', - textBeforeControls: '', - textBetweenControls: '' - }, - DefaultCallbacks: { - callback: function(form) { - return Form.serialize(form); - }, - onComplete: function(transport, element) { - // For backward compatibility, this one is bound to the IPE, and passes - // the element directly. It was too often customized, so we don't break it. - new Effect.Highlight(element, { - startcolor: this.options.highlightColor, keepBackgroundImage: true }); - }, - onEnterEditMode: null, - onEnterHover: function(ipe) { - ipe.element.style.backgroundColor = ipe.options.highlightColor; - if (ipe._effect) - ipe._effect.cancel(); - }, - onFailure: function(transport, ipe) { - alert('Error communication with the server: ' + transport.responseText.stripTags()); - }, - onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. - onLeaveEditMode: null, - onLeaveHover: function(ipe) { - ipe._effect = new Effect.Highlight(ipe.element, { - startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, - restorecolor: ipe._originalBackground, keepBackgroundImage: true - }); - } - }, - Listeners: { - click: 'enterEditMode', - keydown: 'checkForEscapeOrReturn', - mouseover: 'enterHover', - mouseout: 'leaveHover' - } -}); - -Ajax.InPlaceCollectionEditor.DefaultOptions = { - loadingCollectionText: 'Loading options...' -}; - -// Delayed observer, like Form.Element.Observer, -// but waits for delay after last key input -// Ideal for live-search fields - -Form.Element.DelayedObserver = Class.create({ - initialize: function(element, delay, callback) { - this.delay = delay || 0.5; - this.element = $(element); - this.callback = callback; - this.timer = null; - this.lastValue = $F(this.element); - Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); - }, - delayedListener: function(event) { - if(this.lastValue == $F(this.element)) return; - if(this.timer) clearTimeout(this.timer); - this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); - this.lastValue = $F(this.element); - }, - onTimerEvent: function() { - this.timer = null; - this.callback(this.element, $F(this.element)); - } -}); \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/dragdrop.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/dragdrop.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/dragdrop.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/dragdrop.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,974 +0,0 @@ -// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 - -// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -if(Object.isUndefined(Effect)) - throw("dragdrop.js requires including script.aculo.us' effects.js library"); - -var Droppables = { - drops: [], - - remove: function(element) { - this.drops = this.drops.reject(function(d) { return d.element==$(element) }); - }, - - add: function(element) { - element = $(element); - var options = Object.extend({ - greedy: true, - hoverclass: null, - tree: false - }, arguments[1] || { }); - - // cache containers - if(options.containment) { - options._containers = []; - var containment = options.containment; - if(Object.isArray(containment)) { - containment.each( function(c) { options._containers.push($(c)) }); - } else { - options._containers.push($(containment)); - } - } - - if(options.accept) options.accept = [options.accept].flatten(); - - Element.makePositioned(element); // fix IE - options.element = element; - - this.drops.push(options); - }, - - findDeepestChild: function(drops) { - deepest = drops[0]; - - for (i = 1; i < drops.length; ++i) - if (Element.isParent(drops[i].element, deepest.element)) - deepest = drops[i]; - - return deepest; - }, - - isContained: function(element, drop) { - var containmentNode; - if(drop.tree) { - containmentNode = element.treeNode; - } else { - containmentNode = element.parentNode; - } - return drop._containers.detect(function(c) { return containmentNode == c }); - }, - - isAffected: function(point, element, drop) { - return ( - (drop.element!=element) && - ((!drop._containers) || - this.isContained(element, drop)) && - ((!drop.accept) || - (Element.classNames(element).detect( - function(v) { return drop.accept.include(v) } ) )) && - Position.within(drop.element, point[0], point[1]) ); - }, - - deactivate: function(drop) { - if(drop.hoverclass) - Element.removeClassName(drop.element, drop.hoverclass); - this.last_active = null; - }, - - activate: function(drop) { - if(drop.hoverclass) - Element.addClassName(drop.element, drop.hoverclass); - this.last_active = drop; - }, - - show: function(point, element) { - if(!this.drops.length) return; - var drop, affected = []; - - this.drops.each( function(drop) { - if(Droppables.isAffected(point, element, drop)) - affected.push(drop); - }); - - if(affected.length>0) - drop = Droppables.findDeepestChild(affected); - - if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); - if (drop) { - Position.within(drop.element, point[0], point[1]); - if(drop.onHover) - drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); - - if (drop != this.last_active) Droppables.activate(drop); - } - }, - - fire: function(event, element) { - if(!this.last_active) return; - Position.prepare(); - - if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) - if (this.last_active.onDrop) { - this.last_active.onDrop(element, this.last_active.element, event); - return true; - } - }, - - reset: function() { - if(this.last_active) - this.deactivate(this.last_active); - } -}; - -var Draggables = { - drags: [], - observers: [], - - register: function(draggable) { - if(this.drags.length == 0) { - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.updateDrag.bindAsEventListener(this); - this.eventKeypress = this.keyPress.bindAsEventListener(this); - - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - Event.observe(document, "keypress", this.eventKeypress); - } - this.drags.push(draggable); - }, - - unregister: function(draggable) { - this.drags = this.drags.reject(function(d) { return d==draggable }); - if(this.drags.length == 0) { - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - Event.stopObserving(document, "keypress", this.eventKeypress); - } - }, - - activate: function(draggable) { - if(draggable.options.delay) { - this._timeout = setTimeout(function() { - Draggables._timeout = null; - window.focus(); - Draggables.activeDraggable = draggable; - }.bind(this), draggable.options.delay); - } else { - window.focus(); // allows keypress events if window isn't currently focused, fails for Safari - this.activeDraggable = draggable; - } - }, - - deactivate: function() { - this.activeDraggable = null; - }, - - updateDrag: function(event) { - if(!this.activeDraggable) return; - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - // Mozilla-based browsers fire successive mousemove events with - // the same coordinates, prevent needless redrawing (moz bug?) - if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; - this._lastPointer = pointer; - - this.activeDraggable.updateDrag(event, pointer); - }, - - endDrag: function(event) { - if(this._timeout) { - clearTimeout(this._timeout); - this._timeout = null; - } - if(!this.activeDraggable) return; - this._lastPointer = null; - this.activeDraggable.endDrag(event); - this.activeDraggable = null; - }, - - keyPress: function(event) { - if(this.activeDraggable) - this.activeDraggable.keyPress(event); - }, - - addObserver: function(observer) { - this.observers.push(observer); - this._cacheObserverCallbacks(); - }, - - removeObserver: function(element) { // element instead of observer fixes mem leaks - this.observers = this.observers.reject( function(o) { return o.element==element }); - this._cacheObserverCallbacks(); - }, - - notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' - if(this[eventName+'Count'] > 0) - this.observers.each( function(o) { - if(o[eventName]) o[eventName](eventName, draggable, event); - }); - if(draggable.options[eventName]) draggable.options[eventName](draggable, event); - }, - - _cacheObserverCallbacks: function() { - ['onStart','onEnd','onDrag'].each( function(eventName) { - Draggables[eventName+'Count'] = Draggables.observers.select( - function(o) { return o[eventName]; } - ).length; - }); - } -}; - -/*--------------------------------------------------------------------------*/ - -var Draggable = Class.create({ - initialize: function(element) { - var defaults = { - handle: false, - reverteffect: function(element, top_offset, left_offset) { - var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; - new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, - queue: {scope:'_draggable', position:'end'} - }); - }, - endeffect: function(element) { - var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; - new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, - queue: {scope:'_draggable', position:'end'}, - afterFinish: function(){ - Draggable._dragging[element] = false - } - }); - }, - zindex: 1000, - revert: false, - quiet: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } - delay: 0 - }; - - if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) - Object.extend(defaults, { - starteffect: function(element) { - element._opacity = Element.getOpacity(element); - Draggable._dragging[element] = true; - new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); - } - }); - - var options = Object.extend(defaults, arguments[1] || { }); - - this.element = $(element); - - if(options.handle && Object.isString(options.handle)) - this.handle = this.element.down('.'+options.handle, 0); - - if(!this.handle) this.handle = $(options.handle); - if(!this.handle) this.handle = this.element; - - if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { - options.scroll = $(options.scroll); - this._isScrollChild = Element.childOf(this.element, options.scroll); - } - - Element.makePositioned(this.element); // fix IE - - this.options = options; - this.dragging = false; - - this.eventMouseDown = this.initDrag.bindAsEventListener(this); - Event.observe(this.handle, "mousedown", this.eventMouseDown); - - Draggables.register(this); - }, - - destroy: function() { - Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); - Draggables.unregister(this); - }, - - currentDelta: function() { - return([ - parseInt(Element.getStyle(this.element,'left') || '0'), - parseInt(Element.getStyle(this.element,'top') || '0')]); - }, - - initDrag: function(event) { - if(!Object.isUndefined(Draggable._dragging[this.element]) && - Draggable._dragging[this.element]) return; - if(Event.isLeftClick(event)) { - // abort on form elements, fixes a Firefox issue - var src = Event.element(event); - if((tag_name = src.tagName.toUpperCase()) && ( - tag_name=='INPUT' || - tag_name=='SELECT' || - tag_name=='OPTION' || - tag_name=='BUTTON' || - tag_name=='TEXTAREA')) return; - - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var pos = this.element.cumulativeOffset(); - this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); - - Draggables.activate(this); - Event.stop(event); - } - }, - - startDrag: function(event) { - this.dragging = true; - if(!this.delta) - this.delta = this.currentDelta(); - - if(this.options.zindex) { - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); - this.element.style.zIndex = this.options.zindex; - } - - if(this.options.ghosting) { - this._clone = this.element.cloneNode(true); - this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); - if (!this._originallyAbsolute) - Position.absolutize(this.element); - this.element.parentNode.insertBefore(this._clone, this.element); - } - - if(this.options.scroll) { - if (this.options.scroll == window) { - var where = this._getWindowScroll(this.options.scroll); - this.originalScrollLeft = where.left; - this.originalScrollTop = where.top; - } else { - this.originalScrollLeft = this.options.scroll.scrollLeft; - this.originalScrollTop = this.options.scroll.scrollTop; - } - } - - Draggables.notify('onStart', this, event); - - if(this.options.starteffect) this.options.starteffect(this.element); - }, - - updateDrag: function(event, pointer) { - if(!this.dragging) this.startDrag(event); - - if(!this.options.quiet){ - Position.prepare(); - Droppables.show(pointer, this.element); - } - - Draggables.notify('onDrag', this, event); - - this.draw(pointer); - if(this.options.change) this.options.change(this); - - if(this.options.scroll) { - this.stopScrolling(); - - var p; - if (this.options.scroll == window) { - with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } - } else { - p = Position.page(this.options.scroll); - p[0] += this.options.scroll.scrollLeft + Position.deltaX; - p[1] += this.options.scroll.scrollTop + Position.deltaY; - p.push(p[0]+this.options.scroll.offsetWidth); - p.push(p[1]+this.options.scroll.offsetHeight); - } - var speed = [0,0]; - if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); - if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); - if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); - if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); - this.startScrolling(speed); - } - - // fix AppleWebKit rendering - if(Prototype.Browser.WebKit) window.scrollBy(0,0); - - Event.stop(event); - }, - - finishDrag: function(event, success) { - this.dragging = false; - - if(this.options.quiet){ - Position.prepare(); - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - Droppables.show(pointer, this.element); - } - - if(this.options.ghosting) { - if (!this._originallyAbsolute) - Position.relativize(this.element); - delete this._originallyAbsolute; - Element.remove(this._clone); - this._clone = null; - } - - var dropped = false; - if(success) { - dropped = Droppables.fire(event, this.element); - if (!dropped) dropped = false; - } - if(dropped && this.options.onDropped) this.options.onDropped(this.element); - Draggables.notify('onEnd', this, event); - - var revert = this.options.revert; - if(revert && Object.isFunction(revert)) revert = revert(this.element); - - var d = this.currentDelta(); - if(revert && this.options.reverteffect) { - if (dropped == 0 || revert != 'failure') - this.options.reverteffect(this.element, - d[1]-this.delta[1], d[0]-this.delta[0]); - } else { - this.delta = d; - } - - if(this.options.zindex) - this.element.style.zIndex = this.originalZ; - - if(this.options.endeffect) - this.options.endeffect(this.element); - - Draggables.deactivate(this); - Droppables.reset(); - }, - - keyPress: function(event) { - if(event.keyCode!=Event.KEY_ESC) return; - this.finishDrag(event, false); - Event.stop(event); - }, - - endDrag: function(event) { - if(!this.dragging) return; - this.stopScrolling(); - this.finishDrag(event, true); - Event.stop(event); - }, - - draw: function(point) { - var pos = this.element.cumulativeOffset(); - if(this.options.ghosting) { - var r = Position.realOffset(this.element); - pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; - } - - var d = this.currentDelta(); - pos[0] -= d[0]; pos[1] -= d[1]; - - if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { - pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; - pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; - } - - var p = [0,1].map(function(i){ - return (point[i]-pos[i]-this.offset[i]) - }.bind(this)); - - if(this.options.snap) { - if(Object.isFunction(this.options.snap)) { - p = this.options.snap(p[0],p[1],this); - } else { - if(Object.isArray(this.options.snap)) { - p = p.map( function(v, i) { - return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); - } else { - p = p.map( function(v) { - return (v/this.options.snap).round()*this.options.snap }.bind(this)); - } - }} - - var style = this.element.style; - if((!this.options.constraint) || (this.options.constraint=='horizontal')) - style.left = p[0] + "px"; - if((!this.options.constraint) || (this.options.constraint=='vertical')) - style.top = p[1] + "px"; - - if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering - }, - - stopScrolling: function() { - if(this.scrollInterval) { - clearInterval(this.scrollInterval); - this.scrollInterval = null; - Draggables._lastScrollPointer = null; - } - }, - - startScrolling: function(speed) { - if(!(speed[0] || speed[1])) return; - this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; - this.lastScrolled = new Date(); - this.scrollInterval = setInterval(this.scroll.bind(this), 10); - }, - - scroll: function() { - var current = new Date(); - var delta = current - this.lastScrolled; - this.lastScrolled = current; - if(this.options.scroll == window) { - with (this._getWindowScroll(this.options.scroll)) { - if (this.scrollSpeed[0] || this.scrollSpeed[1]) { - var d = delta / 1000; - this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); - } - } - } else { - this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; - this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; - } - - Position.prepare(); - Droppables.show(Draggables._lastPointer, this.element); - Draggables.notify('onDrag', this); - if (this._isScrollChild) { - Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); - Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; - Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; - if (Draggables._lastScrollPointer[0] < 0) - Draggables._lastScrollPointer[0] = 0; - if (Draggables._lastScrollPointer[1] < 0) - Draggables._lastScrollPointer[1] = 0; - this.draw(Draggables._lastScrollPointer); - } - - if(this.options.change) this.options.change(this); - }, - - _getWindowScroll: function(w) { - var T, L, W, H; - with (w.document) { - if (w.document.documentElement && documentElement.scrollTop) { - T = documentElement.scrollTop; - L = documentElement.scrollLeft; - } else if (w.document.body) { - T = body.scrollTop; - L = body.scrollLeft; - } - if (w.innerWidth) { - W = w.innerWidth; - H = w.innerHeight; - } else if (w.document.documentElement && documentElement.clientWidth) { - W = documentElement.clientWidth; - H = documentElement.clientHeight; - } else { - W = body.offsetWidth; - H = body.offsetHeight; - } - } - return { top: T, left: L, width: W, height: H }; - } -}); - -Draggable._dragging = { }; - -/*--------------------------------------------------------------------------*/ - -var SortableObserver = Class.create({ - initialize: function(element, observer) { - this.element = $(element); - this.observer = observer; - this.lastValue = Sortable.serialize(this.element); - }, - - onStart: function() { - this.lastValue = Sortable.serialize(this.element); - }, - - onEnd: function() { - Sortable.unmark(); - if(this.lastValue != Sortable.serialize(this.element)) - this.observer(this.element) - } -}); - -var Sortable = { - SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, - - sortables: { }, - - _findRootElement: function(element) { - while (element.tagName.toUpperCase() != "BODY") { - if(element.id && Sortable.sortables[element.id]) return element; - element = element.parentNode; - } - }, - - options: function(element) { - element = Sortable._findRootElement($(element)); - if(!element) return; - return Sortable.sortables[element.id]; - }, - - destroy: function(element){ - element = $(element); - var s = Sortable.sortables[element.id]; - - if(s) { - Draggables.removeObserver(s.element); - s.droppables.each(function(d){ Droppables.remove(d) }); - s.draggables.invoke('destroy'); - - delete Sortable.sortables[s.element.id]; - } - }, - - create: function(element) { - element = $(element); - var options = Object.extend({ - element: element, - tag: 'li', // assumes li children, override with tag: 'tagname' - dropOnEmpty: false, - tree: false, - treeTag: 'ul', - overlap: 'vertical', // one of 'vertical', 'horizontal' - constraint: 'vertical', // one of 'vertical', 'horizontal', false - containment: element, // also takes array of elements (or id's); or false - handle: false, // or a CSS class - only: false, - delay: 0, - hoverclass: null, - ghosting: false, - quiet: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - format: this.SERIALIZE_RULE, - - // these take arrays of elements or ids and can be - // used for better initialization performance - elements: false, - handles: false, - - onChange: Prototype.emptyFunction, - onUpdate: Prototype.emptyFunction - }, arguments[1] || { }); - - // clear any old sortable with same element - this.destroy(element); - - // build options for the draggables - var options_for_draggable = { - revert: true, - quiet: options.quiet, - scroll: options.scroll, - scrollSpeed: options.scrollSpeed, - scrollSensitivity: options.scrollSensitivity, - delay: options.delay, - ghosting: options.ghosting, - constraint: options.constraint, - handle: options.handle }; - - if(options.starteffect) - options_for_draggable.starteffect = options.starteffect; - - if(options.reverteffect) - options_for_draggable.reverteffect = options.reverteffect; - else - if(options.ghosting) options_for_draggable.reverteffect = function(element) { - element.style.top = 0; - element.style.left = 0; - }; - - if(options.endeffect) - options_for_draggable.endeffect = options.endeffect; - - if(options.zindex) - options_for_draggable.zindex = options.zindex; - - // build options for the droppables - var options_for_droppable = { - overlap: options.overlap, - containment: options.containment, - tree: options.tree, - hoverclass: options.hoverclass, - onHover: Sortable.onHover - }; - - var options_for_tree = { - onHover: Sortable.onEmptyHover, - overlap: options.overlap, - containment: options.containment, - hoverclass: options.hoverclass - }; - - // fix for gecko engine - Element.cleanWhitespace(element); - - options.draggables = []; - options.droppables = []; - - // drop on empty handling - if(options.dropOnEmpty || options.tree) { - Droppables.add(element, options_for_tree); - options.droppables.push(element); - } - - (options.elements || this.findElements(element, options) || []).each( function(e,i) { - var handle = options.handles ? $(options.handles[i]) : - (options.handle ? $(e).select('.' + options.handle)[0] : e); - options.draggables.push( - new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); - Droppables.add(e, options_for_droppable); - if(options.tree) e.treeNode = element; - options.droppables.push(e); - }); - - if(options.tree) { - (Sortable.findTreeElements(element, options) || []).each( function(e) { - Droppables.add(e, options_for_tree); - e.treeNode = element; - options.droppables.push(e); - }); - } - - // keep reference - this.sortables[element.identify()] = options; - - // for onupdate - Draggables.addObserver(new SortableObserver(element, options.onUpdate)); - - }, - - // return all suitable-for-sortable elements in a guaranteed order - findElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.tag); - }, - - findTreeElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.treeTag); - }, - - onHover: function(element, dropon, overlap) { - if(Element.isParent(dropon, element)) return; - - if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { - return; - } else if(overlap>0.5) { - Sortable.mark(dropon, 'before'); - if(dropon.previousSibling != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, dropon); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } else { - Sortable.mark(dropon, 'after'); - var nextElement = dropon.nextSibling || null; - if(nextElement != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, nextElement); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } - }, - - onEmptyHover: function(element, dropon, overlap) { - var oldParentNode = element.parentNode; - var droponOptions = Sortable.options(dropon); - - if(!Element.isParent(dropon, element)) { - var index; - - var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); - var child = null; - - if(children) { - var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); - - for (index = 0; index < children.length; index += 1) { - if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { - offset -= Element.offsetSize (children[index], droponOptions.overlap); - } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { - child = index + 1 < children.length ? children[index + 1] : null; - break; - } else { - child = children[index]; - break; - } - } - } - - dropon.insertBefore(element, child); - - Sortable.options(oldParentNode).onChange(element); - droponOptions.onChange(element); - } - }, - - unmark: function() { - if(Sortable._marker) Sortable._marker.hide(); - }, - - mark: function(dropon, position) { - // mark on ghosting only - var sortable = Sortable.options(dropon.parentNode); - if(sortable && !sortable.ghosting) return; - - if(!Sortable._marker) { - Sortable._marker = - ($('dropmarker') || Element.extend(document.createElement('DIV'))). - hide().addClassName('dropmarker').setStyle({position:'absolute'}); - document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); - } - var offsets = dropon.cumulativeOffset(); - Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); - - if(position=='after') - if(sortable.overlap == 'horizontal') - Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); - else - Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); - - Sortable._marker.show(); - }, - - _tree: function(element, options, parent) { - var children = Sortable.findElements(element, options) || []; - - for (var i = 0; i < children.length; ++i) { - var match = children[i].id.match(options.format); - - if (!match) continue; - - var child = { - id: encodeURIComponent(match ? match[1] : null), - element: element, - parent: parent, - children: [], - position: parent.children.length, - container: $(children[i]).down(options.treeTag) - }; - - /* Get the element containing the children and recurse over it */ - if (child.container) - this._tree(child.container, options, child); - - parent.children.push (child); - } - - return parent; - }, - - tree: function(element) { - element = $(element); - var sortableOptions = this.options(element); - var options = Object.extend({ - tag: sortableOptions.tag, - treeTag: sortableOptions.treeTag, - only: sortableOptions.only, - name: element.id, - format: sortableOptions.format - }, arguments[1] || { }); - - var root = { - id: null, - parent: null, - children: [], - container: element, - position: 0 - }; - - return Sortable._tree(element, options, root); - }, - - /* Construct a [i] index for a particular node */ - _constructIndex: function(node) { - var index = ''; - do { - if (node.id) index = '[' + node.position + ']' + index; - } while ((node = node.parent) != null); - return index; - }, - - sequence: function(element) { - element = $(element); - var options = Object.extend(this.options(element), arguments[1] || { }); - - return $(this.findElements(element, options) || []).map( function(item) { - return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; - }); - }, - - setSequence: function(element, new_sequence) { - element = $(element); - var options = Object.extend(this.options(element), arguments[2] || { }); - - var nodeMap = { }; - this.findElements(element, options).each( function(n) { - if (n.id.match(options.format)) - nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; - n.parentNode.removeChild(n); - }); - - new_sequence.each(function(ident) { - var n = nodeMap[ident]; - if (n) { - n[1].appendChild(n[0]); - delete nodeMap[ident]; - } - }); - }, - - serialize: function(element) { - element = $(element); - var options = Object.extend(Sortable.options(element), arguments[1] || { }); - var name = encodeURIComponent( - (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); - - if (options.tree) { - return Sortable.tree(element, arguments[1]).children.map( function (item) { - return [name + Sortable._constructIndex(item) + "[id]=" + - encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); - }).flatten().join('&'); - } else { - return Sortable.sequence(element, arguments[1]).map( function(item) { - return name + "[]=" + encodeURIComponent(item); - }).join('&'); - } - } -}; - -// Returns true if child is contained within element -Element.isParent = function(child, element) { - if (!child.parentNode || child == element) return false; - if (child.parentNode == element) return true; - return Element.isParent(child.parentNode, element); -}; - -Element.findChildren = function(element, only, recursive, tagName) { - if(!element.hasChildNodes()) return null; - tagName = tagName.toUpperCase(); - if(only) only = [only].flatten(); - var elements = []; - $A(element.childNodes).each( function(e) { - if(e.tagName && e.tagName.toUpperCase()==tagName && - (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) - elements.push(e); - if(recursive) { - var grandchildren = Element.findChildren(e, only, recursive, tagName); - if(grandchildren) elements.push(grandchildren); - } - }); - - return (elements.length>0 ? elements.flatten() : []); -}; - -Element.offsetSize = function (element, type) { - return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; -}; \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/effects.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/effects.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/effects.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/effects.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,1123 +0,0 @@ -// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 - -// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// Contributors: -// Justin Palmer (http://encytemedia.com/) -// Mark Pilgrim (http://diveintomark.org/) -// Martin Bialasinki -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// converts rgb() and #xxx to #xxxxxx format, -// returns self (or first argument) if not convertable -String.prototype.parseColor = function() { - var color = '#'; - if (this.slice(0,4) == 'rgb(') { - var cols = this.slice(4,this.length-1).split(','); - var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); - } else { - if (this.slice(0,1) == '#') { - if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); - if (this.length==7) color = this.toLowerCase(); - } - } - return (color.length==7 ? color : (arguments[0] || this)); -}; - -/*--------------------------------------------------------------------------*/ - -Element.collectTextNodes = function(element) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); - }).flatten().join(''); -}; - -Element.collectTextNodesIgnoreClass = function(element, className) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? - Element.collectTextNodesIgnoreClass(node, className) : '')); - }).flatten().join(''); -}; - -Element.setContentZoom = function(element, percent) { - element = $(element); - element.setStyle({fontSize: (percent/100) + 'em'}); - if (Prototype.Browser.WebKit) window.scrollBy(0,0); - return element; -}; - -Element.getInlineOpacity = function(element){ - return $(element).style.opacity || ''; -}; - -Element.forceRerendering = function(element) { - try { - element = $(element); - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch(e) { } -}; - -/*--------------------------------------------------------------------------*/ - -var Effect = { - _elementDoesNotExistError: { - name: 'ElementDoesNotExistError', - message: 'The specified DOM element does not exist, but is required for this effect to operate' - }, - Transitions: { - linear: Prototype.K, - sinoidal: function(pos) { - return (-Math.cos(pos*Math.PI)/2) + .5; - }, - reverse: function(pos) { - return 1-pos; - }, - flicker: function(pos) { - var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; - return pos > 1 ? 1 : pos; - }, - wobble: function(pos) { - return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; - }, - pulse: function(pos, pulses) { - return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; - }, - spring: function(pos) { - return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); - }, - none: function(pos) { - return 0; - }, - full: function(pos) { - return 1; - } - }, - DefaultOptions: { - duration: 1.0, // seconds - fps: 100, // 100= assume 66fps max. - sync: false, // true for combining - from: 0.0, - to: 1.0, - delay: 0.0, - queue: 'parallel' - }, - tagifyText: function(element) { - var tagifyStyle = 'position:relative'; - if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; - - element = $(element); - $A(element.childNodes).each( function(child) { - if (child.nodeType==3) { - child.nodeValue.toArray().each( function(character) { - element.insertBefore( - new Element('span', {style: tagifyStyle}).update( - character == ' ' ? String.fromCharCode(160) : character), - child); - }); - Element.remove(child); - } - }); - }, - multiple: function(element, effect) { - var elements; - if (((typeof element == 'object') || - Object.isFunction(element)) && - (element.length)) - elements = element; - else - elements = $(element).childNodes; - - var options = Object.extend({ - speed: 0.1, - delay: 0.0 - }, arguments[2] || { }); - var masterDelay = options.delay; - - $A(elements).each( function(element, index) { - new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); - }); - }, - PAIRS: { - 'slide': ['SlideDown','SlideUp'], - 'blind': ['BlindDown','BlindUp'], - 'appear': ['Appear','Fade'] - }, - toggle: function(element, effect, options) { - element = $(element); - effect = (effect || 'appear').toLowerCase(); - - return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({ - queue: { position:'end', scope:(element.id || 'global'), limit: 1 } - }, options || {})); - } -}; - -Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; - -/* ------------- core effects ------------- */ - -Effect.ScopedQueue = Class.create(Enumerable, { - initialize: function() { - this.effects = []; - this.interval = null; - }, - _each: function(iterator) { - this.effects._each(iterator); - }, - add: function(effect) { - var timestamp = new Date().getTime(); - - var position = Object.isString(effect.options.queue) ? - effect.options.queue : effect.options.queue.position; - - switch(position) { - case 'front': - // move unstarted effects after this effect - this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { - e.startOn += effect.finishOn; - e.finishOn += effect.finishOn; - }); - break; - case 'with-last': - timestamp = this.effects.pluck('startOn').max() || timestamp; - break; - case 'end': - // start effect after last queued effect has finished - timestamp = this.effects.pluck('finishOn').max() || timestamp; - break; - } - - effect.startOn += timestamp; - effect.finishOn += timestamp; - - if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) - this.effects.push(effect); - - if (!this.interval) - this.interval = setInterval(this.loop.bind(this), 15); - }, - remove: function(effect) { - this.effects = this.effects.reject(function(e) { return e==effect }); - if (this.effects.length == 0) { - clearInterval(this.interval); - this.interval = null; - } - }, - loop: function() { - var timePos = new Date().getTime(); - for(var i=0, len=this.effects.length;i= this.startOn) { - if (timePos >= this.finishOn) { - this.render(1.0); - this.cancel(); - this.event('beforeFinish'); - if (this.finish) this.finish(); - this.event('afterFinish'); - return; - } - var pos = (timePos - this.startOn) / this.totalTime, - frame = (pos * this.totalFrames).round(); - if (frame > this.currentFrame) { - this.render(pos); - this.currentFrame = frame; - } - } - }, - cancel: function() { - if (!this.options.sync) - Effect.Queues.get(Object.isString(this.options.queue) ? - 'global' : this.options.queue.scope).remove(this); - this.state = 'finished'; - }, - event: function(eventName) { - if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); - if (this.options[eventName]) this.options[eventName](this); - }, - inspect: function() { - var data = $H(); - for(property in this) - if (!Object.isFunction(this[property])) data.set(property, this[property]); - return '#'; - } -}); - -Effect.Parallel = Class.create(Effect.Base, { - initialize: function(effects) { - this.effects = effects || []; - this.start(arguments[1]); - }, - update: function(position) { - this.effects.invoke('render', position); - }, - finish: function(position) { - this.effects.each( function(effect) { - effect.render(1.0); - effect.cancel(); - effect.event('beforeFinish'); - if (effect.finish) effect.finish(position); - effect.event('afterFinish'); - }); - } -}); - -Effect.Tween = Class.create(Effect.Base, { - initialize: function(object, from, to) { - object = Object.isString(object) ? $(object) : object; - var args = $A(arguments), method = args.last(), - options = args.length == 5 ? args[3] : null; - this.method = Object.isFunction(method) ? method.bind(object) : - Object.isFunction(object[method]) ? object[method].bind(object) : - function(value) { object[method] = value }; - this.start(Object.extend({ from: from, to: to }, options || { })); - }, - update: function(position) { - this.method(position); - } -}); - -Effect.Event = Class.create(Effect.Base, { - initialize: function() { - this.start(Object.extend({ duration: 0 }, arguments[0] || { })); - }, - update: Prototype.emptyFunction -}); - -Effect.Opacity = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - // make this work on IE on elements without 'layout' - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - var options = Object.extend({ - from: this.element.getOpacity() || 0.0, - to: 1.0 - }, arguments[1] || { }); - this.start(options); - }, - update: function(position) { - this.element.setOpacity(position); - } -}); - -Effect.Move = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - x: 0, - y: 0, - mode: 'relative' - }, arguments[1] || { }); - this.start(options); - }, - setup: function() { - this.element.makePositioned(); - this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); - this.originalTop = parseFloat(this.element.getStyle('top') || '0'); - if (this.options.mode == 'absolute') { - this.options.x = this.options.x - this.originalLeft; - this.options.y = this.options.y - this.originalTop; - } - }, - update: function(position) { - this.element.setStyle({ - left: (this.options.x * position + this.originalLeft).round() + 'px', - top: (this.options.y * position + this.originalTop).round() + 'px' - }); - } -}); - -// for backwards compatibility -Effect.MoveBy = function(element, toTop, toLeft) { - return new Effect.Move(element, - Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); -}; - -Effect.Scale = Class.create(Effect.Base, { - initialize: function(element, percent) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - scaleX: true, - scaleY: true, - scaleContent: true, - scaleFromCenter: false, - scaleMode: 'box', // 'box' or 'contents' or { } with provided values - scaleFrom: 100.0, - scaleTo: percent - }, arguments[2] || { }); - this.start(options); - }, - setup: function() { - this.restoreAfterFinish = this.options.restoreAfterFinish || false; - this.elementPositioning = this.element.getStyle('position'); - - this.originalStyle = { }; - ['top','left','width','height','fontSize'].each( function(k) { - this.originalStyle[k] = this.element.style[k]; - }.bind(this)); - - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; - - var fontSize = this.element.getStyle('font-size') || '100%'; - ['em','px','%','pt'].each( function(fontSizeType) { - if (fontSize.indexOf(fontSizeType)>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = fontSizeType; - } - }.bind(this)); - - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - - this.dims = null; - if (this.options.scaleMode=='box') - this.dims = [this.element.offsetHeight, this.element.offsetWidth]; - if (/^content/.test(this.options.scaleMode)) - this.dims = [this.element.scrollHeight, this.element.scrollWidth]; - if (!this.dims) - this.dims = [this.options.scaleMode.originalHeight, - this.options.scaleMode.originalWidth]; - }, - update: function(position) { - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); - if (this.options.scaleContent && this.fontSize) - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); - }, - finish: function(position) { - if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); - }, - setDimensions: function(height, width) { - var d = { }; - if (this.options.scaleX) d.width = width.round() + 'px'; - if (this.options.scaleY) d.height = height.round() + 'px'; - if (this.options.scaleFromCenter) { - var topd = (height - this.dims[0])/2; - var leftd = (width - this.dims[1])/2; - if (this.elementPositioning == 'absolute') { - if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; - if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; - } else { - if (this.options.scaleY) d.top = -topd + 'px'; - if (this.options.scaleX) d.left = -leftd + 'px'; - } - } - this.element.setStyle(d); - } -}); - -Effect.Highlight = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); - this.start(options); - }, - setup: function() { - // Prevent executing on elements not in the layout flow - if (this.element.getStyle('display')=='none') { this.cancel(); return; } - // Disable background image during the effect - this.oldStyle = { }; - if (!this.options.keepBackgroundImage) { - this.oldStyle.backgroundImage = this.element.getStyle('background-image'); - this.element.setStyle({backgroundImage: 'none'}); - } - if (!this.options.endcolor) - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); - if (!this.options.restorecolor) - this.options.restorecolor = this.element.getStyle('background-color'); - // init color calculations - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); - }, - update: function(position) { - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ - return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); - }, - finish: function() { - this.element.setStyle(Object.extend(this.oldStyle, { - backgroundColor: this.options.restorecolor - })); - } -}); - -Effect.ScrollTo = function(element) { - var options = arguments[1] || { }, - scrollOffsets = document.viewport.getScrollOffsets(), - elementOffsets = $(element).cumulativeOffset(); - - if (options.offset) elementOffsets[1] += options.offset; - - return new Effect.Tween(null, - scrollOffsets.top, - elementOffsets[1], - options, - function(p){ scrollTo(scrollOffsets.left, p.round()); } - ); -}; - -/* ------------- combination effects ------------- */ - -Effect.Fade = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - var options = Object.extend({ - from: element.getOpacity() || 1.0, - to: 0.0, - afterFinishInternal: function(effect) { - if (effect.options.to!=0) return; - effect.element.hide().setStyle({opacity: oldOpacity}); - } - }, arguments[1] || { }); - return new Effect.Opacity(element,options); -}; - -Effect.Appear = function(element) { - element = $(element); - var options = Object.extend({ - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), - to: 1.0, - // force Safari to render floated elements properly - afterFinishInternal: function(effect) { - effect.element.forceRerendering(); - }, - beforeSetup: function(effect) { - effect.element.setOpacity(effect.options.from).show(); - }}, arguments[1] || { }); - return new Effect.Opacity(element,options); -}; - -Effect.Puff = function(element) { - element = $(element); - var oldStyle = { - opacity: element.getInlineOpacity(), - position: element.getStyle('position'), - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height - }; - return new Effect.Parallel( - [ new Effect.Scale(element, 200, - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], - Object.extend({ duration: 1.0, - beforeSetupInternal: function(effect) { - Position.absolutize(effect.effects[0].element); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().setStyle(oldStyle); } - }, arguments[1] || { }) - ); -}; - -Effect.BlindUp = function(element) { - element = $(element); - element.makeClipping(); - return new Effect.Scale(element, 0, - Object.extend({ scaleContent: false, - scaleX: false, - restoreAfterFinish: true, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }, arguments[1] || { }) - ); -}; - -Effect.BlindDown = function(element) { - element = $(element); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: 0, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - } - }, arguments[1] || { })); -}; - -Effect.SwitchOff = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - return new Effect.Appear(element, Object.extend({ - duration: 0.4, - from: 0, - transition: Effect.Transitions.flicker, - afterFinishInternal: function(effect) { - new Effect.Scale(effect.element, 1, { - duration: 0.3, scaleFromCenter: true, - scaleX: false, scaleContent: false, restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); - } - }); - } - }, arguments[1] || { })); -}; - -Effect.DropOut = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left'), - opacity: element.getInlineOpacity() }; - return new Effect.Parallel( - [ new Effect.Move(element, {x: 0, y: 100, sync: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 }) ], - Object.extend( - { duration: 0.5, - beforeSetup: function(effect) { - effect.effects[0].element.makePositioned(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); - } - }, arguments[1] || { })); -}; - -Effect.Shake = function(element) { - element = $(element); - var options = Object.extend({ - distance: 20, - duration: 0.5 - }, arguments[1] || {}); - var distance = parseFloat(options.distance); - var split = parseFloat(options.duration) / 10.0; - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left') }; - return new Effect.Move(element, - { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { - effect.element.undoPositioned().setStyle(oldStyle); - }}); }}); }}); }}); }}); }}); -}; - -Effect.SlideDown = function(element) { - element = $(element).cleanWhitespace(); - // SlideDown need to have the content of the element wrapped in a container element with fixed height! - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: window.opera ? 0 : 1, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if (window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || { }) - ); -}; - -Effect.SlideUp = function(element) { - element = $(element).cleanWhitespace(); - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, window.opera ? 0 : 1, - Object.extend({ scaleContent: false, - scaleX: false, - scaleMode: 'box', - scaleFrom: 100, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if (window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); - } - }, arguments[1] || { }) - ); -}; - -// Bug in opera makes the TD containing this element expand for a instance after finish -Effect.Squish = function(element) { - return new Effect.Scale(element, window.opera ? 1 : 0, { - restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }); -}; - -Effect.Grow = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.full - }, arguments[1] || { }); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var initialMoveX, initialMoveY; - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - initialMoveX = initialMoveY = moveX = moveY = 0; - break; - case 'top-right': - initialMoveX = dims.width; - initialMoveY = moveY = 0; - moveX = -dims.width; - break; - case 'bottom-left': - initialMoveX = moveX = 0; - initialMoveY = dims.height; - moveY = -dims.height; - break; - case 'bottom-right': - initialMoveX = dims.width; - initialMoveY = dims.height; - moveX = -dims.width; - moveY = -dims.height; - break; - case 'center': - initialMoveX = dims.width / 2; - initialMoveY = dims.height / 2; - moveX = -dims.width / 2; - moveY = -dims.height / 2; - break; - } - - return new Effect.Move(element, { - x: initialMoveX, - y: initialMoveY, - duration: 0.01, - beforeSetup: function(effect) { - effect.element.hide().makeClipping().makePositioned(); - }, - afterFinishInternal: function(effect) { - new Effect.Parallel( - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), - new Effect.Scale(effect.element, 100, { - scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) - ], Object.extend({ - beforeSetup: function(effect) { - effect.effects[0].element.setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); - } - }, options) - ); - } - }); -}; - -Effect.Shrink = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.none - }, arguments[1] || { }); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - moveX = moveY = 0; - break; - case 'top-right': - moveX = dims.width; - moveY = 0; - break; - case 'bottom-left': - moveX = 0; - moveY = dims.height; - break; - case 'bottom-right': - moveX = dims.width; - moveY = dims.height; - break; - case 'center': - moveX = dims.width / 2; - moveY = dims.height / 2; - break; - } - - return new Effect.Parallel( - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) - ], Object.extend({ - beforeStartInternal: function(effect) { - effect.effects[0].element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } - }, options) - ); -}; - -Effect.Pulsate = function(element) { - element = $(element); - var options = arguments[1] || { }, - oldOpacity = element.getInlineOpacity(), - transition = options.transition || Effect.Transitions.linear, - reverser = function(pos){ - return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); - }; - - return new Effect.Opacity(element, - Object.extend(Object.extend({ duration: 2.0, from: 0, - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } - }, options), {transition: reverser})); -}; - -Effect.Fold = function(element) { - element = $(element); - var oldStyle = { - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height }; - element.makeClipping(); - return new Effect.Scale(element, 5, Object.extend({ - scaleContent: false, - scaleX: false, - afterFinishInternal: function(effect) { - new Effect.Scale(element, 1, { - scaleContent: false, - scaleY: false, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().setStyle(oldStyle); - } }); - }}, arguments[1] || { })); -}; - -Effect.Morph = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - style: { } - }, arguments[1] || { }); - - if (!Object.isString(options.style)) this.style = $H(options.style); - else { - if (options.style.include(':')) - this.style = options.style.parseStyle(); - else { - this.element.addClassName(options.style); - this.style = $H(this.element.getStyles()); - this.element.removeClassName(options.style); - var css = this.element.getStyles(); - this.style = this.style.reject(function(style) { - return style.value == css[style.key]; - }); - options.afterFinishInternal = function(effect) { - effect.element.addClassName(effect.options.style); - effect.transforms.each(function(transform) { - effect.element.style[transform.style] = ''; - }); - }; - } - } - this.start(options); - }, - - setup: function(){ - function parseColor(color){ - if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; - color = color.parseColor(); - return $R(0,2).map(function(i){ - return parseInt( color.slice(i*2+1,i*2+3), 16 ); - }); - } - this.transforms = this.style.map(function(pair){ - var property = pair[0], value = pair[1], unit = null; - - if (value.parseColor('#zzzzzz') != '#zzzzzz') { - value = value.parseColor(); - unit = 'color'; - } else if (property == 'opacity') { - value = parseFloat(value); - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - } else if (Element.CSS_LENGTH.test(value)) { - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); - value = parseFloat(components[1]); - unit = (components.length == 3) ? components[2] : null; - } - - var originalValue = this.element.getStyle(property); - return { - style: property.camelize(), - originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), - targetValue: unit=='color' ? parseColor(value) : value, - unit: unit - }; - }.bind(this)).reject(function(transform){ - return ( - (transform.originalValue == transform.targetValue) || - ( - transform.unit != 'color' && - (isNaN(transform.originalValue) || isNaN(transform.targetValue)) - ) - ); - }); - }, - update: function(position) { - var style = { }, transform, i = this.transforms.length; - while(i--) - style[(transform = this.transforms[i]).style] = - transform.unit=='color' ? '#'+ - (Math.round(transform.originalValue[0]+ - (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + - (Math.round(transform.originalValue[1]+ - (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + - (Math.round(transform.originalValue[2]+ - (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : - (transform.originalValue + - (transform.targetValue - transform.originalValue) * position).toFixed(3) + - (transform.unit === null ? '' : transform.unit); - this.element.setStyle(style, true); - } -}); - -Effect.Transform = Class.create({ - initialize: function(tracks){ - this.tracks = []; - this.options = arguments[1] || { }; - this.addTracks(tracks); - }, - addTracks: function(tracks){ - tracks.each(function(track){ - track = $H(track); - var data = track.values().first(); - this.tracks.push($H({ - ids: track.keys().first(), - effect: Effect.Morph, - options: { style: data } - })); - }.bind(this)); - return this; - }, - play: function(){ - return new Effect.Parallel( - this.tracks.map(function(track){ - var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); - var elements = [$(ids) || $$(ids)].flatten(); - return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); - }).flatten(), - this.options - ); - } -}); - -Element.CSS_PROPERTIES = $w( - 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + - 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + - 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + - 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + - 'fontSize fontWeight height left letterSpacing lineHeight ' + - 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ - 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + - 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + - 'right textIndent top width wordSpacing zIndex'); - -Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; - -String.__parseStyleElement = document.createElement('div'); -String.prototype.parseStyle = function(){ - var style, styleRules = $H(); - if (Prototype.Browser.WebKit) - style = new Element('div',{style:this}).style; - else { - String.__parseStyleElement.innerHTML = '
    '; - style = String.__parseStyleElement.childNodes[0].style; - } - - Element.CSS_PROPERTIES.each(function(property){ - if (style[property]) styleRules.set(property, style[property]); - }); - - if (Prototype.Browser.IE && this.include('opacity')) - styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); - - return styleRules; -}; - -if (document.defaultView && document.defaultView.getComputedStyle) { - Element.getStyles = function(element) { - var css = document.defaultView.getComputedStyle($(element), null); - return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { - styles[property] = css[property]; - return styles; - }); - }; -} else { - Element.getStyles = function(element) { - element = $(element); - var css = element.currentStyle, styles; - styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { - results[property] = css[property]; - return results; - }); - if (!styles.opacity) styles.opacity = element.getOpacity(); - return styles; - }; -} - -Effect.Methods = { - morph: function(element, style) { - element = $(element); - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); - return element; - }, - visualEffect: function(element, effect, options) { - element = $(element); - var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); - new Effect[klass](element, options); - return element; - }, - highlight: function(element, options) { - element = $(element); - new Effect.Highlight(element, options); - return element; - } -}; - -$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ - 'pulsate shake puff squish switchOff dropOut').each( - function(effect) { - Effect.Methods[effect] = function(element, options){ - element = $(element); - Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); - return element; - }; - } -); - -$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( - function(f) { Effect.Methods[f] = Element[f]; } -); - -Element.addMethods(Effect.Methods); \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/prototype.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/prototype.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/prototype.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/prototype.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,4874 +0,0 @@ -/* Prototype JavaScript framework, version 1.6.1 - * (c) 2005-2009 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://www.prototypejs.org/ - * - *--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.6.1', - - Browser: (function(){ - var ua = navigator.userAgent; - var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; - return { - IE: !!window.attachEvent && !isOpera, - Opera: isOpera, - WebKit: ua.indexOf('AppleWebKit/') > -1, - Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, - MobileSafari: /Apple.*Mobile.*Safari/.test(ua) - } - })(), - - BrowserFeatures: { - XPath: !!document.evaluate, - SelectorsAPI: !!document.querySelector, - ElementExtensions: (function() { - var constructor = window.Element || window.HTMLElement; - return !!(constructor && constructor.prototype); - })(), - SpecificElementExtensions: (function() { - if (typeof window.HTMLDivElement !== 'undefined') - return true; - - var div = document.createElement('div'); - var form = document.createElement('form'); - var isSupported = false; - - if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { - isSupported = true; - } - - div = form = null; - - return isSupported; - })() - }, - - ScriptFragment: ']*>([\\S\\s]*?)<\/script>', - JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, - - emptyFunction: function() { }, - K: function(x) { return x } -}; - -if (Prototype.Browser.MobileSafari) - Prototype.BrowserFeatures.SpecificElementExtensions = false; - - -var Abstract = { }; - - -var Try = { - these: function() { - var returnValue; - - for (var i = 0, length = arguments.length; i < length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) { } - } - - return returnValue; - } -}; - -/* Based on Alex Arnell's inheritance implementation. */ - -var Class = (function() { - function subclass() {}; - function create() { - var parent = null, properties = $A(arguments); - if (Object.isFunction(properties[0])) - parent = properties.shift(); - - function klass() { - this.initialize.apply(this, arguments); - } - - Object.extend(klass, Class.Methods); - klass.superclass = parent; - klass.subclasses = []; - - if (parent) { - subclass.prototype = parent.prototype; - klass.prototype = new subclass; - parent.subclasses.push(klass); - } - - for (var i = 0; i < properties.length; i++) - klass.addMethods(properties[i]); - - if (!klass.prototype.initialize) - klass.prototype.initialize = Prototype.emptyFunction; - - klass.prototype.constructor = klass; - return klass; - } - - function addMethods(source) { - var ancestor = this.superclass && this.superclass.prototype; - var properties = Object.keys(source); - - if (!Object.keys({ toString: true }).length) { - if (source.toString != Object.prototype.toString) - properties.push("toString"); - if (source.valueOf != Object.prototype.valueOf) - properties.push("valueOf"); - } - - for (var i = 0, length = properties.length; i < length; i++) { - var property = properties[i], value = source[property]; - if (ancestor && Object.isFunction(value) && - value.argumentNames().first() == "$super") { - var method = value; - value = (function(m) { - return function() { return ancestor[m].apply(this, arguments); }; - })(property).wrap(method); - - value.valueOf = method.valueOf.bind(method); - value.toString = method.toString.bind(method); - } - this.prototype[property] = value; - } - - return this; - } - - return { - create: create, - Methods: { - addMethods: addMethods - } - }; -})(); -(function() { - - var _toString = Object.prototype.toString; - - function extend(destination, source) { - for (var property in source) - destination[property] = source[property]; - return destination; - } - - function inspect(object) { - try { - if (isUndefined(object)) return 'undefined'; - if (object === null) return 'null'; - return object.inspect ? object.inspect() : String(object); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } - } - - function toJSON(object) { - var type = typeof object; - switch (type) { - case 'undefined': - case 'function': - case 'unknown': return; - case 'boolean': return object.toString(); - } - - if (object === null) return 'null'; - if (object.toJSON) return object.toJSON(); - if (isElement(object)) return; - - var results = []; - for (var property in object) { - var value = toJSON(object[property]); - if (!isUndefined(value)) - results.push(property.toJSON() + ': ' + value); - } - - return '{' + results.join(', ') + '}'; - } - - function toQueryString(object) { - return $H(object).toQueryString(); - } - - function toHTML(object) { - return object && object.toHTML ? object.toHTML() : String.interpret(object); - } - - function keys(object) { - var results = []; - for (var property in object) - results.push(property); - return results; - } - - function values(object) { - var results = []; - for (var property in object) - results.push(object[property]); - return results; - } - - function clone(object) { - return extend({ }, object); - } - - function isElement(object) { - return !!(object && object.nodeType == 1); - } - - function isArray(object) { - return _toString.call(object) == "[object Array]"; - } - - - function isHash(object) { - return object instanceof Hash; - } - - function isFunction(object) { - return typeof object === "function"; - } - - function isString(object) { - return _toString.call(object) == "[object String]"; - } - - function isNumber(object) { - return _toString.call(object) == "[object Number]"; - } - - function isUndefined(object) { - return typeof object === "undefined"; - } - - extend(Object, { - extend: extend, - inspect: inspect, - toJSON: toJSON, - toQueryString: toQueryString, - toHTML: toHTML, - keys: keys, - values: values, - clone: clone, - isElement: isElement, - isArray: isArray, - isHash: isHash, - isFunction: isFunction, - isString: isString, - isNumber: isNumber, - isUndefined: isUndefined - }); -})(); -Object.extend(Function.prototype, (function() { - var slice = Array.prototype.slice; - - function update(array, args) { - var arrayLength = array.length, length = args.length; - while (length--) array[arrayLength + length] = args[length]; - return array; - } - - function merge(array, args) { - array = slice.call(array, 0); - return update(array, args); - } - - function argumentNames() { - var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] - .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') - .replace(/\s+/g, '').split(','); - return names.length == 1 && !names[0] ? [] : names; - } - - function bind(context) { - if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; - var __method = this, args = slice.call(arguments, 1); - return function() { - var a = merge(args, arguments); - return __method.apply(context, a); - } - } - - function bindAsEventListener(context) { - var __method = this, args = slice.call(arguments, 1); - return function(event) { - var a = update([event || window.event], args); - return __method.apply(context, a); - } - } - - function curry() { - if (!arguments.length) return this; - var __method = this, args = slice.call(arguments, 0); - return function() { - var a = merge(args, arguments); - return __method.apply(this, a); - } - } - - function delay(timeout) { - var __method = this, args = slice.call(arguments, 1); - timeout = timeout * 1000 - return window.setTimeout(function() { - return __method.apply(__method, args); - }, timeout); - } - - function defer() { - var args = update([0.01], arguments); - return this.delay.apply(this, args); - } - - function wrap(wrapper) { - var __method = this; - return function() { - var a = update([__method.bind(this)], arguments); - return wrapper.apply(this, a); - } - } - - function methodize() { - if (this._methodized) return this._methodized; - var __method = this; - return this._methodized = function() { - var a = update([this], arguments); - return __method.apply(null, a); - }; - } - - return { - argumentNames: argumentNames, - bind: bind, - bindAsEventListener: bindAsEventListener, - curry: curry, - delay: delay, - defer: defer, - wrap: wrap, - methodize: methodize - } -})()); - - -Date.prototype.toJSON = function() { - return '"' + this.getUTCFullYear() + '-' + - (this.getUTCMonth() + 1).toPaddedString(2) + '-' + - this.getUTCDate().toPaddedString(2) + 'T' + - this.getUTCHours().toPaddedString(2) + ':' + - this.getUTCMinutes().toPaddedString(2) + ':' + - this.getUTCSeconds().toPaddedString(2) + 'Z"'; -}; - - -RegExp.prototype.match = RegExp.prototype.test; - -RegExp.escape = function(str) { - return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); -}; -var PeriodicalExecuter = Class.create({ - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - execute: function() { - this.callback(this); - }, - - stop: function() { - if (!this.timer) return; - clearInterval(this.timer); - this.timer = null; - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.execute(); - this.currentlyExecuting = false; - } catch(e) { - this.currentlyExecuting = false; - throw e; - } - } - } -}); -Object.extend(String, { - interpret: function(value) { - return value == null ? '' : String(value); - }, - specialChar: { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '\\': '\\\\' - } -}); - -Object.extend(String.prototype, (function() { - - function prepareReplacement(replacement) { - if (Object.isFunction(replacement)) return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; - } - - function gsub(pattern, replacement) { - var result = '', source = this, match; - replacement = prepareReplacement(replacement); - - if (Object.isString(pattern)) - pattern = RegExp.escape(pattern); - - if (!(pattern.length || pattern.source)) { - replacement = replacement(''); - return replacement + source.split('').join(replacement) + replacement; - } - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += String.interpret(replacement(match)); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - } - - function sub(pattern, replacement, count) { - replacement = prepareReplacement(replacement); - count = Object.isUndefined(count) ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - } - - function scan(pattern, iterator) { - this.gsub(pattern, iterator); - return String(this); - } - - function truncate(length, truncation) { - length = length || 30; - truncation = Object.isUndefined(truncation) ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : String(this); - } - - function strip() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - } - - function stripTags() { - return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); - } - - function stripScripts() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - } - - function extractScripts() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - } - - function evalScripts() { - return this.extractScripts().map(function(script) { return eval(script) }); - } - - function escapeHTML() { - return this.replace(/&/g,'&').replace(//g,'>'); - } - - function unescapeHTML() { - return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); - } - - - function toQueryParams(separator) { - var match = this.strip().match(/([^?#]*)(#.*)?$/); - if (!match) return { }; - - return match[1].split(separator || '&').inject({ }, function(hash, pair) { - if ((pair = pair.split('='))[0]) { - var key = decodeURIComponent(pair.shift()); - var value = pair.length > 1 ? pair.join('=') : pair[0]; - if (value != undefined) value = decodeURIComponent(value); - - if (key in hash) { - if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; - hash[key].push(value); - } - else hash[key] = value; - } - return hash; - }); - } - - function toArray() { - return this.split(''); - } - - function succ() { - return this.slice(0, this.length - 1) + - String.fromCharCode(this.charCodeAt(this.length - 1) + 1); - } - - function times(count) { - return count < 1 ? '' : new Array(count + 1).join(this); - } - - function camelize() { - var parts = this.split('-'), len = parts.length; - if (len == 1) return parts[0]; - - var camelized = this.charAt(0) == '-' - ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) - : parts[0]; - - for (var i = 1; i < len; i++) - camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); - - return camelized; - } - - function capitalize() { - return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); - } - - function underscore() { - return this.replace(/::/g, '/') - .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') - .replace(/([a-z\d])([A-Z])/g, '$1_$2') - .replace(/-/g, '_') - .toLowerCase(); - } - - function dasherize() { - return this.replace(/_/g, '-'); - } - - function inspect(useDoubleQuotes) { - var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { - if (character in String.specialChar) { - return String.specialChar[character]; - } - return '\\u00' + character.charCodeAt().toPaddedString(2, 16); - }); - if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; - return "'" + escapedString.replace(/'/g, '\\\'') + "'"; - } - - function toJSON() { - return this.inspect(true); - } - - function unfilterJSON(filter) { - return this.replace(filter || Prototype.JSONFilter, '$1'); - } - - function isJSON() { - var str = this; - if (str.blank()) return false; - str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); - return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); - } - - function evalJSON(sanitize) { - var json = this.unfilterJSON(); - try { - if (!sanitize || json.isJSON()) return eval('(' + json + ')'); - } catch (e) { } - throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); - } - - function include(pattern) { - return this.indexOf(pattern) > -1; - } - - function startsWith(pattern) { - return this.indexOf(pattern) === 0; - } - - function endsWith(pattern) { - var d = this.length - pattern.length; - return d >= 0 && this.lastIndexOf(pattern) === d; - } - - function empty() { - return this == ''; - } - - function blank() { - return /^\s*$/.test(this); - } - - function interpolate(object, pattern) { - return new Template(this, pattern).evaluate(object); - } - - return { - gsub: gsub, - sub: sub, - scan: scan, - truncate: truncate, - strip: String.prototype.trim ? String.prototype.trim : strip, - stripTags: stripTags, - stripScripts: stripScripts, - extractScripts: extractScripts, - evalScripts: evalScripts, - escapeHTML: escapeHTML, - unescapeHTML: unescapeHTML, - toQueryParams: toQueryParams, - parseQuery: toQueryParams, - toArray: toArray, - succ: succ, - times: times, - camelize: camelize, - capitalize: capitalize, - underscore: underscore, - dasherize: dasherize, - inspect: inspect, - toJSON: toJSON, - unfilterJSON: unfilterJSON, - isJSON: isJSON, - evalJSON: evalJSON, - include: include, - startsWith: startsWith, - endsWith: endsWith, - empty: empty, - blank: blank, - interpolate: interpolate - }; -})()); - -var Template = Class.create({ - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - if (object && Object.isFunction(object.toTemplateReplacements)) - object = object.toTemplateReplacements(); - - return this.template.gsub(this.pattern, function(match) { - if (object == null) return (match[1] + ''); - - var before = match[1] || ''; - if (before == '\\') return match[2]; - - var ctx = object, expr = match[3]; - var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; - match = pattern.exec(expr); - if (match == null) return before; - - while (match != null) { - var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; - ctx = ctx[comp]; - if (null == ctx || '' == match[3]) break; - expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); - match = pattern.exec(expr); - } - - return before + String.interpret(ctx); - }); - } -}); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; - -var $break = { }; - -var Enumerable = (function() { - function each(iterator, context) { - var index = 0; - try { - this._each(function(value) { - iterator.call(context, value, index++); - }); - } catch (e) { - if (e != $break) throw e; - } - return this; - } - - function eachSlice(number, iterator, context) { - var index = -number, slices = [], array = this.toArray(); - if (number < 1) return array; - while ((index += number) < array.length) - slices.push(array.slice(index, index+number)); - return slices.collect(iterator, context); - } - - function all(iterator, context) { - iterator = iterator || Prototype.K; - var result = true; - this.each(function(value, index) { - result = result && !!iterator.call(context, value, index); - if (!result) throw $break; - }); - return result; - } - - function any(iterator, context) { - iterator = iterator || Prototype.K; - var result = false; - this.each(function(value, index) { - if (result = !!iterator.call(context, value, index)) - throw $break; - }); - return result; - } - - function collect(iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - this.each(function(value, index) { - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function detect(iterator, context) { - var result; - this.each(function(value, index) { - if (iterator.call(context, value, index)) { - result = value; - throw $break; - } - }); - return result; - } - - function findAll(iterator, context) { - var results = []; - this.each(function(value, index) { - if (iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function grep(filter, iterator, context) { - iterator = iterator || Prototype.K; - var results = []; - - if (Object.isString(filter)) - filter = new RegExp(RegExp.escape(filter)); - - this.each(function(value, index) { - if (filter.match(value)) - results.push(iterator.call(context, value, index)); - }); - return results; - } - - function include(object) { - if (Object.isFunction(this.indexOf)) - if (this.indexOf(object) != -1) return true; - - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - } - - function inGroupsOf(number, fillWith) { - fillWith = Object.isUndefined(fillWith) ? null : fillWith; - return this.eachSlice(number, function(slice) { - while(slice.length < number) slice.push(fillWith); - return slice; - }); - } - - function inject(memo, iterator, context) { - this.each(function(value, index) { - memo = iterator.call(context, memo, value, index); - }); - return memo; - } - - function invoke(method) { - var args = $A(arguments).slice(1); - return this.map(function(value) { - return value[method].apply(value, args); - }); - } - - function max(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value >= result) - result = value; - }); - return result; - } - - function min(iterator, context) { - iterator = iterator || Prototype.K; - var result; - this.each(function(value, index) { - value = iterator.call(context, value, index); - if (result == null || value < result) - result = value; - }); - return result; - } - - function partition(iterator, context) { - iterator = iterator || Prototype.K; - var trues = [], falses = []; - this.each(function(value, index) { - (iterator.call(context, value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - } - - function pluck(property) { - var results = []; - this.each(function(value) { - results.push(value[property]); - }); - return results; - } - - function reject(iterator, context) { - var results = []; - this.each(function(value, index) { - if (!iterator.call(context, value, index)) - results.push(value); - }); - return results; - } - - function sortBy(iterator, context) { - return this.map(function(value, index) { - return { - value: value, - criteria: iterator.call(context, value, index) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - } - - function toArray() { - return this.map(); - } - - function zip() { - var iterator = Prototype.K, args = $A(arguments); - if (Object.isFunction(args.last())) - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - } - - function size() { - return this.toArray().length; - } - - function inspect() { - return '#'; - } - - - - - - - - - - return { - each: each, - eachSlice: eachSlice, - all: all, - every: all, - any: any, - some: any, - collect: collect, - map: collect, - detect: detect, - findAll: findAll, - select: findAll, - filter: findAll, - grep: grep, - include: include, - member: include, - inGroupsOf: inGroupsOf, - inject: inject, - invoke: invoke, - max: max, - min: min, - partition: partition, - pluck: pluck, - reject: reject, - sortBy: sortBy, - toArray: toArray, - entries: toArray, - zip: zip, - size: size, - inspect: inspect, - find: detect - }; -})(); -function $A(iterable) { - if (!iterable) return []; - if ('toArray' in Object(iterable)) return iterable.toArray(); - var length = iterable.length || 0, results = new Array(length); - while (length--) results[length] = iterable[length]; - return results; -} - -function $w(string) { - if (!Object.isString(string)) return []; - string = string.strip(); - return string ? string.split(/\s+/) : []; -} - -Array.from = $A; - - -(function() { - var arrayProto = Array.prototype, - slice = arrayProto.slice, - _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available - - function each(iterator) { - for (var i = 0, length = this.length; i < length; i++) - iterator(this[i]); - } - if (!_each) _each = each; - - function clear() { - this.length = 0; - return this; - } - - function first() { - return this[0]; - } - - function last() { - return this[this.length - 1]; - } - - function compact() { - return this.select(function(value) { - return value != null; - }); - } - - function flatten() { - return this.inject([], function(array, value) { - if (Object.isArray(value)) - return array.concat(value.flatten()); - array.push(value); - return array; - }); - } - - function without() { - var values = slice.call(arguments, 0); - return this.select(function(value) { - return !values.include(value); - }); - } - - function reverse(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - } - - function uniq(sorted) { - return this.inject([], function(array, value, index) { - if (0 == index || (sorted ? array.last() != value : !array.include(value))) - array.push(value); - return array; - }); - } - - function intersect(array) { - return this.uniq().findAll(function(item) { - return array.detect(function(value) { return item === value }); - }); - } - - - function clone() { - return slice.call(this, 0); - } - - function size() { - return this.length; - } - - function inspect() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } - - function toJSON() { - var results = []; - this.each(function(object) { - var value = Object.toJSON(object); - if (!Object.isUndefined(value)) results.push(value); - }); - return '[' + results.join(', ') + ']'; - } - - function indexOf(item, i) { - i || (i = 0); - var length = this.length; - if (i < 0) i = length + i; - for (; i < length; i++) - if (this[i] === item) return i; - return -1; - } - - function lastIndexOf(item, i) { - i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; - var n = this.slice(0, i).reverse().indexOf(item); - return (n < 0) ? n : i - n - 1; - } - - function concat() { - var array = slice.call(this, 0), item; - for (var i = 0, length = arguments.length; i < length; i++) { - item = arguments[i]; - if (Object.isArray(item) && !('callee' in item)) { - for (var j = 0, arrayLength = item.length; j < arrayLength; j++) - array.push(item[j]); - } else { - array.push(item); - } - } - return array; - } - - Object.extend(arrayProto, Enumerable); - - if (!arrayProto._reverse) - arrayProto._reverse = arrayProto.reverse; - - Object.extend(arrayProto, { - _each: _each, - clear: clear, - first: first, - last: last, - compact: compact, - flatten: flatten, - without: without, - reverse: reverse, - uniq: uniq, - intersect: intersect, - clone: clone, - toArray: clone, - size: size, - inspect: inspect, - toJSON: toJSON - }); - - var CONCAT_ARGUMENTS_BUGGY = (function() { - return [].concat(arguments)[0][0] !== 1; - })(1,2) - - if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; - - if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; - if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; -})(); -function $H(object) { - return new Hash(object); -}; - -var Hash = Class.create(Enumerable, (function() { - function initialize(object) { - this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); - } - - function _each(iterator) { - for (var key in this._object) { - var value = this._object[key], pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - } - - function set(key, value) { - return this._object[key] = value; - } - - function get(key) { - if (this._object[key] !== Object.prototype[key]) - return this._object[key]; - } - - function unset(key) { - var value = this._object[key]; - delete this._object[key]; - return value; - } - - function toObject() { - return Object.clone(this._object); - } - - function keys() { - return this.pluck('key'); - } - - function values() { - return this.pluck('value'); - } - - function index(value) { - var match = this.detect(function(pair) { - return pair.value === value; - }); - return match && match.key; - } - - function merge(object) { - return this.clone().update(object); - } - - function update(object) { - return new Hash(object).inject(this, function(result, pair) { - result.set(pair.key, pair.value); - return result; - }); - } - - function toQueryPair(key, value) { - if (Object.isUndefined(value)) return key; - return key + '=' + encodeURIComponent(String.interpret(value)); - } - - function toQueryString() { - return this.inject([], function(results, pair) { - var key = encodeURIComponent(pair.key), values = pair.value; - - if (values && typeof values == 'object') { - if (Object.isArray(values)) - return results.concat(values.map(toQueryPair.curry(key))); - } else results.push(toQueryPair(key, values)); - return results; - }).join('&'); - } - - function inspect() { - return '#'; - } - - function toJSON() { - return Object.toJSON(this.toObject()); - } - - function clone() { - return new Hash(this); - } - - return { - initialize: initialize, - _each: _each, - set: set, - get: get, - unset: unset, - toObject: toObject, - toTemplateReplacements: toObject, - keys: keys, - values: values, - index: index, - merge: merge, - update: update, - toQueryString: toQueryString, - inspect: inspect, - toJSON: toJSON, - clone: clone - }; -})()); - -Hash.from = $H; -Object.extend(Number.prototype, (function() { - function toColorPart() { - return this.toPaddedString(2, 16); - } - - function succ() { - return this + 1; - } - - function times(iterator, context) { - $R(0, this, true).each(iterator, context); - return this; - } - - function toPaddedString(length, radix) { - var string = this.toString(radix || 10); - return '0'.times(length - string.length) + string; - } - - function toJSON() { - return isFinite(this) ? this.toString() : 'null'; - } - - function abs() { - return Math.abs(this); - } - - function round() { - return Math.round(this); - } - - function ceil() { - return Math.ceil(this); - } - - function floor() { - return Math.floor(this); - } - - return { - toColorPart: toColorPart, - succ: succ, - times: times, - toPaddedString: toPaddedString, - toJSON: toJSON, - abs: abs, - round: round, - ceil: ceil, - floor: floor - }; -})()); - -function $R(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var ObjectRange = Class.create(Enumerable, (function() { - function initialize(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - } - - function _each(iterator) { - var value = this.start; - while (this.include(value)) { - iterator(value); - value = value.succ(); - } - } - - function include(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } - - return { - initialize: initialize, - _each: _each, - include: include - }; -})()); - - - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responder) { - if (!this.include(responder)) - this.responders.push(responder); - }, - - unregister: function(responder) { - this.responders = this.responders.without(responder); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (Object.isFunction(responder[callback])) { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) { } - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { Ajax.activeRequestCount++ }, - onComplete: function() { Ajax.activeRequestCount-- } -}); -Ajax.Base = Class.create({ - initialize: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - encoding: 'UTF-8', - parameters: '', - evalJSON: true, - evalJS: true - }; - Object.extend(this.options, options || { }); - - this.options.method = this.options.method.toLowerCase(); - - if (Object.isString(this.options.parameters)) - this.options.parameters = this.options.parameters.toQueryParams(); - else if (Object.isHash(this.options.parameters)) - this.options.parameters = this.options.parameters.toObject(); - } -}); -Ajax.Request = Class.create(Ajax.Base, { - _complete: false, - - initialize: function($super, url, options) { - $super(options); - this.transport = Ajax.getTransport(); - this.request(url); - }, - - request: function(url) { - this.url = url; - this.method = this.options.method; - var params = Object.clone(this.options.parameters); - - if (!['get', 'post'].include(this.method)) { - params['_method'] = this.method; - this.method = 'post'; - } - - this.parameters = params; - - if (params = Object.toQueryString(params)) { - if (this.method == 'get') - this.url += (this.url.include('?') ? '&' : '?') + params; - else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) - params += '&_='; - } - - try { - var response = new Ajax.Response(this); - if (this.options.onCreate) this.options.onCreate(response); - Ajax.Responders.dispatch('onCreate', this, response); - - this.transport.open(this.method.toUpperCase(), this.url, - this.options.asynchronous); - - if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); - - this.transport.onreadystatechange = this.onStateChange.bind(this); - this.setRequestHeaders(); - - this.body = this.method == 'post' ? (this.options.postBody || params) : null; - this.transport.send(this.body); - - /* Force Firefox to handle ready state 4 for synchronous requests */ - if (!this.options.asynchronous && this.transport.overrideMimeType) - this.onStateChange(); - - } - catch (e) { - this.dispatchException(e); - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState > 1 && !((readyState == 4) && this._complete)) - this.respondToReadyState(this.transport.readyState); - }, - - setRequestHeaders: function() { - var headers = { - 'X-Requested-With': 'XMLHttpRequest', - 'X-Prototype-Version': Prototype.Version, - 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' - }; - - if (this.method == 'post') { - headers['Content-type'] = this.options.contentType + - (this.options.encoding ? '; charset=' + this.options.encoding : ''); - - /* Force "Connection: close" for older Mozilla browsers to work - * around a bug where XMLHttpRequest sends an incorrect - * Content-length header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType && - (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) - headers['Connection'] = 'close'; - } - - if (typeof this.options.requestHeaders == 'object') { - var extras = this.options.requestHeaders; - - if (Object.isFunction(extras.push)) - for (var i = 0, length = extras.length; i < length; i += 2) - headers[extras[i]] = extras[i+1]; - else - $H(extras).each(function(pair) { headers[pair.key] = pair.value }); - } - - for (var name in headers) - this.transport.setRequestHeader(name, headers[name]); - }, - - success: function() { - var status = this.getStatus(); - return !status || (status >= 200 && status < 300); - }, - - getStatus: function() { - try { - return this.transport.status || 0; - } catch (e) { return 0 } - }, - - respondToReadyState: function(readyState) { - var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); - - if (state == 'Complete') { - try { - this._complete = true; - (this.options['on' + response.status] - || this.options['on' + (this.success() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - var contentType = response.getHeader('Content-type'); - if (this.options.evalJS == 'force' - || (this.options.evalJS && this.isSameOrigin() && contentType - && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) - this.evalResponse(); - } - - try { - (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); - Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); - } catch (e) { - this.dispatchException(e); - } - - if (state == 'Complete') { - this.transport.onreadystatechange = Prototype.emptyFunction; - } - }, - - isSameOrigin: function() { - var m = this.url.match(/^\s*https?:\/\/[^\/]*/); - return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ - protocol: location.protocol, - domain: document.domain, - port: location.port ? ':' + location.port : '' - })); - }, - - getHeader: function(name) { - try { - return this.transport.getResponseHeader(name) || null; - } catch (e) { return null; } - }, - - evalResponse: function() { - try { - return eval((this.transport.responseText || '').unfilterJSON()); - } catch (e) { - this.dispatchException(e); - } - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - - - - - - - - -Ajax.Response = Class.create({ - initialize: function(request){ - this.request = request; - var transport = this.transport = request.transport, - readyState = this.readyState = transport.readyState; - - if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { - this.status = this.getStatus(); - this.statusText = this.getStatusText(); - this.responseText = String.interpret(transport.responseText); - this.headerJSON = this._getHeaderJSON(); - } - - if(readyState == 4) { - var xml = transport.responseXML; - this.responseXML = Object.isUndefined(xml) ? null : xml; - this.responseJSON = this._getResponseJSON(); - } - }, - - status: 0, - - statusText: '', - - getStatus: Ajax.Request.prototype.getStatus, - - getStatusText: function() { - try { - return this.transport.statusText || ''; - } catch (e) { return '' } - }, - - getHeader: Ajax.Request.prototype.getHeader, - - getAllHeaders: function() { - try { - return this.getAllResponseHeaders(); - } catch (e) { return null } - }, - - getResponseHeader: function(name) { - return this.transport.getResponseHeader(name); - }, - - getAllResponseHeaders: function() { - return this.transport.getAllResponseHeaders(); - }, - - _getHeaderJSON: function() { - var json = this.getHeader('X-JSON'); - if (!json) return null; - json = decodeURIComponent(escape(json)); - try { - return json.evalJSON(this.request.options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - }, - - _getResponseJSON: function() { - var options = this.request.options; - if (!options.evalJSON || (options.evalJSON != 'force' && - !(this.getHeader('Content-type') || '').include('application/json')) || - this.responseText.blank()) - return null; - try { - return this.responseText.evalJSON(options.sanitizeJSON || - !this.request.isSameOrigin()); - } catch (e) { - this.request.dispatchException(e); - } - } -}); - -Ajax.Updater = Class.create(Ajax.Request, { - initialize: function($super, container, url, options) { - this.container = { - success: (container.success || container), - failure: (container.failure || (container.success ? null : container)) - }; - - options = Object.clone(options); - var onComplete = options.onComplete; - options.onComplete = (function(response, json) { - this.updateContent(response.responseText); - if (Object.isFunction(onComplete)) onComplete(response, json); - }).bind(this); - - $super(url, options); - }, - - updateContent: function(responseText) { - var receiver = this.container[this.success() ? 'success' : 'failure'], - options = this.options; - - if (!options.evalScripts) responseText = responseText.stripScripts(); - - if (receiver = $(receiver)) { - if (options.insertion) { - if (Object.isString(options.insertion)) { - var insertion = { }; insertion[options.insertion] = responseText; - receiver.insert(insertion); - } - else options.insertion(receiver, responseText); - } - else receiver.update(responseText); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { - initialize: function($super, container, url, options) { - $super(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = { }; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.options.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(response) { - if (this.options.decay) { - this.decay = (response.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = response.responseText; - } - this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); - - - -function $(element) { - if (arguments.length > 1) { - for (var i = 0, elements = [], length = arguments.length; i < length; i++) - elements.push($(arguments[i])); - return elements; - } - if (Object.isString(element)) - element = document.getElementById(element); - return Element.extend(element); -} - -if (Prototype.BrowserFeatures.XPath) { - document._getElementsByXPath = function(expression, parentElement) { - var results = []; - var query = document.evaluate(expression, $(parentElement) || document, - null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - for (var i = 0, length = query.snapshotLength; i < length; i++) - results.push(Element.extend(query.snapshotItem(i))); - return results; - }; -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Node) var Node = { }; - -if (!Node.ELEMENT_NODE) { - Object.extend(Node, { - ELEMENT_NODE: 1, - ATTRIBUTE_NODE: 2, - TEXT_NODE: 3, - CDATA_SECTION_NODE: 4, - ENTITY_REFERENCE_NODE: 5, - ENTITY_NODE: 6, - PROCESSING_INSTRUCTION_NODE: 7, - COMMENT_NODE: 8, - DOCUMENT_NODE: 9, - DOCUMENT_TYPE_NODE: 10, - DOCUMENT_FRAGMENT_NODE: 11, - NOTATION_NODE: 12 - }); -} - - -(function(global) { - - var SETATTRIBUTE_IGNORES_NAME = (function(){ - var elForm = document.createElement("form"); - var elInput = document.createElement("input"); - var root = document.documentElement; - elInput.setAttribute("name", "test"); - elForm.appendChild(elInput); - root.appendChild(elForm); - var isBuggy = elForm.elements - ? (typeof elForm.elements.test == "undefined") - : null; - root.removeChild(elForm); - elForm = elInput = null; - return isBuggy; - })(); - - var element = global.Element; - global.Element = function(tagName, attributes) { - attributes = attributes || { }; - tagName = tagName.toLowerCase(); - var cache = Element.cache; - if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { - tagName = '<' + tagName + ' name="' + attributes.name + '">'; - delete attributes.name; - return Element.writeAttribute(document.createElement(tagName), attributes); - } - if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); - return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); - }; - Object.extend(global.Element, element || { }); - if (element) global.Element.prototype = element.prototype; -})(this); - -Element.cache = { }; -Element.idCounter = 1; - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function(element) { - element = $(element); - Element[Element.visible(element) ? 'hide' : 'show'](element); - return element; - }, - - - hide: function(element) { - element = $(element); - element.style.display = 'none'; - return element; - }, - - show: function(element) { - element = $(element); - element.style.display = ''; - return element; - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - return element; - }, - - update: (function(){ - - var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ - var el = document.createElement("select"), - isBuggy = true; - el.innerHTML = ""; - if (el.options && el.options[0]) { - isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; - } - el = null; - return isBuggy; - })(); - - var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ - try { - var el = document.createElement("table"); - if (el && el.tBodies) { - el.innerHTML = "test"; - var isBuggy = typeof el.tBodies[0] == "undefined"; - el = null; - return isBuggy; - } - } catch (e) { - return true; - } - })(); - - var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { - var s = document.createElement("script"), - isBuggy = false; - try { - s.appendChild(document.createTextNode("")); - isBuggy = !s.firstChild || - s.firstChild && s.firstChild.nodeType !== 3; - } catch (e) { - isBuggy = true; - } - s = null; - return isBuggy; - })(); - - function update(element, content) { - element = $(element); - - if (content && content.toElement) - content = content.toElement(); - - if (Object.isElement(content)) - return element.update().insert(content); - - content = Object.toHTML(content); - - var tagName = element.tagName.toUpperCase(); - - if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { - element.text = content; - return element; - } - - if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { - if (tagName in Element._insertionTranslations.tags) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { - element.appendChild(node) - }); - } - else { - element.innerHTML = content.stripScripts(); - } - } - else { - element.innerHTML = content.stripScripts(); - } - - content.evalScripts.bind(content).defer(); - return element; - } - - return update; - })(), - - replace: function(element, content) { - element = $(element); - if (content && content.toElement) content = content.toElement(); - else if (!Object.isElement(content)) { - content = Object.toHTML(content); - var range = element.ownerDocument.createRange(); - range.selectNode(element); - content.evalScripts.bind(content).defer(); - content = range.createContextualFragment(content.stripScripts()); - } - element.parentNode.replaceChild(content, element); - return element; - }, - - insert: function(element, insertions) { - element = $(element); - - if (Object.isString(insertions) || Object.isNumber(insertions) || - Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) - insertions = {bottom:insertions}; - - var content, insert, tagName, childNodes; - - for (var position in insertions) { - content = insertions[position]; - position = position.toLowerCase(); - insert = Element._insertionTranslations[position]; - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - insert(element, content); - continue; - } - - content = Object.toHTML(content); - - tagName = ((position == 'before' || position == 'after') - ? element.parentNode : element).tagName.toUpperCase(); - - childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - - if (position == 'top' || position == 'after') childNodes.reverse(); - childNodes.each(insert.curry(element)); - - content.evalScripts.bind(content).defer(); - } - - return element; - }, - - wrap: function(element, wrapper, attributes) { - element = $(element); - if (Object.isElement(wrapper)) - $(wrapper).writeAttribute(attributes || { }); - else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); - else wrapper = new Element('div', wrapper); - if (element.parentNode) - element.parentNode.replaceChild(wrapper, element); - wrapper.appendChild(element); - return wrapper; - }, - - inspect: function(element) { - element = $(element); - var result = '<' + element.tagName.toLowerCase(); - $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); - if (value) result += ' ' + attribute + '=' + value.inspect(true); - }); - return result + '>'; - }, - - recursivelyCollect: function(element, property) { - element = $(element); - var elements = []; - while (element = element[property]) - if (element.nodeType == 1) - elements.push(Element.extend(element)); - return elements; - }, - - ancestors: function(element) { - return Element.recursivelyCollect(element, 'parentNode'); - }, - - descendants: function(element) { - return Element.select(element, "*"); - }, - - firstDescendant: function(element) { - element = $(element).firstChild; - while (element && element.nodeType != 1) element = element.nextSibling; - return $(element); - }, - - immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; - }, - - previousSiblings: function(element) { - return Element.recursivelyCollect(element, 'previousSibling'); - }, - - nextSiblings: function(element) { - return Element.recursivelyCollect(element, 'nextSibling'); - }, - - siblings: function(element) { - element = $(element); - return Element.previousSiblings(element).reverse() - .concat(Element.nextSiblings(element)); - }, - - match: function(element, selector) { - if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); - }, - - up: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(element.parentNode); - var ancestors = Element.ancestors(element); - return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); - }, - - down: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return Element.firstDescendant(element); - return Object.isNumber(expression) ? Element.descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - }, - - previous: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = Element.previousSiblings(element); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); - }, - - next: function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = Element.nextSiblings(element); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); - }, - - - select: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element, args); - }, - - adjacent: function(element) { - var args = Array.prototype.slice.call(arguments, 1); - return Selector.findChildElements(element.parentNode, args).without(element); - }, - - identify: function(element) { - element = $(element); - var id = Element.readAttribute(element, 'id'); - if (id) return id; - do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); - Element.writeAttribute(element, 'id', id); - return id; - }, - - readAttribute: function(element, name) { - element = $(element); - if (Prototype.Browser.IE) { - var t = Element._attributeTranslations.read; - if (t.values[name]) return t.values[name](element, name); - if (t.names[name]) name = t.names[name]; - if (name.include(':')) { - return (!element.attributes || !element.attributes[name]) ? null : - element.attributes[name].value; - } - } - return element.getAttribute(name); - }, - - writeAttribute: function(element, name, value) { - element = $(element); - var attributes = { }, t = Element._attributeTranslations.write; - - if (typeof name == 'object') attributes = name; - else attributes[name] = Object.isUndefined(value) ? true : value; - - for (var attr in attributes) { - name = t.names[attr] || attr; - value = attributes[attr]; - if (t.values[attr]) name = t.values[attr](element, value); - if (value === false || value === null) - element.removeAttribute(name); - else if (value === true) - element.setAttribute(name, name); - else element.setAttribute(name, value); - } - return element; - }, - - getHeight: function(element) { - return Element.getDimensions(element).height; - }, - - getWidth: function(element) { - return Element.getDimensions(element).width; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - var elementClassName = element.className; - return (elementClassName.length > 0 && (elementClassName == className || - new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - if (!Element.hasClassName(element, className)) - element.className += (element.className ? ' ' : '') + className; - return element; - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - element.className = element.className.replace( - new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); - return element; - }, - - toggleClassName: function(element, className) { - if (!(element = $(element))) return; - return Element[Element.hasClassName(element, className) ? - 'removeClassName' : 'addClassName'](element, className); - }, - - cleanWhitespace: function(element) { - element = $(element); - var node = element.firstChild; - while (node) { - var nextNode = node.nextSibling; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - element.removeChild(node); - node = nextNode; - } - return element; - }, - - empty: function(element) { - return $(element).innerHTML.blank(); - }, - - descendantOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - - if (element.compareDocumentPosition) - return (element.compareDocumentPosition(ancestor) & 8) === 8; - - if (ancestor.contains) - return ancestor.contains(element) && ancestor !== element; - - while (element = element.parentNode) - if (element == ancestor) return true; - - return false; - }, - - scrollTo: function(element) { - element = $(element); - var pos = Element.cumulativeOffset(element); - window.scrollTo(pos[0], pos[1]); - return element; - }, - - getStyle: function(element, style) { - element = $(element); - style = style == 'float' ? 'cssFloat' : style.camelize(); - var value = element.style[style]; - if (!value || value == 'auto') { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css[style] : null; - } - if (style == 'opacity') return value ? parseFloat(value) : 1.0; - return value == 'auto' ? null : value; - }, - - getOpacity: function(element) { - return $(element).getStyle('opacity'); - }, - - setStyle: function(element, styles) { - element = $(element); - var elementStyle = element.style, match; - if (Object.isString(styles)) { - element.style.cssText += ';' + styles; - return styles.include('opacity') ? - element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; - } - for (var property in styles) - if (property == 'opacity') element.setOpacity(styles[property]); - else - elementStyle[(property == 'float' || property == 'cssFloat') ? - (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : - property] = styles[property]; - - return element; - }, - - setOpacity: function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - return element; - }, - - getDimensions: function(element) { - element = $(element); - var display = Element.getStyle(element, 'display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - if (Prototype.Browser.Opera) { - element.style.top = 0; - element.style.left = 0; - } - } - return element; - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - return element; - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return element; - element._overflow = Element.getStyle(element, 'overflow') || 'auto'; - if (element._overflow !== 'hidden') - element.style.overflow = 'hidden'; - return element; - }, - - undoClipping: function(element) { - element = $(element); - if (!element._overflow) return element; - element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; - element._overflow = null; - return element; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'absolute') return element; - - var offsets = Element.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (Element.getStyle(element, 'position') == 'relative') return element; - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - - clonePosition: function(element, source) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || { }); - - source = $(source); - var p = Element.viewportOffset(source); - - element = $(element); - var delta = [0, 0]; - var parent = null; - if (Element.getStyle(element, 'position') == 'absolute') { - parent = Element.getOffsetParent(element); - delta = Element.viewportOffset(parent); - } - - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if (options.setWidth) element.style.width = source.offsetWidth + 'px'; - if (options.setHeight) element.style.height = source.offsetHeight + 'px'; - return element; - } -}; - -Object.extend(Element.Methods, { - getElementsBySelector: Element.Methods.select, - - childElements: Element.Methods.immediateDescendants -}); - -Element._attributeTranslations = { - write: { - names: { - className: 'class', - htmlFor: 'for' - }, - values: { } - } -}; - -if (Prototype.Browser.Opera) { - Element.Methods.getStyle = Element.Methods.getStyle.wrap( - function(proceed, element, style) { - switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; - case 'height': case 'width': - if (!Element.visible(element)) return null; - - var dim = parseInt(proceed(element, style), 10); - - if (dim !== element['offset' + style.capitalize()]) - return dim + 'px'; - - var properties; - if (style === 'height') { - properties = ['border-top-width', 'padding-top', - 'padding-bottom', 'border-bottom-width']; - } - else { - properties = ['border-left-width', 'padding-left', - 'padding-right', 'border-right-width']; - } - return properties.inject(dim, function(memo, property) { - var val = proceed(element, property); - return val === null ? memo : memo - parseInt(val, 10); - }) + 'px'; - default: return proceed(element, style); - } - } - ); - - Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( - function(proceed, element, attribute) { - if (attribute === 'title') return element.title; - return proceed(element, attribute); - } - ); -} - -else if (Prototype.Browser.IE) { - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - - Element.Methods.getStyle = function(element, style) { - element = $(element); - style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); - var value = element.style[style]; - if (!value && element.currentStyle) value = element.currentStyle[style]; - - if (style == 'opacity') { - if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) - if (value[1]) return parseFloat(value[1]) / 100; - return 1.0; - } - - if (value == 'auto') { - if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) - return element['offset' + style.capitalize()] + 'px'; - return null; - } - return value; - }; - - Element.Methods.setOpacity = function(element, value) { - function stripAlpha(filter){ - return filter.replace(/alpha\([^\)]*\)/gi,''); - } - element = $(element); - var currentStyle = element.currentStyle; - if ((currentStyle && !currentStyle.hasLayout) || - (!currentStyle && element.style.zoom == 'normal')) - element.style.zoom = 1; - - var filter = element.getStyle('filter'), style = element.style; - if (value == 1 || value === '') { - (filter = stripAlpha(filter)) ? - style.filter = filter : style.removeAttribute('filter'); - return element; - } else if (value < 0.00001) value = 0; - style.filter = stripAlpha(filter) + - 'alpha(opacity=' + (value * 100) + ')'; - return element; - }; - - Element._attributeTranslations = (function(){ - - var classProp = 'className'; - var forProp = 'for'; - - var el = document.createElement('div'); - - el.setAttribute(classProp, 'x'); - - if (el.className !== 'x') { - el.setAttribute('class', 'x'); - if (el.className === 'x') { - classProp = 'class'; - } - } - el = null; - - el = document.createElement('label'); - el.setAttribute(forProp, 'x'); - if (el.htmlFor !== 'x') { - el.setAttribute('htmlFor', 'x'); - if (el.htmlFor === 'x') { - forProp = 'htmlFor'; - } - } - el = null; - - return { - read: { - names: { - 'class': classProp, - 'className': classProp, - 'for': forProp, - 'htmlFor': forProp - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute); - }, - _getAttr2: function(element, attribute) { - return element.getAttribute(attribute, 2); - }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: (function(){ - - var el = document.createElement('div'); - el.onclick = Prototype.emptyFunction; - var value = el.getAttribute('onclick'); - var f; - - if (String(value).indexOf('{') > -1) { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - attribute = attribute.toString(); - attribute = attribute.split('{')[1]; - attribute = attribute.split('}')[0]; - return attribute.strip(); - }; - } - else if (value === '') { - f = function(element, attribute) { - attribute = element.getAttribute(attribute); - if (!attribute) return null; - return attribute.strip(); - }; - } - el = null; - return f; - })(), - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; - } - } - } - } - })(); - - Element._attributeTranslations.write = { - names: Object.extend({ - cellpadding: 'cellPadding', - cellspacing: 'cellSpacing' - }, Element._attributeTranslations.read.names), - values: { - checked: function(element, value) { - element.checked = !!value; - }, - - style: function(element, value) { - element.style.cssText = value ? value : ''; - } - } - }; - - Element._attributeTranslations.has = {}; - - $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + - 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { - Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; - Element._attributeTranslations.has[attr.toLowerCase()] = attr; - }); - - (function(v) { - Object.extend(v, { - href: v._getAttr2, - src: v._getAttr2, - type: v._getAttr, - action: v._getAttrNode, - disabled: v._flag, - checked: v._flag, - readonly: v._flag, - multiple: v._flag, - onload: v._getEv, - onunload: v._getEv, - onclick: v._getEv, - ondblclick: v._getEv, - onmousedown: v._getEv, - onmouseup: v._getEv, - onmouseover: v._getEv, - onmousemove: v._getEv, - onmouseout: v._getEv, - onfocus: v._getEv, - onblur: v._getEv, - onkeypress: v._getEv, - onkeydown: v._getEv, - onkeyup: v._getEv, - onsubmit: v._getEv, - onreset: v._getEv, - onselect: v._getEv, - onchange: v._getEv - }); - })(Element._attributeTranslations.read.values); - - if (Prototype.BrowserFeatures.ElementExtensions) { - (function() { - function _descendants(element) { - var nodes = element.getElementsByTagName('*'), results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName !== "!") // Filter out comment nodes. - results.push(node); - return results; - } - - Element.Methods.down = function(element, expression, index) { - element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? _descendants(element)[expression] : - Element.select(element, expression)[index || 0]; - } - })(); - } - -} - -else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1) ? 0.999999 : - (value === '') ? '' : (value < 0.00001) ? 0 : value; - return element; - }; -} - -else if (Prototype.Browser.WebKit) { - Element.Methods.setOpacity = function(element, value) { - element = $(element); - element.style.opacity = (value == 1 || value === '') ? '' : - (value < 0.00001) ? 0 : value; - - if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { - element.width++; element.width--; - } else try { - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch (e) { } - - return element; - }; - - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; -} - -if ('outerHTML' in document.documentElement) { - Element.Methods.replace = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) { - element.parentNode.replaceChild(content, element); - return element; - } - - content = Object.toHTML(content); - var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); - - if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); - parent.removeChild(element); - if (nextSibling) - fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); - else - fragments.each(function(node) { parent.appendChild(node) }); - } - else element.outerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -Element._returnOffset = function(l, t) { - var result = [l, t]; - result.left = l; - result.top = t; - return result; -}; - -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; - return $A(div.childNodes); -}; - -Element._insertionTranslations = { - before: function(element, node) { - element.parentNode.insertBefore(node, element); - }, - top: function(element, node) { - element.insertBefore(node, element.firstChild); - }, - bottom: function(element, node) { - element.appendChild(node); - }, - after: function(element, node) { - element.parentNode.insertBefore(node, element.nextSibling); - }, - tags: { - TABLE: ['', '
    ', 1], - TBODY: ['', '
    ', 2], - TR: ['', '
    ', 3], - TD: ['
    ', '
    ', 4], - SELECT: ['', 1] - } -}; - -(function() { - var tags = Element._insertionTranslations.tags; - Object.extend(tags, { - THEAD: tags.TBODY, - TFOOT: tags.TBODY, - TH: tags.TD - }); -})(); - -Element.Methods.Simulated = { - hasAttribute: function(element, attribute) { - attribute = Element._attributeTranslations.has[attribute] || attribute; - var node = $(element).getAttributeNode(attribute); - return !!(node && node.specified); - } -}; - -Element.Methods.ByTag = { }; - -Object.extend(Element, Element.Methods); - -(function(div) { - - if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = div['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; - } - - div = null; - -})(document.createElement('div')) - -Element.extend = (function() { - - function checkDeficiency(tagName) { - if (typeof window.Element != 'undefined') { - var proto = window.Element.prototype; - if (proto) { - var id = '_' + (Math.random()+'').slice(2); - var el = document.createElement(tagName); - proto[id] = 'x'; - var isBuggy = (el[id] !== 'x'); - delete proto[id]; - el = null; - return isBuggy; - } - } - return false; - } - - function extendElementWith(element, methods) { - for (var property in methods) { - var value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } - } - - var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); - - if (Prototype.BrowserFeatures.SpecificElementExtensions) { - if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { - return function(element) { - if (element && typeof element._extendedByPrototype == 'undefined') { - var t = element.tagName; - if (t && (/^(?:object|applet|embed)$/i.test(t))) { - extendElementWith(element, Element.Methods); - extendElementWith(element, Element.Methods.Simulated); - extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); - } - } - return element; - } - } - return Prototype.K; - } - - var Methods = { }, ByTag = Element.Methods.ByTag; - - var extend = Object.extend(function(element) { - if (!element || typeof element._extendedByPrototype != 'undefined' || - element.nodeType != 1 || element == window) return element; - - var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(); - - if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - - extendElementWith(element, methods); - - element._extendedByPrototype = Prototype.emptyFunction; - return element; - - }, { - refresh: function() { - if (!Prototype.BrowserFeatures.ElementExtensions) { - Object.extend(Methods, Element.Methods); - Object.extend(Methods, Element.Methods.Simulated); - } - } - }); - - extend.refresh(); - return extend; -})(); - -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; - -Element.addMethods = function(methods) { - var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; - - if (!methods) { - Object.extend(Form, Form.Methods); - Object.extend(Form.Element, Form.Element.Methods); - Object.extend(Element.Methods.ByTag, { - "FORM": Object.clone(Form.Methods), - "INPUT": Object.clone(Form.Element.Methods), - "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) - }); - } - - if (arguments.length == 2) { - var tagName = methods; - methods = arguments[1]; - } - - if (!tagName) Object.extend(Element.Methods, methods || { }); - else { - if (Object.isArray(tagName)) tagName.each(extend); - else extend(tagName); - } - - function extend(tagName) { - tagName = tagName.toUpperCase(); - if (!Element.Methods.ByTag[tagName]) - Element.Methods.ByTag[tagName] = { }; - Object.extend(Element.Methods.ByTag[tagName], methods); - } - - function copy(methods, destination, onlyIfAbsent) { - onlyIfAbsent = onlyIfAbsent || false; - for (var property in methods) { - var value = methods[property]; - if (!Object.isFunction(value)) continue; - if (!onlyIfAbsent || !(property in destination)) - destination[property] = value.methodize(); - } - } - - function findDOMClass(tagName) { - var klass; - var trans = { - "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", - "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", - "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", - "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", - "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": - "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": - "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": - "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": - "FrameSet", "IFRAME": "IFrame" - }; - if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName + 'Element'; - if (window[klass]) return window[klass]; - klass = 'HTML' + tagName.capitalize() + 'Element'; - if (window[klass]) return window[klass]; - - var element = document.createElement(tagName); - var proto = element['__proto__'] || element.constructor.prototype; - element = null; - return proto; - } - - var elementPrototype = window.HTMLElement ? HTMLElement.prototype : - Element.prototype; - - if (F.ElementExtensions) { - copy(Element.Methods, elementPrototype); - copy(Element.Methods.Simulated, elementPrototype, true); - } - - if (F.SpecificElementExtensions) { - for (var tag in Element.Methods.ByTag) { - var klass = findDOMClass(tag); - if (Object.isUndefined(klass)) continue; - copy(T[tag], klass.prototype); - } - } - - Object.extend(Element, Element.Methods); - delete Element.ByTag; - - if (Element.extend.refresh) Element.extend.refresh(); - Element.cache = { }; -}; - - -document.viewport = { - - getDimensions: function() { - return { width: this.getWidth(), height: this.getHeight() }; - }, - - getScrollOffsets: function() { - return Element._returnOffset( - window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); - } -}; - -(function(viewport) { - var B = Prototype.Browser, doc = document, element, property = {}; - - function getRootElement() { - if (B.WebKit && !doc.evaluate) - return document; - - if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) - return document.body; - - return document.documentElement; - } - - function define(D) { - if (!element) element = getRootElement(); - - property[D] = 'client' + D; - - viewport['get' + D] = function() { return element[property[D]] }; - return viewport['get' + D](); - } - - viewport.getWidth = define.curry('Width'); - - viewport.getHeight = define.curry('Height'); -})(document.viewport); - - -Element.Storage = { - UID: 1 -}; - -Element.addMethods({ - getStorage: function(element) { - if (!(element = $(element))) return; - - var uid; - if (element === window) { - uid = 0; - } else { - if (typeof element._prototypeUID === "undefined") - element._prototypeUID = [Element.Storage.UID++]; - uid = element._prototypeUID[0]; - } - - if (!Element.Storage[uid]) - Element.Storage[uid] = $H(); - - return Element.Storage[uid]; - }, - - store: function(element, key, value) { - if (!(element = $(element))) return; - - if (arguments.length === 2) { - Element.getStorage(element).update(key); - } else { - Element.getStorage(element).set(key, value); - } - - return element; - }, - - retrieve: function(element, key, defaultValue) { - if (!(element = $(element))) return; - var hash = Element.getStorage(element), value = hash.get(key); - - if (Object.isUndefined(value)) { - hash.set(key, defaultValue); - value = defaultValue; - } - - return value; - }, - - clone: function(element, deep) { - if (!(element = $(element))) return; - var clone = element.cloneNode(deep); - clone._prototypeUID = void 0; - if (deep) { - var descendants = Element.select(clone, '*'), - i = descendants.length; - while (i--) { - descendants[i]._prototypeUID = void 0; - } - } - return Element.extend(clone); - } -}); -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ - -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); - - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); - } else { - this.mode = "normal"; - this.compileMatcher(); - } - - }, - - shouldUseXPath: (function() { - - var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ - var isBuggy = false; - if (document.evaluate && window.XPathResult) { - var el = document.createElement('div'); - el.innerHTML = '
    '; - - var xpath = ".//*[local-name()='ul' or local-name()='UL']" + - "//*[local-name()='li' or local-name()='LI']"; - - var result = document.evaluate(xpath, el, null, - XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); - - isBuggy = (result.snapshotLength !== 2); - el = null; - } - return isBuggy; - })(); - - return function() { - if (!Prototype.BrowserFeatures.XPath) return false; - - var e = this.expression; - - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - if (IS_DESCENDANT_SELECTOR_BUGGY) return false; - - return true; - } - - })(), - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; - } - - return true; - }, - - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m, len = ps.length, name; - - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; - } - - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; - - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i"; - } -}); - -if (Prototype.BrowserFeatures.SelectorsAPI && - document.compatMode === 'BackCompat') { - Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ - var div = document.createElement('div'), - span = document.createElement('span'); - - div.id = "prototype_test_id"; - span.className = 'Test'; - div.appendChild(span); - var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); - div = span = null; - return isIgnored; - })(); -} - -Object.extend(Selector, { - _cache: { }, - - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v, len = p.length, name; - - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i = 0; i= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } - } - }, - - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: [ - { name: 'laterSibling', re: /^\s*~\s*/ }, - { name: 'child', re: /^\s*>\s*/ }, - { name: 'adjacent', re: /^\s*\+\s*/ }, - { name: 'descendant', re: /^\s/ }, - - { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, - { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, - { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, - { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, - { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, - { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } - ], - - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); - } - }, - - handlers: { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, - - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, - - unmark: (function(){ - - var PROPERTIES_ATTRIBUTES_MAP = (function(){ - var el = document.createElement('div'), - isBuggy = false, - propName = '_countedByPrototype', - value = 'x' - el[propName] = value; - isBuggy = (el.getAttribute(propName) === value); - el = null; - return isBuggy; - })(); - - return PROPERTIES_ATTRIBUTES_MAP ? - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; - } : - function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = void 0; - return nodes; - } - })(), - - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); - } - return Selector.handlers.unmark(results); - }, - - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); - } - return results; - }, - - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - - if (root == document) { - if (!targetNode) return []; - if (!nodes) return [targetNode]; - } else { - if (!root.sourceIndex || root.sourceIndex < 1) { - var nodes = root.getElementsByTagName('*'); - for (var j = 0, node; node = nodes[j]; j++) { - if (node.id === id) return [node]; - } - } - } - - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); - } - }, - - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; - } -}); - -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; - } - }); -} - -function $$() { - return Selector.findChildElements(document, $A(arguments)); -} - -var Form = { - reset: function(form) { - form = $(form); - form.reset(); - return form; - }, - - serializeElements: function(elements, options) { - if (typeof options != 'object') options = { hash: !!options }; - else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; - - var data = elements.inject({ }, function(result, element) { - if (!element.disabled && element.name) { - key = element.name; value = $(element).getValue(); - if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && - submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; - } - } - return result; - }); - - return options.hash ? data : Object.toQueryString(data); - } -}; - -Form.Methods = { - serialize: function(form, options) { - return Form.serializeElements(Form.getElements(form), options); - }, - - getElements: function(form) { - var elements = $(form).getElementsByTagName('*'), - element, - arr = [ ], - serializers = Form.Element.Serializers; - for (var i = 0; element = elements[i]; i++) { - arr.push(element); - } - return arr.inject([], function(elements, child) { - if (serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - }) - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) return $A(inputs).map(Element.extend); - - for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || (name && input.name != name)) - continue; - matchingInputs.push(Element.extend(input)); - } - - return matchingInputs; - }, - - disable: function(form) { - form = $(form); - Form.getElements(form).invoke('disable'); - return form; - }, - - enable: function(form) { - form = $(form); - Form.getElements(form).invoke('enable'); - return form; - }, - - findFirstElement: function(form) { - var elements = $(form).getElements().findAll(function(element) { - return 'hidden' != element.type && !element.disabled; - }); - var firstByIndex = elements.findAll(function(element) { - return element.hasAttribute('tabIndex') && element.tabIndex >= 0; - }).sortBy(function(element) { return element.tabIndex }).first(); - - return firstByIndex ? firstByIndex : elements.find(function(element) { - return /^(?:input|select|textarea)$/i.test(element.tagName); - }); - }, - - focusFirstElement: function(form) { - form = $(form); - form.findFirstElement().activate(); - return form; - }, - - request: function(form, options) { - form = $(form), options = Object.clone(options || { }); - - var params = options.parameters, action = form.readAttribute('action') || ''; - if (action.blank()) action = window.location.href; - options.parameters = form.serialize(true); - - if (params) { - if (Object.isString(params)) params = params.toQueryParams(); - Object.extend(options.parameters, params); - } - - if (form.hasAttribute('method') && !options.method) - options.method = form.method; - - return new Ajax.Request(action, options); - } -}; - -/*--------------------------------------------------------------------------*/ - - -Form.Element = { - focus: function(element) { - $(element).focus(); - return element; - }, - - select: function(element) { - $(element).select(); - return element; - } -}; - -Form.Element.Methods = { - - serialize: function(element) { - element = $(element); - if (!element.disabled && element.name) { - var value = element.getValue(); - if (value != undefined) { - var pair = { }; - pair[element.name] = value; - return Object.toQueryString(pair); - } - } - return ''; - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - return Form.Element.Serializers[method](element); - }, - - setValue: function(element, value) { - element = $(element); - var method = element.tagName.toLowerCase(); - Form.Element.Serializers[method](element, value); - return element; - }, - - clear: function(element) { - $(element).value = ''; - return element; - }, - - present: function(element) { - return $(element).value != ''; - }, - - activate: function(element) { - element = $(element); - try { - element.focus(); - if (element.select && (element.tagName.toLowerCase() != 'input' || - !(/^(?:button|reset|submit)$/i.test(element.type)))) - element.select(); - } catch (e) { } - return element; - }, - - disable: function(element) { - element = $(element); - element.disabled = true; - return element; - }, - - enable: function(element) { - element = $(element); - element.disabled = false; - return element; - } -}; - -/*--------------------------------------------------------------------------*/ - -var Field = Form.Element; - -var $F = Form.Element.Methods.getValue; - -/*--------------------------------------------------------------------------*/ - -Form.Element.Serializers = { - input: function(element, value) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element, value); - default: - return Form.Element.Serializers.textarea(element, value); - } - }, - - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; - else element.checked = !!value; - }, - - textarea: function(element, value) { - if (Object.isUndefined(value)) return element.value; - else element.value = value; - }, - - select: function(element, value) { - if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } - } - else opt.selected = value.include(currentValue); - } - } - }, - - selectOne: function(element) { - var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, - - selectMany: function(element) { - var values, length = element.length; - if (!length) return null; - - for (var i = 0, values = []; i < length; i++) { - var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); - } - return values; - }, - - optionValue: function(opt) { - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; - } -}; - -/*--------------------------------------------------------------------------*/ - - -Abstract.TimedObserver = Class.create(PeriodicalExecuter, { - initialize: function($super, element, frequency, callback) { - $super(callback, frequency); - this.element = $(element); - this.lastValue = this.getValue(); - }, - - execute: function() { - var value = this.getValue(); - if (Object.isString(this.lastValue) && Object.isString(value) ? - this.lastValue != value : String(this.lastValue) != String(value)) { - this.callback(this.element, value); - this.lastValue = value; - } - } -}); - -Form.Element.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(Abstract.TimedObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = Class.create({ - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - Form.getElements(this.element).each(this.registerCallback, this); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - default: - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -}); - -Form.Element.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(Abstract.EventObserver, { - getValue: function() { - return Form.serialize(this.element); - } -}); -(function() { - - var Event = { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, - - cache: {} - }; - - var docEl = document.documentElement; - var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl - && 'onmouseleave' in docEl; - - var _isButton; - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - _isButton = function(event, code) { - return event.button === buttonMap[code]; - }; - } else if (Prototype.Browser.WebKit) { - _isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - } else { - _isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - function isLeftClick(event) { return _isButton(event, 0) } - - function isMiddleClick(event) { return _isButton(event, 1) } - - function isRightClick(event) { return _isButton(event, 2) } - - function element(event) { - event = Event.extend(event); - - var node = event.target, type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - - if (node.nodeType == Node.TEXT_NODE) - node = node.parentNode; - - return Element.extend(node); - } - - function findElement(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - } - - function pointer(event) { - return { x: pointerX(event), y: pointerY(event) }; - } - - function pointerX(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0 }; - - return event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)); - } - - function pointerY(event) { - var docElement = document.documentElement, - body = document.body || { scrollTop: 0 }; - - return event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)); - } - - - function stop(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - - event.stopped = true; - } - - Event.Methods = { - isLeftClick: isLeftClick, - isMiddleClick: isMiddleClick, - isRightClick: isRightClick, - - element: element, - findElement: findElement, - - pointer: pointer, - pointerX: pointerX, - pointerY: pointerY, - - stop: stop - }; - - - var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { - m[name] = Event.Methods[name].methodize(); - return m; - }); - - if (Prototype.Browser.IE) { - function _relatedTarget(event) { - var element; - switch (event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } - - Object.extend(methods, { - stopPropagation: function() { this.cancelBubble = true }, - preventDefault: function() { this.returnValue = false }, - inspect: function() { return '[object Event]' } - }); - - Event.extend = function(event, element) { - if (!event) return false; - if (event._extendedByPrototype) return event; - - event._extendedByPrototype = Prototype.emptyFunction; - var pointer = Event.pointer(event); - - Object.extend(event, { - target: event.srcElement || element, - relatedTarget: _relatedTarget(event), - pageX: pointer.x, - pageY: pointer.y - }); - - return Object.extend(event, methods); - }; - } else { - Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; - Object.extend(Event.prototype, methods); - Event.extend = Prototype.K; - } - - function _createResponder(element, eventName, handler) { - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) { - CACHE.push(element); - registry = Element.retrieve(element, 'prototype_event_registry', $H()); - } - - var respondersForEvent = registry.get(eventName); - if (Object.isUndefined(respondersForEvent)) { - respondersForEvent = []; - registry.set(eventName, respondersForEvent); - } - - if (respondersForEvent.pluck('handler').include(handler)) return false; - - var responder; - if (eventName.include(":")) { - responder = function(event) { - if (Object.isUndefined(event.eventName)) - return false; - - if (event.eventName !== eventName) - return false; - - Event.extend(event, element); - handler.call(element, event); - }; - } else { - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && - (eventName === "mouseenter" || eventName === "mouseleave")) { - if (eventName === "mouseenter" || eventName === "mouseleave") { - responder = function(event) { - Event.extend(event, element); - - var parent = event.relatedTarget; - while (parent && parent !== element) { - try { parent = parent.parentNode; } - catch(e) { parent = element; } - } - - if (parent === element) return; - - handler.call(element, event); - }; - } - } else { - responder = function(event) { - Event.extend(event, element); - handler.call(element, event); - }; - } - } - - responder.handler = handler; - respondersForEvent.push(responder); - return responder; - } - - function _destroyCache() { - for (var i = 0, length = CACHE.length; i < length; i++) { - Event.stopObserving(CACHE[i]); - CACHE[i] = null; - } - } - - var CACHE = []; - - if (Prototype.Browser.IE) - window.attachEvent('onunload', _destroyCache); - - if (Prototype.Browser.WebKit) - window.addEventListener('unload', Prototype.emptyFunction, false); - - - var _getDOMEventName = Prototype.K; - - if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { - _getDOMEventName = function(eventName) { - var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; - return eventName in translations ? translations[eventName] : eventName; - }; - } - - function observe(element, eventName, handler) { - element = $(element); - - var responder = _createResponder(element, eventName, handler); - - if (!responder) return element; - - if (eventName.include(':')) { - if (element.addEventListener) - element.addEventListener("dataavailable", responder, false); - else { - element.attachEvent("ondataavailable", responder); - element.attachEvent("onfilterchange", responder); - } - } else { - var actualEventName = _getDOMEventName(eventName); - - if (element.addEventListener) - element.addEventListener(actualEventName, responder, false); - else - element.attachEvent("on" + actualEventName, responder); - } - - return element; - } - - function stopObserving(element, eventName, handler) { - element = $(element); - - var registry = Element.retrieve(element, 'prototype_event_registry'); - - if (Object.isUndefined(registry)) return element; - - if (eventName && !handler) { - var responders = registry.get(eventName); - - if (Object.isUndefined(responders)) return element; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - return element; - } else if (!eventName) { - registry.each( function(pair) { - var eventName = pair.key, responders = pair.value; - - responders.each( function(r) { - Element.stopObserving(element, eventName, r.handler); - }); - }); - return element; - } - - var responders = registry.get(eventName); - - if (!responders) return; - - var responder = responders.find( function(r) { return r.handler === handler; }); - if (!responder) return element; - - var actualEventName = _getDOMEventName(eventName); - - if (eventName.include(':')) { - if (element.removeEventListener) - element.removeEventListener("dataavailable", responder, false); - else { - element.detachEvent("ondataavailable", responder); - element.detachEvent("onfilterchange", responder); - } - } else { - if (element.removeEventListener) - element.removeEventListener(actualEventName, responder, false); - else - element.detachEvent('on' + actualEventName, responder); - } - - registry.set(eventName, responders.without(responder)); - - return element; - } - - function fire(element, eventName, memo, bubble) { - element = $(element); - - if (Object.isUndefined(bubble)) - bubble = true; - - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent('HTMLEvents'); - event.initEvent('dataavailable', true, true); - } else { - event = document.createEventObject(); - event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) - element.dispatchEvent(event); - else - element.fireEvent(event.eventType, event); - - return Event.extend(event); - } - - - Object.extend(Event, Event.Methods); - - Object.extend(Event, { - fire: fire, - observe: observe, - stopObserving: stopObserving - }); - - Element.addMethods({ - fire: fire, - - observe: observe, - - stopObserving: stopObserving - }); - - Object.extend(document, { - fire: fire.methodize(), - - observe: observe.methodize(), - - stopObserving: stopObserving.methodize(), - - loaded: false - }); - - if (window.Event) Object.extend(window.Event, Event); - else window.Event = Event; -})(); - -(function() { - /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ - - var timer; - - function fireContentLoadedEvent() { - if (document.loaded) return; - if (timer) window.clearTimeout(timer); - document.loaded = true; - document.fire('dom:loaded'); - } - - function checkReadyState() { - if (document.readyState === 'complete') { - document.stopObserving('readystatechange', checkReadyState); - fireContentLoadedEvent(); - } - } - - function pollDoScroll() { - try { document.documentElement.doScroll('left'); } - catch(e) { - timer = pollDoScroll.defer(); - return; - } - fireContentLoadedEvent(); - } - - if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); - } else { - document.observe('readystatechange', checkReadyState); - if (window == top) - timer = pollDoScroll.defer(); - } - - Event.observe(window, 'load', fireContentLoadedEvent); -})(); - -Element.addMethods(); - -/*------------------------------- DEPRECATED -------------------------------*/ - -Hash.toQueryString = Object.toQueryString; - -var Toggle = { display: Element.toggle }; - -Element.Methods.childOf = Element.Methods.descendantOf; - -var Insertion = { - Before: function(element, content) { - return Element.insert(element, {before:content}); - }, - - Top: function(element, content) { - return Element.insert(element, {top:content}); - }, - - Bottom: function(element, content) { - return Element.insert(element, {bottom:content}); - }, - - After: function(element, content) { - return Element.insert(element, {after:content}); - } -}; - -var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); - -var Position = { - includeScrollOffsets: false, - - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = Element.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = Element.cumulativeScrollOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = Element.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - - cumulativeOffset: Element.Methods.cumulativeOffset, - - positionedOffset: Element.Methods.positionedOffset, - - absolutize: function(element) { - Position.prepare(); - return Element.absolutize(element); - }, - - relativize: function(element) { - Position.prepare(); - return Element.relativize(element); - }, - - realOffset: Element.Methods.cumulativeScrollOffset, - - offsetParent: Element.Methods.getOffsetParent, - - page: Element.Methods.viewportOffset, - - clone: function(source, target, options) { - options = options || { }; - return Element.clonePosition(target, source, options); - } -}; - -/*--------------------------------------------------------------------------*/ - -if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ - function iter(name) { - return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; - } - - instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? - function(element, className) { - className = className.toString().strip(); - var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); - return cond ? document._getElementsByXPath('.//*' + cond, element) : []; - } : function(element, className) { - className = className.toString().strip(); - var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); - if (!classNames && !className) return elements; - - var nodes = $(element).getElementsByTagName('*'); - className = ' ' + className + ' '; - - for (var i = 0, child, cn; child = nodes[i]; i++) { - if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || - (classNames && classNames.all(function(name) { - return !name.toString().blank() && cn.include(' ' + name + ' '); - })))) - elements.push(Element.extend(child)); - } - return elements; - }; - - return function(className, parentElement) { - return $(parentElement || document.body).getElementsByClassName(className); - }; -}(Element.Methods); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set($A(this).concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set($A(this).without(classNameToRemove).join(' ')); - }, - - toString: function() { - return $A(this).join(' '); - } -}; - -Object.extend(Element.ClassNames.prototype, Enumerable); - -/*--------------------------------------------------------------------------*/ diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/rails.js ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/rails.js --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/javascripts/rails.js 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/javascripts/rails.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,118 +0,0 @@ -document.observe("dom:loaded", function() { - function handleRemote(element) { - var method, url, params; - - if (element.tagName.toLowerCase() === 'form') { - method = element.readAttribute('method') || 'post'; - url = element.readAttribute('action'); - params = element.serialize(true); - } else { - method = element.readAttribute('data-method') || 'get'; - url = element.readAttribute('href'); - params = {}; - } - - var event = element.fire("ajax:before"); - if (event.stopped) return false; - - new Ajax.Request(url, { - method: method, - parameters: params, - asynchronous: true, - evalScripts: true, - - onLoading: function(request) { element.fire("ajax:loading", {request: request}); }, - onLoaded: function(request) { element.fire("ajax:loaded", {request: request}); }, - onInteractive: function(request) { element.fire("ajax:interactive", {request: request}); }, - onComplete: function(request) { element.fire("ajax:complete", {request: request}); }, - onSuccess: function(request) { element.fire("ajax:success", {request: request}); }, - onFailure: function(request) { element.fire("ajax:failure", {request: request}); } - }); - - element.fire("ajax:after"); - } - - function handleMethod(element) { - var method, url, token_name, token; - - method = element.readAttribute('data-method'); - url = element.readAttribute('href'); - csrf_param = $$('meta[name=csrf-param]').first(); - csrf_token = $$('meta[name=csrf-token]').first(); - - var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); - element.parentNode.appendChild(form); - - if (method != 'post') { - var field = new Element('input', { type: 'hidden', name: '_method', value: method }); - form.appendChild(field); - } - - if (csrf_param) { - var param = csrf_param.readAttribute('content'); - var token = csrf_token.readAttribute('content'); - var field = new Element('input', { type: 'hidden', name: param, value: token }); - form.appendChild(field); - } - - form.submit(); - } - - $(document.body).observe("click", function(event) { - var message = event.findElement().readAttribute('data-confirm'); - if (message && !confirm(message)) { - event.stop(); - return false; - } - - var element = event.findElement("a[data-remote]"); - if (element) { - handleRemote(element); - event.stop(); - return true; - } - - var element = event.findElement("a[data-method]"); - if (element) { - handleMethod(element); - event.stop(); - return true; - } - }); - - // TODO: I don't think submit bubbles in IE - $(document.body).observe("submit", function(event) { - var element = event.findElement(), - message = element.readAttribute('data-confirm'); - if (message && !confirm(message)) { - event.stop(); - return false; - } - - var inputs = element.select("input[type=submit][data-disable-with]"); - inputs.each(function(input) { - input.disabled = true; - input.writeAttribute('data-original-value', input.value); - input.value = input.readAttribute('data-disable-with'); - }); - - var element = event.findElement("form[data-remote]"); - if (element) { - handleRemote(element); - event.stop(); - } - }); - - $(document.body).observe("ajax:after", function(event) { - var element = event.findElement(); - - if (element.tagName.toLowerCase() === 'form') { - var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); - inputs.each(function(input) { - input.value = input.readAttribute('data-original-value'); - input.writeAttribute('data-original-value', null); - input.disabled = false; - }); - } - }); -}); \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/robots.txt ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/robots.txt --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/public/robots.txt 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/public/robots.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file -# -# To ban all spiders from the entire site uncomment the next two lines: -# User-Agent: * -# Disallow: / diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/Rakefile ruby-shoulda-matchers-2.8.0/spec/rails3_root/Rakefile --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/Rakefile 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/Rakefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -# Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. - -require File.expand_path('../config/application', __FILE__) - -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' - -Rails::Application.load_tasks diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/README ruby-shoulda-matchers-2.8.0/spec/rails3_root/README --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/README 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,244 +0,0 @@ -== Welcome to Rails - -Rails is a web-application framework that includes everything needed to create -database-backed web applications according to the Model-View-Control pattern. - -This pattern splits the view (also called the presentation) into "dumb" templates -that are primarily responsible for inserting pre-built data in between HTML tags. -The model contains the "smart" domain objects (such as Account, Product, Person, -Post) that holds all the business logic and knows how to persist themselves to -a database. The controller handles the incoming requests (such as Save New Account, -Update Product, Show Post) by manipulating the model and directing data to the view. - -In Rails, the model is handled by what's called an object-relational mapping -layer entitled Active Record. This layer allows you to present the data from -database rows as objects and embellish these data objects with business logic -methods. You can read more about Active Record in -link:files/vendor/rails/activerecord/README.html. - -The controller and view are handled by the Action Pack, which handles both -layers by its two parts: Action View and Action Controller. These two layers -are bundled in a single package due to their heavy interdependence. This is -unlike the relationship between the Active Record and Action Pack that is much -more separate. Each of these packages can be used independently outside of -Rails. You can read more about Action Pack in -link:files/vendor/rails/actionpack/README.html. - - -== Getting Started - -1. At the command prompt, start a new Rails application using the rails command - and your application name. Ex: rails myapp -2. Change directory into myapp and start the web server: rails server (run with --help for options) -3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!" -4. Follow the guidelines to start developing your application - - -== Web Servers - -By default, Rails will try to use Mongrel if it's installed when started with rails server, otherwise -Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails -with a variety of other web servers. - -Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is -suitable for development and deployment of Rails applications. If you have Ruby Gems installed, -getting up and running with mongrel is as easy as: gem install mongrel. -More info at: http://mongrel.rubyforge.org - -Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or -Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use -FCGI or proxy to a pack of Mongrels/Thin/Ebb servers. - -== Apache .htaccess example for FCGI/CGI - -# General Apache options -AddHandler fastcgi-script .fcgi -AddHandler cgi-script .cgi -Options +FollowSymLinks +ExecCGI - -# If you don't want Rails to look in certain directories, -# use the following rewrite rules so that Apache won't rewrite certain requests -# -# Example: -# RewriteCond %{REQUEST_URI} ^/notrails.* -# RewriteRule .* - [L] - -# Redirect all requests not available on the filesystem to Rails -# By default the cgi dispatcher is used which is very slow -# -# For better performance replace the dispatcher with the fastcgi one -# -# Example: -# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] -RewriteEngine On - -# If your Rails application is accessed via an Alias directive, -# then you MUST also set the RewriteBase in this htaccess file. -# -# Example: -# Alias /myrailsapp /path/to/myrailsapp/public -# RewriteBase /myrailsapp - -RewriteRule ^$ index.html [QSA] -RewriteRule ^([^.]+)$ $1.html [QSA] -RewriteCond %{REQUEST_FILENAME} !-f -RewriteRule ^(.*)$ dispatch.cgi [QSA,L] - -# In case Rails experiences terminal errors -# Instead of displaying this message you can supply a file here which will be rendered instead -# -# Example: -# ErrorDocument 500 /500.html - -ErrorDocument 500 "

    Application error

    Rails application failed to start properly" - - -== Debugging Rails - -Sometimes your application goes wrong. Fortunately there are a lot of tools that -will help you debug it and get it back on the rails. - -First area to check is the application log files. Have "tail -f" commands running -on the server.log and development.log. Rails will automatically display debugging -and runtime information to these files. Debugging info will also be shown in the -browser on requests from 127.0.0.1. - -You can also log your own messages directly into the log file from your code using -the Ruby logger class from inside your controllers. Example: - - class WeblogController < ActionController::Base - def destroy - @weblog = Weblog.find(params[:id]) - @weblog.destroy - logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") - end - end - -The result will be a message in your log file along the lines of: - - Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1 - -More information on how to use the logger is at http://www.ruby-doc.org/core/ - -Also, Ruby documentation can be found at http://www.ruby-lang.org/ including: - -* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/ -* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) - -These two online (and free) books will bring you up to speed on the Ruby language -and also on programming in general. - - -== Debugger - -Debugger support is available through the debugger command when you start your Mongrel or -Webrick server with --debugger. This means that you can break out of execution at any point -in the code, investigate and change the model, AND then resume execution! -You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug' -Example: - - class WeblogController < ActionController::Base - def index - @posts = Post.find(:all) - debugger - end - end - -So the controller will accept the action, run the first line, then present you -with a IRB prompt in the server window. Here you can do things like: - - >> @posts.inspect - => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>, - #\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]" - >> @posts.first.title = "hello from a debugger" - => "hello from a debugger" - -...and even better is that you can examine how your runtime objects actually work: - - >> f = @posts.first - => #nil, "body"=>nil, "id"=>"1"}> - >> f. - Display all 152 possibilities? (y or n) - -Finally, when you're ready to resume execution, you enter "cont" - - -== Console - -You can interact with the domain model by starting the console through rails console. -Here you'll have all parts of the application configured, just like it is when the -application is running. You can inspect domain models, change values, and save to the -database. Starting the script without arguments will launch it in the development environment. -Passing an argument will specify a different environment, like rails console production. - -To reload your controllers and models after launching the console run reload! - -== dbconsole - -You can go to the command line of your database directly through rails dbconsole. -You would be connected to the database with the credentials defined in database.yml. -Starting the script without arguments will connect you to the development database. Passing an -argument will connect you to a different database, like rails dbconsole production. -Currently works for mysql, postgresql and sqlite. - -== Description of Contents - -app - Holds all the code that's specific to this particular application. - -app/controllers - Holds controllers that should be named like weblogs_controller.rb for - automated URL mapping. All controllers should descend from ApplicationController - which itself descends from ActionController::Base. - -app/models - Holds models that should be named like post.rb. - Most models will descend from ActiveRecord::Base. - -app/views - Holds the template files for the view that should be named like - weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby - syntax. - -app/views/layouts - Holds the template files for layouts to be used with views. This models the common - header/footer method of wrapping views. In your views, define a layout using the - layout :default and create a file named default.html.erb. Inside default.html.erb, - call <% yield %> to render the view using this layout. - -app/helpers - Holds view helpers that should be named like weblogs_helper.rb. These are generated - for you automatically when using rails generate for controllers. Helpers can be used to - wrap functionality for your views into methods. - -config - Configuration files for the Rails environment, the routing map, the database, and other dependencies. - -db - Contains the database schema in schema.rb. db/migrate contains all - the sequence of Migrations for your schema. - -doc - This directory is where your application documentation will be stored when generated - using rake doc:app - -lib - Application specific libraries. Basically, any kind of custom code that doesn't - belong under controllers, models, or helpers. This directory is in the load path. - -public - The directory available for the web server. Contains subdirectories for images, stylesheets, - and javascripts. Also contains the dispatchers and the default HTML files. This should be - set as the DOCUMENT_ROOT of your web server. - -script - Helper scripts for automation and generation. - -test - Unit and functional tests along with fixtures. When using the rails generate command, template - test files will be generated for you and placed in this directory. - -vendor - External libraries that the application depends on. Also includes the plugins subdirectory. - If the app has frozen rails, those gems also go here, under vendor/rails/. - This directory is in the load path. diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/script/rails ruby-shoulda-matchers-2.8.0/spec/rails3_root/script/rails --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/script/rails 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/script/rails 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -#!/usr/bin/env ruby -# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. - -ENV_PATH = File.expand_path('../../config/environment', __FILE__) -BOOT_PATH = File.expand_path('../../config/boot', __FILE__) -APP_PATH = File.expand_path('../../config/application', __FILE__) - -require BOOT_PATH -require 'rails/commands' diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/performance/browsing_test.rb ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/performance/browsing_test.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/performance/browsing_test.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/performance/browsing_test.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,9 +0,0 @@ -require 'test_helper' -require 'rails/performance_test_help' - -# Profiling results for each test method are written to tmp/performance. -class BrowsingTest < ActionDispatch::PerformanceTest - def test_homepage - get '/' - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/shoulda_macros/custom_macro.rb ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/shoulda_macros/custom_macro.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/shoulda_macros/custom_macro.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/shoulda_macros/custom_macro.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -module CustomMacro - def custom_macro - end -end -ActiveSupport::TestCase.extend(CustomMacro) - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/test_helper.rb ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/test_helper.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/test/test_helper.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/test/test_helper.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -ENV["RAILS_ENV"] = "test" -require File.expand_path('../../config/environment', __FILE__) -require 'rails/test_help' - -class ActiveSupport::TestCase - # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. - # - # Note: You'll currently still have to declare fixtures explicitly in integration tests - # -- they do not yet inherit this setting - fixtures :all - - # Add more helper methods to be used by all tests here... -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb ruby-shoulda-matchers-2.8.0/spec/rails3_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -module GemMacro - def gem_macro - end -end -ActiveSupport::TestCase.extend(GemMacro) - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb ruby-shoulda-matchers-2.8.0/spec/rails3_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/rails3_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/rails3_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -module PluginMacro - def plugin_macro - end -end -ActiveSupport::TestCase.extend(PluginMacro) - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/report_warnings.rb ruby-shoulda-matchers-2.8.0/spec/report_warnings.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/report_warnings.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/report_warnings.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,7 @@ +require File.expand_path('../warnings_spy', __FILE__) + +# Adapted from + +warnings_spy = WarningsSpy.new('shoulda-matchers') +warnings_spy.capture_warnings +warnings_spy.report_warnings_at_exit diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/assign_to_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/assign_to_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/assign_to_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/assign_to_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,55 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::AssignToMatcher do - - context "a controller that assigns to an instance variable" do - before do - @controller = build_response { @var = 'value' } - end - - it "should accept assigning to that variable" do - @controller.should assign_to(:var) - end - - it "should accept assigning to that variable with the correct class" do - @controller.should assign_to(:var).with_kind_of(String) - end - - it "should reject assigning to that variable with another class" do - @controller.should_not assign_to(:var).with_kind_of(Fixnum) - end - - it "should accept assigning the correct value to that variable" do - @controller.should assign_to(:var).with('value') - end - - it "should reject assigning another value to that variable" do - @controller.should_not assign_to(:var).with('other') - end - - it "should reject assigning to another variable" do - @controller.should_not assign_to(:other) - end - - it "should accept assigning to the same value in the test context" do - @expected = 'value' - @controller.should assign_to(:var).in_context(self).with { @expected } - end - - it "should reject assigning to the another value in the test context" do - @expected = 'other' - @controller.should_not assign_to(:var).in_context(self).with { @expected } - end - end - - context "a controller that assigns a nil value to an instance variable" do - before do - @controller = build_response { @var = nil } - end - - it "should accept assigning to that variable" do - @controller.should assign_to(:var) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/filter_param_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/filter_param_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/filter_param_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/filter_param_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::FilterParamMatcher do - - context "given parameter filters" do - before do - Rails.application.config.filter_parameters = [:secret] - end - - it "should accept filtering that parameter" do - nil.should filter_param(:secret) - end - - it "should reject filtering another parameter" do - matcher = filter_param(:other) - matcher.matches?(nil).should be_false - matcher.failure_message.should include("Expected other to be filtered") - matcher.failure_message.should =~ /secret/ - end - end - -end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/redirect_to_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/redirect_to_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/redirect_to_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/redirect_to_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RedirectToMatcher do - context "a controller that redirects" do - before do - @controller = build_response { redirect_to '/some/url' } - end - - it "accepts redirecting to that url" do - @controller.should redirect_to('/some/url') - end - - it "rejects redirecting to a different url" do - @controller.should_not redirect_to('/some/other/url') - end - - it "accepts redirecting to that url in a block" do - @controller.should redirect_to('somewhere') { '/some/url' } - end - - it "rejects redirecting to a different url in a block" do - @controller.should_not redirect_to('somewhere else') { '/some/other/url' } - end - end - - context "a controller that doesn't redirect" do - before do - @controller = build_response { render :text => 'hello' } - end - - it "rejects redirecting to a url" do - @controller.should_not redirect_to('/some/url') - end - end - - it "provides the correct description when provided a block" do - matcher = redirect_to('somewhere else') { '/some/other/url' } - matcher.description.should == 'redirect to somewhere else' - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/render_template_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/render_template_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/render_template_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/render_template_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RenderTemplateMatcher do - include ActionController::TemplateAssertions - - context "a controller that renders a template" do - before do - @controller = build_response(:action => 'show') { render } - end - - it "should accept rendering that template" do - @controller.should render_template(:show) - end - - it "should reject rendering a different template" do - @controller.should_not render_template(:index) - end - - it "should accept rendering that template in the given context" do - @controller.should render_template(:show).in_context(self) - end - - it "should reject rendering a different template in the given context" do - @controller.should_not render_template(:index).in_context(self) - end - end - - context "a controller that doesn't render a template" do - before do - @controller = build_response { render :nothing => true } - end - - it "should reject rendering a template" do - @controller.should_not render_template(:show) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/render_with_layout_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RenderWithLayoutMatcher do - include ActionController::TemplateAssertions - - context "a controller that renders with a layout" do - before do - create_view('layouts/wide.html.erb', 'some content, <%= yield %>') - @controller = build_response { render :layout => 'wide' } - end - - it "should accept rendering with any layout" do - @controller.should render_with_layout - end - - it "should accept rendering with that layout" do - @controller.should render_with_layout(:wide) - end - - it "should reject rendering with another layout" do - @controller.should_not render_with_layout(:other) - end - end - - context "a controller that renders without a layout" do - before do - @controller = build_response { render :layout => false } - end - - it "should reject rendering with a layout" do - @controller.should_not render_with_layout - end - end - - context "given a context with layouts" do - before do - @layout = 'happy' - @controller = build_response { render :layout => false } - @layouts = Hash.new(0) - @layouts[@layout] = 1 - end - - it "should accept that layout in that context" do - @controller.should render_with_layout(@layout).in_context(self) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/respond_with_content_type_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RespondWithContentTypeMatcher do - - context "a controller responding with content type :xml" do - before do - @controller = build_response { render :xml => { :user => "thoughtbot" }.to_xml } - end - - it "should accept responding with content type :xml" do - @controller.should respond_with_content_type(:xml) - end - - it "should accept responding with content type 'application/xml'" do - @controller.should respond_with_content_type('application/xml') - end - - it "should accept responding with content type /xml/" do - @controller.should respond_with_content_type(/xml/) - end - - it "should reject responding with another content type" do - @controller.should_not respond_with_content_type(:json) - end - end - - it "should generate the correct test name" do - respond_with_content_type(:xml).description. - should == "respond with content type of application/xml" - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/respond_with_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/respond_with_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/respond_with_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/respond_with_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,96 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RespondWithMatcher do - - context "a controller responding with success" do - before do - @controller = build_response { render :text => "text", :status => 200 } - end - - it "should accept responding with 200" do - @controller.should respond_with(200) - end - - it "should accept responding with :success" do - @controller.should respond_with(:success) - end - - it "should reject responding with another status" do - @controller.should_not respond_with(:error) - end - end - - context "a controller responding with redirect" do - before do - @controller = build_response { render :text => "text", :status => 301 } - end - - it "should accept responding with 301" do - @controller.should respond_with(301) - end - - it "should accept responding with :redirect" do - @controller.should respond_with(:redirect) - end - - it "should reject responding with another status" do - @controller.should_not respond_with(:error) - end - end - - context "a controller responding with missing" do - before do - @controller = build_response { render :text => "text", :status => 404 } - end - - it "should accept responding with 404" do - @controller.should respond_with(404) - end - - it "should accept responding with :missing" do - @controller.should respond_with(:missing) - end - - it "should reject responding with another status" do - @controller.should_not respond_with(:success) - end - end - - context "a controller responding with error" do - before do - @controller = build_response { render :text => "text", :status => 500 } - end - - it "should accept responding with 500" do - @controller.should respond_with(500) - end - - it "should accept responding with :error" do - @controller.should respond_with(:error) - end - - it "should reject responding with another status" do - @controller.should_not respond_with(:success) - end - end - - context "a controller responding with not implemented" do - before do - @controller = build_response { render :text => "text", :status => 501 } - end - - it "should accept responding with 501" do - @controller.should respond_with(501) - end - - it "should accept responding with :not_implemented" do - @controller.should respond_with(:not_implemented) - end - - it "should reject responding with another status" do - @controller.should_not respond_with(:success) - end - end - -end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/route_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/route_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/route_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/route_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::RouteMatcher do - - context "given a controller with a defined glob url" do - before do - @controller = define_controller('Examples').new - define_routes do - match 'examples/*id', :to => 'examples#example' - end - end - - it "should accept glob route" do - @controller.should route(:get, '/examples/foo/bar'). - to(:action => 'example', :id => 'foo/bar') - end - - end - - context "given a controller with a defined route" do - before do - @controller = define_controller('Examples').new - define_routes do - match 'examples/:id', :to => 'examples#example' - end - end - - it "should accept routing the correct path to the correct parameters" do - @controller.should route(:get, '/examples/1'). - to(:action => 'example', :id => '1') - end - - it "should accept a symbol controller" do - Object.new.should route(:get, '/examples/1'). - to(:controller => :examples, - :action => 'example', - :id => '1') - end - - it "should accept a symbol action" do - @controller.should route(:get, '/examples/1'). - to(:action => :example, :id => '1') - end - - it "should accept a non-string parameter" do - @controller.should route(:get, '/examples/1'). - to(:action => 'example', :id => 1) - end - - it "should reject an undefined route" do - @controller.should_not route(:get, '/bad_route').to(:var => 'value') - end - - it "should reject a route for another controller" do - @other = define_controller('Other').new - @other.should_not route(:get, '/examples/1'). - to(:action => 'example', :id => '1') - end - - it "should reject a route for different parameters" do - @controller.should_not route(:get, '/examples/1'). - to(:action => 'other', :id => '1') - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/set_session_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/set_session_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/set_session_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/set_session_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::SetSessionMatcher do - - context "a controller that sets a session variable" do - before do - @controller = build_response do - session[:var] = 'value' - session[:false_var] = false - end - end - - it "should accept assigning to that variable" do - @controller.should set_session(:var) - end - - it "should accept assigning the correct value to that variable" do - @controller.should set_session(:var).to('value') - end - - it "should reject assigning another value to that variable" do - @controller.should_not set_session(:var).to('other') - end - - it "should reject assigning to another variable" do - @controller.should_not set_session(:other) - end - - it "should accept assigning nil to another variable" do - @controller.should set_session(:other).to(nil) - end - - it "should accept assigning false to that variable" do - @controller.should set_session(:false_var).to(false) - end - - it "should accept assigning to the same value in the test context" do - @expected = 'value' - @controller.should set_session(:var).in_context(self).to { @expected } - end - - it "should reject assigning to the another value in the test context" do - @expected = 'other' - @controller.should_not set_session(:var).in_context(self).to { @expected } - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_controller/set_the_flash_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionController::SetTheFlashMatcher do - - context "a controller that sets a flash message" do - before do - @controller = build_response { flash[:notice] = 'value' } - end - - it "should accept setting any flash message" do - @controller.should set_the_flash - end - - it "should accept setting the exact flash message" do - @controller.should set_the_flash.to('value') - end - - it "should accept setting a matched flash message" do - @controller.should set_the_flash.to(/value/) - end - - it "should reject setting a different flash message" do - @controller.should_not set_the_flash.to('other') - end - - it "should reject setting a different pattern" do - @controller.should_not set_the_flash.to(/other/) - end - end - - context "a controller that sets a flash.now message" do - before do - @controller = build_response { flash.now[:notice] = 'value' } - end - - it "should reject setting any flash message" do - @controller.should_not set_the_flash - end - - it "should accept setting any flash.now message" do - @controller.should set_the_flash.now - end - - it "should accept setting the exact flash.now message" do - @controller.should set_the_flash.to('value').now - end - - it "should accept setting a matched flash.now message" do - @controller.should set_the_flash.to(/value/).now - end - - it "should reject setting a different flash.now message" do - @controller.should_not set_the_flash.to('other').now - end - - it "should reject setting a different flash.now pattern" do - @controller.should_not set_the_flash.to(/other/).now - end - end - - context "a controller that sets multiple flash messages" do - before do - @controller = build_response { - flash.now[:notice] = 'value' - flash[:success] = 'great job' - } - end - - it "should accept setting any flash.now message" do - @controller.should set_the_flash.now - @controller.should set_the_flash - end - - it "should accept setting a matched flash.now message" do - @controller.should set_the_flash.to(/value/).now - @controller.should set_the_flash.to(/great/) - end - - it "should reject setting a different flash.now message" do - @controller.should_not set_the_flash.to('other').now - @controller.should_not set_the_flash.to('other') - end - end - - context "a controller that doesn't set a flash message" do - before do - @controller = build_response - end - - it "should reject setting any flash message" do - @controller.should_not set_the_flash - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_mailer/have_sent_email_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/action_mailer/have_sent_email_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/action_mailer/have_sent_email_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/action_mailer/have_sent_email_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,84 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActionMailer::HaveSentEmailMatcher do - def add_mail_to_deliveries - ::ActionMailer::Base.deliveries << Mailer.the_email - end - - context "an email" do - before do - define_mailer :mailer, [:the_email] do - def the_email - mail :from => "do-not-reply@example.com", - :to => "myself@me.com", - :subject => "This is spam", - :body => "Every email is spam." - end - end - add_mail_to_deliveries - end - - after { ::ActionMailer::Base.deliveries.clear } - - it "accepts sent e-mail based on the subject" do - should have_sent_email.with_subject(/is spam$/) - matcher = have_sent_email.with_subject(/totally safe/) - matcher.matches?(nil) - matcher.failure_message.should =~ /Expected sent email with subject/ - end - - it "accepts sent e-mail based on a string sender" do - should have_sent_email.from('do-not-reply@example.com') - matcher = have_sent_email.from('you@example.com') - matcher.matches?(nil) - matcher.failure_message.should =~ /Expected sent email from/ - end - - it "accepts sent e-mail based on a regexp sender" do - should have_sent_email.from(/@example\.com/) - matcher = have_sent_email.from(/you@/) - matcher.matches?(nil) - matcher.failure_message.should =~ /Expected sent email from/ - end - - it "accepts sent e-mail based on the body" do - should have_sent_email.with_body(/is spam\./) - matcher = have_sent_email.with_body(/totally safe/) - matcher.matches?(nil) - matcher.failure_message.should =~ /Expected sent email with body/ - end - - it "accept sent e-mail based on the recipient" do - should have_sent_email.to('myself@me.com') - matcher = have_sent_email.to('you@example.com') - matcher.matches?(nil) - matcher.failure_message.should =~ /Expected sent email to/ - end - - it "lists all the deliveries within failure message" do - add_mail_to_deliveries - - matcher = have_sent_email.to('you@example.com') - matcher.matches?(nil) - matcher.failure_message.should =~ /Deliveries:\n"This is spam" to \["myself@me\.com"\]\n"This is spam" to \["myself@me\.com"\]/ - end - - it "allows chaining" do - should have_sent_email.with_subject(/spam/).from('do-not-reply@example.com').with_body(/spam/).to('myself@me.com') - should_not have_sent_email.with_subject(/ham/).from('you@example.com').with_body(/ham/).to('them@example.com') - end - end - - it "provides a detailed description of the e-mail expected to be sent" do - matcher = have_sent_email - matcher.description.should == 'send an email' - matcher = matcher.with_subject("Welcome!") - matcher.description.should == 'send an email with a subject of "Welcome!"' - matcher = matcher.with_body("Welcome, human!") - matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!"' - matcher = matcher.from("alien@example.com") - matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" from "alien@example.com"' - matcher = matcher.to("human@example.com") - matcher.description.should == 'send an email with a subject of "Welcome!" containing "Welcome, human!" from "alien@example.com" to "human@example.com"' - end -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/allow_mass_assignment_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/allow_mass_assignment_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/allow_mass_assignment_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/allow_mass_assignment_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::AllowMassAssignmentOfMatcher do - - context "an attribute that is blacklisted from mass-assignment" do - before do - define_model :example, :attr => :string do - attr_protected :attr - end - @model = Example.new - end - - it "should reject being mass-assignable" do - @model.should_not allow_mass_assignment_of(:attr) - end - end - - context "an attribute that is not whitelisted for mass-assignment" do - before do - define_model :example, :attr => :string, :other => :string do - attr_accessible :other - end - @model = Example.new - end - - it "should reject being mass-assignable" do - @model.should_not allow_mass_assignment_of(:attr) - end - end - - context "an attribute that is whitelisted for mass-assignment" do - before do - define_model :example, :attr => :string do - attr_accessible :attr - end - @model = Example.new - end - - it "should accept being mass-assignable" do - @model.should allow_mass_assignment_of(:attr) - end - end - - context "an attribute not included in the mass-assignment blacklist" do - before do - define_model :example, :attr => :string, :other => :string do - attr_protected :other - end - @model = Example.new - end - - it "should accept being mass-assignable" do - @model.should allow_mass_assignment_of(:attr) - end - end - - context "an attribute on a class with no protected attributes" do - before do - define_model :example, :attr => :string - @model = Example.new - end - - it "should accept being mass-assignable" do - @model.should allow_mass_assignment_of(:attr) - end - - it "should assign a negative failure message" do - matcher = allow_mass_assignment_of(:attr) - matcher.matches?(@model).should == true - matcher.negative_failure_message.should_not be_nil - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/allow_value_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/allow_value_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/allow_value_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/allow_value_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::AllowValueMatcher do - - context "an attribute with a format validation" do - before do - define_model :example, :attr => :string do - validates_format_of :attr, :with => /abc/ - end - @model = Example.new - end - - it "should allow a good value" do - @model.should allow_value("abcde").for(:attr) - end - - it "should not allow a bad value" do - @model.should_not allow_value("xyz").for(:attr) - end - end - - context "an attribute with a format validation and a custom message" do - before do - define_model :example, :attr => :string do - validates_format_of :attr, :with => /abc/, :message => 'bad value' - end - @model = Example.new - end - - it "should allow a good value" do - @model.should allow_value('abcde').for(:attr).with_message(/bad/) - end - - it "should not allow a bad value" do - @model.should_not allow_value('xyz').for(:attr).with_message(/bad/) - end - end - - context "an attribute with several validations" do - before do - define_model :example, :attr => :string do - validates_presence_of :attr - validates_length_of :attr, :within => 1..5 - validates_numericality_of :attr, :greater_than_or_equal_to => 1, - :less_than_or_equal_to => 50000 - end - @model = Example.new - end - - it "should allow a good value" do - @model.should allow_value("12345").for(:attr) - end - - bad_values = [nil, "", "abc", "0", "50001", "123456"] - bad_values.each do |value| - it "should not allow a bad value (#{value.inspect})" do - @model.should_not allow_value(value).for(:attr) - end - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/association_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/association_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/association_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/association_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,261 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::AssociationMatcher do - - context "belong_to" do - before do - @matcher = belong_to(:parent) - end - - it "should accept a good association with the default foreign key" do - define_model :parent - define_model :child, :parent_id => :integer do - belongs_to :parent - end - Child.new.should @matcher - end - - it "should reject a nonexistent association" do - define_model :child - Child.new.should_not @matcher - end - - it "should reject an association of the wrong type" do - define_model :parent, :child_id => :integer - child_class = define_model :child do - has_one :parent - end - Child.new.should_not @matcher - end - - it "should reject an association that has a nonexistent foreign key" do - define_model :parent - define_model :child do - belongs_to :parent - end - Child.new.should_not @matcher - end - - it "should accept an association with an existing custom foreign key" do - define_model :parent - define_model :child, :guardian_id => :integer do - belongs_to :parent, :foreign_key => 'guardian_id' - end - Child.new.should @matcher - end - - it "should accept a polymorphic association" do - define_model :child, :parent_type => :string, - :parent_id => :integer do - belongs_to :parent, :polymorphic => true - end - Child.new.should @matcher - end - - it "should accept an association with a valid :dependent option" do - define_model :parent - define_model :child, :parent_id => :integer do - belongs_to :parent, :dependent => :destroy - end - Child.new.should @matcher.dependent(:destroy) - end - - it "should reject an association with a bad :dependent option" do - define_model :parent - define_model :child, :parent_id => :integer do - belongs_to :parent - end - Child.new.should_not @matcher.dependent(:destroy) - end - end - - context "have_many" do - before do - @matcher = have_many(:children) - end - - it "should accept a valid association without any options" do - define_model :child, :parent_id => :integer - define_model :parent do - has_many :children - end - Parent.new.should @matcher - end - - it "should accept a valid association with a :through option" do - define_model :child - define_model :conception, :child_id => :integer, - :parent_id => :integer do - belongs_to :child - end - define_model :parent do - has_many :conceptions - has_many :children, :through => :conceptions - end - Parent.new.should @matcher - end - - it "should accept a valid association with an :as option" do - define_model :child, :guardian_type => :string, - :guardian_id => :integer - define_model :parent do - has_many :children, :as => :guardian - end - Parent.new.should @matcher - end - - it "should reject an association that has a nonexistent foreign key" do - define_model :child - define_model :parent do - has_many :children - end - Parent.new.should_not @matcher - end - - it "should reject an association with a bad :as option" do - define_model :child, :caretaker_type => :string, - :caretaker_id => :integer - define_model :parent do - has_many :children, :as => :guardian - end - Parent.new.should_not @matcher - end - - it "should reject an association that has a bad :through option" do - define_model :child, :parent_id => :integer - define_model :parent do - has_many :children - end - @matcher.through(:conceptions).matches?(Parent.new).should be_false - @matcher.failure_message.should =~ /does not have any relationship to conceptions/ - end - - it "should reject an association that has the wrong :through option" do - define_model :child - define_model :conception, :child_id => :integer, - :parent_id => :integer do - belongs_to :child - end - define_model :parent do - has_many :conceptions - has_many :relationships - has_many :children, :through => :conceptions - end - @matcher.through(:relationships).matches?(Parent.new).should be_false - @matcher.failure_message.should =~ /through relationships, but got it through conceptions/ - end - - it "should accept an association with a valid :dependent option" do - define_model :child, :parent_id => :integer - define_model :parent do - has_many :children, :dependent => :destroy - end - Parent.new.should @matcher.dependent(:destroy) - end - - it "should reject an association with a bad :dependent option" do - define_model :child, :parent_id => :integer - define_model :parent do - has_many :children - end - Parent.new.should_not @matcher.dependent(:destroy) - end - end - - context "have_one" do - before do - @matcher = have_one(:detail) - end - - it "should accept a valid association without any options" do - define_model :detail, :person_id => :integer - define_model :person do - has_one :detail - end - Person.new.should @matcher - end - - it "should accept a valid association with an :as option" do - define_model :detail, :detailable_id => :integer, - :detailable_type => :string - define_model :person do - has_one :detail, :as => :detailable - end - Person.new.should @matcher - end - - it "should reject an association that has a nonexistent foreign key" do - define_model :detail - define_model :person do - has_one :detail - end - Person.new.should_not @matcher - end - - it "should reject an association with a bad :as option" do - define_model :detail, :detailable_id => :integer, - :detailable_type => :string - define_model :person do - has_one :detail, :as => :describable - end - Person.new.should_not @matcher - end - - it "should accept an association with a valid :dependent option" do - define_model :detail, :person_id => :integer - define_model :person do - has_one :detail, :dependent => :destroy - end - Person.new.should @matcher.dependent(:destroy) - end - - it "should reject an association with a bad :dependent option" do - define_model :detail, :person_id => :integer - define_model :person do - has_one :detail - end - Person.new.should_not @matcher.dependent(:destroy) - end - end - - context "have_and_belong_to_many" do - before do - @matcher = have_and_belong_to_many(:relatives) - end - - it "should accept a valid association" do - define_model :relatives - define_model :person do - has_and_belongs_to_many :relatives - end - define_model :people_relative, :person_id => :integer, - :relative_id => :integer - Person.new.should @matcher - end - - it "should reject a nonexistent association" do - define_model :relatives - define_model :person - define_model :people_relative, :person_id => :integer, - :relative_id => :integer - Person.new.should_not @matcher - end - - it "should reject an association with a nonexistent join table" do - define_model :relatives - define_model :person do - has_and_belongs_to_many :relatives - end - Person.new.should_not @matcher - end - - it "should reject an association of the wrong type" do - define_model :relatives, :person_id => :integer - define_model :person do - has_many :relatives - end - Person.new.should_not @matcher - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/ensure_inclusion_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/ensure_inclusion_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/ensure_inclusion_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/ensure_inclusion_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::EnsureInclusionOfMatcher do - - context "an attribute which must be included in a range" do - before do - @model = define_model(:example, :attr => :integer) do - validates_inclusion_of :attr, :in => 2..5 - end.new - end - - it "should accept ensuring the correct range" do - @model.should ensure_inclusion_of(:attr).in_range(2..5) - end - - it "should reject ensuring a lower minimum value" do - @model.should_not ensure_inclusion_of(:attr).in_range(1..5) - end - - it "should reject ensuring a higher minimum value" do - @model.should_not ensure_inclusion_of(:attr).in_range(3..5) - end - - it "should reject ensuring a lower maximum value" do - @model.should_not ensure_inclusion_of(:attr).in_range(2..4) - end - - it "should reject ensuring a higher maximum value" do - @model.should_not ensure_inclusion_of(:attr).in_range(2..6) - end - - it "should not override the default message with a blank" do - @model.should ensure_inclusion_of(:attr).in_range(2..5).with_message(nil) - end - end - - context "an attribute with a custom ranged value validation" do - before do - @model = define_model(:example, :attr => :string) do - validates_inclusion_of :attr, :in => 2..4, :message => 'not good' - - end.new - end - - it "should accept ensuring the correct range" do - @model.should ensure_inclusion_of(:attr).in_range(2..4).with_message(/not good/) - end - end - - context "an attribute with custom range validations" do - before do - define_model :example, :attr => :integer do - validate :custom_validation - def custom_validation - if attr < 2 - errors.add(:attr, 'too low') - elsif attr > 5 - errors.add(:attr, 'too high') - end - end - end - @model = Example.new - end - - it "should accept ensuring the correct range and messages" do - @model.should ensure_inclusion_of(:attr).in_range(2..5).with_low_message(/low/).with_high_message(/high/) - end - - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/ensure_length_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/ensure_length_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/ensure_length_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/ensure_length_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,125 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::EnsureLengthOfMatcher do - - context "an attribute with a non-zero minimum length validation" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :minimum => 4 - end.new - end - - it "should accept ensuring the correct minimum length" do - @model.should ensure_length_of(:attr).is_at_least(4) - end - - it "should reject ensuring a lower minimum length with any message" do - @model.should_not ensure_length_of(:attr).is_at_least(3).with_short_message(/.*/) - end - - it "should reject ensuring a higher minimum length with any message" do - @model.should_not ensure_length_of(:attr).is_at_least(5).with_short_message(/.*/) - end - - it "should not override the default message with a blank" do - @model.should ensure_length_of(:attr).is_at_least(4).with_short_message(nil) - end - end - - context "an attribute with a minimum length validation of 0" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :minimum => 0 - end.new - end - - it "should accept ensuring the correct minimum length" do - @model.should ensure_length_of(:attr).is_at_least(0) - end - end - - context "an attribute with a maximum length" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :maximum => 4 - end.new - end - - it "should accept ensuring the correct maximum length" do - @model.should ensure_length_of(:attr).is_at_most(4) - end - - it "should reject ensuring a lower maximum length with any message" do - @model.should_not ensure_length_of(:attr).is_at_most(3).with_long_message(/.*/) - end - - it "should reject ensuring a higher maximum length with any message" do - @model.should_not ensure_length_of(:attr).is_at_most(5).with_long_message(/.*/) - end - - it "should not override the default message with a blank" do - @model.should ensure_length_of(:attr).is_at_most(4).with_long_message(nil) - end - end - - context "an attribute with a required exact length" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :is => 4 - end.new - end - - it "should accept ensuring the correct length" do - @model.should ensure_length_of(:attr).is_equal_to(4) - end - - it "should reject ensuring a lower maximum length with any message" do - @model.should_not ensure_length_of(:attr).is_equal_to(3).with_message(/.*/) - end - - it "should reject ensuring a higher maximum length with any message" do - @model.should_not ensure_length_of(:attr).is_equal_to(5).with_message(/.*/) - end - - it "should not override the default message with a blank" do - @model.should ensure_length_of(:attr).is_equal_to(4).with_message(nil) - end - end - - context "an attribute with a custom minimum length validation" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :minimum => 4, :too_short => 'short' - end.new - end - - it "should accept ensuring the correct minimum length" do - @model.should ensure_length_of(:attr).is_at_least(4).with_short_message(/short/) - end - - end - - context "an attribute with a custom maximum length validation" do - before do - @model = define_model(:example, :attr => :string) do - validates_length_of :attr, :maximum => 4, :too_long => 'long' - end.new - end - - it "should accept ensuring the correct minimum length" do - @model.should ensure_length_of(:attr).is_at_most(4).with_long_message(/long/) - end - - end - - context "an attribute without a length validation" do - before do - @model = define_model(:example, :attr => :string).new - end - - it "should reject ensuring a minimum length" do - @model.should_not ensure_length_of(:attr).is_at_least(1) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_db_column_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_db_column_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_db_column_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_db_column_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::HaveDbColumnMatcher do - - context "have_db_column" do - before do - @matcher = have_db_column(:nickname) - end - - it "should accept an existing database column" do - create_table 'superheros' do |table| - table.string :nickname - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a nonexistent database column" do - define_model :superhero - Superhero.new.should_not @matcher - end - end - - context "have_db_column of type string" do - before do - @matcher = have_db_column(:nickname).of_type(:string) - end - - it "should accept a column of correct type" do - create_table 'superheros' do |table| - table.string :nickname - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a nonexistent database column" do - define_model :superhero - Superhero.new.should_not @matcher - end - - it "should reject a column of wrong type" do - create_table 'superheros' do |table| - table.integer :nickname - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_column with precision option" do - before do - @matcher = have_db_column(:salary).with_options(:precision => 5) - end - - it "should accept a column of correct precision" do - create_table 'superheros' do |table| - table.decimal :salary, :precision => 5 - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a column of wrong precision" do - create_table 'superheros' do |table| - table.decimal :salary, :precision => 15 - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_column with limit option" do - before do - @matcher = have_db_column(:email). - of_type(:string). - with_options(:limit => 255) - end - - it "should accept a column of correct limit" do - create_table 'superheros' do |table| - table.string :email, :limit => 255 - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a column of wrong limit" do - create_table 'superheros' do |table| - table.string :email, :limit => 500 - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_column with default option" do - before do - @matcher = have_db_column(:admin). - of_type(:boolean). - with_options(:default => false) - end - - it "should accept a column of correct default" do - create_table 'superheros' do |table| - table.boolean :admin, :default => false - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a column of wrong default" do - create_table 'superheros' do |table| - table.boolean :admin, :default => true - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_column with null option" do - before do - @matcher = have_db_column(:admin). - of_type(:boolean). - with_options(:null => false) - end - - it "should accept a column of correct null" do - create_table 'superheros' do |table| - table.boolean :admin, :null => false - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a column of wrong null" do - create_table 'superheros' do |table| - table.boolean :admin, :null => true - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_column with scale option" do - before do - @matcher = have_db_column(:salary). - of_type(:decimal). - with_options(:scale => 2) - end - - it "should accept a column of correct scale" do - create_table 'superheros' do |table| - table.decimal :salary, :precision => 10, :scale => 2 - end - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a column of wrong scale" do - create_table 'superheros' do |table| - table.decimal :salary, :precision => 10, :scale => 4 - end - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_db_index_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_db_index_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_db_index_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_db_index_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,90 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::HaveDbIndexMatcher do - - context "have_db_index" do - before do - @matcher = have_db_index(:age) - end - - it "should accept an existing index" do - db_connection = create_table 'superheros' do |table| - table.integer :age - end - db_connection.add_index :superheros, :age - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject a nonexistent index" do - define_model :superhero - Superhero.new.should_not @matcher - end - end - - context "have_db_index with unique option" do - before do - @matcher = have_db_index(:ssn).unique(true) - end - - it "should accept an index of correct unique" do - db_connection = create_table 'superheros' do |table| - table.integer :ssn - end - db_connection.add_index :superheros, :ssn, :unique => true - define_model_class 'Superhero' - Superhero.new.should @matcher - end - - it "should reject an index of wrong unique" do - db_connection = create_table 'superheros' do |table| - table.integer :ssn - end - db_connection.add_index :superheros, :ssn, :unique => false - define_model_class 'Superhero' - Superhero.new.should_not @matcher - end - end - - context "have_db_index on multiple columns" do - before do - @matcher = have_db_index([:geocodable_type, :geocodable_id]) - end - - it "should accept an existing index" do - db_connection = create_table 'geocodings' do |table| - table.integer :geocodable_id - table.string :geocodable_type - end - db_connection.add_index :geocodings, [:geocodable_type, :geocodable_id] - define_model_class 'Geocoding' - Geocoding.new.should @matcher - end - - it "should reject a nonexistant index" do - db_connection = create_table 'geocodings' do |table| - table.integer :geocodable_id - table.string :geocodable_type - end - define_model_class 'Geocoding' - Geocoding.new.should_not @matcher - end - end - - it "should join columns with and describing multiple columns" do - have_db_index([:user_id, :post_id]).description.should =~ /on columns user_id and post_id/ - end - - it "should context a unique index as unique" do - have_db_index(:user_id).unique(true).description.should =~ /a unique index/ - end - - it "should context a non-unique index as non-unique" do - have_db_index(:user_id).unique(false).description.should =~ /a non-unique index/ - end - - it "should not context an index's uniqueness when it isn't important" do - have_db_index(:user_id).description.should_not =~ /unique/ - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/have_readonly_attributes_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::HaveReadonlyAttributeMatcher do - - context "an attribute that cannot be set after being saved" do - before do - define_model :example, :attr => :string do - attr_readonly :attr - end - @model = Example.new - end - - it "should accept being read-only" do - @model.should have_readonly_attribute(:attr) - end - end - - context "an attribute not included in the readonly set" do - before do - define_model :example, :attr => :string, :other => :string do - attr_readonly :other - end - @model = Example.new - end - - it "should not accept being read-only" do - @model.should_not have_readonly_attribute(:attr) - end - end - - context "an attribute on a class with no readonly attributes" do - before do - define_model :example, :attr => :string - @model = Example.new - end - - it "should not accept being read-only" do - @model.should_not have_readonly_attribute(:attr) - end - - it "should assign a failure message" do - matcher = have_readonly_attribute(:attr) - matcher.matches?(@model).should == false - matcher.failure_message.should_not be_nil - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_acceptance_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_acceptance_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_acceptance_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_acceptance_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::ValidateAcceptanceOfMatcher do - - context "an attribute which must be accepted" do - before do - @model = define_model(:example) do - validates_acceptance_of :attr - end.new - end - - it "should require that attribute to be accepted" do - @model.should validate_acceptance_of(:attr) - end - - it "should not overwrite the default message with nil" do - @model.should validate_acceptance_of(:attr).with_message(nil) - end - end - - context "an attribute that does not need to be accepted" do - before do - @model = define_model(:example, :attr => :string).new - end - - it "should not require that attribute to be accepted" do - @model.should_not validate_acceptance_of(:attr) - end - end - - context "an attribute which must be accepted with a custom message" do - before do - @model = define_model(:example) do - validates_acceptance_of :attr, :message => 'custom' - end.new - end - - it "should require that attribute to be accepted with that message" do - @model.should validate_acceptance_of(:attr).with_message(/custom/) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_format_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_format_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_format_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_format_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,38 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::ValidateFormatOfMatcher do - - context "a postal code" do - before do - define_model :example, :attr => :string do - validates_format_of :attr, :with => /^\d{5}$/ - end - @model = Example.new - end - - it "should be valid" do - @model.should validate_format_of(:attr).with('12345') - end - - it "should not be valid with alpha in zip" do - @model.should_not validate_format_of(:attr).with('1234a') - @model.should validate_format_of(:attr).not_with('1234a') - end - - it "should not be valid with too few digits" do - @model.should_not validate_format_of(:attr).with('1234') - @model.should validate_format_of(:attr).not_with('1234') - end - - it "should not be valid with too many digits" do - @model.should_not validate_format_of(:attr).with('123456') - @model.should validate_format_of(:attr).not_with('123456') - end - - it "should raise error if you try to call both with and not_with" do - expect { validate_format_of(:attr).not_with('123456').with('12345') }. - to raise_error(RuntimeError) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_numericality_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_numericality_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_numericality_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_numericality_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::ValidateNumericalityOfMatcher do - - context "a numeric attribute" do - before do - define_model :example, :attr => :string do - validates_numericality_of :attr - end - @model = Example.new - end - - it "should only allow numeric values for that attribute" do - @model.should validate_numericality_of(:attr) - end - - it "should not override the default message with a blank" do - @model.should validate_numericality_of(:attr).with_message(nil) - end - end - - context "a numeric attribute with a custom validation message" do - before do - define_model :example, :attr => :string do - validates_numericality_of :attr, :message => 'custom' - end - @model = Example.new - end - - it "should only allow numeric values for that attribute with that message" do - @model.should validate_numericality_of(:attr).with_message(/custom/) - end - - it "should not allow numeric values for that attribute with another message" do - @model.should_not validate_numericality_of(:attr) - end - end - - context "a non-numeric attribute" do - before do - @model = define_model(:example, :attr => :string).new - end - - it "should not only allow numeric values for that attribute" do - @model.should_not validate_numericality_of(:attr) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_presence_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_presence_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_presence_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_presence_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::ValidatePresenceOfMatcher do - - context "a required attribute" do - before do - define_model :example, :attr => :string do - validates_presence_of :attr - end - @model = Example.new - end - - it "should require a value" do - @model.should validate_presence_of(:attr) - end - - it "should not override the default message with a blank" do - @model.should validate_presence_of(:attr).with_message(nil) - end - end - - context "a required attribute on a class using ActiveModel::Validations" do - before do - define_active_model_class("Example", :accessors => [:attr]) do - validates_presence_of :attr - end - @model = Example.new - end - - it "should require a value" do - @model.should validate_presence_of(:attr) - end - - it "should not override the default message with a blank" do - @model.should validate_presence_of(:attr).with_message(nil) - end - end - - context "an optional attribute" do - before do - @model = define_model(:example, :attr => :string).new - end - - it "should not require a value" do - @model.should_not validate_presence_of(:attr) - end - end - - context "an optional attribute on a class using ActiveModel::Validations" do - before do - @model = define_active_model_class("Example", :accessors => [:attr]).new - end - - it "should not require a value" do - @model.should_not validate_presence_of(:attr) - end - end - - context "a required has_many association" do - before do - define_model :child - @model = define_model :parent do - has_many :children - validates_presence_of :children - end.new - end - - it "should require the attribute to be set" do - @model.should validate_presence_of(:children) - end - end - - context "an optional has_many association" do - before do - define_model :child - @model = define_model :parent do - has_many :children - end.new - end - - it "should not require the attribute to be set" do - @model.should_not validate_presence_of(:children) - end - end - - context "a required has_and_belongs_to_many association" do - before do - define_model :child - @model = define_model :parent do - has_and_belongs_to_many :children - validates_presence_of :children - end.new - end - - it "should require the attribute to be set" do - @model.should validate_presence_of(:children) - end - end - - context "an optional has_and_belongs_to_many association" do - before do - define_model :child - @model = define_model :parent do - has_and_belongs_to_many :children - end.new - end - - it "should not require the attribute to be set" do - @model.should_not validate_presence_of(:children) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_uniqueness_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_uniqueness_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/shoulda/active_record/validate_uniqueness_of_matcher_spec.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/shoulda/active_record/validate_uniqueness_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,145 +0,0 @@ -require 'spec_helper' - -describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher do - - context "a unique attribute" do - before do - @model = define_model(:example, :attr => :string, - :other => :integer) do - validates_uniqueness_of :attr - end.new - end - - context "with an existing value" do - before do - @existing = Example.create!(:attr => 'value', :other => 1) - end - - it "should require a unique value for that attribute" do - @model.should validate_uniqueness_of(:attr) - end - - it "should pass when the subject is an existing record" do - @existing.should validate_uniqueness_of(:attr) - end - - it "should fail when a scope is specified" do - @model.should_not validate_uniqueness_of(:attr).scoped_to(:other) - end - end - - context "without an existing value" do - before do - Example.find(:first).should be_nil - @matcher = validate_uniqueness_of(:attr) - end - - it "should fail to require a unique value" do - @model.should_not @matcher - end - - it "should alert the tester that an existing value is not present" do - @matcher.matches?(@model) - @matcher.negative_failure_message.should =~ /^Can't find first .*/ - end - end - end - - context "a unique attribute with a custom error and an existing value" do - before do - @model = define_model(:example, :attr => :string) do - validates_uniqueness_of :attr, :message => 'Bad value' - end.new - Example.create! - end - - it "should fail when checking the default message" do - @model.should_not validate_uniqueness_of(:attr) - end - - it "should fail when checking a message that doesn't match" do - @model.should_not validate_uniqueness_of(:attr).with_message(/abc/i) - end - - it "should pass when checking a message that matches" do - @model.should validate_uniqueness_of(:attr).with_message(/bad/i) - end - end - - context "a scoped unique attribute with an existing value" do - before do - @model = define_model(:example, :attr => :string, - :scope1 => :integer, - :scope2 => :integer) do - validates_uniqueness_of :attr, :scope => [:scope1, :scope2] - end.new - @existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2) - end - - it "should pass when the correct scope is specified" do - @model.should validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2) - end - - it "should pass when the subject is an existing record" do - @existing.should validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2) - end - - it "should fail when a different scope is specified" do - @model.should_not validate_uniqueness_of(:attr).scoped_to(:scope1) - end - - it "should fail when no scope is specified" do - @model.should_not validate_uniqueness_of(:attr) - end - - it "should fail when a non-existent attribute is specified as a scope" do - @model.should_not validate_uniqueness_of(:attr).scoped_to(:fake) - end - end - - context "a non-unique attribute with an existing value" do - before do - @model = define_model(:example, :attr => :string).new - Example.create!(:attr => 'value') - end - - it "should not require a unique value for that attribute" do - @model.should_not validate_uniqueness_of(:attr) - end - end - - context "a case sensitive unique attribute with an existing value" do - before do - @model = define_model(:example, :attr => :string) do - validates_uniqueness_of :attr, :case_sensitive => true - end.new - Example.create!(:attr => 'value') - end - - it "should not require a unique, case-insensitive value for that attribute" do - @model.should_not validate_uniqueness_of(:attr).case_insensitive - end - - it "should require a unique, case-sensitive value for that attribute" do - @model.should validate_uniqueness_of(:attr) - end - end - - context "a case sensitive unique integer attribute with an existing value" do - before do - @model = define_model(:example, :attr => :integer) do - validates_uniqueness_of :attr, :case_sensitive => true - end.new - Example.create!(:attr => 'value') - end - - it "should require a unique, case-insensitive value for that attribute" do - @model.should validate_uniqueness_of(:attr).case_insensitive - end - - it "should require a unique, case-sensitive value for that attribute" do - @model.should validate_uniqueness_of(:attr) - end - end - -end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/spec_helper.rb ruby-shoulda-matchers-2.8.0/spec/spec_helper.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/spec_helper.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/spec_helper.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -ENV['RAILS_ENV'] = 'test' -ENV['RAILS_VERSION'] ||= '3.0.3' -RAILS_GEM_VERSION = ENV['RAILS_VERSION'] - -rails_root = File.dirname(__FILE__) + '/rails3_root' -ENV['BUNDLE_GEMFILE'] = rails_root + '/Gemfile' - -require "#{rails_root}/config/environment" -require 'rspec' -require 'rspec/autorun' - -PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')).freeze - -$LOAD_PATH << File.join(PROJECT_ROOT, 'lib') - -Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) } - -require 'shoulda-matchers' -require 'rspec/rails' - -# Run the migrations -ActiveRecord::Migration.verbose = false -ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate") - -RSpec.configure do |config| - config.mock_with :mocha - config.include Shoulda::Matchers::ActionController, - :example_group => { :file_path => /action_controller/ } - config.include Shoulda::Matchers::ActionMailer, - :example_group => { :file_path => /action_mailer/ } -end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/active_model_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/active_model_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/active_model_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/active_model_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,11 @@ +require_relative 'gem_helpers' + +module AcceptanceTests + module ActiveModelHelpers + include GemHelpers + + def active_model_version + bundle_version_of('activemodel') + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/array_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/array_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/array_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/array_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,13 @@ +module AcceptanceTests + module ArrayHelpers + def to_sentence(array) + if array.size == 1 + array[0] + elsif array.size == 2 + array.join(' and ') + else + to_sentence(array[1..-2].join(', '), [array[-1]]) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/base_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/base_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/base_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/base_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,14 @@ +require_relative '../../tests/filesystem' +require_relative '../../tests/bundle' + +module AcceptanceTests + module BaseHelpers + def fs + @_fs ||= Tests::Filesystem.new + end + + def bundle + @_bundle ||= Tests::Bundle.new + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/command_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/command_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/command_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/command_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,51 @@ +require_relative 'base_helpers' +require_relative '../../tests/command_runner' + +module AcceptanceTests + module CommandHelpers + include BaseHelpers + extend RSpec::Matchers::DSL + + def run_command(*args) + Tests::CommandRunner.run(*args) do |runner| + runner.directory = fs.project_directory + yield runner if block_given? + end + end + + def run_command!(*args) + run_command(*args) do |runner| + runner.run_successfully = true + yield runner if block_given? + end + end + + def run_command_within_bundle(*args) + run_command(*args) do |runner| + runner.command_prefix = 'bundle exec' + runner.env['BUNDLE_GEMFILE'] = fs.find_in_project('Gemfile').to_s + + runner.around_command do |run_command| + Bundler.with_clean_env(&run_command) + end + + yield runner if block_given? + end + end + + def run_command_within_bundle!(*args) + run_command_within_bundle(*args) do |runner| + runner.run_successfully = true + yield runner if block_given? + end + end + + def run_rake_tasks(*tasks) + run_command_within_bundle('rake', *tasks) + end + + def run_rake_tasks!(*tasks) + run_command_within_bundle!('rake', *tasks) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/file_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/file_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/file_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/file_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,19 @@ +require_relative 'base_helpers' + +module AcceptanceTests + module FileHelpers + include BaseHelpers + + def append_to_file(path, content, options = {}) + fs.append_to_file(path, content, options) + end + + def remove_from_file(path, pattern) + fs.remove_from_file(path, pattern) + end + + def write_file(path, content) + fs.write(path, content) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/gem_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/gem_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/gem_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/gem_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,31 @@ +require_relative 'base_helpers' +require_relative 'command_helpers' +require_relative 'file_helpers' + +module AcceptanceTests + module GemHelpers + include BaseHelpers + include CommandHelpers + include FileHelpers + + def add_gem(gem, *args) + bundle.add_gem(gem, *args) + end + + def install_gems + bundle.install_gems + end + + def updating_bundle(&block) + bundle.updating(&block) + end + + def bundle_version_of(gem) + bundle.version_of(gem) + end + + def bundle_includes?(gem) + bundle.includes?(gem) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/minitest_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/minitest_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/minitest_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/minitest_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,19 @@ +require_relative 'gem_helpers' + +module AcceptanceTests + module MinitestHelpers + include GemHelpers + + def minitest_test_case_superclass + if minitest_version >= 5 + 'Minitest::Test' + else + 'MiniTest::Unit::TestCase' + end + end + + def minitest_version + bundle_version_of('minitest') + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/pluralization_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/pluralization_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/pluralization_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/pluralization_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,13 @@ +module AcceptanceTests + module PluralizationHelpers + def pluralize(count, singular_version, plural_version = nil) + plural_version ||= singular_version + 's' + + if count == 1 + "#{count} #{singular_version}" + else + "#{count} #{plural_version}" + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/rails_version_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/rails_version_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/rails_version_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/rails_version_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,11 @@ +require_relative 'gem_helpers' + +module AcceptanceTests + module RailsVersionHelpers + include GemHelpers + + def rails_version + bundle_version_of('rails') + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/rspec_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/rspec_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/rspec_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/rspec_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,26 @@ +module AcceptanceTests + module RspecHelpers + include GemHelpers + + def rspec_rails_version + bundle_version_of('rspec-rails') + end + + def add_rspec_file(path, content) + content = "require '#{spec_helper_require_path}'\n#{content}" + write_file path, content + end + + def spec_helper_require_path + if rspec_rails_version >= 3 + 'rails_helper' + else + 'spec_helper' + end + end + + def spec_helper_file_path + "spec/#{spec_helper_require_path}.rb" + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/ruby_version_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/ruby_version_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/ruby_version_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/ruby_version_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,9 @@ +require_relative '../../tests/version' + +module AcceptanceTests + module RubyVersionHelpers + def ruby_version + Tests::Version.new(RUBY_VERSION) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/step_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/step_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers/step_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers/step_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,117 @@ +require_relative 'file_helpers' +require_relative 'gem_helpers' +require_relative 'minitest_helpers' + +module AcceptanceTests + module StepHelpers + include FileHelpers + include GemHelpers + include MinitestHelpers + + extend RSpec::Matchers::DSL + + def create_active_model_project + create_generic_bundler_project + add_gem 'activemodel', active_model_version + end + + def create_generic_bundler_project + fs.create + run_command! 'bundle init' + end + + def add_shoulda_matchers_to_project(options = {}) + gem_options = { path: fs.root_directory } + + if options[:manually] + gem_options[:require] = false + end + + add_gem 'shoulda-matchers', gem_options + + if options[:manually] + if options[:test_frameworks].include?(:rspec) + append_to_file spec_helper_file_path, "require 'shoulda/matchers'" + end + + if options[:test_frameworks].include?(:n_unit) + append_to_file 'test/test_helper.rb', "require 'shoulda/matchers'" + end + end + end + + def add_minitest_to_project + add_gem 'minitest-reporters' + + append_to_file 'test/test_helper.rb', <<-FILE + require 'minitest/autorun' + require 'minitest/reporters' + + Minitest::Reporters.use!(Minitest::Reporters::SpecReporter.new) + FILE + end + + def add_shoulda_context_to_project(options = {}) + add_gem 'shoulda-context' + + if options[:manually] + append_to_file 'test/test_helper.rb', <<-FILE + require 'shoulda/context' + FILE + end + end + + def write_minitest_test(path) + contents = yield minitest_test_case_superclass + write_file(path, contents) + end + + def run_n_unit_tests(*paths) + run_command_within_bundle 'ruby -I lib -I test', *paths + end + + def run_n_unit_test_suite + run_rake_tasks('test', env: { TESTOPTS: '-v' }) + end + + def create_rails_application + command = "bundle exec rails new #{fs.project_directory} --skip-bundle" + + run_command!(command) do |runner| + runner.directory = nil + end + + updating_bundle do |bundle| + bundle.remove_gem 'turn' + bundle.remove_gem 'coffee-rails' + bundle.remove_gem 'uglifier' + end + end + + def configure_routes_with_single_wildcard_route + write_file 'config/routes.rb', <<-FILE + Rails.application.routes.draw do + get ':controller(/:action(/:id(.:format)))' + end + FILE + end + + def add_rspec_rails_to_project! + add_gem 'rspec-rails', rspec_rails_version + run_command_within_bundle!('rails g rspec:install') + remove_from_file '.rspec', '--warnings' + end + + def run_rspec_suite + run_rake_tasks('spec', env: { SPEC_OPTS: '-fd' }) + end + + def add_spring_to_project + if rails_version < 4 + add_gem 'spring' + end + + add_gem 'spring-commands-rspec' + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,29 @@ +require_relative 'helpers/active_model_helpers' +require_relative 'helpers/base_helpers' +require_relative 'helpers/command_helpers' +require_relative 'helpers/gem_helpers' +require_relative 'helpers/rails_version_helpers' +require_relative 'helpers/rspec_helpers' +require_relative 'helpers/ruby_version_helpers' +require_relative 'helpers/step_helpers' + +module AcceptanceTests + module Helpers + def self.configure_example_group(example_group) + example_group.include(self) + + example_group.before do + fs.clean + end + end + + include ActiveModelHelpers + include BaseHelpers + include CommandHelpers + include GemHelpers + include RailsVersionHelpers + include RspecHelpers + include RubyVersionHelpers + include StepHelpers + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/have_output.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/have_output.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/have_output.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/have_output.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,31 @@ +module AcceptanceTests + module Matchers + def have_output(output) + HaveOutputMatcher.new(output) + end + + class HaveOutputMatcher + def initialize(output) + @output = output + end + + def matches?(runner) + @runner = runner + runner.has_output?(output) + end + + def failure_message + "Expected command to have output, but did not.\n\n" + + "Command: #{runner.formatted_command}\n\n" + + "Expected output:\n" + + output + "\n\n" + + "Actual output:\n" + + runner.elided_output + end + + protected + + attr_reader :output, :runner + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,55 @@ +require_relative '../helpers/pluralization_helpers' +require_relative '../helpers/rails_version_helpers' + +module AcceptanceTests + module Matchers + def indicate_number_of_tests_was_run(expected_output) + IndicateNumberOfTestsWasRunMatcher.new(expected_output) + end + + class IndicateNumberOfTestsWasRunMatcher + include PluralizationHelpers + include RailsVersionHelpers + + def initialize(number) + @number = number + end + + def matches?(runner) + @runner = runner + expected_output === actual_output + end + + def failure_message + message = "Expected output to indicate that #{some_tests_were_run}.\n" + + "Expected output: #{expected_output}\n" + + if actual_output.empty? + message << 'Actual output: (empty)' + else + message << "Actual output:\n#{actual_output}" + end + + message + end + + protected + + attr_reader :number, :runner + + private + + def expected_output + /#{number} (tests|runs), #{number} assertions, 0 failures, 0 errors(, 0 skips)?/ + end + + def actual_output + runner.output + end + + def some_tests_were_run + pluralize(number, 'test was', 'tests were') + ' run' + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,103 @@ +require_relative '../helpers/array_helpers' +require_relative '../helpers/pluralization_helpers' +require_relative '../helpers/rails_version_helpers' + +module AcceptanceTests + module Matchers + def indicate_that_tests_were_run(series) + IndicateThatTestsWereRunMatcher.new(series) + end + + class IndicateThatTestsWereRunMatcher + include ArrayHelpers + include PluralizationHelpers + include RailsVersionHelpers + + def initialize(args) + @args = args + @series = args.values + end + + def matches?(runner) + @runner = runner + !matching_expected_output.nil? + end + + def failure_message + "Expected output to indicate that #{some_tests_were_run}.\n" + + "#{formatted_expected_output}\n" + + "#{formatted_actual_output}\n" + end + + protected + + attr_reader :args, :series, :runner + + private + + def expected_outputs + [ + expected_output_for_rails_3, + expected_output_for_turn, + expected_output_for_rails_4 + ] + end + + def matching_expected_output + @_matching_expected_output ||= + expected_outputs.detect do |expected_output| + actual_output =~ expected_output + end + end + + def expected_output_for_rails_3 + full_report = series.map do |number| + "#{number} tests, #{number} assertions, 0 failures, 0 errors(, 0 skips)?" + end.join('.+') + + Regexp.new(full_report, Regexp::MULTILINE) + end + + def expected_output_for_turn + full_report = series.map do |number| + "pass: #{number}, fail: 0, error: 0" + end.join('.+') + + Regexp.new(full_report, Regexp::MULTILINE) + end + + def expected_output_for_rails_4 + total = series.inject(:+) + /#{total} (tests|runs), #{total} assertions, 0 failures, 0 errors(, 0 skips)?/ + end + + def formatted_expected_output + if matching_expected_output + "Expected output:\n#{matching_actual_output}" + else + "Expected output: (n/a)" + end + end + + def actual_output + runner.output + end + + def formatted_actual_output + if actual_output.empty? + "Actual output: (empty)" + else + "Actual output:\n#{actual_output}" + end + end + + def some_tests_were_run + clauses = args.map do |type, number| + pluralize(number, "#{type} test was run", "#{type} tests were run") + end + + to_sentence(clauses) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/model_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/model_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/model_builder.rb 2011-03-17 17:22:27.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/model_builder.rb 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -module ModelBuilder - TMP_VIEW_PATH = - File.expand_path(File.join(File.dirname(__FILE__), 'rails3_root', 'tmp', 'views')).freeze - - def self.included(example_group) - example_group.class_eval do - before do - @created_tables ||= [] - end - - after { teardown_defined_constants } - end - end - - def create_table(table_name, &block) - connection = ActiveRecord::Base.connection - - begin - connection.execute("DROP TABLE IF EXISTS #{table_name}") - connection.create_table(table_name, &block) - @created_tables << table_name - connection - rescue Exception => e - connection.execute("DROP TABLE IF EXISTS #{table_name}") - raise e - end - end - - def define_constant(class_name, base, &block) - class_name = class_name.to_s.camelize - - klass = Class.new(base) - Object.const_set(class_name, klass) - klass.unloadable - - klass.class_eval(&block) if block_given? - - klass - end - - def define_model_class(class_name, &block) - define_constant(class_name, ActiveRecord::Base, &block) - end - - def define_active_model_class(class_name, options = {}, &block) - define_constant(class_name, Object) do - include ActiveModel::Validations - - options[:accessors].each do |column| - attr_accessor column.to_sym - end - - class_eval(&block) if block_given? - end - end - - def define_model(name, columns = {}, &block) - class_name = name.to_s.pluralize.classify - table_name = class_name.tableize - - create_table(table_name) do |table| - columns.each do |name, type| - table.column name, type - end - end - - define_model_class(class_name, &block) - end - - def define_mailer(name, paths, &block) - class_name = name.to_s.pluralize.classify - klass = define_constant(class_name, ActionMailer::Base, &block) - end - - def define_controller(class_name, &block) - class_name = class_name.to_s - class_name << 'Controller' unless class_name =~ /Controller$/ - define_constant(class_name, ActionController::Base, &block) - end - - def define_routes(&block) - Rails.application.routes.draw(&block) - @routes = Rails.application.routes - class << self - include ActionDispatch::Assertions - end - end - - def build_response(opts = {}, &block) - action = opts[:action] || 'example' - klass = define_controller('Examples') - block ||= lambda { render :nothing => true } - klass.class_eval { layout false; define_method(action, &block) } - define_routes do - match 'examples', :to => "examples##{action}" - end - - create_view("examples/#{action}.html.erb", "abc") - klass.view_paths = [TMP_VIEW_PATH] - - @controller = klass.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - @controller.send :assign_shortcuts, @request, @response - @controller.send :initialize_template_class, @response - - class << self - include ActionController::TestCase::Behavior - end - @routes = Rails.application.routes - - get action - - @controller - end - - def create_view(path, contents) - full_path = File.join(TMP_VIEW_PATH, path) - FileUtils.mkdir_p(File.dirname(full_path)) - File.open(full_path, 'w') { |file| file.write(contents) } - end - - def teardown_defined_constants - ActiveSupport::Dependencies.clear - - @created_tables.each do |table_name| - ActiveRecord::Base. - connection. - execute("DROP TABLE IF EXISTS #{table_name}") - end - - FileUtils.rm_rf(TMP_VIEW_PATH) - - Rails.application.reload_routes! - end -end - -RSpec.configure do |config| - config.include ModelBuilder -end - diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/bundle.rb ruby-shoulda-matchers-2.8.0/spec/support/tests/bundle.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/bundle.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/tests/bundle.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,94 @@ +require_relative 'filesystem' +require_relative 'command_runner' +require_relative 'version' + +module Tests + class Bundle + def initialize + @already_updating = false + @fs = Filesystem.new + end + + def updating(&block) + if already_updating? + yield self + return + end + + @already_updating = true + + yield self + + @already_updating = false + + install_gems + end + + def add_gem(gem, *args) + updating do + options = args.last.is_a?(Hash) ? args.pop : {} + version = args.shift + line = assemble_gem_line(gem, version, options) + fs.append_to_file('Gemfile', line) + end + end + + def remove_gem(gem) + updating do + fs.remove_from_file('Gemfile', /^gem ("|')gem\1/) + end + end + + def install_gems + CommandRunner.run!('bundle install --local') do |runner| + runner.retries = 5 + end + end + + def version_of(gem) + Version.new(Bundler.definition.specs[gem][0].version) + end + + def includes?(gem) + Bundler.definition.dependencies.any? do |dependency| + dependency.name == gem + end + end + + protected + + attr_reader :fs + + private + + def already_updating? + @already_updating + end + + def assemble_gem_line(gem, version, options) + formatted_options = options. + map { |key, value| "#{key}: #{formatted_value(value)}" }. + join(', ') + + line = %(gem '#{gem}') + + if version + line << %(, '#{version}') + end + + if options.any? + line << %(, #{formatted_options}) + end + + line << "\n" + end + + def formatted_value(value) + if value.is_a?(Pathname) + value.to_s.inspect + else + value.inspect + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/command_runner.rb ruby-shoulda-matchers-2.8.0/spec/support/tests/command_runner.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/command_runner.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/tests/command_runner.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,214 @@ +require 'timeout' +require 'shellwords' + +module Tests + class CommandRunner + TimeoutError = Class.new(StandardError) + + def self.run(*args) + new(*args).tap do |runner| + yield runner + runner.call + end + end + + def self.run!(*args) + run(*args) do |runner| + runner.run_successfully = true + yield runner if block_given? + end + end + + attr_reader :status, :options, :env, :directory + attr_accessor :command_prefix, :run_quickly, :run_successfully, :retries, + :timeout + + def initialize(*args) + @reader, @writer = IO.pipe + options = (args.last.is_a?(Hash) ? args.pop : {}) + @args = args + @options = options.merge( + err: [:child, :out], + out: writer + ) + @env = extract_env_from(@options) + + @wrapper = ->(block) { block.call } + @command_prefix = '' + @directory = Dir.pwd + @run_quickly = false + @run_successfully = false + @retries = 1 + @num_times_run = 0 + @timeout = 20 + end + + def around_command(&block) + @wrapper = block + end + + def directory=(directory) + @directory = directory || Dir.pwd + end + + def formatted_command + [formatted_env, Shellwords.join(command)]. + select { |value| !value.empty? }. + join(' ') + end + + def call + possibly_retrying do + possibly_running_quickly do + debug { "\n\e[32mRunning command:\e[0m #{formatted_command}" } + wrapper.call(-> { run }) + debug { "\n" + divider('START') + output + divider('END') } + + if run_successfully && !success? + fail! + end + end + end + + self + end + + def stop + unless writer.closed? + writer.close + end + end + + def output + @_output ||= begin + stop + without_colors(reader.read) + end + end + + def elided_output + lines = output.split(/\n/) + new_lines = lines[0..4] + + if lines.size > 10 + new_lines << "(...#{lines.size - 10} more lines...)" + end + + new_lines << lines[-5..-1] + new_lines.join("\n") + end + + def success? + status.success? + end + + def exit_status + status.exitstatus + end + + def fail! + raise <<-MESSAGE +Command #{command.inspect} exited with status #{exit_status}. +Output: +#{divider('START') + output + divider('END')} + MESSAGE + end + + def has_output?(expected_output) + output.include?(expected_output) + end + + protected + + attr_reader :args, :reader, :writer, :wrapper + + private + + def extract_env_from(options) + options.delete(:env) { {} }.inject({}) do |hash, (key, value)| + hash[key.to_s] = value + hash + end + end + + def command + ([command_prefix] + args).flatten.flat_map do |word| + Shellwords.split(word) + end + end + + def formatted_env + env.map { |key, value| "#{key}=#{value.inspect}" }.join(' ') + end + + def run + Dir.chdir(directory) do + pid = spawn(env, *command, options) + Process.waitpid(pid) + end + + @status = $? + end + + def possibly_running_quickly(&block) + if run_quickly + begin + Timeout.timeout(timeout, &block) + rescue Timeout::Error + stop + + message = + "Command timed out after #{timeout} seconds: #{formatted_command}\n" + + "Output:\n" + + elided_output + + raise TimeoutError, message + end + else + yield + end + end + + def possibly_retrying + begin + @num_times_run += 1 + yield + rescue => error + debug { "#{error.class}: #{error.message}" } + + if @num_times_run < @retries + sleep @num_times_run + retry + else + raise error + end + end + end + + def divider(title = '') + total_length = 72 + start_length = 3 + + string = '' + string << ('-' * start_length) + string << title + string << '-' * (total_length - start_length - title.length) + string << "\n" + string + end + + def without_colors(string) + string.gsub(/\e\[\d+(?:;\d+)?m(.+?)\e\[0m/, '\1') + end + + def debugging_enabled? + ENV['DEBUG_COMMANDS'] == '1' + end + + def debug(&block) + if debugging_enabled? + puts block.call + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/filesystem.rb ruby-shoulda-matchers-2.8.0/spec/support/tests/filesystem.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/filesystem.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/tests/filesystem.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,77 @@ +require 'fileutils' + +module Tests + class Filesystem + PROJECT_NAME = 'test-project' + ROOT_DIRECTORY = Pathname.new('../../../..').expand_path(__FILE__) + TEMP_DIRECTORY = ROOT_DIRECTORY.join('tmp/acceptance') + PROJECT_DIRECTORY = TEMP_DIRECTORY.join(PROJECT_NAME) + + def root_directory + ROOT_DIRECTORY + end + + def temp_directory + TEMP_DIRECTORY + end + + def project_directory + PROJECT_DIRECTORY + end + + def wrap(path) + if path.is_a?(Pathname) + path + else + find_in_project(path) + end + end + + def within_project(&block) + Dir.chdir(project_directory, &block) + end + + def clean + if temp_directory.exist? + temp_directory.rmtree + end + end + + def create + project_directory.mkpath + end + + def find_in_project(path) + project_directory.join(path) + end + + def open(path, *args, &block) + find_in_project(path).open(*args, &block) + end + + def read(path) + find_in_project(path).read + end + + def write(path, content) + pathname = wrap(path) + create_parents_of(pathname) + pathname.open('w') { |f| f.write(content) } + end + + def create_parents_of(path) + wrap(path).dirname.mkpath + end + + def append_to_file(path, content, options = {}) + create_parents_of(path) + open(path, 'a') { |f| f.puts(content + "\n") } + end + + def remove_from_file(path, pattern) + content = read(path) + content.sub!(/#{pattern}\n/, '') + write(path, content) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/version.rb ruby-shoulda-matchers-2.8.0/spec/support/tests/version.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/tests/version.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/tests/version.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,45 @@ +module Tests + class Version + def initialize(version) + @version = Gem::Version.new(version.to_s + '') + end + + def <(other_version) + compare?(:<, other_version) + end + + def <=(other_version) + compare?(:<=, other_version) + end + + def ==(other_version) + compare?(:==, other_version) + end + + def >=(other_version) + compare?(:>=, other_version) + end + + def >(other_version) + compare?(:>, other_version) + end + + def =~(other_version) + Gem::Requirement.new(other_version).satisfied_by?(version) + end + + def to_s + version.to_s + end + + protected + + attr_reader :version + + private + + def compare?(op, other_version) + Gem::Requirement.new("#{op} #{other_version}").satisfied_by?(version) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/capture.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/capture.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/capture.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/capture.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,34 @@ +module Kernel + # #capture, #silence_stream, and #silence_stderr are deprecated after Rails + # 4.2 and will be removed in 5.0, so just override them completely here + + def capture(stream) + stream = stream.to_s + captured_stream = Tempfile.new(stream) + stream_io = eval("$#{stream}") + origin_stream = stream_io.dup + stream_io.reopen(captured_stream) + + yield + + stream_io.rewind + return captured_stream.read + ensure + captured_stream.unlink + stream_io.reopen(origin_stream) + end + + def silence_stream(stream) + old_stream = stream.dup + stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null') + stream.sync = true + yield + ensure + stream.reopen(old_stream) + old_stream.close + end + + def silence_stderr + silence_stream(STDERR) { yield } + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_model_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_model_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_model_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_model_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,27 @@ +module UnitTests + module ActiveModelHelpers + def self.configure_example_group(example_group) + example_group.include(self) + end + + def custom_validation(options = {}, &block) + attribute_name = options.fetch(:attribute_name, :attr) + attribute_type = options.fetch(:attribute_type, :integer) + column_options = options.fetch(:column_options, {}) + attribute_options = { type: attribute_type, options: column_options } + + define_model(:example, attribute_name => attribute_options) do + validate :custom_validation + + define_method(:custom_validation, &block) + end.new + end + alias record_with_custom_validation custom_validation + + def validating_format(options) + define_model :example, attr: :string do + validates_format_of :attr, options + end.new + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_model_versions.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_model_versions.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_model_versions.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_model_versions.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,28 @@ +module UnitTests + module ActiveModelVersions + def self.configure_example_group(example_group) + example_group.include(self) + example_group.extend(self) + end + + def active_model_version + Tests::Version.new(::ActiveModel::VERSION::STRING) + end + + def active_model_3_1? + (::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR >= 1) || active_model_4_0? + end + + def active_model_3_2? + (::ActiveModel::VERSION::MAJOR == 3 && ::ActiveModel::VERSION::MINOR >= 2) || active_model_4_0? + end + + def active_model_4_0? + ::ActiveModel::VERSION::MAJOR == 4 + end + + def active_model_supports_strict? + active_model_version >= 3.2 + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_record_versions.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_record_versions.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_record_versions.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_record_versions.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,16 @@ +module UnitTests + module ActiveRecordVersions + def self.configure_example_group(example_group) + example_group.include(self) + example_group.extend(self) + end + + def active_record_version + Tests::Version.new(ActiveRecord::VERSION::STRING) + end + + def active_record_can_raise_range_error? + active_record_version >= 4.2 + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_resource_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_resource_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/active_resource_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/active_resource_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,27 @@ +require 'active_resource' + +module UnitTests + module ActiveResourceBuilder + def self.configure_example_group(example_group) + example_group.include ActiveResourceBuilder + + example_group.after do + ActiveSupport::Dependencies.clear + end + end + + def define_active_resource_class(class_name, attributes = {}, &block) + define_class(class_name, ActiveResource::Base) do + schema do + attributes.each do |attr, type| + attribute attr, type + end + end + + if block_given? + class_eval(&block) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/allow_value_matcher_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/allow_value_matcher_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/allow_value_matcher_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/allow_value_matcher_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,15 @@ +require_relative '../record_with_different_error_attribute_builder' +require_relative '../record_builder_with_i18n_validation_message' + +module UnitTests + module AllowValueMatcherHelpers + def builder_for_record_with_different_error_attribute(options = {}) + RecordWithDifferentErrorAttributeBuilder.new(options) + end + + def builder_for_record_with_different_error_attribute_using_i18n(options = {}) + builder = builder_for_record_with_different_error_attribute(options) + RecordBuilderWithI18nValidationMessage.new(builder) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/class_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/class_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/class_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/class_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,72 @@ +module UnitTests + module ClassBuilder + def self.parse_constant_name(name) + namespace = Shoulda::Matchers::Util.deconstantize(name) + qualified_namespace = (namespace.presence || 'Object').constantize + name_without_namespace = name.to_s.demodulize + [qualified_namespace, name_without_namespace] + end + + def self.configure_example_group(example_group) + example_group.include(self) + + example_group.after do + teardown_defined_constants + end + end + + def define_module(module_name, &block) + module_name = module_name.to_s.camelize + + namespace, name_without_namespace = + ClassBuilder.parse_constant_name(module_name) + + if namespace.const_defined?(name_without_namespace, false) + namespace.__send__(:remove_const, name_without_namespace) + end + + eval <<-RUBY + module #{namespace}::#{name_without_namespace} + end + RUBY + + namespace.const_get(name_without_namespace).tap do |constant| + constant.unloadable + + if block + constant.module_eval(&block) + end + end + end + + def define_class(class_name, parent_class = Object, &block) + class_name = class_name.to_s.camelize + + namespace, name_without_namespace = + ClassBuilder.parse_constant_name(class_name) + + if namespace.const_defined?(name_without_namespace, false) + namespace.__send__(:remove_const, name_without_namespace) + end + + eval <<-RUBY + class #{namespace}::#{name_without_namespace} < #{parent_class} + end + RUBY + + namespace.const_get(name_without_namespace).tap do |constant| + constant.unloadable + + if block_given? + constant.class_eval(&block) + end + end + end + + private + + def teardown_defined_constants + ActiveSupport::Dependencies.clear + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/confirmation_matcher_helpers.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/confirmation_matcher_helpers.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/confirmation_matcher_helpers.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/confirmation_matcher_helpers.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,17 @@ +require_relative '../record_validating_confirmation_builder' +require_relative '../record_builder_with_i18n_validation_message' + +module UnitTests + module ConfirmationMatcherHelpers + def builder_for_record_validating_confirmation(options = {}) + RecordValidatingConfirmationBuilder.new(options) + end + + def builder_for_record_validating_confirmation_with_18n_message(options = {}) + builder = builder_for_record_validating_confirmation(options) + RecordBuilderWithI18nValidationMessage.new(builder, + validation_message_key: :confirmation + ) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/controller_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/controller_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/controller_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/controller_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,91 @@ +module UnitTests + module ControllerBuilder + def self.configure_example_group(example_group) + example_group.include(self) + + example_group.after do + delete_temporary_views + restore_original_routes + end + end + + def define_controller(class_name, &block) + class_name = class_name.to_s + class_name << 'Controller' unless class_name =~ /Controller$/ + define_class(class_name, ActionController::Base, &block) + end + + def define_routes(&block) + self.routes = $test_app.draw_routes(&block) + end + + def build_fake_response(opts = {}, &block) + action = opts[:action] || 'example' + partial = opts[:partial] || '_partial' + block ||= lambda { render nothing: true } + controller_class = define_controller('Examples') do + layout false + define_method(action, &block) + end + controller_class.view_paths = [ $test_app.temp_views_directory.to_s ] + + define_routes do + get 'examples', to: "examples##{action}" + end + + create_view("examples/#{action}.html.erb", 'action') + create_view("examples/#{partial}.html.erb", 'partial') + + setup_rails_controller_test(controller_class) + self.class.render_views(true) + + get action + + controller + end + + def setup_rails_controller_test(controller_class) + @controller = controller_class.new + end + + def create_view(path, contents) + $test_app.create_temp_view(path, contents) + end + + def controller_for_resource_with_strong_parameters(options = {}, &action_body) + model_name = options.fetch(:model_name, 'User') + controller_name = options.fetch(:controller_name, 'UsersController') + collection_name = controller_name. + to_s.sub(/Controller$/, '').underscore. + to_sym + action_name = options.fetch(:action, :some_action) + routes ||= options.fetch(:routes, -> { resources collection_name }) + + define_model(model_name) + + controller_class = define_controller(controller_name) do + define_method action_name do + if action_body + instance_eval(&action_body) + end + + render nothing: true + end + end + + setup_rails_controller_test(controller_class) + + define_routes(&routes) + + controller_class + end + + def delete_temporary_views + $test_app.delete_temp_views + end + + def restore_original_routes + Rails.application.reload_routes! + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/i18n_faker.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/i18n_faker.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/i18n_faker.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/i18n_faker.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,15 @@ +module UnitTests + module I18nFaker + extend self + + def self.configure_example_group(example_group) + example_group.include(self) + end + + def stub_translation(key_or_keys, message) + keys = [key_or_keys].flatten.join('.').split('.') + tree = keys.reverse.inject(message) { |data, key| { key => data } } + I18n.backend.store_translations(:en, tree) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/mailer_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/mailer_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/mailer_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/mailer_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,12 @@ +module UnitTests + module MailerBuilder + def self.configure_example_group(example_group) + example_group.include(self) + end + + def define_mailer(name, paths, &block) + class_name = name.to_s.pluralize.classify + define_class(class_name, ActionMailer::Base, &block) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/model_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/model_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/model_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/model_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,102 @@ +require_relative 'class_builder' + +module UnitTests + module ModelBuilder + include ClassBuilder + + def self.configure_example_group(example_group) + example_group.include(self) + + example_group.after do + clear_column_caches + drop_created_tables + end + end + + def create_table(table_name, options = {}, &block) + connection = ActiveRecord::Base.connection + + begin + connection.execute("DROP TABLE IF EXISTS #{table_name}") + connection.create_table(table_name, options, &block) + created_tables << table_name + connection + rescue Exception => e + connection.execute("DROP TABLE IF EXISTS #{table_name}") + raise e + end + end + + def define_model_class(class_name, &block) + define_class(class_name, ActiveRecord::Base, &block) + end + + def define_active_model_class(class_name, options = {}, &block) + define_class(class_name) do + include ActiveModel::Validations + + options[:accessors].each do |column| + attr_accessor column.to_sym + end + + if block_given? + class_eval(&block) + end + end + end + + def define_model(name, columns = {}, &block) + class_name = name.to_s.pluralize.classify + table_name = class_name.tableize.gsub('/', '_') + + table_block = lambda do |table| + columns.each do |column_name, specification| + if specification.is_a?(Hash) + table.column column_name, specification[:type], specification[:options] + else + table.column column_name, specification + end + end + end + + if columns.key?(:id) && columns[:id] == false + columns.delete(:id) + create_table(table_name, id: false, &table_block) + else + create_table(table_name, &table_block) + end + + define_model_class(class_name).tap do |model| + if block + model.class_eval(&block) + end + + model.table_name = table_name + end + end + + private + + def clear_column_caches + # Rails 4.x + if ActiveRecord::Base.connection.respond_to?(:schema_cache) + ActiveRecord::Base.connection.schema_cache.clear! + # Rails 3.1 - 4.0 + elsif ActiveRecord::Base.connection_pool.respond_to?(:clear_cache!) + ActiveRecord::Base.connection_pool.clear_cache! + end + end + + def drop_created_tables + connection = ActiveRecord::Base.connection + + created_tables.each do |table_name| + connection.execute("DROP TABLE IF EXISTS #{table_name}") + end + end + + def created_tables + @_created_tables ||= [] + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/rails_versions.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/rails_versions.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/helpers/rails_versions.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/helpers/rails_versions.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,28 @@ +module UnitTests + module RailsVersions + def self.configure_example_group(example_group) + example_group.include(self) + example_group.extend(self) + end + + def rails_version + Tests::Version.new(Rails::VERSION::STRING) + end + + def rails_3_x? + rails_version =~ '~> 3.0' + end + + def rails_4_x? + rails_version =~ '~> 4.0' + end + + def rails_gte_4_1? + rails_version >= 4.1 + end + + def active_record_supports_enum? + defined?(::ActiveRecord::Enum) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/i18n.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/i18n.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/i18n.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/i18n.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,7 @@ +RSpec.configure do |config| + config.after do + # Clear any translations added during tests by telling the backend to + # replace its translations with whatever is in the YAML files. + I18n.backend.reload! + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/deprecate.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/deprecate.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/deprecate.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/deprecate.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,60 @@ +module UnitTests + module Matchers + def deprecate(old_method, new_method) + DeprecateMatcher.new(old_method, new_method) + end + + class DeprecateMatcher + def initialize(old_method, new_method) + @old_method = old_method + @new_method = new_method + end + + def matches?(block) + @captured_stderr = capture(:stderr, &block).gsub(/\n+/, ' ') + captured_stderr.include?(expected_message) + end + + def failure_message + "Expected block to #{expectation}, but it did not.\nActual warning: #{actual_warning}" + end + alias_method :failure_message_for_should, :failure_message + + def failure_message_when_negated + "Expected block not to #{expectation}, but it did." + end + alias_method :failure_message_for_should_not, + :failure_message_when_negated + + def description + "should #{expectation}" + end + + def supports_block_expectations? + true + end + + protected + + attr_reader :old_method, :new_method, :captured_stderr + + private + + def expected_message + "#{old_method} is deprecated and will be removed in the next major release. Please use #{new_method} instead." + end + + def expectation + "print a warning deprecating #{old_method} in favor of #{new_method}" + end + + def actual_warning + if captured_stderr.empty? + "nothing" + else + "\n #{captured_stderr}" + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/fail_with_message_including_matcher.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/fail_with_message_including_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/fail_with_message_including_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/fail_with_message_including_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,50 @@ +module UnitTests + module Matchers + extend RSpec::Matchers::DSL + + matcher :fail_with_message_including do |expected| + def supports_block_expectations? + true + end + + match do |block| + @actual = nil + + begin + block.call + rescue RSpec::Expectations::ExpectationNotMetError => ex + @actual = ex.message + end + + @actual && @actual.include?(expected) + end + + def failure_message + msg = "Expectation should have failed with message including '#{expected}'" + + if @actual + msg << ",\nactually failed with '#{@actual}'" + else + msg << ", but did not fail." + end + + msg + end + + def failure_message_for_should + failure_message + end + + def failure_message_when_negated + msg = "Expectation should not have failed with message including '#{expected}'" + msg << ", but did." + + msg + end + + def failure_message_for_should_not + failure_message_when_negated + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/fail_with_message_matcher.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/fail_with_message_matcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/fail_with_message_matcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/fail_with_message_matcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,51 @@ +module UnitTests + module Matchers + extend RSpec::Matchers::DSL + + matcher :fail_with_message do |expected| + def supports_block_expectations? + true + end + + match do |block| + @actual = nil + + begin + block.call + rescue RSpec::Expectations::ExpectationNotMetError => ex + @actual = ex.message + end + + @actual && @actual == expected + end + + def failure_message + lines = ['Expectation should have failed with message:'] + lines << Shoulda::Matchers::Util.indent(expected, 2) + + if @actual + lines << 'Actually failed with:' + lines << Shoulda::Matchers::Util.indent(@actual, 2) + else + lines << 'However, the expectation did not fail.' + end + + lines.join("\n") + end + + def failure_message_for_should + failure_message + end + + def failure_message_when_negated + lines = ['Expectation should not have failed with message:'] + lines << Shoulda::Matchers::Util.indent(expected, 2) + lines.join("\n") + end + + def failure_message_for_should_not + failure_message_when_negated + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/print_warning_including.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/print_warning_including.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/matchers/print_warning_including.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/matchers/print_warning_including.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,59 @@ +module UnitTests + module Matchers + def print_warning_including(expected_warning) + PrintWarningIncludingMatcher.new(expected_warning) + end + + class PrintWarningIncludingMatcher + def initialize(expected_warning) + @expected_warning = collapse_whitespace(expected_warning) + end + + def matches?(block) + @captured_stderr = collapse_whitespace(capture(:stderr, &block)) + captured_stderr.include?(expected_warning) + end + + def failure_message + "Expected block to #{expectation}\nbut actually printed#{actual_warning}" + end + alias_method :failure_message_for_should, :failure_message + + def failure_message_when_negated + "Expected block not to #{expectation}, but it did." + end + alias_method :failure_message_for_should_not, + :failure_message_when_negated + + def description + "should #{expectation}" + end + + def supports_block_expectations? + true + end + + protected + + attr_reader :expected_warning, :captured_stderr + + private + + def expectation + "print a warning including:\n #{expected_warning}" + end + + def actual_warning + if captured_stderr.empty? + " nothing." + else + ":\n #{captured_stderr}" + end + end + + def collapse_whitespace(string) + string.gsub(/\n+/, ' ').squeeze(' ') + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/rails_application.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/rails_application.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/rails_application.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/rails_application.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,110 @@ +require_relative '../tests/command_runner' +require_relative '../tests/filesystem' +require_relative '../tests/bundle' + +module UnitTests + class RailsApplication + def initialize + @fs = Tests::Filesystem.new + @bundle = Tests::Bundle.new + end + + def create + fs.clean + generate + fs.within_project { install_gems } + end + + def load + load_environment + run_migrations + end + + def gemfile_path + fs.find('Gemfile') + end + + def environment_file_path + fs.find_in_project('config/environment') + end + + def temp_views_directory + fs.find_in_project('tmp/views') + end + + def create_temp_view(path, contents) + full_path = temp_view_path_for(path) + full_path.dirname.mkpath + full_path.open('w') { |f| f.write(contents) } + end + + def delete_temp_views + if temp_views_directory.exist? + temp_views_directory.rmtree + end + end + + def draw_routes(&block) + Rails.application.routes.draw(&block) + Rails.application.routes + end + + protected + + attr_reader :fs, :shell, :bundle + + private + + def migrations_directory + fs.find_in_project('db/migrate') + end + + def temp_view_path_for(path) + temp_views_directory.join(path) + end + + def generate + rails_new + fix_available_locales_warning + end + + def rails_new + run_command! %W(rails new #{fs.project_directory} --skip-bundle) + end + + def fix_available_locales_warning + # See here for more on this: + # http://stackoverflow.com/questions/20361428/rails-i18n-validation-deprecation-warning + + filename = 'config/application.rb' + + lines = fs.read(filename).split("\n") + lines.insert(-3, < :string) do + validates_confirmation_of(_attribute, _options) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/record_with_different_error_attribute_builder.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/record_with_different_error_attribute_builder.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/record_with_different_error_attribute_builder.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/record_with_different_error_attribute_builder.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,92 @@ +require_relative 'helpers/model_builder' + +module UnitTests + class RecordWithDifferentErrorAttributeBuilder + include ModelBuilder + + def initialize(options) + @options = options.reverse_merge(default_options) + end + + def attribute_that_receives_error + options[:attribute_that_receives_error] + end + + def attribute_to_validate + options[:attribute_to_validate] + end + + def message + options[:message] + end + + def message=(message) + options[:message] = message + end + + def model + @_model ||= create_model + end + + def model_name + 'Example' + end + + def record + model.new + end + + def valid_value + 'some value' + end + + protected + + attr_reader :options + + private + + def context + { + validation_method_name: validation_method_name, + valid_value: valid_value, + attribute_to_validate: attribute_to_validate, + attribute_that_receives_error: attribute_that_receives_error, + message: message + } + end + + def create_model + _context = context + + define_model model_name, model_columns do + validate _context[:validation_method_name] + + define_method(_context[:validation_method_name]) do + if self[_context[:attribute_to_validate]] != _context[:valid_value] + self.errors.add(_context[:attribute_that_receives_error], _context[:message]) + end + end + end + end + + def validation_method_name + :custom_validation + end + + def model_columns + { + attribute_to_validate => :string, + attribute_that_receives_error => :string + } + end + + def default_options + { + attribute_that_receives_error: :attribute_that_receives_error, + attribute_to_validate: :attribute_to_validate, + message: 'some message' + } + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/shared_examples/numerical_submatcher.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/shared_examples/numerical_submatcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/shared_examples/numerical_submatcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/shared_examples/numerical_submatcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,17 @@ +shared_examples 'a numerical submatcher' do + it 'implements the with_message method' do + expect(subject).to respond_to(:with_message).with(1).arguments + end + + it 'implements the matches? method' do + expect(subject).to respond_to(:matches?).with(1).arguments + end + + it 'implements the failure_message method' do + expect(subject).to respond_to(:failure_message).with(0).arguments + end + + it 'implements the failure_message_when_negated method' do + expect(subject).to respond_to(:failure_message_when_negated).with(0).arguments + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/shared_examples/numerical_type_submatcher.rb ruby-shoulda-matchers-2.8.0/spec/support/unit/shared_examples/numerical_type_submatcher.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/support/unit/shared_examples/numerical_type_submatcher.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/support/unit/shared_examples/numerical_type_submatcher.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,15 @@ +shared_examples 'a numerical type submatcher' do + it 'implements the allowed_type method' do + expect(subject).to respond_to(:allowed_type).with(0).arguments + expect { subject.allowed_type }.not_to raise_error + end + + it 'implements the diff_to_compare' do + expect(subject).to respond_to(:diff_to_compare).with(0).arguments + expect { subject.diff_to_compare }.not_to raise_error + end + + it 'returns itself when given a message' do + expect(subject.with_message('some message')).to eq subject + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/callback_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,82 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::CallbackMatcher, type: :controller do + shared_examples 'CallbackMatcher' do |kind, callback_type| + let(:kind) { kind } + let(:callback_type) { callback_type } + let(:method_name) { :authenticate_user! } + let(:matcher) { described_class.new(method_name, kind, callback_type) } + let(:controller) { define_controller('HookController').new } + + def match + __send__("use_#{kind}_#{callback_type}", method_name) + end + + it "matches when a #{kind} hook is in place" do + add_callback(kind, callback_type, method_name) + + expect(controller).to match + end + + it "does not match when a #{kind} hook is missing" do + expect(controller).not_to match + end + + describe 'description' do + it 'includes the filter kind and name' do + expect(matcher.description).to eq "have #{method_name.inspect} as a #{kind}_#{callback_type}" + end + end + + describe 'failure message' do + it 'includes the filter kind and name that was expected' do + message = "Expected that HookController would have #{method_name.inspect} as a #{kind}_#{callback_type}" + + expect { + expect(controller).to send("use_#{kind}_#{callback_type}", method_name) + }.to fail_with_message(message) + end + end + + describe 'failure message when negated' do + it 'includes the filter kind and name that was expected' do + add_callback(kind, callback_type, method_name) + message = "Expected that HookController would not have #{method_name.inspect} as a #{kind}_#{callback_type}" + + expect { expect(controller).not_to match }.to fail_with_message(message) + end + end + + private + + def add_callback(kind, callback_type, callback) + controller.class.__send__("#{kind}_#{callback_type}", callback) + end + end + + describe '#use_before_filter' do + it_behaves_like 'CallbackMatcher', :before, :filter + end + + describe '#use_after_filter' do + it_behaves_like 'CallbackMatcher', :after, :filter + end + + describe '#use_around_filter' do + it_behaves_like 'CallbackMatcher', :around, :filter + end + + if rails_4_x? + describe '#use_before_action' do + it_behaves_like 'CallbackMatcher', :before, :action + end + + describe '#use_after_action' do + it_behaves_like 'CallbackMatcher', :after, :action + end + + describe '#use_around_action' do + it_behaves_like 'CallbackMatcher', :around, :action + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/filter_param_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,28 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::FilterParamMatcher, type: :controller do + it 'accepts filtering a filtered parameter' do + filter(:secret) + + expect(nil).to filter_param(:secret) + end + + it 'accepts filtering a parameter matching a filtered regex' do + filter(/(?!tip)pin(?!g)/) + + expect(nil).to filter_param(:pin) + end + + it 'rejects filtering an unfiltered parameter' do + filter(:secret) + matcher = filter_param(:other) + + expect(matcher.matches?(nil)).to eq false + + expect(matcher.failure_message).to match(/Expected other to be filtered.*secret/) + end + + def filter(param) + Rails.application.config.filter_parameters = [param] + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,42 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RedirectToMatcher, type: :controller do + context 'a controller that redirects' do + it 'accepts redirecting to that url' do + expect(controller_redirecting_to('/some/url')).to redirect_to('/some/url') + end + + it 'rejects redirecting to a different url' do + expect(controller_redirecting_to('/some/url')). + not_to redirect_to('/some/other/url') + end + + it 'accepts redirecting to that url in a block' do + expect(controller_redirecting_to('/some/url')). + to redirect_to('somewhere') { '/some/url' } + end + + it 'rejects redirecting to a different url in a block' do + expect(controller_redirecting_to('/some/url')). + not_to redirect_to('somewhere else') { '/some/other/url' } + end + + def controller_redirecting_to(url) + build_fake_response { redirect_to url } + end + end + + context 'a controller that does not redirect' do + it 'rejects redirecting to a url' do + controller = build_fake_response { render text: 'hello' } + + expect(controller).not_to redirect_to('/some/url') + end + end + + it 'provides the correct description when provided a block' do + matcher = redirect_to('somewhere else') { '/some/other/url' } + + expect(matcher.description).to eq 'redirect to "somewhere else"' + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/render_template_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,76 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RenderTemplateMatcher, type: :controller do + context 'a controller that renders a template' do + it 'accepts rendering that template' do + expect(controller_with_show).to render_template(:show) + end + + it 'rejects rendering a different template' do + expect(controller_with_show).not_to render_template(:index) + end + + it 'accepts rendering that template in the given context' do + expect(controller_with_show).to render_template(:show).in_context(self) + end + + it 'rejects rendering a different template in the given context' do + expect(controller_with_show).not_to render_template(:index).in_context(self) + end + + def controller_with_show + build_fake_response(action: 'show') { render } + end + end + + context 'a controller that renders a partial' do + it 'accepts rendering that partial' do + expect(controller_with_customer_partial). + to render_template(partial: '_customer') + end + + it 'rejects rendering a different template' do + expect(controller_with_customer_partial). + not_to render_template(partial: '_client') + end + + it 'accepts rendering that template in the given context' do + expect(controller_with_customer_partial). + to render_template(partial: '_customer').in_context(self) + end + + it 'rejects rendering a different template in the given context' do + expect(controller_with_customer_partial). + not_to render_template(partial: '_client').in_context(self) + end + + def controller_with_customer_partial + build_fake_response(partial: '_customer') { render partial: 'customer' } + end + end + + context 'a controller that does not render partials' do + it 'accepts not rendering a partial' do + controller = build_fake_response(action: 'show') { render } + + expect(controller).to render_template(partial: false) + end + end + + context 'a controller that renders a partial several times' do + it 'accepts rendering that partial twice' do + controller = build_fake_response(partial: '_customer') do + render partial: 'customer', collection: [1,2] + end + + expect(controller).to render_template(partial: '_customer', count: 2) + end + end + + context 'a controller that does not render a template' do + it 'rejects rendering a template' do + expect(build_fake_response { render nothing: true }). + not_to render_template(:show) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,66 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RenderWithLayoutMatcher, type: :controller do + include ActionController::TemplateAssertions + + context 'a controller that renders with a layout' do + it 'accepts rendering with any layout' do + expect(controller_with_wide_layout).to render_with_layout + end + + it 'accepts rendering with that layout' do + expect(controller_with_wide_layout).to render_with_layout(:wide) + end + + it 'rejects rendering with another layout' do + expect(controller_with_wide_layout).not_to render_with_layout(:other) + end + + def controller_with_wide_layout + create_view('layouts/wide.html.erb', 'some content, <%= yield %>') + build_fake_response { render layout: 'wide' } + end + end + + context 'a controller that renders without a layout' do + + it 'rejects rendering with a layout' do + controller_without_layout = build_fake_response { render layout: false } + + expect(controller_without_layout).not_to render_with_layout + end + end + + context 'a controller that renders a partial' do + it 'rejects rendering with a layout' do + controller_with_partial = build_fake_response { render partial: 'partial' } + + expect(controller_with_partial).not_to render_with_layout + end + end + + context 'given a context with layouts' do + it 'accepts that layout in that context' do + context = Object.new + set_layout_in_context(context, 'happy') + + expect(controller_without_layout). + to render_with_layout('happy'). + in_context(context) + end + + def set_layout_in_context(context, layout) + layouts = Hash.new(0) + layouts[layout] = 1 + context.instance_variable_set(layouts_ivar, layouts) + end + + def layouts_ivar + Shoulda::Matchers::RailsShim.layouts_ivar + end + + def controller_without_layout + build_fake_response { render layout: false } + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,90 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RescueFromMatcher, type: :controller do + context 'a controller that rescues from RuntimeError' do + it 'asserts controller is setup with rescue_from' do + expect(controller_with_rescue_from).to rescue_from RuntimeError + end + + context 'with a handler method' do + it 'asserts rescue_from can find the handler when it is public' do + controller = controller_with_rescue_from_and_method(:public) + check_rescue_with_method_for(controller) + end + + it 'asserts rescue_from can find the handler when it is protected' do + controller = controller_with_rescue_from_and_method(:protected) + check_rescue_with_method_for(controller) + end + + it 'asserts rescue_from can find the handler when it is private' do + controller = controller_with_rescue_from_and_method(:private) + check_rescue_with_method_for(controller) + end + + it 'asserts rescue_from was not set up with incorrect handler method' do + expect(controller_with_rescue_from_and_method).not_to rescue_from(RuntimeError).with(:other_method) + end + + it 'asserts the controller responds to the handler method' do + matcher = rescue_from(RuntimeError).with(:error_method) + expect(matcher.matches?(controller_with_rescue_from_and_invalid_method)).to eq false + expect(matcher.failure_message).to match(/does not respond to/) + end + end + + context 'without a handler method' do + it 'the handler method is not included in the description' do + matcher = rescue_from(RuntimeError) + expect(matcher.matches?(controller_with_rescue_from)).to eq true + expect(matcher.description).not_to match(/with #/) + end + end + end + + context 'a controller that does not rescue from RuntimeError' do + it 'asserts controller is not setup with rescue_from' do + matcher = rescue_from RuntimeError + expect(define_controller('RandomController')).not_to matcher + expect(matcher.failure_message_when_negated).to match(/Did not expect \w+ to rescue from/) + end + end + + def check_rescue_with_method_for(controller) + expect(controller).to rescue_from(RuntimeError).with(:error_method) + end + + def controller_with_rescue_from + define_controller 'RescueRuntimeError' do + rescue_from(RuntimeError) {} + end + end + + def controller_with_rescue_from_and_invalid_method + define_controller 'RescueRuntimeErrorWithMethod' do + rescue_from RuntimeError, with: :error_method + end + end + + def controller_with_rescue_from_and_method(access = :public) + controller = controller_with_rescue_from_and_invalid_method + class << controller + def error_method + true + end + end + + case access + when :protected + class << controller + protected :error_method + end + when :private + class << controller + private :error_method + end + end + + controller + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/respond_with_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,31 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RespondWithMatcher, type: :controller do + statuses = { success: 200, redirect: 301, missing: 404, error: 500, + not_implemented: 501 } + + statuses.each do |human_name, numeric_code| + context "a controller responding with #{human_name}" do + it 'accepts responding with a numeric response code' do + expect(controller_with_status(numeric_code)).to respond_with(numeric_code) + end + + it 'accepts responding with a symbol response code' do + expect(controller_with_status(numeric_code)).to respond_with(human_name) + end + + it 'rejects responding with another status' do + another_status = statuses.except(human_name).keys.first + + expect(controller_with_status(numeric_code)). + not_to respond_with(another_status) + end + end + end + + def controller_with_status(status) + build_fake_response do + render text: 'text', status: status + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,126 @@ +require 'unit_spec_helper' + +describe 'Shoulda::Matchers::ActionController::RouteMatcher', type: :controller do + shared_examples_for 'a controller with a defined route' do + context 'when controller and action are specified as explicit options' do + it 'accepts' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}"). + to(action: 'index') + end + + it 'accepts a symbol controller' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}"). + to(controller: controller_path.to_sym, action: 'index') + end + + it 'accepts a symbol action' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}"). + to(action: :index) + end + + it 'rejects an undefined route' do + expect(controller_with_defined_routes). + not_to route(:get, '/non_existent_route'). + to(action: 'non_existent') + end + + it 'rejects a route for another controller' do + define_controller_with_defined_routes + other_controller = define_controller('Other').new + expect(other_controller). + not_to route(:get, "/#{controller_path}"). + to(action: 'index') + end + + context 'when route has parameters' do + it 'accepts a non-string parameter' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}/1"). + to(action: 'show', id: 1) + end + + it 'rejects a route for different parameters' do + expect(controller_with_defined_routes). + not_to route(:get, "/#{controller_path}/1"). + to(action: 'show', some: 'other', params: 'here') + end + end + end + + context 'when controller and action are specified as a joined string' do + it 'accepts' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}"). + to("#{controller_path}#index") + end + + context 'when route has parameters' do + it 'accepts a non-string parameter' do + expect(controller_with_defined_routes). + to route(:get, "/#{controller_path}/1"). + to("#{controller_path}#show", id: 1) + end + end + end + + def controller_with_defined_routes + @_controller_with_defined_routes ||= begin + controller_class = define_controller(controller_name) + _controller_path = controller_path + + setup_rails_controller_test(controller_class) + + define_routes do + get "/#{_controller_path}", to: "#{_controller_path}#index" + get "/#{_controller_path}/:id", to: "#{_controller_path}#show" + end + + controller + end + end + + def controller_path + controller_name.sub(/Controller$/, '').underscore + end + + alias_method :define_controller_with_defined_routes, + :controller_with_defined_routes + end + + context 'given a controller with a defined glob url' do + it 'accepts glob route' do + controller_class = define_controller('Examples') + setup_rails_controller_test(controller_class) + + define_routes do + get '/examples/*id', to: 'examples#example' + end + + expect(controller).to route(:get, '/examples/foo/bar'). + to(action: 'example', id: 'foo/bar') + end + end + + context 'given a controller that is not namespaced' do + it_behaves_like 'a controller with a defined route' do + def controller_name + 'ExamplesController' + end + end + end + + context 'given a controller that is namespaced' do + it_behaves_like 'a controller with a defined route' do + before do + define_module('Admin') + end + + def controller_name + 'Admin::ExamplesController' + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/route_params_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,30 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController::RouteParams, type: :controller do + describe "#normalize" do + context "when the route parameters is a hash" do + it "stringifies the values in the hash" do + expect(build_route_params(controller: :examples, action: 'example', id: '1').normalize). + to eq({ controller: "examples", action: "example", id: "1" }) + end + end + + context "when the route parameters is a string and a hash" do + it "produces a hash of route parameters" do + expect(build_route_params("examples#example", id: '1').normalize). + to eq({ controller: "examples", action: "example", id: "1" }) + end + end + + context "when the route params is a string" do + it "produces a hash of route params" do + expect(build_route_params("examples#index").normalize). + to eq({ controller: "examples", action: "index"}) + end + end + end + + def build_route_params(*params) + Shoulda::Matchers::ActionController::RouteParams.new(params) + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,167 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController, type: :controller do + describe '#set_the_flash' do + it 'is deprecated in favor of #set_flash' do + expect { set_the_flash }.to deprecate(:set_the_flash, :set_flash) + end + + it 'still works regardless' do + silence_warnings do + expect(controller_with_flash(notice: 'hi')).to set_the_flash + end + end + end + + describe '#set_flash' do + it 'fails with unmatchable #to' do + expect { set_flash.to(1) }.to raise_error('cannot match against 1') + end + + context 'a controller that sets a flash message' do + it 'accepts setting any flash message' do + expect(controller_with_flash(notice: 'hi')).to set_flash + end + + it 'accepts setting the exact flash message' do + expect(controller_with_flash(notice: 'hi')).to set_flash.to('hi') + end + + it 'accepts setting a matched flash message' do + expect(controller_with_flash(notice: 'hello')).to set_flash.to(/he/) + end + + it 'rejects setting a different flash message' do + expect(controller_with_flash(notice: 'hi')). + not_to set_flash.to('other') + end + + it 'rejects setting a different pattern' do + expect(controller_with_flash(notice: 'hi')). + not_to set_flash.to(/other/) + end + end + + context 'a controller that sets a flash.now message' do + it 'rejects setting any flash message' do + expect(controller_with_flash_now).not_to set_flash + end + + it 'accepts setting any flash.now message' do + expect(controller_with_flash_now).to set_flash.now + end + + it 'accepts setting the exact flash.now message' do + expect(controller_with_flash_now(notice: 'hi')). + to set_flash.now.to('hi') + end + + it 'accepts setting a matched flash.now message' do + expect(controller_with_flash_now(notice: 'flasher')). + to set_flash.now.to(/lash/) + end + + it 'rejects setting a different flash.now message' do + expect(controller_with_flash_now(notice: 'hi')). + not_to set_flash.now.to('other') + end + + it 'rejects setting a different flash.now pattern' do + expect(controller_with_flash_now(notice: 'hi')). + not_to set_flash.now.to(/other/) + end + end + + context 'a controller that sets flash messages for multiple keys' do + it 'accepts flash message for either key' do + controller = controller_with_flash(notice: 'one', alert: 'two') + + expect(controller).to set_flash[:notice] + expect(controller).to set_flash[:alert] + end + + it 'rejects a flash message that is not one of the set keys' do + expect(controller_with_flash(notice: 'one', alert: 'two')). + not_to set_flash[:warning] + end + + it 'accepts exact flash message of notice' do + expect(controller_with_flash(notice: 'one', alert: 'two')). + to set_flash[:notice].to('one') + end + + it 'accepts setting a matched flash message of notice' do + expect(controller_with_flash(notice: 'one', alert: 'two')). + to set_flash[:notice].to(/on/) + end + + it 'rejects setting a different flash message of notice' do + expect(controller_with_flash(notice: 'one', alert: 'two')). + not_to set_flash[:notice].to('other') + end + + it 'rejects setting a different pattern' do + expect(controller_with_flash(notice: 'one', alert: 'two')). + not_to set_flash[:notice].to(/other/) + end + end + + context 'a controller that sets flash and flash.now' do + it 'accepts setting any flash.now message' do + controller = build_fake_response do + flash.now[:notice] = 'value' + flash[:success] = 'great job' + end + + expect(controller).to set_flash.now + expect(controller).to set_flash + end + + it 'accepts setting a matched flash.now message' do + controller = build_fake_response do + flash.now[:notice] = 'value' + flash[:success] = 'great job' + end + + expect(controller).to set_flash.now.to(/value/) + expect(controller).to set_flash.to(/great/) + end + + it 'rejects setting a different flash.now message' do + controller = build_fake_response do + flash.now[:notice] = 'value' + flash[:success] = 'great job' + end + + expect(controller).not_to set_flash.now.to('other') + expect(controller).not_to set_flash.to('other') + end + end + + context 'a controller that does not set a flash message' do + it 'rejects setting any flash message' do + expect(controller_with_no_flashes).not_to set_flash + end + end + end + + def controller_with_no_flashes + build_fake_response + end + + def controller_with_flash(flash_hash) + build_fake_response do + flash_hash.each do |key, value| + flash[key] = value + end + end + end + + def controller_with_flash_now(flash_hash = { notice: 'hi' }) + build_fake_response do + flash_hash.each do |key, value| + flash.now[key] = value + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,294 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActionController, '#set_session', type: :controller do + context 'passing an argument to the initializer' do + it 'is deprecated in favor of using #[]' do + expectation = proc { set_session(:foo) } + + expect(&expectation).to print_warning_including( + 'Passing a key to set_session is deprecated' + ) + end + + it 'still works regardless' do + silence_warnings do + expect(controller_with_session(var: 'hi')).to set_session(:var) + end + end + end + + context 'a controller that sets a session variable' do + context 'without any qualifiers' do + it 'accepts' do + expect(controller_with_session(var: 'hi')).to set_session + end + end + + context 'with #to' do + context 'given a static value' do + context 'when any key in session has the given value' do + it 'accepts' do + expect(controller_with_session(var: 'hi')). + to set_session.to('hi') + end + + it 'accepts given nil' do + silence_warnings do + expect(controller_with_session(var: nil)). + to set_session.to(nil) + end + end + + it 'accepts given false' do + expect(controller_with_session(var: false)). + to set_session.to(false) + end + end + + context 'when no key in session has the given value' do + it 'rejects' do + expect(controller_with_session(var: 'hi')). + not_to set_session.to('different') + end + end + end + + context 'given a dynamic value' do + context 'when any key in session has the given value' do + it 'accepts' do + context = double(expected: 'hi') + expect(controller_with_session(var: 'hi')). + to set_session.in_context(context).to { expected } + end + + it 'accepts given nil' do + silence_warnings do + context = double(expected: nil) + expect(controller_with_session(var: nil)). + to set_session.in_context(context).to { expected } + end + end + + it 'accepts given false' do + context = double(expected: false) + expect(controller_with_session(var: false)). + to set_session.in_context(context).to { expected } + end + end + + context 'when no key in session has the given value' do + it 'rejects' do + context = double(expected: 'different') + expect(controller_with_session(var: 'hi')). + not_to set_session.in_context(context).to { expected } + end + end + end + + context 'given a regexp' do + context 'when any value in session matches the regexp' do + it 'accepts' do + expect(controller_with_session(var: 'hello')). + to set_session.to(/ello/) + end + end + + context 'when no value in session matches the regexp' do + it 'rejects' do + expect(controller_with_session(var: 'hello')). + not_to set_session.to(/different/) + end + end + end + end + + context 'with #[]' do + context 'when the given key is present in session' do + it 'accepts' do + expect(controller_with_session(var: 'hi')).to set_session[:var] + end + + it 'accepts when expected key is a string' do + expect(controller_with_session(var: 'hi')).to set_session['var'] + end + end + + context 'when the given key is not present in session' do + it 'rejects' do + expect(controller_with_session(var: 'hi')).not_to set_session[:other] + end + end + end + + context 'with #[] + #to' do + context 'given a static value' do + context 'when the given key and value are present in session' do + it 'accepts' do + expect(controller_with_session(var: 'hi')). + to set_session[:var].to('hi') + end + + it 'accepts given nil' do + silence_warnings do + expect(controller_with_session(var: nil)). + to set_session[:var].to(nil) + end + end + + it 'accepts given false' do + expect(controller_with_session(var: false)). + to set_session[:var].to(false) + end + end + + context 'when the given key is present in session but not the given value' do + it 'rejects' do + expect(controller_with_session(var: 'hi')). + not_to set_session[:var].to('other') + end + + it 'rejects given nil' do + expect(controller_with_session(var: 'hi')). + not_to set_session[:var].to(nil) + end + end + + context 'when the given key is not present in session' do + it 'accepts given nil' do + silence_warnings do + expect(controller_with_session(var: 'hi')). + to set_session[:other].to(nil) + end + end + + it 'rejects given false' do + expect(controller_with_session(var: false)). + not_to set_session[:other].to(false) + end + end + end + + context 'given a dynamic value' do + context 'when the given key and value are present in session' do + it 'accepts' do + context = double(expected: 'value') + + expect(controller_with_session(var: 'value')). + to set_session[:var].in_context(context).to { expected } + end + + it 'accepts given nil' do + silence_warnings do + context = double(expected: nil) + + expect(controller_with_session(var: nil)). + to set_session[:var].in_context(context).to { expected } + end + end + + it 'accepts given false' do + context = double(expected: false) + + expect(controller_with_session(var: false)). + to set_session[:var].in_context(context).to { expected } + end + end + + context 'when the given key is present in session but not the given value' do + it 'rejects given nil' do + context = double(expected: nil) + + expect(controller_with_session(var: 'hi')). + not_to set_session[:var].in_context(context).to { expected } + end + + it 'rejects given false' do + context = double(expected: false) + + expect(controller_with_session(var: 'hi')). + not_to set_session[:var].in_context(context).to { expected } + end + end + + context 'when the given key is not present in session' do + it 'rejects' do + context = double(expected: 'other') + + expect(controller_with_session(var: 'unexpected')). + not_to set_session[:var].in_context(context).to { expected } + end + + it 'accepts given nil' do + silence_warnings do + context = double(expected: nil) + + expect(controller_with_session(var: 'hi')). + to set_session[:other].in_context(context).to { expected } + end + end + + it 'rejects given false' do + context = double(expected: false) + + expect(controller_with_session(var: false)). + not_to set_session[:other].in_context(context).to { expected } + end + end + end + end + end + + context 'a controller that does not set any session variables' do + context 'without any qualifiers' do + it 'rejects' do + expect(controller_without_session).not_to set_session + end + end + + context 'with #[]' do + it 'rejects' do + expect(controller_without_session). + not_to set_session['any key'] + end + end + + context 'with #to' do + it 'rejects' do + expect(controller_without_session). + not_to set_session.to('any value') + end + end + + context 'with #[] + #to' do + it 'rejects' do + expect(controller_without_session). + not_to set_session['any key'].to('any value') + end + + it 'prints a warning when using .to(nil) to assert that a variable is unset' do + expectation = proc do + expect(controller_without_session).to set_session['any key'].to(nil) + end + + expected_warning = < { + get '/posts/:slug', to: 'posts#show' + } + } + controller_for_resource_with_strong_parameters(options) do + params.require(:user).permit(:name) + end + + matcher = described_class.new([:name]). + in_context(self). + for(:show, verb: :get, params: { slug: 'foo' }) + expect(matcher.matches?(@controller)).to be true + end + + it 'works with #update specifically' do + controller_for_resource_with_strong_parameters(action: :update) do + params.require(:user).permit(:name) + end + + matcher = described_class.new([:name]). + in_context(self). + for(:update, params: { id: 1 }) + expect(matcher.matches?(@controller)).to be true + end + + it 'does not raise an error when #fetch was used instead of #require (issue #495)' do + controller_for_resource_with_strong_parameters(action: :create) do + params.fetch(:order, {}).permit(:eta, :diner_id) + end + + matcher = described_class.new([:eta, :diner_id]). + in_context(self). + for(:create) + expect(matcher.matches?(@controller)).to be true + end + + it 'tracks multiple calls to #permit' do + sets_of_attributes = [ + [:eta, :diner_id], + [:phone_number, :address_1, :address_2, :city, :state, :zip] + ] + controller_for_resource_with_strong_parameters(action: :create) do + params.require(:order).permit(sets_of_attributes[0]) + params.require(:diner).permit(sets_of_attributes[1]) + end + + matcher = described_class.new(sets_of_attributes[0]). + in_context(self). + for(:create) + expect(matcher.matches?(@controller)).to be true + + matcher = described_class.new(sets_of_attributes[1]). + in_context(self). + for(:create) + expect(matcher.matches?(@controller)).to be true + end + + context 'stubbing params on the controller' do + it 'still allows the original params to be set and accessed' do + actual_user_params = nil + actual_foo_param = nil + + controller_for_resource_with_strong_parameters(action: :create) do + params[:foo] = 'bar' + actual_foo_param = params[:foo] + + actual_user_params = params[:user] + + params.require(:user).permit(:name) + end + + matcher = described_class.new([:name]). + in_context(self). + for(:create, params: { user: { some: 'params' } }) + matcher.matches?(@controller) + + expect(actual_user_params).to eq('some' => 'params') + expect(actual_foo_param).to eq 'bar' + end + + it 'stubs the params during the controller action' do + controller_for_resource_with_strong_parameters(action: :create) do + params.require(:user) + end + + matcher = described_class.new([:name]).in_context(self).for(:create) + + expect { matcher.matches?(@controller) }.not_to raise_error + end + + it 'does not permanently stub params' do + controller_for_resource_with_strong_parameters(action: :create) + + matcher = described_class.new([:name]).in_context(self).for(:create) + matcher.matches?(@controller) + + expect { + @controller.params.require(:user) + }.to raise_error(::ActionController::ParameterMissing) + end + + it 'prevents permanently stubbing params on error' do + stub_controller_with_exception + + begin + matcher = described_class.new([:name]).in_context(self).for(:create) + matcher.matches?(@controller) + rescue SimulatedError + end + + expect { + @controller.params.require(:user) + }.to raise_error(::ActionController::ParameterMissing) + end + end + end + + describe 'failure message' do + it 'includes all missing attributes' do + controller_for_resource_with_strong_parameters(action: :create) do + params.require(:user).permit(:name, :age) + end + + expect { + expect(@controller).to permit(:name, :age, :city, :country).for(:create) + }.to fail_with_message('Expected controller to permit city and country, but it did not.') + end + + it 'includes all attributes that should not have been allowed but were' do + controller_for_resource_with_strong_parameters(action: :create) do + params.require(:user).permit(:name, :age) + end + + expect { + expect(@controller).not_to permit(:name, :age).for(:create) + }.to fail_with_message('Expected controller not to permit name and age, but it did.') + end + end + + describe '#for' do + context 'when given :create' do + it 'POSTs to the controller' do + controller = ActionController::Base.new + context = build_context + matcher = described_class.new([:name]).in_context(context).for(:create) + + matcher.matches?(controller) + + expect(context).to have_received(:post).with(:create, {}) + end + end + + context 'when given :update' do + if rails_gte_4_1? + it 'PATCHes to the controller' do + controller = ActionController::Base.new + context = build_context + matcher = described_class.new([:name]).in_context(context).for(:update) + + matcher.matches?(controller) + + expect(context).to have_received(:patch).with(:update, {}) + end + else + it 'PUTs to the controller' do + controller = ActionController::Base.new + context = build_context + matcher = described_class.new([:name]).in_context(context).for(:update) + + matcher.matches?(controller) + + expect(context).to have_received(:put).with(:update, {}) + end + end + end + + context 'when given a custom action and verb' do + it 'calls the action with the verb' do + controller = ActionController::Base.new + context = build_context + matcher = described_class.new([:name]). + in_context(context). + for(:hide, verb: :delete) + + matcher.matches?(controller) + + expect(context).to have_received(:delete).with(:hide, {}) + end + end + end + + def stub_controller_with_exception + controller_class = define_controller('Examples') do + def create + raise SimulatedError + end + end + + setup_rails_controller_test(controller_class) + + define_routes do + get 'examples', to: 'examples#create' + end + end + + def build_context + double('context', post: nil, put: nil, patch: nil, delete: nil) + end + + class SimulatedError < StandardError; end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,111 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::AllowMassAssignmentOfMatcher, type: :model do + context '#description' do + context 'without a role' do + it 'includes the attribute name' do + expect(described_class.new(:attr).description). + to eq 'allow mass assignment of attr' + end + end + + if active_model_3_1? + context 'with a role' do + it 'includes the attribute name and the role' do + expect(described_class.new(:attr).as(:admin).description). + to eq 'allow mass assignment of attr as admin' + end + end + end + end + + context 'an attribute that is blacklisted from mass-assignment' do + it 'rejects being mass-assignable' do + model = define_model(:example, blacklisted: :string) do + attr_protected :blacklisted + end.new + + expect(model).not_to allow_mass_assignment_of(:blacklisted) + end + end + + context 'an attribute that is not whitelisted for mass-assignment' do + it 'rejects being mass-assignable' do + model = define_model(:example, not_whitelisted: :string, + whitelisted: :string) do + attr_accessible :whitelisted + end.new + + expect(model).not_to allow_mass_assignment_of(:not_whitelisted) + end + end + + context 'an attribute that is whitelisted for mass-assignment' do + it 'accepts being mass-assignable' do + expect(define_model(:example, whitelisted: :string) do + attr_accessible :whitelisted + end.new).to allow_mass_assignment_of(:whitelisted) + end + end + + context 'an attribute not included in the mass-assignment blacklist' do + it 'accepts being mass-assignable' do + model = define_model(:example, not_blacklisted: :string, + blacklisted: :string) do + attr_protected :blacklisted + end.new + + expect(model).to allow_mass_assignment_of(:not_blacklisted) + end + end + + unless active_model_3_2? || active_model_4_0? + context 'an attribute on a class with no protected attributes' do + it 'accepts being mass-assignable' do + expect(no_protected_attributes).to allow_mass_assignment_of(:attr) + end + + it 'assigns a negative failure message' do + matcher = allow_mass_assignment_of(:attr) + + expect(matcher.matches?(no_protected_attributes)).to eq true + + expect(matcher.failure_message_when_negated).not_to be_nil + end + end + + def no_protected_attributes + define_model(:example, attr: :string).new + end + end + + context 'an attribute on a class with all protected attributes' do + it 'rejects being mass-assignable' do + expect(all_protected_attributes).not_to allow_mass_assignment_of(:attr) + end + + def all_protected_attributes + define_model(:example, attr: :string) do + attr_accessible nil + end.new + end + end + + if active_model_3_1? + context 'an attribute included in the mass-assignment whitelist for admin role only' do + it 'rejects being mass-assignable' do + expect(mass_assignable_as_admin).not_to allow_mass_assignment_of(:attr) + end + + it 'accepts being mass-assignable for admin' do + expect(mass_assignable_as_admin).to allow_mass_assignment_of(:attr).as(:admin) + end + + def mass_assignable_as_admin + define_model(:example, attr: :string) do + attr_accessible :attr, as: :admin + end.new + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,304 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::AllowValueMatcher, type: :model do + context "#description" do + it 'describes itself with multiple values' do + matcher = allow_value('foo', 'bar').for(:baz) + + expect(matcher.description).to eq 'allow baz to be set to any of ["foo", "bar"]' + end + + it 'describes itself with a single value' do + matcher = allow_value('foo').for(:baz) + + expect(matcher.description).to eq 'allow baz to be set to "foo"' + end + + if active_model_3_2? + it 'describes itself with a strict validation' do + strict_matcher = allow_value('xyz').for(:attr).strict + + expect(strict_matcher.description). + to eq %q(doesn't raise when attr is set to "xyz") + end + end + end + + describe '#_after_setting_value' do + it 'sets a block which is yielded after each value is set on the attribute' do + attribute = :attr + record = define_model(:example, attribute => :string).new + matcher = described_class.new('a', 'b', 'c').for(attribute) + call_count = 0 + + matcher._after_setting_value { call_count += 1 } + matcher.matches?(record) + + expect(call_count).to eq 3 + end + end + + context 'an attribute with a validation' do + it 'allows a good value' do + expect(validating_format(with: /abc/)).to allow_value('abcde').for(:attr) + end + + it 'rejects a bad value' do + expect(validating_format(with: /abc/)).not_to allow_value('xyz').for(:attr) + end + + it 'allows several good values' do + expect(validating_format(with: /abc/)). + to allow_value('abcde', 'deabc').for(:attr) + end + + it 'rejects several bad values' do + expect(validating_format(with: /abc/)). + not_to allow_value('xyz', 'zyx', nil, []).for(:attr) + end + end + + context 'an attribute with a validation and a custom message' do + it 'allows a good value' do + expect(validating_format(with: /abc/, message: 'bad value')). + to allow_value('abcde').for(:attr).with_message(/bad/) + end + + it 'rejects a bad value' do + expect(validating_format(with: /abc/, message: 'bad value')). + not_to allow_value('xyz').for(:attr).with_message(/bad/) + end + + it 'allows interpolation values for the message to be provided' do + options = { + attribute_name: :attr, + attribute_type: :string + } + + record = record_with_custom_validation(options) do + if self.attr == 'xyz' + self.errors.add :attr, :greater_than, count: 2 + end + end + + expect(record). + not_to allow_value('xyz'). + for(:attr). + with_message(:greater_than, values: { count: 2 }) + end + end + + context 'when the attribute being validated is different than the attribute that receives the validation error' do + include UnitTests::AllowValueMatcherHelpers + + context 'when the validation error message was provided directly' do + it 'passes given a valid value' do + builder = builder_for_record_with_different_error_attribute + expect(builder.record). + to allow_value(builder.valid_value). + for(builder.attribute_to_validate). + with_message(builder.message, + against: builder.attribute_that_receives_error + ) + end + + it 'fails given an invalid value' do + builder = builder_for_record_with_different_error_attribute + invalid_value = "#{builder.valid_value} (invalid)" + expect(builder.record). + not_to allow_value(invalid_value). + for(builder.attribute_to_validate). + with_message(builder.message, + against: builder.attribute_that_receives_error + ) + end + end + + context 'when the validation error message was provided via i18n' do + it 'passes given a valid value' do + builder = builder_for_record_with_different_error_attribute_using_i18n + expect(builder.record). + to allow_value(builder.valid_value). + for(builder.attribute_to_validate). + with_message(builder.validation_message_key, + against: builder.attribute_that_receives_error + ) + end + + it 'fails given an invalid value' do + builder = builder_for_record_with_different_error_attribute_using_i18n + invalid_value = "#{builder.valid_value} (invalid)" + expect(builder.record). + not_to allow_value(invalid_value). + for(builder.attribute_to_validate). + with_message(builder.validation_message_key, + against: builder.attribute_that_receives_error + ) + end + end + end + + context "an attribute with a context-dependent validation" do + context "without the validation context" do + it "allows a bad value" do + expect(validating_format(with: /abc/, on: :customisable)).to allow_value("xyz").for(:attr) + end + end + + context "with the validation context" do + it "allows a good value" do + expect(validating_format(with: /abc/, on: :customisable)).to allow_value("abcde").for(:attr).on(:customisable) + end + + it "rejects a bad value" do + expect(validating_format(with: /abc/, on: :customisable)).not_to allow_value("xyz").for(:attr).on(:customisable) + end + end + end + + context 'an attribute with several validations' do + let(:model) do + define_model :example, attr: :string do + validates_presence_of :attr + validates_length_of :attr, within: 1..5 + validates_numericality_of :attr, greater_than_or_equal_to: 1, + less_than_or_equal_to: 50000 + end.new + end + bad_values = [nil, '', 'abc', '0', '50001', '123456', []] + + it 'allows a good value' do + expect(model).to allow_value('12345').for(:attr) + end + + bad_values.each do |bad_value| + it "rejects a bad value (#{bad_value.inspect})" do + expect(model).not_to allow_value(bad_value).for(:attr) + end + end + + it "rejects several bad values (#{bad_values.map(&:inspect).join(', ')})" do + expect(model).not_to allow_value(*bad_values).for(:attr) + end + + it "rejects a mix of both good and bad values" do + expect(model).not_to allow_value('12345', *bad_values).for(:attr) + end + end + + context 'with a single value' do + it 'allows you to call description before calling matches?' do + model = define_model(:example, attr: :string).new + matcher = described_class.new('foo').for(:attr) + matcher.description + + expect { matcher.matches?(model) }.not_to raise_error + end + end + + context 'with no values' do + it 'raises an error' do + expect { allow_value.for(:baz) }. + to raise_error(ArgumentError, /at least one argument/) + end + end + + if active_model_3_2? + context 'an attribute with a strict format validation' do + it 'strictly rejects a bad value' do + expect(validating_format(with: /abc/, strict: true)). + not_to allow_value('xyz').for(:attr).strict + end + + it 'strictly allows a bad value with a different message' do + expect(validating_format(with: /abc/, strict: true)). + to allow_value('xyz').for(:attr).with_message(/abc/).strict + end + + it 'provides a useful negative failure message' do + matcher = allow_value('xyz').for(:attr).strict.with_message(/abc/) + + matcher.matches?(validating_format(with: /abc/, strict: true)) + + expect(matcher.failure_message_when_negated).to eq( + %{Expected exception to include /abc/ when attr is set to "xyz",\n} + + %{got: "Attr is invalid"} + ) + end + end + end + + if active_record_can_raise_range_error? + context 'when the value is outside of the range of the column' do + context 'not qualified with strict' do + it 'rejects, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> { expect(record).to allow_value(100000).for(:attr) } + message = <<-MESSAGE.strip_heredoc.strip + Did not expect errors when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + + context 'qualified with a message' do + it 'ignores any specified message, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + to allow_value(100000). + for(:attr). + with_message('some message') + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect errors to include "some message" when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + end + end + + if active_model_supports_strict? + context 'qualified with strict' do + it 'rejects, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + to allow_value(100000). + for(:attr). + strict + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect an exception to have been raised when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + + context 'qualified with a message' do + it 'ignores any specified message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + to allow_value(100000). + for(:attr). + with_message('some message'). + strict + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect exception to include "some message" when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,160 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::DisallowValueMatcher, type: :model do + context 'an attribute with a format validation' do + it 'does not match if the value is allowed' do + expect(validating_format(with: /abc/)).not_to matcher('abcde').for(:attr) + end + + it 'matches if the value is not allowed' do + expect(validating_format(with: /abc/)).to matcher('xyz').for(:attr) + end + end + + context "an attribute with a context-dependent validation" do + context "without the validation context" do + it "does not match" do + expect(validating_format(with: /abc/, on: :customisable)).not_to matcher("xyz").for(:attr) + end + end + + context "with the validation context" do + it "disallows a bad value" do + expect(validating_format(with: /abc/, on: :customisable)).to matcher("xyz").for(:attr).on(:customisable) + end + + it "does not match a good value" do + expect(validating_format(with: /abc/, on: :customisable)).not_to matcher("abcde").for(:attr).on(:customisable) + end + end + end + + context 'an attribute with a format validation and a custom message' do + it 'does not match if the value and message are both correct' do + expect(validating_format(with: /abc/, message: 'good message')). + not_to matcher('abcde').for(:attr).with_message('good message') + end + + it "delegates its failure message to its allow matcher's negative failure message" do + allow_matcher = double('allow_matcher', + failure_message_when_negated: 'allow matcher failure', + ).as_null_object + allow(Shoulda::Matchers::ActiveModel::AllowValueMatcher). + to receive(:new). + and_return(allow_matcher) + + matcher = matcher('abcde').for(:attr).with_message('good message') + matcher.matches?(validating_format(with: /abc/, message: 'good message')) + + expect(matcher.failure_message).to eq 'allow matcher failure' + end + + it 'matches if the message is correct but the value is not' do + expect(validating_format(with: /abc/, message: 'good message')). + to matcher('xyz').for(:attr).with_message('good message') + end + end + + context 'an attribute where the message occurs on another attribute' do + it 'matches if the message is correct but the value is not' do + expect(record_with_custom_validation).to \ + matcher('bad value').for(:attr).with_message(/some message/, against: :attr2) + end + + it 'does not match if the value and message are both correct' do + expect(record_with_custom_validation).not_to \ + matcher('good value').for(:attr).with_message(/some message/, against: :attr2) + end + + def record_with_custom_validation + define_model :example, attr: :string, attr2: :string do + validate :custom_validation + + def custom_validation + if self[:attr] != 'good value' + self.errors[:attr2] << 'some message' + end + end + end.new + end + end + + if active_record_can_raise_range_error? + context 'when the value is outside of the range of the column' do + context 'not qualified with strict' do + it 'accepts, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> { expect(record).not_to disallow_value(100000).for(:attr) } + message = <<-MESSAGE.strip_heredoc.strip + Did not expect errors when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + + context 'qualified with a message' do + it 'ignores any specified message, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + not_to disallow_value(100000). + for(:attr). + with_message('some message') + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect errors to include "some message" when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + end + end + + if active_model_supports_strict? + context 'qualified with strict' do + it 'accepts, failing with the correct message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + not_to disallow_value(100000). + for(:attr). + strict + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect an exception to have been raised when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + + context 'qualified with a message' do + it 'ignores any specified message' do + attribute_options = { type: :integer, options: { limit: 2 } } + record = define_model(:example, attr: attribute_options).new + assertion = -> do + expect(record). + not_to disallow_value(100000). + for(:attr). + with_message('some message'). + strict + end + message = <<-MESSAGE.strip_heredoc.strip + Did not expect exception to include "some message" when attr is set to 100000, + got RangeError: "100000 is out of range for ActiveRecord::Type::Integer with limit 2" + MESSAGE + expect(&assertion).to fail_with_message(message) + end + end + end + end + end + end + + def matcher(value) + described_class.new(value) + end + alias_method :disallow_value, :matcher +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,20 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::HaveSecurePasswordMatcher, type: :model do + if active_model_3_1? + it 'matches when the subject configures has_secure_password with default options' do + working_model = define_model(:example, password_digest: :string) { has_secure_password } + expect(working_model.new).to have_secure_password + end + + it 'does not match when the subject does not authenticate a password' do + no_secure_password = define_model(:example) + expect(no_secure_password.new).not_to have_secure_password + end + + it 'does not match when the subject is missing the password_digest attribute' do + no_digest_column = define_model(:example) { has_secure_password } + expect(no_digest_column.new).not_to have_secure_password + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/helpers_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/helpers_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/helpers_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/helpers_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,162 @@ +# encoding: UTF-8 +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::Helpers do + include Shoulda::Matchers::ActiveModel + after { I18n.backend.reload! } + + describe 'default_error_message' do + context 'if the translation for the model attribute’s error exists' do + it 'provides the right error message for validate_presence_of' do + store_translations + + assert_presence_validation_has_correct_message + end + + it 'provides the right error message for validates_length_of' do + store_translations + + assert_length_validation_has_correct_message + end + end + + context 'if no translation for the model attribute’s error exists' do + context 'and the translation for the model’s error exists' do + it 'provides the right error message for validate_presence_of' do + store_translations(without: :model_attribute) + + assert_presence_validation_has_correct_message + end + + it 'provides the right error message for validates_length_of' do + store_translations(without: :model_attribute) + + assert_length_validation_has_correct_message + end + end + + context 'and no translation for the model’s error exists' do + context 'and the translation for the message exists' do + it 'provides the right error message for validate_presence_of' do + store_translations(without: [:model_attribute, :model]) + + assert_presence_validation_has_correct_message + end + + it 'provides the right error message for validates_length_of' do + store_translations(without: [:model_attribute, :model]) + + assert_length_validation_has_correct_message + end + end + + context 'and no translation for the message exists' do + context 'and the translation for the attribute exists' do + it 'provides the right error message for validate_presence_of' do + store_translations(without: [:model_attribute, :model, :message]) + + assert_presence_validation_has_correct_message + end + + it 'provides the right error message for validates_length_of' do + store_translations(without: [:model_attribute, :model, :message]) + + assert_length_validation_has_correct_message + end + end + + context 'and no translation for the attribute exists' do + it 'provides the general error message for validate_presence_of' do + assert_presence_validation_has_correct_message + end + + it 'provides the general error message for validates_length_of' do + assert_length_validation_has_correct_message + end + end + end + end + end + + context 'if ActiveModel::Errors#generate_message behavior has changed' do + it 'provides the right error message for validate_presence_of' do + stub_active_model_message_generation(type: :blank, + message: 'Behavior has diverged.') + assert_presence_validation_has_correct_message + end + end + end + + def assert_presence_validation_has_correct_message + record = define_model :example, attr: :string do + validates_presence_of :attr + end.new + expect(record).to validate_presence_of(:attr) + end + + def assert_length_validation_has_correct_message + record = define_model :example, attr: :string do + validates_length_of :attr, is: 40, allow_blank: true + end.new + expect(record).to validate_length_of(:attr).is_equal_to(40) + end + + def store_translations(options = {without: []}) + options[:without] = Array.wrap(options[:without] || []) + + translations = { + activerecord: { + errors: { + models: { + example: { + attributes: { + attr: {} + } + } + }, + messages: {} + } + }, + errors: { + attributes: { + attr: {} + }, + messages: {} + } + } + + unless options[:without].include?(:model_attribute) + translations[:activerecord][:errors][:models][:example][:attributes][:attr][:blank] = "Don't you do that to me!" + translations[:activerecord][:errors][:models][:example][:attributes][:attr][:wrong_length] = "Don't you do that to me!" + end + + unless options[:without].include?(:model) + translations[:activerecord][:errors][:models][:example][:blank] = 'Give it one more try!' + translations[:activerecord][:errors][:models][:example][:wrong_length] = 'Give it one more try!' + end + + unless options[:without].include?(:message) + translations[:activerecord][:errors][:messages][:blank] = 'Oh no!' + translations[:activerecord][:errors][:messages][:wrong_length] = 'Oh no!' + end + + unless options[:without].include?(:attribute) + translations[:errors][:attributes][:attr][:blank] = 'Seriously?' + translations[:errors][:attributes][:attr][:wrong_length] = 'Seriously?' + end + + I18n.backend.store_translations(:en, translations) + end + + def stub_active_model_message_generation(options = {}) + attribute = options.delete(:attribute) || :attr + message = options.delete(:message) + type = options.delete(:type) + + expect_any_instance_of(ActiveModel::Errors). + to receive(:generate_message). + with(attribute, type, {}). + at_least(1). + and_return(message) + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,169 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::ComparisonMatcher do + subject { described_class.new(matcher, 0, :>) } + + it_behaves_like 'a numerical submatcher' + + context 'when initialized without correct numerical matcher' do + it 'raises an argument error' do + fake_matcher = matcher + class << fake_matcher + undef_method :diff_to_compare + end + expect do + described_class.new(fake_matcher, 0, :>) + end.to raise_error ArgumentError + end + end + + context 'is_greater_than' do + it do + expect(instance_with_validations(greater_than: 2)) + .to matcher.is_greater_than(2) + end + + it do + expect(instance_with_validations(greater_than: 1.5)) + .not_to matcher.is_greater_than(2) + end + + it do + expect(instance_with_validations(greater_than: 2.5)) + .not_to matcher.is_greater_than(2) + end + + it do + expect(instance_without_validations).not_to matcher.is_greater_than(2) + end + end + + context 'greater_than_or_equal_to' do + it do + expect(instance_with_validations(greater_than_or_equal_to: 2)) + .to matcher.is_greater_than_or_equal_to(2) + end + + it do + expect(instance_with_validations(greater_than_or_equal_to: 1.5)) + .not_to matcher.is_greater_than_or_equal_to(2) + end + + it do + expect(instance_with_validations(greater_than_or_equal_to: 2.5)) + .not_to matcher.is_greater_than_or_equal_to(2) + end + + it do + expect(instance_without_validations) + .not_to matcher.is_greater_than_or_equal_to(2) + end + end + + context 'less_than' do + it do + expect(instance_with_validations(less_than: 2)) + .to matcher.is_less_than(2) + end + + it do + expect(instance_with_validations(less_than: 1.5)) + .not_to matcher.is_less_than(2) + end + + it do + expect(instance_with_validations(less_than: 2.5)) + .not_to matcher.is_less_than(2) + end + + it do + expect(instance_without_validations) + .not_to matcher.is_less_than(2) + end + end + + context 'less_than_or_equal_to' do + it do + expect(instance_with_validations(less_than_or_equal_to: 2)) + .to matcher.is_less_than_or_equal_to(2) + end + + it do + expect(instance_with_validations(less_than_or_equal_to: 1.5)) + .not_to matcher.is_less_than_or_equal_to(2) + end + + it do + expect(instance_with_validations(less_than_or_equal_to: 2.5)) + .not_to matcher.is_less_than_or_equal_to(2) + end + + it do + expect(instance_without_validations) + .not_to matcher.is_less_than_or_equal_to(2) + end + end + + context 'is_equal_to' do + it do + expect(instance_with_validations(equal_to: 0)) + .to matcher.is_equal_to(0) + end + + it do + expect(instance_with_validations(equal_to: -0.5)) + .not_to matcher.is_equal_to(0) + end + + it do + expect(instance_with_validations(equal_to: 0.5)) + .not_to matcher.is_equal_to(0) + end + + it do + expect(instance_without_validations) + .not_to matcher.is_equal_to(0) + end + end + + context 'with_message' do + it 'verifies the message for the validation' do + instance = instance_with_validations(equal_to: 0, message: 'Must be zero') + expect(instance).to matcher.is_equal_to(0).with_message('Must be zero') + end + end + + describe '#comparison_description' do + [{ operator: :>, value: 0, expectation: 'greater than 0' }, + { operator: :>=, value: -1.0, expectation: 'greater than or equal to -1.0' }, + { operator: :==, value: 2.2, expectation: 'equal to 2.2' }, + { operator: :<, value: -3, expectation: 'less than -3' }, + { operator: :<=, value: 4, expectation: 'less than or equal to 4' }, + ].each do |h| + context "with :#{h[:operator]} as operator and #{h[:value]} as value" do + subject do + described_class.new(matcher, h[:value], h[:operator]) + .comparison_description + end + it { should eq h[:expectation] } + end + end + end + + def instance_with_validations(options = {}) + define_model :example, attr: :string do + validates_numericality_of :attr, options + attr_accessible :attr + end.new + end + + def instance_without_validations + define_model :example, attr: :string do + attr_accessible :attr + end.new + end + + def matcher + validate_numericality_of(:attr) + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,59 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher do + subject { described_class.new(:attr) } + + it_behaves_like 'a numerical submatcher' + it_behaves_like 'a numerical type submatcher' + + it 'allows even number' do + expect(subject.allowed_type).to eq 'even numbers' + end + + describe '#diff_to_compare' do + it { expect(subject.diff_to_compare).to eq 2 } + end + + context 'when the model has an even validation' do + it 'matches' do + match = subject + expect(validating_even_number).to match + end + end + + context 'when the model does not have an even validation' do + it 'does not match' do + match = subject + expect(not_validating_even_number).not_to match + end + + it 'fails with the ActiveRecord :even message' do + match = subject + expect { + expect(not_validating_even_number).to match + }.to fail_with_message_including('Expected errors to include "must be even"') + end + end + + context 'with custom validation message' do + it 'only accepts even number values for that attribute with that message' do + expect(validating_even_number(message: 'custom')).to subject.with_message(/custom/) + end + + it 'fails even number values for that attribute with another message' do + expect(validating_even_number(message: 'custom')).not_to subject.with_message(/wrong/) + end + end + + + def validating_even_number(options = {}) + define_model :example, attr: :string do + validates_numericality_of :attr, { even: true }.merge(options) + end.new + end + + def not_validating_even_number + define_model(:example, attr: :string).new + end + +end \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,59 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OddNumberMatcher do + subject { described_class.new(:attr) } + + it_behaves_like 'a numerical submatcher' + it_behaves_like 'a numerical type submatcher' + + it 'allows odd number' do + expect(subject.allowed_type).to eq 'odd numbers' + end + + describe '#diff_to_compare' do + it { expect(subject.diff_to_compare).to eq 2 } + end + + context 'when the model has an odd validation' do + it 'matches' do + match = subject + expect(validating_odd_number).to match + end + end + + context 'when the model does not have an odd validation' do + it 'does not match' do + match = subject + expect(not_validating_odd_number).not_to match + end + + it 'fails with the ActiveRecord :odd message' do + match = subject + expect { + expect(not_validating_odd_number).to match + }.to fail_with_message_including('Expected errors to include "must be odd"') + end + end + + context 'with custom validation message' do + it 'only accepts odd number values for that attribute with that message' do + expect(validating_odd_number(message: 'custom')).to subject.with_message(/custom/) + end + + it 'fails odd number values for that attribute with another message' do + expect(validating_odd_number(message: 'custom')).not_to subject.with_message(/wrong/) + end + end + + + def validating_odd_number(options = {}) + define_model :example, attr: :string do + validates_numericality_of :attr, { odd: true }.merge(options) + end.new + end + + def not_validating_odd_number + define_model(:example, attr: :string).new + end + +end \ No newline at end of file diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,57 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OnlyIntegerMatcher do + subject { described_class.new(:attr) } + + it_behaves_like 'a numerical submatcher' + it_behaves_like 'a numerical type submatcher' + + it 'allows integer types' do + expect(subject.allowed_type).to eq 'integers' + end + + describe '#diff_to_compare' do + it { expect(subject.diff_to_compare).to eq 1 } + end + + context 'given an attribute that only allows integer values' do + it 'matches' do + match = subject + expect(validating_only_integer).to match + end + end + + context 'given an attribute that only allows integer values with a custom validation message' do + it 'only accepts integer values for that attribute with that message' do + expect(validating_only_integer(message: 'custom')).to subject.with_message(/custom/) + end + + it 'rejects integer values for that attribute with another message' do + expect(validating_only_integer(message: 'custom')).not_to subject.with_message(/wrong/) + end + end + + context 'when the model does not have an only_integer validation' do + it 'does not match' do + match = subject + expect(not_validating_only_integer).not_to match + end + + it 'fails with the ActiveRecord :not_an_integer message' do + match = subject + expect { + expect(not_validating_only_integer).to match + }.to fail_with_message_including('Expected errors to include "must be an integer"') + end + end + + def validating_only_integer(options = {}) + define_model :example, attr: :string do + validates_numericality_of :attr, { only_integer: true }.merge(options) + end.new + end + + def not_validating_only_integer + define_model(:example, attr: :string).new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,166 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher, type: :model do + if active_model_4_0? + def self.available_column_types + [ + :string, + :text, + :integer, + :float, + :decimal, + :datetime, + :timestamp, + :time, + :date, + :binary + ] + end + + context 'a model with an absence validation' do + it 'accepts' do + expect(validating_absence_of(:attr)).to validate_absence_of(:attr) + end + + it 'does not override the default message with a present' do + expect(validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil) + end + + available_column_types.each do |type| + context "when column is of type #{type}" do + it "accepts" do + expect(validating_absence_of(:attr, {}, type: type)). + to validate_absence_of(:attr) + end + end + end + end + + context 'a model without an absence validation' do + it 'rejects' do + model = define_model(:example, attr: :string).new + expect(model).not_to validate_absence_of(:attr) + end + end + + context 'an ActiveModel class with an absence validation' do + it 'accepts' do + expect(active_model_validating_absence_of(:attr)).to validate_absence_of(:attr) + end + + it 'does not override the default message with a blank' do + expect(active_model_validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil) + end + end + + context 'an ActiveModel class without an absence validation' do + it 'rejects' do + expect(active_model_with(:attr)).not_to validate_absence_of(:attr) + end + + it 'provides the correct failure message' do + message = %{Expected errors to include "must be blank" when attr is set to "an arbitrary value",\ngot no errors} + + expect { expect(active_model_with(:attr)).to validate_absence_of(:attr) }.to fail_with_message(message) + end + end + + context 'a has_many association with an absence validation' do + it 'requires the attribute to not be set' do + expect(having_many(:children, absence: true)).to validate_absence_of(:children) + end + end + + context 'a has_many association without an absence validation' do + it 'does not require the attribute to not be set' do + expect(having_many(:children, absence: false)). + not_to validate_absence_of(:children) + end + end + + context 'an absent has_and_belongs_to_many association' do + it 'accepts' do + model = having_and_belonging_to_many(:children, absence: true) + expect(model).to validate_absence_of(:children) + end + end + + context 'a non-absent has_and_belongs_to_many association' do + it 'rejects' do + model = having_and_belonging_to_many(:children, absence: false) + expect(model).not_to validate_absence_of(:children) + end + end + + context "an i18n translation containing %{attribute} and %{model}" do + after { I18n.backend.reload! } + + it "does not raise an exception" do + stub_translation("activerecord.errors.messages.present", + "%{attribute} must be blank in a %{model}") + + expect { + expect(validating_absence_of(:attr)).to validate_absence_of(:attr) + }.to_not raise_exception + end + end + + context "an attribute with a context-dependent validation" do + context "without the validation context" do + it "does not match" do + expect(validating_absence_of(:attr, on: :customisable)).not_to validate_absence_of(:attr) + end + end + + context "with the validation context" do + it "matches" do + expect(validating_absence_of(:attr, on: :customisable)).to validate_absence_of(:attr).on(:customisable) + end + end + end + + def validating_absence_of(attr, validation_options = {}, given_column_options = {}) + default_column_options = { type: :string, options: {} } + column_options = default_column_options.merge(given_column_options) + + define_model :example, attr => column_options do + validates_absence_of attr, validation_options + end.new + end + + def active_model_with(attr, &block) + define_active_model_class('Example', accessors: [attr], &block).new + end + + def active_model_validating_absence_of(attr) + active_model_with(attr) do + validates_absence_of attr + end + end + + def having_many(plural_name, options = {}) + define_model plural_name.to_s.singularize + define_model :parent do + has_many plural_name + if options[:absence] + validates_absence_of plural_name + end + end.new + end + + def having_and_belonging_to_many(plural_name, options = {}) + create_table 'children_parents', id: false do |t| + t.integer "#{plural_name.to_s.singularize}_id" + t.integer :parent_id + end + + define_model plural_name.to_s.singularize + define_model :parent do + has_and_belongs_to_many plural_name + if options[:absence] + validates_absence_of plural_name + end + end.new + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher, type: :model do + context 'a model with an acceptance validation' do + it 'accepts when the attributes match' do + expect(validating_acceptance).to matcher + end + + it 'does not overwrite the default message with nil' do + expect(validating_acceptance).to matcher.with_message(nil) + end + end + + context 'a model without an acceptance validation' do + it 'rejects' do + expect(define_model(:example, attr: :string).new).not_to matcher + end + end + + context 'an attribute which must be accepted with a custom message' do + it 'accepts when the message matches' do + expect(validating_acceptance(message: 'custom')). + to matcher.with_message(/custom/) + end + + it 'rejects when the message does not match' do + expect(validating_acceptance(message: 'custom')). + not_to matcher.with_message(/wrong/) + end + end + + def matcher + validate_acceptance_of(:attr) + end + + def validating_acceptance(options = {}) + define_model(:example, attr: :string) do + validates_acceptance_of :attr, options + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,63 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher, type: :model do + include UnitTests::ConfirmationMatcherHelpers + + context '#description' do + it 'states that the confirmation must match its base attribute' do + builder = builder_for_record_validating_confirmation + message = "require #{builder.confirmation_attribute} to match #{builder.attribute_to_confirm}" + matcher = described_class.new(builder.attribute_to_confirm) + expect(matcher.description).to eq(message) + end + end + + context 'when the model has a confirmation validation' do + it 'passes' do + builder = builder_for_record_validating_confirmation + expect(builder.record). + to validate_confirmation_of(builder.attribute_to_confirm) + end + + context 'when a nil message is specified' do + it 'ignores it' do + builder = builder_for_record_validating_confirmation + expect(builder.record). + to validate_confirmation_of(builder.attribute_to_confirm). + with_message(nil) + end + end + end + + context 'when the model does not have a confirmation validation' do + it 'fails' do + model = define_model(:example, attribute_to_confirm: :string) + record = model.new + expect(record).not_to validate_confirmation_of(:attribute_to_confirm) + end + end + + context 'when both validation and matcher specify a custom message' do + it 'passes when the expected and actual messages match' do + builder = builder_for_record_validating_confirmation(message: 'custom') + expect(builder.record). + to validate_confirmation_of(builder.attribute_to_confirm). + with_message(/custom/) + end + + it 'fails when the expected and actual messages do not match' do + builder = builder_for_record_validating_confirmation(message: 'custom') + expect(builder.record). + not_to validate_confirmation_of(builder.attribute_to_confirm). + with_message(/wrong/) + end + end + + context 'when the validation specifies a message via i18n' do + it 'passes' do + builder = builder_for_record_validating_confirmation_with_18n_message + expect(builder.record). + to validate_confirmation_of(builder.attribute_to_confirm) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,112 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel, type: :model do + describe '#ensure_exclusion_of' do + it 'is aliased to #validate_exclusion_of' do + allow(matchers).to receive(:validate_exclusion_of) + + silence_warnings do + matchers.ensure_exclusion_of(:attr) + expect(matchers).to have_received(:validate_exclusion_of).with(:attr) + end + end + end + + def matchers + @_matchers ||= Object.new.extend(described_class) + end +end + +describe Shoulda::Matchers::ActiveModel::ValidateExclusionOfMatcher, type: :model do + context 'an attribute which must be excluded from a range' do + it 'accepts ensuring the correct range' do + expect(validating_exclusion(in: 2..5)). + to validate_exclusion_of(:attr).in_range(2..5) + end + + it 'rejects ensuring excluded value' do + expect(validating_exclusion(in: 2..5)). + not_to validate_exclusion_of(:attr).in_range(2..6) + end + + it 'does not override the default message with a blank' do + expect(validating_exclusion(in: 2..5)). + to validate_exclusion_of(:attr).in_range(2..5).with_message(nil) + end + end + + context 'an attribute which must be excluded from a range with excluded end' do + it 'accepts ensuring the correct range' do + expect(validating_exclusion(in: 2...5)). + to validate_exclusion_of(:attr).in_range(2...5) + end + + it 'rejects ensuring excluded value' do + expect(validating_exclusion(in: 2...5)). + not_to validate_exclusion_of(:attr).in_range(2...4) + end + end + + context 'an attribute with a custom validation message' do + it 'accepts ensuring the correct range' do + expect(validating_exclusion(in: 2..4, message: 'not good')). + to validate_exclusion_of(:attr).in_range(2..4).with_message(/not good/) + end + end + + context 'an attribute with custom range validations' do + it 'accepts ensuring the correct range and messages' do + model = custom_validation do + if attr >= 2 && attr <= 5 + errors.add(:attr, 'should be out of this range') + end + end + + expect(model).to validate_exclusion_of(:attr).in_range(2..5). + with_message(/should be out of this range/) + + model = custom_validation do + if attr >= 2 && attr <= 4 + errors.add(:attr, 'should be out of this range') + end + end + + expect(model).to validate_exclusion_of(:attr).in_range(2...5). + with_message(/should be out of this range/) + end + end + + context 'an attribute which must be excluded from an array' do + it 'accepts with correct array' do + expect(validating_exclusion(in: %w(one two))). + to validate_exclusion_of(:attr).in_array(%w(one two)) + end + + it 'rejects when only part of array matches' do + expect(validating_exclusion(in: %w(one two))). + not_to validate_exclusion_of(:attr).in_array(%w(one wrong_value)) + end + + it 'rejects when array does not match at all' do + expect(validating_exclusion(in: %w(one two))). + not_to validate_exclusion_of(:attr).in_array(%w(cat dog)) + end + + it 'has correct description' do + expect(validate_exclusion_of(:attr).in_array([true, 'dog']).description). + to eq 'ensure exclusion of attr in [true, "dog"]' + end + + def validating_exclusion(options) + define_model(:example, attr: :string) do + validates_exclusion_of :attr, options + end.new + end + end + + def validating_exclusion(options) + define_model(:example, attr: :integer) do + validates_exclusion_of :attr, options + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,697 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel, type: :model do + describe '#ensure_inclusion_of' do + it 'is aliased to #validate_inclusion_of' do + allow(matchers).to receive(:validate_inclusion_of) + + silence_warnings do + matchers.ensure_inclusion_of(:attr) + expect(matchers).to have_received(:validate_inclusion_of) + end + end + end + + def matchers + @_matchers ||= Object.new.extend(described_class) + end +end + +describe Shoulda::Matchers::ActiveModel::ValidateInclusionOfMatcher, type: :model do + shared_context 'for a generic attribute' do + def self.testing_values_of_option(option_name, &block) + [nil, true, false].each do |option_value| + context_name = "+ #{option_name}" + option_args = [] + matches_or_not = ['matches', 'does not match'] + to_or_not_to = [:to, :not_to] + + unless option_value == nil + context_name << "(#{option_value})" + option_args = [option_value] + end + + if option_value == false + matches_or_not.reverse! + to_or_not_to.reverse! + end + + end + end + + context 'against an integer attribute' do + it_behaves_like 'it supports in_array', + possible_values: (1..5).to_a, + zero: 0, + reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM + + it_behaves_like 'it supports in_range', + possible_values: 1..5, + zero: 0 + + context 'when attribute validates a range of values via custom validation' do + it 'matches ensuring the correct range and messages' do + expect_to_match_ensuring_range_and_messages(2..5, 2, 5) + expect_to_match_ensuring_range_and_messages(2...5, 2, 4) + end + end + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge(column_type: :integer, value: 1), + &block + ) + end + + def add_outside_value_to(values) + values + [values.last + 1] + end + end + + context 'against an attribute with a specific column limit' do + it 'does not raise an exception when attempting to use the matcher' do + possible_values = (1..5).to_a + builder = build_object_allowing(possible_values) + assertion = -> { expect_to_match_on_values(builder, possible_values) } + expect(&assertion).not_to raise_error + end + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge( + column_type: :integer, + column_options: { limit: 2 }, + value: 1 + ), + &block + ) + end + + def expect_to_match_on_values(builder, values, &block) + expect_to_match_in_array(builder, values, &block) + end + end + + context "against a float attribute" do + it_behaves_like 'it supports in_array', + possible_values: [1.0, 2.0, 3.0, 4.0, 5.0], + zero: 0.0, + reserved_outside_value: described_class::ARBITRARY_OUTSIDE_FIXNUM + + it_behaves_like 'it supports in_range', + possible_values: 1.0..5.0, + zero: 0.0 + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge(column_type: :float, value: 1.0), + &block + ) + end + + def add_outside_value_to(values) + values + [values.last + 1] + end + end + + context "against a decimal attribute" do + it_behaves_like 'it supports in_array', + possible_values: [1.0, 2.0, 3.0, 4.0, 5.0].map { |number| + BigDecimal.new(number.to_s) + }, + zero: BigDecimal.new('0.0'), + reserved_outside_value: described_class::ARBITRARY_OUTSIDE_DECIMAL + + it_behaves_like 'it supports in_range', + possible_values: BigDecimal.new('1.0') .. BigDecimal.new('5.0'), + zero: BigDecimal.new('0.0') + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge(column_type: :decimal, value: BigDecimal.new('1.0')), + &block + ) + end + + def add_outside_value_to(values) + values + [values.last + 1] + end + end + + context 'against a string attribute' do + it_behaves_like 'it supports in_array', + possible_values: %w(foo bar baz), + reserved_outside_value: described_class::ARBITRARY_OUTSIDE_STRING + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge(column_type: :string), + &block + ) + end + + def add_outside_value_to(values) + values + %w(qux) + end + end + end + + shared_examples_for 'it supports allow_nil' do |args| + valid_values = args.fetch(:valid_values) + + testing_values_of_option 'allow_nil' do |option_args, matches_or_not, to_or_not_to| + it "#{matches_or_not[0]} when the validation specifies allow_nil" do + builder = build_object_allowing(valid_values, allow_nil: true) + + __send__("expect_#{to_or_not_to[0]}_match_on_values", builder, valid_values) do |matcher| + matcher.allow_nil(*option_args) + end + end + + it "#{matches_or_not[1]} when the validation does not specify allow_nil" do + builder = build_object_allowing(valid_values) + + __send__("expect_#{to_or_not_to[1]}_match_on_values", builder, valid_values) do |matcher| + matcher.allow_nil(*option_args) + end + end + end + end + + shared_examples_for 'it supports allow_blank' do |args| + valid_values = args.fetch(:valid_values) + + testing_values_of_option 'allow_blank' do |option_args, matches_or_not, to_or_not_to| + it "#{matches_or_not[0]} when the validation specifies allow_blank" do + builder = build_object_allowing(valid_values, allow_blank: true) + + __send__("expect_#{to_or_not_to[0]}_match_on_values", builder, valid_values) do |matcher| + matcher.allow_blank(*option_args) + end + end + + it "#{matches_or_not[1]} when the validation does not specify allow_blank" do + builder = build_object_allowing(valid_values) + + __send__("expect_#{to_or_not_to[1]}_match_on_values", builder, valid_values) do |matcher| + matcher.allow_blank(*option_args) + end + end + end + end + + shared_examples_for 'it supports with_message' do |args| + valid_values = args.fetch(:valid_values) + + context 'given a string' do + it 'matches when validation uses given message' do + builder = build_object_allowing(valid_values, message: 'a message') + + expect_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message('a message') + end + end + + it 'does not match when validation uses the default message instead of given message' do + builder = build_object_allowing(valid_values) + + expect_not_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message('a message') + end + end + + it 'does not match when validation uses a message but it is not same as given' do + builder = build_object_allowing(valid_values, message: 'a different message') + + expect_not_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message('a message') + end + end + end + + context 'given a regex' do + it 'matches when validation uses a message that matches the regex' do + builder = build_object_allowing(valid_values, message: 'this is a message') + + expect_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message(/a message/) + end + end + + it 'does not match when validation uses the default message instead of given message' do + builder = build_object_allowing(valid_values) + + expect_not_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message(/a message/) + end + end + + it 'does not match when validation uses a message but it does not match regex' do + builder = build_object_allowing(valid_values, message: 'a different message') + + expect_not_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message(/a message/) + end + end + end + + context 'given nil' do + it 'is as if with_message had never been called' do + builder = build_object_allowing(valid_values) + + expect_to_match_on_values(builder, valid_values) do |matcher| + matcher.with_message(nil) + end + end + end + end + + shared_examples_for 'it supports in_array' do |args| + possible_values = args.fetch(:possible_values) + zero = args[:zero] + reserved_outside_value = args.fetch(:reserved_outside_value) + + it 'does not match a record with no validations' do + builder = build_object + expect_not_to_match_on_values(builder, possible_values) + end + + it 'matches given the same array of valid values' do + builder = build_object_allowing(possible_values) + expect_to_match_on_values(builder, possible_values) + end + + it 'matches given a subset of the valid values' do + builder = build_object_allowing(possible_values) + expect_to_match_on_values(builder, possible_values[1..-1]) + end + + if zero + it 'matches when one of the given values is a 0' do + valid_values = possible_values + [zero] + builder = build_object_allowing(valid_values) + expect_to_match_on_values(builder, valid_values) + end + end + + it 'does not match when one of the given values is invalid' do + builder = build_object_allowing(possible_values) + expect_not_to_match_on_values(builder, add_outside_value_to(possible_values)) + end + + it 'raises an error when valid and given value is our test outside value' do + error_class = Shoulda::Matchers::ActiveModel::CouldNotDetermineValueOutsideOfArray + builder = build_object_allowing([reserved_outside_value]) + + expect { expect_to_match_on_values(builder, [reserved_outside_value]) }. + to raise_error(error_class) + end + + it_behaves_like 'it supports allow_nil', valid_values: possible_values + it_behaves_like 'it supports allow_blank', valid_values: possible_values + it_behaves_like 'it supports with_message', valid_values: possible_values + + if active_model_3_2? + context '+ strict' do + context 'when the validation specifies strict' do + it 'matches when the given values match the valid values' do + builder = build_object_allowing(possible_values, strict: true) + + expect_to_match_on_values(builder, possible_values) do |matcher| + matcher.strict + end + end + + it 'does not match when the given values do not match the valid values' do + builder = build_object_allowing(possible_values, strict: true) + + values = add_outside_value_to(possible_values) + expect_not_to_match_on_values(builder, values) do |matcher| + matcher.strict + end + end + end + + context 'when the validation does not specify strict' do + it 'does not match' do + builder = build_object_allowing(possible_values) + + expect_not_to_match_on_values(builder, possible_values) do |matcher| + matcher.strict + end + end + end + end + end + + def expect_to_match_on_values(builder, values, &block) + expect_to_match_in_array(builder, values, &block) + end + + def expect_not_to_match_on_values(builder, values, &block) + expect_not_to_match_in_array(builder, values, &block) + end + end + + shared_examples_for 'it supports in_range' do |args| + possible_values = args[:possible_values] + + it 'does not match a record with no validations' do + builder = build_object + expect_not_to_match_on_values(builder, possible_values) + end + + it 'matches given a range that exactly matches the valid range' do + builder = build_object_allowing(possible_values) + expect_to_match_on_values(builder, possible_values) + end + + it 'does not match given a range whose start value falls outside valid range' do + builder = build_object_allowing(possible_values) + expect_not_to_match_on_values(builder, + Range.new(possible_values.first - 1, possible_values.last) + ) + end + + it 'does not match given a range whose start value falls inside valid range' do + builder = build_object_allowing(possible_values) + expect_not_to_match_on_values(builder, + Range.new(possible_values.first + 1, possible_values.last) + ) + end + + it 'does not match given a range whose end value falls inside valid range' do + builder = build_object_allowing(possible_values) + expect_not_to_match_on_values(builder, + Range.new(possible_values.first, possible_values.last - 1) + ) + end + + it 'does not match given a range whose end value falls outside valid range' do + builder = build_object_allowing(possible_values) + expect_not_to_match_on_values(builder, + Range.new(possible_values.first, possible_values.last + 1) + ) + end + + it_behaves_like 'it supports allow_nil', valid_values: possible_values + it_behaves_like 'it supports allow_blank', valid_values: possible_values + it_behaves_like 'it supports with_message', valid_values: possible_values + + if active_model_3_2? + context '+ strict' do + context 'when the validation specifies strict' do + it 'matches when the given range matches the range in the validation' do + builder = build_object_allowing(possible_values, strict: true) + + expect_to_match_on_values(builder, possible_values) do |matcher| + matcher.strict + end + end + + it 'matches when the given range does not match the range in the validation' do + builder = build_object_allowing(possible_values, strict: true) + + range = Range.new(possible_values.first, possible_values.last + 1) + expect_not_to_match_on_values(builder, range) do |matcher| + matcher.strict + end + end + end + + context 'when the validation does not specify strict' do + it 'does not match' do + builder = build_object_allowing(possible_values) + + expect_not_to_match_on_values(builder, possible_values) do |matcher| + matcher.strict + end + end + end + end + end + + def expect_to_match_on_values(builder, range, &block) + expect_to_match_in_range(builder, range, &block) + end + + def expect_not_to_match_on_values(builder, range, &block) + expect_not_to_match_in_range(builder, range, &block) + end + end + + shared_context 'against a boolean attribute for true and false' do + context 'when ensuring inclusion of true' do + it 'matches' do + valid_values = [true] + builder = build_object_allowing(valid_values) + expect_to_match_in_array(builder, valid_values) + end + end + + context 'when ensuring inclusion of false' do + it 'matches' do + valid_values = [false] + builder = build_object_allowing(valid_values) + expect_to_match_in_array(builder, valid_values) + end + end + + context 'when ensuring inclusion of true and false' do + it 'matches' do + valid_values = [true, false] + builder = build_object_allowing(valid_values) + silence_stderr do + expect_to_match_in_array(builder, valid_values) + end + end + + [[false, true], [true, false]].each do |booleans| + it 'prints a warning' do + valid_values = booleans + builder = build_object_allowing(valid_values) + message = 'You are using `validate_inclusion_of` to assert that a boolean column allows boolean values and disallows non-boolean ones' + + stderr = capture(:stderr) do + expect_to_match_in_array(builder, valid_values) + end + + expect(stderr.gsub(/\n+/, ' ')).to include(message) + end + end + end + end + + context 'for a database column' do + include_context 'for a generic attribute' + + context 'against a boolean attribute' do + context 'which is nullable' do + include_context 'against a boolean attribute for true and false' + + context 'when ensuring inclusion of nil' do + it 'matches' do + valid_values = [nil] + builder = build_object_allowing(valid_values) + silence_stderr do + expect_to_match_in_array(builder, valid_values) + end + end + + it 'prints a warning' do + valid_values = [nil] + builder = build_object_allowing(valid_values) + message = 'You are using `validate_inclusion_of` to assert that a boolean column allows nil' + + stderr = capture(:stderr) do + expect_to_match_in_array(builder, valid_values) + end + + expect(stderr.gsub(/\n+/, ' ')).to include(message) + end + end + + def build_object(options = {}, &block) + super(options.merge(column_options: { null: true }, value: true)) + end + end + + context 'which is non-nullable' do + include_context 'against a boolean attribute for true and false' + + context 'when ensuring inclusion of nil' do + it 'raises a specific error' do + valid_values = [nil] + builder = build_object_allowing(valid_values) + error_class = Shoulda::Matchers::ActiveModel::NonNullableBooleanError + + expect { + expect_to_match_in_array(builder, valid_values) + }.to raise_error(error_class) + end + end + + def build_object(options = {}, &block) + super(options.merge(column_options: { null: false })) + end + end + + def build_object(options = {}, &block) + build_object_with_generic_attribute( + options.merge(column_type: :boolean), + &block + ) + end + end + + + def build_object_with_generic_attribute(options = {}, &block) + attribute_name = :attr + column_type = options.fetch(:column_type) + column_options = { + type: column_type, + options: options.fetch(:column_options, {}) + } + validation_options = options[:validation_options] + custom_validation = options[:custom_validation] + + model = define_model :example, attribute_name => column_options + customize_model_class( + model, + attribute_name, + validation_options, + custom_validation + ) + + object = model.new + + object_builder_class.new(attribute_name, object, validation_options) + end + end + + context 'for a plain Ruby attribute' do + include_context 'for a generic attribute' + + context 'against a boolean attribute (designated by true)' do + include_context 'against a boolean attribute for true and false' + + def build_object(options = {}, &block) + build_object_with_generic_attribute(options.merge(value: true)) + end + end + + context 'against a boolean attribute (designated by false)' do + include_context 'against a boolean attribute for true and false' + + def build_object(options = {}, &block) + build_object_with_generic_attribute(options.merge(value: false)) + end + end + + def build_object_with_generic_attribute(options = {}, &block) + attribute_name = :attr + validation_options = options[:validation_options] + custom_validation = options[:custom_validation] + value = options[:value] + + model = define_active_model_class :example, accessors: [attribute_name] + customize_model_class( + model, + attribute_name, + validation_options, + custom_validation + ) + + object = model.new + object.__send__("#{attribute_name}=", value) + + object_builder_class.new(attribute_name, object, validation_options) + end + end + + def object_builder_class + @_object_builder_class ||= Struct.new(:attribute, :object, :validation_options) + end + + def customize_model_class(klass, attribute_name, validation_options, custom_validation) + klass.class_eval do + if validation_options + validates_inclusion_of attribute_name, validation_options + end + + if custom_validation + define_method :custom_validation do + instance_exec(attribute_name, &custom_validation) + end + + validate :custom_validation + end + end + end + + def build_object_allowing(values, options = {}) + build_object(validation_options: options.merge(in: values)) + end + + def expect_to_match(builder) + matcher = validate_inclusion_of(builder.attribute) + yield matcher if block_given? + expect(builder.object).to(matcher) + end + + def expect_not_to_match(builder) + matcher = validate_inclusion_of(builder.attribute) + yield matcher if block_given? + expect(builder.object).not_to(matcher) + end + + def expect_to_match_in_array(builder, array) + expect_to_match(builder) do |matcher| + matcher.in_array(array) + yield matcher if block_given? + end + end + + def expect_not_to_match_in_array(builder, array) + expect_not_to_match(builder) do |matcher| + matcher.in_array(array) + yield matcher if block_given? + end + end + + def expect_to_match_in_range(builder, range) + expect_to_match(builder) do |matcher| + matcher.in_range(range) + yield matcher if block_given? + end + end + + def expect_not_to_match_in_range(builder, range) + expect_not_to_match(builder) do |matcher| + matcher.in_range(range) + yield matcher if block_given? + end + end + + def expect_to_match_ensuring_range_and_messages(range, low_value, high_value) + low_message = 'too low' + high_message = 'too high' + + builder = build_object custom_validation: ->(attribute) { + value = __send__(attribute) + + if value < low_value + errors.add(attribute, low_message) + elsif value > high_value + errors.add(attribute, high_message) + end + } + + expect_to_match(builder) do |matcher| + matcher. + in_range(range). + with_low_message(low_message). + with_high_message(high_message) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,186 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel, type: :model do + describe '#ensure_length_of' do + it 'is aliased to #validate_length_of' do + allow(matchers).to receive(:validate_length_of) + + silence_warnings do + matchers.ensure_length_of(:attr) + expect(matchers).to have_received(:validate_length_of).with(:attr) + end + end + end + + def matchers + @_matchers ||= Object.new.extend(described_class) + end +end + +describe Shoulda::Matchers::ActiveModel::ValidateLengthOfMatcher, type: :model do + context 'an attribute with a non-zero minimum length validation' do + it 'accepts ensuring the correct minimum length' do + expect(validating_length(minimum: 4)). + to validate_length_of(:attr).is_at_least(4) + end + + it 'rejects ensuring a lower minimum length with any message' do + expect(validating_length(minimum: 4)). + not_to validate_length_of(:attr).is_at_least(3).with_short_message(/.*/) + end + + it 'rejects ensuring a higher minimum length with any message' do + expect(validating_length(minimum: 4)). + not_to validate_length_of(:attr).is_at_least(5).with_short_message(/.*/) + end + + it 'does not override the default message with a blank' do + expect(validating_length(minimum: 4)). + to validate_length_of(:attr).is_at_least(4).with_short_message(nil) + end + end + + context 'an attribute with a minimum length validation of 0' do + it 'accepts ensuring the correct minimum length' do + expect(validating_length(minimum: 0)). + to validate_length_of(:attr).is_at_least(0) + end + end + + context 'an attribute with a maximum length' do + it 'accepts ensuring the correct maximum length' do + expect(validating_length(maximum: 4)). + to validate_length_of(:attr).is_at_most(4) + end + + it 'rejects ensuring a lower maximum length with any message' do + expect(validating_length(maximum: 4)). + not_to validate_length_of(:attr).is_at_most(3).with_long_message(/.*/) + end + + it 'rejects ensuring a higher maximum length with any message' do + expect(validating_length(maximum: 4)). + not_to validate_length_of(:attr).is_at_most(5).with_long_message(/.*/) + end + + it 'does not override the default message with a blank' do + expect(validating_length(maximum: 4)). + to validate_length_of(:attr).is_at_most(4).with_long_message(nil) + end + end + + context 'an attribute with a required exact length' do + it 'accepts ensuring the correct length' do + expect(validating_length(is: 4)). + to validate_length_of(:attr).is_equal_to(4) + end + + it 'rejects ensuring a lower maximum length with any message' do + expect(validating_length(is: 4)). + not_to validate_length_of(:attr).is_equal_to(3).with_message(/.*/) + end + + it 'rejects ensuring a higher maximum length with any message' do + expect(validating_length(is: 4)). + not_to validate_length_of(:attr).is_equal_to(5).with_message(/.*/) + end + + it 'does not override the default message with a blank' do + expect(validating_length(is: 4)). + to validate_length_of(:attr).is_equal_to(4).with_message(nil) + end + end + + context 'an attribute with a required exact length and another validation' do + it 'accepts ensuring the correct length' do + model = define_model(:example, attr: :string) do + validates_length_of :attr, is: 4 + validates_numericality_of :attr + end.new + + expect(model).to validate_length_of(:attr).is_equal_to(4) + end + end + + context 'an attribute with a custom minimum length validation' do + it 'accepts ensuring the correct minimum length' do + expect(validating_length(minimum: 4, too_short: 'foobar')). + to validate_length_of(:attr).is_at_least(4).with_short_message(/foo/) + end + end + + context 'an attribute with a custom maximum length validation' do + it 'accepts ensuring the correct minimum length' do + expect(validating_length(maximum: 4, too_long: 'foobar')). + to validate_length_of(:attr).is_at_most(4).with_long_message(/foo/) + end + end + + context 'an attribute with a custom equal validation' do + it 'accepts ensuring the correct exact length' do + expect(validating_length(is: 4, message: 'foobar')). + to validate_length_of(:attr).is_equal_to(4).with_message(/foo/) + end + end + + context 'an attribute without a length validation' do + it 'rejects ensuring a minimum length' do + expect(define_model(:example, attr: :string).new). + not_to validate_length_of(:attr).is_at_least(1) + end + end + + context 'using translations' do + after { I18n.backend.reload! } + + context "a too_long translation containing %{attribute}, %{model}" do + before do + stub_translation( + "activerecord.errors.messages.too_long", + "The %{attribute} of your %{model} is too long (maximum is %{count} characters)") + end + + it "does not raise an exception" do + expect { + expect(validating_length(maximum: 4)). + to validate_length_of(:attr).is_at_most(4) + }.to_not raise_exception + end + end + + context "a too_short translation containing %{attribute}, %{model}" do + before do + stub_translation( + "activerecord.errors.messages.too_short", + "The %{attribute} of your %{model} is too short (minimum is %{count} characters)") + end + + it "does not raise an exception" do + expect { + expect(validating_length(minimum: 4)).to validate_length_of(:attr).is_at_least(4) + }.to_not raise_exception + end + end + + context "a wrong_length translation containing %{attribute}, %{model}" do + before do + stub_translation( + "activerecord.errors.messages.wrong_length", + "The %{attribute} of your %{model} is the wrong length (should be %{count} characters)") + end + + it "does not raise an exception" do + expect { + expect(validating_length(is: 4)). + to validate_length_of(:attr).is_equal_to(4) + }.to_not raise_exception + end + end + end + + def validating_length(options = {}) + define_model(:example, attr: :string) do + validates_length_of :attr, options + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,425 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher, type: :model do + context 'with a model with a numericality validation' do + it 'accepts' do + expect(validating_numericality).to matcher + end + + it 'does not override the default message with a blank' do + expect(validating_numericality).to matcher.with_message(nil) + end + end + + context 'with a model without a numericality validation' do + it 'rejects' do + expect(not_validating_numericality).not_to matcher + end + + it 'rejects with the ActiveRecord :not_a_number message' do + the_matcher = matcher + expect do + expect(not_validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "is not a number"' + ) + end + + it 'rejects with the ActiveRecord :not_an_integer message' do + the_matcher = matcher.only_integer + expect do + expect(not_validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be an integer"' + ) + end + + it 'rejects with the ActiveRecord :odd message' do + the_matcher = matcher.odd + expect do + expect(not_validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be odd"' + ) + end + + it 'rejects with the ActiveRecord :even message' do + the_matcher = matcher.even + expect do + expect(not_validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be even"' + ) + end + end + + context 'with the allow_nil option' do + it 'allows nil values for that attribute' do + expect(validating_numericality(allow_nil: true)).to matcher.allow_nil + end + + it 'rejects when the model does not allow nil' do + the_matcher = matcher.allow_nil + expect { + expect(validating_numericality).to the_matcher + }.to fail_with_message_including('Did not expect errors to include "is not a number"') + end + end + + context 'with the only_integer option' do + it 'allows integer values for that attribute' do + expect(validating_numericality(only_integer: true)).to matcher.only_integer + end + + it 'rejects when the model does not enforce integer values' do + expect(validating_numericality).not_to matcher.only_integer + end + + it 'rejects with the ActiveRecord :not_an_integer message' do + the_matcher = matcher.only_integer + expect do + expect(validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be an integer"' + ) + end + end + + context 'with the odd option' do + it 'allows odd number values for that attribute' do + expect(validating_numericality(odd: true)).to matcher.odd + end + + it 'rejects when the model does not enforce odd number values' do + expect(validating_numericality).not_to matcher.odd + end + + it 'rejects with the ActiveRecord :odd message' do + the_matcher = matcher.odd + expect do + expect(validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be odd"' + ) + end + end + + context 'with the even option' do + it 'allows even number values for that attribute' do + expect(validating_numericality(even: true)).to matcher.even + end + + it 'rejects when the model does not enforce even number values' do + expect(validating_numericality).not_to matcher.even + end + + it 'rejects with the ActiveRecord :even message' do + the_matcher = matcher.even + expect do + expect(validating_numericality).to the_matcher + end.to fail_with_message_including( + 'Expected errors to include "must be even"' + ) + end + end + + context 'qualified with less_than_or_equal_to' do + it 'does not raise an error if the given value is right at the allowed max value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, less_than_or_equal_to: 32767) + assertion = -> { + expect(record).to validate_numericality_of(:attr).is_less_than_or_equal_to(32767) + } + expect(&assertion).not_to raise_error + end + end + + context 'qualified with less_than' do + it 'does not raise an error if the given value is right at the allowed max value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, less_than: 32767) + assertion = -> { + expect(record).to validate_numericality_of(:attr).is_less_than(32767) + } + expect(&assertion).not_to raise_error + end + end + + context 'qualified with equal_to' do + it 'does not raise an error if the given value is right at the allowed min value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, equal_to: -32768) + assertion = -> { + expect(record).to validate_numericality_of(:attr).is_equal_to(-32768) + } + expect(&assertion).not_to raise_error + end + + it 'does not raise an error if the given value is right at the allowed max value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, equal_to: 32767) + assertion = -> { + expect(record).to validate_numericality_of(:attr).is_equal_to(32767) + } + expect(&assertion).not_to raise_error + end + end + + context 'qualified with greater_than_or_equal to' do + it 'does not raise an error if the given value is right at the allowed min value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, + greater_than_or_equal_to: -32768 + ) + assertion = -> { + expect(record). + to validate_numericality_of(:attr). + is_greater_than_or_equal_to(-32768) + } + expect(&assertion).not_to raise_error + end + end + + context 'qualified with greater_than' do + it 'does not raise an error if the given value is right at the allowed min value for the column' do + record = record_with_integer_column_of_limit(:attr, 2, + greater_than: -32768 + ) + assertion = -> { + expect(record). + to validate_numericality_of(:attr). + is_greater_than(-32768) + } + expect(&assertion).not_to raise_error + end + end + + context 'with multiple options together' do + context 'the success cases' do + it do + expect(validating_numericality(only_integer: true, greater_than: 18)) + .to matcher.only_integer.is_greater_than(18) + end + + it do + expect(validating_numericality(even: true, greater_than: 18)) + .to matcher.even.is_greater_than(18) + end + it do + expect(validating_numericality(odd: true, less_than_or_equal_to: 99)) + .to matcher.odd.is_less_than_or_equal_to(99) + end + + it do + expect(validating_numericality( + only_integer: true, + greater_than: 18, + less_than: 99) + ).to matcher.only_integer.is_greater_than(18).is_less_than(99) + end + end + + context 'the failure cases with different validators' do + it do + expect(validating_numericality(even: true, greater_than: 18)) + .not_to matcher.only_integer.is_greater_than(18) + end + + it do + expect(validating_numericality(greater_than: 18)) + .not_to matcher.only_integer.is_greater_than(18) + end + + it do + expect( + validating_numericality(even: true, greater_than_or_equal_to: 18) + ).not_to matcher.even.is_greater_than(18) + end + + it do + expect(validating_numericality(odd: true, greater_than: 18)) + .not_to matcher.even.is_greater_than(18) + end + + it do + expect(validating_numericality( + odd: true, + greater_than_or_equal_to: 99 + ) + ).not_to matcher.odd.is_less_than_or_equal_to(99) + end + + it do + expect(validating_numericality( + only_integer: true, + greater_than_or_equal_to: 18, + less_than: 99 + ) + ).not_to matcher.only_integer.is_greater_than(18).is_less_than(99) + end + end + + context 'the failure cases with wrong values' do + it do + expect(validating_numericality(only_integer: true, greater_than: 19)) + .not_to matcher.only_integer.is_greater_than(18) + end + + it do + expect(validating_numericality(only_integer: true, greater_than: 17)) + .not_to matcher.only_integer.is_greater_than(18) + end + + it do + expect(validating_numericality(even: true, greater_than: 20)) + .not_to matcher.even.is_greater_than(18) + end + + it do + expect(validating_numericality(even: true, greater_than: 16)) + .not_to matcher.even.is_greater_than(18) + end + + it do + expect(validating_numericality(odd: true, less_than_or_equal_to: 101)) + .not_to matcher.odd.is_less_than_or_equal_to(99) + end + + it do + expect(validating_numericality(odd: true, less_than_or_equal_to: 97)) + .not_to matcher.odd.is_less_than_or_equal_to(99) + end + + it do + expect(validating_numericality(only_integer: true, + greater_than: 19, + less_than: 99)) + .not_to matcher.only_integer.is_greater_than(18).is_less_than(99) + end + + it do + expect(validating_numericality(only_integer: true, + greater_than: 18, + less_than: 100)) + .not_to matcher.only_integer.is_greater_than(18).is_less_than(99) + end + end + end + + context 'with large numbers' do + it do + expect(validating_numericality(greater_than: 100_000)) + .to matcher.is_greater_than(100_000) + end + + it do + expect(validating_numericality(less_than: 100_000)) + .to matcher.is_less_than(100_000) + end + + it do + expect(validating_numericality(greater_than_or_equal_to: 100_000)) + .to matcher.is_greater_than_or_equal_to(100_000) + end + + it do + expect(validating_numericality(less_than_or_equal_to: 100_000)) + .to matcher.is_less_than_or_equal_to(100_000) + end + end + + context 'with a custom validation message' do + it 'accepts when the messages match' do + expect(validating_numericality(message: 'custom')). + to matcher.with_message(/custom/) + end + + it 'rejects when the messages do not match' do + expect(validating_numericality(message: 'custom')). + not_to matcher.with_message(/wrong/) + end + end + + context 'when the subject is stubbed' do + it 'retains stubs on submatchers' do + subject = define_model :example, attr: :string do + validates_numericality_of :attr, odd: true + before_validation :set_attr! + def set_attr!; self.attr = 5 end + end.new + + allow(subject).to receive(:set_attr!) + expect(subject).to matcher.odd + end + end + + describe '#description' do + context 'without submatchers' do + it { expect(matcher.description).to eq 'only allow numbers for attr' } + end + + context 'with only integer option' do + it do + expect(matcher.only_integer.description) + .to eq 'only allow integers for attr' + end + end + + [:odd, :even].each do |type| + context "with #{type} option" do + it do + expect(matcher.__send__(type).description) + .to eq "only allow #{type} numbers for attr" + end + end + end + + [:is_greater_than, + :is_greater_than_or_equal_to, + :is_less_than, + :is_less_than_or_equal_to, + :is_equal_to ].each do |comparison| + context "with #{comparison} option" do + it do + expect(matcher.__send__(comparison, 18).description) + .to eq( + 'only allow numbers for attr which are ' + + "#{comparison.to_s.sub('is_', '').gsub('_', ' ')} 18" + ) + end + end + end + + context 'with odd, is_greater_than_or_equal_to option' do + it do + expect(matcher.odd.is_greater_than_or_equal_to(18).description) + .to eq( + 'only allow odd numbers for attr ' + + 'which are greater than or equal to 18' + ) + end + end + + context 'with only integer, is_greater_than and less_than_or_equal_to option' do + it { expect(matcher.only_integer.is_greater_than(18).is_less_than_or_equal_to(100).description). + to eq "only allow integers for attr which are greater than 18 and less than or equal to 100" } + end + end + + + def validating_numericality(options = {}) + define_model :example, attr: :string do + validates_numericality_of :attr, options + end.new + end + + def not_validating_numericality + define_model(:example, attr: :string).new + end + + def matcher + validate_numericality_of(:attr) + end + + def record_with_integer_column_of_limit(attribute, limit, validation_options = {}) + column_options = { type: :integer, options: { limit: limit } } + define_model :example, attribute => column_options do + validates_numericality_of attribute, validation_options + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,218 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher, type: :model do + context 'a model with a presence validation' do + it 'accepts' do + expect(validating_presence).to matcher + end + + it 'does not override the default message with a blank' do + expect(validating_presence).to matcher.with_message(nil) + end + end + + context 'a model without a presence validation' do + it 'rejects' do + expect(define_model(:example, attr: :string).new).not_to matcher + end + end + + context 'an ActiveModel class with a presence validation' do + it 'accepts' do + expect(active_model_validating_presence).to matcher + end + + it 'does not override the default message with a blank' do + expect(active_model_validating_presence).to matcher.with_message(nil) + end + end + + context 'an ActiveModel class without a presence validation' do + it 'rejects' do + expect(active_model).not_to matcher + end + + it 'provides the correct failure message' do + message = %{Expected errors to include "can't be blank" when attr is set to nil,\ngot no errors} + + expect { expect(active_model).to matcher }.to fail_with_message(message) + end + end + + context 'a has_many association with a presence validation' do + it 'requires the attribute to be set' do + expect(has_many_children(presence: true)).to validate_presence_of(:children) + end + end + + context 'a has_many association without a presence validation' do + it 'does not require the attribute to be set' do + expect(has_many_children(presence: false)). + not_to validate_presence_of(:children) + end + end + + context 'a required has_and_belongs_to_many association' do + before do + define_model :child + @model = define_model :parent do + has_and_belongs_to_many :children + validates_presence_of :children + end.new + create_table 'children_parents', id: false do |t| + t.integer :child_id + t.integer :parent_id + end + end + + it 'accepts' do + expect(@model).to validate_presence_of(:children) + end + end + + context 'an optional has_and_belongs_to_many association' do + before do + define_model :child + @model = define_model :parent do + has_and_belongs_to_many :children + end.new + create_table 'children_parents', id: false do |t| + t.integer :child_id + t.integer :parent_id + end + end + + it 'rejects' do + expect(@model).not_to validate_presence_of(:children) + end + end + + context "an i18n translation containing %{attribute} and %{model}" do + before do + stub_translation( + "activerecord.errors.messages.blank", + "Please enter a %{attribute} for your %{model}") + end + + after { I18n.backend.reload! } + + it "does not raise an exception" do + expect { + expect(validating_presence).to validate_presence_of(:attr) + }.to_not raise_exception + end + end + + if active_model_3_2? + context 'a strictly required attribute' do + it 'accepts when the :strict options match' do + expect(validating_presence(strict: true)).to matcher.strict + end + + it 'rejects when the :strict options do not match' do + expect(validating_presence(strict: false)).not_to matcher.strict + end + end + + it 'does not override the default message with a blank' do + expect(validating_presence(strict: true)). + to matcher.strict.with_message(nil) + end + end + + context "an attribute with a context-dependent validation" do + context "without the validation context" do + it "does not match" do + expect(validating_presence(on: :customisable)).not_to matcher + end + end + + context "with the validation context" do + it "matches" do + expect(validating_presence(on: :customisable)).to matcher.on(:customisable) + end + end + end + + context 'an active_resource model' do + context 'with the validation context' do + it 'does not raise an exception' do + expect { + expect(active_resource_model).to validate_presence_of(:attr) + }.to_not raise_exception + end + end + end + + if rails_4_x? + context 'against a pre-set password in a model that has_secure_password' do + it 'raises a CouldNotSetPasswordError exception' do + user_class = define_model :user, password_digest: :string do + has_secure_password validations: false + validates_presence_of :password + end + + user = user_class.new + user.password = 'something' + + error_class = Shoulda::Matchers::ActiveModel::CouldNotSetPasswordError + expect do + expect(user).to validate_presence_of(:password) + end.to raise_error(error_class) + end + end + end + + context 'when the attribute being tested intercepts the blank value we set on it (issue #479)' do + context 'for a non-collection attribute' do + it 'does not raise an error' do + record = define_model :example, attr: :string do + validates :attr, presence: true + + def attr=(value) + value = '' if value.nil? + super(value) + end + end.new + + expect do + expect(record).to validate_presence_of(:attr) + end.not_to raise_error + end + end + end + + def matcher + validate_presence_of(:attr) + end + + def validating_presence(options = {}) + define_model :example, attr: :string do + validates_presence_of :attr, options + end.new + end + + def active_model(&block) + define_active_model_class('Example', accessors: [:attr], &block).new + end + + def active_model_validating_presence + active_model { validates_presence_of :attr } + end + + def has_many_children(options = {}) + define_model :child + define_model :parent do + has_many :children + if options[:presence] + validates_presence_of :children + end + end.new + end + + def active_resource_model + define_active_resource_class :foo, attr: :string do + validates_presence_of :attr + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,564 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher, type: :model do + context 'a model without a a uniqueness validation' do + it 'rejects' do + model = define_model(:example, attr: :string) { attr_accessible :attr } .new + Example.create!(attr: 'value') + expect(model).not_to matcher + end + end + + context 'a model with a uniqueness validation' do + context 'where the subject has a character limit' do + it 'tests with values within the character limit' do + model = define_model(:example, attr: { type: :string, options: { limit: 1 } }) do + attr_accessible :attr + validates_uniqueness_of :attr + end.new + expect(model).to matcher + end + end + + context 'with an existing record' do + it 'requires a unique value for that attribute' do + create_existing + expect(validating_uniqueness_with_other).to matcher + end + + it 'accepts when the subject is an existing record' do + expect(create_existing).to matcher + end + + it 'rejects when a scope is specified' do + create_existing + expect(validating_uniqueness_with_other).not_to matcher.scoped_to(:other) + end + + def create_existing + define_model_with_other + Example.create!(attr: 'value', other: 1) + end + end + + context 'without an existing record' do + it 'does not require a created instance' do + define_model_with_other + expect(Example.count).to eq 0 + expect(validating_uniqueness_with_other).to matcher + end + + context "and the table uses non-nullable columns, set beforehand" do + it "does not require the record to be persisted" do + model = define_model_with_non_nullable_column + record = model.new(required_attribute_name => "some value") + expect(record).to validate_uniqueness_of(unique_attribute_name) + end + + def define_model_with_non_nullable_column + model = define_model(:example, + unique_attribute_name => :string, + required_attribute_name => { + type: :string, + options: { null: false } + } + ) + + model.tap do + model.attr_accessible( + required_attribute_name, + unique_attribute_name + ) + model.validates_presence_of(required_attribute_name) + model.validates_uniqueness_of(unique_attribute_name) + end + end + + def required_attribute_name + :required_attribute_name + end + + def unique_attribute_name + :unique_attribute_name + end + end + end + + def define_model_with_other(options = {}) + @model ||= define_model(:example, attr: :string, other: :integer) do + attr_accessible :attr, :other + validates_uniqueness_of :attr, options + end + end + + def validating_uniqueness_with_other(options = {}) + define_model_with_other.new + end + end + + context 'a model with a uniqueness validation, a custom error, and an existing record' do + it 'rejects when the actual message does not match the default message' do + expect(validating_uniqueness_with_existing_record(message: 'Bad value')). + not_to matcher + end + + it 'rejects when the messages do not match' do + expect(validating_uniqueness_with_existing_record(message: 'Bad value')). + not_to matcher.with_message(/abc/) + end + + it 'accepts when the messages match' do + expect(validating_uniqueness_with_existing_record(message: 'Bad value')). + to matcher.with_message(/Bad/) + end + + def validating_uniqueness_with_existing_record(options = {}) + model = define_model(:example, attr: :string) do + attr_accessible :attr + validates_uniqueness_of :attr, options + end.new + Example.create!(attr: 'value') + model + end + end + + context 'a model with a scoped uniqueness validation with an existing value' do + it 'accepts when the correct scope is specified' do + expect(validating_scoped_uniqueness([:scope1, :scope2])). + to matcher.scoped_to(:scope1, :scope2) + end + + it 'accepts when the subject is an existing record' do + define_scoped_model([:scope1, :scope2]) + expect(create_existing_record).to matcher.scoped_to(:scope1, :scope2) + end + + it 'rejects when too narrow of a scope is specified' do + expect(validating_scoped_uniqueness([:scope1, :scope2])). + not_to matcher.scoped_to(:scope1, :scope2, :other) + end + + it 'rejects when too broad of a scope is specified' do + expect(validating_scoped_uniqueness([:scope1, :scope2])). + not_to matcher.scoped_to(:scope1) + end + + it 'rejects when a different scope is specified' do + expect(validating_scoped_uniqueness([:scope1])). + not_to matcher.scoped_to(:other) + end + + it 'rejects when no scope is specified' do + expect(validating_scoped_uniqueness([:scope1])).not_to matcher + end + + it 'rejects when a non-existent attribute is specified as a scope' do + expect(validating_scoped_uniqueness([:scope1])). + not_to matcher.scoped_to(:fake) + end + + if rails_gte_4_1? + context 'when the scoped attribute is an enum' do + it 'accepts' do + expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: 0)). + to matcher.scoped_to(:scope1) + end + + context 'with a nil value' do + it 'accepts' do + expect(validating_scoped_uniqueness_with_enum([:scope1], scope1: nil)). + to matcher.scoped_to(:scope1) + end + end + + context 'when too narrow of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness_with_enum_with_two_scopes). + not_to matcher.scoped_to(:scope1, :scope2, :other) + end + end + + context 'when too broad of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness_with_enum_with_two_scopes). + not_to matcher.scoped_to(:scope1) + end + end + + def validating_scoped_uniqueness_with_enum_with_two_scopes + validating_scoped_uniqueness_with_enum([:scope1, :scope2], scope1: 0, scope2: 0) + end + end + end + + context 'when the scoped attribute is a date' do + it "accepts" do + expect(validating_scoped_uniqueness([:scope1], :date, scope1: Date.today)). + to matcher.scoped_to(:scope1) + end + + context 'with an existing record that conflicts with scope.next' do + it 'accepts' do + expect(validating_scoped_uniqueness_with_conflicting_next(:scope1, :date, scope1: Date.today)). + to matcher.scoped_to(:scope1) + end + end + + context 'when too narrow of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness([:scope1, :scope2], :date, scope1: Date.today, scope2: Date.today)). + not_to matcher.scoped_to(:scope1, :scope2, :other) + end + end + + context 'when too broad of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness([:scope1, :scope2], :date, scope1: Date.today, scope2: Date.today)). + not_to matcher.scoped_to(:scope1) + end + end + end + + context 'when the scoped attribute is a datetime' do + it 'accepts' do + expect(validating_scoped_uniqueness([:scope1], :datetime, scope1: DateTime.now)). + to matcher.scoped_to(:scope1) + end + + context 'with an existing record that conflicts with scope.next' do + it 'accepts' do + expect(validating_scoped_uniqueness_with_conflicting_next(:scope1, :datetime, scope1: DateTime.now)). + to matcher.scoped_to(:scope1) + end + end + + context 'with a nil value' do + it 'accepts' do + expect(validating_scoped_uniqueness([:scope1], :datetime, scope1: nil)). + to matcher.scoped_to(:scope1) + end + end + + context 'when too narrow of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness([:scope1, :scope2], :datetime, scope1: DateTime.now, scope2: DateTime.now)). + not_to matcher.scoped_to(:scope1, :scope2, :other) + end + end + + context 'when too broad of a scope is specified' do + it 'rejects' do + expect(validating_scoped_uniqueness([:scope1, :scope2], :datetime, scope1: DateTime.now, scope2: DateTime.now)). + not_to matcher.scoped_to(:scope1) + end + end + end + + context 'when the scoped attribute is a uuid' do + it 'accepts' do + expect(validating_scoped_uniqueness([:scope1], :uuid, scope1: SecureRandom.uuid)). + to matcher.scoped_to(:scope1) + end + + context 'with an existing record that conflicts with scope.next' do + it 'accepts' do + expect(validating_scoped_uniqueness_with_conflicting_next(:scope1, :uuid, scope1: SecureRandom.uuid)). + to matcher.scoped_to(:scope1) + end + end + + context 'with a nil value' do + it 'accepts' do + expect(validating_scoped_uniqueness([:scope1], :uuid, scope1: nil)). + to matcher.scoped_to(:scope1) + end + end + + context 'when too narrow of a scope is specified' do + it 'rejects' do + record = validating_scoped_uniqueness([:scope1, :scope2], :uuid, + scope1: SecureRandom.uuid, + scope2: SecureRandom.uuid + ) + expect(record).not_to matcher.scoped_to(:scope1, :scope2, :other) + end + end + + context 'when too broad of a scope is specified' do + it 'rejects' do + record = validating_scoped_uniqueness([:scope1, :scope2], :uuid, + scope1: SecureRandom.uuid, + scope2: SecureRandom.uuid + ) + expect(record).not_to matcher.scoped_to(:scope1) + end + end + end + + def create_existing_record(attributes = {}) + @existing ||= create_record(attributes) + end + + def create_record(attributes = {}) + default_attributes = {attr: 'value', scope1: 1, scope2: 2, other: 3} + Example.create!(default_attributes.merge(attributes)) + end + + def define_scoped_model(scope, scope_attr_type = :integer) + define_model(:example, attr: :string, scope1: scope_attr_type, + scope2: scope_attr_type, other: :integer) do + attr_accessible :attr, :scope1, :scope2, :other + validates_uniqueness_of :attr, scope: scope + end + end + + def validating_scoped_uniqueness(*args) + attributes = args.extract_options! + model = define_scoped_model(*args).new + create_existing_record(attributes) + model + end + + def validating_scoped_uniqueness_with_enum(*args) + attributes = args.extract_options! + model = define_scoped_model(*args) + model.enum scope1: [:foo, :bar] + create_existing_record(attributes) + model.new + end + + def validating_scoped_uniqueness_with_conflicting_next(*args) + attributes = args.extract_options! + model = define_scoped_model(*args).new + 2.times do + attributes[:scope1] = attributes[:scope1].next + create_record(attributes) + end + model + end + end + + context 'a model with a case-sensitive uniqueness validation on a string attribute and an existing record' do + it 'accepts a case-sensitive value for that attribute' do + expect(case_sensitive_validation_with_existing_value(:string)). + to matcher + end + + it 'rejects a case-insensitive value for that attribute' do + expect(case_sensitive_validation_with_existing_value(:string)). + not_to matcher.case_insensitive + end + end + + context 'a model with a case-sensitive uniqueness validation on an integer attribute with an existing value' do + it 'accepts a case-insensitive value for that attribute' do + expect(case_sensitive_validation_with_existing_value(:integer)). + to matcher.case_insensitive + end + + it 'accepts a case-sensitive value for that attribute' do + expect(case_sensitive_validation_with_existing_value(:integer)).to matcher + end + end + + context "when the validation allows nil" do + context "when there is an existing entry with a nil" do + it "should allow_nil" do + model = define_model_with_allow_nil + Example.create!(attr: nil) + expect(model).to matcher.allow_nil + end + end + + if active_model_3_1? + context 'when the subject has a secure password' do + it 'allows nil on the attribute' do + model = define_model(:example, attr: :string, password_digest: :string) do |m| + validates_uniqueness_of :attr, allow_nil: true + has_secure_password + end.new + expect(model).to matcher.allow_nil + end + end + end + + it "should create a nil and verify that it is allowed" do + model = define_model_with_allow_nil + expect(model).to matcher.allow_nil + Example.all.any?{ |instance| instance.attr.nil? } + end + + def define_model_with_allow_nil + define_model(:example, attr: :integer) do + attr_accessible :attr + validates_uniqueness_of :attr, allow_nil: true + end.new + end + end + + context "when the validation does not allow a nil" do + context "when there is an existing entry with a nil" do + it "should not allow_nil" do + model = define_model_without_allow_nil + Example.create!(attr: nil) + expect(model).not_to matcher.allow_nil + end + end + + it "should not allow_nil" do + model = define_model_without_allow_nil + expect(model).not_to matcher.allow_nil + end + + def define_model_without_allow_nil + define_model(:example, attr: :integer) do + attr_accessible :attr + validates_uniqueness_of :attr + end.new + end + end + + context 'when the validation allows blank' do + context 'when there is an existing record with a blank value' do + it 'accepts' do + model = model_allowing_blank + model.create!(attribute_name => '') + expect(model.new).to matcher.allow_blank + end + end + + context 'when there is not an an existing record with a blank value' do + it 'still accepts' do + expect(record_allowing_blank).to matcher.allow_blank + end + + it 'automatically creates a record' do + model = model_allowing_blank + matcher.allow_blank.matches?(model.new) + + record_created = model.all.any? do |instance| + instance.__send__(attribute_name).blank? + end + + expect(record_created).to be true + end + end + + def attribute_name + :attr + end + + def model_allowing_blank + _attribute_name = attribute_name + + define_model(:example, attribute_name => :string) do + attr_accessible _attribute_name + validates_uniqueness_of _attribute_name, allow_blank: true + end + end + + def record_allowing_blank + model_allowing_blank.new + end + end + + context 'when the validation does not allow blank' do + context 'when there is an existing entry with a blank value' do + it 'rejects' do + model = model_disallowing_blank + model.create!(attribute_name => '') + expect(model.new).not_to matcher.allow_blank + end + end + + it 'should not allow_blank' do + expect(record_disallowing_blank).not_to matcher.allow_blank + end + + def attribute_name + :attr + end + + def model_disallowing_blank + _attribute_name = attribute_name + + define_model(:example, attribute_name => :string) do + attr_accessible _attribute_name + validates_uniqueness_of _attribute_name, allow_blank: false + end + end + + def record_disallowing_blank + model_disallowing_blank.new + end + end + + context "when testing that a polymorphic *_type column is one of the validation scopes" do + it "sets that column to a meaningful value that works with other validations on the same column" do + user_model = define_model :user + favorite_columns = { + favoriteable_id: { type: :integer, options: { null: false } }, + favoriteable_type: { type: :string, options: { null: false } } + } + favorite_model = define_model :favorite, favorite_columns do + attr_accessible :favoriteable + belongs_to :favoriteable, polymorphic: true + validates :favoriteable, presence: true + validates :favoriteable_id, uniqueness: { scope: :favoriteable_type } + end + + user = user_model.create! + favorite_model.create!(favoriteable: user) + new_favorite = favorite_model.new + + expect(new_favorite). + to validate_uniqueness_of(:favoriteable_id). + scoped_to(:favoriteable_type) + end + + context "if the model the *_type column refers to is namespaced, and shares the last part of its name with an existing model" do + it "still works" do + define_class 'User' + define_module 'Models' + user_model = define_model 'Models::User' + favorite_columns = { + favoriteable_id: { type: :integer, options: { null: false } }, + favoriteable_type: { type: :string, options: { null: false } } + } + favorite_model = define_model 'Models::Favorite', favorite_columns do + attr_accessible :favoriteable + belongs_to :favoriteable, polymorphic: true + validates :favoriteable, presence: true + validates :favoriteable_id, uniqueness: { scope: :favoriteable_type } + end + + user = user_model.create! + favorite_model.create!(favoriteable: user) + new_favorite = favorite_model.new + + expect(new_favorite). + to validate_uniqueness_of(:favoriteable_id). + scoped_to(:favoriteable_type) + end + end + end + + def case_sensitive_validation_with_existing_value(attr_type) + model = define_model(:example, attr: attr_type) do + attr_accessible :attr + validates_uniqueness_of :attr, case_sensitive: true + end.new + if attr_type == :string + Example.create!(attr: 'value') + elsif attr_type == :integer + Example.create!(attr: 1) + else + raise 'Must be :string or :integer' + end + model + end + + def matcher + validate_uniqueness_of(:attr) + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,107 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::AcceptNestedAttributesForMatcher, type: :model do + it 'accepts an existing declaration' do + expect(accepting_children).to accept_nested_attributes_for(:children) + end + + it 'rejects a missing declaration' do + matcher = children_matcher + + expect(matcher.matches?(rejecting_children)).to eq false + + expect(matcher.failure_message). + to eq 'Expected Parent to accept nested attributes for children (is not declared)' + end + + context 'allow_destroy' do + it 'accepts a valid truthy value' do + matching = accepting_children(allow_destroy: true) + + expect(matching).to children_matcher.allow_destroy(true) + end + + it 'accepts a valid falsey value' do + matching = accepting_children(allow_destroy: false) + + expect(matching).to children_matcher.allow_destroy(false) + end + + it 'rejects an invalid truthy value' do + matcher = children_matcher + matching = accepting_children(allow_destroy: true) + + expect(matcher.allow_destroy(false).matches?(matching)).to eq false + expect(matcher.failure_message).to match(/should not allow destroy/) + end + + it 'rejects an invalid falsey value' do + matcher = children_matcher + matching = accepting_children(allow_destroy: false) + + expect(matcher.allow_destroy(true).matches?(matching)).to eq false + expect(matcher.failure_message).to match(/should allow destroy/) + end + end + + context 'limit' do + it 'accepts a correct value' do + expect(accepting_children(limit: 3)).to children_matcher.limit(3) + end + + it 'rejects a false value' do + matcher = children_matcher + rejecting = accepting_children(limit: 3) + + expect(matcher.limit(2).matches?(rejecting)).to eq false + expect(matcher.failure_message).to match(/limit should be 2, got 3/) + end + end + + context 'update_only' do + it 'accepts a valid truthy value' do + expect(accepting_children(update_only: true)). + to children_matcher.update_only(true) + end + + it 'accepts a valid falsey value' do + expect(accepting_children(update_only: false)). + to children_matcher.update_only(false) + end + + it 'rejects an invalid truthy value' do + matcher = children_matcher.update_only(false) + rejecting = accepting_children(update_only: true) + + expect(matcher.matches?(rejecting)).to eq false + expect(matcher.failure_message).to match(/should not be update only/) + end + + it 'rejects an invalid falsey value' do + matcher = children_matcher.update_only(true) + rejecting = accepting_children(update_only: false) + + expect(matcher.matches?(rejecting)).to eq false + expect(matcher.failure_message).to match(/should be update only/) + end + end + + def accepting_children(options = {}) + define_model :child, parent_id: :integer + define_model :parent do + has_many :children + accepts_nested_attributes_for :children, options + end.new + end + + def children_matcher + accept_nested_attributes_for(:children) + end + + def rejecting_children + define_model :child, parent_id: :integer + define_model :parent do + has_many :children + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,251 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::AssociationMatchers::ModelReflection do + it 'delegates other methods to the given Reflection object' do + define_model(:country) + person_model = define_model(:person, country_id: :integer) do + belongs_to :country + end + delegate_reflection = person_model.reflect_on_association(:country) + allow(delegate_reflection).to receive(:foo).and_return('bar') + reflection = described_class.new(delegate_reflection) + + expect(reflection.foo).to eq 'bar' + end + + describe '#associated_class' do + it 'returns the model that the association refers to' do + define_model(:country) + person_model = define_model(:person, country_id: :integer) do + belongs_to :country + end + delegate_reflection = person_model.reflect_on_association(:country) + reflection = described_class.new(delegate_reflection) + + expect(reflection.associated_class).to be Country + end + end + + describe '#through?' do + it 'returns true if the reflection is for a has_many :through association' do + define_model(:city, person_id: :integer) + define_model(:person, country_id: :integer) do + has_many :cities + end + country_model = define_model(:country) do + has_many :people + has_many :cities, through: :people + end + delegate_reflection = country_model.reflect_on_association(:cities) + reflection = described_class.new(delegate_reflection) + + expect(reflection).to be_through + end + + it 'returns false if not' do + define_model(:person, country_id: :integer) + country_model = define_model(:country) do + has_many :people + end + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + expect(reflection).not_to be_through + end + end + + describe '#join_table' do + context 'when the association was defined with a :join_table option' do + it 'returns the value of the option' do + create_table :foos, id: false do |t| + t.integer :person_id + t.integer :country_id + end + define_model(:person, country_id: :integer) + country_model = define_model(:country) do + has_and_belongs_to_many :people, join_table: 'foos' + end + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + expect(reflection.join_table).to eq 'foos' + end + end + + context 'when the association was not defined with :join_table' do + it 'returns the default join_table that ActiveRecord generates' do + define_model(:person, country_id: :integer) + country_model = define_model(:country) do + has_and_belongs_to_many :people + end + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + expect(reflection.join_table).to eq 'countries_people' + end + end + end + + describe '#association_relation' do + if rails_4_x? + context 'when the reflection object has a #scope method' do + context 'when the scope is a block' do + it 'executes the block in the context of an empty scope' do + define_model(:country, mood: :string) + person_model = define_model(:person, country_id: :integer) do + belongs_to :country, -> { where(mood: 'nice') } + end + delegate_reflection = person_model.reflect_on_association(:country) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Country.where(mood: 'nice').to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the scope is nil' do + it 'returns an empty scope' do + define_model(:country) + person_model = define_model(:person, country_id: :integer) do + belongs_to :country + end + delegate_reflection = person_model.reflect_on_association(:country) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Country.all.to_sql + expect(actual_sql).to eq expected_sql + end + end + end + end + + if rails_3_x? + context 'when the reflection object does not have a #scope method' do + context 'when the reflection options contain :conditions' do + it 'creates an ActiveRecord::Relation from the conditions' do + define_model(:country, mood: :string) + person_model = define_model(:person, country_id: :integer) do + belongs_to :country, conditions: { mood: 'nice' } + end + delegate_reflection = person_model.reflect_on_association(:country) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Country.where(mood: 'nice').to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :order' do + it 'creates an ActiveRecord::Relation from the order' do + define_model(:person, country_id: :integer, age: :integer) + country_model = define_model(:country) do + has_many :people, order: 'age' + end + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.order('age').to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :include' do + it 'creates an ActiveRecord::Relation from the include' do + define_model(:city, country_id: :integer) + define_model(:country) do + has_many :cities + end + person_model = define_model(:person, country_id: :integer) do + belongs_to :country, include: :cities + end + delegate_reflection = person_model.reflect_on_association(:country) + reflection = described_class.new(delegate_reflection) + + actual_includes = reflection.association_relation.includes_values + expected_includes = Country.includes(:cities).includes_values + expect(actual_includes).to eq expected_includes + end + end + + context 'when the reflection options contain :group' do + it 'creates an ActiveRecord::Relation from the group' do + country_model = define_model(:country, mood: :string) do + has_many :people, group: 'age' + end + define_model(:person, country_id: :integer, age: :integer) + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.group('age').to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :having' do + it 'creates an ActiveRecord::Relation from the having' do + country_model = define_model(:country) do + has_many :people, having: 'country_id > 1' + end + define_model(:person, country_id: :integer) + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.having('country_id > 1').to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :limit' do + it 'creates an ActiveRecord::Relation from the limit' do + country_model = define_model(:country) do + has_many :people, limit: 10 + end + define_model(:person, country_id: :integer) + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.limit(10).to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :offset' do + it 'creates an ActiveRecord::Relation from the offset' do + country_model = define_model(:country) do + has_many :people, offset: 5 + end + define_model(:person, country_id: :integer) + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.offset(5).to_sql + expect(actual_sql).to eq expected_sql + end + end + + context 'when the reflection options contain :select' do + it 'creates an ActiveRecord::Relation from the select' do + country_model = define_model(:country) do + has_many :people, select: 'age' + end + define_model(:person, country_id: :integer, age: :integer) + delegate_reflection = country_model.reflect_on_association(:people) + reflection = described_class.new(delegate_reflection) + + actual_sql = reflection.association_relation.to_sql + expected_sql = Person.select('age').to_sql + expect(actual_sql).to eq expected_sql + end + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,1149 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do + context 'belong_to' do + it 'accepts a good association with the default foreign key' do + expect(belonging_to_parent).to belong_to(:parent) + end + + it 'rejects a nonexistent association' do + expect(define_model(:child).new).not_to belong_to(:parent) + end + + it 'rejects an association of the wrong type' do + define_model :parent, child_id: :integer + expect(define_model(:child) { has_one :parent }.new).not_to belong_to(:parent) + end + + it 'rejects an association that has a nonexistent foreign key' do + define_model :parent + expect(define_model(:child) { belongs_to :parent }.new).not_to belong_to(:parent) + end + + it 'accepts an association with an existing custom foreign key' do + define_model :parent + define_model :child, guardian_id: :integer do + belongs_to :parent, foreign_key: 'guardian_id' + end + + expect(Child.new).to belong_to(:parent) + end + + it 'accepts an association using an existing custom primary key' do + define_model :parent + define_model :child, parent_id: :integer, custom_primary_key: :integer do + belongs_to :parent, primary_key: :custom_primary_key + end + expect(Child.new).to belong_to(:parent).with_primary_key(:custom_primary_key) + end + + it 'rejects an association with a bad :primary_key option' do + matcher = belong_to(:parent).with_primary_key(:custom_primary_key) + + expect(belonging_to_parent).not_to matcher + + expect(matcher.failure_message).to match(/Child does not have a custom_primary_key primary key/) + end + + it 'accepts a polymorphic association' do + define_model :child, parent_type: :string, parent_id: :integer do + belongs_to :parent, polymorphic: true + end + + expect(Child.new).to belong_to(:parent) + end + + it 'accepts an association with a valid :dependent option' do + expect(belonging_to_parent(dependent: :destroy)). + to belong_to(:parent).dependent(:destroy) + end + + it 'rejects an association with a bad :dependent option' do + expect(belonging_to_parent).not_to belong_to(:parent).dependent(:destroy) + end + + it 'accepts an association with a valid :counter_cache option' do + expect(belonging_to_parent(counter_cache: :attribute_count)). + to belong_to(:parent).counter_cache(:attribute_count) + end + + it 'defaults :counter_cache to true' do + expect(belonging_to_parent(counter_cache: true)). + to belong_to(:parent).counter_cache + end + + it 'rejects an association with a bad :counter_cache option' do + expect(belonging_to_parent(counter_cache: :attribute_count)). + not_to belong_to(:parent).counter_cache(true) + end + + it 'rejects an association that has no :counter_cache option' do + expect(belonging_to_parent).not_to belong_to(:parent).counter_cache + end + + it 'accepts an association with a valid :inverse_of option' do + expect(belonging_to_parent(inverse_of: :children)) + .to belong_to(:parent).inverse_of(:children) + end + + it 'rejects an association with a bad :inverse_of option' do + expect(belonging_to_parent(inverse_of: :other_children)) + .not_to belong_to(:parent).inverse_of(:children) + end + + it 'rejects an association that has no :inverse_of option' do + expect(belonging_to_parent) + .not_to belong_to(:parent).inverse_of(:children) + end + + it 'accepts an association with a valid :conditions option' do + define_model :parent, adopter: :boolean + define_model(:child, parent_id: :integer).tap do |model| + define_association_with_conditions(model, :belongs_to, :parent, adopter: true) + end + + expect(Child.new).to belong_to(:parent).conditions(adopter: true) + end + + it 'rejects an association with a bad :conditions option' do + define_model :parent, adopter: :boolean + define_model :child, parent_id: :integer do + belongs_to :parent + end + + expect(Child.new).not_to belong_to(:parent).conditions(adopter: true) + end + + it 'accepts an association without a :class_name option' do + expect(belonging_to_parent).to belong_to(:parent).class_name('Parent') + end + + it 'accepts an association with a valid :class_name option' do + define_model :tree_parent + define_model :child, parent_id: :integer do + belongs_to :parent, class_name: 'TreeParent' + end + + expect(Child.new).to belong_to(:parent).class_name('TreeParent') + end + + it 'rejects an association with a bad :class_name option' do + expect(belonging_to_parent).not_to belong_to(:parent).class_name('TreeChild') + end + + it 'rejects an association with non-existent implicit class name' do + expect(belonging_to_non_existent_class(:child, :parent)).not_to belong_to(:parent) + end + + it 'rejects an association with non-existent explicit class name' do + expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent')).not_to belong_to(:parent) + end + + it 'adds error message when rejecting an association with non-existent class' do + message = 'Expected Child to have a belongs_to association called parent (Parent2 does not exist)' + expect { + expect(belonging_to_non_existent_class(:child, :parent, class_name: 'Parent2')).to belong_to(:parent) + }.to fail_with_message(message) + end + + it 'accepts an association with a namespaced class name' do + define_module 'Models' + define_model 'Models::Organization' + user_model = define_model 'Models::User', organization_id: :integer do + belongs_to :organization, class_name: 'Organization' + end + + expect(user_model.new). + to belong_to(:organization). + class_name('Organization') + end + + it 'resolves class_name within the context of the namespace before the global namespace' do + define_module 'Models' + define_model 'Organization' + define_model 'Models::Organization' + user_model = define_model 'Models::User', organization_id: :integer do + belongs_to :organization, class_name: 'Organization' + end + + expect(user_model.new). + to belong_to(:organization). + class_name('Organization') + end + + it 'accepts an association with a matching :autosave option' do + define_model :parent, adopter: :boolean + define_model :child, parent_id: :integer do + belongs_to :parent, autosave: true + end + expect(Child.new).to belong_to(:parent).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :parent, adopter: :boolean + define_model :child, parent_id: :integer do + belongs_to :parent, autosave: false + end + + message = 'Expected Child to have a belongs_to association called parent (parent should have autosave set to true)' + expect { + expect(Child.new).to belong_to(:parent).autosave(true) + }.to fail_with_message(message) + end + + context 'an association with a :validate option' do + [false, true].each do |validate_value| + context "when the model has validate: #{validate_value}" do + it 'accepts a matching validate option' do + expect(belonging_to_parent(validate: validate_value)). + to belong_to(:parent).validate(validate_value) + end + + it 'rejects a non-matching validate option' do + expect(belonging_to_parent(validate: validate_value)). + not_to belong_to(:parent).validate(!validate_value) + end + + it 'defaults to validate(true)' do + if validate_value + expect(belonging_to_parent(validate: validate_value)). + to belong_to(:parent).validate + else + expect(belonging_to_parent(validate: validate_value)). + not_to belong_to(:parent).validate + end + end + + it 'will not break matcher when validate option is unspecified' do + expect(belonging_to_parent(validate: validate_value)).to belong_to(:parent) + end + end + end + end + + context 'an association without a :validate option' do + it 'accepts validate(false)' do + expect(belonging_to_parent).to belong_to(:parent).validate(false) + end + + it 'rejects validate(true)' do + expect(belonging_to_parent).not_to belong_to(:parent).validate(true) + end + + it 'rejects validate()' do + expect(belonging_to_parent).not_to belong_to(:parent).validate + end + end + + context 'an association with a :touch option' do + [false, true].each do |touch_value| + context "when the model has touch: #{touch_value}" do + it 'accepts a matching touch option' do + expect(belonging_to_parent(touch: touch_value)). + to belong_to(:parent).touch(touch_value) + end + + it 'rejects a non-matching touch option' do + expect(belonging_to_parent(touch: touch_value)). + not_to belong_to(:parent).touch(!touch_value) + end + + it 'defaults to touch(true)' do + if touch_value + expect(belonging_to_parent(touch: touch_value)). + to belong_to(:parent).touch + else + expect(belonging_to_parent(touch: touch_value)). + not_to belong_to(:parent).touch + end + end + + it 'will not break matcher when touch option is unspecified' do + expect(belonging_to_parent(touch: touch_value)).to belong_to(:parent) + end + end + end + end + + context 'an association without a :touch option' do + it 'accepts touch(false)' do + expect(belonging_to_parent).to belong_to(:parent).touch(false) + end + + it 'rejects touch(true)' do + expect(belonging_to_parent).not_to belong_to(:parent).touch(true) + end + + it 'rejects touch()' do + expect(belonging_to_parent).not_to belong_to(:parent).touch + end + end + + def belonging_to_parent(options = {}) + define_model :parent + define_model :child, parent_id: :integer do + belongs_to :parent, options + end.new + end + + def belonging_to_non_existent_class(model_name, assoc_name, options = {}) + define_model model_name, "#{assoc_name}_id" => :integer do + belongs_to assoc_name, options + end.new + end + end + + context 'have_many' do + it 'accepts a valid association without any options' do + expect(having_many_children).to have_many(:children) + end + + it 'accepts a valid association with a :through option' do + define_model :child + define_model :conception, child_id: :integer, + parent_id: :integer do + belongs_to :child + end + define_model :parent do + has_many :conceptions + has_many :children, through: :conceptions + end + expect(Parent.new).to have_many(:children) + end + + it 'accepts a valid association with an :as option' do + define_model :child, guardian_type: :string, guardian_id: :integer + define_model :parent do + has_many :children, as: :guardian + end + + expect(Parent.new).to have_many(:children) + end + + it 'rejects an association that has a nonexistent foreign key' do + define_model :child + define_model :parent do + has_many :children + end + + expect(Parent.new).not_to have_many(:children) + end + + it 'accepts an association using an existing custom primary key' do + define_model :child, parent_id: :integer + define_model :parent, custom_primary_key: :integer do + has_many :children, primary_key: :custom_primary_key + end + expect(Parent.new).to have_many(:children).with_primary_key(:custom_primary_key) + end + + it 'rejects an association with a bad :primary_key option' do + matcher = have_many(:children).with_primary_key(:custom_primary_key) + + expect(having_many_children).not_to matcher + + expect(matcher.failure_message).to match(/Parent does not have a custom_primary_key primary key/) + end + + it 'rejects an association with a bad :as option' do + define_model :child, caretaker_type: :string, + caretaker_id: :integer + define_model :parent do + has_many :children, as: :guardian + end + + expect(Parent.new).not_to have_many(:children) + end + + it 'rejects an association that has a bad :through option' do + matcher = have_many(:children).through(:conceptions) + + expect(matcher.matches?(having_many_children)).to eq false + + expect(matcher.failure_message).to match(/does not have any relationship to conceptions/) + end + + it 'rejects an association that has the wrong :through option' do + define_model :child + + define_model :conception, child_id: :integer, + parent_id: :integer do + belongs_to :child + end + + define_model :parent do + has_many :conceptions + has_many :relationships + has_many :children, through: :conceptions + end + + matcher = have_many(:children).through(:relationships) + expect(matcher.matches?(Parent.new)).to eq false + expect(matcher.failure_message).to match(/through relationships, but got it through conceptions/) + end + + it 'produces a failure message without exception when association is missing :through option' do + define_model :child + define_model :parent + matcher = have_many(:children).through(:relationships).source(:child) + failure_message = 'Expected Parent to have a has_many association called children (no association called children)' + + matcher.matches?(Parent.new) + expect(matcher.failure_message).to eq failure_message + end + + it 'accepts an association with a valid :dependent option' do + expect(having_many_children(dependent: :destroy)). + to have_many(:children).dependent(:destroy) + end + + it 'rejects an association with a bad :dependent option' do + matcher = have_many(:children).dependent(:destroy) + + expect(having_many_children).not_to matcher + + expect(matcher.failure_message).to match(/children should have destroy dependency/) + end + + it 'accepts an association with a valid :source option' do + expect(having_many_children(source: :user)). + to have_many(:children).source(:user) + end + + it 'rejects an association with a bad :source option' do + matcher = have_many(:children).source(:user) + + expect(having_many_children).not_to matcher + + expect(matcher.failure_message).to match(/children should have user as source option/) + end + + it 'accepts an association with a valid :order option' do + expect(having_many_children(order: :id)). + to have_many(:children).order(:id) + end + + it 'rejects an association with a bad :order option' do + matcher = have_many(:children).order(:id) + + expect(having_many_children).not_to matcher + + expect(matcher.failure_message).to match(/children should be ordered by id/) + end + + it 'accepts an association with a valid :conditions option' do + define_model :child, parent_id: :integer, adopted: :boolean + define_model(:parent).tap do |model| + define_association_with_conditions(model, :has_many, :children, adopted: true) + end + + expect(Parent.new).to have_many(:children).conditions(adopted: true) + end + + it 'rejects an association with a bad :conditions option' do + define_model :child, parent_id: :integer, adopted: :boolean + define_model :parent do + has_many :children + end + + expect(Parent.new).not_to have_many(:children).conditions(adopted: true) + end + + it 'accepts an association without a :class_name option' do + expect(having_many_children).to have_many(:children).class_name('Child') + end + + it 'accepts an association with a valid :class_name option' do + define_model :node, parent_id: :integer + define_model :parent do + has_many :children, class_name: 'Node' + end + + expect(Parent.new).to have_many(:children).class_name('Node') + end + + it 'rejects an association with a bad :class_name option' do + expect(having_many_children).not_to have_many(:children).class_name('Node') + end + + it 'rejects an association with non-existent implicit class name' do + expect(having_many_non_existent_class(:parent, :children)).not_to have_many(:children) + end + + it 'rejects an association with non-existent explicit class name' do + expect(having_many_non_existent_class(:parent, :children, class_name: 'Child')).not_to have_many(:children) + end + + it 'adds error message when rejecting an association with non-existent class' do + message = 'Expected Parent to have a has_many association called children (Child2 does not exist)' + expect { + expect(having_many_non_existent_class(:parent, :children, class_name: 'Child2')).to have_many(:children) + }.to fail_with_message(message) + end + + it 'accepts an association with a namespaced class name' do + define_module 'Models' + define_model 'Models::Friend', user_id: :integer + friend_model = define_model 'Models::User' do + has_many :friends, class_name: 'Friend' + end + + expect(friend_model.new). + to have_many(:friends). + class_name('Friend') + end + + it 'resolves class_name within the context of the namespace before the global namespace' do + define_module 'Models' + define_model 'Friend' + define_model 'Models::Friend', user_id: :integer + friend_model = define_model 'Models::User' do + has_many :friends, class_name: 'Friend' + end + + expect(friend_model.new). + to have_many(:friends). + class_name('Friend') + end + + it 'accepts an association with a matching :autosave option' do + define_model :child, parent_id: :integer + define_model :parent do + has_many :children, autosave: true + end + expect(Parent.new).to have_many(:children).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :child, parent_id: :integer + define_model :parent do + has_many :children, autosave: false + end + + message = 'Expected Parent to have a has_many association called children (children should have autosave set to true)' + expect { + expect(Parent.new).to have_many(:children).autosave(true) + }.to fail_with_message(message) + end + + context 'validate' do + it 'accepts when the :validate option matches' do + expect(having_many_children(validate: false)).to have_many(:children).validate(false) + end + + it 'rejects when the :validate option does not match' do + expect(having_many_children(validate: true)).not_to have_many(:children).validate(false) + end + + it 'assumes validate() means validate(true)' do + expect(having_many_children(validate: false)).not_to have_many(:children).validate + end + + it 'matches validate(false) to having no validate option specified' do + expect(having_many_children).to have_many(:children).validate(false) + end + end + + it 'accepts an association with a nonstandard reverse foreign key, using :inverse_of' do + define_model :child, ancestor_id: :integer do + belongs_to :ancestor, inverse_of: :children, class_name: :Parent + end + + define_model :parent do + has_many :children, inverse_of: :ancestor + end + + expect(Parent.new).to have_many(:children) + end + + it 'rejects an association with a nonstandard reverse foreign key, if :inverse_of is not correct' do + define_model :child, mother_id: :integer do + belongs_to :mother, inverse_of: :children, class_name: :Parent + end + + define_model :parent do + has_many :children, inverse_of: :ancestor + end + + expect(Parent.new).not_to have_many(:children) + end + + def having_many_children(options = {}) + define_model :child, parent_id: :integer + define_model(:parent).tap do |model| + if options.key?(:order) + order = options.delete(:order) + define_association_with_order(model, :has_many, :children, order, options) + else + model.has_many :children, options + end + end.new + end + + def having_many_non_existent_class(model_name, assoc_name, options = {}) + define_model model_name do + has_many assoc_name, options + end.new + end + end + + context 'have_one' do + it 'accepts a valid association without any options' do + expect(having_one_detail).to have_one(:detail) + end + + it 'accepts a valid association with an :as option' do + define_model :detail, detailable_id: :integer, + detailable_type: :string + define_model :person do + has_one :detail, as: :detailable + end + + expect(Person.new).to have_one(:detail) + end + + it 'rejects an association that has a nonexistent foreign key' do + define_model :detail + define_model :person do + has_one :detail + end + + expect(Person.new).not_to have_one(:detail) + end + + it 'accepts an association with an existing custom foreign key' do + define_model :detail, detailed_person_id: :integer + define_model :person do + has_one :detail, foreign_key: :detailed_person_id + end + expect(Person.new).to have_one(:detail).with_foreign_key(:detailed_person_id) + end + + it 'accepts an association using an existing custom primary key' do + define_model :detail, person_id: :integer + define_model :person, custom_primary_key: :integer do + has_one :detail, primary_key: :custom_primary_key + end + expect(Person.new).to have_one(:detail).with_primary_key(:custom_primary_key) + end + + it 'rejects an association with a bad :primary_key option' do + matcher = have_one(:detail).with_primary_key(:custom_primary_key) + + expect(having_one_detail).not_to matcher + + expect(matcher.failure_message).to match(/Person does not have a custom_primary_key primary key/) + end + + it 'rejects an association with a bad :as option' do + define_model :detail, detailable_id: :integer, + detailable_type: :string + define_model :person do + has_one :detail, as: :describable + end + + expect(Person.new).not_to have_one(:detail) + end + + it 'accepts an association with a valid :dependent option' do + dependent_options.each do |option| + expect(having_one_detail(dependent: option)). + to have_one(:detail).dependent(option) + end + end + + it 'accepts any dependent option if true' do + dependent_options.each do |option| + expect(having_one_detail(dependent: option)). + to have_one(:detail).dependent(true) + end + end + + it 'rejects any dependent options if false' do + dependent_options.each do |option| + expect(having_one_detail(dependent: option)). + to_not have_one(:detail).dependent(false) + end + end + + it 'accepts a nil dependent option if false' do + expect(having_one_detail).to have_one(:detail).dependent(false) + end + + it 'rejects an association with a bad :dependent option' do + matcher = have_one(:detail).dependent(:destroy) + + expect(having_one_detail).not_to matcher + + expect(matcher.failure_message).to match(/detail should have destroy dependency/) + end + + it 'accepts an association with a valid :order option' do + expect(having_one_detail(order: :id)).to have_one(:detail).order(:id) + end + + it 'rejects an association with a bad :order option' do + matcher = have_one(:detail).order(:id) + + expect(having_one_detail).not_to matcher + + expect(matcher.failure_message).to match(/detail should be ordered by id/) + end + + it 'accepts an association with a valid :conditions option' do + define_model :detail, person_id: :integer, disabled: :boolean + define_model(:person).tap do |model| + define_association_with_conditions(model, :has_one, :detail, disabled: true) + end + + expect(Person.new).to have_one(:detail).conditions(disabled: true) + end + + it 'rejects an association with a bad :conditions option' do + define_model :detail, person_id: :integer, disabled: :boolean + define_model :person do + has_one :detail + end + + expect(Person.new).not_to have_one(:detail).conditions(disabled: true) + end + + it 'accepts an association without a :class_name option' do + expect(having_one_detail).to have_one(:detail).class_name('Detail') + end + + it 'accepts an association with a valid :class_name option' do + define_model :person_detail, person_id: :integer + define_model :person do + has_one :detail, class_name: 'PersonDetail' + end + + expect(Person.new).to have_one(:detail).class_name('PersonDetail') + end + + it 'rejects an association with a bad :class_name option' do + expect(having_one_detail).not_to have_one(:detail).class_name('NotSet') + end + + it 'rejects an association with non-existent implicit class name' do + expect(having_one_non_existent(:pserson, :detail)).not_to have_one(:detail) + end + + it 'rejects an association with non-existent explicit class name' do + expect(having_one_non_existent(:person, :detail, class_name: 'Detail')).not_to have_one(:detail) + end + + it 'adds error message when rejecting an association with non-existent class' do + message = 'Expected Person to have a has_one association called detail (Detail2 does not exist)' + expect { + expect(having_one_non_existent(:person, :detail, class_name: 'Detail2')).to have_one(:detail) + }.to fail_with_message(message) + end + + it 'accepts an association with a namespaced class name' do + define_module 'Models' + define_model 'Models::Account', user_id: :integer + user_model = define_model 'Models::User' do + has_one :account, class_name: 'Account' + end + + expect(user_model.new). + to have_one(:account). + class_name('Account') + end + + it 'resolves class_name within the context of the namespace before the global namespace' do + define_module 'Models' + define_model 'Account' + define_model 'Models::Account', user_id: :integer + user_model = define_model 'Models::User' do + has_one :account, class_name: 'Account' + end + + expect(user_model.new). + to have_one(:account). + class_name('Account') + end + + it 'accepts an association with a matching :autosave option' do + define_model :detail, person_id: :integer, disabled: :boolean + define_model :person do + has_one :detail, autosave: true + end + expect(Person.new).to have_one(:detail).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :detail, person_id: :integer, disabled: :boolean + define_model :person do + has_one :detail, autosave: false + end + + message = 'Expected Person to have a has_one association called detail (detail should have autosave set to true)' + expect { + expect(Person.new).to have_one(:detail).autosave(true) + }.to fail_with_message(message) + end + + + it 'accepts an association with a through' do + define_model :detail + + define_model :account do + has_one :detail + end + + define_model :person do + has_one :account + has_one :detail, through: :account + end + + expect(Person.new).to have_one(:detail).through(:account) + end + + it 'rejects an association with a bad through' do + expect(having_one_detail).not_to have_one(:detail).through(:account) + end + + context 'validate' do + it 'accepts when the :validate option matches' do + expect(having_one_detail(validate: false)). + to have_one(:detail).validate(false) + end + + it 'rejects when the :validate option does not match' do + expect(having_one_detail(validate: true)). + not_to have_one(:detail).validate(false) + end + + it 'assumes validate() means validate(true)' do + expect(having_one_detail(validate: false)). + not_to have_one(:detail).validate + end + + it 'matches validate(false) to having no validate option specified' do + expect(having_one_detail).to have_one(:detail).validate(false) + end + end + + def having_one_detail(options = {}) + define_model :detail, person_id: :integer + define_model(:person).tap do |model| + if options.key?(:order) + order = options.delete(:order) + define_association_with_order(model, :has_one, :detail, order, options) + else + model.has_one :detail, options + end + end.new + end + + def having_one_non_existent(model_name, assoc_name, options = {}) + define_model model_name do + has_one assoc_name, options + end.new + end + end + + context 'have_and_belong_to_many' do + it 'accepts a valid association' do + expect(having_and_belonging_to_many_relatives). + to have_and_belong_to_many(:relatives) + end + + it 'rejects a nonexistent association' do + define_model :relative + define_model :person + define_model :people_relative, id: false, person_id: :integer, + relative_id: :integer + + expect(Person.new).not_to have_and_belong_to_many(:relatives) + end + + it 'rejects an association with a nonexistent join table' do + define_model :relative + define_model :person do + has_and_belongs_to_many :relatives + end + + expected_failure_message = "join table people_relatives doesn't exist" + + expect do + expect(Person.new).to have_and_belong_to_many(:relatives) + end.to fail_with_message_including(expected_failure_message) + end + + it 'rejects an association with a join table with incorrect columns' do + define_model :relative + define_model :person do + has_and_belongs_to_many :relatives + end + + define_model :people_relative, id: false, some_crazy_id: :integer + + expect do + expect(Person.new).to have_and_belong_to_many(:relatives) + end.to fail_with_message_including('missing columns: person_id, relative_id') + end + + context 'using a custom foreign key' do + it 'rejects an association with a join table with incorrect columns' do + define_model :relative + define_model :person do + has_and_belongs_to_many :relatives, + foreign_key: :custom_foreign_key_id + end + + define_model :people_relative, + id: false, + custom_foreign_key_id: :integer, + some_crazy_id: :integer + + expect do + expect(Person.new).to have_and_belong_to_many(:relatives) + end.to fail_with_message_including('missing column: relative_id') + end + end + + context 'using a custom association foreign key' do + it 'rejects an association with a join table with incorrect columns' do + define_model :relative + define_model :person do + has_and_belongs_to_many :relatives, + association_foreign_key: :custom_association_foreign_key_id + end + + define_model :people_relative, + id: false, + custom_association_foreign_key_id: :integer, + some_crazy_id: :integer + + expect do + expect(Person.new).to have_and_belong_to_many(:relatives) + end.to fail_with_message_including('missing column: person_id') + end + + it 'accepts foreign keys when they are symbols' do + define_model :relative + define_model :person do + has_and_belongs_to_many :relatives, + foreign_key: :some_foreign_key_id, + association_foreign_key: :custom_association_foreign_key_id + end + + define_model :people_relative, + id: false, + custom_association_foreign_key_id: :integer, + some_foreign_key_id: :integer + + expect(Person.new).to have_and_belong_to_many(:relatives) + + end + + end + + it 'rejects an association of the wrong type' do + define_model :relative, person_id: :integer + define_model :person do + has_many :relatives + end + + expect(Person.new).not_to have_and_belong_to_many(:relatives) + end + + it 'accepts an association with a valid :conditions option' do + define_model :relative, adopted: :boolean + define_model(:person).tap do |model| + define_association_with_conditions(model, :has_and_belongs_to_many, :relatives, adopted: true) + end + define_model :people_relative, id: false, person_id: :integer, + relative_id: :integer + + expect(Person.new).to have_and_belong_to_many(:relatives).conditions(adopted: true) + end + + it 'rejects an association with a bad :conditions option' do + define_model :relative, adopted: :boolean + define_model :person do + has_and_belongs_to_many :relatives + end + define_model :people_relative, id: false, person_id: :integer, + relative_id: :integer + + expect(Person.new).not_to have_and_belong_to_many(:relatives).conditions(adopted: true) + end + + it 'accepts an association without a :class_name option' do + expect(having_and_belonging_to_many_relatives). + to have_and_belong_to_many(:relatives).class_name('Relative') + end + + it 'accepts an association with a valid :class_name option' do + define_model :person_relative, adopted: :boolean + define_model :person do + has_and_belongs_to_many :relatives, class_name: 'PersonRelative' + end + + define_model :people_person_relative, person_id: :integer, + person_relative_id: :integer + + expect(Person.new).to have_and_belong_to_many(:relatives).class_name('PersonRelative') + end + + it 'rejects an association with a bad :class_name option' do + expect(having_and_belonging_to_many_relatives). + not_to have_and_belong_to_many(:relatives).class_name('PersonRelatives') + end + + it 'rejects an association with non-existent implicit class name' do + expect(having_and_belonging_to_many_non_existent_class(:person, :relatives)). + not_to have_and_belong_to_many(:relatives) + end + + it 'rejects an association with non-existent explicit class name' do + expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative')). + not_to have_and_belong_to_many(:relatives) + end + + it 'adds error message when rejecting an association with non-existent class' do + message = 'Expected Person to have a has_and_belongs_to_many association called relatives (Relative2 does not exist)' + expect { + expect(having_and_belonging_to_many_non_existent_class(:person, :relatives, class_name: 'Relative2')). + to have_and_belong_to_many(:relatives) + }.to fail_with_message(message) + end + + it 'accepts an association with a namespaced class name' do + possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users] + possible_join_table_names.each do |join_table_name| + create_table join_table_name, id: false do |t| + t.integer :group_id + t.integer :user_id + end + end + define_module 'Models' + define_model 'Models::Group' + user_model = define_model 'Models::User' do + has_and_belongs_to_many :groups, class_name: 'Group' + end + + expect(user_model.new). + to have_and_belong_to_many(:groups). + class_name('Group') + end + + it 'resolves class_name within the context of the namespace before the global namespace' do + possible_join_table_names = [:groups_users, :models_groups_users, :groups_models_users] + possible_join_table_names.each do |join_table_name| + create_table join_table_name, id: false do |t| + t.integer :group_id + t.integer :user_id + end + end + define_module 'Models' + define_model 'Group' + define_model 'Models::Group' + user_model = define_model 'Models::User' do + has_and_belongs_to_many :groups, class_name: 'Group' + end + + expect(user_model.new). + to have_and_belong_to_many(:groups). + class_name('Group') + end + + it 'accepts an association with a matching :autosave option' do + define_model :relatives, adopted: :boolean + define_model :person do + has_and_belongs_to_many :relatives, autosave: true + end + define_model :people_relative, person_id: :integer, + relative_id: :integer + expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true) + end + + it 'rejects an association with a non-matching :autosave option with the correct message' do + define_model :relatives, adopted: :boolean + define_model :person do + has_and_belongs_to_many :relatives + end + define_model :people_relative, person_id: :integer, + relative_id: :integer + + message = 'Expected Person to have a has_and_belongs_to_many association called relatives (relatives should have autosave set to true)' + expect { + expect(Person.new).to have_and_belong_to_many(:relatives).autosave(true) + }.to fail_with_message(message) + end + + context 'validate' do + it 'accepts when the :validate option matches' do + expect(having_and_belonging_to_many_relatives(validate: false)). + to have_and_belong_to_many(:relatives).validate(false) + end + + it 'rejects when the :validate option does not match' do + expect(having_and_belonging_to_many_relatives(validate: true)). + to have_and_belong_to_many(:relatives).validate(false) + end + + it 'assumes validate() means validate(true)' do + expect(having_and_belonging_to_many_relatives(validate: false)). + not_to have_and_belong_to_many(:relatives).validate + end + + it 'matches validate(false) to having no validate option specified' do + expect(having_and_belonging_to_many_relatives). + to have_and_belong_to_many(:relatives).validate(false) + end + end + + def having_and_belonging_to_many_relatives(options = {}) + define_model :relative + define_model :people_relative, id: false, person_id: :integer, + relative_id: :integer + define_model :person do + has_and_belongs_to_many :relatives + end.new + end + + def having_and_belonging_to_many_non_existent_class(model_name, assoc_name, options = {}) + define_model model_name do + has_and_belongs_to_many assoc_name, options + end.new + end + end + + def define_association_with_conditions(model, macro, name, conditions, other_options={}) + args = [] + options = {} + if Shoulda::Matchers::RailsShim.active_record_major_version == 4 + args << proc { where(conditions) } + else + options[:conditions] = conditions + end + args << options + model.__send__(macro, name, *args) + end + + def define_association_with_order(model, macro, name, order, other_options={}) + args = [] + options = {} + if Shoulda::Matchers::RailsShim.active_record_major_version == 4 + args << proc { order(order) } + else + options[:order] = order + end + args << options + model.__send__(macro, name, *args) + end + + def dependent_options + case Rails.version + when /\A3/ + [:destroy, :delete, :nullify, :restrict] + when /\A4/ + [:destroy, :delete, :nullify, :restrict_with_exception, :restrict_with_error] + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,101 @@ +require "unit_spec_helper" + +describe Shoulda::Matchers::ActiveRecord::DefineEnumForMatcher, type: :model do + if active_record_supports_enum? + describe "with only the attribute name specified" do + it "accepts a record where the attribute is defined as an enum" do + expect(record_with_array_values).to define_enum_for(enum_attribute) + end + + it "rejects a record where the attribute is not defined as an enum" do + message = "Expected #{record_with_array_values.class} to define :#{non_enum_attribute} as an enum" + + expect do + expect(record_with_array_values).to define_enum_for(non_enum_attribute) + end.to fail_with_message(message) + end + + it "rejects a record where the attribute is not defined as an enum with should not" do + message = "Did not expect #{record_with_array_values.class} to define :#{enum_attribute} as an enum" + + expect do + expect(record_with_array_values).to_not define_enum_for(enum_attribute) + end.to fail_with_message(message) + end + end + + describe "with both attribute name and enum values specified" do + context "when the actual enum values are an array" do + it "accepts a record where the attribute is defined as an enum and the enum values match" do + expect(record_with_array_values).to define_enum_for(enum_attribute). + with(["published", "unpublished", "draft"]) + end + + it "accepts a record where the attribute is not defined as an enum" do + message = %{Expected #{record_with_array_values.class} to define :#{non_enum_attribute} as an enum with ["open", "close"]} + + expect do + expect(record_with_array_values).to define_enum_for(non_enum_attribute).with(["open", "close"]) + end.to fail_with_message(message) + end + + it "accepts a record where the attribute is defined as an enum but the enum values do not match" do + message = %{Expected #{record_with_array_values.class} to define :#{enum_attribute} as an enum with ["open", "close"]} + + expect do + expect(record_with_array_values).to define_enum_for(enum_attribute).with(["open", "close"]) + end.to fail_with_message(message) + end + end + + context "when the actual enum values are a hash" do + it "accepts a record where the attribute is defined as an enum and the enum values match" do + expect(record_with_hash_values).to define_enum_for(enum_attribute).with(active: 0, archived: 1) + end + + it "accepts a record where the enum values match when expected enum values are given as an array" do + expect(record_with_hash_values).to define_enum_for(enum_attribute).with(["active", "archived"]) + end + + it "accepts a record where the attribute is defined as an enum but the enum values do not match" do + message = %{Expected #{record_with_hash_values.class} to define :#{enum_attribute} as an enum with {:active=>5, :archived=>10}} + + expect do + expect(record_with_hash_values).to define_enum_for(enum_attribute).with(active: 5, archived: 10) + end.to fail_with_message(message) + end + + it "rejects a record where the attribute is not defined as an enum" do + message = %{Expected #{record_with_hash_values.class} to define :record_with_hash_values as an enum with {:active=>5, :archived=>10}} + + expect do + expect(record_with_hash_values) + .to define_enum_for(:record_with_hash_values).with(active: 5, archived: 10) + end.to fail_with_message(message) + end + end + end + + def enum_attribute + :status + end + + def non_enum_attribute + :condition + end + + def record_with_array_values + _enum_attribute = enum_attribute + define_model :record_with_array_values do + enum(_enum_attribute => %w(published unpublished draft)) + end.new + end + + def record_with_hash_values + _enum_attribute = enum_attribute + define_model :record_with_hash_values do + enum(_enum_attribute => { active: 0, archived: 1 }) + end.new + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_db_column_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,111 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::HaveDbColumnMatcher, type: :model do + it 'accepts an existing database column' do + expect(model(nickname: :string)).to have_db_column(:nickname) + end + + it 'rejects a nonexistent database column' do + expect(define_model(:employee).new).not_to have_db_column(:nickname) + end + + context '#of_type' do + it 'accepts a column of correct type' do + expect(model(nickname: :string)). + to have_db_column(:nickname).of_type(:string) + end + + it 'rejects a nonexistent database column' do + expect(define_model(:superhero).new). + not_to have_db_column(:nickname).of_type(:string) + end + + it 'rejects a column of wrong type' do + expect(model(nickname: :integer)). + not_to have_db_column(:nickname).of_type(:string) + end + end + + context 'with precision option' do + it 'accepts a column of correct precision' do + expect(with_table(:salary, :decimal, precision: 5)). + to have_db_column(:salary).with_options(precision: 5) + end + + it 'rejects a column of wrong precision' do + expect(with_table(:salary, :decimal, precision: 6)). + not_to have_db_column(:salary).with_options(precision: 5) + end + end + + context 'with limit option' do + it 'accepts a column of correct limit' do + expect(with_table(:email, :string, limit: 255)). + to have_db_column(:email).with_options(limit: 255) + end + + it 'rejects a column of wrong limit' do + expect(with_table(:email, :string, limit: 100)). + not_to have_db_column(:email).with_options(limit: 255) + end + end + + context 'with default option' do + it 'accepts a column with correct default' do + expect(with_table(:admin, :boolean, default: false)). + to have_db_column(:admin).with_options(default: false) + end + + it 'rejects a column with wrong default' do + expect(with_table(:admin, :boolean, default: true)). + not_to have_db_column(:admin).with_options(default: false) + end + end + + context 'with null option' do + it 'accepts a column of correct null' do + expect(with_table(:admin, :boolean, null: false)). + to have_db_column(:admin).with_options(null: false) + end + + it 'rejects a column of wrong null' do + expect(with_table(:admin, :boolean, null: true)). + not_to have_db_column(:admin).with_options(null: false) + end + end + + context 'with scale option' do + it 'accepts a column of correct scale' do + expect(with_table(:salary, :decimal, precision: 10, scale: 2)). + to have_db_column(:salary).with_options(scale: 2) + end + + it 'rejects a column of wrong scale' do + expect(with_table(:salary, :decimal, precision: 10, scale: 4)). + not_to have_db_column(:salary).with_options(scale: 2) + end + end + + context 'with primary option' do + it 'accepts a column that is primary' do + expect(with_table(:custom_id, :integer, primary: true)). + to have_db_column(:id).with_options(primary: true) + end + + it 'rejects a column that is not primary' do + expect(with_table(:whatever, :integer, primary: false)). + not_to have_db_column(:whatever).with_options(primary: true) + end + end + + def model(options = {}) + define_model(:employee, options).new + end + + def with_table(column_name, column_type, options) + create_table 'employees' do |table| + table.__send__(column_type, column_name, options) + end + define_model_class('Employee').new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,85 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::HaveDbIndexMatcher, type: :model do + context 'have_db_index' do + it 'accepts an existing index' do + expect(with_index_on(:age)).to have_db_index(:age) + end + + it 'rejects a nonexistent index' do + expect(define_model(:employee).new).not_to have_db_index(:age) + end + end + + context 'have_db_index with unique option' do + it 'accepts an index of correct unique' do + expect(with_index_on(:ssn, unique: true)). + to have_db_index(:ssn).unique(true) + end + + it 'rejects an index of wrong unique' do + expect(with_index_on(:ssn, unique: false)). + not_to have_db_index(:ssn).unique(true) + end + end + + context 'have_db_index on multiple columns' do + it 'accepts an existing index' do + db_connection = create_table 'geocodings' do |table| + table.integer :geocodable_id + table.string :geocodable_type + end + db_connection.add_index :geocodings, [:geocodable_type, :geocodable_id] + expect(define_model_class('Geocoding').new). + to have_db_index([:geocodable_type, :geocodable_id]) + end + + it 'rejects a nonexistent index' do + create_table 'geocodings' do |table| + table.integer :geocodable_id + table.string :geocodable_type + end + expect(define_model_class('Geocoding').new). + not_to have_db_index([:geocodable_type, :geocodable_id]) + end + end + + it 'join columns with and when describing multiple columns' do + expect(have_db_index([:user_id, :post_id]).description).to match(/on columns user_id and post_id/) + end + + it 'describes a unique index as unique' do + expect(have_db_index(:user_id).unique(true).description).to match(/a unique index/) + end + + it 'describes a unique index as unique when no argument is given' do + expect(have_db_index(:user_id).unique.description).to match(/a unique index/) + end + + it 'describes a non-unique index as non-unique' do + expect(have_db_index(:user_id).unique(false).description).to match(/a non-unique index/) + end + + it "does not display an index's uniqueness when it's not important" do + expect(have_db_index(:user_id).description).not_to match(/unique/) + end + + it 'allows an IndexDefinition to have a truthy value for unique' do + index_definition = double( + 'ActiveRecord::ConnectionAdapters::IndexDefinition', + unique: 7, + name: :age + ) + matcher = have_db_index(:age).unique(true) + allow(matcher).to receive(:matched_index).and_return(index_definition) + + expect(with_index_on(:age)).to matcher + end + + def with_index_on(column_name, index_options = {}) + create_table 'employees' do |table| + table.integer column_name + end.add_index(:employees, column_name, index_options) + define_model_class('Employee').new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,41 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::HaveReadonlyAttributeMatcher, type: :model do + context 'a read-only attribute' do + it 'accepts' do + expect(with_readonly_attr).to have_readonly_attribute(:attr) + end + end + + context 'an attribute that is not part of the read-only set' do + it 'rejects being read-only' do + model = define_model :example, attr: :string, other: :string do + attr_readonly :attr + end.new + + expect(model).not_to have_readonly_attribute(:other) + end + end + + context 'an attribute on a class with no readonly attributes' do + it 'rejects being read-only' do + expect(define_model(:example, attr: :string).new). + not_to have_readonly_attribute(:attr) + end + + it 'assigns a failure message' do + model = define_model(:example, attr: :string).new + matcher = have_readonly_attribute(:attr) + + matcher.matches?(model) + + expect(matcher.failure_message).not_to be_nil + end + end + + def with_readonly_attr + define_model :example, attr: :string do + attr_readonly :attr + end.new + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/active_record/serialize_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,86 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::ActiveRecord::SerializeMatcher, type: :model do + it 'accepts when the attribute is serialized' do + expect(with_serialized_attr).to serialize(:attr) + end + + context 'when attribute is not serialized' do + it 'rejects' do + expect(unserialized_model).not_to serialize(:attr) + end + + it 'assigns a helpful failure message' do + matcher = serialize(:attr) + + matcher.matches?(unserialized_model) + + expect(matcher.failure_message).to match(/to serialize the attribute called :attr/) + end + + it 'assigns a helpful failure message when using #as' do + matcher = serialize(:attr).as(Hash) + + matcher.matches?(unserialized_model) + + expect(matcher.failure_message).to match(/with a type of Hash/) + end + + it 'assigns a helpful failure message when using #as_instance_of' do + matcher = serialize(:attr).as_instance_of(Hash) + + matcher.matches?(unserialized_model) + + expect(matcher.failure_message).to match(/with an instance of Hash/) + end + + def unserialized_model + @model ||= define_model(:example, attr: :string).new + end + end + + context 'an attribute that will end up being serialized as YAML' do + it 'accepts when the types match' do + expect(with_serialized_attr(Hash)).to serialize(:attr).as(Hash) + end + + it 'rejects when the types do not match' do + expect(with_serialized_attr(Hash)).not_to serialize(:attr).as(String) + end + + it 'rejects when using as_instance_of' do + expect(with_serialized_attr(Hash)).not_to serialize(:attr).as_instance_of(Hash) + end + end + + context 'a serializer that is an instance of a class' do + it 'accepts when using #as_instance_of' do + define_serializer(:ExampleSerializer) + expect(with_serialized_attr(ExampleSerializer.new)). + to serialize(:attr).as_instance_of(ExampleSerializer) + end + + it 'rejects when using #as' do + define_serializer(:ExampleSerializer) + expect(with_serialized_attr(ExampleSerializer.new)). + not_to serialize(:attr).as(ExampleSerializer) + end + end + + def with_serialized_attr(type = nil) + define_model(:example, attr: :string) do + if type + serialize :attr, type + else + serialize :attr + end + end.new + end + + def define_serializer(name) + define_class(name) do + def load(*); end + def dump(*); end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,124 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe DoubleCollection do + describe '#register_stub' do + it 'calls DoubleImplementationRegistry.find correctly' do + allow(DoubleImplementationRegistry).to receive(:find) + double_collection = described_class.new(:klass) + + double_collection.register_stub(:a_method) + + expect(DoubleImplementationRegistry).to have_received(:find).with(:stub) + end + + it 'calls Double.new correctly' do + allow(DoubleImplementationRegistry). + to receive(:find). + and_return(:implementation) + allow(Double).to receive(:new) + double_collection = described_class.new(:klass) + + double_collection.register_stub(:a_method) + + expect(Double). + to have_received(:new). + with(:klass, :a_method, :implementation) + end + end + + describe '#register_proxy' do + it 'calls DoubleImplementationRegistry.find correctly' do + allow(DoubleImplementationRegistry).to receive(:find) + double_collection = described_class.new(:klass) + + double_collection.register_proxy(:a_method) + + expect(DoubleImplementationRegistry). + to have_received(:find). + with(:proxy) + end + + it 'calls Double.new correctly' do + allow(DoubleImplementationRegistry). + to receive(:find). + and_return(:implementation) + allow(Double).to receive(:new) + double_collection = described_class.new(:klass) + + double_collection.register_proxy(:a_method) + + expect(Double). + to have_received(:new). + with(:klass, :a_method, :implementation) + end + end + + describe '#activate' do + it 'replaces all registered methods with doubles' do + klass = create_class(first_method: 1, second_method: 2) + double_collection = described_class.new(klass) + double_collection.register_stub(:first_method) + double_collection.register_stub(:second_method) + + double_collection.activate + + instance = klass.new + expect(instance.first_method).to eq nil + expect(instance.second_method).to eq nil + end + end + + describe '#deactivate' do + it 'restores the original methods that were doubled' do + klass = create_class(first_method: 1, second_method: 2) + double_collection = described_class.new(klass) + double_collection.register_stub(:first_method) + double_collection.register_stub(:second_method) + + double_collection.activate + double_collection.deactivate + + instance = klass.new + expect(instance.first_method).to eq 1 + expect(instance.second_method).to eq 2 + end + end + + describe '#calls_to' do + it 'returns all calls to the given method' do + klass = create_class(a_method: nil) + double_collection = described_class.new(klass) + double_collection.register_stub(:a_method) + double_collection.activate + + actual_calls = [ + { args: [:some, :args, :here] }, + { args: [:some, :args], block: -> { :whatever } } + ] + instance = klass.new + instance.a_method(*actual_calls[0][:args]) + instance.a_method(*actual_calls[1][:args], &actual_calls[1][:block]) + + calls = double_collection.calls_to(:a_method) + expect(calls[0].args).to eq actual_calls[0][:args] + expect(calls[1].args).to eq actual_calls[1][:args] + expect(calls[1].block).to eq actual_calls[1][:block] + end + + it 'returns an empty array if the method has never been doubled' do + klass = create_class + double_collection = described_class.new(klass) + expect(double_collection.calls_to(:non_existent_method)).to eq [] + end + end + + def create_class(methods = {}) + Class.new.tap do |klass| + methods.each do |name, value| + klass.__send__(:define_method, name) { |*args| value } + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,21 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe DoubleImplementationRegistry do + describe '.find' do + it 'returns an instance of StubImplementation if given :stub' do + expect(described_class.find(:stub)).to be_a(StubImplementation) + end + + it 'returns ProxyImplementation if given :proxy' do + expect(described_class.find(:proxy)).to be_a(ProxyImplementation) + end + + it 'raises an ArgumentError if not given a registered implementation' do + expect { + expect(described_class.find(:something_else)) + }.to raise_error(ArgumentError) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/double_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/double_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,154 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe Double do + describe '#to_return' do + it 'tells its implementation to call the given block' do + sent_block = -> { } + actual_block = nil + implementation = build_implementation + implementation.singleton_class.__send__(:undef_method, :returns) + implementation.singleton_class.__send__(:define_method, :returns) do |&block| + actual_block = block + end + double = described_class.new(:klass, :a_method, implementation) + double.to_return(&sent_block) + expect(actual_block).to eq sent_block + end + + it 'tells its implementation to return the given value' do + implementation = build_implementation + double = described_class.new(:klass, :a_method, implementation) + double.to_return(:implementation) + + expect(implementation).to have_received(:returns).with(:implementation) + end + + it 'prefers a block over a non-block' do + sent_block = -> { } + actual_block = nil + implementation = build_implementation + implementation.singleton_class.__send__(:undef_method, :returns) + implementation.singleton_class.__send__(:define_method, :returns) do |&block| + actual_block = block + end + double = described_class.new(:klass, :a_method, implementation) + double.to_return(:value, &sent_block) + expect(actual_block).to eq sent_block + end + end + + describe '#activate' do + it 'replaces the method with an implementation' do + implementation = build_implementation + klass = create_class(a_method: 42) + instance = klass.new + double = described_class.new(klass, :a_method, implementation) + args = [:any, :args] + block = -> {} + + double.activate + instance.a_method(*args, &block) + + expect(implementation). + to have_received(:call). + with(double, instance, args, block) + end + end + + describe '#deactivate' do + it 'restores the original method after being doubled' do + implementation = build_implementation + klass = create_class(a_method: 42) + instance = klass.new + double = described_class.new(klass, :a_method, implementation) + + double.activate + double.deactivate + expect(instance.a_method).to eq 42 + end + + it 'still restores the original method if #activate was called twice' do + implementation = build_implementation + klass = create_class(a_method: 42) + instance = klass.new + double = described_class.new(klass, :a_method, implementation) + + double.activate + double.activate + double.deactivate + expect(instance.a_method).to eq 42 + end + + it 'does nothing if the method has not been doubled' do + implementation = build_implementation + klass = create_class(a_method: 42) + instance = klass.new + double = described_class.new(klass, :a_method, implementation) + + double.deactivate + expect(instance.a_method).to eq 42 + end + end + + describe '#record_call' do + it 'stores the arguments and block given to the method in calls' do + double = described_class.new(:klass, :a_method, :implementation) + calls = [ + [:any, :args], :block, + [:more, :args] + ] + double.record_call(calls[0][0], calls[0][1]) + double.record_call(calls[1][0], nil) + + expect(double.calls[0].args).to eq calls[0][0] + expect(double.calls[0].block).to eq calls[0][1] + expect(double.calls[1].args).to eq calls[1][0] + end + end + + describe '#call_original_method' do + it 'binds the stored method object to the class and calls it with the given args and block' do + klass = create_class + instance = klass.new + actual_args = actual_block = method_called = nil + expected_args = [:one, :two, :three] + expected_block = -> { } + double = described_class.new(klass, :a_method, :implementation) + + klass.__send__(:define_method, :a_method) do |*args, &block| + actual_args = expected_args + actual_block = expected_block + method_called = true + end + + double.activate + double.call_original_method(instance, expected_args, expected_block) + + expect(expected_args).to eq actual_args + expect(expected_block).to eq actual_block + expect(method_called).to eq true + end + + it 'does nothing if no method has been stored' do + double = described_class.new(:klass, :a_method, :implementation) + + expect { + double.call_original_method(:instance, [:any, :args], nil) + }.not_to raise_error + end + end + + def create_class(methods = {}) + Class.new.tap do |klass| + methods.each do |name, value| + klass.__send__(:define_method, name) { |*args| value } + end + end + end + + def build_implementation + double('implementation', returns: nil, call: nil) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,77 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe ObjectDouble do + it 'responds to any method' do + double = described_class.new + + expect(double.respond_to?(:foo)).to be true + expect(double.respond_to?(:bar)).to be true + expect(double.respond_to?(:baz)).to be true + end + + it 'returns nil from any method call' do + double = described_class.new + + expect(double.foo).to be nil + expect(double.bar).to be nil + expect(double.baz).to be nil + end + + it 'records every method call' do + double = described_class.new + + block = -> { :some_return_value } + double.foo + double.bar(42) + double.baz(:zing, :zang, &block) + + expect(double.calls.size).to eq 3 + double.calls[0].tap do |call| + expect(call.args).to eq [] + expect(call.block).to eq nil + end + double.calls[1].tap do |call| + expect(call.args).to eq [42] + expect(call.block).to eq nil + end + double.calls[2].tap do |call| + expect(call.args).to eq [:zing, :zang] + expect(call.block).to eq block + end + end + + describe '#calls_to' do + it 'returns all of the invocations of the given method and their arguments/block' do + double = described_class.new + + block = -> { :some_return_value } + double.foo + double.foo(42) + double.foo(:zing, :zang, &block) + double.some_other_method(:doesnt_matter) + + calls = double.calls_to(:foo) + + expect(calls.size).to eq 3 + calls[0].tap do |call| + expect(call.args).to eq [] + expect(call.block).to eq nil + end + calls[1].tap do |call| + expect(call.args).to eq [42] + expect(call.block).to eq nil + end + calls[2].tap do |call| + expect(call.args).to eq [:zing, :zang] + expect(call.block).to eq block + end + end + + it 'returns an empty array if the given method was never called' do + double = described_class.new + expect(double.calls_to(:unknown_method)).to eq [] + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,47 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe ProxyImplementation do + describe '#returns' do + it 'delegates to its stub_implementation' do + stub_implementation = build_stub_implementation + implementation = described_class.new(stub_implementation) + implementation.returns(:value) + + expect(stub_implementation).to have_received(:returns).with(:value) + end + end + + describe '#call' do + it 'delegates to its stub_implementation' do + stub_implementation = build_stub_implementation + double = build_double + implementation = described_class.new(stub_implementation) + implementation.call(double, :object, :args, :block) + + expect(stub_implementation). + to have_received(:call). + with(double, :object, :args, :block) + end + + it 'calls #call_original_method on the double' do + stub_implementation = build_stub_implementation + implementation = described_class.new(stub_implementation) + double = build_double + implementation.call(double, :object, :args, :block) + + expect(double). + to have_received(:call_original_method). + with(:object, :args, :block) + end + end + + def build_stub_implementation + double('stub_implementation', returns: nil, call: nil) + end + + def build_double + double('double', call_original_method: nil) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,88 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe StubImplementation do + describe '#call' do + it 'calls #record_call on the double' do + implementation = described_class.new + double = build_double + + double.expects(:record_call).with(:args, :block) + + implementation.call(double, :object, :args, :block) + end + + context 'if no explicit implementation was set' do + it 'returns nil' do + implementation = described_class.new + double = build_double + + return_value = implementation.call(double, :object, :args, :block) + + expect(return_value).to eq nil + end + end + + context 'if the implementation was set as a value' do + it 'returns the set return value' do + implementation = described_class.new + implementation.returns(42) + double = build_double + + return_value = implementation.call(double, :object, :args, :block) + + expect(return_value).to eq 42 + end + end + + context 'if the implementation was set as a block' do + it 'calls the block with the object and args/block passed to the method' do + double = build_double + expected_object, expected_args, expected_block = :object, :args, :block + actual_object, actual_args, actual_block = [] + implementation = described_class.new + implementation.returns do |object, args, block| + actual_object, actual_args, actual_block = object, args, block + end + + implementation.call( + double, + expected_object, + expected_args, + expected_block + ) + + expect(actual_object).to eq expected_object + expect(actual_args).to eq expected_args + expect(actual_block).to eq expected_block + end + + it 'returns the return value of the block' do + implementation = described_class.new + implementation.returns { 42 } + double = build_double + + return_value = implementation.call(double, :object, :args, :block) + + expect(return_value).to eq 42 + end + end + + context 'if the implementation was set as both a value and a block' do + it 'prefers the block over the value' do + implementation = described_class.new + implementation.returns(:something_else) { 42 } + double = build_double + + return_value = implementation.call(double, :object, :args, :block) + + expect(return_value).to eq 42 + end + end + end + + def build_double + double('double', record_call: nil) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/world_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/world_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak/world_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak/world_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,77 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers::Doublespeak + describe World do + describe '#double_collection_for' do + it 'calls DoubleCollection.new once with the given class' do + allow(DoubleCollection).to receive(:new).and_return(:klass) + world = described_class.new + + world.double_collection_for(:klass) + world.double_collection_for(:klass) + + expect(DoubleCollection).to have_received(:new).with(:klass).once + end + + it 'returns the created DoubleCollection' do + double_collection = build_double_collection + allow(DoubleCollection). + to receive(:new). + with(:klass). + and_return(double_collection) + world = described_class.new + + expect(world.double_collection_for(:klass)).to be double_collection + end + end + + describe '#with_doubles_activated' do + it 'installs all doubles, yields the block, then uninstalls them all' do + block_called = false + double_collections = Array.new(3) { build_double_collection } + double_collections.each do |double_collection| + allow(double_collection).to receive(:activate).ordered + end + double_collections.each do |double_collection| + allow(double_collection).to receive(:deactivate).ordered + end + klasses = Array.new(3) { |i| "Klass #{i}" } + world = described_class.new + double_collections.zip(klasses).each do |double_collection, klass| + allow(DoubleCollection). + to receive(:new). + with(klass). + and_return(double_collection) + world.double_collection_for(klass) + end + + world.with_doubles_activated { block_called = true } + + expect(block_called).to eq true + + double_collections.each do |double_collection| + expect(double_collection).to have_received(:activate) + expect(double_collection).to have_received(:deactivate) + end + end + + it 'still makes sure to uninstall all doubles even if the block raises an error' do + double_collection = build_double_collection + allow(DoubleCollection).to receive(:new).and_return(double_collection) + world = described_class.new + world.double_collection_for(:klass) + + begin + world.with_doubles_activated { raise 'error' } + rescue RuntimeError + end + + expect(double_collection).to have_received(:deactivate) + end + end + + def build_double_collection + double('double_collection', activate: nil, deactivate: nil) + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/doublespeak_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/doublespeak_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,27 @@ +require 'unit_spec_helper' + +module Shoulda::Matchers + describe Doublespeak do + describe '.double_collection_for' do + it 'delegates to its world' do + allow(Doublespeak.world).to receive(:double_collection_for) + + described_class.double_collection_for(:klass) + + expect(Doublespeak.world). + to have_received(:double_collection_for). + with(:klass) + end + end + + describe '.with_doubles_activated' do + it 'delegates to its world' do + allow(Doublespeak.world).to receive(:with_doubles_activated) + + described_class.with_doubles_activated + + expect(Doublespeak.world).to have_received(:with_doubles_activated) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/independent/delegate_method_matcher/stubbed_target_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,43 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::Independent::DelegateMethodMatcher::StubbedTarget do + subject(:target) { described_class.new(:stubbed_method) } + + describe '#has_received_method?' do + it 'returns true when the method has been called on the target' do + target.stubbed_method + + expect(target).to have_received_method + end + + it 'returns false when the method has not been called on the target' do + expect(target).not_to have_received_method + end + end + + describe '#has_received_arguments?' do + context 'method is called with specified arguments' do + it 'returns true' do + target.stubbed_method(:arg1, :arg2) + + expect(target).to have_received_arguments(:arg1, :arg2) + end + end + + context 'method is not called with specified arguments' do + it 'returns false' do + target.stubbed_method + + expect(target).not_to have_received_arguments(:arg1) + end + end + + context 'method is called with arguments in incorrect order' do + it 'returns false' do + target.stubbed_method(:arg2, :arg1) + + expect(target).not_to have_received_arguments(:arg1, :arg2) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit/shoulda/matchers/independent/delegate_method_matcher_spec.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,517 @@ +require 'unit_spec_helper' + +describe Shoulda::Matchers::Independent::DelegateMethodMatcher do + describe '#description' do + context 'when the subject is an instance' do + subject { Object.new } + + context 'without any qualifiers' do + it 'states that it should delegate method to the right object' do + matcher = delegate_method(:method_name).to(:delegate) + message = 'delegate #method_name to #delegate object' + + expect(matcher.description).to eq message + end + end + + context 'qualified with #as' do + it 'states that it should delegate method to the right object and method' do + matcher = delegate_method(:method_name).to(:delegate).as(:alternate) + message = 'delegate #method_name to #delegate object as #alternate' + + expect(matcher.description).to eq message + end + end + + context 'qualified with #with_arguments' do + it 'states that it should delegate method to the right object with right argument' do + matcher = delegate_method(:method_name).to(:delegate). + with_arguments(:foo, bar: [1, 2]) + message = 'delegate #method_name to #delegate object passing arguments [:foo, {:bar=>[1, 2]}]' + + expect(matcher.description).to eq message + end + end + + context 'qualified with #with_prefix' do + context 'without arguments' do + before do + define_model('Country') do + def hello; 'hello' end + end + end + + context "when the subject's delegating method also has a prefix" do + it 'produces the correct description' do + define_class('Person') do + delegate :hello, to: :country, prefix: true + + def country + Country.new + end + end + + matcher = delegate_method(:hello).to(:country).with_prefix + expect(matcher.description). + to eq('delegate #country_hello to #country object as #hello') + end + end + end + + context 'as true' do + before do + define_model('Country') do + def hello; 'hello' end + end + end + + context "when the subject's delegating method also has a prefix" do + it 'produces the correct description' do + define_class('Person') do + delegate :hello, to: :country, prefix: true + + def country + Country.new + end + end + + matcher = delegate_method(:hello).to(:country).with_prefix(true) + expect(matcher.description). + to eq('delegate #country_hello to #country object as #hello') + end + end + end + + context 'as a symbol/string' do + it 'should delegate as (prefix_supplied)_(method_on_target)' do + define_model('Country') do + def hello; 'hello' end + end + + define_class('Person') do + delegate :hello, to: :country, prefix: 'county' + + def country + Country.new + end + end + + matcher = delegate_method(:hello).to(:country).with_prefix('county') + expect(matcher.description). + to eq('delegate #county_hello to #country object as #hello') + end + end + end + end + + context 'when the subject is a class' do + subject { Object } + + context 'without any qualifiers' do + it 'states that it should delegate method to the right object' do + matcher = delegate_method(:method_name).to(:delegate) + + expect(matcher.description). + to eq 'delegate .method_name to .delegate object' + end + end + + context 'qualified with #as' do + it 'states that it should delegate method to the right object and method' do + matcher = delegate_method(:method_name).to(:delegate).as(:alternate) + message = 'delegate .method_name to .delegate object as .alternate' + + expect(matcher.description).to eq message + end + end + + context 'qualified with #with_arguments' do + it 'states that it should delegate method to the right object with right argument' do + matcher = delegate_method(:method_name).to(:delegate). + with_arguments(:foo, bar: [1, 2]) + message = 'delegate .method_name to .delegate object passing arguments [:foo, {:bar=>[1, 2]}]' + + expect(matcher.description).to eq message + end + end + end + end + + it 'raises an error if the delegate object was never specified before matching' do + expect { + expect(Object.new).to delegate_method(:name) + }.to raise_error described_class::DelegateObjectNotSpecified + end + + context 'stubbing a delegating method on an instance' do + it 'only happens temporarily and is removed after the match' do + define_class('Company') do + def name + 'Acme Company' + end + end + + define_class('Person') do + def company_name + company.name + end + + def company + Company.new + end + end + + person = Person.new + matcher = delegate_method(:company_name).to(:company).as(:name) + matcher.matches?(person) + + expect(person.company.name).to eq 'Acme Company' + end + end + + context 'when the subject does not delegate anything' do + before do + define_class('PostOffice') + end + + context 'when the subject is an instance' do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = [ + 'Expected PostOffice to delegate #deliver_mail to #mailman object', + 'Method calls sent to PostOffice#mailman: (none)' + ].join("\n") + + expect { + expect(post_office).to delegate_method(:deliver_mail).to(:mailman) + }.to fail_with_message(message) + end + end + + context 'when the subject is a class' do + it 'uses the proper syntax for class methods in errors' do + message = [ + 'Expected PostOffice to delegate .deliver_mail to .mailman object', + 'Method calls sent to PostOffice.mailman: (none)' + ].join("\n") + + expect { + expect(PostOffice).to delegate_method(:deliver_mail).to(:mailman) + }.to fail_with_message(message) + end + end + end + + context 'when the subject delegates correctly' do + before do + define_class('Mailman') + + define_class('PostOffice') do + def deliver_mail + mailman.deliver_mail + end + + def mailman + Mailman.new + end + end + end + + it 'accepts' do + post_office = PostOffice.new + expect(post_office).to delegate_method(:deliver_mail).to(:mailman) + end + + context 'negating the matcher' do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = 'Expected PostOffice not to delegate #deliver_mail to #mailman object, but it did' + + expect { + expect(post_office).not_to delegate_method(:deliver_mail).to(:mailman) + }.to fail_with_message(message) + end + end + end + + context 'when the delegating method is private' do + before do + define_class('Mailman') + + define_class('PostOffice') do + def deliver_mail + mailman.deliver_mail + end + + def mailman + Mailman.new + end + + private :mailman + end + end + + it 'accepts' do + post_office = PostOffice.new + expect(post_office).to delegate_method(:deliver_mail).to(:mailman) + end + end + + context 'qualified with #with_arguments' do + before do + define_class('Mailman') + + define_class('PostOffice') do + def deliver_mail(*args) + mailman.deliver_mail('221B Baker St.', hastily: true) + end + + def mailman + Mailman.new + end + end + end + + context 'qualified with #with_arguments' do + context 'when the subject delegates with matching arguments' do + it 'accepts' do + post_office = PostOffice.new + expect(post_office).to delegate_method(:deliver_mail). + to(:mailman).with_arguments('221B Baker St.', hastily: true) + end + + context 'negating the matcher' do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = 'Expected PostOffice not to delegate #deliver_mail to #mailman object passing arguments ["221B Baker St.", {:hastily=>true}], but it did' + + expect { + expect(post_office). + not_to delegate_method(:deliver_mail). + to(:mailman). + with_arguments('221B Baker St.', hastily: true) + }.to fail_with_message(message) + end + end + end + + context 'when not given the correct arguments' do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = [ + 'Expected PostOffice to delegate #deliver_mail to #mailman object passing arguments ["123 Nowhere Ln."]', + 'Method calls sent to PostOffice#mailman:', + '1) deliver_mail("221B Baker St.", {:hastily=>true})' + ].join("\n") + + expect { + expect(post_office).to delegate_method(:deliver_mail). + to(:mailman).with_arguments('123 Nowhere Ln.') + }.to fail_with_message(message) + end + end + end + end + + context 'qualified with #as' do + before do + define_class(:mailman) + + define_class(:post_office) do + def deliver_mail + mailman.deliver_mail_and_avoid_dogs + end + + def mailman + Mailman.new + end + end + end + + context "when the given method is the same as the subject's delegating method" do + it 'accepts' do + post_office = PostOffice.new + expect(post_office).to delegate_method(:deliver_mail). + to(:mailman).as(:deliver_mail_and_avoid_dogs) + end + + context 'negating the assertion' do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = 'Expected PostOffice not to delegate #deliver_mail to #mailman object as #deliver_mail_and_avoid_dogs, but it did' + + expect { + expect(post_office). + not_to delegate_method(:deliver_mail). + to(:mailman). + as(:deliver_mail_and_avoid_dogs) + }.to fail_with_message(message) + end + end + end + + context "when the given method is not the same as the subject's delegating method" do + it 'rejects with the correct failure message' do + post_office = PostOffice.new + message = [ + 'Expected PostOffice to delegate #deliver_mail to #mailman object as #watch_tv', + 'Method calls sent to PostOffice#mailman:', + '1) deliver_mail_and_avoid_dogs()' + ].join("\n") + + expect { + expect(post_office).to delegate_method(:deliver_mail). + to(:mailman).as(:watch_tv) + }.to fail_with_message(message) + end + end + end + + context 'qualified with #with_prefix' do + context 'without arguments' do + before do + define_model('Country') do + def hello; 'hello' end + end + end + + context "when the subject's delegating method also has a prefix" do + it 'accepts' do + define_class('Person') do + delegate :hello, to: :country, prefix: true + + def country + Country.new + end + end + + person = Person.new + expect(person).to delegate_method(:hello). to(:country).with_prefix + end + end + + context "when the subject's delegating method does not have a prefix" do + it 'rejects with the correct failure message' do + define_class('Person') do + delegate :hello, to: :country + + def country + Country.new + end + end + + message = [ + 'Expected Person to delegate #country_hello to #country object as #hello', + 'Method calls sent to Person#country: (none)' + ].join("\n") + + person = Person.new + + expect { + expect(person).to delegate_method(:hello). to(:country).with_prefix + }.to fail_with_message(message) + end + end + end + + context 'as true' do + before do + define_model('Country') do + def hello; 'hello' end + end + end + + context "when the subject's delegating method also has a prefix" do + it 'accepts' do + define_class('Person') do + delegate :hello, to: :country, prefix: true + + def country + Country.new + end + end + + person = Person.new + expect(person). + to delegate_method(:hello). + to(:country).with_prefix(true) + end + end + + context "when the subject's delegating method does not have a prefix" do + it 'rejects with the correct failure message' do + define_class('Person') do + delegate :hello, to: :country + + def country + Country.new + end + end + + message = [ + 'Expected Person to delegate #country_hello to #country object as #hello', + 'Method calls sent to Person#country: (none)' + ].join("\n") + + person = Person.new + + expect { + expect(person). + to delegate_method(:hello). + to(:country).with_prefix(true) + }.to fail_with_message(message) + end + end + end + + context 'as a symbol/string' do + before do + define_model('Country') do + def hello; 'hello' end + end + end + + context "when the subject's delegating method has the same prefix" do + it 'accepts' do + define_class('Person') do + delegate :hello, to: :country, prefix: 'county' + + def country + Country.new + end + end + + person = Person.new + expect(person). + to delegate_method(:hello). + to(:country).with_prefix('county') + end + end + + context "when the subject's delegating method has a different prefix" do + it 'rejects with the correct failure message' do + define_class('Person') do + delegate :hello, to: :country, prefix: 'something_else' + + def country + Country.new + end + end + + message = [ + 'Expected Person to delegate #county_hello to #country object as #hello', + 'Method calls sent to Person#country: (none)' + ].join("\n") + + person = Person.new + + expect { + expect(person). + to delegate_method(:hello). + to(:country).with_prefix('county') + }.to fail_with_message(message) + end + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/unit_spec_helper.rb ruby-shoulda-matchers-2.8.0/spec/unit_spec_helper.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/unit_spec_helper.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/unit_spec_helper.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,68 @@ +require File.expand_path('../support/unit/rails_application', __FILE__) + +def monkey_patch_minitest_to_do_nothing + # Rails 3.1's test_help file requires Turn, which loads Minitest in autorun + # mode. This means that Minitest tests will run after these RSpec tests are + # finished running. This will break on CI since we pass --color to the `rspec` + # command. + + if defined?(MiniTest) + MiniTest::Unit.class_eval do + def run(*); end + end + end +end + +$test_app = UnitTests::RailsApplication.new +$test_app.create +$test_app.load + +monkey_patch_minitest_to_do_nothing + +ENV['BUNDLE_GEMFILE'] ||= app.gemfile_path +ENV['RAILS_ENV'] = 'test' + +require 'rspec/rails' +require 'shoulda-matchers' + +PROJECT_ROOT = File.expand_path('../..', __FILE__) +$LOAD_PATH << File.join(PROJECT_ROOT, 'lib') + +Dir[ File.join(File.expand_path('../support/unit/**/*.rb', __FILE__)) ].sort.each do |file| + require file +end + +RSpec.configure do |config| + config.order = :random + + config.expect_with :rspec do |c| + c.syntax = :expect + end + + config.mock_with :rspec + + if config.respond_to?(:infer_spec_type_from_file_location!) + config.infer_spec_type_from_file_location! + end + + config.before(:all, type: :controller) do + self.class.controller(ApplicationController) { } + end + + UnitTests::ActiveModelHelpers.configure_example_group(config) + UnitTests::ActiveModelVersions.configure_example_group(config) + UnitTests::ActiveResourceBuilder.configure_example_group(config) + UnitTests::ClassBuilder.configure_example_group(config) + UnitTests::ControllerBuilder.configure_example_group(config) + UnitTests::I18nFaker.configure_example_group(config) + UnitTests::MailerBuilder.configure_example_group(config) + UnitTests::ModelBuilder.configure_example_group(config) + UnitTests::RailsVersions.configure_example_group(config) + UnitTests::ActiveRecordVersions.configure_example_group(config) + UnitTests::ActiveModelVersions.configure_example_group(config) + + config.include UnitTests::Matchers +end + +ActiveSupport::Deprecation.behavior = :stderr +$VERBOSE = true diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/filesystem.rb ruby-shoulda-matchers-2.8.0/spec/warnings_spy/filesystem.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/filesystem.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/warnings_spy/filesystem.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,45 @@ +require 'fileutils' + +class WarningsSpy + class Filesystem + PROJECT_DIR = File.expand_path('../../..', __FILE__) + TEMP_DIR = File.join(PROJECT_DIR, 'tmp') + + def initialize + @files_by_name = Hash.new do |hash, name| + FileUtils.mkdir_p(TEMP_DIR) + hash[name] = file_for(name) + end + end + + def warnings_file + files_by_name['all_warnings'] + end + + def irrelevant_warnings_file + files_by_name['irrelevant_warnings'] + end + + def relevant_warnings_file + files_by_name['relevant_warnings'] + end + + def project_dir + PROJECT_DIR + end + + protected + + attr_reader :files_by_name + + private + + def path_for(name) + File.join(TEMP_DIR, "#{name}.txt") + end + + def file_for(name) + File.open(path_for(name), 'w+') + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/partitioner.rb ruby-shoulda-matchers-2.8.0/spec/warnings_spy/partitioner.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/partitioner.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/warnings_spy/partitioner.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,36 @@ +require 'forwardable' + +class WarningsSpy + class Partitioner + extend Forwardable + + attr_reader :relevant_warning_groups, :irrelevant_warning_groups + + def initialize(reader, filesystem) + @reader = reader + @search_text = filesystem.project_dir + end + + def partition + @relevant_warning_groups, @irrelevant_warning_groups = + warning_groups.partition { |group| relevant_warnings?(group) } + end + + protected + + attr_reader :reader, :search_text + + private + + def_delegators :reader, :warning_groups + + def relevant_warnings?(group) + first_line = group[0] + first_line.start_with?("#{project_root}/lib") + end + + def project_root + File.expand_path('../../..') + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/reader.rb ruby-shoulda-matchers-2.8.0/spec/warnings_spy/reader.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/reader.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/warnings_spy/reader.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,53 @@ +class WarningsSpy + class Reader + attr_reader :warning_groups + + def initialize(filesystem) + @warnings_file = filesystem.warnings_file + + @current_group = [] + @warning_groups = [] + end + + def read + warnings_file.rewind + + warnings_file.each_line do |line| + process_line(line) + end + + add_group(current_group) + end + + protected + + attr_reader :warnings_file, :current_group + + private + + def process_line(line) + if start_of_group?(line) + add_group(current_group) + @current_group = [] + end + + current_group << line + end + + def start_of_group?(line) + line =~ /^\S/ + end + + def add_group(group) + unless group.empty? || group_already_added?(group) + warning_groups << group + end + end + + def group_already_added?(group_to_be_added) + warning_groups.any? do |group| + group == group_to_be_added + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/reporter.rb ruby-shoulda-matchers-2.8.0/spec/warnings_spy/reporter.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy/reporter.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/warnings_spy/reporter.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,88 @@ +require 'forwardable' + +class WarningsSpy + class Reporter + extend Forwardable + + def initialize(partitioner, filesystem, project_name) + @partitioner = partitioner + @warnings_file = filesystem.warnings_file + @relevant_warnings_file = filesystem.relevant_warnings_file + @irrelevant_warnings_file = filesystem.irrelevant_warnings_file + @project_name = project_name + end + + def report + reporting_all_groups do + report_relevant_warning_groups + report_irrelevant_warning_groups + end + end + + protected + + attr_reader :partitioner, :warnings_file, :relevant_warnings_file, + :irrelevant_warnings_file, :project_name + + private + + def_delegators :partitioner, :relevant_warning_groups, + :irrelevant_warning_groups + + def report_relevant_warning_groups + if relevant_warning_groups.any? + print_divider('-', 75, header: " #{project_name} warnings:") + relevant_warning_groups.each do |group| + group.each do |line| + relevant_warnings_file.puts(line) + puts line + end + end + print_divider('-', 75) + puts "#{project_name} warnings written to #{relevant_warnings_file.path}." + end + end + + def report_irrelevant_warning_groups + if irrelevant_warning_groups.any? + irrelevant_warning_groups.each do |group| + group.each do |line| + irrelevant_warnings_file.puts(line) + end + end + puts "Non #{project_name} warnings were raised during the test run. These have been written to #{irrelevant_warnings_file.path}." + end + end + + def reporting_all_groups + if relevant_warning_groups.any? || irrelevant_warning_groups.any? + puts + yield + puts "All warnings were written to #{warnings_file.path}." + puts + end + end + + def print_divider(character, count, options = {}) + puts + + if options[:header] + first_count = 10 + second_count = options[:header].length - first_count + string = + horizontal_rule(character, first_count) + + options[:header] + + horizontal_rule(character, second_count) + puts string + else + puts horizontal_rule(character, count) + end + + puts + end + + def horizontal_rule(character, count) + character * count + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy.rb ruby-shoulda-matchers-2.8.0/spec/warnings_spy.rb --- ruby-shoulda-matchers-1.0.0~beta2/spec/warnings_spy.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/spec/warnings_spy.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,64 @@ +require 'forwardable' + +require File.expand_path('../warnings_spy/filesystem', __FILE__) +require File.expand_path('../warnings_spy/reader', __FILE__) +require File.expand_path('../warnings_spy/partitioner', __FILE__) +require File.expand_path('../warnings_spy/reporter', __FILE__) + +class WarningsSpy + extend Forwardable + + def initialize(project_name) + filesystem = Filesystem.new + @warnings_file = filesystem.warnings_file + @reader = Reader.new(filesystem) + @partitioner = Partitioner.new(reader, filesystem) + @reporter = Reporter.new(partitioner, filesystem, project_name) + end + + def capture_warnings + $stderr.reopen(warnings_file.path) + end + + def report_warnings_at_exit + at_exit do + printing_exceptions do + report_and_exit + end + end + end + + protected + + attr_reader :warnings_file, :reader, :partitioner, :reporter + + private + + def_delegators :partitioner, :relevant_warning_groups, + :irrelevant_warning_groups + + def report_and_exit + reader.read + partitioner.partition + reporter.report + #fail_build_if_there_are_any_warnings + end + + def fail_build_if_there_are_any_warnings + if relevant_warning_groups.any? + exit(1) + end + end + + def printing_exceptions + begin + yield + rescue => error + puts "\n--- ERROR IN AT_EXIT --------------------------------" + puts "#{error.class}: #{error.message}" + puts error.backtrace.join("\n") + puts "-----------------------------------------------------" + raise error + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/tasks/documentation.rb ruby-shoulda-matchers-2.8.0/tasks/documentation.rb --- ruby-shoulda-matchers-1.0.0~beta2/tasks/documentation.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/tasks/documentation.rb 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,171 @@ +require_relative '../lib/shoulda/matchers/version' +require 'erb' + +module Shoulda + module Matchers + module DocumentationTasks + extend Rake::DSL + + def self.create + publisher = DocumentationPublisher.new + + namespace :docs do + file DocumentationPublisher.gh_pages_dir do + publisher.create_reference_to_gh_pages_branch + end + + file DocumentationPublisher.docs_dir => DocumentationPublisher.gh_pages_dir + + task :setup => DocumentationPublisher.docs_dir do + publisher.reset_repo_directory + end + + desc 'Generate docs for a particular version' + task :generate, [:version, :latest_version] => :setup do |t, args| + unless args.version + raise ArgumentError, "Missing version" + end + + unless args.latest_version + raise ArgumentError, "Missing latest_version" + end + + publisher.generate_docs_for(args.version, latest_version: args.latest_version) + end + + desc 'Generate docs for a particular version and push them to GitHub' + task :publish, [:version, :latest_version] => :setup do |t, args| + unless args.version + raise ArgumentError, "Missing version" + end + + unless args.latest_version + raise ArgumentError, "Missing latest_version" + end + + publisher.generate_docs_for(args.version, latest_version: args.latest_version) + publisher.publish_docs_for(args.version, latest_version: args.latest_version) + end + + desc "Generate docs for version #{DocumentationPublisher.current_version} and push them to GitHub" + task :publish_latest => :setup do + publisher.publish_latest_version + end + end + end + end + + class DocumentationPublisher + CURRENT_VERSION = Shoulda::Matchers::VERSION + GITHUB_USERNAME = 'thoughtbot' + # GITHUB_USERNAME = 'mcmire' + GH_PAGES_DIR = ".#{GITHUB_USERNAME}-gh-pages" + DOCS_DIR = "#{GH_PAGES_DIR}/docs" + + def self.current_version + CURRENT_VERSION + end + + def self.gh_pages_dir + GH_PAGES_DIR + end + + def self.docs_dir + DOCS_DIR + end + + def create_reference_to_gh_pages_branch + system "git clone git@github.com:#{GITHUB_USERNAME}/shoulda-matchers.git #{GH_PAGES_DIR} --branch gh-pages" + end + + def reset_repo_directory + within_gh_pages_dir do + system 'git fetch origin' + system 'git reset --hard origin/gh-pages' + end + end + + def generate_docs_for(version, options = {}) + ref = determine_ref_from(version) + + system "rm -rf #{DOCS_DIR}/#{ref}" + system "bundle exec yard -o #{DOCS_DIR}/#{ref}" + + add_version_to_index_page_for(ref, version) + + within_docs_dir do + system "git add #{ref}" + end + + if options[:latest_version] + generate_file_that_redirects_to_latest_version(options[:latest_version]) + end + end + + def publish_docs_for(version, options = {}) + message = build_commit_message(version) + + within_gh_pages_dir do + system 'git clean -f' + system "git commit -m '#{message}'" + system 'git push origin gh-pages' + end + end + + def publish_latest_version + version = Gem::Version.new(CURRENT_VERSION) + options = {} + + unless version.prerelease? + options[:latest_version] = version.to_s + end + + generate_docs_for(CURRENT_VERSION, options) + publish_docs_for(CURRENT_VERSION, options) + end + + private + + def add_version_to_index_page_for(ref, version) + within_docs_dir do + filename = "#{ref}/index.html" + content = File.read(filename) + content.sub!(%r{

    shoulda-matchers.+

    }, "

    shoulda-matchers (#{version})

    ") + File.open(filename, 'w') {|f| f.write(content) } + end + end + + def generate_file_that_redirects_to_latest_version(version) + ref = determine_ref_from(version) + locals = { ref: ref, github_username: GITHUB_USERNAME } + + erb = ERB.new(File.read('doc_config/gh-pages/index.html.erb')) + + within_docs_dir do + File.open('index.html', 'w') { |f| f.write(erb.result(binding)) } + system 'git add index.html' + end + end + + def determine_ref_from(version) + if version =~ /^\d+\.\d+\.\d+/ + 'v' + version + else + version + end + end + + def build_commit_message(version) + "Regenerated docs for version #{version}" + end + + def within_gh_pages_dir(&block) + Dir.chdir(GH_PAGES_DIR, &block) + end + + def within_docs_dir(&block) + Dir.chdir(DOCS_DIR, &block) + end + end + end +end diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.travis.yml ruby-shoulda-matchers-2.8.0/.travis.yml --- ruby-shoulda-matchers-1.0.0~beta2/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.travis.yml 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,62 @@ +language: ruby +sudo: false +script: "bundle exec rake" + +branches: + except: + - site + - gh-pages + +rvm: + - 1.9.2 + - 1.9.3 + +gemfile: + - gemfiles/3.0.gemfile + - gemfiles/3.1.gemfile + - gemfiles/3.2.gemfile + +matrix: + allow_failures: + - rvm: rbx-19mode + - rvm: jruby-19mode + include: + - rvm: 1.9.2 + gemfile: gemfiles/3.1_1.9.2.gemfile + - rvm: 1.9.2 + gemfile: gemfiles/3.2_1.9.2.gemfile + - rvm: 1.9.3 + gemfile: gemfiles/4.0.0.gemfile + - rvm: 1.9.3 + gemfile: gemfiles/4.0.1.gemfile + - rvm: 1.9.3 + gemfile: gemfiles/4.1.gemfile + - rvm: 2.0.0 + gemfile: gemfiles/3.2.gemfile + - rvm: 2.0.0 + gemfile: gemfiles/4.0.0.gemfile + - rvm: 2.0.0 + gemfile: gemfiles/4.0.1.gemfile + - rvm: 2.0.0 + gemfile: gemfiles/4.1.gemfile + - rvm: 2.0.0 + gemfile: gemfiles/4.2.gemfile + - rvm: 2.1.4 + gemfile: gemfiles/3.2.gemfile + - rvm: 2.1.4 + gemfile: gemfiles/4.0.0.gemfile + - rvm: 2.1.4 + gemfile: gemfiles/4.0.1.gemfile + - rvm: 2.1.4 + gemfile: gemfiles/4.1.gemfile + - rvm: 2.1.4 + gemfile: gemfiles/4.2.gemfile + - rvm: rbx-19mode + gemfile: gemfiles/3.2.gemfile + - rvm: jruby-19mode + gemfile: gemfiles/3.2.gemfile + exclude: + - rvm: 1.9.2 + gemfile: gemfiles/3.1.gemfile + - rvm: 1.9.2 + gemfile: gemfiles/3.2.gemfile diff -Nru ruby-shoulda-matchers-1.0.0~beta2/.yardopts ruby-shoulda-matchers-2.8.0/.yardopts --- ruby-shoulda-matchers-1.0.0~beta2/.yardopts 1970-01-01 00:00:00.000000000 +0000 +++ ruby-shoulda-matchers-2.8.0/.yardopts 2015-02-25 02:12:36.000000000 +0000 @@ -0,0 +1,8 @@ +--no-private +--protected +--readme README.md +--files NEWS.md +--markup markdown +--hide-tag return +--hide-tag param +-e ./doc_config/yard/setup.rb