From eefbbb2a51563f01cbc925db8c61704143f64f9d Mon Sep 17 00:00:00 2001 From: Pedro Paiva Date: Sat, 17 Sep 2022 11:04:45 -0300 Subject: [PATCH] Regenerated docs for version 5.2.0 --- docs/index.html | 2 +- docs/v5.2.0/Shoulda.html | 133 + docs/v5.2.0/Shoulda/Matchers.html | 139 + .../Shoulda/Matchers/ActionController.html | 1849 +++++ docs/v5.2.0/Shoulda/Matchers/ActiveModel.html | 2524 +++++++ .../v5.2.0/Shoulda/Matchers/ActiveRecord.html | 3082 +++++++++ docs/v5.2.0/Shoulda/Matchers/Independent.html | 383 ++ docs/v5.2.0/_index.html | 200 + docs/v5.2.0/class_list.html | 37 + docs/v5.2.0/css/bootstrap.css | 5967 +++++++++++++++++ docs/v5.2.0/css/common.css | 1 + docs/v5.2.0/css/full_list.css | 12 + docs/v5.2.0/css/global.css | 68 + docs/v5.2.0/css/solarized.css | 69 + docs/v5.2.0/css/style.css | 312 + docs/v5.2.0/file.CHANGELOG.html | 1392 ++++ .../file.NonCaseSwappableValueError.html | 217 + docs/v5.2.0/file.README.html | 592 ++ docs/v5.2.0/file_list.html | 53 + docs/v5.2.0/frames.html | 17 + docs/v5.2.0/index.html | 592 ++ docs/v5.2.0/js/app.js | 281 + docs/v5.2.0/js/full_list.js | 1 + docs/v5.2.0/js/jquery.js | 4 + docs/v5.2.0/js/jquery.stickyheaders.js | 289 + docs/v5.2.0/js/underscore.min.js | 6 + docs/v5.2.0/method_list.html | 278 + docs/v5.2.0/top-level-namespace.html | 133 + 28 files changed, 18632 insertions(+), 1 deletion(-) create mode 100644 docs/v5.2.0/Shoulda.html create mode 100644 docs/v5.2.0/Shoulda/Matchers.html create mode 100644 docs/v5.2.0/Shoulda/Matchers/ActionController.html create mode 100644 docs/v5.2.0/Shoulda/Matchers/ActiveModel.html create mode 100644 docs/v5.2.0/Shoulda/Matchers/ActiveRecord.html create mode 100644 docs/v5.2.0/Shoulda/Matchers/Independent.html create mode 100644 docs/v5.2.0/_index.html create mode 100644 docs/v5.2.0/class_list.html create mode 100644 docs/v5.2.0/css/bootstrap.css create mode 100644 docs/v5.2.0/css/common.css create mode 100644 docs/v5.2.0/css/full_list.css create mode 100644 docs/v5.2.0/css/global.css create mode 100644 docs/v5.2.0/css/solarized.css create mode 100644 docs/v5.2.0/css/style.css create mode 100644 docs/v5.2.0/file.CHANGELOG.html create mode 100644 docs/v5.2.0/file.NonCaseSwappableValueError.html create mode 100644 docs/v5.2.0/file.README.html create mode 100644 docs/v5.2.0/file_list.html create mode 100644 docs/v5.2.0/frames.html create mode 100644 docs/v5.2.0/index.html create mode 100644 docs/v5.2.0/js/app.js create mode 100644 docs/v5.2.0/js/full_list.js create mode 100644 docs/v5.2.0/js/jquery.js create mode 100644 docs/v5.2.0/js/jquery.stickyheaders.js create mode 100644 docs/v5.2.0/js/underscore.min.js create mode 100644 docs/v5.2.0/method_list.html create mode 100644 docs/v5.2.0/top-level-namespace.html diff --git a/docs/index.html b/docs/index.html index 4da068df..f7d470b1 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,7 +2,7 @@ shoulda-matchers Documentation - latest - + diff --git a/docs/v5.2.0/Shoulda.html b/docs/v5.2.0/Shoulda.html new file mode 100644 index 00000000..c5a4487c --- /dev/null +++ b/docs/v5.2.0/Shoulda.html @@ -0,0 +1,133 @@ + + + + + + + Module: Shoulda + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda + + + +

+ +
+ + + + + + + +
+

Defined Under Namespace

+

+ + + Modules: Matchers + + + + +

+ + + + + + + + + +
+ + + +
+ + + diff --git a/docs/v5.2.0/Shoulda/Matchers.html b/docs/v5.2.0/Shoulda/Matchers.html new file mode 100644 index 00000000..ebc8015c --- /dev/null +++ b/docs/v5.2.0/Shoulda/Matchers.html @@ -0,0 +1,139 @@ + + + + + + + Module: Shoulda::Matchers + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda::Matchers + + + +

+ +
+ + + + + + + +
+

Defined Under Namespace

+

+ + + Modules: ActionController, ActiveModel, ActiveRecord, Independent + + + + +

+ + + + + + + + + + + + + + + +
+ + + +
+ + + diff --git a/docs/v5.2.0/Shoulda/Matchers/ActionController.html b/docs/v5.2.0/Shoulda/Matchers/ActionController.html new file mode 100644 index 00000000..7100f8b7 --- /dev/null +++ b/docs/v5.2.0/Shoulda/Matchers/ActionController.html @@ -0,0 +1,1849 @@ + + + + + + + Module: Shoulda::Matchers::ActionController + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda::Matchers::ActionController + + + +

+ +
+ + + + + + + +
+

Overview

+
+

This module provides matchers that are used to test behavior within +controllers.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #filter_param(key) ⇒ FilterParamMatcher + + + + + +

+
+

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
+RSpec.describe ApplicationController, type: :controller do
+  it { should filter_param(:secret_key) }
+end
+
+# Minitest (Shoulda)
+class ApplicationControllerTest < ActionController::TestCase
+  should filter_param(:secret_key)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+24
+25
+26
+
+
# File 'lib/shoulda/matchers/action_controller/filter_param_matcher.rb', line 24
+
+def filter_param(key)
+  FilterParamMatcher.new(key)
+end
+
+ +
+ +
+

+ + #permit(*params) ⇒ PermitMatcher + + + + + +

+
+

The permit matcher tests that an action in your controller receives a +whitelist of parameters using Rails' Strong Parameters feature +(specifically that permit was called with the correct arguments).

+ +

Here's an example:

+ +
class UsersController < ApplicationController
+  def create
+    user = User.create(user_params)
+    # ...
+  end
+
+  private
+
+  def user_params
+    params.require(:user).permit(
+      :first_name,
+      :last_name,
+      :email,
+      :password
+    )
+  end
+end
+
+# RSpec
+RSpec.describe UsersController, type: :controller do
+  it do
+    params = {
+      user: {
+        first_name: 'John',
+        last_name: 'Doe',
+        email: 'johndoe@example.com',
+        password: 'password'
+      }
+    }
+    should permit(:first_name, :last_name, :email, :password).
+      for(:create, params: params).
+      on(:user)
+  end
+end
+
+# Minitest (Shoulda)
+class UsersControllerTest < ActionController::TestCase
+  should "(for POST #create) restrict parameters on :user to first_name, last_name, email, and password" do
+    params = {
+      user: {
+        first_name: 'John',
+        last_name: 'Doe',
+        email: 'johndoe@example.com',
+        password: 'password'
+      }
+    }
+    matcher = permit(:first_name, :last_name, :email, :password).
+      for(:create, params: params).
+      on(:user)
+    assert_accepts matcher, subject
+  end
+end
+
+ +

If your action requires query parameters in order to work, then you'll +need to supply them:

+ +
class UsersController < ApplicationController
+  def update
+    user = User.find(params[:id])
+
+    if user.update_attributes(user_params)
+      # ...
+    else
+      # ...
+    end
+  end
+
+  private
+
+  def user_params
+    params.require(:user).permit(
+      :first_name,
+      :last_name,
+      :email,
+      :password
+    )
+  end
+end
+
+# RSpec
+RSpec.describe UsersController, type: :controller do
+  before do
+    create(:user, id: 1)
+  end
+
+  it do
+    params = {
+      id: 1,
+      user: {
+        first_name: 'Jon',
+        last_name: 'Doe',
+        email: 'jondoe@example.com',
+        password: 'password'
+      }
+    }
+    should permit(:first_name, :last_name, :email, :password).
+      for(:update, params: params).
+      on(:user)
+  end
+end
+
+# Minitest (Shoulda)
+class UsersControllerTest < ActionController::TestCase
+  setup do
+    create(:user, id: 1)
+  end
+
+  should "(for PATCH #update) restrict parameters on :user to :first_name, :last_name, :email, and :password" do
+    params = {
+      id: 1,
+      user: {
+        first_name: 'Jon',
+        last_name: 'Doe',
+        email: 'jondoe@example.com',
+        password: 'password'
+      }
+    }
+    matcher = permit(:first_name, :last_name, :email, :password).
+      for(:update, params: params).
+      on(:user)
+    assert_accepts matcher, subject
+  end
+end
+
+ +

Finally, if you have an action that isn't one of the seven resourceful +actions, then you'll need to provide the HTTP verb that it responds to:

+ +
Rails.application.routes.draw do
+  resources :users do
+    member do
+      put :toggle
+    end
+  end
+end
+
+class UsersController < ApplicationController
+  def toggle
+    user = User.find(params[:id])
+
+    if user.update_attributes(user_params)
+      # ...
+    else
+      # ...
+    end
+  end
+
+  private
+
+  def user_params
+    params.require(:user).permit(:activated)
+  end
+end
+
+# RSpec
+RSpec.describe UsersController, type: :controller do
+  before do
+    create(:user, id: 1)
+  end
+
+  it do
+    params = { id: 1, user: { activated: true } }
+    should permit(:activated).
+      for(:toggle, params: params, verb: :put).
+      on(:user)
+  end
+end
+
+# Minitest (Shoulda)
+class UsersControllerTest < ActionController::TestCase
+  setup do
+    create(:user, id: 1)
+  end
+
+  should "(for PUT #toggle) restrict parameters on :user to :activated" do
+    params = { id: 1, user: { activated: true } }
+    matcher = permit(:activated).
+      for(:toggle, params: params, verb: :put).
+      on(:user)
+    assert_accepts matcher, subject
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+203
+204
+205
+
+
# File 'lib/shoulda/matchers/action_controller/permit_matcher.rb', line 203
+
+def permit(*params)
+  PermitMatcher.new(params).in_context(self)
+end
+
+ +
+ +
+

+ + #redirect_to(url_or_description, &block) ⇒ RedirectToMatcher + + + + + +

+
+

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 Minitest + +Shoulda, it provides a more expressive syntax over +assert_redirected_to.

+ +
class PostsController < ApplicationController
+  def show
+    redirect_to :index
+  end
+end
+
+# RSpec
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #show' do
+    before { get :show }
+
+    it { should redirect_to(posts_path) }
+    it { should redirect_to(action: :index) }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'GET #show' do
+    setup { get :show }
+
+    should redirect_to('/posts') { posts_path }
+    should redirect_to(action: :index)
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+38
+39
+40
+
+
# File 'lib/shoulda/matchers/action_controller/redirect_to_matcher.rb', line 38
+
+def redirect_to(url_or_description, &block)
+  RedirectToMatcher.new(url_or_description, self, &block)
+end
+
+ +
+ +
+

+ + #render_template(options = {}, message = nil) ⇒ RenderTemplateMatcher + + + + + +

+
+

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 a test suite using Minitest + Shoulda, 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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #show' do
+    before { get :show }
+
+    it { should render_template('show') }
+    it { should render_template(partial: '_sidebar') }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'GET #show' do
+    setup { get :show }
+
+    should render_template('show')
+    should render_template(partial: '_sidebar')
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+39
+40
+41
+
+
# File 'lib/shoulda/matchers/action_controller/render_template_matcher.rb', line 39
+
+def render_template(options = {}, message = nil)
+  RenderTemplateMatcher.new(options, message, self)
+end
+
+ +
+ +
+

+ + #render_with_layout(expected_layout = nil) ⇒ RenderWithLayoutMatcher + + + + + +

+
+

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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #show' do
+    before { get :show }
+
+    it { should render_with_layout('posts') }
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #sidebar' do
+    before { get :sidebar }
+
+    it { should_not render_with_layout }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'GET #sidebar' do
+    setup { get :sidebar }
+
+    should_not render_with_layout
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+60
+61
+62
+
+
# File 'lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb', line 60
+
+def render_with_layout(expected_layout = nil)
+  RenderWithLayoutMatcher.new(expected_layout).in_context(self)
+end
+
+ +
+ +
+

+ + #rescue_from(exception) ⇒ RescueFromMatcher + + + + + +

+
+

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
+RSpec.describe ApplicationController, type: :controller do
+  it do
+    should rescue_from(ActiveRecord::RecordNotFound).
+      with(:handle_not_found)
+  end
+end
+
+# Minitest (Shoulda)
+class ApplicationControllerTest < ActionController::TestCase
+  should rescue_from(ActiveRecord::RecordNotFound).
+    with(:handle_not_found)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+34
+35
+36
+
+
# File 'lib/shoulda/matchers/action_controller/rescue_from_matcher.rb', line 34
+
+def rescue_from(exception)
+  RescueFromMatcher.new exception
+end
+
+ +
+ +
+

+ + #respond_with(status) ⇒ RespondWithMatcher + + + + + +

+
+

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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    before { get :index }
+
+    it { should respond_with(403) }
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller do
+  describe 'DELETE #destroy' do
+    before { delete :destroy }
+
+    it { should respond_with(500..600) }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'DELETE #destroy' do
+    setup { delete :destroy }
+
+    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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #show' do
+    before { get :show }
+
+    it { should respond_with(:locked) }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'GET #show' do
+    setup { get :show }
+
+    should respond_with(:locked)
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+87
+88
+89
+
+
# File 'lib/shoulda/matchers/action_controller/respond_with_matcher.rb', line 87
+
+def respond_with(status)
+  RespondWithMatcher.new(status)
+end
+
+ +
+ +
+

+ + #route(method, path, port: nil) ⇒ RouteMatcher + + + + + +

+
+

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. In a test suite using +Minitest + Shoulda, 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', to: 'posts#index'
+  get '/posts/:id', to: 'posts#show'
+end
+
+ +

You could choose to write tests for these routes alongside other tests +for PostsController:

+ +
class PostsController < ApplicationController
+  # ...
+end
+
+# RSpec
+RSpec.describe PostsController, type: :controller do
+  it { should route(:get, '/posts').to(action: :index) }
+  it { should route(:get, '/posts/1').to(action: :show, id: 1) }
+end
+
+# Minitest (Shoulda)
+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', type: :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
+
+# Minitest (Shoulda)
+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.

+ +

Specifying a port

+ +

If the route you're testing has a constraint on it that limits the route +to a particular port, you can specify it by passing a port option to +the matcher:

+ +
class PortConstraint
+  def initialize(port)
+    @port = port
+  end
+
+  def matches?(request)
+    request.port == @port
+  end
+end
+
+My::Application.routes.draw do
+  get '/posts',
+    to: 'posts#index',
+    constraints: PortConstraint.new(12345)
+end
+
+# RSpec
+describe 'Routing', type: :routing do
+  it do
+    should route(:get, '/posts', port: 12345).
+      to('posts#index')
+  end
+end
+
+# Minitest (Shoulda)
+class RoutesTest < ActionController::IntegrationTest
+  should route(:get, '/posts', port: 12345).
+    to('posts#index')
+end
+
+ +

Qualifiers

+ +
to
+ +

Use to to specify the action (along with the controller, if needed) +that the route resolves to.

+ +

to takes either keyword arguments (controller and action) or a +string that represents the controller/action pair:

+ +
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)
+
+ +

You may also specify special parameters such as :format:

+ +
route(:get, '/posts').to('posts#index', format: :json)
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+127
+128
+129
+
+
# File 'lib/shoulda/matchers/action_controller/route_matcher.rb', line 127
+
+def route(method, path, port: nil)
+  RouteMatcher.new(self, method, path, port: port)
+end
+
+ +
+ +
+

+ + #set_flashSetFlashMatcher + + + + + +

+
+

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
+RSpec.describe PostsController, type: :controller 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
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    before { get :index }
+
+    it { should set_flash[:foo] }
+    it { should_not set_flash[:bar] }
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller 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
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #show' do
+    before { get :show }
+
+    it { should set_flash.now }
+    it { should set_flash.now[:foo] }
+    it { should set_flash.now[:foo].to('bar') }
+  end
+end
+
+# Minitest (Shoulda)
+class PostsControllerTest < ActionController::TestCase
+  context 'GET #index' do
+    setup { get :show }
+
+    should set_flash.now
+    should set_flash.now[:foo]
+    should set_flash.now[:foo].to('bar')
+  end
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+150
+151
+152
+
+
# File 'lib/shoulda/matchers/action_controller/set_flash_matcher.rb', line 150
+
+def set_flash
+  SetFlashMatcher.new.in_context(self)
+end
+
+ +
+ +
+

+ + #set_sessionSetSessionMatcher + + + + + +

+
+

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
+RSpec.describe PostsController, type: :controller 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
+
+# Minitest (Shoulda)
+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.

+ +
class PostsController < ApplicationController
+  def index
+    session[:foo] = 'A candy bar'
+  end
+end
+
+# RSpec
+RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    before { get :index }
+
+    it { should set_session[:foo] }
+    it { should_not set_session[:bar] }
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe PostsController, type: :controller 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
+
+# Minitest (Shoulda)
+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
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+117
+118
+119
+
+
# File 'lib/shoulda/matchers/action_controller/set_session_matcher.rb', line 117
+
+def set_session
+  SetSessionMatcher.new.in_context(self)
+end
+
+ +
+ +
+

+ + #use_after_action(callback) ⇒ CallbackMatcher + + + + + +

+
+

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
+RSpec.describe IssuesController, type: :controller do
+  it { should use_after_action(:log_activity) }
+  it { should_not use_after_action(:destroy_user) }
+end
+
+# Minitest (Shoulda)
+class IssuesControllerTest < ActionController::TestCase
+  should use_after_action(:log_activity)
+  should_not use_after_action(:destroy_user)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+50
+51
+52
+
+
# File 'lib/shoulda/matchers/action_controller/callback_matcher.rb', line 50
+
+def use_after_action(callback)
+  CallbackMatcher.new(callback, :after, :action)
+end
+
+ +
+ +
+

+ + #use_around_action(callback) ⇒ CallbackMatcher + + + + + +

+
+

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
+RSpec.describe ChangesController, type: :controller do
+  it { should use_around_action(:wrap_in_transaction) }
+  it { should_not use_around_action(:save_view_context) }
+end
+
+# Minitest (Shoulda)
+class ChangesControllerTest < ActionController::TestCase
+  should use_around_action(:wrap_in_transaction)
+  should_not use_around_action(:save_view_context)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+75
+76
+77
+
+
# File 'lib/shoulda/matchers/action_controller/callback_matcher.rb', line 75
+
+def use_around_action(callback)
+  CallbackMatcher.new(callback, :around, :action)
+end
+
+ +
+ +
+

+ + #use_before_action(callback) ⇒ CallbackMatcher + + + + + +

+
+

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
+RSpec.describe UsersController, type: :controller do
+  it { should use_before_action(:authenticate_user!) }
+  it { should_not use_before_action(:prevent_ssl) }
+end
+
+# Minitest (Shoulda)
+class UsersControllerTest < ActionController::TestCase
+  should use_before_action(:authenticate_user!)
+  should_not use_before_action(:prevent_ssl)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'lib/shoulda/matchers/action_controller/callback_matcher.rb', line 25
+
+def use_before_action(callback)
+  CallbackMatcher.new(callback, :before, :action)
+end
+
+ +
+ +
+ +
+ + + +
+ + + diff --git a/docs/v5.2.0/Shoulda/Matchers/ActiveModel.html b/docs/v5.2.0/Shoulda/Matchers/ActiveModel.html new file mode 100644 index 00000000..97da4473 --- /dev/null +++ b/docs/v5.2.0/Shoulda/Matchers/ActiveModel.html @@ -0,0 +1,2524 @@ + + + + + + + Module: Shoulda::Matchers::ActiveModel + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda::Matchers::ActiveModel + + + +

+ +
+ + + + + + + +
+

Overview

+
+

This module provides matchers that are used to test behavior within +ActiveModel or ActiveRecord classes.

+ +

Testing conditional validations

+ +

If your model defines a validation conditionally -- meaning that the +validation is declared with an :if or :unless option -- how do you +test it? You might expect the validation matchers here to have +corresponding if or unless qualifiers, but this isn't what you use. +Instead, before using the matcher in question, you place the record +you're testing in a state such that the validation you're also testing +will be run. A common way to do this is to make a new context and +override the subject to populate the record accordingly. You'll also want +to make sure to test that the validation is not run when the +conditional fails.

+ +

Here's an example to illustrate what we mean:

+ +
class User
+  include ActiveModel::Model
+
+  attr_accessor :role, :admin
+
+  validates_presence_of :role, if: :admin
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  context "when an admin" do
+    subject { User.new(admin: true) }
+
+    it { should validate_presence_of(:role) }
+  end
+
+  context "when not an admin" do
+    subject { User.new(admin: false) }
+
+    it { should_not validate_presence_of(:role) }
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  context "when an admin" do
+    subject { User.new(admin: true) }
+
+    should validate_presence_of(:role)
+  end
+
+  context "when not an admin" do
+    subject { User.new(admin: false) }
+
+    should_not validate_presence_of(:role)
+  end
+end
+
+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #allow_value(*values) ⇒ AllowValueMatcher + + + + Also known as: + allow_values + + + + +

