pineapples 0.3.34 → 0.3.345

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/bin/pineapples +13 -13
  3. data/lib/pineapples.rb +3 -1
  4. data/lib/pineapples/actions.rb +6 -0
  5. data/lib/pineapples/actions/base/target.rb +41 -91
  6. data/lib/pineapples/actions/bundle.rb +16 -0
  7. data/lib/pineapples/actions/chmod.rb +3 -2
  8. data/lib/pineapples/actions/copy_file.rb +1 -1
  9. data/lib/pineapples/actions/empty_directory.rb +1 -1
  10. data/lib/pineapples/actions/gsub_file.rb +5 -3
  11. data/lib/pineapples/actions/inside.rb +5 -1
  12. data/lib/pineapples/actions/rails/erb_converters.rb +11 -4
  13. data/lib/pineapples/actions/rails/new_hash_syntax_converter.rb +36 -0
  14. data/lib/pineapples/actions/rails/rails.rb +1 -0
  15. data/lib/pineapples/actions/remove_file.rb +28 -28
  16. data/lib/pineapples/actions/shell.rb +43 -9
  17. data/lib/pineapples/app_generator.rb +154 -38
  18. data/lib/pineapples/helpers.rb +31 -0
  19. data/lib/pineapples/parser.rb +42 -37
  20. data/lib/pineapples/setting.rb +155 -155
  21. data/lib/pineapples/settings.rb +31 -31
  22. data/lib/pineapples/templates/.example.env.tt +15 -0
  23. data/lib/pineapples/templates/.gitignore +3 -0
  24. data/lib/pineapples/templates/.simplecov.tt +11 -0
  25. data/lib/pineapples/templates/Gemfile.tt +23 -5
  26. data/lib/pineapples/templates/Procfile +1 -1
  27. data/lib/pineapples/templates/Procfile.dev.tt +2 -0
  28. data/lib/pineapples/templates/app/assets/javascripts/libs.js +4 -2
  29. data/lib/pineapples/templates/app/assets/stylesheets/application.scss +4 -1
  30. data/lib/pineapples/templates/app/controllers/application_controller.rb.tt +0 -2
  31. data/lib/pineapples/templates/app/controllers/auth!=devise!/confirmations_controller.rb +11 -0
  32. data/lib/pineapples/templates/app/controllers/auth!=devise!/passwords_controller.rb.tt +12 -0
  33. data/lib/pineapples/templates/app/controllers/auth!=devise!/registrations_controller.rb.tt +25 -0
  34. data/lib/pineapples/templates/app/controllers/auth!=devise!/sessions_controller.rb.tt +59 -0
  35. data/lib/pineapples/templates/app/models/user!=needs_user_model!.rb.tt +7 -4
  36. data/lib/pineapples/templates/app/policies!=pundit!/application_policy.rb +49 -0
  37. data/lib/pineapples/templates/app/presenters/base_presenter.rb.tt +24 -0
  38. data/lib/pineapples/templates/app/responders/application_responder.rb +9 -0
  39. data/lib/pineapples/templates/app/services/service.rb +7 -0
  40. data/lib/pineapples/templates/app/views/common/_footer.html.erb +3 -3
  41. data/lib/pineapples/templates/app/views/common/_header.html.erb +5 -5
  42. data/lib/pineapples/templates/app/views/layouts/application.html.erb.tt +0 -1
  43. data/lib/pineapples/templates/app/views/pages/home.html.erb +0 -1
  44. data/lib/pineapples/templates/bin/nginx +4 -0
  45. data/lib/pineapples/templates/bin/rails +1 -0
  46. data/lib/pineapples/templates/bin/rspec +19 -0
  47. data/lib/pineapples/templates/bin/setup +111 -21
  48. data/lib/pineapples/templates/config.ru.tt +3 -0
  49. data/lib/pineapples/templates/config/application.rb.tt +3 -3
  50. data/lib/pineapples/templates/config/boot.rb +5 -5
  51. data/lib/pineapples/templates/config/database.yml.tt +1 -1
  52. data/lib/pineapples/templates/config/environments/{development.rb → development.rb.tt} +6 -1
  53. data/lib/pineapples/templates/config/environments/production.rb +1 -1
  54. data/lib/pineapples/templates/config/environments/test.rb +2 -2
  55. data/lib/pineapples/templates/config/i18n-tasks.yml +2 -0
  56. data/lib/pineapples/templates/config/initializers/{carrierwave.rb → carrierwave!=carrierwave!.rb} +22 -22
  57. data/lib/pineapples/templates/config/initializers/devise!=devise!.rb.tt +262 -0
  58. data/lib/pineapples/templates/config/initializers/kaminari.rb +10 -0
  59. data/lib/pineapples/templates/config/initializers/seed_migrations.rb +15 -0
  60. data/lib/pineapples/templates/config/initializers/simple_form.rb +165 -0
  61. data/lib/pineapples/templates/config/locales/devise.en.yml +60 -0
  62. data/lib/pineapples/templates/config/locales/{en.yml → en.yml.tt} +2 -0
  63. data/lib/pineapples/templates/config/locales/kaminari.en.yml +17 -0
  64. data/lib/pineapples/templates/config/locales/simple_form.en.yml +31 -0
  65. data/lib/pineapples/templates/config/nginx.conf.tt +147 -0
  66. data/lib/pineapples/templates/config/puma/development.rb.tt +27 -0
  67. data/lib/pineapples/templates/config/{puma.rb → puma/production.rb} +5 -5
  68. data/lib/pineapples/templates/config/routes.rb.tt +4 -0
  69. data/lib/pineapples/templates/config/spring.rb +4 -0
  70. data/lib/pineapples/templates/lib/devise!=devise!/{ajax_failure.rb → ajax_failure!=ajax_login!.rb} +0 -0
  71. data/lib/pineapples/templates/lib/logging/custom_rack_logger.rb +7 -9
  72. data/lib/pineapples/templates/lib/logging/custom_request_logger.rb +46 -48
  73. data/lib/pineapples/templates/lib/tasks/admin!=user_role_field!.rake +18 -19
  74. data/lib/pineapples/templates/lib/templates/{erb → erb!=erb!}/scaffold/_form.html.erb +0 -0
  75. data/lib/pineapples/templates/lib/templates/haml!=haml!/scaffold/_form.html.haml +9 -0
  76. data/lib/pineapples/templates/lib/templates/slim!=slim!/scaffold/_form.html.slim +9 -0
  77. data/lib/pineapples/templates/spec/i18n_spec.rb +17 -0
  78. data/lib/pineapples/templates/spec/rails_helper.rb +30 -0
  79. data/lib/pineapples/templates/spec/spec_helper.rb +44 -0
  80. data/lib/pineapples/templates/spec/support/capybara.rb +4 -0
  81. data/lib/pineapples/templates/spec/support/database_cleaner.rb +27 -0
  82. data/lib/pineapples/templates/spec/support/email_matchers.rb +17 -0
  83. data/lib/pineapples/templates/spec/support/factory_girl.rb +14 -0
  84. data/lib/pineapples/templates/spec/support/job_helpers.rb +8 -0
  85. data/lib/pineapples/templates/spec/support/matchers.rb +10 -0
  86. data/lib/pineapples/templates/spec/support/rake_tasks.rb +8 -0
  87. data/lib/pineapples/templates/spec/support/shoulda_matchers.rb +24 -0
  88. data/lib/pineapples/version.rb +2 -2
  89. data/pineapples.gemspec +1 -3
  90. metadata +46 -12
  91. data/lib/pineapples/app_builder.rb +0 -70
  92. data/lib/pineapples/build_tasks/root_files.rb +0 -23
  93. data/lib/pineapples/templates/app/controllers/auth/confirmations_controller.rb +0 -2
