├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-request.md │ └── feature_request.md └── workflows │ └── ci.yml ├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app └── models │ └── rails │ └── decorators │ ├── test_decorator.decorator │ └── test_model.rb ├── bin ├── console ├── rails ├── setup └── test ├── lib └── rails │ ├── decorators.rb │ └── decorators │ ├── application.rb │ ├── decorator.rb │ ├── engine.rb │ ├── invalid_decorator.rb │ ├── object.rb │ ├── version.rb │ └── zeitwerk.rb ├── rails-decorators.gemspec └── test ├── dummy ├── Rakefile ├── app │ ├── assets │ │ ├── config │ │ │ └── manifest.js │ │ ├── images │ │ │ └── .keep │ │ ├── javascripts │ │ │ ├── application.js │ │ │ ├── cable.js │ │ │ └── channels │ │ │ │ └── .keep │ │ └── stylesheets │ │ │ └── application.css │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ ├── controllers │ │ ├── application_controller.rb │ │ └── concerns │ │ │ └── .keep │ ├── helpers │ │ └── application_helper.rb │ ├── jobs │ │ └── application_job.rb │ ├── mailers │ │ └── application_mailer.rb │ ├── models │ │ ├── application_record.rb │ │ ├── concerns │ │ │ └── .keep │ │ └── rails │ │ │ └── decorators │ │ │ └── test_model.decorator │ └── views │ │ └── layouts │ │ ├── application.html.erb │ │ ├── mailer.html.erb │ │ └── mailer.text.erb ├── bin │ ├── bundle │ ├── rails │ ├── rake │ ├── setup │ └── update ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── application_controller_renderer.rb │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── content_security_policy.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── new_framework_defaults_6_0.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── secrets.yml │ ├── spring.rb │ └── storage.yml ├── lib │ └── assets │ │ └── .keep ├── log │ └── .keep └── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon.png │ └── favicon.ico ├── lib └── rails │ ├── decorators │ ├── decorate_test.rb │ ├── decorates_test.rb │ ├── decorator_loading_test.rb │ ├── invalid_decoration_test.rb │ └── multiple_decorations_test.rb │ └── decorators_test.rb └── test_helper.rb /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Workarea 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ⚠️**Before you create**⚠️ 11 | Please verify the issue you're experiencing is not part of your Workarea project customizations. The best way to do this is with a [vanilla Workarea installation](https://developer.workarea.com/articles/create-a-new-host-application.html). This will help us spend time on fixes/improvements for the whole community. Thank you! 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **To Reproduce** 17 | Steps to reproduce the behavior: 18 | 1. Go to '...' 19 | 2. Click on '....' 20 | 3. Scroll down to '....' 21 | 4. See error 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Workarea Setup (please complete the following information):** 27 | - Workarea Version: [e.g. v3.4.6] 28 | - Plugins [e.g. workarea-blog, workarea-sitemaps] 29 | 30 | **Attachments** 31 | If applicable, add any attachments to help explain your problem, things like: 32 | - screenshots 33 | - Gemfile.lock 34 | - test cases 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation request 3 | about: Suggest documentation 4 | title: '' 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your documentation related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm confused by [...] 12 | 13 | **Describe the article you'd like** 14 | A clear and concise description of what would be in the documentation article. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for Workarea 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | 4 | jobs: 5 | static_analysis: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v1 9 | - uses: workarea-commerce/ci/bundler-audit@v1 10 | - uses: workarea-commerce/ci/rubocop@v1 11 | 12 | tests: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-ruby@v1 17 | with: 18 | ruby-version: 2.6.x 19 | - name: Install Dependencies 20 | run: | 21 | sudo apt-get install -y libsqlite3-dev 22 | bundle install 23 | - name: Run Tests 24 | run: bin/rails test 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/db/*.sqlite3-journal 6 | test/dummy/log/*.log 7 | test/dummy/tmp/ 8 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: 2 | - https://raw.githubusercontent.com/workarea-commerce/workarea/master/.rubocop.yml 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.3.2 5 | before_install: gem install bundler -v 1.13.6 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Declare your gem's dependencies in rails-decorators.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | # Declare any dependencies that are still in development here instead of in 9 | # your gemspec. These might include edge Rails or gems from your path or 10 | # Git. Remember to move these dependencies to your gemspec before releasing 11 | # your gem to rubygems.org. 12 | 13 | # To use a debugger 14 | # gem 'byebug', group: [:development, :test] 15 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ben Crouse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Ben Crouse 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rails::Decorators 2 | Using [Rails engines](http://guides.rubyonrails.org/engines.html) extensively, we needed a way to customize behavior for implementations of the platform. Rails provides a great mechanism for views and assets, but doesn't offer any functionality to handle controller/model/lib overriding/customizing. The suggested mechanism in the documentation is `class_eval` or ActiveSupport::Concern. Our preferred method for this is module prepending, which is cleaner than `class_eval` in that it avoids alias method chaining and becomes part of the ancestor chain. 3 | 4 | We also want junior developers to be able to jump in and be productive ASAP - not necessarily requiring they learn the techniques of `class_eval` to fix a bug or get a simple task done. Yes, we educate and promote this as the developer grows, but we want the barriers to contribution as low as possible. 5 | 6 | We like the [`ActiveSupport::Concern`](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html) API, so this library mimics the API of `ActiveSupport::Concern` and layers on top some niceties for the specific task of customizing a Rails engine. Also, we don't like having to store decorated behavior in a separate directory (like https://github.com/parndt/decorators). Storing decorations in the same place as new classes makes it much easier to see the overall picture of how the engine has been customized/extended in one shot. 7 | 8 | ## Usage 9 | Say we have a class in an engine like so: 10 | ```ruby 11 | # in ecommerce/app/models/ecommerce/product.rb 12 | module Ecommerce 13 | class Product < ApplicationRecord 14 | def price 15 | skus.first.price 16 | end 17 | end 18 | end 19 | ``` 20 | 21 | `Rails::Decorators` allows customizing this class like so: 22 | ```ruby 23 | # in Rails.root/app/models/ecommerce/product.decorator 24 | module Ecommerce 25 | decorate Product do 26 | decorated do 27 | # Class methods may be called here. Evaluates after prepending module. 28 | attr_writer :on_sale 29 | end 30 | 31 | class_methods do 32 | # Methods defined here extend/decorate static methods on the 33 | # decorated class. 34 | def sorts 35 | super + ['discount_rate'] 36 | end 37 | end 38 | 39 | # Methods defined here extend/decorate instance methods on the 40 | # decorated class. 41 | def price 42 | result = super 43 | result *= discount_rate if on_sale? 44 | result 45 | end 46 | end 47 | end 48 | ``` 49 | 50 | `Rails::Decorators` achieves this in a manner similar to `ActiveSupport::Concern` - it dynamically creates a module out of the block passed, and then prepends that into the original class. The above is equivalent to (note that this would need to be required as well): 51 | ```ruby 52 | # in Rails.root/app/models/ecommerce/product_decorator.rb 53 | module Ecommerce 54 | class Product 55 | module Decorator 56 | module ClassMethods 57 | # Methods defined here extend/decorate static methods on the 58 | # decorated class. 59 | def sorts 60 | super + ['discount_rate'] 61 | end 62 | end 63 | 64 | # Methods defined here extend/decorate instance methods on the 65 | # decorated class. 66 | def price 67 | result = super 68 | result *= discount_rate if on_sale? 69 | result 70 | end 71 | end 72 | end 73 | 74 | Product.send(:prepend, Product::Decorator) 75 | Product.singleton_class.send(:prepend, Product::Decorator::ClassMethods) 76 | Product.class_eval do 77 | # Class methods may be called here. Evaluates after prepending module. 78 | attr_writer :on_sale 79 | end 80 | end 81 | ``` 82 | 83 | You can also decorate more than one class at a time: 84 | ```ruby 85 | # in Rails.root/app/models/ecommerce/navigable.decorator 86 | module Ecommerce 87 | decorate Product, Category, Page do 88 | def generate_slug 89 | # my custom logic here 90 | end 91 | end 92 | end 93 | ``` 94 | 95 | Other engines may want to namespace their customizations so as not to collide with further customizations: 96 | ```ruby 97 | # in ecommerce_blog/app/models/ecommerce/product.decorator 98 | module Ecommerce 99 | decorate Product, with: 'blog' do 100 | def blog_entries 101 | BlogEntry.for_product(id) 102 | end 103 | end 104 | end 105 | ``` 106 | 107 | It is strongly suggested you update your editor of choice to use Ruby syntax highlighting on \*.decorator files. 108 | 109 | ### Case Study: Modifying Devise 110 | 111 | Let's examine a more real-world case: In the [Devise OmniAuth How-To 112 | Article](https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview), 113 | the maintainers instruct users to create a new controller named 114 | `Users::OmniauthCallbacksController` that inherits from 115 | `Devise::OmniauthCallbacksController`, and override the entire class in 116 | the `devise_for` method by supplying the name of the controller to use. 117 | This has always been a point of contention for some as it's quite 118 | difficult to understand why you need to do this if you don't have a lot 119 | of experience with Rails applications. 120 | 121 | However, if you had `rails-decorators` installed, you don't need to do 122 | any of that. Just decorate the controller supplied by Devise in 123 | **app/controllers/devise/omniauth_callbacks_controller.decorator**! 124 | 125 | ```ruby 126 | module Devise 127 | decorate OmniauthCallbacksController do 128 | # We're using Facebook as an example here so it can be directly 129 | # translated from the aforementioned article... 130 | def facebook 131 | # You need to implement the method below in your model (e.g. app/models/user.rb) 132 | @user = User.from_omniauth(request.env["omniauth.auth"]) 133 | 134 | if @user.persisted? 135 | sign_in_and_redirect @user, event: :authentication #this will throw if @user is not activated 136 | set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format? 137 | else 138 | session["devise.facebook_data"] = request.env["omniauth.auth"] 139 | redirect_to new_user_registration_url 140 | end 141 | end 142 | 143 | def failure 144 | redirect_to root_path 145 | end 146 | end 147 | end 148 | ``` 149 | 150 | With `rails-decorators`, you get to skip about 3 or 4 paragraphs of docs 151 | and go right to the `.from_omniauth` definition. Decorating saves both 152 | time and mental energy so you can get back to actually writing your 153 | application. 154 | 155 | ## Installation 156 | Add this line to your application's Gemfile: 157 | 158 | ```ruby 159 | gem 'rails-decorators' 160 | ``` 161 | 162 | And then execute: 163 | ```bash 164 | $ bundle 165 | ``` 166 | 167 | Or install it yourself as: 168 | ```bash 169 | $ gem install rails-decorators 170 | ``` 171 | 172 | ## Contributing 173 | Contribution directions go here. 174 | 175 | ## License 176 | The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). 177 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | begin 2 | require 'bundler/setup' 3 | rescue LoadError 4 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 5 | end 6 | 7 | require 'rdoc/task' 8 | 9 | RDoc::Task.new(:rdoc) do |rdoc| 10 | rdoc.rdoc_dir = 'rdoc' 11 | rdoc.title = 'Rails::Decorators' 12 | rdoc.options << '--line-numbers' 13 | rdoc.rdoc_files.include('README.md') 14 | rdoc.rdoc_files.include('lib/**/*.rb') 15 | end 16 | 17 | APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) 18 | load 'rails/tasks/engine.rake' 19 | 20 | 21 | load 'rails/tasks/statistics.rake' 22 | 23 | 24 | 25 | require 'bundler/gem_tasks' 26 | 27 | require 'rake/testtask' 28 | 29 | Rake::TestTask.new(:test) do |t| 30 | t.libs << 'lib' 31 | t.libs << 'test' 32 | t.pattern = 'test/**/*_test.rb' 33 | t.verbose = false 34 | end 35 | 36 | 37 | task default: :test 38 | -------------------------------------------------------------------------------- /app/models/rails/decorators/test_decorator.decorator: -------------------------------------------------------------------------------- 1 | class Rails::Decorators::TestDecorator 2 | end 3 | -------------------------------------------------------------------------------- /app/models/rails/decorators/test_model.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module Decorators 3 | class TestModel 4 | def foo 5 | 'bar' 6 | end 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "rails/decorators" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails gems 3 | # installed from the root of your application. 4 | 5 | ENGINE_ROOT = File.expand_path('../..', __FILE__) 6 | ENGINE_PATH = File.expand_path('../../lib/rails/decorators/engine', __FILE__) 7 | 8 | # Set up gems listed in the Gemfile. 9 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 10 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 11 | 12 | require 'rails/all' 13 | require 'rails/engine/commands' 14 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | $: << File.expand_path(File.expand_path('../../test', __FILE__)) 3 | 4 | require 'bundler/setup' 5 | require 'rails/test_unit/minitest_plugin' 6 | 7 | Rails::TestUnitReporter.executable = 'bin/test' 8 | 9 | Minitest.run_via = :rails 10 | 11 | require "active_support/testing/autorun" 12 | -------------------------------------------------------------------------------- /lib/rails/decorators.rb: -------------------------------------------------------------------------------- 1 | require 'zeitwerk' 2 | 3 | module Rails 4 | module Decorators 5 | mattr_accessor :extension 6 | self.extension = :decorator 7 | end 8 | end 9 | 10 | require 'rails/decorators/engine' 11 | require 'rails/decorators/version' 12 | require 'rails/decorators/application' 13 | require 'rails/decorators/decorator' 14 | require 'rails/decorators/invalid_decorator' 15 | require 'rails/decorators/object' 16 | require 'rails/decorators/zeitwerk' 17 | -------------------------------------------------------------------------------- /lib/rails/decorators/application.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | class Application < Engine 3 | module Decorators 4 | def watchable_args 5 | result = super 6 | 7 | result.last.keys.each do |path| 8 | result.last[path] << Rails::Decorators.extension 9 | end 10 | 11 | result 12 | end 13 | end 14 | 15 | prepend Decorators 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rails/decorators/decorator.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module Decorators 3 | module Decorator 4 | def self.decorate(*targets, &module_definition) 5 | options = targets.extract_options! 6 | 7 | targets.each do |target| 8 | unless target.is_a?(Class) 9 | raise( 10 | InvalidDecorator, 11 | <<-eos.strip_heredoc 12 | Problem: 13 | You cannot decorate a Module 14 | Summary: 15 | Decoration only works with classes. Decorating modules requires 16 | managing load order, a problem that is very complicated and 17 | beyond the scope of this system. 18 | Resolution: 19 | Decorate multiple classes that include the module like so: 20 | `decorate Catalog::Product, Content::Page do` 21 | eos 22 | ) 23 | end 24 | 25 | if target.name.to_s.end_with?('Helper') 26 | raise( 27 | InvalidDecorator, 28 | <<-eos.strip_heredoc 29 | Problem: 30 | Rails::Decorators doesn't work with helpers. 31 | Summary: 32 | Rails does some magic with helpers which in certain cases 33 | causes decoration to not work. 34 | Resolution: 35 | Create a new helper and in a `to_prepare` block, use 36 | ActionPack's `helper` method to include the helper, e.g. 37 | `MyEngine::ApplicationController.helper(MyEngine::BlogsHelper)` 38 | eos 39 | ) 40 | end 41 | 42 | namespace = target.to_s.remove('::') 43 | decorator_name = "#{options[:with].to_s.camelize}#{namespace}Decorator" 44 | 45 | if target.const_defined?(decorator_name) 46 | # We are probably reloading in Rails development env if this happens 47 | next if !Rails.application.config.cache_classes 48 | 49 | raise( 50 | InvalidDecorator, 51 | <<-eos.strip_heredoc 52 | Problem: 53 | #{decorator_name} is already defined in #{target.name}. 54 | Summary: 55 | When decorating a class, Rails::Decorators dynamically defines 56 | a module for prepending the decorations passed in the block. In 57 | this case, the name for the decoration module is already defined 58 | in the namespace, so decorating would redefine the constant. 59 | Resolution: 60 | Please specify a unique `with` option when decorating #{target.name}. 61 | eos 62 | ) 63 | end 64 | 65 | mod = Module.new do 66 | extend Rails::Decorators::Decorator 67 | module_eval(&module_definition) 68 | end 69 | 70 | target.const_set(decorator_name, mod) 71 | mod.decorates(target) 72 | end 73 | end 74 | 75 | def prepend_features(base) 76 | if instance_variable_defined?(:@_before_decorate_block) 77 | base.class_eval(&@_before_decorate_block) 78 | end 79 | 80 | super 81 | 82 | if const_defined?(:ClassMethodsDecorator) 83 | base 84 | .singleton_class 85 | .send(:prepend, const_get(:ClassMethodsDecorator)) 86 | end 87 | 88 | if instance_variable_defined?(:@_decorated_block) 89 | base.class_eval(&@_decorated_block) 90 | end 91 | end 92 | 93 | def before_decorate(&block) 94 | instance_variable_set(:@_before_decorate_block, block) 95 | end 96 | 97 | def decorated(&block) 98 | instance_variable_set(:@_decorated_block, block) 99 | end 100 | 101 | def class_methods(&class_methods_module_definition) 102 | mod = const_set(:ClassMethodsDecorator, Module.new) 103 | mod.module_eval(&class_methods_module_definition) 104 | end 105 | alias_method :module_methods, :class_methods 106 | 107 | def decorates(klass) 108 | klass.send(:prepend, self) 109 | end 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /lib/rails/decorators/engine.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module Decorators 3 | class MissingZeitwerkError < StandardError; end 4 | 5 | class Engine < ::Rails::Engine 6 | isolate_namespace Rails::Decorators 7 | 8 | config.after_initialize do |app| 9 | unless Rails.configuration.autoloader == :zeitwerk 10 | raise MissingZeitwerkError, <<-eos.strip_heredoc 11 | rails-decorators requires using the Zeitwerk code loader. You can set this in config/application.rb by doing `config.autoloader = :zeitwerk` 12 | eos 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/rails/decorators/invalid_decorator.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module Decorators 3 | class InvalidDecorator < RuntimeError; end 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/rails/decorators/object.rb: -------------------------------------------------------------------------------- 1 | class Object 2 | delegate :decorate, to: Rails::Decorators::Decorator 3 | end 4 | -------------------------------------------------------------------------------- /lib/rails/decorators/version.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module Decorators 3 | VERSION = '1.0.0.pre' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/rails/decorators/zeitwerk.rb: -------------------------------------------------------------------------------- 1 | module Zeitwerk 2 | class Loader 3 | module RailsDecorators 4 | def do_preload 5 | super 6 | load_decorators 7 | end 8 | 9 | def load_decorators 10 | decorator_ext = /\.#{Rails::Decorators.extension}$/ 11 | queue = [] 12 | actual_root_dirs.each do |root_dir, namespace| 13 | queue << [namespace, root_dir] unless eager_load_exclusions.member?(root_dir) 14 | end 15 | 16 | while dir_to_load = queue.shift 17 | namespace, dir = dir_to_load 18 | 19 | ls(dir) do |basename, abspath| 20 | if abspath =~ decorator_ext 21 | load(abspath) 22 | elsif dir?(abspath) && !root_dirs.key?(abspath) 23 | if collapse_dirs.member?(abspath) 24 | queue << [namespace, abspath] 25 | else 26 | cname = inflector.camelize(basename, abspath) 27 | queue << [namespace.const_get(cname, false), abspath] 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | 35 | prepend RailsDecorators 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /rails-decorators.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "rails/decorators/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "rails-decorators" 9 | s.version = Rails::Decorators::VERSION 10 | s.authors = ["Ben Crouse"] 11 | s.email = ["bencrouse@gmail.com"] 12 | s.homepage = "https://github.com/weblinc/rails-decorators" 13 | s.summary = "Rails::Decorators provides a clean, familiar API for decorating the behavior of a Rails engine." 14 | s.license = "MIT" 15 | 16 | s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] 17 | 18 | s.add_dependency "rails", ">= 6.0.x" 19 | 20 | s.add_development_dependency "sqlite3" 21 | end 22 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /test/dummy/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | 2 | //= link_tree ../images 3 | //= link_directory ../javascripts .js 4 | //= link_directory ../stylesheets .css 5 | //= link rails_decorators_manifest.js 6 | -------------------------------------------------------------------------------- /test/dummy/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/app/assets/images/.keep -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require_tree . 14 | -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the rails generate channel command. 3 | // 4 | //= require action_cable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /test/dummy/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /test/dummy/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/app/models/concerns/.keep -------------------------------------------------------------------------------- /test/dummy/app/models/rails/decorators/test_model.decorator: -------------------------------------------------------------------------------- 1 | decorate Rails::Decorators::TestModel do 2 | def foo 3 | "#{super} baz" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= csrf_meta_tags %> 6 | 7 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 8 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /test/dummy/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /test/dummy/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /test/dummy/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /test/dummy/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to setup or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at anytime and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?('config/database.yml') 22 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! 'bin/rails db:prepare' 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! 'bin/rails log:clear tmp:clear' 30 | 31 | puts "\n== Restarting application server ==" 32 | system! 'bin/rails restart' 33 | end 34 | -------------------------------------------------------------------------------- /test/dummy/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | require "rails/decorators" 9 | 10 | module Dummy 11 | class Application < Rails::Application 12 | # Settings in config/environments/* take precedence over those specified here. 13 | # Application configuration can go into files in config/initializers 14 | # -- all .rb files in that directory are automatically loaded after loading 15 | # the framework and any gems in your application. 16 | 17 | config.load_defaults "6.0" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /test/dummy/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: dummy_production 11 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | # Run rails dev:cache to toggle caching. 17 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 18 | config.action_controller.perform_caching = true 19 | config.action_controller.enable_fragment_cache_logging = true 20 | 21 | config.cache_store = :memory_store 22 | config.public_file_server.headers = { 23 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 24 | } 25 | else 26 | config.action_controller.perform_caching = false 27 | 28 | config.cache_store = :null_store 29 | end 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # Don't care if the mailer can't send. 35 | config.action_mailer.raise_delivery_errors = false 36 | 37 | config.action_mailer.perform_caching = false 38 | 39 | # Print deprecation notices to the Rails logger. 40 | config.active_support.deprecation = :log 41 | 42 | # Raise an error on page load if there are pending migrations. 43 | config.active_record.migration_error = :page_load 44 | 45 | # Highlight code that triggered database queries in logs. 46 | config.active_record.verbose_query_logs = true 47 | 48 | # Debug mode disables concatenation and preprocessing of assets. 49 | # This option may cause significant delays in view rendering with a large 50 | # number of complex assets. 51 | config.assets.debug = true 52 | 53 | # Suppress logger output for asset requests. 54 | config.assets.quiet = true 55 | 56 | # Raises error for missing translations. 57 | # config.action_view.raise_on_missing_translations = true 58 | 59 | # Use an evented file watcher to asynchronously detect changes in source code, 60 | # routes, locales, etc. This feature depends on the listen gem. 61 | # config.file_watcher = ActiveSupport::EventedFileUpdateChecker 62 | end 63 | -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 18 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 19 | # config.require_master_key = true 20 | 21 | # Disable serving static files from the `/public` folder by default since 22 | # Apache or NGINX already handles this. 23 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 24 | 25 | # Compress CSS using a preprocessor. 26 | # config.assets.css_compressor = :sass 27 | 28 | # Do not fallback to assets pipeline if a precompiled asset is missed. 29 | config.assets.compile = false 30 | 31 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 32 | # config.action_controller.asset_host = 'http://assets.example.com' 33 | 34 | # Specifies the header that your server uses for sending files. 35 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 36 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 37 | 38 | # Store uploaded files on the local file system (see config/storage.yml for options). 39 | config.active_storage.service = :local 40 | 41 | # Mount Action Cable outside main process or domain. 42 | # config.action_cable.mount_path = nil 43 | # config.action_cable.url = 'wss://example.com/cable' 44 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 45 | 46 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 47 | # config.force_ssl = true 48 | 49 | # Use the lowest log level to ensure availability of diagnostic information 50 | # when problems arise. 51 | config.log_level = :debug 52 | 53 | # Prepend all log lines with the following tags. 54 | config.log_tags = [ :request_id ] 55 | 56 | # Use a different cache store in production. 57 | # config.cache_store = :mem_cache_store 58 | 59 | # Use a real queuing backend for Active Job (and separate queues per environment). 60 | # config.active_job.queue_adapter = :resque 61 | # config.active_job.queue_name_prefix = "dummy_production" 62 | 63 | config.action_mailer.perform_caching = false 64 | 65 | # Ignore bad email addresses and do not raise email delivery errors. 66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 67 | # config.action_mailer.raise_delivery_errors = false 68 | 69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 70 | # the I18n.default_locale when a translation cannot be found). 71 | config.i18n.fallbacks = true 72 | 73 | # Send deprecation notices to registered listeners. 74 | config.active_support.deprecation = :notify 75 | 76 | # Use default logging formatter so that PID and timestamp are not suppressed. 77 | config.log_formatter = ::Logger::Formatter.new 78 | 79 | # Use a different logger for distributed setups. 80 | # require 'syslog/logger' 81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 82 | 83 | if ENV["RAILS_LOG_TO_STDOUT"].present? 84 | logger = ActiveSupport::Logger.new(STDOUT) 85 | logger.formatter = config.log_formatter 86 | config.logger = ActiveSupport::TaggedLogging.new(logger) 87 | end 88 | 89 | # Do not dump schema after migrations. 90 | config.active_record.dump_schema_after_migration = false 91 | 92 | # Inserts middleware to perform automatic connection switching. 93 | # The `database_selector` hash is used to pass options to the DatabaseSelector 94 | # middleware. The `delay` is used to determine how long to wait after a write 95 | # to send a subsequent read to the primary. 96 | # 97 | # The `database_resolver` class is used by the middleware to determine which 98 | # database is appropriate to use based on the time delay. 99 | # 100 | # The `database_resolver_context` class is used by the middleware to set 101 | # timestamps for the last write to the primary. The resolver uses the context 102 | # class timestamps to determine how long to wait before reading from the 103 | # replica. 104 | # 105 | # By default Rails will store a last write timestamp in the session. The 106 | # DatabaseSelector middleware is designed as such you can define your own 107 | # strategy for connection switching and pass that into the middleware through 108 | # these configuration options. 109 | # config.active_record.database_selector = { delay: 2.seconds } 110 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 111 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 112 | end 113 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | config.cache_classes = true 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure public file server for tests with Cache-Control for performance. 17 | config.public_file_server.enabled = true 18 | config.public_file_server.headers = { 19 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 20 | } 21 | 22 | # Show full error reports and disable caching. 23 | config.consider_all_requests_local = true 24 | config.action_controller.perform_caching = false 25 | config.cache_store = :null_store 26 | 27 | # Raise exceptions instead of rendering exception templates. 28 | config.action_dispatch.show_exceptions = false 29 | 30 | # Disable request forgery protection in test environment. 31 | config.action_controller.allow_forgery_protection = false 32 | 33 | # Store uploaded files on the local file system in a temporary directory. 34 | config.active_storage.service = :test 35 | 36 | config.action_mailer.perform_caching = false 37 | 38 | # Tell Action Mailer not to deliver emails to the real world. 39 | # The :test delivery method accumulates sent emails in the 40 | # ActionMailer::Base.deliveries array. 41 | config.action_mailer.delivery_method = :test 42 | 43 | # Print deprecation notices to the stderr. 44 | config.active_support.deprecation = :stderr 45 | 46 | # Raises error for missing translations. 47 | # config.action_view.raise_on_missing_translations = true 48 | end 49 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | 19 | # If you are using UJS then enable automatic nonce generation 20 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 21 | 22 | # Set the nonce only to specific directives 23 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 24 | 25 | # Report CSP violations to a specified URI 26 | # For further information see the following documentation: 27 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 28 | # Rails.application.config.content_security_policy_report_only = true 29 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/new_framework_defaults_6_0.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 6.0 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 8 | 9 | # Don't force requests from old versions of IE to be UTF-8 encoded. 10 | # Rails.application.config.action_view.default_enforce_utf8 = false 11 | 12 | # Embed purpose and expiry metadata inside signed and encrypted 13 | # cookies for increased security. 14 | # 15 | # This option is not backwards compatible with earlier Rails versions. 16 | # It's best enabled when your entire app is migrated and stable on 6.0. 17 | # Rails.application.config.action_dispatch.use_cookies_with_metadata = true 18 | 19 | # Change the return value of `ActionDispatch::Response#content_type` to Content-Type header without modification. 20 | # Rails.application.config.action_dispatch.return_only_media_type_on_content_type = false 21 | 22 | # Return false instead of self when enqueuing is aborted from a callback. 23 | # Rails.application.config.active_job.return_false_on_aborted_enqueue = true 24 | 25 | # Send Active Storage analysis and purge jobs to dedicated queues. 26 | # Rails.application.config.active_storage.queues.analysis = :active_storage_analysis 27 | # Rails.application.config.active_storage.queues.purge = :active_storage_purge 28 | 29 | # When assigning to a collection of attachments declared via `has_many_attached`, replace existing 30 | # attachments instead of appending. Use #attach to add new attachments without replacing existing ones. 31 | # Rails.application.config.active_storage.replace_on_assign_to_many = true 32 | 33 | # Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. 34 | # 35 | # The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), 36 | # will be removed in Rails 6.1. This setting is not backwards compatible with earlier Rails versions. 37 | # If you send mail in the background, job workers need to have a copy of 38 | # MailDeliveryJob to ensure all delivery jobs are processed properly. 39 | # Make sure your entire app is migrated and stable on 6.0 before using this setting. 40 | # Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" 41 | 42 | # Enable the same cache key to be reused when the object being cached of type 43 | # `ActiveRecord::Relation` changes by moving the volatile information (max updated at and count) 44 | # of the relation's cache key into the cache version to support recycling cache key. 45 | # Rails.application.config.active_record.collection_cache_versioning = true 46 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /test/dummy/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum, this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # The code in the `on_worker_boot` will be called if you are using 36 | # clustered mode by specifying a number of `workers`. After each worker 37 | # process is booted this block will be run, if you are using `preload_app!` 38 | # option you will want to use this block to reconnect to any threads 39 | # or connections that may have been created at application boot, Ruby 40 | # cannot share connections between processes. 41 | # 42 | # on_worker_boot do 43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 44 | # end 45 | 46 | # Allow puma to be restarted by `rails restart` command. 47 | plugin :tmp_restart 48 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 6bd8e5f088bb60201e69cd03b4bb6de8064e8b85f1c008be1d4cd80a74549b8fe35490015832f22bc6520bdbb9b937475ea512911bb2444d0861204d750da584 15 | 16 | test: 17 | secret_key_base: 7a8f65781846d959bd9af9d79ab155bc02bec208e1c147d083c17df7676b88d16897c310a09f3a8df7fe8e89fc70c9c12059ca8cc67c2ad0fdd6c0637302c447 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /test/dummy/config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /test/dummy/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/lib/assets/.keep -------------------------------------------------------------------------------- /test/dummy/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/log/.keep -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /test/dummy/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /test/dummy/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/public/apple-touch-icon.png -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workarea-commerce/rails-decorators/0d413f10f842039f6ed31553636ca63c24009375/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/lib/rails/decorators/decorate_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class DecorateTest < Minitest::Test 4 | class TestClass 5 | def self.foo 6 | 'bar' 7 | end 8 | 9 | def foo 10 | 'bar' 11 | end 12 | end 13 | 14 | module Namespace 15 | class TestClass < TestClass 16 | def foo 17 | 'baz' 18 | end 19 | end 20 | end 21 | 22 | class ChildClass < TestClass 23 | end 24 | 25 | decorate(TestClass, with: 'testing') do 26 | class_methods do 27 | def foo 28 | "#{super}|baz" 29 | end 30 | end 31 | 32 | before_decorate { alias_method :foobar, :foo } 33 | decorated { attr_reader :test } 34 | 35 | def foo 36 | "#{super}|baz" 37 | end 38 | end 39 | 40 | decorate(ChildClass, with: 'testing') do 41 | def baz 42 | 'decorated' 43 | end 44 | end 45 | 46 | decorate(Namespace::TestClass, with: 'testing') do 47 | def foo 48 | 'namespace decorated' 49 | end 50 | end 51 | 52 | def test_decorate 53 | assert(TestClass.new.respond_to?(:test)) 54 | assert_equal('bar|baz', TestClass.new.foo) 55 | assert_equal('bar|baz', TestClass.foo) 56 | assert_equal('bar', TestClass.new.foobar) 57 | end 58 | 59 | def test_subclass_decoration 60 | assert_equal('decorated', ChildClass.new.baz) 61 | end 62 | 63 | def test_decorating_within_a_namespace 64 | assert_equal('namespace decorated', Namespace::TestClass.new.foo) 65 | end 66 | 67 | def test_module_definition 68 | decorate(TestClass, with: 'more_tests') {} 69 | assert(TestClass.const_defined?(:MoreTestsDecorateTestTestClassDecorator)) 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /test/lib/rails/decorators/decorates_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Rails 4 | class DecoratesTest < Minitest::Test 5 | class TestClass 6 | def self.foo 7 | 'bar' 8 | end 9 | 10 | def foo 11 | 'bar' 12 | end 13 | end 14 | 15 | module FooModule 16 | extend Rails::Decorators::Decorator 17 | 18 | module ClassMethodsDecorator 19 | def foo 20 | "#{super}|baz" 21 | end 22 | end 23 | 24 | decorated { attr_reader :test } 25 | 26 | def foo 27 | "#{super}|baz" 28 | end 29 | end 30 | 31 | def test_decorates 32 | FooModule.decorates(TestClass) 33 | 34 | assert(TestClass.new.respond_to?(:test)) 35 | assert_equal('bar|baz', TestClass.new.foo) 36 | assert_equal('bar|baz', TestClass.foo) 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/lib/rails/decorators/decorator_loading_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class DecoratorLoadingTest < Minitest::Test 4 | def test_loads_decorators_from_host_app 5 | assert_equal('bar baz', Rails::Decorators::TestModel.new.foo) 6 | end 7 | 8 | def test_loads_decorators_from_engine 9 | assert(Rails::Decorators.const_defined?('TestDecorator')) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/lib/rails/decorators/invalid_decoration_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Rails 4 | class InvalidDecorationTest < Minitest::Test 5 | class TestClass 6 | end 7 | 8 | module TestModule 9 | end 10 | 11 | def test_duplicate_decorating 12 | decorate(TestClass, with: 'testing') {} 13 | 14 | assert_raises(Rails::Decorators::InvalidDecorator) do 15 | decorate(TestClass, with: 'testing') {} 16 | end 17 | end 18 | 19 | def test_module_decorating 20 | assert_raises(Rails::Decorators::InvalidDecorator) do 21 | decorate(TestModule) {} 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /test/lib/rails/decorators/multiple_decorations_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Rails 4 | class MultipleDecorationsTest < Minitest::Test 5 | class One 6 | def self.foo 7 | '1' 8 | end 9 | 10 | def foo 11 | '1' 12 | end 13 | end 14 | 15 | class Two 16 | def self.foo 17 | '2' 18 | end 19 | 20 | def foo 21 | '2' 22 | end 23 | end 24 | 25 | def test_can_decorate_multiple_classes_at_once 26 | decorate(One, Two, with: 'testing') do 27 | class_methods do 28 | def foo 29 | "#{super}|baz" 30 | end 31 | end 32 | 33 | decorated { attr_reader :test } 34 | 35 | def foo 36 | "#{super}|baz" 37 | end 38 | end 39 | 40 | assert(One.new.respond_to?(:test)) 41 | assert_equal('1|baz', One.new.foo) 42 | assert_equal('1|baz', One.foo) 43 | 44 | assert(Two.new.respond_to?(:test)) 45 | assert_equal('2|baz', Two.new.foo) 46 | assert_equal('2|baz', Two.foo) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /test/lib/rails/decorators_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module Rails 4 | class DecoratorsTest < Minitest::Test 5 | def test_that_it_has_a_version_number 6 | refute_nil ::Rails::Decorators::VERSION 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require File.expand_path("../../test/dummy/config/environment.rb", __FILE__) 5 | ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../test/dummy/db/migrate", __FILE__)] 6 | ActiveRecord::Migrator.migrations_paths << File.expand_path('../../db/migrate', __FILE__) 7 | require "rails/test_help" 8 | 9 | # Filter out Minitest backtrace while allowing backtrace from other libraries 10 | # to be shown. 11 | Minitest.backtrace_filter = Minitest::BacktraceFilter.new 12 | 13 | 14 | # Load fixtures from the engine 15 | if ActiveSupport::TestCase.respond_to?(:fixture_path=) 16 | ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) 17 | ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path 18 | ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" 19 | ActiveSupport::TestCase.fixtures :all 20 | end 21 | --------------------------------------------------------------------------------