+
+

The allow_value matcher (or its alias, allow_values) is used to +ensure that an attribute is valid or invalid if set to one or more +values.

+ +

Take this model for example:

+ +
class UserProfile
+  include ActiveModel::Model
+  attr_accessor :website_url
+
+  validates_format_of :website_url, with: URI.regexp
+end
+
+ +

You can use allow_value to test one value at a time:

+ +
# RSpec
+RSpec.describe UserProfile, type: :model do
+  it { should allow_value('https://foo.com').for(:website_url) }
+  it { should allow_value('https://bar.com').for(:website_url) }
+end
+
+# Minitest (Shoulda)
+class UserProfileTest < ActiveSupport::TestCase
+  should allow_value('https://foo.com').for(:website_url)
+  should allow_value('https://bar.com').for(:website_url)
+end
+
+ +

You can also test multiple values in one go, if you like. In the +positive sense, this makes an assertion that none of the values cause the +record to be invalid. In the negative sense, this makes an assertion +that none of the values cause the record to be valid:

+ +
# RSpec
+RSpec.describe UserProfile, type: :model do
+  it do
+    should allow_values('https://foo.com', 'https://bar.com').
+      for(:website_url)
+  end
+
+  it do
+    should_not allow_values('foo', 'buz').
+      for(:website_url)
+  end
+end
+
+# Minitest (Shoulda)
+class UserProfileTest < ActiveSupport::TestCase
+  should allow_values('https://foo.com', 'https://bar.com/baz').
+    for(:website_url)
+
+  should_not allow_values('foo', 'buz').
+    for(:website_url)
+end
+
+ +

Caveats

+ +

When using allow_value or any matchers that depend on it, you may +encounter an AttributeChangedValueError. This exception is raised if the +matcher, in attempting to set a value on the attribute, detects that +the value set is different from the value that the attribute returns +upon reading it back.

+ +

This usually happens if the writer method (foo=, bar=, etc.) for +that attribute has custom logic to ignore certain incoming values or +change them in any way. Here are three examples we've seen:

+ +
    +
  • You're attempting to assert that an attribute should not allow nil, +yet the attribute's writer method contains a conditional to do nothing +if the attribute is set to nil:

    + +
    class Foo
    +  include ActiveModel::Model
    +
    +  attr_reader :bar
    +
    +  def bar=(value)
    +    return if value.nil?
    +    @bar = value
    +  end
    +end
    +
    +RSpec.describe Foo, type: :model do
    +  it do
    +    foo = Foo.new
    +    foo.bar = "baz"
    +    # This will raise an AttributeChangedValueError since `foo.bar` is now "123"
    +    expect(foo).not_to allow_value(nil).for(:bar)
    +  end
    +end
    +
  • +
  • You're attempting to assert that a numeric attribute should not allow +a string that contains non-numeric characters, yet the writer method +for that attribute strips out non-numeric characters:

    + +
    class Foo
    +  include ActiveModel::Model
    +
    +  attr_reader :bar
    +
    +  def bar=(value)
    +    @bar = value.gsub(/\D+/, '')
    +  end
    +end
    +
    +RSpec.describe Foo, type: :model do
    +  it do
    +    foo = Foo.new
    +    # This will raise an AttributeChangedValueError since `foo.bar` is now "123"
    +    expect(foo).not_to allow_value("abc123").for(:bar)
    +  end
    +end
    +
  • +
  • You're passing a value to allow_value that the model typecasts into +another value:

    + +
    RSpec.describe Foo, type: :model do
    +  # Assume that `attr` is a string
    +  # This will raise an AttributeChangedValueError since `attr` typecasts `[]` to `"[]"`
    +  it { should_not allow_value([]).for(:attr) }
    +end
    +
  • +
+ +

Fortunately, if you understand why this is happening, and wish to get +around this exception, it is possible to do so. You can use the +ignoring_interference_by_writer qualifier like so:

+ +
    it do
+      should_not allow_value([]).
+        for(:attr).
+        ignoring_interference_by_writer
+    end
+
+ +

Please note, however, that this qualifier won't magically cause your +test to pass. It may just so happen that the final value that ends up +being set causes the model to fail validation. In that case, you'll have +to figure out what to do. You may need to write your own test, or +perhaps even remove your test altogether.

+ +

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
+RSpec.describe UserProfile, type: :model do
+  it do
+    should allow_value('2013-01-01').
+      for(:birthday_as_string).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe UserProfile, type: :model do
+  it do
+    should allow_value('open', 'closed').
+      for(:state).
+      with_message('State must be open or closed')
+  end
+end
+
+# Minitest (Shoulda)
+class UserProfileTest < ActiveSupport::TestCase
+  should allow_value('open', 'closed').
+    for(:state).
+    with_message('State must be open or closed')
+end
+
+ +

Use with_message with a regexp to perform a partial match:

+ +
class UserProfile
+  include ActiveModel::Model
+  attr_accessor :state
+
+  validates_format_of :state,
+    with: /^(open|closed)$/,
+    message: 'State must be open or closed'
+end
+
+# RSpec
+RSpec.describe UserProfile, type: :model do
+  it do
+    should allow_value('open', 'closed').
+      for(:state).
+      with_message(/open or closed/)
+  end
+end
+
+# Minitest (Shoulda)
+class UserProfileTest < ActiveSupport::TestCase
+  should allow_value('open', 'closed').
+    for(:state).
+    with_message(/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
+RSpec.describe UserProfile, type: :model 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
+
+# Minitest (Shoulda)
+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
+
+ +
ignoring_interference_by_writer
+ +

Use ignoring_interference_by_writer to bypass an +AttributeChangedValueError that you have encountered. Please read the +Caveats section above for more information.

+ +
class Address < ActiveRecord::Base
+  # Address has a zip_code field which is a string
+end
+
+# RSpec
+RSpec.describe Address, type: :model do
+  it do
+    should_not allow_value([]).
+      for(:zip_code).
+      ignoring_interference_by_writer
+  end
+end
+
+# Minitest (Shoulda)
+class AddressTest < ActiveSupport::TestCase
+  should_not allow_value([]).
+    for(:zip_code).
+    ignoring_interference_by_writer
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+296
+297
+298
+299
+300
+301
+302
+
+
# File 'lib/shoulda/matchers/active_model/allow_value_matcher.rb', line 296
+
+def allow_value(*values)
+  if values.empty?
+    raise ArgumentError, 'need at least one argument'
+  else
+    AllowValueMatcher.new(*values)
+  end
+end
+
+ +
+ +
+

+ + #have_secure_password(attr = :password) ⇒ HaveSecurePasswordMatcher + + + + + +

+
+

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
+  attr_accessor :reset_password
+
+  has_secure_password
+  has_secure_password :reset_password
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should have_secure_password }
+  it { should have_secure_password(:reset_password) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should have_secure_password
+  should have_secure_password(:reset_password)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+33
+34
+35
+
+
# File 'lib/shoulda/matchers/active_model/have_secure_password_matcher.rb', line 33
+
+def have_secure_password(attr = :password)
+  HaveSecurePasswordMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_absence_of(attr) ⇒ ValidateAbsenceOfMatcher + + + + + +

+
+

The validate_absence_of matcher tests the usage of the +validates_absence_of validation.

+ +
class PowerHungryCountry
+  include ActiveModel::Model
+  attr_accessor :nuclear_weapons
+
+  validates_absence_of :nuclear_weapons
+end
+
+# RSpec
+RSpec.describe PowerHungryCountry, type: :model do
+  it { should validate_absence_of(:nuclear_weapons) }
+end
+
+# Minitest (Shoulda)
+class PowerHungryCountryTest < ActiveSupport::TestCase
+  should validate_absence_of(:nuclear_weapons)
+end
+
+ +

Qualifiers

+ +
on
+ +

Use on if your validation applies only under a certain context.

+ +
class PowerHungryCountry
+  include ActiveModel::Model
+  attr_accessor :nuclear_weapons
+
+  validates_absence_of :nuclear_weapons, on: :create
+end
+
+# RSpec
+RSpec.describe PowerHungryCountry, type: :model do
+  it { should validate_absence_of(:nuclear_weapons).on(:create) }
+end
+
+# Minitest (Shoulda)
+class PowerHungryCountryTest < ActiveSupport::TestCase
+  should validate_absence_of(:nuclear_weapons).on(:create)
+end
+
+ +
with_message
+ +

Use with_message if you are using a custom validation message.

+ +
class PowerHungryCountry
+  include ActiveModel::Model
+  attr_accessor :nuclear_weapons
+
+  validates_absence_of :nuclear_weapons,
+    message: "there shall be peace on Earth"
+end
+
+# RSpec
+RSpec.describe PowerHungryCountry, type: :model do
+  it do
+    should validate_absence_of(:nuclear_weapons).
+      with_message("there shall be peace on Earth")
+  end
+end
+
+# Minitest (Shoulda)
+class PowerHungryCountryTest < ActiveSupport::TestCase
+  should validate_absence_of(:nuclear_weapons).
+    with_message("there shall be peace on Earth")
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+75
+76
+77
+
+
# File 'lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb', line 75
+
+def validate_absence_of(attr)
+  ValidateAbsenceOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_acceptance_of(attr) ⇒ ValidateAcceptanceOfMatcher + + + + + +

+
+

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
+RSpec.describe Registration, type: :model do
+  it { should validate_acceptance_of(:eula) }
+end
+
+# Minitest (Shoulda)
+class RegistrationTest < ActiveSupport::TestCase
+  should validate_acceptance_of(:eula)
+end
+
+ +

Qualifiers

+ +
on
+ +

Use on if your validation applies only under a certain context.

+ +
class Registration
+  include ActiveModel::Model
+  attr_accessor :terms_of_service
+
+  validates_acceptance_of :terms_of_service, on: :create
+end
+
+# RSpec
+RSpec.describe Registration, type: :model do
+  it do
+    should validate_acceptance_of(:terms_of_service).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+class RegistrationTest < ActiveSupport::TestCase
+  should validate_acceptance_of(:terms_of_service).on(:create)
+end
+
+ +
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
+RSpec.describe Registration, type: :model do
+  it do
+    should validate_acceptance_of(:terms_of_service).
+      with_message('You must accept the terms of service')
+  end
+end
+
+# Minitest (Shoulda)
+class RegistrationTest < ActiveSupport::TestCase
+  should validate_acceptance_of(:terms_of_service).
+    with_message('You must accept the terms of service')
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+78
+79
+80
+
+
# File 'lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb', line 78
+
+def validate_acceptance_of(attr)
+  ValidateAcceptanceOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_confirmation_of(attr) ⇒ ValidateConfirmationOfMatcher + + + + + +

+
+

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
+RSpec.describe User, type: :model do
+  it { should validate_confirmation_of(:email) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_confirmation_of(:email)
+end
+
+ +

Qualifiers

+ +
on
+ +

Use on if your validation applies only under a certain context.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :password
+
+  validates_confirmation_of :password, on: :create
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should validate_confirmation_of(:password).on(:create) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_confirmation_of(:password).on(:create)
+end
+
+ +
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
+RSpec.describe User, type: :model do
+  it do
+    should validate_confirmation_of(:password).
+      with_message('Please re-enter your password')
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_confirmation_of(:password).
+    with_message('Please re-enter your password')
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+75
+76
+77
+
+
# File 'lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb', line 75
+
+def validate_confirmation_of(attr)
+  ValidateConfirmationOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_exclusion_of(attr) ⇒ ValidateExclusionOfMatcher + + + + + +

+
+

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
+RSpec.describe Game, type: :model do
+  it do
+    should validate_exclusion_of(:supported_os).
+      in_array(['Mac', 'Linux'])
+  end
+end
+
+# Minitest (Shoulda)
+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: 5..8
+end
+
+# RSpec
+RSpec.describe Game, type: :model do
+  it do
+    should validate_exclusion_of(:floors_with_enemies).
+      in_range(5..8)
+  end
+end
+
+# Minitest (Shoulda)
+class GameTest < ActiveSupport::TestCase
+  should validate_exclusion_of(:floors_with_enemies).
+    in_range(5..8)
+end
+
+ +

Qualifiers

+ +
on
+ +

Use on if your validation applies only under a certain context.

+ +
class Game
+  include ActiveModel::Model
+  attr_accessor :weapon
+
+  validates_exclusion_of :weapon,
+    in: ['pistol', 'paintball gun', 'stick'],
+    on: :create
+end
+
+# RSpec
+RSpec.describe Game, type: :model do
+  it do
+    should validate_exclusion_of(:weapon).
+      in_array(['pistol', 'paintball gun', 'stick']).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+class GameTest < ActiveSupport::TestCase
+  should validate_exclusion_of(:weapon).
+    in_array(['pistol', 'paintball gun', 'stick']).
+    on(:create)
+end
+
+ +
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
+RSpec.describe Game, type: :model do
+  it do
+    should validate_exclusion_of(:weapon).
+      in_array(['pistol', 'paintball gun', 'stick']).
+      with_message('You chose a puny weapon')
+  end
+end
+
+# Minitest (Shoulda)
+class GameTest < ActiveSupport::TestCase
+  should validate_exclusion_of(:weapon).
+    in_array(['pistol', 'paintball gun', 'stick']).
+    with_message('You chose a puny weapon')
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+117
+118
+119
+
+
# File 'lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb', line 117
+
+def validate_exclusion_of(attr)
+  ValidateExclusionOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_inclusion_of(attr) ⇒ ValidateInclusionOfMatcher + + + + + +

+
+

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: ['open', 'resolved', 'unresolved']
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should validate_inclusion_of(:state).
+      in_array(['open', 'resolved', 'unresolved'])
+  end
+end
+
+# Minitest (Shoulda)
+class IssueTest < ActiveSupport::TestCase
+  should validate_inclusion_of(:state).
+    in_array(['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
+RSpec.describe Issue, type: :model do
+  it { should validate_inclusion_of(:state).in_range(1..5) }
+end
+
+# Minitest (Shoulda)
+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 do
+  should validate_inclusion_of(:imported).
+    in_array([true, false])
+end
+
+ +

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

+ +

Use on if your validation applies only under a certain context.

+ +
class Issue
+  include ActiveModel::Model
+  attr_accessor :severity
+
+  validates_inclusion_of :severity,
+    in: %w(low medium high),
+    on: :create
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should validate_inclusion_of(:severity).
+      in_array(%w(low medium high)).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+class IssueTest < ActiveSupport::TestCase
+  should validate_inclusion_of(:severity).
+    in_array(%w(low medium high)).
+    on(:create)
+end
+
+ +
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
+RSpec.describe Issue, type: :model 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
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should validate_inclusion_of(:age).
+      in_range(0..65).
+      with_low_message('You do not receive any benefits')
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should validate_inclusion_of(:age).
+      in_range(0..21).
+      with_high_message("You're too old for this stuff")
+  end
+end
+
+# Minitest (Shoulda)
+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: ['open', 'resolved', 'unresolved'],
+    allow_nil: true
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should validate_inclusion_of(:state).
+      in_array(['open', 'resolved', 'unresolved']).
+      allow_nil
+  end
+end
+
+# Minitest (Shoulda)
+class IssueTest < ActiveSupport::TestCase
+  should validate_inclusion_of(:state).
+    in_array(['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: ['open', 'resolved', 'unresolved'],
+    allow_blank: true
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should validate_inclusion_of(:state).
+      in_array(['open', 'resolved', 'unresolved']).
+      allow_blank
+  end
+end
+
+# Minitest (Shoulda)
+class IssueTest < ActiveSupport::TestCase
+  should validate_inclusion_of(:state).
+    in_array(['open', 'resolved', 'unresolved']).
+    allow_blank
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+265
+266
+267
+
+
# File 'lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb', line 265
+
+def validate_inclusion_of(attr)
+  ValidateInclusionOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_length_of(attr) ⇒ ValidateLengthOfMatcher + + + + + +

+
+

The validate_length_of matcher tests usage of the +validates_length_of matcher. Note that this matcher is intended to be +used against string columns and not integer columns.

+ +

Qualifiers

+ +

Use on if your validation applies only under a certain context.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :password
+
+  validates_length_of :password, minimum: 10, on: :create
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it do
+    should validate_length_of(:password).
+      is_at_least(10).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:password).
+    is_at_least(10).
+    on(:create)
+end
+
+ +
is_at_least
+ +

Use is_at_least to test usage of the :minimum option. This asserts +that the attribute can take a string which is equal to or longer than +the given length and cannot take a string which is shorter.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :bio
+
+  validates_length_of :bio, minimum: 15
+end
+
+# RSpec
+
+RSpec.describe User, type: :model do
+  it { should validate_length_of(:bio).is_at_least(15) }
+end
+
+# Minitest (Shoulda)
+
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:bio).is_at_least(15)
+end
+
+ +
is_at_most
+ +

Use is_at_most to test usage of the :maximum option. This asserts +that the attribute can take a string which is equal to or shorter than +the given length and cannot take a string which is longer.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :status_update
+
+  validates_length_of :status_update, maximum: 140
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should validate_length_of(:status_update).is_at_most(140) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:status_update).is_at_most(140)
+end
+
+ +
is_equal_to
+ +

Use is_equal_to to test usage of the :is option. This asserts that +the attribute can take a string which is exactly equal to the given +length and cannot take a string which is shorter or longer.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :favorite_superhero
+
+  validates_length_of :favorite_superhero, is: 6
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should validate_length_of(:favorite_superhero).is_equal_to(6) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:favorite_superhero).is_equal_to(6)
+end
+
+ +
is_at_least + is_at_most
+ +

Use is_at_least and is_at_most together to test usage of the :in +option.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :password
+
+  validates_length_of :password, in: 5..30
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it do
+    should validate_length_of(:password).
+      is_at_least(5).is_at_most(30)
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:password).
+    is_at_least(5).is_at_most(30)
+end
+
+ +
with_message
+ +

Use with_message if you are using a custom validation message.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :password
+
+  validates_length_of :password,
+    minimum: 10,
+    message: "Password isn't long enough"
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it do
+    should validate_length_of(:password).
+      is_at_least(10).
+      with_message("Password isn't long enough")
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:password).
+    is_at_least(10).
+    with_message("Password isn't long enough")
+end
+
+ +
with_short_message
+ +

Use with_short_message if you are using a custom "too short" message.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :secret_key
+
+  validates_length_of :secret_key,
+    in: 15..100,
+    too_short: 'Secret key must be more than 15 characters'
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it do
+    should validate_length_of(:secret_key).
+      is_at_least(15).
+      with_short_message('Secret key must be more than 15 characters')
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:secret_key).
+    is_at_least(15).
+    with_short_message('Secret key must be more than 15 characters')
+end
+
+ +
with_long_message
+ +

Use with_long_message if you are using a custom "too long" message.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :secret_key
+
+  validates_length_of :secret_key,
+    in: 15..100,
+    too_long: 'Secret key must be less than 100 characters'
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it do
+    should validate_length_of(:secret_key).
+      is_at_most(100).
+      with_long_message('Secret key must be less than 100 characters')
+  end
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:secret_key).
+    is_at_most(100).
+    with_long_message('Secret key must be less than 100 characters')
+end
+
+ +
allow_nil
+ +

Use allow_nil to assert that the attribute allows nil.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :bio
+
+  validates_length_of :bio, minimum: 15, allow_nil: true
+end
+
+# RSpec
+describe User do
+  it { should validate_length_of(:bio).is_at_least(15).allow_nil }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:bio).is_at_least(15).allow_nil
+end
+
+ +
allow_blank
+ +

Use allow_blank to assert that the attribute allows blank.

+ +
class User
+  include ActiveModel::Model
+  attr_accessor :bio
+
+  validates_length_of :bio, minimum: 15, allow_blank: true
+end
+
+# RSpec
+describe User do
+  it { should validate_length_of(:bio).is_at_least(15).allow_blank }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should validate_length_of(:bio).is_at_least(15).allow_blank
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+263
+264
+265
+
+
# File 'lib/shoulda/matchers/active_model/validate_length_of_matcher.rb', line 263
+
+def validate_length_of(attr)
+  ValidateLengthOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_numericality_of(attr) ⇒ ValidateNumericalityOfMatcher + + + + + +

+
+

The validate_numericality_of matcher tests usage of the +validates_numericality_of validation.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :gpa
+
+  validates_numericality_of :gpa
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should validate_numericality_of(:gpa) }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:gpa)
+end
+
+ +

Qualifiers

+ +
on
+ +

Use on if your validation applies only under a certain context.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :number_of_dependents
+
+  validates_numericality_of :number_of_dependents, on: :create
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:number_of_dependents).
+      on(:create)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:number_of_dependents).on(:create)
+end
+
+ +
only_integer
+ +

Use only_integer to test usage of the :only_integer option. This +asserts that your attribute only allows integer numbers and disallows +non-integer ones.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :age
+
+  validates_numericality_of :age, only_integer: true
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should validate_numericality_of(:age).only_integer }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:age).only_integer
+end
+
+ +
is_less_than
+ +

Use is_less_than to test usage of the the :less_than option. This +asserts that the attribute can take a number which is less than the +given value and cannot take a number which is greater than or equal to +it.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :number_of_cars
+
+  validates_numericality_of :number_of_cars, less_than: 2
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:number_of_cars).
+      is_less_than(2)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:number_of_cars).
+    is_less_than(2)
+end
+
+ +
is_less_than_or_equal_to
+ +

Use is_less_than_or_equal_to to test usage of the +:less_than_or_equal_to option. This asserts that the attribute can +take a number which is less than or equal to the given value and cannot +take a number which is greater than it.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :birth_year
+
+  validates_numericality_of :birth_year, less_than_or_equal_to: 1987
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:birth_year).
+      is_less_than_or_equal_to(1987)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:birth_year).
+    is_less_than_or_equal_to(1987)
+end
+
+ +
is_equal_to
+ +