@@ -3,19 +3,19 @@
3
3
  # The environment variable WEB_CONCURRENCY may be set to a default value based
4
4
  # on dyno size. To manually configure this value use heroku config:set
5
5
  # WEB_CONCURRENCY.
6
- workers Integer(ENV.fetch('WEB_CONCURRENCY', 3))
7
- threads_count = Integer(ENV.fetch('MAX_THREADS', 5))
6
+ workers Integer(ENV.fetch('WEB_CONCURRENCY', 1))
7
+ threads_count = Integer(ENV.fetch('MAX_THREADS', 3))
8
8
  threads(threads_count, threads_count)
9
9
 
10
10
  preload_app!
11
11
 
12
12
  rackup DefaultRackup
13
- environment ENV.fetch('RACK_ENV', 'development')
13
+ environment ENV.fetch('RACK_ENV')
14
14
 
15
15
  on_worker_boot do
16
16
  # Worker specific setup for Rails 4.1+
17
17
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
18
18
  ActiveRecord::Base.establish_connection
19
- puts 'Reconnecting Rails.cache'
20
- Rails.cache.reconnect
19
+ # puts 'Reconnecting Rails.cache'
20
+ # Rails.cache.reconnect
21
21
  end
@@ -6,5 +6,9 @@ Rails.application.routes.draw do
6
6
  sessions: 'auth/sessions'}