Use is_equal_to to test usage of the :equal_to option. This asserts +that the attribute can take a number which is equal to the given value +and cannot take a number which is not equal.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :weight
+
+  validates_numericality_of :weight, equal_to: 150
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should validate_numericality_of(:weight).is_equal_to(150) }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:weight).is_equal_to(150)
+end
+
+ +
is_greater_than_or_equal_to
+ +

Use is_greater_than_or_equal_to to test usage of the +:greater_than_or_equal_to option. This asserts that the attribute can +take a number which is greater than or equal to the given value and +cannot take a number which is less than it.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :height
+
+  validates_numericality_of :height, greater_than_or_equal_to: 55
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:height).
+      is_greater_than_or_equal_to(55)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:height).
+    is_greater_than_or_equal_to(55)
+end
+
+ +
is_greater_than
+ +

Use is_greater_than to test usage of the :greater_than option. +This asserts that the attribute can take a number which is greater than +the given value and cannot take a number less than or equal to it.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :legal_age
+
+  validates_numericality_of :legal_age, greater_than: 21
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:legal_age).
+      is_greater_than(21)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:legal_age).
+    is_greater_than(21)
+end
+
+ +
is_other_than
+ +

Use is_other_than to test usage of the :other_than option. +This asserts that the attribute can take a number which is not equal to +the given value.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :legal_age
+
+  validates_numericality_of :legal_age, other_than: 21
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:legal_age).
+      is_other_than(21)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:legal_age).
+    is_other_than(21)
+end
+
+ +
even
+ +

Use even to test usage of the :even option. This asserts that the +attribute can take odd numbers and cannot take even ones.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :birth_month
+
+  validates_numericality_of :birth_month, even: true
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should validate_numericality_of(:birth_month).even }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:birth_month).even
+end
+
+ +
odd
+ +

Use odd to test usage of the :odd option. This asserts that the +attribute can take a number which is odd and cannot take a number which +is even.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :birth_day
+
+  validates_numericality_of :birth_day, odd: true
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should validate_numericality_of(:birth_day).odd }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:birth_day).odd
+end
+
+ +
with_message
+ +

Use with_message if you are using a custom validation message.

+ +
class Person
+  include ActiveModel::Model
+  attr_accessor :number_of_dependents
+
+  validates_numericality_of :number_of_dependents,
+    message: 'Number of dependents must be a number'
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should validate_numericality_of(:number_of_dependents).
+      with_message('Number of dependents must be a number')
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should validate_numericality_of(:number_of_dependents).
+    with_message('Number of dependents must be a number')
+end
+
+ +
allow_nil
+ +

Use allow_nil to assert that the attribute allows nil.

+ +
class Post
+  include ActiveModel::Model
+  attr_accessor :age
+
+  validates_numericality_of :age, allow_nil: true
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_numericality_of(:age).allow_nil }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_numericality_of(:age).allow_nil
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+328
+329
+330
+
+
# File 'lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb', line 328
+
+def validate_numericality_of(attr)
+  ValidateNumericalityOfMatcher.new(attr)
+end
+
+ +
+ +
+

+ + #validate_presence_of(attr) ⇒ ValidatePresenceOfMatcher + + + + + +

+
+

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
+RSpec.describe Robot, type: :model do
+  it { should validate_presence_of(:arms) }
+end
+
+# Minitest (Shoulda)
+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
+
+RSpec.describe User, type: :model 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

+ +
allow_nil
+ +

Use allow_nil if your model has an optional attribute.

+ +

class Robot + include ActiveModel::Model + attr_accessor :nickname

+ +
validates_presence_of :nickname, allow_nil: true
+
+ +

end

+ +

# RSpec + RSpec.describe Robot, type: :model do + it { should validate_presence_of(:nickname).allow_nil } + end

+ +

# Minitest (Shoulda) + class RobotTest < ActiveSupport::TestCase + should validate_presence_of(:nickname).allow_nil + end

+ +

allow_blank

+ +

Use allow_blank to assert that the attribute allows blank.

+ +

class Robot + include ActiveModel::Model + attr_accessor :nickname

+ +
validates_presence_of :nickname, allow_blank: true
+
+ +

end

+ +

# RSpec + RSpec.describe Robot, type: :model do + it { should validate_presence_of(:nickname).allow_blank } + end

+ +

# Minitest (Shoulda) + class RobotTest < ActiveSupport::TestCase + should validate_presence_of(:nickname).allow_blank + end

+ +
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
+RSpec.describe Robot, type: :model do
+  it { should validate_presence_of(:arms).on(:create) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Robot, type: :model do
+  it do
+    should validate_presence_of(:legs).
+      with_message('Robot has no legs')
+  end
+end
+
+# Minitest (Shoulda)
+class RobotTest < ActiveSupport::TestCase
+  should validate_presence_of(:legs).
+    with_message('Robot has no legs')
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+150
+151
+152
+
+
# File 'lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb', line 150
+
+def validate_presence_of(attr)
+  ValidatePresenceOfMatcher.new(attr)
+end
+
+ +
+ +
+ +
+ + + +
+ + + diff --git a/docs/v5.2.0/Shoulda/Matchers/ActiveRecord.html b/docs/v5.2.0/Shoulda/Matchers/ActiveRecord.html new file mode 100644 index 00000000..42659189 --- /dev/null +++ b/docs/v5.2.0/Shoulda/Matchers/ActiveRecord.html @@ -0,0 +1,3082 @@ + + + + + + + Module: Shoulda::Matchers::ActiveRecord + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda::Matchers::ActiveRecord + + + +

+ +
+ + + + + + + +
+

Overview

+
+

This module provides matchers that are used to test behavior within +ActiveRecord classes.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #accept_nested_attributes_for(name) ⇒ AcceptNestedAttributesForMatcher + + + + + +

+
+

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
+RSpec.describe Car, type: :model do
+  it { should accept_nested_attributes_for(:doors) }
+end
+
+# Minitest (Shoulda) (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
+RSpec.describe Car, type: :model do
+  it do
+    should accept_nested_attributes_for(:mirrors).
+      allow_destroy(true)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Car, type: :model do
+  it do
+    should accept_nested_attributes_for(:windows).
+      limit(3)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Car, type: :model do
+  it do
+    should accept_nested_attributes_for(:engine).
+      update_only(true)
+  end
+end
+
+# Minitest (Shoulda)
+class CarTest < ActiveSupport::TestCase
+  should accept_nested_attributes_for(:engine).
+    update_only(true)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+93
+94
+95
+
+
# File 'lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb', line 93
+
+def accept_nested_attributes_for(name)
+  AcceptNestedAttributesForMatcher.new(name)
+end
+
+ +
+ +
+

+ + #belong_to(name) ⇒ AssociationMatcher + + + + + +

+
+

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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:organization) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Comment, type: :model do
+  it { should belong_to(:commentable) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should belong_to(:family).
+      conditions(everyone_is_perfect: false)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:previous_company).order('hired_on desc') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:ancient_city).class_name('City') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should belong_to(:great_country).
+      with_primary_key('country_id')
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should belong_to(:great_country).
+      with_foreign_key('country_id')
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:world).dependent(:destroy) }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should belong_to(:world).dependent(:destroy)
+end
+
+ +

To assert that any :dependent option was specified, use true:

+ +
# RSpec
+RSpec.describe Person, type: :model 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
+RSpec.describe Person, type: :model 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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:organization).counter_cache(true) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should belong_to(:organization).touch(true) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Account, type: :model do
+  it { should belong_to(:bank).autosave(true) }
+end
+
+# Minitest (Shoulda)
+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
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should belong_to(:organization).inverse_of(:employees)
+end
+
+ +
required
+ +

Use required to assert that the association is not allowed to be nil. +(Enabled by default in Rails 5+.)

+ +
class Person < ActiveRecord::Base
+  belongs_to :organization, required: true
+end
+
+# RSpec
+describe Person
+  it { should belong_to(:organization).required }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should belong_to(:organization).required
+end
+
+ +
without_validating_presence
+ +

Use without_validating_presence with belong_to to prevent the +matcher from checking whether the association disallows nil (Rails 5+ +only). This can be helpful if you have a custom hook that always sets +the association to a meaningful value:

+ +
class Person < ActiveRecord::Base
+  belongs_to :organization
+
+  before_validation :autoassign_organization
+
+  private
+
+  def autoassign_organization
+    self.organization = Organization.create!
+  end
+end
+
+# RSpec
+describe Person
+  it { should belong_to(:organization).without_validating_presence }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should belong_to(:organization).without_validating_presence
+end
+
+ +
optional
+ +

Use optional to assert that the association is allowed to be nil. +(Rails 5+ only.)

+ +
class Person < ActiveRecord::Base
+  belongs_to :organization, optional: true
+end
+
+# RSpec
+describe Person
+  it { should belong_to(:organization).optional }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should belong_to(:organization).optional
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+325
+326
+327
+
+
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 325
+
+def belong_to(name)
+  AssociationMatcher.new(:belongs_to, name)
+end
+
+ +
+ +
+

+ + #define_enum_for(attribute_name) ⇒ DefineEnumForMatcher + + + + + +

+
+

The define_enum_for matcher is used to test that the enum macro has +been used to decorate an attribute with enum capabilities.

+ +
class Process < ActiveRecord::Base
+  enum status: [:running, :stopped, :suspended]
+
+  alias_attribute :kind, :SomeLegacyField
+
+  enum kind: [:foo, :bar]
+end
+
+# RSpec
+RSpec.describe Process, type: :model do
+  it { should define_enum_for(:status) }
+  it { should define_enum_for(:kind) }
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status)
+  should define_enum_for(:kind)
+end
+
+ +

Qualifiers

+ +
with_values
+ +

Use with_values to test that the attribute can only receive a certain +set of possible values.

+ +
class Process < ActiveRecord::Base
+  enum status: [:running, :stopped, :suspended]
+end
+
+# RSpec
+RSpec.describe Process, type: :model do
+  it do
+    should define_enum_for(:status).
+      with_values([:running, :stopped, :suspended])
+  end
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    with_values([:running, :stopped, :suspended])
+end
+
+ +

If the values backing your enum attribute are arbitrary instead of a +series of integers starting from 0, pass a hash to with_values instead +of an array:

+ +
class Process < ActiveRecord::Base
+  enum status: {
+    running: 0,
+    stopped: 1,
+    suspended: 3,
+    other: 99
+  }
+end
+
+# RSpec
+RSpec.describe Process, type: :model do
+  it do
+    should define_enum_for(:status).
+      with_values(running: 0, stopped: 1, suspended: 3, other: 99)
+  end
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    with_values(running: 0, stopped: 1, suspended: 3, other: 99)
+end
+
+ +
backed_by_column_of_type
+ +

Use backed_by_column_of_type when the column backing your column type +is a string instead of an integer:

+ +
class LoanApplication < ActiveRecord::Base
+  enum status: {
+    active: "active",
+    pending: "pending",
+    rejected: "rejected"
+  }
+end
+
+# RSpec
+RSpec.describe LoanApplication, type: :model do
+  it do
+    should define_enum_for(:status).
+      with_values(
+        active: "active",
+        pending: "pending",
+        rejected: "rejected"
+      ).
+      backed_by_column_of_type(:string)
+  end
+end
+
+# Minitest (Shoulda)
+class LoanApplicationTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    with_values(
+      active: "active",
+      pending: "pending",
+      rejected: "rejected"
+    ).
+    backed_by_column_of_type(:string)
+end
+
+ +
with_prefix
+ +

Use with_prefix to test that the enum is defined with a _prefix +option (Rails 6+ only). Can take either a boolean or a symbol:

+ +
class Issue < ActiveRecord::Base
+  enum status: [:open, :closed], _prefix: :old
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should define_enum_for(:status).
+      with_values([:open, :closed]).
+      with_prefix(:old)
+  end
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    with_values([:open, :closed]).
+    with_prefix(:old)
+end
+
+ +
with_suffix
+ +

Use with_suffix to test that the enum is defined with a _suffix +option (Rails 5 only). Can take either a boolean or a symbol:

+ +
class Issue < ActiveRecord::Base
+  enum status: [:open, :closed], _suffix: true
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should define_enum_for(:status).
+      with_values([:open, :closed]).
+      with_suffix
+  end
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    with_values([:open, :closed]).
+    with_suffix
+end
+
+ +
without_scopes
+ +

Use without_scopes to test that the enum is defined with +'_scopes: false' option (Rails 5 only). Can take either a boolean or a +symbol:

+ +
class Issue < ActiveRecord::Base
+  enum status: [:open, :closed], _scopes: false
+end
+
+# RSpec
+RSpec.describe Issue, type: :model do
+  it do
+    should define_enum_for(:status).
+      without_scopes
+  end
+end
+
+# Minitest (Shoulda)
+class ProcessTest < ActiveSupport::TestCase
+  should define_enum_for(:status).
+    without_scopes
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+192
+193
+194
+
+
# File 'lib/shoulda/matchers/active_record/define_enum_for_matcher.rb', line 192
+
+def define_enum_for(attribute_name)
+  DefineEnumForMatcher.new(attribute_name)
+end
+
+ +
+ +
+

+ + #have_and_belong_to_many(name) ⇒ AssociationMatcher + + + + + +

+
+

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
+RSpec.describe Person, type: :model do
+  it { should have_and_belong_to_many(:awards) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should have_and_belong_to_many(:issues).
+      conditions(difficulty: 'hard')
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should have_and_belong_to_many(:projects).
+      order('time_spent')
+  end
+end
+
+# Minitest (Shoulda)
+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
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should have_and_belong_to_many(:places_visited).
+      class_name('City')
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should have_and_belong_to_many(:places_visited).
+    class_name('City')
+end
+
+ +
join_table
+ +

Use join_table to test usage of the :join_table option. This +asserts that the table you're referring to actually exists.

+ +
class Person < ActiveRecord::Base
+  has_and_belongs_to_many :issues, join_table: :people_tickets
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it do
+    should have_and_belong_to_many(:issues).
+      join_table(:people_tickets)
+  end
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should have_and_belong_to_many(:issues).
+    join_table(:people_tickets)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should have_and_belong_to_many(:interviews).
+      validate(false)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Publisher, type: :model do
+  it { should have_and_belong_to_many(:advertisers).autosave(true) }
+end
+
+# Minitest (Shoulda)
+class AccountTest < ActiveSupport::TestCase
+  should have_and_belong_to_many(:advertisers).autosave(true)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+982
+983
+984
+
+
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 982
+
+def have_and_belong_to_many(name)
+  AssociationMatcher.new(:has_and_belongs_to_many, name)
+end
+
+ +
+ +
+

+ + #have_db_column(column) ⇒ HaveDbColumnMatcher + + + + + +

+
+

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
+RSpec.describe Phone, type: :model do
+  it { should have_db_column(:supported_ios_version) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Phone, type: :model do
+  it do
+    should have_db_column(:camera_aperture).of_type(:decimal)
+  end
+end
+
+# Minitest (Shoulda)
+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, +:primary or :array).

+ +
class CreatePhones < ActiveRecord::Migration
+  def change
+    create_table :phones do |t|
+      t.decimal :camera_aperture, precision: 1, null: false
+    end
+  end
+end
+
+# RSpec
+RSpec.describe Phone, type: :model do
+  it do
+    should have_db_column(:camera_aperture).
+      with_options(precision: 1, null: false)
+  end
+end
+
+# Minitest (Shoulda)
+class PhoneTest < ActiveSupport::TestCase
+  should have_db_column(:camera_aperture).
+    with_options(precision: 1, null: false)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+81
+82
+83
+
+
# File 'lib/shoulda/matchers/active_record/have_db_column_matcher.rb', line 81
+
+def have_db_column(column)
+  HaveDbColumnMatcher.new(column)
+end
+
+ +
+ +
+

+ + #have_db_index(columns) ⇒ HaveDbIndexMatcher + + + + + +

+
+

The have_db_index matcher tests that the table that backs your model +has a specific index.

+ +

You can specify one 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
+RSpec.describe Blog, type: :model do
+  it { should have_db_index(:user_id) }
+end
+
+# Minitest (Shoulda)
+class BlogTest < ActiveSupport::TestCase
+  should have_db_index(:user_id)
+end
+
+ +

Or you can specify a group of columns:

+ +
class CreateBlogs < ActiveRecord::Migration
+  def change
+    create_table :blogs do |t|
+      t.integer :user_id
+      t.string :name
+    end
+
+    add_index :blogs, :user_id, :name
+  end
+end
+
+# RSpec
+RSpec.describe Blog, type: :model do
+  it { should have_db_index([:user_id, :name]) }
+end
+
+# Minitest (Shoulda)
+class BlogTest < ActiveSupport::TestCase
+  should have_db_index([:user_id, :name])
+end
+
+ +

Finally, if you're using Rails 5 and PostgreSQL, you can also specify an +expression:

+ +
class CreateLoggedErrors < ActiveRecord::Migration
+  def change
+    create_table :logged_errors do |t|
+      t.string :code
+      t.jsonb :content
+    end
+
+    add_index :logged_errors, 'lower(code)::text'
+  end
+end
+
+# RSpec
+RSpec.describe LoggedError, type: :model do
+  it { should have_db_index('lower(code)::text') }
+end
+
+# Minitest (Shoulda)
+class LoggedErrorTest < ActiveSupport::TestCase
+  should have_db_index('lower(code)::text')
+end
+
+ +

Qualifiers

+ +
unique
+ +

Use unique to assert that the index is either unique or non-unique:

+ +
class CreateBlogs < ActiveRecord::Migration
+  def change
+    create_table :blogs do |t|
+      t.string :domain
+      t.integer :user_id
+    end
+
+    add_index :blogs, :domain, unique: true
+    add_index :blogs, :user_id
+  end
+end
+
+# RSpec
+RSpec.describe Blog, type: :model do
+  it { should have_db_index(:name).unique }
+  it { should have_db_index(:name).unique(true) }   # if you want to be explicit
+  it { should have_db_index(:user_id).unique(false) }
+end
+
+# Minitest (Shoulda)
+class BlogTest < ActiveSupport::TestCase
+  should have_db_index(:name).unique
+  should have_db_index(:name).unique(true)   # if you want to be explicit
+  should have_db_index(:user_id).unique(false)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+110
+111
+112
+
+
# File 'lib/shoulda/matchers/active_record/have_db_index_matcher.rb', line 110
+
+def have_db_index(columns)
+  HaveDbIndexMatcher.new(columns)
+end
+
+ +
+ +
+

+ + #have_implicit_order_column(column_name) ⇒ Object + + + + + +

+ + + + +
+
+
+
+24
+25
+26
+
+
# File 'lib/shoulda/matchers/active_record/have_implicit_order_column.rb', line 24
+
+def have_implicit_order_column(column_name)
+  HaveImplicitOrderColumnMatcher.new(column_name)
+end
+
+ +
+ +
+

+ + #have_many(name) ⇒ AssociationMatcher + + + + + +

+
+

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
+RSpec.describe Person, type: :model do
+  it { should have_many(:friends) }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should have_many(:friends)
+end
+
+ +

Note that polymorphic associations are automatically detected and do not +need any qualifiers:

+ +
class Person < ActiveRecord::Base
+  has_many :pictures, as: :imageable
+end
+
+# RSpec
+RSpec.describe Person, type: :model do
+  it { should have_many(:pictures) }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should have_many(:pictures)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:coins).conditions(quality: 'mint') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:shirts).order('color') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:hopes).class_name('Dream') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:worries).with_primary_key('worrier_id') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:worries).with_foreign_key('worrier_id') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:secret_documents).dependent(:destroy) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:acquaintances).through(:friends) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it do
+    should have_many(:job_offers).
+      through(:friends).
+      source(:opportunities)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_many(:ideas).validate(false) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Player, type: :model do
+  it { should have_many(:games).autosave(true) }
+end
+
+# Minitest (Shoulda)
+class PlayerTest < ActiveSupport::TestCase
+  should have_many(:games).autosave(true)
+end
+
+ +
index_errors
+ +

Use index_errors to assert that the :index_errors option was +specified.

+ +
class Player < ActiveRecord::Base
+  has_many :games, index_errors: true
+end
+
+# RSpec
+RSpec.describe Player, type: :model do
+  it { should have_many(:games).index_errors(true) }
+end
+
+# Minitest (Shoulda)
+class PlayerTest < ActiveSupport::TestCase
+  should have_many(:games).index_errors(true)
+end
+
+ +
inverse_of
+ +

Use inverse_of to assert that the :inverse_of option was specified.

+ +
class Organization < ActiveRecord::Base
+  has_many :employees, inverse_of: :company
+end
+
+# RSpec
+describe Organization
+  it { should have_many(:employees).inverse_of(:company) }
+end
+
+# Minitest (Shoulda)
+class OrganizationTest < ActiveSupport::TestCase
+  should have_many(:employees).inverse_of(:company)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+595
+596
+597
+
+
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 595
+
+def have_many(name)
+  AssociationMatcher.new(:has_many, name)
+end
+
+ +
+ +
+

+ + #have_many_attached(name) ⇒ HaveAttachedMatcher + + + + + +

+
+

The have_many_attached matcher tests usage of the +has_many_attached macro.

+ +

Example

+ +
class Message < ApplicationRecord
+  has_many_attached :images
+end
+
+# RSpec
+RSpec.describe Message, type: :model do
+  it { should have_many_attached(:images) }
+end
+
+# Minitest (Shoulda)
+class MessageTest < ActiveSupport::TestCase
+  should have_many_attached(:images)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+50
+51
+52
+
+
# File 'lib/shoulda/matchers/active_record/have_attached_matcher.rb', line 50
+
+def have_many_attached(name)
+  HaveAttachedMatcher.new(:many, name)
+end
+
+ +
+ +
+