7
7
  <% end -%>
8
8
 
9
+ concern :paginatable do
10
+ get '(page/:page)', action: :index, on: :collection, as: ''
11
+ end
12
+
9
13
  root 'pages#home'
10
14
  end
@@ -0,0 +1,4 @@
1
+ if ENV['RAILS_ENV'] == 'test' && ENV.fetch('COVERAGE', false)
2
+ require 'simplecov'
3
+ SimpleCov.start 'rails'
4
+ end
@@ -1,11 +1,9 @@
1
- if !Rails.env.production?
2
- class Rails::Rack::Logger
3
- protected
4
- def started_request_message(request)
5
- "%-7s IP: %-15s | %s\nURL: \"%s\"" % [request.request_method,
6
- request.ip,
7
- Time.now.to_default_s,
8
- request.filtered_path,]
9
- end
1
+ class Rails::Rack::Logger
2
+ protected
3
+ def started_request_message(request)
4
+ "%-7s IP: %-15s | %s\nURL: \"%s\"" % [request.request_method,
5
+ request.ip,
6
+ Time.now.to_default_s,
7
+ request.filtered_path,]
10
8
  end
11
9
  end
@@ -1,65 +1,63 @@
1
- if !Rails.env.production?
2
- require 'show_data'
1
+ require 'show_data'
3
2
 
4
- module CustomRequestLogger
5
- class LogSubscriber < ActiveSupport::LogSubscriber
6
- INTERNAL_PARAMS = %w(controller action format _method only_path)
3
+ module CustomRequestLogger
4
+ class LogSubscriber < ActiveSupport::LogSubscriber
5
+ INTERNAL_PARAMS = %w(controller action format _method only_path)
7
6
 
8
- def start_processing(event)
9
- payload = event.payload
10
- params = payload[:params].except(*INTERNAL_PARAMS)
11
- format = payload[:format]
12
- format = format.to_s.upcase if format.is_a?(Symbol)
7
+ def start_processing(event)
8
+ payload = event.payload
9
+ params = payload[:params].except(*INTERNAL_PARAMS)
10
+ format = payload[:format]
11
+ format = format.to_s.upcase if format.is_a?(Symbol)
13
12
 
14
- info "Action: #{payload[:controller]}##{payload[:action]} \nFormat: #{format}"
15
- #logger.info "Parameters: #{params.inspect}" unless params.empty?
16
- end
17
-
18
- def process_action(event)
19
- indent = 8
20
- payload = event.payload
21
- param_method = payload[:params]['_method']
22
- status = compute_status(payload)
23
- path = payload[:path]
24
- params = payload[:params].except(*INTERNAL_PARAMS)
25
-
26
- redirect_to = Thread.current[:redirect_to]
27
- Thread.current[:redirect_to] = nil
13
+ info "Action: #{payload[:controller]}##{payload[:action]} \nFormat: #{format}"
14
+ #logger.info "Parameters: #{params.inspect}" unless params.empty?
15
+ end
28
16
 
29
- message = "Status: #{status} for \"#{path}\" \n"
30
- message << "Redirect URL: #{redirect_to} \n" if redirect_to
31
- message << "Params: #{format_data(params, indent)} \n" if params.present?
17
+ def process_action(event)
18
+ indent = 8
19
+ payload = event.payload
20
+ param_method = payload[:params]['_method']
21
+ status = compute_status(payload)
22
+ path = payload[:path]
23
+ params = payload[:params].except(*INTERNAL_PARAMS)
32
24
 
33
- info(message)
34
- end
25
+ redirect_to = Thread.current[:redirect_to]
26
+ Thread.current[:redirect_to] = nil
35
27
 
36
- def redirect_to(event)
37
- Thread.current[:redirect_to] = event.payload[:location]
38
- end
28
+ message = "Status: #{status} for \"#{path}\" \n"
29
+ message << "Redirect URL: #{redirect_to} \n" if redirect_to
30
+ message << "Params: #{format_data(params, indent)} \n" if params.present?
39
31
 
40
- private
41
- def compute_status(payload)
42
- status = payload[:status]
43
- if status.nil? && payload[:exception].present?
44
- exception_class_name = payload[:exception].first
45
- status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
46
- end
47
- status
48
- end
32
+ info(message)
33
+ end
49
34
 
35
+ def redirect_to(event)
36
+ Thread.current[:redirect_to] = event.payload[:location]
50
37
  end
51
38
 
52
- class Formatter < Logger::Formatter
53
- def call(severity, time, progname, msg)
54
- msg = msg.is_a?(String) ? msg : msg.inspect
55
- "#{Rails.env.production? ? severity : ''} #{time.utc.strftime('%F %T')} #{msg} \n"
39
+ private
40
+ def compute_status(payload)
41
+ status = payload[:status]
42
+ if status.nil? && payload[:exception].present?
43
+ exception_class_name = payload[:exception].first
44
+ status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception_class_name)
56
45
  end
46
+ status
57
47
  end
48
+
58
49
  end
59
50
 
60
- %w(process_action start_processing).each do |event|
61
- ActiveSupport::Notifications.unsubscribe "#{event}.action_controller"
51
+ class Formatter < Logger::Formatter
52
+ def call(severity, time, progname, msg)
53
+ msg = msg.is_a?(String) ? msg : msg.inspect
54
+ "#{Rails.env.production? ? severity : ''} #{time.utc.strftime('%F %T')} #{msg} \n"
55
+ end
62
56
  end
57
+ end
63
58
 
64
- CustomRequestLogger::LogSubscriber.attach_to :action_controller
59
+ %w(process_action start_processing).each do |event|
60
+ ActiveSupport::Notifications.unsubscribe "#{event}.action_controller"
65
61
  end
62
+
63
+ CustomRequestLogger::LogSubscriber.attach_to :action_controller
@@ -3,35 +3,34 @@ namespace :admin do
3
3
  task create: :environment do
4
4
  require 'highline/import'
5
5
 
6
+ class User
7
+ def reset_password
8
+ begin
9
+ password = ask('Password: ') { |q| q.echo = 'x' }
10
+ password_confirmation = ask('Repeat password: ') { |q| q.echo = 'x' }
11
+ end while password != password_confirmation
12
+ self.password = password
13
+ self.password_confirmation = password
14
+ end
15
+ end
16
+
6
17
  begin
7
18
  email = ask('Email: ')
8
19
  existing_user = User.find_by_email(email)
9
20
 
10
21
  # check if user account already exists
11
22
  if existing_user
12
- admin = existing_user
23
+ user = existing_user
13
24
  # user already exists, ask for password reset
14
25
  reset_password = ask('User with this email already exists! Do you want to reset the password for this email? (Y/n) ')
15
- if yes?(reset_password)
16
- begin
17
- password = ask('Password: ') { |q| q.echo = 'x' }
18
- password_confirmation = ask('Repeat password: ') { |q| q.echo = 'x' }
19
- end while password != password_confirmation
20
- admin.password = password
21
- admin.password_confirmation = password
22
- end
26
+ user.reset_password if yes?(reset_password)
23
27
  else
24
28
  # create new user otherwise