+ + #have_one(name) ⇒ AssociationMatcher + + + + + +

+
+

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
+RSpec.describe Person, type: :model do
+  it { should have_one(:partner) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:pet).conditions('weight < 80') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:focus).order('priority desc') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:chance).class_name('Opportunity') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:contract).dependent(:nullify) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:job).with_primary_key('worker_id') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:job).with_foreign_key('worker_id') }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:life).through(:partner) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:car).through(:partner).source(:vehicle) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Person, type: :model do
+  it { should have_one(:parking_card).validate(false) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Account, type: :model do
+  it { should have_one(:bank).autosave(true) }
+end
+
+# Minitest (Shoulda)
+class AccountTest < ActiveSupport::TestCase
+  should have_one(:bank).autosave(true)
+end
+
+ +
required
+ +

Use required to assert that the association is not allowed to be nil. +(Rails 5+ only.)

+ +
class Person < ActiveRecord::Base
+  has_one :brain, required: true
+end
+
+# RSpec
+describe Person
+  it { should have_one(:brain).required }
+end
+
+# Minitest (Shoulda)
+class PersonTest < ActiveSupport::TestCase
+  should have_one(:brain).required
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+824
+825
+826
+
+
# File 'lib/shoulda/matchers/active_record/association_matcher.rb', line 824
+
+def have_one(name)
+  AssociationMatcher.new(:has_one, name)
+end
+
+ +
+ +
+

+ + #have_one_attached(name) ⇒ HaveAttachedMatcher + + + + + +

+
+

The have_one_attached matcher tests usage of the +has_one_attached macro.

+ +

Example

+ +
class User < ApplicationRecord
+  has_one_attached :avatar
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should have_one_attached(:avatar) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should have_one_attached(:avatar)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'lib/shoulda/matchers/active_record/have_attached_matcher.rb', line 25
+
+def have_one_attached(name)
+  HaveAttachedMatcher.new(:one, name)
+end
+
+ +
+ +
+

+ + #have_readonly_attribute(value) ⇒ HaveReadonlyAttributeMatcher + + + + + +

+
+

The have_readonly_attribute matcher tests usage of the +attr_readonly macro.

+ +
class User < ActiveRecord::Base
+  attr_readonly :password
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should have_readonly_attribute(:password) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should have_readonly_attribute(:password)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+23
+24
+25
+
+
# File 'lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb', line 23
+
+def have_readonly_attribute(value)
+  HaveReadonlyAttributeMatcher.new(value)
+end
+
+ +
+ +
+

+ + #have_rich_text(rich_text_attribute) ⇒ HaveRichTextMatcher + + + + + +

+
+

The have_rich_text matcher tests usage of the +has_rich_text macro.

+ +

Example

+ +
class Post < ActiveRecord
+  has_rich_text :content
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should have_rich_text(:content) }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should have_rich_text(:content)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+25
+26
+27
+
+
# File 'lib/shoulda/matchers/active_record/have_rich_text_matcher.rb', line 25
+
+def have_rich_text(rich_text_attribute)
+  HaveRichTextMatcher.new(rich_text_attribute)
+end
+
+ +
+ +
+

+ + #have_secure_token(token_attribute = :token) ⇒ HaveSecureToken + + + + + +

+
+

The have_secure_token matcher tests usage of the +has_secure_token macro.

+ +
class User < ActiveRecord
+  has_secure_token
+  has_secure_token :auth_token
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should have_secure_token }
+  it { should have_secure_token(:auth_token) }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should have_secure_token
+  should have_secure_token(:auth_token)
+end
+
+ +

Qualifiers

+ +
ignoring_check_for_db_index
+ +

By default, this matcher tests that an index is defined on your token +column. Use ignoring_check_for_db_index if this is not the case.

+ +
class User < ActiveRecord
+  has_secure_token :auth_token
+end
+
+# RSpec
+RSpec.describe User, type: :model do
+  it { should have_secure_token(:auth_token).ignoring_check_for_db_index }
+end
+
+# Minitest (Shoulda)
+class UserTest < ActiveSupport::TestCase
+  should have_secure_token(:auth_token).ignoring_check_for_db_index
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+47
+48
+49
+
+
# File 'lib/shoulda/matchers/active_record/have_secure_token_matcher.rb', line 47
+
+def have_secure_token(token_attribute = :token)
+  HaveSecureTokenMatcher.new(token_attribute)
+end
+
+ +
+ +
+

+ + #serialize(name) ⇒ SerializeMatcher + + + + + +

+
+

The serialize matcher tests usage of the serialize macro.

+ +
class Product < ActiveRecord::Base
+  serialize :customizations
+end
+
+# RSpec
+RSpec.describe Product, type: :model do
+  it { should serialize(:customizations) }
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Product, type: :model do
+  it do
+    should serialize(:specifications).
+      as(ProductSpecsSerializer)
+  end
+end
+
+# Minitest (Shoulda)
+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
+RSpec.describe Product, type: :model do
+  it do
+    should serialize(:options).
+      as_instance_of(ProductOptionsSerializer)
+  end
+end
+
+# Minitest (Shoulda)
+class ProductTest < ActiveSupport::TestCase
+  should serialize(:options).
+    as_instance_of(ProductOptionsSerializer)
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+88
+89
+90
+
+
# File 'lib/shoulda/matchers/active_record/serialize_matcher.rb', line 88
+
+def serialize(name)
+  SerializeMatcher.new(name)
+end
+
+ +
+ +
+

+ + #validate_uniqueness_of(attr) ⇒ ValidateUniquenessOfMatcher + + + + + +

+
+

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 :permalink, uniqueness: true
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:permalink) }
+end
+
+# Minitest (Shoulda)
+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:

+ +
RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:title) }
+end
+
+ +

However, running this test will fail with an exception such as:

+ +
Shoulda::Matchers::ActiveRecord::ValidateUniquenessOfMatcher::ExistingRecordInvalid:
+  validate_uniqueness_of works by matching a new record against an
+  existing record. If there is no existing record, it will create one
+  using the record you provide.
+
+  While doing this, the following error was raised:
+
+    PG::NotNullViolation: ERROR:  null value in column "content" violates not-null constraint
+    DETAIL:  Failing row contains (1, null, null).
+    : INSERT INTO "posts" DEFAULT VALUES RETURNING "id"
+
+  The best way to fix this is to provide the matcher with a record where
+  any required attributes are filled in with valid values beforehand.
+
+ +

(The exact error message will differ depending on which database you're +using, but you get the idea.)

+ +

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. As indicated at the +end of the error message, the solution is to build a custom Post object +ahead of time with content filled in:

+ +
RSpec.describe Post, type: :model 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 +FactoryBot and you have a +post factory defined which automatically fills in content, you can +say:

+ +
RSpec.describe Post, type: :model do
+  describe "validations" do
+    subject { FactoryBot.build(:post) }
+    it { should validate_uniqueness_of(:title) }
+  end
+end
+
+ +

Qualifiers

+ +

Use on if your validation applies only under a certain context.

+ +
class Post < ActiveRecord::Base
+  validates :title, uniqueness: true, on: :create
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:title).on(:create) }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:title).on(:create)
+end
+
+ +
with_message
+ +

Use with_message if you are using a custom validation message.

+ +
class Post < ActiveRecord::Base
+  validates :title, uniqueness: true, message: 'Please choose another title'
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it do
+    should validate_uniqueness_of(:title).
+      with_message('Please choose another title')
+  end
+end
+
+# Minitest (Shoulda)
+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 :slug, uniqueness: { scope: :journal_id }
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:slug).scoped_to(:journal_id) }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:slug).scoped_to(:journal_id)
+end
+
+ +

NOTE: Support for testing uniqueness validation scoped to an array of +associations is not available.

+ +

For more information, please refer to +https://github.com/thoughtbot/shoulda-matchers/issues/814

+ +
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 :key, uniqueness: { case_sensitive: false }
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:key).case_insensitive }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:key).case_insensitive
+end
+
+ +
ignoring_case_sensitivity
+ +

By default, validate_uniqueness_of will check that the +validation is case sensitive: it asserts that uniquable attributes pass +validation when their values are in a different case than corresponding +attributes in the pre-existing record.

+ +

Use ignoring_case_sensitivity to skip this check. This qualifier is +particularly handy if your model has somehow changed the behavior of +attribute you're testing so that it modifies the case of incoming values +as they are set. For instance, perhaps you've overridden the writer +method or added a before_validation callback to normalize the +attribute.

+ +
class User < ActiveRecord::Base
+  validates :email, uniqueness: true
+
+  def email=(value)
+    super(value.downcase)
+  end
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it do
+    should validate_uniqueness_of(:email).ignoring_case_sensitivity
+  end
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:email).ignoring_case_sensitivity
+end
+
+ +
allow_nil
+ +

Use allow_nil to assert that the attribute allows nil.

+ +
class Post < ActiveRecord::Base
+  validates :author_id, uniqueness: true, allow_nil: true
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:author_id).allow_nil }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:author_id).allow_nil
+end
+
+ +
allow_blank
+ +

Use allow_blank to assert that the attribute allows a blank value.

+ +
class Post < ActiveRecord::Base
+  validates :author_id, uniqueness: true, allow_blank: true
+end
+
+# RSpec
+RSpec.describe Post, type: :model do
+  it { should validate_uniqueness_of(:author_id).allow_blank }
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  should validate_uniqueness_of(:author_id).allow_blank
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+261
+262
+263
+
+
# File 'lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb', line 261
+
+def validate_uniqueness_of(attr)
+  ValidateUniquenessOfMatcher.new(attr)
+end
+
+ +
+ +
+ +
+ + + +
+ + + diff --git a/docs/v5.2.0/Shoulda/Matchers/Independent.html b/docs/v5.2.0/Shoulda/Matchers/Independent.html new file mode 100644 index 00000000..e2f5d7be --- /dev/null +++ b/docs/v5.2.0/Shoulda/Matchers/Independent.html @@ -0,0 +1,383 @@ + + + + + + + Module: Shoulda::Matchers::Independent + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Module: Shoulda::Matchers::Independent + + + +

+ +
+ + + + + + + +
+

Overview

+
+

This module provides matchers that are used to test behavior outside of +Rails-specific classes.

+ + +
+
+
+ + +
+ + + + + + + +

+ Instance Method Summary + collapse +

+ + + + + + +
+

Instance Method Details

+ + +
+

+ + #delegate_method(delegating_method) ⇒ DelegateMethodMatcher + + + + + +

+
+

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
+
+# Minitest
+class CourierTest < Minitest::Test
+  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
+
+# Minitest
+class CourierTest < Minitest::Test
+  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
+
+# Minitest
+class PageTest < Minitest::Test
+  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
+
+# Minitest
+class CourierTest < Minitest::Test
+  should delegate_method(:deliver_package).
+    to(:post_office).
+    with_arguments(expedited: true)
+end
+
+ +
allow_nil
+ +