25
- admin = User.new(email: email, confirmed_at: Time.current)
26
- begin
27
- password = ask('Password: ') { |q| q.echo = 'x' }
28
- password_confirmation = ask('Repeat password: ') { |q| q.echo = 'x' }
29
- end while password != password_confirmation
30
- admin.password = password
31
- admin.password_confirmation = password
29
+ user = User.new(email: email, confirmed_at: Time.current)
30
+ user.reset_password
32
31
  end
33
32
 
34
- saved = admin.save
33
+ saved = user.save
35
34
  if !saved
36
35
  puts admin.errors.full_messages.join("\n")
37
36
  next
@@ -39,8 +38,8 @@ namespace :admin do
39
38
 
40
39
  grant_admin = ask('Do you want to grant Admin privileges to this account? (Y/n) ')
41
40
  if yes?(grant_admin)
42
- admin.role = :admin
43
- say("\nYour account now has Admin privileges!") if admin.save
41
+ user.role = :admin
42
+ say("\nYour account now has Admin privileges!") if user.save
44
43
  end
45
44
  end while !saved
46
45
  end
@@ -0,0 +1,9 @@
1
+ = simple_form_for(@<%= singular_table_name %>) do |f|
2
+ = f.error_notification
3
+
4
+ = f.inputs do
5
+ <% attributes.each do |attribute| -%>
6
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
7
+ <% end -%>
8
+ = f.actions do
9
+ = f.button :submit
@@ -0,0 +1,9 @@
1
+ = simple_form_for(@<%= singular_table_name %>) do |f|
2
+ = f.error_notification
3
+
4
+ = f.inputs do
5
+ <% attributes.each do |attribute| -%>
6
+ = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
7
+ <% end -%>
8
+ = f.actions do
9
+ = f.button :submit
@@ -0,0 +1,17 @@
1
+ require 'i18n/tasks'
2
+
3
+ RSpec.describe 'I18n' do
4
+ let(:i18n) { I18n::Tasks::BaseTask.new }
5
+ let(:missing_keys) { i18n.missing_keys }
6
+ let(:unused_keys) { i18n.unused_keys }
7
+
8
+ it 'does not have missing keys' do
9
+ expect(missing_keys).to be_empty,
10
+ "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
11
+ end
12
+
13
+ it 'does not have unused keys' do
14
+ expect(unused_keys).to be_empty,
15
+ "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ # simple_cov must be enabled before Rails is loaded
4
+ require 'spec_helper'
5
+
6
+ require File.expand_path('../../config/environment', __FILE__)
7
+
8
+ # Prevent database truncation if the environment is production
9
+ abort('The Rails environment is running in production mode!') if Rails.env.production?
10
+
11
+ require 'rspec/rails'
12
+ # Add additional requires below this line. Rails is not loaded until this point!
13
+
14
+ # The following line is provided for convenience purposes. It has the downside
15
+ # of increasing the boot-up time by auto-requiring all files in the support
16
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
17
+ # require only the support files necessary.
18
+ #
19
+ # !! Do not name files in support folder ending with _spec.rb !!
20
+ Dir[Rails.root.join('spec/support/*.rb')].each { |file| require file }
21
+
22
+ # Checks for pending migrations before tests are run.
23
+ ActiveRecord::Migration.maintain_test_schema!
24
+
25
+ RSpec.configure do |config|
26
+ config.include AbstractController::Translation
27
+ config.include Devise::TestHelpers, type: :controller
28
+
29
+ config.infer_base_class_for_anonymous_controllers = false
30
+ end
@@ -0,0 +1,44 @@
1
+ require 'simple_cov' if ENV.fetch('COVERAGE', false)
2
+
3
+ RSpec.configure do |config|
4
+ config.disable_monkey_patching!
5
+
6
+ config.expect_with :rspec do |expectations|
7
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
8
+ end
9
+
10
+ config.mock_with :rspec do |mocks|
11
+ mocks.verify_partial_doubles = true
12
+ end
13
+
14
+ # These two settings work together to allow you to limit a spec run
15
+ # to individual examples or groups you care about by tagging them with
16
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
17
+ # get run.
18
+ config.filter_run :focus
19
+ config.run_all_when_everything_filtered = true
20
+
21
+ # Allows RSpec to persist some state between runs in order to support
22
+ # the `--only-failures` and `--next-failure` CLI options.
23
+ config.example_status_persistence_file_path = 'tmp/rspec_examples.txt'
24
+
25
+ # Many RSpec users commonly either run the entire suite or an individual
26
+ # file, and it's useful to allow more verbose output when running an
27
+ # individual spec file.
28
+ if config.files_to_run.one?
29
+ config.default_formatter = 'doc'
30
+ end
31
+
32
+ # Print the 10 slowest examples and example groups at the
33
+ # end of the spec run, to help surface which specs are running
34
+ # particularly slow.
35
+ config.profile_examples = 10
36
+
37
+ config.order = :random
38
+
39
+ # Seed global randomization in this process using the `--seed` CLI option.
40
+ # Setting this allows you to use `--seed` to deterministically reproduce
41
+ # test failures related to randomization by passing the same `--seed` value
42
+ # as the one that triggered the failure.
43
+ Kernel.srand config.seed
44
+ end
@@ -0,0 +1,4 @@
1
+ require 'capybara/rails'
2
+ require 'capybara/rspec'
3
+
4
+ Capybara.javascript_driver = :webkit
@@ -0,0 +1,27 @@
1
+
2
+ RSpec.configure do |config|
3
+ # MUST turn off transactional fixtures since we are using database_cleaner instead
4
+ config.use_transactional_fixtures = false
5
+
6
+ # truncation gives cleaner starting state for the database...
7
+ config.before(:suite) do
8
+ DatabaseCleaner.clean_with(:truncation)
9
+ end
10
+
11
+ # Transactions are the fastest, each example is wrapped into transaction, which is
12
+ # simply rolled back after example completes. Very fast.
13
+ config.before(:each) do
14
+ DatabaseCleaner.strategy = :transaction
15
+ end
16
+
17
+ # Deletion is much faster than truncation on smaller datasets, especially at the
18
+ # beginning of app development. You'd want to use it until you'll have huge
19
+ # datasets to test againt and/or tons of tables with many foreign keys.
20
+ config.before(:each, js: true) do
21
+ DatabaseCleaner.strategy = :deletion
22
+ end
23
+
24
+ config.around(:each) do |example|
25
+ DatabaseCleaner.cleaning { example.run }
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ require 'email_spec'
2
+
3
+ # Collection of rspec matchers to test email deliveries.
4
+ # --------------
5
+ # Docs:
6
+ # https://github.com/bmabey/email-spec#rspec-matchers
7
+
8
+ RSpec.configure do |config|
9
+ config.include EmailSpec::Helpers
10
+ config.include EmailSpec::Matchers
11
+
12
+ config.before(:each) do
13
+ # Clear out ActionMailer::Base.deliveries
14
+ reset_mailer
15
+ end
16
+
17
+ end
@@ -0,0 +1,14 @@
1
+ RSpec.configure do |config|
2
+ config.include FactoryGirl::Syntax::Methods
3
+
4
+ # config.before(:suite) do
5
+ # begin
6
+ # DatabaseCleaner.start
7
+ # # Test factories in spec/factories are working.
8
+ # FactoryGirl.lint
9
+ # ensure
10
+ # DatabaseCleaner.clean
11
+ # end
12
+ # end
13
+
14
+ end
@@ -0,0 +1,8 @@
1
+ # Use Rails-provided test helper methods for testing jobs
2
+ # --------------
3
+ # Docs:
4
+ # http://api.rubyonrails.org/classes/ActiveJob/TestHelper.html
5
+
6
+ RSpec.configure do |config|
7
+ config.include ActiveJob::TestHelper, type: :job
8
+ end
@@ -0,0 +1,10 @@
1
+ # Loads custom matchers.
2
+ # Write custom matcher classes in `spec/matchers/` directory.
3
+
4
+ Dir[Rails.root.join('spec/support/matchers/**/*.rb')].each { |file| require file }
5
+
6
+ # Each matcher class will shoule be in a `Matchers` module
7
+ # to work with this RSpec configuration.
8
+ RSpec.configure do |config|
9
+ config.include Matchers
10
+ end