Use allow_nil if the delegation accounts for the fact that your +delegate object could be nil. (This is mostly intended as an analogue to +the allow_nil option that Rails' delegate helper takes.)

+ +
class Account
+  delegate :plan, to: :subscription, allow_nil: true
+end
+
+# RSpec
+describe Account do
+  it { should delegate_method(:plan).to(:subscription).allow_nil }
+end
+
+# Minitest
+class PageTest < Minitest::Test
+  should delegate_method(:plan).to(:subscription).allow_nil
+end
+
+ + +
+
+
+ + +
+ + + + +
+
+
+
+173
+174
+175
+
+
# File 'lib/shoulda/matchers/independent/delegate_method_matcher.rb', line 173
+
+def delegate_method(delegating_method)
+  DelegateMethodMatcher.new(delegating_method).in_context(self)
+end
+
+ +
+ +
+ +
+ + + +
+ + + diff --git a/docs/v5.2.0/_index.html b/docs/v5.2.0/_index.html new file mode 100644 index 00000000..abc23591 --- /dev/null +++ b/docs/v5.2.0/_index.html @@ -0,0 +1,200 @@ + + + + + + + Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Documentation by YARD 0.9.25

+
+

Alphabetic Index

+ +

File Listing

+ + +
+

Namespace Listing A-Z

+ + + + + + + + +
+ + + + + +
    +
  • I
  • + +
+ + +
    +
  • M
  • + +
+ + + + +
+ +
+ +
+ + + +
+ + + diff --git a/docs/v5.2.0/class_list.html b/docs/v5.2.0/class_list.html new file mode 100644 index 00000000..8769e0df --- /dev/null +++ b/docs/v5.2.0/class_list.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + Class List + + + +
+

Class List

+ + +
+ + diff --git a/docs/v5.2.0/css/bootstrap.css b/docs/v5.2.0/css/bootstrap.css new file mode 100644 index 00000000..2db07a4a --- /dev/null +++ b/docs/v5.2.0/css/bootstrap.css @@ -0,0 +1,5967 @@ +/*! + * Bootstrap v3.0.3 + * + * Copyright 2013 Twitter, Inc + * Licensed under the Apache License v2.0 + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} +audio, +canvas, +video { + display: inline-block; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +a { + background: transparent; +} +a:focus { + outline: thin dotted; +} +a:active, +a:hover { + outline: 0; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +mark { + background: #ff0; + color: #000; +} +code, +kbd, +pre, +samp { + font-family: monospace, serif; + font-size: 1em; +} +pre { + white-space: pre-wrap; +} +q { + quotes: "\201C" "\201D" "\2018" "\2019"; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 0; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + margin: 0; +} +button, +input { + line-height: normal; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +textarea { + overflow: auto; + vertical-align: top; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +@media print { + * { + text-shadow: none !important; + color: #000 !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 2cm .5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +*, +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 62.5%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 1.5; + color: #333333; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #428bca; + text-decoration: none; +} +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +img { + vertical-align: middle; +} +.img-responsive { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + padding: 4px; + line-height: 1.5; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 24px; + margin-bottom: 24px; + border: 0; + border-top: 1px solid #eeeeee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #999999; +} +h1, +h2, +h3 { + margin-top: 24px; + margin-bottom: 12px; +} +h1 small, +h2 small, +h3 small, +h1 .small, +h2 .small, +h3 .small { + font-size: 65%; +} +h4, +h5, +h6 { + margin-top: 12px; + margin-bottom: 12px; +} +h4 small, +h5 small, +h6 small, +h4 .small, +h5 .small, +h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 41px; +} +h2, +.h2 { + font-size: 34px; +} +h3, +.h3 { + font-size: 28px; +} +h4, +.h4 { + font-size: 20px; +} +h5, +.h5 { + font-size: 16px; +} +h6, +.h6 { + font-size: 14px; +} +p { + margin: 0 0 12px; +} +.lead { + margin-bottom: 24px; + font-size: 18px; + font-weight: 200; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 24px; + } +} +small, +.small { + font-size: 85%; +} +cite { + font-style: normal; +} +.text-muted { + color: #999999; +} +.text-primary { + color: #428bca; +} +.text-primary:hover { + color: #3071a9; +} +.text-warning { + color: #8a6d3b; +} +.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +.text-danger:hover { + color: #843534; +} +.text-success { + color: #3c763d; +} +.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +.text-info:hover { + color: #245269; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.page-header { + padding-bottom: 11px; + margin: 48px 0 24px; + border-bottom: 1px solid #eeeeee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 12px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +.list-inline > li:first-child { + padding-left: 0; +} +dl { + margin-top: 0; + margin-bottom: 24px; +} +dt, +dd { + line-height: 1.5; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + content: " "; + display: table; + } + .dl-horizontal dd:after { + clear: both; + } + .dl-horizontal dd:before, + .dl-horizontal dd:after { + content: " "; + display: table; + } + .dl-horizontal dd:after { + clear: both; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 12px 24px; + margin: 0 0 24px; + border-left: 5px solid #eeeeee; +} +blockquote p { + font-size: 20px; + font-weight: 300; + line-height: 1.25; +} +blockquote p:last-child { + margin-bottom: 0; +} +blockquote small, +blockquote .small { + display: block; + line-height: 1.5; + color: #999999; +} +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} +blockquote.pull-right p, +blockquote.pull-right small, +blockquote.pull-right .small { + text-align: right; +} +blockquote.pull-right small:before, +blockquote.pull-right .small:before { + content: ''; +} +blockquote.pull-right small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +blockquote:before, +blockquote:after { + content: ""; +} +address { + margin-bottom: 24px; + font-style: normal; + line-height: 1.5; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + white-space: nowrap; + border-radius: 4px; +} +pre { + display: block; + padding: 11.5px; + margin: 0 0 12px; + font-size: 15px; + line-height: 1.5; + word-break: break-all; + word-wrap: break-word; + color: #333333; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.container:before, +.container:after { + content: " "; + display: table; +} +.container:after { + clear: both; +} +.container:before, +.container:after { + content: " "; + display: table; +} +.container:after { + clear: both; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.row:before, +.row:after { + content: " "; + display: table; +} +.row:after { + clear: both; +} +.row:before, +.row:after { + content: " "; + display: table; +} +.row:after { + clear: both; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666666666666%; +} +.col-xs-10 { + width: 83.33333333333334%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666666666666%; +} +.col-xs-7 { + width: 58.333333333333336%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666666666667%; +} +.col-xs-4 { + width: 33.33333333333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.666666666666664%; +} +.col-xs-1 { + width: 8.333333333333332%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666666666666%; +} +.col-xs-pull-10 { + right: 83.33333333333334%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666666666666%; +} +.col-xs-pull-7 { + right: 58.333333333333336%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666666666667%; +} +.col-xs-pull-4 { + right: 33.33333333333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.666666666666664%; +} +.col-xs-pull-1 { + right: 8.333333333333332%; +} +.col-xs-pull-0 { + right: 0%; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666666666666%; +} +.col-xs-push-10 { + left: 83.33333333333334%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666666666666%; +} +.col-xs-push-7 { + left: 58.333333333333336%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666666666667%; +} +.col-xs-push-4 { + left: 33.33333333333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.666666666666664%; +} +.col-xs-push-1 { + left: 8.333333333333332%; +} +.col-xs-push-0 { + left: 0%; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0%; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0%; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0%; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0%; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0%; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0%; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + max-width: 100%; + background-color: transparent; +} +th { + text-align: left; +} +.table { + width: 100%; + margin-bottom: 24px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.5; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #dddddd; +} +.table .table { + background-color: #ffffff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + float: none; + display: table-cell; +} +.table > thead > tr > .active, +.table > tbody > tr > .active, +.table > tfoot > tr > .active, +.table > thead > .active > td, +.table > tbody > .active > td, +.table > tfoot > .active > td, +.table > thead > .active > th, +.table > tbody > .active > th, +.table > tfoot > .active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > .active:hover, +.table-hover > tbody > .active:hover > td, +.table-hover > tbody > .active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > .success, +.table > tbody > tr > .success, +.table > tfoot > tr > .success, +.table > thead > .success > td, +.table > tbody > .success > td, +.table > tfoot > .success > td, +.table > thead > .success > th, +.table > tbody > .success > th, +.table > tfoot > .success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > .success:hover, +.table-hover > tbody > .success:hover > td, +.table-hover > tbody > .success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > .danger, +.table > tbody > tr > .danger, +.table > tfoot > tr > .danger, +.table > thead > .danger > td, +.table > tbody > .danger > td, +.table > tfoot > .danger > td, +.table > thead > .danger > th, +.table > tbody > .danger > th, +.table > tfoot > .danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > .danger:hover, +.table-hover > tbody > .danger:hover > td, +.table-hover > tbody > .danger:hover > th { + background-color: #ebcccc; +} +.table > thead > tr > .warning, +.table > tbody > tr > .warning, +.table > tfoot > tr > .warning, +.table > thead > .warning > td, +.table > tbody > .warning > td, +.table > tfoot > .warning > td, +.table > thead > .warning > th, +.table > tbody > .warning > th, +.table > tfoot > .warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > .warning:hover, +.table-hover > tbody > .warning:hover > td, +.table-hover > tbody > .warning:hover > th { + background-color: #faf2cc; +} +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 18px; + overflow-y: hidden; + overflow-x: scroll; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dddddd; + -webkit-overflow-scrolling: touch; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 24px; + font-size: 24px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + + line-height: normal; +} +input[type="file"] { + display: block; +} +select[multiple], +select[size] { + height: auto; +} +select optgroup { + font-size: inherit; + font-style: inherit; + font-family: inherit; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +input[type="number"]::-webkit-outer-spin-button, +input[type="number"]::-webkit-inner-spin-button { + height: auto; +} +output { + display: block; + padding-top: 7px; + font-size: 16px; + line-height: 1.5; + color: #555555; + vertical-align: middle; +} +.form-control { + display: block; + width: 100%; + height: 38px; + padding: 6px 12px; + font-size: 16px; + line-height: 1.5; + color: #555555; + vertical-align: middle; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.form-control:-moz-placeholder { + color: #999999; +} +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999999; +} +.form-control::-webkit-input-placeholder { + color: #999999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eeeeee; +} +textarea.form-control { + height: auto; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + display: block; + min-height: 24px; + margin-top: 10px; + margin-bottom: 10px; + padding-left: 20px; + vertical-align: middle; +} +.radio label, +.checkbox label { + display: inline; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.input-sm { + height: 29px; + padding: 5px 10px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +select.input-sm { + height: 29px; + line-height: 29px; +} +textarea.input-sm { + height: auto; +} +.input-lg { + height: 57px; + padding: 10px 16px; + font-size: 20px; + line-height: 1.75; + border-radius: 6px; +} +select.input-lg { + height: 57px; + line-height: 57px; +} +textarea.input-lg { + height: auto; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + border-color: #8a6d3b; + background-color: #fcf8e3; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + border-color: #a94442; + background-color: #f2dede; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + border-color: #3c763d; + background-color: #dff0d8; +} +.form-control-static { + margin-bottom: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + } + .form-inline select.form-control { + width: auto; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 7px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 31px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + content: " "; + display: table; +} +.form-horizontal .form-group:after { + clear: both; +} +.form-horizontal .form-group:before, +.form-horizontal .form-group:after { + content: " "; + display: table; +} +.form-horizontal .form-group:after { + clear: both; +} +.form-horizontal .form-control-static { + padding-top: 7px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 6px 12px; + font-size: 16px; + line-height: 1.5; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} +.btn:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + pointer-events: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-default { + color: #333333; + background-color: #ffffff; + border-color: #cccccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333333; + background-color: #ebebeb; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #ffffff; + border-color: #cccccc; +} +.btn-default .badge { + color: #ffffff; + background-color: #fff; +} +.btn-primary { + color: #ffffff; + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #3276b1; + border-color: #285e8e; +} +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary .badge { + color: #428bca; + background-color: #fff; +} +.btn-warning { + color: #ffffff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #ed9c28; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #ffffff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #d2322d; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-success { + color: #ffffff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #47a447; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #ffffff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #39b3d7; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-link { + color: #428bca; + font-weight: normal; + cursor: pointer; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999999; + text-decoration: none; +} +.btn-lg { + padding: 10px 16px; + font-size: 20px; + line-height: 1.75; + border-radius: 6px; +} +.btn-sm { + padding: 5px 10px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +.btn-xs { + padding: 1px 5px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; + padding-left: 0; + padding-right: 0; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + transition: height 0.35s ease; +} +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon:empty { + width: 1em; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 16px; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 11px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.5; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #262626; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #428bca; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 14px; + line-height: 1.5; + color: #999999; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar:before, +.btn-toolbar:after { + content: " "; + display: table; +} +.btn-toolbar:after { + clear: both; +} +.btn-toolbar:before, +.btn-toolbar:after { + content: " "; + display: table; +} +.btn-toolbar:after { + clear: both; +} +.btn-toolbar .btn-group { + float: left; +} +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group, +.btn-toolbar > .btn-group + .btn-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 20px; + line-height: 1.75; + border-radius: 6px; +} +.btn-group > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + content: " "; + display: table; +} +.btn-group-vertical > .btn-group:after { + clear: both; +} +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after { + content: " "; + display: table; +} +.btn-group-vertical > .btn-group:after { + clear: both; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child > .btn:last-child, +.btn-group-vertical > .btn-group:first-child > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + float: none; + display: table-cell; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 57px; + padding: 10px 16px; + font-size: 20px; + line-height: 1.75; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 57px; + line-height: 57px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 29px; + padding: 5px 10px; + font-size: 14px; + line-height: 1.25; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 29px; + line-height: 29px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 16px; + font-weight: normal; + line-height: 1; + color: #555555; + text-align: center; + background-color: #eeeeee; + border: 1px solid #cccccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 14px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 20px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + white-space: nowrap; +} +.input-group-btn:first-child > .btn { + margin-right: -1px; +} +.input-group-btn:last-child > .btn { + margin-left: -1px; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -4px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:active { + z-index: 2; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav:before, +.nav:after { + content: " "; + display: table; +} +.nav:after { + clear: both; +} +.nav:before, +.nav:after { + content: " "; + display: table; +} +.nav:after { + clear: both; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.nav > li.disabled > a { + color: #999999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eeeeee; + border-color: #428bca; +} +.nav .nav-divider { + height: 1px; + margin: 11px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.5; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #ffffff; + background-color: #428bca; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 24px; + border: 1px solid transparent; +} +.navbar:before, +.navbar:after { + content: " "; + display: table; +} +.navbar:after { + clear: both; +} +.navbar:before, +.navbar:after { + content: " "; + display: table; +} +.navbar:after { + clear: both; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +.navbar-header:before, +.navbar-header:after { + content: " "; + display: table; +} +.navbar-header:after { + clear: both; +} +.navbar-header:before, +.navbar-header:after { + content: " "; + display: table; +} +.navbar-header:after { + clear: both; +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + max-height: 340px; + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse:before, +.navbar-collapse:after { + content: " "; + display: table; +} +.navbar-collapse:after { + clear: both; +} +.navbar-collapse:before, +.navbar-collapse:after { + content: " "; + display: table; +} +.navbar-collapse:after { + clear: both; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.container > .navbar-header, +.container > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 13px 15px; + font-size: 20px; + line-height: 24px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 8px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 6.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 24px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 24px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 13px; + padding-bottom: 13px; + } + .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 6px; + margin-bottom: 6px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + } + .navbar-form select.form-control { + width: auto; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-form.navbar-right:last-child { + margin-right: -15px; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-nav.pull-right > li > .dropdown-menu, +.navbar-nav > li > .dropdown-menu.pull-right { + left: auto; + right: 0; +} +.navbar-btn { + margin-top: 6px; + margin-bottom: 6px; +} +.navbar-btn.btn-sm { + margin-top: 10.5px; + margin-bottom: 10.5px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 13px; + margin-bottom: 13px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } + .navbar-text.navbar-right:last-child { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777777; +} +.navbar-default .navbar-nav > li > a { + color: #777777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #dddddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #dddddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #cccccc; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #e7e7e7; + color: #555555; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777777; +} +.navbar-default .navbar-link:hover { + color: #333333; +} +.navbar-inverse { + background-color: #222222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #999999; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #999999; +} +.navbar-inverse .navbar-nav > li > a { + color: #999999; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #080808; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #999999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #ffffff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #999999; +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 24px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #cccccc; +} +.breadcrumb > .active { + color: #999999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 24px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + line-height: 1.5; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + background-color: #eeeeee; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + background-color: #ffffff; + border-color: #dddddd; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 20px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 6px; + border-top-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 14px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 24px 0; + list-style: none; + text-align: center; +} +.pager:before, +.pager:after { + content: " "; + display: table; +} +.pager:after { + clear: both; +} +.pager:before, +.pager:after { + content: " "; + display: table; +} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + background-color: #ffffff; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +.label[href]:hover, +.label[href]:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #999999; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} +.label-primary { + background-color: #428bca; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 14px; + font-weight: bold; + color: #ffffff; + line-height: 1; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: #999999; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #ffffff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px; + margin-bottom: 30px; + font-size: 24px; + font-weight: 200; + line-height: 2.25; + color: inherit; + background-color: #eeeeee; +} +.jumbotron h1, +.jumbotron .h1 { + line-height: 1; + color: inherit; +} +.jumbotron p { + line-height: 1.4; +} +.container .jumbotron { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 72px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 24px; + line-height: 1.5; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 4px; + -webkit-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + display: block; + max-width: 100%; + height: auto; + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} +.thumbnail .caption { + padding: 9px; + color: #333333; +} +.alert { + padding: 15px; + margin-bottom: 24px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable { + padding-right: 35px; +} +.alert-dismissable .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #dff0d8; + border-color: #d6e9c6; + color: #3c763d; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + background-color: #d9edf7; + border-color: #bce8f1; + color: #31708f; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + background-color: #fcf8e3; + border-color: #faebcc; + color: #8a6d3b; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + background-color: #f2dede; + border-color: #ebccd1; + color: #a94442; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 24px; + margin-bottom: 24px; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 14px; + line-height: 24px; + color: #ffffff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 24px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-body:before, +.panel-body:after { + content: " "; + display: table; +} +.panel-body:after { + clear: both; +} +.panel-body:before, +.panel-body:after { + content: " "; + display: table; +} +.panel-body:after { + clear: both; +} +.panel > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item { + border-width: 1px 0; +} +.panel > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel > .list-group .list-group-item:last-child { + border-bottom: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #dddddd; +} +.panel > .table > tbody:first-child th, +.panel > .table > tbody:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:last-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-bordered > thead > tr:last-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 18px; + color: inherit; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; + overflow: hidden; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #428bca; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #428bca; + border-color: #428bca; +} +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 24px; + font-weight: bold; + line-height: 1; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: auto; + overflow-y: scroll; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; + z-index: 1050; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: none; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; + min-height: 16.5px; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.5; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + margin-top: 15px; + padding: 19px 20px 20px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.modal-footer:after { + clear: both; +} +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.modal-footer:after { + clear: both; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +@media screen and (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } +} +.tooltip { + position: absolute; + z-index: 1030; + display: block; + visibility: visible; + font-size: 14px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + right: 5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + background-color: #ffffff; + background-clip: padding-box; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + white-space: normal; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 16px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: 11px; +} +.popover .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); +} +.carousel-control.right { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); +} +.carousel-control:hover, +.carousel-control:focus { + outline: none; + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} +.clearfix:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-xs.visible-sm { + display: block !important; + } + table.visible-xs.visible-sm { + display: table; + } + tr.visible-xs.visible-sm { + display: table-row !important; + } + th.visible-xs.visible-sm, + td.visible-xs.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-xs.visible-md { + display: block !important; + } + table.visible-xs.visible-md { + display: table; + } + tr.visible-xs.visible-md { + display: table-row !important; + } + th.visible-xs.visible-md, + td.visible-xs.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-xs.visible-lg { + display: block !important; + } + table.visible-xs.visible-lg { + display: table; + } + tr.visible-xs.visible-lg { + display: table-row !important; + } + th.visible-xs.visible-lg, + td.visible-xs.visible-lg { + display: table-cell !important; + } +} +.visible-sm, +tr.visible-sm, +th.visible-sm, +td.visible-sm { + display: none !important; +} +@media (max-width: 767px) { + .visible-sm.visible-xs { + display: block !important; + } + table.visible-sm.visible-xs { + display: table; + } + tr.visible-sm.visible-xs { + display: table-row !important; + } + th.visible-sm.visible-xs, + td.visible-sm.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-sm.visible-md { + display: block !important; + } + table.visible-sm.visible-md { + display: table; + } + tr.visible-sm.visible-md { + display: table-row !important; + } + th.visible-sm.visible-md, + td.visible-sm.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-sm.visible-lg { + display: block !important; + } + table.visible-sm.visible-lg { + display: table; + } + tr.visible-sm.visible-lg { + display: table-row !important; + } + th.visible-sm.visible-lg, + td.visible-sm.visible-lg { + display: table-cell !important; + } +} +.visible-md, +tr.visible-md, +th.visible-md, +td.visible-md { + display: none !important; +} +@media (max-width: 767px) { + .visible-md.visible-xs { + display: block !important; + } + table.visible-md.visible-xs { + display: table; + } + tr.visible-md.visible-xs { + display: table-row !important; + } + th.visible-md.visible-xs, + td.visible-md.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-md.visible-sm { + display: block !important; + } + table.visible-md.visible-sm { + display: table; + } + tr.visible-md.visible-sm { + display: table-row !important; + } + th.visible-md.visible-sm, + td.visible-md.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-md.visible-lg { + display: block !important; + } + table.visible-md.visible-lg { + display: table; + } + tr.visible-md.visible-lg { + display: table-row !important; + } + th.visible-md.visible-lg, + td.visible-md.visible-lg { + display: table-cell !important; + } +} +.visible-lg, +tr.visible-lg, +th.visible-lg, +td.visible-lg { + display: none !important; +} +@media (max-width: 767px) { + .visible-lg.visible-xs { + display: block !important; + } + table.visible-lg.visible-xs { + display: table; + } + tr.visible-lg.visible-xs { + display: table-row !important; + } + th.visible-lg.visible-xs, + td.visible-lg.visible-xs { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-lg.visible-sm { + display: block !important; + } + table.visible-lg.visible-sm { + display: table; + } + tr.visible-lg.visible-sm { + display: table-row !important; + } + th.visible-lg.visible-sm, + td.visible-lg.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-lg.visible-md { + display: block !important; + } + table.visible-lg.visible-md { + display: table; + } + tr.visible-lg.visible-md { + display: table-row !important; + } + th.visible-lg.visible-md, + td.visible-lg.visible-md { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +.hidden-xs { + display: block !important; +} +table.hidden-xs { + display: table; +} +tr.hidden-xs { + display: table-row !important; +} +th.hidden-xs, +td.hidden-xs { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-xs.hidden-sm, + tr.hidden-xs.hidden-sm, + th.hidden-xs.hidden-sm, + td.hidden-xs.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-xs.hidden-md, + tr.hidden-xs.hidden-md, + th.hidden-xs.hidden-md, + td.hidden-xs.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-xs.hidden-lg, + tr.hidden-xs.hidden-lg, + th.hidden-xs.hidden-lg, + td.hidden-xs.hidden-lg { + display: none !important; + } +} +.hidden-sm { + display: block !important; +} +table.hidden-sm { + display: table; +} +tr.hidden-sm { + display: table-row !important; +} +th.hidden-sm, +td.hidden-sm { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-sm.hidden-xs, + tr.hidden-sm.hidden-xs, + th.hidden-sm.hidden-xs, + td.hidden-sm.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-sm.hidden-md, + tr.hidden-sm.hidden-md, + th.hidden-sm.hidden-md, + td.hidden-sm.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-sm.hidden-lg, + tr.hidden-sm.hidden-lg, + th.hidden-sm.hidden-lg, + td.hidden-sm.hidden-lg { + display: none !important; + } +} +.hidden-md { + display: block !important; +} +table.hidden-md { + display: table; +} +tr.hidden-md { + display: table-row !important; +} +th.hidden-md, +td.hidden-md { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-md.hidden-xs, + tr.hidden-md.hidden-xs, + th.hidden-md.hidden-xs, + td.hidden-md.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-md.hidden-sm, + tr.hidden-md.hidden-sm, + th.hidden-md.hidden-sm, + td.hidden-md.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-md.hidden-lg, + tr.hidden-md.hidden-lg, + th.hidden-md.hidden-lg, + td.hidden-md.hidden-lg { + display: none !important; + } +} +.hidden-lg { + display: block !important; +} +table.hidden-lg { + display: table; +} +tr.hidden-lg { + display: table-row !important; +} +th.hidden-lg, +td.hidden-lg { + display: table-cell !important; +} +@media (max-width: 767px) { + .hidden-lg.hidden-xs, + tr.hidden-lg.hidden-xs, + th.hidden-lg.hidden-xs, + td.hidden-lg.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-lg.hidden-sm, + tr.hidden-lg.hidden-sm, + th.hidden-lg.hidden-sm, + td.hidden-lg.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-lg.hidden-md, + tr.hidden-lg.hidden-md, + th.hidden-lg.hidden-md, + td.hidden-lg.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} +.visible-print, +tr.visible-print, +th.visible-print, +td.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} diff --git a/docs/v5.2.0/css/common.css b/docs/v5.2.0/css/common.css new file mode 100644 index 00000000..cf25c452 --- /dev/null +++ b/docs/v5.2.0/css/common.css @@ -0,0 +1 @@ +/* Override this file with custom rules */ \ No newline at end of file diff --git a/docs/v5.2.0/css/full_list.css b/docs/v5.2.0/css/full_list.css new file mode 100644 index 00000000..3763a010 --- /dev/null +++ b/docs/v5.2.0/css/full_list.css @@ -0,0 +1,12 @@ +body { + font-size: 14px; + padding: 20px; +} + +h1 { + font-size: 1.5em; +} + +.search_info, .toggle { + display: none; +} diff --git a/docs/v5.2.0/css/global.css b/docs/v5.2.0/css/global.css new file mode 100644 index 00000000..5344d6e8 --- /dev/null +++ b/docs/v5.2.0/css/global.css @@ -0,0 +1,68 @@ +@import "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic,400,400italic,600,600italic,800|Droid+Sans+Mono"; + +body { + font-size: 16px; + line-height: 1.5; +} + +a, a:hover { + color: #136cc6; +} + +h1, h2, h3, h4, h5, h6, p, pre { + margin-bottom: 1em; + margin-top: 0; +} + +h1, h2, h3, h4, h5, h6, body { + font-family: "Source Sans Pro", sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 800; +} + +pre, tt, code { + background: #FFFBF4; + border-radius: 3px; + border: 1px solid rgba(0,0,0,0.1); + font-family: "Droid Sans Mono", monospace; + font-size: 13px; +} + +pre code { + border: none; +} + +tt, code { + color: black; + padding: 0 4px; +} + +ul, ol { + margin-left: 1em; + padding-left: 1em; +} + +p, blockquote { + margin-bottom: 1.25em; +} + +blockquote { + font-style: italic; + padding-top: 0; + padding-bottom: 0; + padding-left: 1em; +} + +blockquote p { + font-size: inherit; + font-weight: inherit; + line-height: inherit; +} + +/* +ul ul, ol ol, ul ol, ol ul { + margin-bottom: 1.25em; +} +*/ diff --git a/docs/v5.2.0/css/solarized.css b/docs/v5.2.0/css/solarized.css new file mode 100644 index 00000000..29313953 --- /dev/null +++ b/docs/v5.2.0/css/solarized.css @@ -0,0 +1,69 @@ +pre, code { background-color: #fdf6e3; color: #586e75 } +pre .c { color: #93a1a1 } /* Comment */ +pre .err { color: #586e75 } /* Error */ +pre .g { color: #586e75 } /* Generic */ +pre .k { color: #859900 } /* Keyword */ +pre .l { color: #586e75 } /* Literal */ +pre .n { color: #586e75 } /* Name */ +pre .o { color: #859900 } /* Operator */ +pre .x { color: #cb4b16 } /* Other */ +pre .p { color: #586e75 } /* Punctuation */ +pre .cm { color: #93a1a1 } /* Comment.Multiline */ +pre .cp { color: #859900 } /* Comment.Preproc */ +pre .c1 { color: #93a1a1 } /* Comment.Single */ +pre .cs { color: #859900 } /* Comment.Special */ +pre .gd { color: #2aa198 } /* Generic.Deleted */ +pre .ge { color: #586e75; font-style: italic } /* Generic.Emph */ +pre .gr { color: #dc322f } /* Generic.Error */ +pre .gh { color: #cb4b16 } /* Generic.Heading */ +pre .gi { color: #859900 } /* Generic.Inserted */ +pre .go { color: #586e75 } /* Generic.Output */ +pre .gp { color: #586e75 } /* Generic.Prompt */ +pre .gs { color: #586e75; font-weight: bold } /* Generic.Strong */ +pre .gu { color: #cb4b16 } /* Generic.Subheading */ +pre .gt { color: #586e75 } /* Generic.Traceback */ +pre .kc { color: #cb4b16 } /* Keyword.Constant */ +pre .kd { color: #268bd2 } /* Keyword.Declaration */ +pre .kn { color: #859900 } /* Keyword.Namespace */ +pre .kp { color: #859900 } /* Keyword.Pseudo */ +pre .kr { color: #268bd2 } /* Keyword.Reserved */ +pre .kt { color: #dc322f } /* Keyword.Type */ +pre .ld { color: #586e75 } /* Literal.Date */ +pre .m { color: #2aa198 } /* Literal.Number */ +pre .s { color: #2aa198 } /* Literal.String */ +pre .na { color: #586e75 } /* Name.Attribute */ +pre .nb { color: #B58900 } /* Name.Builtin */ +pre .nc { color: #268bd2 } /* Name.Class */ +pre .no { color: #cb4b16 } /* Name.Constant */ +pre .nd { color: #268bd2 } /* Name.Decorator */ +pre .ni { color: #cb4b16 } /* Name.Entity */ +pre .ne { color: #cb4b16 } /* Name.Exception */ +pre .nf { color: #268bd2 } /* Name.Function */ +pre .nl { color: #586e75 } /* Name.Label */ +pre .nn { color: #586e75 } /* Name.Namespace */ +pre .nx { color: #586e75 } /* Name.Other */ +pre .py { color: #586e75 } /* Name.Property */ +pre .nt { color: #268bd2 } /* Name.Tag */ +pre .nv { color: #268bd2 } /* Name.Variable */ +pre .ow { color: #859900 } /* Operator.Word */ +pre .w { color: #586e75 } /* Text.Whitespace */ +pre .mf { color: #2aa198 } /* Literal.Number.Float */ +pre .mh { color: #2aa198 } /* Literal.Number.Hex */ +pre .mi { color: #2aa198 } /* Literal.Number.Integer */ +pre .mo { color: #2aa198 } /* Literal.Number.Oct */ +pre .sb { color: #93a1a1 } /* Literal.String.Backtick */ +pre .sc { color: #2aa198 } /* Literal.String.Char */ +pre .sd { color: #586e75 } /* Literal.String.Doc */ +pre .s2 { color: #2aa198 } /* Literal.String.Double */ +pre .se { color: #cb4b16 } /* Literal.String.Escape */ +pre .sh { color: #586e75 } /* Literal.String.Heredoc */ +pre .si { color: #2aa198 } /* Literal.String.Interpol */ +pre .sx { color: #2aa198 } /* Literal.String.Other */ +pre .sr { color: #dc322f } /* Literal.String.Regex */ +pre .s1 { color: #2aa198 } /* Literal.String.Single */ +pre .ss { color: #2aa198 } /* Literal.String.Symbol */ +pre .bp { color: #268bd2 } /* Name.Builtin.Pseudo */ +pre .vc { color: #268bd2 } /* Name.Variable.Class */ +pre .vg { color: #268bd2 } /* Name.Variable.Global */ +pre .vi { color: #268bd2 } /* Name.Variable.Instance */ +pre .il { color: #2aa198 } /* Literal.Number.Integer.Long */ diff --git a/docs/v5.2.0/css/style.css b/docs/v5.2.0/css/style.css new file mode 100644 index 00000000..0d629119 --- /dev/null +++ b/docs/v5.2.0/css/style.css @@ -0,0 +1,312 @@ +/******** LAYOUT *********/ + +h1 { + font-size: 2.2em; + margin-top: 1em; +} + +h2 { + font-size: 2em; +} + +h2, h3 { + margin-top: 1em; + padding-top: 0.5em; +} + +h4, h5 { + margin-top: 1em; +} + +h1 + h2, +h2 + h3, +h2 + .method_details h3, +h4 + h5 { + margin-top: 0; +} + +#main h3 tt, +#sticky-header tt { + background: transparent; + border: none; + font-family: "Source Sans Pro", sans-serif; + font-size: 1em; + font-style: italic; + font-weight: normal; + padding: 0; +} + +#main h2, +#main h3, +#sticky-header h2, +#sticky-header h3 { + border: none; + padding-bottom: 0; +} + +#main h2, +#sticky-header h2 { + font-size: 1.8em; +} + +#main h3, +#sticky-header h3 { + font-size: 1.5em; + font-style: italic; +} + +#main h4, +#sticky-header h4 { + border-bottom: 1px solid rgba(0,0,0,0.3); + font-size: 1.4em; + font-style: italic; + padding-bottom: 2px; +} + +#main h5, +#sticky-header h5 { + font-size: 1.1em; +} + +#sticky-header h2, +#sticky-header h3, +#sticky-header h4 { + line-height: inherit; + margin: 0; + padding: 0; +} + +/* Header */ + +#header, #main { + position: absolute; +} + +#header { + left: 0; + right: 0; + top: 0; +} + +#menu, #search { + height: 6rem; + line-height: 6rem; + font-size: 1.1em; +} +#main { + top: 6rem; +} + +#menu { + float: left; + padding-left: 2em; + position: relative; + width: 45em; +} + +#menu .noframes { + display: inline; +} + +#search { + float: right; +} + + #search ul { + list-style: none; + } + + #search ul, #search li { + margin: 0; + padding: 0; + display: inline; + } + + #search a { + border-left: 1px solid rgba(0,0,0,0.3); + float: left; + padding: 0 2em; + text-align: center; + text-decoration: none; + -webkit-transition: 0.1s background-color, 0.1s color; + -moz-transition: 0.1s background-color, 0.1s color; + transition: 0.1s background-color, 0.1s color; + } + + #search a:hover { + background-color: #f0f8ff; + } + + #search .active a { + background-color: #136cc6; + border-left-color: #136cc6; + color: white; + } + + #search .active + li a { + border-left-color: #136cc6; + } + +#search_frame { + background: white; + border: 1px solid rgba(0,0,0,0.2); + box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.3); + height: 0; + opacity: 0; + position: absolute; + right: 0; + top: 100%; + -webkit-transition: 0.1s height ease-in-out, 0.1s opacity 0.05s; + -moz-transition: 0.1s height ease-in-out, 0.1s opacity 0.05s; + transition: 0.1s height ease-in-out, 0.1s opacity 0.05s; + width: 500px; + z-index: 9999; +} +#search_frame.open { + height: 500px; + opacity: 1; + -webkit-transition: 0.1s height ease-in-out, 0.1s opacity; + -moz-transition: 0.1s height ease-in-out, 0.1s opacity; + transition: 0.1s height ease-in-out, 0.1s opacity; +} + +/* Main */ + +#main { + border-top: 1px solid rgba(0,0,0,0.2); + bottom: 0; + left: 0; + overflow-y: auto; + right: 0; +} + +#content { + padding-bottom: 1.5em; + padding-left: 2em; + padding-right: 2em; +} + +#toc { + display: none; +} + +/* Footer */ + +#footer { + background-color: rgba(0,0,0,0.3); + color: white; + font-weight: 100; + padding: 10px; + text-align: center; + text-shadow: 0 1px 1px rgba(0,0,0,0.4); + font-size: 0.9em; +} + +#footer a { + color: #ffedd5; +} + +/* Class/Module */ + +.summary .deprecated { + display: none; +} + +.method_details {} + .method_details .signature .aliases { + display: none; + } + + .method_details td { + padding: 10px; + } + + .method_details .showSource { + display: block; + margin-bottom: 1em; + } + + .method_details .source_code { + border: 1px solid rgba(0,0,0,0.1); + display: none; + overflow: auto; + width: 100%; + } + + .method_details .source_code pre { + background-color: transparent; + border-radius: 0; + border: none; + color: inherit; + margin-bottom: 0; + padding: 0; + } + + .method_details .source_code td { + border: 1px solid rgba(0,0,0,0.1); + } + + .method_details .source_code td.lines { + background-color: #f0f0f0; + color: #93a1a1; + width: 50px; + } + + .method_details .source_code td.code { + background-color: #f8f8f8; + } + + .method_details .source_code td.code pre .info { + color: #93a1a1 /* Comment */ + } + + .method_details .deprecated { + margin-bottom: 1em; + font-size: 1.1em; + } + + .method_details .deprecated strong { + background-color: #F03434; + color: white; + text-transform: uppercase; + border-radius: 3px; + padding: 0 4px; + } + + .method_details .deprecated .inline { + padding-left: 3px; + } + + .method_details .deprecated div, + .method_details .deprecated p { + display: inline + } + +.docstring, .method_details .showSource, .method_details .source_code { + margin-left: 1em; +} + +#sticky-header { + background-color: rgba(255,255,255,0.8); + border-bottom: 1px solid rgba(0,0,0,0.2); + height: 3em; + line-height: 3em; + opacity: 0; + padding-left: 2em; /* same as content padding */ + padding-right: 2em; /* same as content padding */ + position: fixed; + text-align: right; + top: 6.1rem; + -webkit-transition: 0.1s opacity ease-in-out; + -moz-transition: 0.1s opacity ease-in-out; + transition: 0.1s opacity ease-in-out; + width: 100%; + z-index: 999; +} +#sticky-header.show { + opacity: 1; +} + +.clear { + clear: both; +} diff --git a/docs/v5.2.0/file.CHANGELOG.html b/docs/v5.2.0/file.CHANGELOG.html new file mode 100644 index 00000000..092c407b --- /dev/null +++ b/docs/v5.2.0/file.CHANGELOG.html @@ -0,0 +1,1392 @@ + + + + + + + File: CHANGELOG + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Changelog

+ +

5.2.0 - 2022-09-15

+ +

Features

+ +
    +
  • Add without_scopes method to enum matcher. (#1453)

  • +
  • Add support for Ruby 3.1. (#1474)

  • +
  • Add allow_blank method to validate_presence_of matcher. (#1499)

  • +
  • Add support for Rails 7.0. No new Rails 7.0 features are supported, but only +existing features that broke with the upgrade. (#1506)

  • +
+ +

5.1.0 - 2021-12-22

+ +

Bug fixes

+ +
    +
  • Fix the undefined method error for non rails project due to use of many? - method from ActiveSupport. (#1459)
  • +
+ +

Features

+ +
    +
  • Add array option support for have db column matcher. (#1465)

  • +
  • Add enum attributes support for validate_absence_of matcher. (#1464)

  • +
+ +

5.0.0 - 2021-07-09

+ +

Bug fixes

+ +
    +
  • Replace in?, method from ActiveSupport, with include? to prevent exception "undefined method in?" on non-Rails app. (#1405)
  • +
+ +

Features

+ +
    +
  • Add support for Rails 6.1. No new Rails 6.1 features are supported, but only +existing features that broke with the upgrade. (#1418)

  • +
  • Add support for RVM (Ruby Version Manager) to setting up local environment. (#1424)

  • +
  • Add support for alias in matcher define_enum. (#1419)

  • +
  • Add support for Ruby 3.0. (#1406, #1427)

  • +
+ +

Improvements

+ +
    +
  • Remove deprecated warnings emitted on Rails 6.1 in ActiveModel errors. (#1444)
  • +
+ +

Backward-incompatible changes

+ +
    +
  • Drop support for Rails 4.2, 5.0 and 5.1 as well as Ruby 2.4 and 2.5 +they've been end-of-lifed. The gem now supports Ruby 2.6+ and Rails 5.2+. (#1412, #1415, #1422, #1428, #1429)

  • +
  • Remove deprecated matchers: use_before_filter, use_after_filter, use_around_filter and allow_mass_assignment_of. (#1430, #1431)

  • +
+ +

5.0.0.rc1 - 2021-06-04

+ +

Bug fixes

+ +
    +
  • Replace in?, method from ActiveSupport, with include? to prevent exception "undefined method in?" on non-Rails app. (#1405)
  • +
+ +

Features

+ +
    +
  • Add support for Rails 6.1. No new Rails 6.1 features are supported, but only +existing features that broke with the upgrade. (#1418)

  • +
  • Add support for RVM (Ruby Version Manager) to setting up local environment. (#1424)

  • +
  • Add support for alias in matcher define_enum. (#1419)

  • +
  • Add support for Ruby 3.0. (#1406, #1427)

  • +
+ +

Backward-incompatible changes

+ +
    +
  • Drop support for Rails 4.2, 5.0 and 5.1 as well as Ruby 2.4 and 2.5 +they've been end-of-lifed. The gem now supports Ruby 2.6+ and Rails 5.2+. (#1412, #1415, #1422, #1428, #1429)

  • +
  • Remove deprecated matchers: use_before_filter, use_after_filter, use_around_filter and allow_mass_assignment_of. (#1430, #1431)

  • +
+ +

4.5.1 - 2021-01-15

+ +

Bug fixes

+ +
    +
  • Update belongs_to to work with composite primary keys. (#1396)
  • +
+ +

4.5.0 - 2020-12-28

+ +

Bug fixes

+ +
    +
  • Fix bundle exec yard doc replacing pygments.rb with rouge to keep the documentation up to date. (#1343)
  • +
  • Fix have_db_column.with_options not raising an error when the user adds an invalid value. (#1358)
  • +
  • Fix default value of assossiation_matcher.validate option. It was returning false instead of true. (#1378)
  • +
  • Fix validate_absence_of failing for array columns. (#1383)
  • +
+ +

Features

+ +
    +
  • Add support for has_secure_password custom attributes. (#1356)
  • +
+ +

Improvements

+ +
    +
  • Replace all links with http to https. (#1340)
  • +
  • Update the links for have_and_belong_to_many, have_many and have_one in the README to redirect the user to where the matcher description starts. (#1348)
  • +
  • Drop git ls-files in gemspec to help downstreams maintenance, because they often need to build packages in an environment that does not have git. (#1354)
  • +
  • Add comment about no support of validate_uniqueness_of(:item).scoped_to(array). (#1355)
  • +
  • Improve error message for assossiation_matcher.with_foreign_key option. (#1376)
  • +
+ +

4.4.1 - 2020-08-26

+ +

Bug fixes

+ +
    +
  • Revert reorganization around autoloading introduced in 4.4.0 which prevented +matchers from being loaded. (#1334)
  • +
+ +

4.4.0 - 2020-08-25

+ +

Bug fixes

+ +
    +
  • Fix performance of allow_value so that it doesn't hang if the given value is +really long. (#1290)

  • +
  • Fix have_many so that it is possible to test an association that has a scope +that takes an argument. (#952, #992)

  • +
  • Update validate_uniqueness_of to use the public validators_on instead of +the private _validators when reading validations off of a model. This +enables shoulda-matchers to be used with the schema_validations gem. +(#995)

  • +
  • Update validate_uniqueness_of to work with scopes that are time columns. +(#1190)

  • +
  • Fix have_and_belong_to_many so that when using the join_table qualifier +you can pass a symbol rather than a string. (#1323)

  • +
+ +

Features

+ +
    +
  • Add an ignoring_check_for_db_index qualifier to the have_secure_token +matcher, since has_secure_token encourages use of an index but does not +enforce it. (#1278)

  • +
  • Add allow_blank to validate_length_of to match other validation matchers. +(#725, #1318)

  • +
  • Add new matcher have_implicit_order_column which can be used to test the +implicit_order_column setting for ActiveRecord models under Rails 6+. +(#1243)

  • +
  • Add a new is_other_than qualifier to validate_numericality_of to be able +to test the numericality validation's :other_than option. (#1282)

  • +
  • Add a new have_one_attached and have_many_attached matchers for testing +the new model-level ActiveStorage macros in Rails 6. (#1102)

  • +
+ +

Improvements

+ +
    +
  • Update have_many when used against a :through association so that it fails +if the inverse model does not have a belongs_to association. (#646, +#723, c0a1578)

  • +
  • Add Ruby 2.7 to test matrix and default development Ruby. (#1310)

  • +
  • Remove warnings emitted on Ruby 2.7 in word_wrap. (#1314)

  • +
  • Remove warnings emitted on Ruby 2.7 in Doublespeak. (#1328)

  • +
  • Clean up requires within the code by converting them to autoloads. (#1320)

  • +
+ +

4.3.0 - 2020-02-18

+ +

Bug fixes

+ +
    +
  • Fix missing attribute:: scope 1 intermittent test. (#1274)
  • +
+ +

Features

+ +
    +
  • Add have_rich_text matcher for ActionText. (#1263)
  • +
+ +

Improvements

+ +
    +
  • Use range on validate_exclusion_of#in_range documentation. (#1273)
  • +
+ +

4.2.0 - 2020-01-29

+ +

Bug fixes

+ +
    +
  • Fix typos in documentation of allow_values. (#1241)

  • +
  • Fix appraisal command in CONTRIBUTING.md file. (#1253)

  • +
+ +

Features

+ +
    +
  • Add support for optional: false in belongs_to associations. +(#1237)

  • +
  • Add support for associations with inverse_of: false and non-standard foreign +key (#1106)

  • +
+ +

Improvements

+ +
    +
  • Remove minitest-reporters dependency. ([#1251])

  • +
  • Development dependency updates.

  • +
+ +

4.1.2 - 2019-08-01

+ +

Bug fixes

+ +
    +
  • Fix another regression with validate_presence_of so that it works against an +attribute that has been decorated with serialize using a custom serializer +class. (#1236)
  • +
+ +

4.1.1 - 2019-07-16

+ +

Bug fixes

+ +
    +
  • Patch some backward-incompatible changes to validate_presence_of that were +made in the last version. As of 4.1.0 the presence matcher now checks to +ensure that empty string will cause the record to be invalid (in addition to +nil, which it was already checking against). However, this check was being +performed even if the attribute or column the presence matcher is being run +against didn't support being set to an empty string. This releases fixes this. +(#1222, #1224, #1231)
  • +
+ +

4.1.0 - 2019-06-09

+ +

Bug fixes

+ +
    +
  • Fix validate_uniqueness_of so that it works when a scope is defined as a +string instead of a symbol on the model. (#1176)

  • +
  • Fix have_db_index so that it can be used against multiple models that are +connected to different databases. (#1200)

  • +
+ +

Features

+ +
    +
  • Add support for Rails 6. No new Rails 6 features are supported, but only +existing features that broke with the upgrade. (#1193)

  • +
  • Add support for expression indexes (Rails 5, Postgres only) to +have_db_index. (#1211)

  • +
  • Add allow_nil to the validate_presence_of matcher. (834d8d0, #1100)

  • +
+ +

Improvements

+ +
    +
  • Update validate_presence_of so that if it is being used against an +association which is required: true or optional: false, or it is not +configured as such but ActiveRecord defaults belong_to associations to +optional: false, and the matcher fails, the developer is reminded in the +failure message that the belong_to matcher can be used instead. (#1214, +8697b01)

  • +
  • Update define_enum_for so that it produces a more helpful message on +failure. (#1216)

  • +
+ +

4.0.1 - 2019-02-26

+ +

Bug fixes

+ +
    +
  • Fix gemspec so that setup script isn't installed globally when gem is +installed. (#1180)
  • +
+ +

4.0.0 - 2019-02-26 [YANKED]

+ +

This release mainly brings the gem up to date with modern versions of Ruby and +Rails and drops support for older, unsupported versions. The compatibility list +is now:

+ +
    +
  • Ruby: 2.6.0, 2.5.1, 2.4.4, 2.3.7
  • +
  • Rails: 5.2.2, 5.1.6.1, 5.0.7, 4.2.10
  • +
+ +

Backward-incompatible changes

+ +
    +
  • Drop support for Rails 4.0 and 4.1 as well as Ruby 2.0, 2.1, and 2.2, since +they've been end-of-lifed. The gem now supports Ruby 2.3+ and Rails 4.2+.

  • +
  • use_before_filter, use_after_filter, and use_around_filter are no longer +usable when using shoulda-matchers under Rails 5.x, as the corresponding +controller callbacks don't exist there. (#1054)

  • +
+ +

Deprecations

+ +
    +
  • define_enum_for: with is deprecated in favor of with_values. This is to +prevent confusion with with_prefix and with_suffix, which are new. +(#1077)
  • +
+ +

Bug fixes

+ +
    +
  • Fix association matchers when used under Rails 5.x so that they make use of +ActiveRecord::Base.connection.data_sources instead of +ActiveRecord::Base.connection.tables, which was deprecated. (#933, #943, +61c3654)

  • +
  • Fix the serialize matcher so that it works with Rails 5.x. (#913, #965, +df04f87)

  • +
  • Fix our custom mocking library Doublespeak, which is used by +delegate_method, so that it does not produce a warning under Ruby 2.4. +(#1006, #1038, 8d7dcb8)

  • +
  • Fix the permit matcher so that it uses the correct method signature to call +the controller action with params in order to prevent a warning under Rails +5.x. (#867, #917, #964, #989, ce9624b)

  • +
  • Fix the define_enum_for matcher so that it once more allows string columns +to be used as enum attributes. (#912, #1063, 5650aae)

  • +
  • Fix validate_uniqueness_of when used under Rails 4.2 so that when the +attribute you're testing is a boolean column, it will no longer emit a +warning. (#949, #1073)

  • +
  • Fix validate_inclusion_of so that if it fails, it will no longer blow up +with the error "undefined method `attribute_setter' for nil:NilClass". +(#904)

  • +
  • Add negative versions of all validation matchers (i.e. implement +does_not_match? for them) to prevent them from blowing up with +"undefined method `attribute_setter' for nil:NilClass". (#904)

  • +
+ +

Features

+ +
    +
  • Add required and optional qualifiers to belong_to and have_one +matchers. (When using the belong_to matcher under Rails 5+, required is +assumed unless overridden.) (#861, #870, #956, 3af3d9f)

  • +
  • Add without_validating_presence qualifier to belong_to to get around the +fact that required is assumed, above. (#1153, #1154)

  • +
  • Add allow_nil qualifier to delegate_method. (#798, d49cfca)

  • +
  • Add allow_nil qualifier to validate_length_of. (#724)

  • +
  • Add a port option to the route matcher to allow testing a route that has +a constraint on it such that only a specific port may be used to access that +route. (#954, #1074, #1075)

  • +
  • Add with_prefix and with_suffix to define_enum_for to allow testing +the enum macro with corresponding prefix and suffix options (Rails 5 +only). (#961, #1077)

  • +
  • Add index_errors option to has_many (Rails 5 only). (#1089, 795ca68)

  • +
+ +

Improvements

+ + + +

3.1.3 - 2019-01-29

+ +

Improvements

+ +
    +
  • Update BigDecimal.new() to use BigDecimal() and avoid deprecation warnings +in Ruby 2.6.
  • +
+ +

3.1.2 - 2017-07-12

+ +

Deprecations

+ +
    +
  • This is the last version that supports Rails 4.0 and 4.1 and Ruby 2.0 and +2.1.
  • +
+ +

Bug fixes

+ +
    +
  • When the permit matcher was used without #on, the controller did not use +params#require, the params object was duplicated, and the matcher did not +recognize the #permit call inside the controller. This behavior happened +because the matcher overwrote double registries with the same parameter hash +whenever ActionController::Parameters was instantiated. (#899, #902, +44c019)
  • +
+ +

3.1.1 - 2016-01-28

+ +

Bug fixes

+ +
    +
  • Some matchers make use of ActiveSupport's in? method, but do not include the +file where this is defined in ActiveSupport. This causes problems with +projects using shoulda-matchers that do not include all of ActiveSupport by +default. To fix this, replace in? with Ruby's builtin include?. (#879)

  • +
  • validate_uniqueness_of works by creating a record if it doesn't exist, and +then testing against a new record with various attributes set that are equal +to (or different than) corresponding attributes in the existing record. In +3.1.0 a change was made whereby when the uniqueness matcher is given a new +record and creates an existing record out of it, it ensures that the record is +valid before continuing on. This created a problem because if the subject, +before it was saved, was empty and therefore in an invalid state, it could not +effectively be saved. While ideally this should be enforced, doing so would be +a backward-incompatible change, so this behavior has been rolled back. +(#880, #884, #885, 45de869)

  • +
  • Fix an issue with validate_uniqueness_of + scoped_to when used against a +model where the attribute has multiple uniqueness validations and each +validation has a different set of scopes. In this case, a test written for the +first validation (and its scopes) would pass, but tests for the other +validations (and their scopes) would not, as the matcher only considered the +first set of scopes as the actual set of scopes. (#830, 28bd9a1)

  • +
+ +

Improvements

+ +
    +
  • Update validate_uniqueness_of so that if an existing record fails to be +created because a column is non-nullable and was not filled in, raise an +ExistingRecordInvalid exception with details on how to fix the test. +(78ccfc5)
  • +
+ +

3.1.0 - 2016-01-11

+ +

Bug fixes

+ +
    +
  • Update validate_numericality_of so that submatchers are applied lazily +instead of immediately. Previously, qualifiers were order-dependent, meaning +that if you used strict before you used, say, odd, then strict wouldn't +actually apply to odd. Now the order that you specify qualifiers doesn't +matter. (6c67a5e)

  • +
  • Fix allow_value so that it does not raise an AttributeChangedValueError +(formerly CouldNotSetAttributeError) when used against an attribute that is an +enum in an ActiveRecord model. (9e8603e)

  • +
  • Add a ignoring_interference_by_writer qualifier to all matchers, not just +allow_value. This is enabled by default, which means that you should never +get a CouldNotSetAttributeError again. (You may get some more information if +a test fails, however.) (#786, #799, #801, #804, #817, #841, +#849, #872, #873, #874, 1189934, 5532f43)

  • +
  • Fix validate_numericality_of so that it does not blow up when used against +a virtual attribute defined in an ActiveRecord model (that is, an attribute +that is not present in the database but is defined using attr_accessor). +(#822)

  • +
  • Update validate_numericality_of so that it no longer raises an +IneffectiveTestError if used against a numeric column. (#832, 5ed0362)

  • +
+ +

Features

+ +
    +
  • Add a new qualifier, ignoring_case_sensitivity, to validate_uniqueness_of. +This provides a way to test uniqueness of an attribute whose case is +normalized, either in a custom writer method for that attribute, or in a +custom before_validation callback. (#836, #840)
  • +
+ +

Improvements

+ +
    +
  • Improve failure messages and descriptions of all matchers across the board so +that it is easier to understand what the matcher was doing when it failed. +(You'll see a huge difference in the output of the numericality and uniqueness +matchers in particular.)

  • +
  • Matchers now raise an error if any attributes that the matcher is attempting +to set do not exist on the model. (2962112)

  • +
  • Update validate_numericality_of so that it doesn't always run all of the +submatchers, but stops on the first one that fails. Since failure messages +now contain information as to what value the matcher set on the attribute when +it failed, this change guarantees that the correct value will be shown. +(8e24a6e)

  • +
  • Continue to detect if attributes change incoming values, but now instead of +immediately seeing a CouldNotSetAttributeError, you will only be informed +about it if the test you've written fails. (1189934)

  • +
  • Add an additional check to define_enum_for to ensure that the column that +underlies the enum attribute you're testing is an integer column. (68dd70a)

  • +
  • Add a test for validate_numericality_of so that it officially supports money +columns. (#841, a559713)

  • +
+ +

3.0.1 - 2015-10-23

+ +

Bug fixes

+ +
    +
  • Fix validate_inclusion_of + in_array when used against a date or datetime +column/attribute so that it does not raise a CouldNotSetAttributeError. +(#783, 8fa97b4)

  • +
  • Fix validate_numericality_of when used against a numeric column so that it +no longer raises a CouldNotSetAttributeError if the matcher has been qualified +in any way (only_integer, greater_than, odd, etc.). (#784, #812)

  • +
+ +

Improvements

+ +
    +
  • validate_uniqueness_of now raises a NonCaseSwappableValueError if the value +the matcher is using to test uniqueness cannot be case-swapped -- in other +words, if it doesn't contain any alpha characters. When this is the case, the +matcher cannot work effectively. (#789, ada9bd3)
  • +
+ +

3.0.0 - 2015-10-01

+ +

Backward-incompatible changes

+ +
    +
  • We've dropped support for Rails 3.x, Ruby 1.9.2, and Ruby 1.9.3, and RSpec 2. +All of these have been end-of-lifed. (a4045a1, b7fe87a, 32c0e62)

  • +
  • The gem no longer detects the test framework you're using or mixes itself into +that framework automatically. History has +shown that performing any kind of detection is prone +to bugs and more complicated than it should be.

  • +
+ +

Here are the updated instructions:

+ +
    +
  • You no longer need to say require: false in your Gemfile; you can +include the gem as normal.
  • +
  • You'll need to add the following somewhere in your rails_helper (for +RSpec) or test_helper (for Minitest / Test::Unit):

    + +
    Shoulda::Matchers.configure do |config|
    +  config.integrate do |with|
    +    # Choose a test framework:
    +    with.test_framework :rspec
    +    with.test_framework :minitest
    +    with.test_framework :minitest_4
    +    with.test_framework :test_unit
    +
    +    # Choose one or more libraries:
    +    with.library :active_record
    +    with.library :active_model
    +    with.library :action_controller
    +    # Or, choose the following (which implies all of the above):
    +    with.library :rails
    +  end
    +end
    +
  • +
+ +

(1900071)

+ +
    +
  • Previously, under RSpec, all of the matchers were mixed into all of the +example groups. This created a problem because some gems, such as +active_model_serializers-matchers, provide matchers that share the same +name as some of our own matchers. Now, matchers are only mixed into whichever +example group they belong to:

    + +
      +
    • ActiveModel and ActiveRecord matchers are available only in model example +groups.
    • +
    • ActionController matchers are available only in controller example groups.
    • +
    • The route matcher is available only in routing example groups.
    • +
  • +
+ +

(af98a23, 8cf449b)

+ +
    +
  • There are two changes to allow_value:

    + +
      +
    • The negative form of allow_value has been changed so that instead of +asserting that any of the given values is an invalid value (allowing good +values to pass through), assert that all values are invalid values +(allowing good values not to pass through). This means that this test which +formerly passed will now fail:
    • +
    + +
    expect(record).not_to allow_value('good value', *bad_values)
    +
    + +

    (19ce8a6)

    + +
      +
    • allow_value now raises a CouldNotSetAttributeError if in setting the +attribute, the value of the attribute from reading the attribute back is +different from the one used to set it.
    • +
    + +

    This would happen if the writer method for that attribute has custom logic +to ignore certain incoming values or change them in any way. Here are three +examples we've seen:

    + +
      +
    • You're attempting to assert that an attribute should not allow nil, yet +the attribute's writer method contains a conditional to do nothing if +the attribute is set to nil:
    • +
    + +
      class Foo
    +    include ActiveModel::Model
    +
    +    attr_reader :bar
    +
    +    def bar=(value)
    +      return if value.nil?
    +      @bar = value
    +    end
    +  end
    +
    +  describe Foo do
    +    it do
    +      foo = Foo.new
    +      foo.bar = "baz"
    +      # This will raise a CouldNotSetAttributeError since `foo.bar` is now "123"
    +      expect(foo).not_to allow_value(nil).for(:bar)
    +    end
    +  end
    +
    + +
      +
    • You're attempting to assert that an numeric attribute should not allow a +string that contains non-numeric characters, yet the writer method for +that attribute strips out non-numeric characters:
    • +
    + +
      class Foo
    +    include ActiveModel::Model
    +
    +    attr_reader :bar
    +
    +    def bar=(value)
    +      @bar = value.gsub(/\D+/, '')
    +    end
    +  end
    +
    +  describe Foo do
    +    it do
    +      foo = Foo.new
    +      # This will raise a CouldNotSetAttributeError since `foo.bar` is now "123"
    +      expect(foo).not_to allow_value("abc123").for(:bar)
    +    end
    +  end
    +
    + +
      +
    • You're passing a value to allow_value that the model typecasts into +another value:
    • +
    + +
      describe Foo do
    +    # Assume that `attr` is a string
    +    # This will raise a CouldNotSetAttributeError since `attr` typecasts `[]` to `"[]"`
    +    it { should_not allow_value([]).for(:attr) }
    +  end
    +
    + +

    With all of these failing examples, why are we making this change? We want +to guard you (as the developer) from writing a test that you think acts one +way but actually acts a different way, as this could lead to a confusing +false positive or negative.

    + +

    If you understand the problem and wish to override this behavior so that +you do not get a CouldNotSetAttributeError, you can add the +ignoring_interference_by_writer qualifier like so. Note that this will not +always cause the test to pass.

    + +
    it { should_not allow_value([]).for(:attr).ignoring_interference_by_writer }
    +
    + +

    (9d9dc4e)

  • +
  • validate_uniqueness_of is now properly case-sensitive by default, to match +the default behavior of the validation itself. This is a backward-incompatible +change because this test which incorrectly passed before will now fail:

    + +
    class Product < ActiveRecord::Base
    +  validates_uniqueness_of :name, case_sensitive: false
    +end
    +
    +describe Product do
    +  it { is_expected.to validate_uniqueness_of(:name) }
    +end
    +
    + +

    (57a1922)

  • +
  • ensure_inclusion_of, ensure_exclusion_of, and ensure_length_of have been +removed in favor of their validate_* counterparts. (55c8d09)

  • +
  • set_the_flash and set_session have been changed to more closely align with +each other:

    + +
      +
    • set_the_flash has been removed in favor of set_flash. (801f2c7)
    • +
    • set_session('foo') is no longer valid syntax, please use +set_session['foo'] instead. (535fe05)
    • +
    • set_session['key'].to(nil) will no longer pass when the key in question +has not been set yet. (535fe05)
    • +
  • +
  • Change set_flash so that set_flash[:foo].now is no longer valid syntax. +You'll want to use set_flash.now[:foo] instead. This was changed in order to +more closely align with how flash.now works when used in a controller. +(#755, #752)

  • +
  • Change behavior of validate_uniqueness_of when the matcher is not +qualified with any scopes, but your validation is. Previously the following +test would pass when it now fails:

  • +
+ +
  class Post < ActiveRecord::Base
+    validate :slug, uniqueness: { scope: :user_id }
+  end
+
+  describe Post do
+    it { should validate_uniqueness_of(:slug) }
+  end
+
+ +

(6ac7b81)

+ +

Bug fixes

+ +
    +
  • So far the tests for the gem have been running against only SQLite. Now they +run against PostgreSQL, too. As a result we were able to fix some +Postgres-related bugs, specifically around validate_uniqueness_of:

    + +
      +
    • When scoped to a UUID column that ends in an "f", the matcher is able to +generate a proper "next" value without erroring. (#402, #587, #662)
    • +
    • Support scopes that are PostgreSQL array columns. Please note that this is +only supported for Rails 4.2 and greater, as versions before this cannot +handle array columns correctly, particularly in conjunction with the +uniqueness validator. (#554)
    • +
    • Fix so that when scoped to a text column and the scope is set to nil before +running it through the matcher, the matcher does not fail. (#521, #607)
    • +
  • +
  • Fix define_enum_for so that it actually tests that the attribute is present +in the list of defined enums, as you could fool it by merely defining a class +method that was the pluralized version of the attribute name. In the same +vein, passing a pluralized version of the attribute name to define_enum_for +would erroneously pass, and now it fails. (#641)

  • +
  • Fix permit so that it does not break the functionality of +ActionController::Parameters#require. (#648, #675)

  • +
  • Fix validate_uniqueness_of + scoped_to so that it does not raise an error +if a record exists where the scoped attribute is nil. (#677)

  • +
  • Fix route matcher so if your route includes a default format, you can +specify this as a symbol or string. (#693)

  • +
  • Fix validate_uniqueness_of so that it allows you to test against scoped +attributes that are boolean columns. (#457, #694)

  • +
  • Fix failure message for validate_numericality_of as it sometimes didn't +provide the reason for failure. (#699)

  • +
  • Fix shoulda/matchers/independent so that it can be required +independently, without having to require all of the gem. (#746, e0a0200)

  • +
+ +

Features

+ +
    +
  • Add on qualifier to permit. This allows you to make an assertion that +a restriction was placed on a slice of the params hash and not the entire +params hash. Although we don't require you to use this qualifier, we do +recommend it, as it's a more precise check. (#675)

  • +
  • Add strict qualifier to validate_numericality_of. (#620)

  • +
  • Add on qualifier to validate_numericality_of. (9748869; h/t #356, +#358)

  • +
  • Add join_table qualifier to have_and_belong_to_many. (#556)

  • +
  • allow_values is now an alias for allow_value. This makes more sense when +checking against multiple values:

  • +
+ +
  it { should allow_values('this', 'and', 'that') }
+
+ +

(#692)

+ +

2.8.0 - 2015-01-30

+ +

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)

  • +
+ +

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.
  • +
+ +

2.7.0 - 2014-09-03

+ +

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 - 2014-07-19

+ +

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 - 2014-04-30

+ +

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 - 2014-04-12

+ +
    +
  • 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
    • +
  • +
+ +

2.5.0 - 2014-01-10

+ +
    +
  • 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.

  • +
+ +

2.4.0 - 2013-09-20

+ +
    +
  • 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).

  • +
+ +

2.3.0 - 2013-08-16

+ +
    +
  • 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.

  • +
+ +

2.2.0 - 2013-06-11

+ +
    +
  • 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).

  • +
+ +

2.1.0 - 2013-05-05

+ +
    +
  • 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.

  • +
+ +

2.0.0 - 2013-04-05

+ +
    +
  • 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: +https://robots.thoughtbot.com/post/47031676783/shoulda-matchers-2-0.

+ +

1.5.6 - 2013-03-29

+ +
    +
  • Revert previous change in AllowValueMatcher that added a check for a +properly-set attribute.
  • +
+ +

1.5.5 - 2013-03-28

+ +
    +
  • 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.

  • +
+ +

1.5.4 - 2013-03-21

+ +
    +
  • Properly-released version of 1.5.3.
  • +
+ +

1.5.3 - 2013-03-21 [YANKED]

+ +
    +
  • Alleviate the need to add rspec gem to your app.
  • +
+ +

1.5.2 - 2013-03-19

+ +

???

+ +

1.5.1 - 2013-03-19

+ +
    +
  • Bump version dependency of Bourne to allow for Mocha upgrade.

  • +
  • Should fix incompatibility with MiniTest.

  • +
+ +

1.5.0 - 2013-03-15

+ +
    +
  • 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).

  • +
+ +

1.4.2 - 2012-11-30

+ +
    +
  • Add a new delegate_method matcher.
  • +
+ +

1.4.1 - 2012-10-15

+ +
    +
  • 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.

  • +
+ +

1.4.0 - 2012-10-05

+ +
    +
  • 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.

  • +
+ +

1.3.0 - 2012-08-30

+ +
    +
  • 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".

  • +
+ +

1.2.0 - 2012-06-14

+ +
    +
  • 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.

  • +
+ +

1.1.0 - 2012-04-13

+ +
    +
  • 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

  • +
+ +

1.0.0 - 2011-11-02

+ +

First release!

+
+ + + +
+ + + diff --git a/docs/v5.2.0/file.NonCaseSwappableValueError.html b/docs/v5.2.0/file.NonCaseSwappableValueError.html new file mode 100644 index 00000000..b8edd8bb --- /dev/null +++ b/docs/v5.2.0/file.NonCaseSwappableValueError.html @@ -0,0 +1,217 @@ + + + + + + + File: NonCaseSwappableValueError + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

NonCaseSwappableValueError

+ +

This error is raised when using validate_uniqueness_of. This matcher, of +course, tests that an attribute disallows a non-unique value -- and what +constitutes as "unique" depends on whether the case-sensitivity of that value +matters. If it does matter -- meaning that the uniqueness validation in your +model isn't using case_sensitive: false and you haven't qualified the matcher +with case_insensitive -- then the matcher will run the following test:

+ +
+

Creating first a record with a value of "A":

+ +
    +
  • A new record with a value of "A" should not be valid (failing the uniqueness +validation)
  • +
  • A new record with a value of "a" should be valid
  • +
+
+ +

The test value we're using is in this case "A", and this is what the matcher +will use if an existing record is not already present in the database. But if +a record already exists, then the matcher will use it as comparison -- it will +read the attribute under test off of the record and use its value. So a better +example might be:

+ +
+

Given an existing record with a value:

+ +
    +
  • A new record with the same value should not be valid (failing the uniqueness +validation)
  • +
  • A new record with the same value, but where the case is swapped (using +String#swapcase), should be valid
  • +
+
+ +

Now, what happens if an existing record is there, but the value being used is +not one whose case can be swapped, such as "123" or "{-#%}"? Then the second +assertion cannot be made effectively.

+ +

So this is why you're getting this exception. What can you do about it? As the +error message explains, you have two options:

+ +
    +
  1. If you want the uniqueness validation in the model to operate +case-sensitively and you didn't mean to use a non-case-swappable value, +then you need to provide an existing record with a different value, one that +contains alpha characters. Here's an example:

    + +
    # Model
    +class User < ActiveRecord::Base
    +  validates_uniqueness_of :username
    +end
    +
    +# RSpec
    +RSpec.describe User, type: :model do
    +  context "validations" do
    +    subject do
    +      # Note that "123" == "123".swapcase. This is a problem!
    +      User.new(username: "123")
    +    end
    +
    +    it do
    +      # So you can either override it like this, or just fix the subject.
    +      user = User.create!(username: "john123")
    +      expect(user).to validate_uniqueness_of(:username)
    +    end
    +  end
    +end
    +
    +# Minitest (Shoulda)
    +class UserTest < ActiveSupport::TestCase
    +  context "validations" do
    +    subject do
    +      # Note that "123" == "123".swapcase. This is a problem!
    +      User.new(username: "123")
    +    end
    +
    +    should "validate uniqueness of :username" do
    +      # So you can either override it like this, or just fix the subject.
    +      user = User.create!(username: "john123")
    +      assert_accepts validate_uniqueness_of(:username), record
    +    end
    +  end
    +end
    +
  2. +
  3. If you don't want the uniqueness validation to operate case-sensitively, +then you need to add case_sensitive: false to the validation and add +case_insensitive to the matcher:

    + +
    # Model
    +class User < ActiveRecord::Base
    +  validates_uniqueness_of :username, case_sensitive: false
    +end
    +
    +# RSpec
    +RSpec.describe User, type: :model do
    +  context "validations" do
    +    subject do
    +      # Note that "123" == "123".swapcase, but it's okay
    +      User.new(username: "123")
    +    end
    +
    +    it { should validate_uniqueness_of(:username).case_insensitive }
    +  end
    +end
    +
    +# Minitest (Shoulda)
    +class UserTest < ActiveSupport::TestCase
    +  context "validations" do
    +    subject do
    +      # Note that "123" == "123".swapcase, but it's okay
    +      User.new(username: "123")
    +    end
    +
    +    should validate_uniqueness_of(:username).case_insensitive
    +  end
    +end
    +
  4. +
+
+ + + +
+ + + diff --git a/docs/v5.2.0/file.README.html b/docs/v5.2.0/file.README.html new file mode 100644 index 00000000..625439ac --- /dev/null +++ b/docs/v5.2.0/file.README.html @@ -0,0 +1,592 @@ + + + + + + + File: README + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Shoulda Matchers Gem Version Build Status Total Downloads Downloads

+ +

shoulda-matchers

+ +

Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test +common Rails functionality that, if written by hand, would be much longer, more +complex, and error-prone.

+ + + +

📖 Read the documentation for the latest version. +📢 See what's changed in recent versions.

+ +

Table of contents

+ + + +

Getting started

+ +

RSpec

+ +

Start by including shoulda-matchers in your Gemfile:

+ +
group :test do
+  gem 'shoulda-matchers', '~> 5.0'
+end
+
+ +

Then run bundle install.

+ +

Now you need to configure the gem by telling it:

+ +
    +
  • which matchers you want to use in your tests
  • +
  • that you're using RSpec so that it can make those matchers available in +your example groups
  • +
+ +

Rails apps

+ +

If you're working on a Rails app, simply place this at the bottom of +spec/rails_helper.rb (or in a support file if you so choose):

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :rspec
+    with.library :rails
+  end
+end
+
+ +

Non-Rails apps

+ +

If you're not working on a Rails app, but you still make use of ActiveRecord or +ActiveModel in your project, you can still use this gem too! In that case, +you'll want to place the following configuration at the bottom of +spec/spec_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :rspec
+
+    # Keep as many of these lines as are necessary:
+    with.library :active_record
+    with.library :active_model
+  end
+end
+
+ +

Minitest

+ +

If you're using our umbrella gem Shoulda, then make sure that you're using the +latest version:

+ +
group :test do
+  gem 'shoulda', '~> 4.0'
+end
+
+ +

Otherwise, add shoulda-matchers to your Gemfile:

+ +
group :test do
+  gem 'shoulda-matchers', '~> 5.0'
+end
+
+ +

Then run bundle install.

+ +

Now you need to configure the gem by telling it:

+ +
    +
  • which matchers you want to use in your tests
  • +
  • that you're using Minitest so that it can make those matchers available in +your test case classes
  • +
+ +

Rails apps

+ +

If you're working on a Rails app, simply place this at the bottom of +test/test_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :minitest
+    with.library :rails
+  end
+end
+
+ +

Non-Rails apps

+ +

If you're not working on a Rails app, but you still make use of ActiveRecord or +ActiveModel in your project, you can still use this gem too! In that case, +you'll want to place the following configuration at the bottom of +test/test_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :minitest
+
+    # Keep as many of these lines as are necessary:
+    with.library :active_record
+    with.library :active_model
+  end
+end
+
+ +

Usage

+ +

Most of the matchers provided by this gem are useful in a Rails context, and as +such, can be used for different parts of a Rails app:

+ + + +

As the name of the gem indicates, most matchers are designed to be used in +"one-liner" form using the should macro, a special directive available in both +RSpec and Shoulda. For instance, a model test case may look something like:

+ +
# RSpec
+RSpec.describe MenuItem, type: :model do
+  describe 'associations' do
+    it { should belong_to(:category).class_name('MenuCategory') }
+  end
+
+  describe 'validations' do
+    it { should validate_presence_of(:name) }
+    it { should validate_uniqueness_of(:name).scoped_to(:category_id) }
+  end
+end
+
+# Minitest (Shoulda)
+class MenuItemTest < ActiveSupport::TestCase
+  context 'associations' do
+    should belong_to(:category).class_name('MenuCategory')
+  end
+
+  context 'validations' do
+    should validate_presence_of(:name)
+    should validate_uniqueness_of(:name).scoped_to(:category_id)
+  end
+end
+
+ +

See below for the full set of matchers that you can use.

+ +

On the subject of subject

+ +

For both RSpec and Shoulda, the subject is an implicit reference to the +object under test, and through the use of should as demonstrated above, all of +the matchers make use of subject internally when they are run. A subject is +always set automatically by your test framework in any given test case; however, +in certain cases it can be advantageous to override it. For instance, when +testing validations in a model, it is customary to provide a valid model instead +of a fresh one:

+ +
# RSpec
+RSpec.describe Post, type: :model do
+  describe 'validations' do
+    # Here we're using FactoryBot, but you could use anything
+    subject { build(:post) }
+
+    it { should validate_presence_of(:title) }
+  end
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  context 'validations' do
+    subject { build(:post) }
+
+    should validate_presence_of(:title)
+  end
+end
+
+ +

When overriding the subject in this manner, then, it's important to provide the +correct object. When in doubt, provide an instance of the class under test. +This is particularly necessary for controller tests, where it is easy to +accidentally write something like:

+ +
RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    subject { get :index }
+
+    # This may work...
+    it { should have_http_status(:success) }
+    # ...but this will not!
+    it { should permit(:title, :body).for(:post) }
+  end
+end
+
+ +

In this case, you would want to use before rather than subject:

+ +
RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    before { get :index }
+
+    # Notice that we have to assert have_http_status on the response here...
+    it { expect(response).to have_http_status(:success) }
+    # ...but we do not have to provide a subject for render_template
+    it { should render_template('index') }
+  end
+end
+
+ +

Availability of RSpec matchers in example groups

+ +

Rails projects

+ +

If you're using RSpec, then you're probably familiar with the concept of example +groups. Example groups can be assigned tags order to assign different behavior +to different kinds of example groups. This comes into play especially when using +rspec-rails, where, for instance, controller example groups, tagged with +type: :controller, are written differently than request example groups, tagged +with type: :request. This difference in writing style arises because +rspec-rails mixes different behavior and methods into controller example +groups vs. request example groups.

+ +

Relying on this behavior, Shoulda Matchers automatically makes certain matchers +available in certain kinds of example groups:

+ +
    +
  • ActiveRecord and ActiveModel matchers are available only in model example +groups, i.e., those tagged with type: :model or in files located under +spec/models.
  • +
  • ActionController matchers are available only in controller example groups, +i.e., those tagged with type: :controller or in files located under +spec/controllers.
  • +
  • The route matcher is available in routing example groups, i.e., those +tagged with type: :routing or in files located under spec/routing.
  • +
  • Independent matchers are available in all example groups.
  • +
+ +

As long as you're using Rails, you don't need to worry about these details — +everything should "just work".

+ +

Non-Rails projects

+ +

What if you are using ActiveModel or ActiveRecord outside of Rails, however, +and you want to use model matchers in a certain example group? Then you'll +need to manually include the module that holds those matchers into that example +group. For instance, you might have to say:

+ +
RSpec.describe MySpecialModel do
+  include Shoulda::Matchers::ActiveModel
+  include Shoulda::Matchers::ActiveRecord
+end
+
+ +

If you have a lot of similar example groups in which you need to do this, then +you might find it more helpful to tag your example groups appropriately, then +instruct RSpec to mix these modules into any example groups that have that tag. +For instance, you could add this to your rails_helper.rb:

+ +
RSpec.configure do |config|
+  config.include(Shoulda::Matchers::ActiveModel, type: :model)
+  config.include(Shoulda::Matchers::ActiveRecord, type: :model)
+end
+
+ +

And from then on, you could say:

+ +
RSpec.describe MySpecialModel, type: :model do
+  # ...
+end
+
+ +

should vs is_expected.to

+ +

In this README and throughout the documentation, you'll notice that we use the +should form of RSpec's one-liner syntax over is_expected.to. Beside being +the namesake of the gem itself, this is our preferred syntax as it's short and +sweet. But if you prefer to use is_expected.to, you can do that too:

+ +
RSpec.describe Person, type: :model do
+  it { is_expected.to validate_presence_of(:name) }
+end
+
+ +

Matchers

+ +

Here is the full list of matchers that ship with this gem. If you need details +about any of them, make sure to consult the documentation!

+ +

ActiveModel matchers

+ + + +

ActiveRecord matchers

+ + + +

ActionController matchers

+ +
    +
  • filter_param +tests parameter filtering configuration.
  • +
  • permit tests +that an action places a restriction on the params hash.
  • +
  • redirect_to +tests that an action redirects to a certain location.
  • +
  • render_template +tests that an action renders a template.
  • +
  • render_with_layout +tests that an action is rendered with a certain layout.
  • +
  • rescue_from +tests usage of the rescue_from macro.
  • +
  • respond_with +tests that an action responds with a certain status code.
  • +
  • route tests +your routes.
  • +
  • set_session +makes assertions on the session hash.
  • +
  • set_flash +makes assertions on the flash hash.
  • +
  • use_after_action +tests that an after_action callback is defined in your controller.
  • +
  • use_around_action +tests that an around_action callback is defined in your controller.
  • +
  • use_before_action +tests that a before_action callback is defined in your controller.
  • +
+ +

Routing matchers

+ +
    +
  • route tests +your routes.
  • +
+ +

Independent matchers

+ +
    +
  • delegate_method +tests that an object forwards messages to other, internal objects by way of +delegation.
  • +
+ +

Extensions

+ +

Over time our community has created extensions to Shoulda Matchers. If you've +created something that you want to share, please let us know!

+ + + +

Contributing

+ +

Have a fix for a problem you've been running into or an idea for a new feature +you think would be useful? Take a look at the Contributing +document for instructions on setting up the repo on your +machine, understanding the codebase, and creating a good pull request.

+ +

Compatibility

+ +

Shoulda Matchers is tested and supported against Ruby 2.6+, Rails +5.2+, RSpec 3.x, and Minitest 5.x.

+ +
    +
  • For Ruby < 2.4 and Rails < 4.1 compatibility, please use v3.1.3.
  • +
  • For Ruby < 3.0 and Rails < 6.1 compatibility, please use v4.5.1.
  • +
+ +

Versioning

+ +

Shoulda Matchers follows Semantic Versioning 2.0 as defined at +https://semver.org.

+ +

Team

+ +

Shoulda Matchers is maintained by Elliot Winkler and Gui +Albuk.

+ + + +

Shoulda Matchers is copyright © 2006-2022 Tammer Saleh and thoughtbot, +inc. It is free and opensource software and may be +redistributed under the terms specified in the LICENSE file.

+ +

About thoughtbot

+ +

thoughtbot

+ +

The names and logos for thoughtbot are trademarks of thoughtbot, inc.

+ +

We are passionate about open source software. See our other +projects. We are available for hire.

+
+ + + +
+ + + diff --git a/docs/v5.2.0/file_list.html b/docs/v5.2.0/file_list.html new file mode 100644 index 00000000..ac47f212 --- /dev/null +++ b/docs/v5.2.0/file_list.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + File List + + + +
+

File List

+ + +
+ + diff --git a/docs/v5.2.0/frames.html b/docs/v5.2.0/frames.html new file mode 100644 index 00000000..691af4e9 --- /dev/null +++ b/docs/v5.2.0/frames.html @@ -0,0 +1,17 @@ + + + + + Documentation by YARD 0.9.25 + + + + diff --git a/docs/v5.2.0/index.html b/docs/v5.2.0/index.html new file mode 100644 index 00000000..625439ac --- /dev/null +++ b/docs/v5.2.0/index.html @@ -0,0 +1,592 @@ + + + + + + + File: README + + — Documentation by YARD 0.9.25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Shoulda Matchers Gem Version Build Status Total Downloads Downloads

+ +

shoulda-matchers

+ +

Shoulda Matchers provides RSpec- and Minitest-compatible one-liners to test +common Rails functionality that, if written by hand, would be much longer, more +complex, and error-prone.

+ + + +

📖 Read the documentation for the latest version. +📢 See what's changed in recent versions.

+ +

Table of contents

+ + + +

Getting started

+ +

RSpec

+ +

Start by including shoulda-matchers in your Gemfile:

+ +
group :test do
+  gem 'shoulda-matchers', '~> 5.0'
+end
+
+ +

Then run bundle install.

+ +

Now you need to configure the gem by telling it:

+ +
    +
  • which matchers you want to use in your tests
  • +
  • that you're using RSpec so that it can make those matchers available in +your example groups
  • +
+ +

Rails apps

+ +

If you're working on a Rails app, simply place this at the bottom of +spec/rails_helper.rb (or in a support file if you so choose):

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :rspec
+    with.library :rails
+  end
+end
+
+ +

Non-Rails apps

+ +

If you're not working on a Rails app, but you still make use of ActiveRecord or +ActiveModel in your project, you can still use this gem too! In that case, +you'll want to place the following configuration at the bottom of +spec/spec_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :rspec
+
+    # Keep as many of these lines as are necessary:
+    with.library :active_record
+    with.library :active_model
+  end
+end
+
+ +

Minitest

+ +

If you're using our umbrella gem Shoulda, then make sure that you're using the +latest version:

+ +
group :test do
+  gem 'shoulda', '~> 4.0'
+end
+
+ +

Otherwise, add shoulda-matchers to your Gemfile:

+ +
group :test do
+  gem 'shoulda-matchers', '~> 5.0'
+end
+
+ +

Then run bundle install.

+ +

Now you need to configure the gem by telling it:

+ +
    +
  • which matchers you want to use in your tests
  • +
  • that you're using Minitest so that it can make those matchers available in +your test case classes
  • +
+ +

Rails apps

+ +

If you're working on a Rails app, simply place this at the bottom of +test/test_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :minitest
+    with.library :rails
+  end
+end
+
+ +

Non-Rails apps

+ +

If you're not working on a Rails app, but you still make use of ActiveRecord or +ActiveModel in your project, you can still use this gem too! In that case, +you'll want to place the following configuration at the bottom of +test/test_helper.rb:

+ +
Shoulda::Matchers.configure do |config|
+  config.integrate do |with|
+    with.test_framework :minitest
+
+    # Keep as many of these lines as are necessary:
+    with.library :active_record
+    with.library :active_model
+  end
+end
+
+ +

Usage

+ +

Most of the matchers provided by this gem are useful in a Rails context, and as +such, can be used for different parts of a Rails app:

+ + + +

As the name of the gem indicates, most matchers are designed to be used in +"one-liner" form using the should macro, a special directive available in both +RSpec and Shoulda. For instance, a model test case may look something like:

+ +
# RSpec
+RSpec.describe MenuItem, type: :model do
+  describe 'associations' do
+    it { should belong_to(:category).class_name('MenuCategory') }
+  end
+
+  describe 'validations' do
+    it { should validate_presence_of(:name) }
+    it { should validate_uniqueness_of(:name).scoped_to(:category_id) }
+  end
+end
+
+# Minitest (Shoulda)
+class MenuItemTest < ActiveSupport::TestCase
+  context 'associations' do
+    should belong_to(:category).class_name('MenuCategory')
+  end
+
+  context 'validations' do
+    should validate_presence_of(:name)
+    should validate_uniqueness_of(:name).scoped_to(:category_id)
+  end
+end
+
+ +

See below for the full set of matchers that you can use.

+ +

On the subject of subject

+ +

For both RSpec and Shoulda, the subject is an implicit reference to the +object under test, and through the use of should as demonstrated above, all of +the matchers make use of subject internally when they are run. A subject is +always set automatically by your test framework in any given test case; however, +in certain cases it can be advantageous to override it. For instance, when +testing validations in a model, it is customary to provide a valid model instead +of a fresh one:

+ +
# RSpec
+RSpec.describe Post, type: :model do
+  describe 'validations' do
+    # Here we're using FactoryBot, but you could use anything
+    subject { build(:post) }
+
+    it { should validate_presence_of(:title) }
+  end
+end
+
+# Minitest (Shoulda)
+class PostTest < ActiveSupport::TestCase
+  context 'validations' do
+    subject { build(:post) }
+
+    should validate_presence_of(:title)
+  end
+end
+
+ +

When overriding the subject in this manner, then, it's important to provide the +correct object. When in doubt, provide an instance of the class under test. +This is particularly necessary for controller tests, where it is easy to +accidentally write something like:

+ +
RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    subject { get :index }
+
+    # This may work...
+    it { should have_http_status(:success) }
+    # ...but this will not!
+    it { should permit(:title, :body).for(:post) }
+  end
+end
+
+ +

In this case, you would want to use before rather than subject:

+ +
RSpec.describe PostsController, type: :controller do
+  describe 'GET #index' do
+    before { get :index }
+
+    # Notice that we have to assert have_http_status on the response here...
+    it { expect(response).to have_http_status(:success) }
+    # ...but we do not have to provide a subject for render_template
+    it { should render_template('index') }
+  end
+end
+
+ +

Availability of RSpec matchers in example groups

+ +

Rails projects

+ +

If you're using RSpec, then you're probably familiar with the concept of example +groups. Example groups can be assigned tags order to assign different behavior +to different kinds of example groups. This comes into play especially when using +rspec-rails, where, for instance, controller example groups, tagged with +type: :controller, are written differently than request example groups, tagged +with type: :request. This difference in writing style arises because +rspec-rails mixes different behavior and methods into controller example +groups vs. request example groups.

+ +

Relying on this behavior, Shoulda Matchers automatically makes certain matchers +available in certain kinds of example groups:

+ +
    +
  • ActiveRecord and ActiveModel matchers are available only in model example +groups, i.e., those tagged with type: :model or in files located under +spec/models.
  • +
  • ActionController matchers are available only in controller example groups, +i.e., those tagged with type: :controller or in files located under +spec/controllers.
  • +
  • The route matcher is available in routing example groups, i.e., those +tagged with type: :routing or in files located under spec/routing.
  • +
  • Independent matchers are available in all example groups.
  • +
+ +

As long as you're using Rails, you don't need to worry about these details — +everything should "just work".

+ +

Non-Rails projects

+ +

What if you are using ActiveModel or ActiveRecord outside of Rails, however, +and you want to use model matchers in a certain example group? Then you'll +need to manually include the module that holds those matchers into that example +group. For instance, you might have to say:

+ +
RSpec.describe MySpecialModel do
+  include Shoulda::Matchers::ActiveModel
+  include Shoulda::Matchers::ActiveRecord
+end
+
+ +

If you have a lot of similar example groups in which you need to do this, then +you might find it more helpful to tag your example groups appropriately, then +instruct RSpec to mix these modules into any example groups that have that tag. +For instance, you could add this to your rails_helper.rb:

+ +
RSpec.configure do |config|
+  config.include(Shoulda::Matchers::ActiveModel, type: :model)
+  config.include(Shoulda::Matchers::ActiveRecord, type: :model)
+end
+
+ +

And from then on, you could say:

+ +
RSpec.describe MySpecialModel, type: :model do
+  # ...
+end
+
+ +

should vs is_expected.to

+ +

In this README and throughout the documentation, you'll notice that we use the +should form of RSpec's one-liner syntax over is_expected.to. Beside being +the namesake of the gem itself, this is our preferred syntax as it's short and +sweet. But if you prefer to use is_expected.to, you can do that too:

+ +
RSpec.describe Person, type: :model do
+  it { is_expected.to validate_presence_of(:name) }
+end
+
+ +

Matchers

+ +

Here is the full list of matchers that ship with this gem. If you need details +about any of them, make sure to consult the documentation!

+ +

ActiveModel matchers

+ + + +

ActiveRecord matchers

+ + + +

ActionController matchers

+ +
    +
  • filter_param +tests parameter filtering configuration.
  • +
  • permit tests +that an action places a restriction on the params hash.
  • +
  • redirect_to +tests that an action redirects to a certain location.
  • +
  • render_template +tests that an action renders a template.
  • +
  • render_with_layout +tests that an action is rendered with a certain layout.
  • +
  • rescue_from +tests usage of the rescue_from macro.
  • +
  • respond_with +tests that an action responds with a certain status code.
  • +
  • route tests +your routes.
  • +
  • set_session +makes assertions on the session hash.
  • +
  • set_flash +makes assertions on the flash hash.
  • +
  • use_after_action +tests that an after_action callback is defined in your controller.
  • +
  • use_around_action +tests that an around_action callback is defined in your controller.
  • +
  • use_before_action +tests that a before_action callback is defined in your controller.
  • +
+ +

Routing matchers

+ +
    +
  • route tests +your routes.
  • +
+ +

Independent matchers

+ +
    +
  • delegate_method +tests that an object forwards messages to other, internal objects by way of +delegation.
  • +
+ +

Extensions

+ +

Over time our community has created extensions to Shoulda Matchers. If you've +created something that you want to share, please let us know!

+ + + +

Contributing

+ +

Have a fix for a problem you've been running into or an idea for a new feature +you think would be useful? Take a look at the Contributing +document for instructions on setting up the repo on your +machine, understanding the codebase, and creating a good pull request.

+ +

Compatibility

+ +

Shoulda Matchers is tested and supported against Ruby 2.6+, Rails +5.2+, RSpec 3.x, and Minitest 5.x.

+ +
    +
  • For Ruby < 2.4 and Rails < 4.1 compatibility, please use v3.1.3.
  • +
  • For Ruby < 3.0 and Rails < 6.1 compatibility, please use v4.5.1.
  • +
+ +

Versioning

+ +

Shoulda Matchers follows Semantic Versioning 2.0 as defined at +https://semver.org.

+ +

Team

+ +

Shoulda Matchers is maintained by Elliot Winkler and Gui +Albuk.

+ + + +

Shoulda Matchers is copyright © 2006-2022 Tammer Saleh and thoughtbot, +inc. It is free and opensource software and may be +redistributed under the terms specified in the LICENSE file.

+ +

About thoughtbot

+ +

thoughtbot

+ +

The names and logos for thoughtbot are trademarks of thoughtbot, inc.

+ +

We are passionate about open source software. See our other +projects. We are available for hire.

+
+ + + +
+ + + diff --git a/docs/v5.2.0/js/app.js b/docs/v5.2.0/js/app.js new file mode 100644 index 00000000..a00de8ed --- /dev/null +++ b/docs/v5.2.0/js/app.js @@ -0,0 +1,281 @@ +function createSourceLinks() { + $('.method_details_list .source_code'). + before("[View source]"); + $('.toggleSource').toggle(function() { + $(this).parent().nextAll('.source_code').show(); + $(this).text("Hide source"); + StickyHeaders.update(); + }, + function() { + $(this).parent().nextAll('.source_code').hide(); + $(this).text("View source"); + StickyHeaders.update(); + }); +} + +function createDefineLinks() { + var tHeight = 0; + $('.defines').after(" more..."); + $('.toggleDefines').toggle(function() { + tHeight = $(this).parent().prev().height(); + $(this).prev().show(); + $(this).parent().prev().height($(this).parent().height()); + $(this).text("(less)"); + StickyHeaders.update(); + }, + function() { + $(this).prev().hide(); + $(this).parent().prev().height(tHeight); + $(this).text("more..."); + StickyHeaders.update(); + }); +} + +function createFullTreeLinks() { + var tHeight = 0; + $('.inheritanceTree').toggle(function() { + tHeight = $(this).parent().prev().height(); + $(this).parent().toggleClass('showAll'); + $(this).text("(hide)"); + $(this).parent().prev().height($(this).parent().height()); + StickyHeaders.update(); + }, + function() { + $(this).parent().toggleClass('showAll'); + $(this).parent().prev().height(tHeight); + $(this).text("show all"); + StickyHeaders.update(); + }); +} + +function hideSearchFrameOnBlur() { + $(document.body).on('click', hideSearchFrame); +} + +function initSearchFrameLinks() { + var search = $('.js-search'); + var items = search.find('li'); + var links = search.find('a'); + var frame = $('.js-search-frame'); + + function listen() { + links.on('click', function (event) { + event.preventDefault(); + event.stopPropagation(); + toggle(this, this.href); + }); + + $(document).on('keydown', function (event) { + if (event.which == 27) { + close(); + } + }) + + $(document).on('click', function (event) { + close(); + }) + } + + function toggle(link, frameSrc) { + if (isOpen() && clickedOnSameLink(frameSrc)) { + close(); + } else { + open(link, frameSrc); + } + } + + function isOpen() { + return frame.hasClass('open'); + } + + function clickedOnSameLink(location) { + return frame.attr('src') === location; + } + + function reset() { + items.removeClass('active'); + } + + function open(link, location) { + reset(); + $(link).parent().addClass('active'); + frame.attr('src', location).one('load', function () { + frame.addClass('open'); + }) + } + + function close() { + reset(); + frame.removeClass('open'); + } + + listen(); +} + + +function linkSummaries() { + $('.summary_signature').click(function() { + document.location = $(this).find('a').attr('href'); + }); +} + +function keyboardShortcuts() { + if (window.top.frames.main) return; + + $(document).keypress(function(evt) { + if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) return; + + if ( + typeof evt.target !== "undefined" && + (evt.target.nodeName == "INPUT" || evt.target.nodeName == "TEXTAREA") + ) return; + + switch (evt.charCode) { + case 67: case 99: $('#class_list_link').click(); break; // 'c' + case 77: case 109: $('#method_list_link').click(); break; // 'm' + case 70: case 102: $('#file_list_link').click(); break; // 'f' + default: break; + } + }); +} + +function summaryToggle() { + $('.summary_toggle').click(function() { + if (localStorage) { + localStorage.summaryCollapsed = $(this).text(); + } + $('.summary_toggle').each(function() { + $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); + var next = $(this).parent().parent().nextAll('ul.summary').first(); + if (next.hasClass('compact')) { + next.toggle(); + next.nextAll('ul.summary').first().toggle(); + } + else if (next.hasClass('summary')) { + var list = $('