All Files ( 15.5% covered at 2.4 hits/line )
138 files in total.
7213 relevant lines,
1118 lines covered and
6095 lines missed.
(
15.5%
)
-
# frozen_string_literal: true
-
-
require "active_support/core_ext/module/attribute_accessors"
-
require "rails/test_unit/reporter"
-
require "rails/test_unit/runner"
-
-
module Minitest
-
class SuppressedSummaryReporter < SummaryReporter
-
# Disable extra failure output after a run if output is inline.
-
def aggregated_results(*)
-
super unless options[:output_inline]
-
end
-
end
-
-
def self.plugin_rails_options(opts, options)
-
::Rails::TestUnit::Runner.attach_before_load_options(opts)
-
-
opts.on("-b", "--backtrace", "Show the complete backtrace") do
-
options[:full_backtrace] = true
-
end
-
-
opts.on("-d", "--defer-output", "Output test failures and errors after the test run") do
-
options[:output_inline] = false
-
end
-
-
opts.on("-f", "--fail-fast", "Abort test run on first failure or error") do
-
options[:fail_fast] = true
-
end
-
-
opts.on("-c", "--[no-]color", "Enable color in the output") do |value|
-
options[:color] = value
-
end
-
-
options[:color] = true
-
options[:output_inline] = true
-
end
-
-
# Owes great inspiration to test runner trailblazers like RSpec,
-
# minitest-reporters, maxitest and others.
-
def self.plugin_rails_init(options)
-
unless options[:full_backtrace] || ENV["BACKTRACE"]
-
# Plugin can run without Rails loaded, check before filtering.
-
Minitest.backtrace_filter = ::Rails.backtrace_cleaner if ::Rails.respond_to?(:backtrace_cleaner)
-
end
-
-
# Suppress summary reports when outputting inline rerun snippets.
-
if reporter.reporters.reject! { |reporter| reporter.kind_of?(SummaryReporter) }
-
reporter << SuppressedSummaryReporter.new(options[:io], options)
-
end
-
-
# Replace progress reporter for colors.
-
if reporter.reporters.reject! { |reporter| reporter.kind_of?(ProgressReporter) }
-
reporter << ::Rails::TestUnitReporter.new(options[:io], options)
-
end
-
end
-
-
# Backwards compatibility with Rails 5.0 generated plugin test scripts
-
mattr_reader :run_via, default: {}
-
end
-
# frozen_string_literal: true
-
-
require "rails/ruby_version_check"
-
-
require "pathname"
-
-
require "active_support"
-
require "active_support/core_ext/kernel/reporting"
-
require "active_support/core_ext/module/delegation"
-
require "active_support/core_ext/array/extract_options"
-
require "active_support/core_ext/object/blank"
-
-
require "rails/application"
-
require "rails/version"
-
require "rails/autoloaders"
-
-
require "active_support/railtie"
-
require "action_dispatch/railtie"
-
-
# UTF-8 is the default internal and external encoding.
-
silence_warnings do
-
Encoding.default_external = Encoding::UTF_8
-
Encoding.default_internal = Encoding::UTF_8
-
end
-
-
module Rails
-
extend ActiveSupport::Autoload
-
-
autoload :Info
-
autoload :InfoController
-
autoload :MailersController
-
autoload :WelcomeController
-
-
class << self
-
@application = @app_class = nil
-
-
attr_writer :application
-
attr_accessor :app_class, :cache, :logger
-
def application
-
@application ||= (app_class.instance if app_class)
-
end
-
-
delegate :initialize!, :initialized?, to: :application
-
-
# The Configuration instance used to configure the Rails environment
-
def configuration
-
application.config
-
end
-
-
def backtrace_cleaner
-
@backtrace_cleaner ||= begin
-
# Relies on Active Support, so we have to lazy load to postpone definition until Active Support has been loaded
-
require "rails/backtrace_cleaner"
-
Rails::BacktraceCleaner.new
-
end
-
end
-
-
# Returns a Pathname object of the current Rails project,
-
# otherwise it returns +nil+ if there is no project:
-
#
-
# Rails.root
-
# # => #<Pathname:/Users/someuser/some/path/project>
-
def root
-
application && application.config.root
-
end
-
-
# Returns the current Rails environment.
-
#
-
# Rails.env # => "development"
-
# Rails.env.development? # => true
-
# Rails.env.production? # => false
-
def env
-
@_env ||= ActiveSupport::EnvironmentInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development")
-
end
-
-
# Sets the Rails environment.
-
#
-
# Rails.env = "staging" # => "staging"
-
def env=(environment)
-
@_env = ActiveSupport::EnvironmentInquirer.new(environment)
-
end
-
-
# Returns all Rails groups for loading based on:
-
#
-
# * The Rails environment;
-
# * The environment variable RAILS_GROUPS;
-
# * The optional envs given as argument and the hash with group dependencies;
-
#
-
# Rails.groups assets: [:development, :test]
-
# # => [:default, "development", :assets] for Rails.env == "development"
-
# # => [:default, "production"] for Rails.env == "production"
-
def groups(*groups)
-
hash = groups.extract_options!
-
env = Rails.env
-
groups.unshift(:default, env)
-
groups.concat ENV["RAILS_GROUPS"].to_s.split(",")
-
groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) }
-
groups.compact!
-
groups.uniq!
-
groups
-
end
-
-
# Returns a Pathname object of the public folder of the current
-
# Rails project, otherwise it returns +nil+ if there is no project:
-
#
-
# Rails.public_path
-
# # => #<Pathname:/Users/someuser/some/path/project/public>
-
def public_path
-
application && Pathname.new(application.paths["public"].first)
-
end
-
-
def autoloaders
-
Autoloaders
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
# rubocop:disable Style/RedundantBegin
-
-
17
require "rails"
-
-
%w(
-
active_record/railtie
-
active_storage/engine
-
action_controller/railtie
-
action_view/railtie
-
action_mailer/railtie
-
active_job/railtie
-
action_cable/engine
-
action_mailbox/engine
-
action_text/engine
-
rails/test_unit/railtie
-
sprockets/railtie
-
17
).each do |railtie|
-
187
begin
-
187
require railtie
-
rescue LoadError
-
end
-
end
-
# frozen_string_literal: true
-
-
require "sdoc"
-
require "active_support/core_ext/array/extract"
-
-
class RDoc::Generator::API < RDoc::Generator::SDoc # :nodoc:
-
RDoc::RDoc.add_generator self
-
-
def generate_class_tree_level(classes, visited = {})
-
# Only process core extensions on the first visit and remove
-
# Active Storage duplicated classes that are at the top level
-
# since they aren't nested under a definition of the `ActiveStorage` module.
-
if visited.empty?
-
classes = classes.reject { |klass| active_storage?(klass) }
-
core_exts = classes.extract! { |klass| core_extension?(klass) }
-
-
super.unshift([ "Core extensions", "", "", build_core_ext_subtree(core_exts, visited) ])
-
else
-
super
-
end
-
end
-
-
private
-
def build_core_ext_subtree(classes, visited)
-
classes.map do |klass|
-
[ klass.name, klass.document_self_or_methods ? klass.path : "", "",
-
generate_class_tree_level(klass.classes_and_modules, visited) ]
-
end
-
end
-
-
def core_extension?(klass)
-
klass.name != "ActiveSupport" && klass.in_files.any? { |file| file.absolute_name.include?("core_ext") }
-
end
-
-
def active_storage?(klass)
-
klass.name != "ActiveStorage" && klass.in_files.all? { |file| file.absolute_name.include?("active_storage") }
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rdoc/task"
-
require "rails/api/generator"
-
-
module Rails
-
module API
-
class Task < RDoc::Task
-
RDOC_FILES = {
-
"activesupport" => {
-
include: %w(
-
README.rdoc
-
lib/active_support/**/*.rb
-
)
-
},
-
-
"activerecord" => {
-
include: %w(
-
README.rdoc
-
lib/active_record/**/*.rb
-
lib/arel.rb
-
)
-
},
-
-
"activemodel" => {
-
include: %w(
-
README.rdoc
-
lib/active_model/**/*.rb
-
)
-
},
-
-
"actionpack" => {
-
include: %w(
-
README.rdoc
-
lib/abstract_controller/**/*.rb
-
lib/action_controller/**/*.rb
-
lib/action_dispatch/**/*.rb
-
)
-
},
-
-
"actionview" => {
-
include: %w(
-
README.rdoc
-
lib/action_view/**/*.rb
-
),
-
exclude: "lib/action_view/vendor/*"
-
},
-
-
"actionmailer" => {
-
include: %w(
-
README.rdoc
-
lib/action_mailer/**/*.rb
-
)
-
},
-
-
"activejob" => {
-
include: %w(
-
README.md
-
lib/active_job/**/*.rb
-
)
-
},
-
-
"actioncable" => {
-
include: %w(
-
README.md
-
lib/action_cable/**/*.rb
-
)
-
},
-
-
"activestorage" => {
-
include: %w(
-
README.md
-
app/**/active_storage/**/*.rb
-
lib/active_storage/**/*.rb
-
)
-
},
-
-
"actionmailbox" => {
-
include: %w(
-
README.md
-
app/**/action_mailbox/**/*.rb
-
lib/action_mailbox/**/*.rb
-
)
-
},
-
-
"actiontext" => {
-
include: %w(
-
README.md
-
app/**/action_text/**/*.rb
-
lib/action_text/**/*.rb
-
)
-
},
-
-
"railties" => {
-
include: %w(
-
README.rdoc
-
lib/**/*.rb
-
),
-
exclude: %w(
-
lib/rails/generators/**/templates/**/*.rb
-
lib/rails/test_unit/*
-
lib/rails/api/generator.rb
-
)
-
}
-
}
-
-
def initialize(name)
-
super
-
-
# Every time rake runs this task is instantiated as all the rest.
-
# Be lazy computing stuff to have as light impact as possible to
-
# the rest of tasks.
-
before_running_rdoc do
-
configure_sdoc
-
configure_rdoc_files
-
setup_horo_variables
-
end
-
end
-
-
# Hack, ignore the desc calls performed by the original initializer.
-
def desc(description)
-
# no-op
-
end
-
-
def configure_sdoc
-
self.title = "Ruby on Rails API"
-
self.rdoc_dir = api_dir
-
-
options << "-m" << api_main
-
options << "-e" << "UTF-8"
-
-
options << "-f" << "api"
-
options << "-T" << "rails"
-
end
-
-
def configure_rdoc_files
-
rdoc_files.include(api_main)
-
-
RDOC_FILES.each do |component, cfg|
-
cdr = component_root_dir(component)
-
-
Array(cfg[:include]).each do |pattern|
-
rdoc_files.include("#{cdr}/#{pattern}")
-
end
-
-
Array(cfg[:exclude]).each do |pattern|
-
rdoc_files.exclude("#{cdr}/#{pattern}")
-
end
-
end
-
-
# Only generate documentation for files that have been
-
# changed since the API was generated.
-
if Dir.exist?("doc/rdoc") && !ENV["ALL"]
-
last_generation = DateTime.rfc2822(File.open("doc/rdoc/created.rid", &:readline))
-
-
rdoc_files.keep_if do |file|
-
File.mtime(file).to_datetime > last_generation
-
end
-
-
# Nothing to do
-
exit(0) if rdoc_files.empty?
-
end
-
end
-
-
def setup_horo_variables
-
ENV["HORO_PROJECT_NAME"] = "Ruby on Rails"
-
ENV["HORO_PROJECT_VERSION"] = rails_version
-
end
-
-
def api_main
-
component_root_dir("railties") + "/RDOC_MAIN.rdoc"
-
end
-
end
-
-
class RepoTask < Task
-
def configure_sdoc
-
super
-
options << "-g" # link to GitHub, SDoc flag
-
end
-
-
def component_root_dir(component)
-
component
-
end
-
-
def api_dir
-
"doc/rdoc"
-
end
-
end
-
-
class EdgeTask < RepoTask
-
def rails_version
-
"master@#{`git rev-parse HEAD`[0, 7]}"
-
end
-
end
-
-
class StableTask < RepoTask
-
def rails_version
-
File.read("RAILS_VERSION").strip
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
require "rails/version"
-
-
module Rails
-
module AppLoader # :nodoc:
-
extend self
-
-
RUBY = Gem.ruby
-
EXECUTABLES = ["bin/rails", "script/rails"]
-
BUNDLER_WARNING = <<EOS
-
Beginning in Rails 4, Rails ships with a `rails` binstub at ./bin/rails that
-
should be used instead of the Bundler-generated `rails` binstub.
-
-
If you are seeing this message, your binstub at ./bin/rails was generated by
-
Bundler instead of Rails.
-
-
You might need to regenerate your `rails` binstub locally and add it to source
-
control:
-
-
rails app:update:bin # Bear in mind this generates other binstubs
-
# too that you may or may not want (like yarn)
-
-
If you already have Rails binstubs in source control, you might be
-
inadvertently overwriting them during deployment by using bundle install
-
with the --binstubs option.
-
-
If your application was created prior to Rails 4, here's how to upgrade:
-
-
bundle config --delete bin # Turn off Bundler's stub generator
-
rails app:update:bin # Use the new Rails executables
-
git add bin # Add bin/ to source control
-
-
You may need to remove bin/ from your .gitignore as well.
-
-
When you install a gem whose executable you want to use in your app,
-
generate it and add it to source control:
-
-
bundle binstubs some-gem-name
-
git add bin/new-executable
-
-
EOS
-
-
def exec_app
-
original_cwd = Dir.pwd
-
-
loop do
-
if exe = find_executable
-
contents = File.read(exe)
-
-
if /(APP|ENGINE)_PATH/.match?(contents)
-
exec RUBY, exe, *ARGV
-
break # non reachable, hack to be able to stub exec in the test suite
-
elsif exe.end_with?("bin/rails") && contents.include?("This file was generated by Bundler")
-
$stderr.puts(BUNDLER_WARNING)
-
Object.const_set(:APP_PATH, File.expand_path("config/application", Dir.pwd))
-
require File.expand_path("../boot", APP_PATH)
-
require "rails/commands"
-
break
-
end
-
end
-
-
# If we exhaust the search there is no executable, this could be a
-
# call to generate a new application, so restore the original cwd.
-
Dir.chdir(original_cwd) && return if Pathname.new(Dir.pwd).root?
-
-
# Otherwise keep moving upwards in search of an executable.
-
Dir.chdir("..")
-
end
-
end
-
-
def find_executable
-
EXECUTABLES.find { |exe| File.file?(exe) }
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators"
-
require "rails/generators/rails/app/app_generator"
-
-
module Rails
-
class AppUpdater # :nodoc:
-
class << self
-
def invoke_from_app_generator(method)
-
app_generator.send(method)
-
end
-
-
def app_generator
-
@app_generator ||= begin
-
gen = Rails::Generators::AppGenerator.new ["rails"], generator_options, destination_root: Rails.root
-
File.exist?(Rails.root.join("config", "application.rb")) ? gen.send(:app_const) : gen.send(:valid_const?)
-
gen
-
end
-
end
-
-
private
-
def generator_options
-
options = { api: !!Rails.application.config.api_only, update: true }
-
options[:skip_javascript] = !File.exist?(Rails.root.join("bin", "yarn"))
-
options[:skip_active_record] = !defined?(ActiveRecord::Railtie)
-
options[:skip_active_storage] = !defined?(ActiveStorage::Engine) || !defined?(ActiveRecord::Railtie)
-
options[:skip_action_mailer] = !defined?(ActionMailer::Railtie)
-
options[:skip_action_cable] = !defined?(ActionCable::Engine)
-
options[:skip_sprockets] = !defined?(Sprockets::Railtie)
-
options[:skip_puma] = !defined?(Puma)
-
options[:skip_bootsnap] = !defined?(Bootsnap)
-
options[:skip_spring] = !defined?(Spring)
-
options
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "yaml"
-
require "active_support/core_ext/hash/keys"
-
require "active_support/core_ext/object/blank"
-
require "active_support/key_generator"
-
require "active_support/message_verifier"
-
require "active_support/encrypted_configuration"
-
require "active_support/deprecation"
-
require "active_support/hash_with_indifferent_access"
-
require "active_support/configuration_file"
-
require "rails/engine"
-
require "rails/secrets"
-
-
module Rails
-
# An Engine with the responsibility of coordinating the whole boot process.
-
#
-
# == Initialization
-
#
-
# Rails::Application is responsible for executing all railties and engines
-
# initializers. It also executes some bootstrap initializers (check
-
# Rails::Application::Bootstrap) and finishing initializers, after all the others
-
# are executed (check Rails::Application::Finisher).
-
#
-
# == Configuration
-
#
-
# Besides providing the same configuration as Rails::Engine and Rails::Railtie,
-
# the application object has several specific configurations, for example
-
# "cache_classes", "consider_all_requests_local", "filter_parameters",
-
# "logger" and so forth.
-
#
-
# Check Rails::Application::Configuration to see them all.
-
#
-
# == Routes
-
#
-
# The application object is also responsible for holding the routes and reloading routes
-
# whenever the files change in development.
-
#
-
# == Middlewares
-
#
-
# The Application is also responsible for building the middleware stack.
-
#
-
# == Booting process
-
#
-
# The application is also responsible for setting up and executing the booting
-
# process. From the moment you require "config/application.rb" in your app,
-
# the booting process goes like this:
-
#
-
# 1) require "config/boot.rb" to set up load paths
-
# 2) require railties and engines
-
# 3) Define Rails.application as "class MyApp::Application < Rails::Application"
-
# 4) Run config.before_configuration callbacks
-
# 5) Load config/environments/ENV.rb
-
# 6) Run config.before_initialize callbacks
-
# 7) Run Railtie#initializer defined by railties, engines and application.
-
# One by one, each engine sets up its load paths, routes and runs its config/initializers/* files.
-
# 8) Custom Railtie#initializers added by railties, engines and applications are executed
-
# 9) Build the middleware stack and run to_prepare callbacks
-
# 10) Run config.before_eager_load and eager_load! if eager_load is true
-
# 11) Run config.after_initialize callbacks
-
#
-
# == Multiple Applications
-
#
-
# If you decide to define multiple applications, then the first application
-
# that is initialized will be set to +Rails.application+, unless you override
-
# it with a different application.
-
#
-
# To create a new application, you can instantiate a new instance of a class
-
# that has already been created:
-
#
-
# class Application < Rails::Application
-
# end
-
#
-
# first_application = Application.new
-
# second_application = Application.new(config: first_application.config)
-
#
-
# In the above example, the configuration from the first application was used
-
# to initialize the second application. You can also use the +initialize_copy+
-
# on one of the applications to create a copy of the application which shares
-
# the configuration.
-
#
-
# If you decide to define Rake tasks, runners, or initializers in an
-
# application other than +Rails.application+, then you must run them manually.
-
class Application < Engine
-
autoload :Bootstrap, "rails/application/bootstrap"
-
autoload :Configuration, "rails/application/configuration"
-
autoload :DefaultMiddlewareStack, "rails/application/default_middleware_stack"
-
autoload :Finisher, "rails/application/finisher"
-
autoload :Railties, "rails/engine/railties"
-
autoload :RoutesReloader, "rails/application/routes_reloader"
-
-
class << self
-
def inherited(base)
-
super
-
Rails.app_class = base
-
add_lib_to_load_path!(find_root(base.called_from))
-
ActiveSupport.run_load_hooks(:before_configuration, base)
-
end
-
-
def instance
-
super.run_load_hooks!
-
end
-
-
def create(initial_variable_values = {}, &block)
-
new(initial_variable_values, &block).run_load_hooks!
-
end
-
-
def find_root(from)
-
find_root_with_flag "config.ru", from, Dir.pwd
-
end
-
-
# Makes the +new+ method public.
-
#
-
# Note that Rails::Application inherits from Rails::Engine, which
-
# inherits from Rails::Railtie and the +new+ method on Rails::Railtie is
-
# private
-
public :new
-
end
-
-
attr_accessor :assets, :sandbox
-
alias_method :sandbox?, :sandbox
-
attr_reader :reloaders, :reloader, :executor
-
-
delegate :default_url_options, :default_url_options=, to: :routes
-
-
INITIAL_VARIABLES = [:config, :railties, :routes_reloader, :reloaders,
-
:routes, :helpers, :app_env_config, :secrets] # :nodoc:
-
-
def initialize(initial_variable_values = {}, &block)
-
super()
-
@initialized = false
-
@reloaders = []
-
@routes_reloader = nil
-
@app_env_config = nil
-
@ordered_railties = nil
-
@railties = nil
-
@message_verifiers = {}
-
@ran_load_hooks = false
-
-
@executor = Class.new(ActiveSupport::Executor)
-
@reloader = Class.new(ActiveSupport::Reloader)
-
@reloader.executor = @executor
-
-
# are these actually used?
-
@initial_variable_values = initial_variable_values
-
@block = block
-
end
-
-
# Returns true if the application is initialized.
-
def initialized?
-
@initialized
-
end
-
-
def run_load_hooks! # :nodoc:
-
return self if @ran_load_hooks
-
@ran_load_hooks = true
-
-
@initial_variable_values.each do |variable_name, value|
-
if INITIAL_VARIABLES.include?(variable_name)
-
instance_variable_set("@#{variable_name}", value)
-
end
-
end
-
-
instance_eval(&@block) if @block
-
self
-
end
-
-
# Reload application routes regardless if they changed or not.
-
def reload_routes!
-
routes_reloader.reload!
-
end
-
-
# Returns the application's KeyGenerator
-
def key_generator
-
# number of iterations selected based on consultation with the google security
-
# team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
-
@caching_key_generator ||= ActiveSupport::CachingKeyGenerator.new(
-
ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
-
)
-
end
-
-
# Returns a message verifier object.
-
#
-
# This verifier can be used to generate and verify signed messages in the application.
-
#
-
# It is recommended not to use the same verifier for different things, so you can get different
-
# verifiers passing the +verifier_name+ argument.
-
#
-
# ==== Parameters
-
#
-
# * +verifier_name+ - the name of the message verifier.
-
#
-
# ==== Examples
-
#
-
# message = Rails.application.message_verifier('sensitive_data').generate('my sensible data')
-
# Rails.application.message_verifier('sensitive_data').verify(message)
-
# # => 'my sensible data'
-
#
-
# See the +ActiveSupport::MessageVerifier+ documentation for more information.
-
def message_verifier(verifier_name)
-
@message_verifiers[verifier_name] ||= begin
-
secret = key_generator.generate_key(verifier_name.to_s)
-
ActiveSupport::MessageVerifier.new(secret)
-
end
-
end
-
-
# Convenience for loading config/foo.yml for the current Rails env.
-
#
-
# Examples:
-
#
-
# # config/exception_notification.yml:
-
# production:
-
# url: http://127.0.0.1:8080
-
# namespace: my_app_production
-
#
-
# development:
-
# url: http://localhost:3001
-
# namespace: my_app_development
-
#
-
# # config/environments/production.rb
-
# Rails.application.configure do
-
# config.middleware.use ExceptionNotifier, config_for(:exception_notification)
-
# end
-
#
-
# # You can also store configurations in a shared section which will be
-
# # merged with the environment configuration
-
#
-
# # config/example.yml
-
# shared:
-
# foo:
-
# bar:
-
# baz: 1
-
#
-
# development:
-
# foo:
-
# bar:
-
# qux: 2
-
#
-
# # development environment
-
# Rails.application.config_for(:example)[:foo][:bar]
-
# # => { baz: 1, qux: 2 }
-
def config_for(name, env: Rails.env)
-
yaml = name.is_a?(Pathname) ? name : Pathname.new("#{paths["config"].existent.first}/#{name}.yml")
-
-
if yaml.exist?
-
require "erb"
-
all_configs = ActiveSupport::ConfigurationFile.parse(yaml, symbolize_names: true)
-
config, shared = all_configs[env.to_sym], all_configs[:shared]
-
-
if config.is_a?(Hash)
-
ActiveSupport::OrderedOptions.new.update(shared&.deep_merge(config) || config)
-
else
-
config || shared
-
end
-
else
-
raise "Could not load configuration. No such file - #{yaml}"
-
end
-
end
-
-
# Stores some of the Rails initial environment parameters which
-
# will be used by middlewares and engines to configure themselves.
-
def env_config
-
@app_env_config ||= begin
-
super.merge(
-
"action_dispatch.parameter_filter" => config.filter_parameters,
-
"action_dispatch.redirect_filter" => config.filter_redirect,
-
"action_dispatch.secret_key_base" => secret_key_base,
-
"action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
-
"action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local,
-
"action_dispatch.logger" => Rails.logger,
-
"action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner,
-
"action_dispatch.key_generator" => key_generator,
-
"action_dispatch.http_auth_salt" => config.action_dispatch.http_auth_salt,
-
"action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt,
-
"action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt,
-
"action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt,
-
"action_dispatch.authenticated_encrypted_cookie_salt" => config.action_dispatch.authenticated_encrypted_cookie_salt,
-
"action_dispatch.use_authenticated_cookie_encryption" => config.action_dispatch.use_authenticated_cookie_encryption,
-
"action_dispatch.encrypted_cookie_cipher" => config.action_dispatch.encrypted_cookie_cipher,
-
"action_dispatch.signed_cookie_digest" => config.action_dispatch.signed_cookie_digest,
-
"action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer,
-
"action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest,
-
"action_dispatch.cookies_rotations" => config.action_dispatch.cookies_rotations,
-
"action_dispatch.cookies_same_site_protection" => config.action_dispatch.cookies_same_site_protection,
-
"action_dispatch.use_cookies_with_metadata" => config.action_dispatch.use_cookies_with_metadata,
-
"action_dispatch.content_security_policy" => config.content_security_policy,
-
"action_dispatch.content_security_policy_report_only" => config.content_security_policy_report_only,
-
"action_dispatch.content_security_policy_nonce_generator" => config.content_security_policy_nonce_generator,
-
"action_dispatch.content_security_policy_nonce_directives" => config.content_security_policy_nonce_directives,
-
"action_dispatch.feature_policy" => config.feature_policy,
-
)
-
end
-
end
-
-
# If you try to define a set of Rake tasks on the instance, these will get
-
# passed up to the Rake tasks defined on the application's class.
-
def rake_tasks(&block)
-
self.class.rake_tasks(&block)
-
end
-
-
# Sends the initializers to the +initializer+ method defined in the
-
# Rails::Initializable module. Each Rails::Application class has its own
-
# set of initializers, as defined by the Initializable module.
-
def initializer(name, opts = {}, &block)
-
self.class.initializer(name, opts, &block)
-
end
-
-
# Sends any runner called in the instance of a new application up
-
# to the +runner+ method defined in Rails::Railtie.
-
def runner(&blk)
-
self.class.runner(&blk)
-
end
-
-
# Sends any console called in the instance of a new application up
-
# to the +console+ method defined in Rails::Railtie.
-
def console(&blk)
-
self.class.console(&blk)
-
end
-
-
# Sends any generators called in the instance of a new application up
-
# to the +generators+ method defined in Rails::Railtie.
-
def generators(&blk)
-
self.class.generators(&blk)
-
end
-
-
# Sends the +isolate_namespace+ method up to the class method.
-
def isolate_namespace(mod)
-
self.class.isolate_namespace(mod)
-
end
-
-
## Rails internal API
-
-
# This method is called just after an application inherits from Rails::Application,
-
# allowing the developer to load classes in lib and use them during application
-
# configuration.
-
#
-
# class MyApplication < Rails::Application
-
# require "my_backend" # in lib/my_backend
-
# config.i18n.backend = MyBackend
-
# end
-
#
-
# Notice this method takes into consideration the default root path. So if you
-
# are changing config.root inside your application definition or having a custom
-
# Rails application, you will need to add lib to $LOAD_PATH on your own in case
-
# you need to load files in lib/ during the application configuration as well.
-
def self.add_lib_to_load_path!(root) #:nodoc:
-
path = File.join root, "lib"
-
if File.exist?(path) && !$LOAD_PATH.include?(path)
-
$LOAD_PATH.unshift(path)
-
end
-
end
-
-
def require_environment! #:nodoc:
-
environment = paths["config/environment"].existent.first
-
require environment if environment
-
end
-
-
def routes_reloader #:nodoc:
-
@routes_reloader ||= RoutesReloader.new
-
end
-
-
# Returns an array of file paths appended with a hash of
-
# directories-extensions suitable for ActiveSupport::FileUpdateChecker
-
# API.
-
def watchable_args #:nodoc:
-
files, dirs = config.watchable_files.dup, config.watchable_dirs.dup
-
-
ActiveSupport::Dependencies.autoload_paths.each do |path|
-
File.file?(path) ? files << path.to_s : dirs[path.to_s] = [:rb]
-
end
-
-
[files, dirs]
-
end
-
-
# Initialize the application passing the given group. By default, the
-
# group is :default
-
def initialize!(group = :default) #:nodoc:
-
raise "Application has been already initialized." if @initialized
-
run_initializers(group, self)
-
@initialized = true
-
self
-
end
-
-
def initializers #:nodoc:
-
Bootstrap.initializers_for(self) +
-
railties_initializers(super) +
-
Finisher.initializers_for(self)
-
end
-
-
def config #:nodoc:
-
@config ||= Application::Configuration.new(self.class.find_root(self.class.called_from))
-
end
-
-
attr_writer :config
-
-
# Returns secrets added to config/secrets.yml.
-
#
-
# Example:
-
#
-
# development:
-
# secret_key_base: 836fa3665997a860728bcb9e9a1e704d427cfc920e79d847d79c8a9a907b9e965defa4154b2b86bdec6930adbe33f21364523a6f6ce363865724549fdfc08553
-
# test:
-
# secret_key_base: 5a37811464e7d378488b0f073e2193b093682e4e21f5d6f3ae0a4e1781e61a351fdc878a843424e81c73fb484a40d23f92c8dafac4870e74ede6e5e174423010
-
# production:
-
# secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
-
# namespace: my_app_production
-
#
-
# +Rails.application.secrets.namespace+ returns +my_app_production+ in the
-
# production environment.
-
def secrets
-
@secrets ||= begin
-
secrets = ActiveSupport::OrderedOptions.new
-
files = config.paths["config/secrets"].existent
-
files = files.reject { |path| path.end_with?(".enc") } unless config.read_encrypted_secrets
-
secrets.merge! Rails::Secrets.parse(files, env: Rails.env)
-
-
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
-
secrets.secret_key_base ||= config.secret_key_base
-
-
secrets
-
end
-
end
-
-
attr_writer :secrets
-
-
# The secret_key_base is used as the input secret to the application's key generator, which in turn
-
# is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies.
-
#
-
# In development and test, this is randomly generated and stored in a
-
# temporary file in <tt>tmp/development_secret.txt</tt>.
-
#
-
# In all other environments, we look for it first in ENV["SECRET_KEY_BASE"],
-
# then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications,
-
# the correct place to store it is in the encrypted credentials file.
-
def secret_key_base
-
if Rails.env.development? || Rails.env.test?
-
secrets.secret_key_base ||= generate_development_secret
-
else
-
validate_secret_key_base(
-
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
-
)
-
end
-
end
-
-
# Decrypts the credentials hash as kept in +config/credentials.yml.enc+. This file is encrypted with
-
# the Rails master key, which is either taken from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading
-
# +config/master.key+.
-
# If specific credentials file exists for current environment, it takes precedence, thus for +production+
-
# environment look first for +config/credentials/production.yml.enc+ with master key taken
-
# from <tt>ENV["RAILS_MASTER_KEY"]</tt> or from loading +config/credentials/production.key+.
-
# Default behavior can be overwritten by setting +config.credentials.content_path+ and +config.credentials.key_path+.
-
def credentials
-
@credentials ||= encrypted(config.credentials.content_path, key_path: config.credentials.key_path)
-
end
-
-
# Shorthand to decrypt any encrypted configurations or files.
-
#
-
# For any file added with <tt>rails encrypted:edit</tt> call +read+ to decrypt
-
# the file with the master key.
-
# The master key is either stored in +config/master.key+ or <tt>ENV["RAILS_MASTER_KEY"]</tt>.
-
#
-
# Rails.application.encrypted("config/mystery_man.txt.enc").read
-
# # => "We've met before, haven't we?"
-
#
-
# It's also possible to interpret encrypted YAML files with +config+.
-
#
-
# Rails.application.encrypted("config/credentials.yml.enc").config
-
# # => { next_guys_line: "I don't think so. Where was it you think we met?" }
-
#
-
# Any top-level configs are also accessible directly on the return value:
-
#
-
# Rails.application.encrypted("config/credentials.yml.enc").next_guys_line
-
# # => "I don't think so. Where was it you think we met?"
-
#
-
# The files or configs can also be encrypted with a custom key. To decrypt with
-
# a key in the +ENV+, use:
-
#
-
# Rails.application.encrypted("config/special_tokens.yml.enc", env_key: "SPECIAL_TOKENS")
-
#
-
# Or to decrypt with a file, that should be version control ignored, relative to +Rails.root+:
-
#
-
# Rails.application.encrypted("config/special_tokens.yml.enc", key_path: "config/special_tokens.key")
-
def encrypted(path, key_path: "config/master.key", env_key: "RAILS_MASTER_KEY")
-
ActiveSupport::EncryptedConfiguration.new(
-
config_path: Rails.root.join(path),
-
key_path: Rails.root.join(key_path),
-
env_key: env_key,
-
raise_if_missing_key: config.require_master_key
-
)
-
end
-
-
def to_app #:nodoc:
-
self
-
end
-
-
def helpers_paths #:nodoc:
-
config.helpers_paths
-
end
-
-
console do
-
unless ::Kernel.private_method_defined?(:y)
-
require "psych/y"
-
end
-
end
-
-
# Return an array of railties respecting the order they're loaded
-
# and the order specified by the +railties_order+ config.
-
#
-
# While running initializers we need engines in reverse order here when
-
# copying migrations from railties ; we need them in the order given by
-
# +railties_order+.
-
def migration_railties # :nodoc:
-
ordered_railties.flatten - [self]
-
end
-
-
# Eager loads the application code.
-
def eager_load!
-
if Rails.autoloaders.zeitwerk_enabled?
-
Rails.autoloaders.each(&:eager_load)
-
else
-
super
-
end
-
end
-
-
protected
-
alias :build_middleware_stack :app
-
-
def run_tasks_blocks(app) #:nodoc:
-
railties.each { |r| r.run_tasks_blocks(app) }
-
super
-
require "rails/tasks"
-
task :environment do
-
ActiveSupport.on_load(:before_initialize) { config.eager_load = config.rake_eager_load }
-
-
require_environment!
-
end
-
end
-
-
def run_generators_blocks(app) #:nodoc:
-
railties.each { |r| r.run_generators_blocks(app) }
-
super
-
end
-
-
def run_runner_blocks(app) #:nodoc:
-
railties.each { |r| r.run_runner_blocks(app) }
-
super
-
end
-
-
def run_console_blocks(app) #:nodoc:
-
railties.each { |r| r.run_console_blocks(app) }
-
super
-
end
-
-
# Returns the ordered railties for this application considering railties_order.
-
def ordered_railties #:nodoc:
-
@ordered_railties ||= begin
-
order = config.railties_order.map do |railtie|
-
if railtie == :main_app
-
self
-
elsif railtie.respond_to?(:instance)
-
railtie.instance
-
else
-
railtie
-
end
-
end
-
-
all = (railties - order)
-
all.push(self) unless (all + order).include?(self)
-
order.push(:all) unless order.include?(:all)
-
-
index = order.index(:all)
-
order[index] = all
-
order
-
end
-
end
-
-
def railties_initializers(current) #:nodoc:
-
initializers = []
-
ordered_railties.reverse.flatten.each do |r|
-
if r == self
-
initializers += current
-
else
-
initializers += r.initializers
-
end
-
end
-
initializers
-
end
-
-
def default_middleware_stack #:nodoc:
-
default_stack = DefaultMiddlewareStack.new(self, config, paths)
-
default_stack.build_stack
-
end
-
-
def validate_secret_key_base(secret_key_base)
-
if secret_key_base.is_a?(String) && secret_key_base.present?
-
secret_key_base
-
elsif secret_key_base
-
raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`"
-
else
-
raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
-
end
-
end
-
-
private
-
def generate_development_secret
-
if secrets.secret_key_base.nil?
-
key_file = Rails.root.join("tmp/development_secret.txt")
-
-
if !File.exist?(key_file)
-
random_key = SecureRandom.hex(64)
-
FileUtils.mkdir_p(key_file.dirname)
-
File.binwrite(key_file, random_key)
-
end
-
-
secrets.secret_key_base = File.binread(key_file)
-
end
-
-
secrets.secret_key_base
-
end
-
-
def build_request(env)
-
req = super
-
env["ORIGINAL_FULLPATH"] = req.fullpath
-
env["ORIGINAL_SCRIPT_NAME"] = req.script_name
-
req
-
end
-
-
def build_middleware
-
config.app_middleware + super
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "fileutils"
-
require "active_support/notifications"
-
require "active_support/dependencies"
-
require "active_support/descendants_tracker"
-
require "rails/secrets"
-
-
module Rails
-
class Application
-
module Bootstrap
-
include Initializable
-
-
initializer :load_environment_hook, group: :all do end
-
-
initializer :load_active_support, group: :all do
-
require "active_support/all" unless config.active_support.bare
-
end
-
-
initializer :set_eager_load, group: :all do
-
if config.eager_load.nil?
-
warn <<~INFO
-
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
-
-
* development - set it to false
-
* test - set it to false (unless you use a tool that preloads your test environment)
-
* production - set it to true
-
-
INFO
-
config.eager_load = config.cache_classes
-
end
-
end
-
-
# Initialize the logger early in the stack in case we need to log some deprecation.
-
initializer :initialize_logger, group: :all do
-
Rails.logger ||= config.logger || begin
-
logger = ActiveSupport::Logger.new(config.default_log_file)
-
logger.formatter = config.log_formatter
-
logger = ActiveSupport::TaggedLogging.new(logger)
-
logger
-
rescue StandardError
-
path = config.paths["log"].first
-
logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDERR))
-
logger.level = ActiveSupport::Logger::WARN
-
logger.warn(
-
"Rails Error: Unable to access log file. Please ensure that #{path} exists and is writable " \
-
"(ie, make it writable for user and group: chmod 0664 #{path}). " \
-
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
-
)
-
logger
-
end
-
-
Rails.logger.level = ActiveSupport::Logger.const_get(config.log_level.to_s.upcase)
-
end
-
-
# Initialize cache early in the stack so railties can make use of it.
-
initializer :initialize_cache, group: :all do
-
unless Rails.cache
-
Rails.cache = ActiveSupport::Cache.lookup_store(*config.cache_store)
-
-
if Rails.cache.respond_to?(:middleware)
-
config.middleware.insert_before(::Rack::Runtime, Rails.cache.middleware)
-
end
-
end
-
end
-
-
# Sets the dependency loading mechanism.
-
initializer :initialize_dependency_mechanism, group: :all do
-
ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load
-
end
-
-
initializer :bootstrap_hook, group: :all do |app|
-
ActiveSupport.run_load_hooks(:before_initialize, app)
-
end
-
-
initializer :set_secrets_root, group: :all do
-
Rails::Secrets.root = root
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
17
require "ipaddr"
-
17
require "active_support/core_ext/kernel/reporting"
-
17
require "active_support/core_ext/symbol/starts_ends_with"
-
17
require "active_support/file_update_checker"
-
17
require "active_support/configuration_file"
-
17
require "rails/engine/configuration"
-
17
require "rails/source_annotation_extractor"
-
-
17
module Rails
-
17
class Application
-
17
class Configuration < ::Rails::Engine::Configuration
-
17
attr_accessor :allow_concurrency, :asset_host, :autoflush_log,
-
:cache_classes, :cache_store, :consider_all_requests_local, :console,
-
:eager_load, :exceptions_app, :file_watcher, :filter_parameters,
-
:force_ssl, :helpers_paths, :hosts, :logger, :log_formatter, :log_tags,
-
:railties_order, :relative_url_root, :secret_key_base,
-
:ssl_options, :public_file_server,
-
:session_options, :time_zone, :reload_classes_only_on_change,
-
:beginning_of_week, :filter_redirect, :x, :enable_dependency_loading,
-
:read_encrypted_secrets, :log_level, :content_security_policy_report_only,
-
:content_security_policy_nonce_generator, :content_security_policy_nonce_directives,
-
:require_master_key, :credentials, :disable_sandbox, :add_autoload_paths_to_load_path,
-
:rake_eager_load
-
-
17
attr_reader :encoding, :api_only, :loaded_config_version, :autoloader
-
-
17
def initialize(*)
-
17
super
-
17
self.encoding = Encoding::UTF_8
-
17
@allow_concurrency = nil
-
17
@consider_all_requests_local = false
-
17
@filter_parameters = []
-
17
@filter_redirect = []
-
17
@helpers_paths = []
-
17
@hosts = Array(([".localhost", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")] if Rails.env.development?))
-
17
@public_file_server = ActiveSupport::OrderedOptions.new
-
17
@public_file_server.enabled = true
-
17
@public_file_server.index_name = "index"
-
17
@force_ssl = false
-
17
@ssl_options = {}
-
17
@session_store = nil
-
17
@time_zone = "UTC"
-
17
@beginning_of_week = :monday
-
17
@log_level = :debug
-
17
@generators = app_generators
-
17
@cache_store = [ :file_store, "#{root}/tmp/cache/" ]
-
17
@railties_order = [:all]
-
17
@relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"]
-
17
@reload_classes_only_on_change = true
-
17
@file_watcher = ActiveSupport::FileUpdateChecker
-
17
@exceptions_app = nil
-
17
@autoflush_log = true
-
17
@log_formatter = ActiveSupport::Logger::SimpleFormatter.new
-
17
@eager_load = nil
-
17
@secret_key_base = nil
-
17
@api_only = false
-
17
@debug_exception_response_format = nil
-
17
@x = Custom.new
-
17
@enable_dependency_loading = false
-
17
@read_encrypted_secrets = false
-
17
@content_security_policy = nil
-
17
@content_security_policy_report_only = false
-
17
@content_security_policy_nonce_generator = nil
-
17
@content_security_policy_nonce_directives = nil
-
17
@require_master_key = false
-
17
@loaded_config_version = nil
-
17
@credentials = ActiveSupport::OrderedOptions.new
-
17
@credentials.content_path = default_credentials_content_path
-
17
@credentials.key_path = default_credentials_key_path
-
17
@autoloader = :classic
-
17
@disable_sandbox = false
-
17
@add_autoload_paths_to_load_path = true
-
17
@feature_policy = nil
-
17
@rake_eager_load = false
-
end
-
-
# Loads default configurations. See {the result of the method for each version}[https://guides.rubyonrails.org/configuring.html#results-of-config-load-defaults].
-
17
def load_defaults(target_version)
-
case target_version.to_s
-
when "5.0"
-
if respond_to?(:action_controller)
-
action_controller.per_form_csrf_tokens = true
-
action_controller.forgery_protection_origin_check = true
-
end
-
-
ActiveSupport.to_time_preserves_timezone = true
-
-
if respond_to?(:active_record)
-
active_record.belongs_to_required_by_default = true
-
end
-
-
self.ssl_options = { hsts: { subdomains: true } }
-
when "5.1"
-
load_defaults "5.0"
-
-
if respond_to?(:assets)
-
assets.unknown_asset_fallback = false
-
end
-
-
if respond_to?(:action_view)
-
action_view.form_with_generates_remote_forms = true
-
end
-
when "5.2"
-
load_defaults "5.1"
-
-
if respond_to?(:active_record)
-
active_record.cache_versioning = true
-
end
-
-
if respond_to?(:action_dispatch)
-
action_dispatch.use_authenticated_cookie_encryption = true
-
end
-
-
if respond_to?(:active_support)
-
active_support.use_authenticated_message_encryption = true
-
active_support.use_sha1_digests = true
-
end
-
-
if respond_to?(:action_controller)
-
action_controller.default_protect_from_forgery = true
-
end
-
-
if respond_to?(:action_view)
-
action_view.form_with_generates_ids = true
-
end
-
when "6.0"
-
load_defaults "5.2"
-
-
self.autoloader = :zeitwerk if RUBY_ENGINE == "ruby"
-
-
if respond_to?(:action_view)
-
action_view.default_enforce_utf8 = false
-
end
-
-
if respond_to?(:action_dispatch)
-
action_dispatch.use_cookies_with_metadata = true
-
action_dispatch.return_only_media_type_on_content_type = false
-
end
-
-
if respond_to?(:action_mailer)
-
action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
-
end
-
-
if respond_to?(:active_job)
-
active_job.return_false_on_aborted_enqueue = true
-
end
-
-
if respond_to?(:active_storage)
-
active_storage.queues.analysis = :active_storage_analysis
-
active_storage.queues.purge = :active_storage_purge
-
-
active_storage.replace_on_assign_to_many = true
-
end
-
-
if respond_to?(:active_record)
-
active_record.collection_cache_versioning = true
-
end
-
when "6.1"
-
load_defaults "6.0"
-
-
if respond_to?(:active_record)
-
active_record.has_many_inversing = true
-
end
-
-
if respond_to?(:active_storage)
-
active_storage.track_variants = true
-
end
-
-
if respond_to?(:active_job)
-
active_job.retry_jitter = 0.15
-
active_job.skip_after_callbacks_if_terminated = true
-
end
-
-
if respond_to?(:action_dispatch)
-
action_dispatch.cookies_same_site_protection = :lax
-
action_dispatch.ssl_default_redirect_status = 308
-
end
-
-
if respond_to?(:action_controller)
-
action_controller.urlsafe_csrf_tokens = true
-
end
-
-
ActiveSupport.utc_to_local_returns_utc_offset_times = true
-
else
-
raise "Unknown version #{target_version.to_s.inspect}"
-
end
-
-
@loaded_config_version = target_version
-
end
-
-
17
def encoding=(value)
-
17
@encoding = value
-
17
silence_warnings do
-
17
Encoding.default_external = value
-
17
Encoding.default_internal = value
-
end
-
end
-
-
17
def api_only=(value)
-
@api_only = value
-
generators.api_only = value
-
-
@debug_exception_response_format ||= :api
-
end
-
-
17
def debug_exception_response_format
-
@debug_exception_response_format || :default
-
end
-
-
17
attr_writer :debug_exception_response_format
-
-
17
def paths
-
33
@paths ||= begin
-
17
paths = super
-
17
paths.add "config/database", with: "config/database.yml"
-
17
paths.add "config/secrets", with: "config", glob: "secrets.yml{,.enc}"
-
17
paths.add "config/environment", with: "config/environment.rb"
-
17
paths.add "lib/templates"
-
17
paths.add "log", with: "log/#{Rails.env}.log"
-
17
paths.add "public"
-
17
paths.add "public/javascripts"
-
17
paths.add "public/stylesheets"
-
17
paths.add "tmp"
-
17
paths
-
end
-
end
-
-
# Load the database YAML without evaluating ERB. This allows us to
-
# create the rake tasks for multiple databases without filling in the
-
# configuration values or loading the environment. Do not use this
-
# method.
-
#
-
# This uses a DummyERB custom compiler so YAML can ignore the ERB
-
# tags and load the database.yml for the rake tasks.
-
17
def load_database_yaml # :nodoc:
-
if path = paths["config/database"].existent.first
-
require "rails/application/dummy_erb_compiler"
-
-
yaml = Pathname.new(path)
-
erb = DummyERB.new(yaml.read)
-
-
YAML.load(erb.result) || {}
-
else
-
{}
-
end
-
end
-
-
# Loads and returns the entire raw configuration of database from
-
# values stored in <tt>config/database.yml</tt>.
-
17
def database_configuration
-
path = paths["config/database"].existent.first
-
yaml = Pathname.new(path) if path
-
-
config = if yaml&.exist?
-
loaded_yaml = ActiveSupport::ConfigurationFile.parse(yaml)
-
if (shared = loaded_yaml.delete("shared"))
-
loaded_yaml.each do |_k, values|
-
values.reverse_merge!(shared)
-
end
-
end
-
Hash.new(shared).merge(loaded_yaml)
-
elsif ENV["DATABASE_URL"]
-
# Value from ENV['DATABASE_URL'] is set to default database connection
-
# by Active Record.
-
{}
-
else
-
raise "Could not load database configuration. No such file - #{paths["config/database"].instance_variable_get(:@paths)}"
-
end
-
-
config
-
rescue => e
-
raise e, "Cannot load database configuration:\n#{e.message}", e.backtrace
-
end
-
-
17
def colorize_logging
-
ActiveSupport::LogSubscriber.colorize_logging
-
end
-
-
17
def colorize_logging=(val)
-
ActiveSupport::LogSubscriber.colorize_logging = val
-
generators.colorize_logging = val
-
end
-
-
17
def session_store(new_session_store = nil, **options)
-
if new_session_store
-
if new_session_store == :active_record_store
-
begin
-
ActionDispatch::Session::ActiveRecordStore
-
rescue NameError
-
raise "`ActiveRecord::SessionStore` is extracted out of Rails into a gem. " \
-
"Please add `activerecord-session_store` to your Gemfile to use it."
-
end
-
end
-
-
@session_store = new_session_store
-
@session_options = options || {}
-
else
-
case @session_store
-
when :disabled
-
nil
-
when :active_record_store
-
ActionDispatch::Session::ActiveRecordStore
-
when Symbol
-
ActionDispatch::Session.const_get(@session_store.to_s.camelize)
-
else
-
@session_store
-
end
-
end
-
end
-
-
17
def session_store? #:nodoc:
-
@session_store
-
end
-
-
17
def annotations
-
Rails::SourceAnnotationExtractor::Annotation
-
end
-
-
17
def content_security_policy(&block)
-
if block_given?
-
@content_security_policy = ActionDispatch::ContentSecurityPolicy.new(&block)
-
else
-
@content_security_policy
-
end
-
end
-
-
17
def feature_policy(&block)
-
if block_given?
-
@feature_policy = ActionDispatch::FeaturePolicy.new(&block)
-
else
-
@feature_policy
-
end
-
end
-
-
17
def autoloader=(autoloader)
-
case autoloader
-
when :classic
-
@autoloader = autoloader
-
when :zeitwerk
-
require "zeitwerk"
-
@autoloader = autoloader
-
else
-
raise ArgumentError, "config.autoloader may be :classic or :zeitwerk, got #{autoloader.inspect} instead"
-
end
-
end
-
-
17
def default_log_file
-
path = paths["log"].first
-
unless File.exist? File.dirname path
-
FileUtils.mkdir_p File.dirname path
-
end
-
-
f = File.open path, "a"
-
f.binmode
-
f.sync = autoflush_log # if true make sure every write flushes
-
f
-
end
-
-
17
class Custom #:nodoc:
-
17
def initialize
-
17
@configurations = Hash.new
-
end
-
-
17
def method_missing(method, *args)
-
if method.end_with?("=")
-
@configurations[:"#{method[0..-2]}"] = args.first
-
else
-
@configurations.fetch(method) {
-
@configurations[method] = ActiveSupport::OrderedOptions.new
-
}
-
end
-
end
-
-
17
def respond_to_missing?(symbol, *)
-
true
-
end
-
end
-
-
17
private
-
17
def default_credentials_content_path
-
17
if credentials_available_for_current_env?
-
root.join("config", "credentials", "#{Rails.env}.yml.enc")
-
else
-
17
root.join("config", "credentials.yml.enc")
-
end
-
end
-
-
17
def default_credentials_key_path
-
17
if credentials_available_for_current_env?
-
root.join("config", "credentials", "#{Rails.env}.key")
-
else
-
17
root.join("config", "master.key")
-
end
-
end
-
-
17
def credentials_available_for_current_env?
-
34
File.exist?(root.join("config", "credentials", "#{Rails.env}.yml.enc"))
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
class Application
-
class DefaultMiddlewareStack
-
attr_reader :config, :paths, :app
-
-
def initialize(app, config, paths)
-
@app = app
-
@config = config
-
@paths = paths
-
end
-
-
def build_stack
-
ActionDispatch::MiddlewareStack.new do |middleware|
-
middleware.use ::ActionDispatch::HostAuthorization, config.hosts, config.action_dispatch.hosts_response_app
-
-
if config.force_ssl
-
middleware.use ::ActionDispatch::SSL, **config.ssl_options,
-
ssl_default_redirect_status: config.action_dispatch.ssl_default_redirect_status
-
end
-
-
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
-
-
if config.public_file_server.enabled
-
headers = config.public_file_server.headers || {}
-
-
middleware.use ::ActionDispatch::Static, paths["public"].first, index: config.public_file_server.index_name, headers: headers
-
end
-
-
if rack_cache = load_rack_cache
-
require "action_dispatch/http/rack_cache"
-
middleware.use ::Rack::Cache, rack_cache
-
end
-
-
if config.allow_concurrency == false
-
# User has explicitly opted out of concurrent request
-
# handling: presumably their code is not threadsafe
-
-
middleware.use ::Rack::Lock
-
end
-
-
middleware.use ::ActionDispatch::Executor, app.executor
-
-
middleware.use ::Rack::Runtime
-
middleware.use ::Rack::MethodOverride unless config.api_only
-
middleware.use ::ActionDispatch::RequestId
-
middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
-
-
middleware.use ::Rails::Rack::Logger, config.log_tags
-
middleware.use ::ActionDispatch::ShowExceptions, show_exceptions_app
-
middleware.use ::ActionDispatch::DebugExceptions, app, config.debug_exception_response_format
-
middleware.use ::ActionDispatch::ActionableExceptions
-
-
unless config.cache_classes
-
middleware.use ::ActionDispatch::Reloader, app.reloader
-
end
-
-
middleware.use ::ActionDispatch::Callbacks
-
middleware.use ::ActionDispatch::Cookies unless config.api_only
-
-
if !config.api_only && config.session_store
-
if config.force_ssl && config.ssl_options.fetch(:secure_cookies, true) && !config.session_options.key?(:secure)
-
config.session_options[:secure] = true
-
end
-
middleware.use config.session_store, config.session_options
-
middleware.use ::ActionDispatch::Flash
-
end
-
-
unless config.api_only
-
middleware.use ::ActionDispatch::ContentSecurityPolicy::Middleware
-
middleware.use ::ActionDispatch::FeaturePolicy::Middleware
-
end
-
-
middleware.use ::Rack::Head
-
middleware.use ::Rack::ConditionalGet
-
middleware.use ::Rack::ETag, "no-cache"
-
-
middleware.use ::Rack::TempfileReaper unless config.api_only
-
end
-
end
-
-
private
-
def load_rack_cache
-
rack_cache = config.action_dispatch.rack_cache
-
return unless rack_cache
-
-
begin
-
require "rack/cache"
-
rescue LoadError => error
-
error.message << " Be sure to add rack-cache to your Gemfile"
-
raise
-
end
-
-
if rack_cache == true
-
{
-
metastore: "rails:/",
-
entitystore: "rails:/",
-
verbose: false
-
}
-
else
-
rack_cache
-
end
-
end
-
-
def show_exceptions_app
-
config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
# These classes are used to strip out the ERB configuration
-
# values so we can evaluate the database.yml without evaluating
-
# the ERB values.
-
class DummyERB < ERB # :nodoc:
-
def make_compiler(trim_mode)
-
DummyCompiler.new trim_mode
-
end
-
end
-
-
class DummyCompiler < ERB::Compiler # :nodoc:
-
def compile_content(stag, out)
-
if stag == "<%="
-
out.push "_erbout << ''"
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/core_ext/string/inflections"
-
require "active_support/core_ext/array/conversions"
-
-
module Rails
-
class Application
-
module Finisher
-
include Initializable
-
-
initializer :add_generator_templates do
-
config.generators.templates.unshift(*paths["lib/templates"].existent)
-
end
-
-
initializer :ensure_autoload_once_paths_as_subset do
-
extra = ActiveSupport::Dependencies.autoload_once_paths -
-
ActiveSupport::Dependencies.autoload_paths
-
-
unless extra.empty?
-
abort <<-end_error
-
autoload_once_paths must be a subset of the autoload_paths.
-
Extra items in autoload_once_paths: #{extra * ','}
-
end_error
-
end
-
end
-
-
# This will become an error if/when we remove classic mode. The plan is
-
# autoloaders won't be configured up to this point in the finisher, so
-
# constants just won't be found, raising regular NameError exceptions.
-
initializer :warn_if_autoloaded, before: :let_zeitwerk_take_over do
-
next if config.cache_classes
-
next if ActiveSupport::Dependencies.autoloaded_constants.empty?
-
-
autoloaded = ActiveSupport::Dependencies.autoloaded_constants
-
constants = "constant".pluralize(autoloaded.size)
-
enum = autoloaded.to_sentence
-
have = autoloaded.size == 1 ? "has" : "have"
-
these = autoloaded.size == 1 ? "This" : "These"
-
example = autoloaded.first
-
example_klass = example.constantize.class
-
-
if config.autoloader == :zeitwerk
-
ActiveSupport::DescendantsTracker.clear
-
ActiveSupport::Dependencies.clear
-
-
unload_message = "#{these} autoloaded #{constants} #{have} been unloaded."
-
else
-
unload_message = "`config.autoloader` is set to `#{config.autoloader}`. #{these} autoloaded #{constants} would have been unloaded if `config.autoloader` had been set to `:zeitwerk`."
-
end
-
-
ActiveSupport::Deprecation.warn(<<~WARNING)
-
Initialization autoloaded the #{constants} #{enum}.
-
-
Being able to do this is deprecated. Autoloading during initialization is going
-
to be an error condition in future versions of Rails.
-
-
Reloading does not reboot the application, and therefore code executed during
-
initialization does not run again. So, if you reload #{example}, for example,
-
the expected changes won't be reflected in that stale #{example_klass} object.
-
-
#{unload_message}
-
-
In order to autoload safely at boot time, please wrap your code in a reloader
-
callback this way:
-
-
Rails.application.reloader.to_prepare do
-
# Autoload classes and modules needed at boot time here.
-
end
-
-
That block runs when the application boots, and every time there is a reload.
-
For historical reasons, it may run twice, so it has to be idempotent.
-
-
Check the "Autoloading and Reloading Constants" guide to learn more about how
-
Rails autoloads and reloads.
-
WARNING
-
end
-
-
initializer :let_zeitwerk_take_over do
-
if config.autoloader == :zeitwerk
-
require "active_support/dependencies/zeitwerk_integration"
-
ActiveSupport::Dependencies::ZeitwerkIntegration.take_over(enable_reloading: !config.cache_classes)
-
end
-
end
-
-
initializer :add_builtin_route do |app|
-
if Rails.env.development?
-
app.routes.prepend do
-
get "/rails/info/properties" => "rails/info#properties", internal: true
-
get "/rails/info/routes" => "rails/info#routes", internal: true
-
get "/rails/info" => "rails/info#index", internal: true
-
end
-
-
app.routes.append do
-
get "/" => "rails/welcome#index", internal: true
-
end
-
end
-
end
-
-
# Setup default session store if not already set in config/application.rb
-
initializer :setup_default_session_store, before: :build_middleware_stack do |app|
-
unless app.config.session_store?
-
app_name = app.class.name ? app.railtie_name.chomp("_application") : ""
-
app.config.session_store :cookie_store, key: "_#{app_name}_session"
-
end
-
end
-
-
initializer :build_middleware_stack do
-
build_middleware_stack
-
end
-
-
initializer :define_main_app_helper do |app|
-
app.routes.define_mounted_helper(:main_app)
-
end
-
-
initializer :add_to_prepare_blocks do |app|
-
config.to_prepare_blocks.each do |block|
-
app.reloader.to_prepare(&block)
-
end
-
end
-
-
# This needs to happen before eager load so it happens
-
# in exactly the same point regardless of config.eager_load
-
initializer :run_prepare_callbacks do |app|
-
app.reloader.prepare!
-
end
-
-
initializer :eager_load! do
-
if config.eager_load
-
ActiveSupport.run_load_hooks(:before_eager_load, self)
-
# Checks defined?(Zeitwerk) instead of zeitwerk_enabled? because we
-
# want to eager load any dependency managed by Zeitwerk regardless of
-
# the autoloading mode of the application.
-
Zeitwerk::Loader.eager_load_all if defined?(Zeitwerk)
-
config.eager_load_namespaces.each(&:eager_load!)
-
end
-
end
-
-
# All initialization is done, including eager loading in production
-
initializer :finisher_hook do
-
ActiveSupport.run_load_hooks(:after_initialize, self)
-
end
-
-
class MutexHook
-
def initialize(mutex = Mutex.new)
-
@mutex = mutex
-
end
-
-
def run
-
@mutex.lock
-
end
-
-
def complete(_state)
-
@mutex.unlock
-
end
-
end
-
-
module InterlockHook
-
def self.run
-
ActiveSupport::Dependencies.interlock.start_running
-
end
-
-
def self.complete(_state)
-
ActiveSupport::Dependencies.interlock.done_running
-
end
-
end
-
-
initializer :configure_executor_for_concurrency do |app|
-
if config.allow_concurrency == false
-
# User has explicitly opted out of concurrent request
-
# handling: presumably their code is not threadsafe
-
-
app.executor.register_hook(MutexHook.new, outer: true)
-
-
elsif config.allow_concurrency == :unsafe
-
# Do nothing, even if we know this is dangerous. This is the
-
# historical behavior for true.
-
-
else
-
# Default concurrency setting: enabled, but safe
-
-
unless config.cache_classes && config.eager_load
-
# Without cache_classes + eager_load, the load interlock
-
# is required for proper operation
-
-
app.executor.register_hook(InterlockHook, outer: true)
-
end
-
end
-
end
-
-
# Set routes reload after the finisher hook to ensure routes added in
-
# the hook are taken into account.
-
initializer :set_routes_reloader_hook do |app|
-
reloader = routes_reloader
-
reloader.eager_load = app.config.eager_load
-
reloader.execute
-
reloaders << reloader
-
app.reloader.to_run do
-
# We configure #execute rather than #execute_if_updated because if
-
# autoloaded constants are cleared we need to reload routes also in
-
# case any was used there, as in
-
#
-
# mount MailPreview => 'mail_view'
-
#
-
# This means routes are also reloaded if i18n is updated, which
-
# might not be necessary, but in order to be more precise we need
-
# some sort of reloaders dependency support, to be added.
-
require_unload_lock!
-
reloader.execute
-
end
-
end
-
-
# Set clearing dependencies after the finisher hook to ensure paths
-
# added in the hook are taken into account.
-
initializer :set_clear_dependencies_hook, group: :all do |app|
-
callback = lambda do
-
ActiveSupport::DescendantsTracker.clear
-
ActiveSupport::Dependencies.clear
-
end
-
-
if config.cache_classes
-
app.reloader.check = lambda { false }
-
elsif config.reload_classes_only_on_change
-
app.reloader.check = lambda do
-
app.reloaders.map(&:updated?).any?
-
end
-
else
-
app.reloader.check = lambda { true }
-
end
-
-
if config.cache_classes
-
# No reloader
-
elsif config.reload_classes_only_on_change
-
reloader = config.file_watcher.new(*watchable_args, &callback)
-
reloaders << reloader
-
-
# Prepend this callback to have autoloaded constants cleared before
-
# any other possible reloading, in case they need to autoload fresh
-
# constants.
-
app.reloader.to_run(prepend: true) do
-
# In addition to changes detected by the file watcher, if routes
-
# or i18n have been updated we also need to clear constants,
-
# that's why we run #execute rather than #execute_if_updated, this
-
# callback has to clear autoloaded constants after any update.
-
class_unload! do
-
reloader.execute
-
end
-
end
-
else
-
app.reloader.to_complete do
-
class_unload!(&callback)
-
end
-
end
-
end
-
-
# Disable dependency loading during request cycle
-
initializer :disable_dependency_loading do
-
if config.eager_load && config.cache_classes && !config.enable_dependency_loading
-
ActiveSupport::Dependencies.unhook!
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/core_ext/module/delegation"
-
-
module Rails
-
class Application
-
class RoutesReloader
-
attr_reader :route_sets, :paths, :external_routes
-
attr_accessor :eager_load
-
delegate :execute_if_updated, :execute, :updated?, to: :updater
-
-
def initialize
-
@paths = []
-
@route_sets = []
-
@external_routes = []
-
@eager_load = false
-
end
-
-
def reload!
-
clear!
-
load_paths
-
finalize!
-
route_sets.each(&:eager_load!) if eager_load
-
ensure
-
revert
-
end
-
-
private
-
def updater
-
@updater ||= begin
-
dirs = @external_routes.each_with_object({}) do |dir, hash|
-
hash[dir.to_s] = %w(rb)
-
end
-
-
ActiveSupport::FileUpdateChecker.new(paths, dirs) { reload! }
-
end
-
end
-
-
def clear!
-
route_sets.each do |routes|
-
routes.disable_clear_and_finalize = true
-
routes.clear!
-
end
-
end
-
-
def load_paths
-
paths.each { |path| load(path) }
-
end
-
-
def finalize!
-
route_sets.each(&:finalize!)
-
end
-
-
def revert
-
route_sets.each do |routes|
-
routes.disable_clear_and_finalize = false
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
class Rails::ApplicationController < ActionController::Base # :nodoc:
-
self.view_paths = File.expand_path("templates", __dir__)
-
layout "application"
-
-
before_action :disable_content_security_policy_nonce!
-
-
content_security_policy do |policy|
-
policy.script_src :unsafe_inline
-
policy.style_src :unsafe_inline
-
end
-
-
private
-
def require_local!
-
unless local_request?
-
render html: "<p>For security purposes, this information is only available to local requests.</p>".html_safe, status: :forbidden
-
end
-
end
-
-
def local_request?
-
Rails.application.config.consider_all_requests_local || request.local?
-
end
-
-
def disable_content_security_policy_nonce!
-
request.content_security_policy_nonce_generator = nil
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/dependencies/zeitwerk_integration"
-
-
module Rails
-
module Autoloaders # :nodoc:
-
class << self
-
include Enumerable
-
-
def main
-
if zeitwerk_enabled?
-
@main ||= Zeitwerk::Loader.new.tap do |loader|
-
loader.tag = "rails.main"
-
loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
-
end
-
end
-
end
-
-
def once
-
if zeitwerk_enabled?
-
@once ||= Zeitwerk::Loader.new.tap do |loader|
-
loader.tag = "rails.once"
-
loader.inflector = ActiveSupport::Dependencies::ZeitwerkIntegration::Inflector
-
end
-
end
-
end
-
-
def each
-
if zeitwerk_enabled?
-
yield main
-
yield once
-
end
-
end
-
-
def logger=(logger)
-
each { |loader| loader.logger = logger }
-
end
-
-
def log!
-
each(&:log!)
-
end
-
-
def zeitwerk_enabled?
-
Rails.configuration.autoloader == :zeitwerk
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/backtrace_cleaner"
-
require "active_support/core_ext/string/access"
-
-
module Rails
-
class BacktraceCleaner < ActiveSupport::BacktraceCleaner
-
APP_DIRS_PATTERN = /\A(?:\.\/)?(?:app|config|lib|test|\(\w*\))/
-
RENDER_TEMPLATE_PATTERN = /:in `.*_\w+_{2,3}\d+_\d+'/
-
-
def initialize
-
super
-
@root = "#{Rails.root}/"
-
add_filter do |line|
-
line.start_with?(@root) ? line.from(@root.size) : line
-
end
-
add_filter do |line|
-
if RENDER_TEMPLATE_PATTERN.match?(line)
-
line.sub(RENDER_TEMPLATE_PATTERN, "")
-
else
-
line
-
end
-
end
-
add_silencer { |line| !APP_DIRS_PATTERN.match?(line) }
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/app_loader"
-
-
# If we are inside a Rails application this method performs an exec and thus
-
# the rest of this script is not run.
-
Rails::AppLoader.exec_app
-
-
require "rails/ruby_version_check"
-
Signal.trap("INT") { puts; exit(1) }
-
-
require "rails/command"
-
-
if ARGV.first == "plugin"
-
ARGV.shift
-
Rails::Command.invoke :plugin, ARGV
-
else
-
Rails::Command.invoke :application, ARGV
-
end
-
# frozen_string_literal: true
-
-
require "rails/code_statistics_calculator"
-
require "active_support/core_ext/enumerable"
-
-
class CodeStatistics #:nodoc:
-
TEST_TYPES = ["Controller tests",
-
"Helper tests",
-
"Model tests",
-
"Mailer tests",
-
"Mailbox tests",
-
"Channel tests",
-
"Job tests",
-
"Integration tests",
-
"System tests"]
-
-
HEADERS = { lines: " Lines", code_lines: " LOC", classes: "Classes", methods: "Methods" }
-
-
def initialize(*pairs)
-
@pairs = pairs
-
@statistics = calculate_statistics
-
@total = calculate_total if pairs.length > 1
-
end
-
-
def to_s
-
print_header
-
@pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
-
print_splitter
-
-
if @total
-
print_line("Total", @total)
-
print_splitter
-
end
-
-
print_code_test_stats
-
end
-
-
private
-
def calculate_statistics
-
Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }]
-
end
-
-
def calculate_directory_statistics(directory, pattern = /^(?!\.).*?\.(rb|js|ts|coffee|rake)$/)
-
stats = CodeStatisticsCalculator.new
-
-
Dir.foreach(directory) do |file_name|
-
path = "#{directory}/#{file_name}"
-
-
if File.directory?(path) && !file_name.start_with?(".")
-
stats.add(calculate_directory_statistics(path, pattern))
-
elsif file_name&.match?(pattern)
-
stats.add_by_file_path(path)
-
end
-
end
-
-
stats
-
end
-
-
def calculate_total
-
@statistics.each_with_object(CodeStatisticsCalculator.new) do |pair, total|
-
total.add(pair.last)
-
end
-
end
-
-
def calculate_code
-
code_loc = 0
-
@statistics.each { |k, v| code_loc += v.code_lines unless TEST_TYPES.include? k }
-
code_loc
-
end
-
-
def calculate_tests
-
test_loc = 0
-
@statistics.each { |k, v| test_loc += v.code_lines if TEST_TYPES.include? k }
-
test_loc
-
end
-
-
def width_for(label)
-
[@statistics.values.sum { |s| s.send(label) }.to_s.size, HEADERS[label].length].max
-
end
-
-
def print_header
-
print_splitter
-
print "| Name "
-
HEADERS.each do |k, v|
-
print " | #{v.rjust(width_for(k))}"
-
end
-
puts " | M/C | LOC/M |"
-
print_splitter
-
end
-
-
def print_splitter
-
print "+----------------------"
-
HEADERS.each_key do |k|
-
print "+#{'-' * (width_for(k) + 2)}"
-
end
-
puts "+-----+-------+"
-
end
-
-
def print_line(name, statistics)
-
m_over_c = (statistics.methods / statistics.classes) rescue 0
-
loc_over_m = (statistics.code_lines / statistics.methods) - 2 rescue 0
-
-
print "| #{name.ljust(20)} "
-
HEADERS.each_key do |k|
-
print "| #{statistics.send(k).to_s.rjust(width_for(k))} "
-
end
-
puts "| #{m_over_c.to_s.rjust(3)} | #{loc_over_m.to_s.rjust(5)} |"
-
end
-
-
def print_code_test_stats
-
code = calculate_code
-
tests = calculate_tests
-
-
puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f / code)}"
-
puts ""
-
end
-
end
-
# frozen_string_literal: true
-
-
class CodeStatisticsCalculator #:nodoc:
-
attr_reader :lines, :code_lines, :classes, :methods
-
-
PATTERNS = {
-
rb: {
-
line_comment: /^\s*#/,
-
begin_block_comment: /^=begin/,
-
end_block_comment: /^=end/,
-
class: /^\s*class\s+[_A-Z]/,
-
method: /^\s*def\s+[_a-z]/,
-
},
-
js: {
-
line_comment: %r{^\s*//},
-
begin_block_comment: %r{^\s*/\*},
-
end_block_comment: %r{\*/},
-
method: /function(\s+[_a-zA-Z][\da-zA-Z]*)?\s*\(/,
-
},
-
coffee: {
-
line_comment: /^\s*#/,
-
begin_block_comment: /^\s*###/,
-
end_block_comment: /^\s*###/,
-
class: /^\s*class\s+[_A-Z]/,
-
method: /[-=]>/,
-
}
-
}
-
-
PATTERNS[:minitest] = PATTERNS[:rb].merge method: /^\s*(def|test)\s+['"_a-z]/
-
PATTERNS[:rake] = PATTERNS[:rb]
-
-
def initialize(lines = 0, code_lines = 0, classes = 0, methods = 0)
-
@lines = lines
-
@code_lines = code_lines
-
@classes = classes
-
@methods = methods
-
end
-
-
def add(code_statistics_calculator)
-
@lines += code_statistics_calculator.lines
-
@code_lines += code_statistics_calculator.code_lines
-
@classes += code_statistics_calculator.classes
-
@methods += code_statistics_calculator.methods
-
end
-
-
def add_by_file_path(file_path)
-
File.open(file_path) do |f|
-
add_by_io(f, file_type(file_path))
-
end
-
end
-
-
def add_by_io(io, file_type)
-
patterns = PATTERNS[file_type] || {}
-
-
comment_started = false
-
-
while line = io.gets
-
@lines += 1
-
-
if comment_started
-
if patterns[:end_block_comment] && patterns[:end_block_comment].match?(line)
-
comment_started = false
-
end
-
next
-
else
-
if patterns[:begin_block_comment] && patterns[:begin_block_comment].match?(line)
-
comment_started = true
-
next
-
end
-
end
-
-
@classes += 1 if patterns[:class] && patterns[:class].match?(line)
-
@methods += 1 if patterns[:method] && patterns[:method].match?(line)
-
if !line.match?(/^\s*$/) && (patterns[:line_comment].nil? || !line.match?(patterns[:line_comment]))
-
@code_lines += 1
-
end
-
end
-
end
-
-
private
-
def file_type(file_path)
-
if file_path.end_with? "_test.rb"
-
:minitest
-
else
-
File.extname(file_path).delete_prefix(".").downcase.to_sym
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
require "active_support"
-
16
require "active_support/core_ext/enumerable"
-
16
require "active_support/core_ext/object/blank"
-
-
16
require "thor"
-
-
16
module Rails
-
16
module Command
-
16
extend ActiveSupport::Autoload
-
-
16
autoload :Spellchecker
-
16
autoload :Behavior
-
16
autoload :Base
-
-
16
include Behavior
-
-
16
HELP_MAPPINGS = %w(-h -? --help)
-
-
16
class << self
-
16
def hidden_commands # :nodoc:
-
@hidden_commands ||= []
-
end
-
-
16
def environment # :nodoc:
-
ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development"
-
end
-
-
# Receives a namespace, arguments and the behavior to invoke the command.
-
16
def invoke(full_namespace, args = [], **config)
-
namespace = full_namespace = full_namespace.to_s
-
-
if char = namespace =~ /:(\w+)$/
-
command_name, namespace = $1, namespace.slice(0, char)
-
else
-
command_name = namespace
-
end
-
-
command_name, namespace = "help", "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
-
command_name, namespace = "version", "version" if %w( -v --version ).include?(command_name)
-
-
# isolate ARGV to ensure that commands depend only on the args they are given
-
args = args.dup # args might *be* ARGV so dup before clearing
-
old_argv = ARGV.dup
-
ARGV.clear
-
-
command = find_by_namespace(namespace, command_name)
-
if command && command.all_commands[command_name]
-
command.perform(command_name, args, config)
-
else
-
find_by_namespace("rake").perform(full_namespace, args, config)
-
end
-
ensure
-
ARGV.replace(old_argv)
-
end
-
-
# Rails finds namespaces similar to Thor, it only adds one rule:
-
#
-
# Command names must end with "_command.rb". This is required because Rails
-
# looks in load paths and loads the command just before it's going to be used.
-
#
-
# find_by_namespace :webrat, :rails, :integration
-
#
-
# Will search for the following commands:
-
#
-
# "rails:webrat", "webrat:integration", "webrat"
-
#
-
# Notice that "rails:commands:webrat" could be loaded as well, what
-
# Rails looks for is the first and last parts of the namespace.
-
16
def find_by_namespace(namespace, command_name = nil) # :nodoc:
-
lookups = [ namespace ]
-
lookups << "#{namespace}:#{command_name}" if command_name
-
lookups.concat lookups.map { |lookup| "rails:#{lookup}" }
-
-
lookup(lookups)
-
-
namespaces = subclasses.index_by(&:namespace)
-
namespaces[(lookups & namespaces.keys).first]
-
end
-
-
# Returns the root of the Rails engine or app running the command.
-
16
def root
-
if defined?(ENGINE_ROOT)
-
Pathname.new(ENGINE_ROOT)
-
elsif defined?(APP_PATH)
-
Pathname.new(File.expand_path("../..", APP_PATH))
-
end
-
end
-
-
16
def print_commands # :nodoc:
-
commands.each { |command| puts(" #{command}") }
-
end
-
-
16
private
-
16
COMMANDS_IN_USAGE = %w(generate console server test test:system dbconsole new)
-
16
private_constant :COMMANDS_IN_USAGE
-
-
16
def commands
-
lookup!
-
-
visible_commands = (subclasses - hidden_commands).flat_map(&:printing_commands)
-
-
(visible_commands - COMMANDS_IN_USAGE).sort
-
end
-
-
16
def command_type # :doc:
-
@command_type ||= "command"
-
end
-
-
16
def lookup_paths # :doc:
-
@lookup_paths ||= %w( rails/commands commands )
-
end
-
-
16
def file_lookup_paths # :doc:
-
@file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ]
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
module Actions
-
# Change to the application's path if there is no <tt>config.ru</tt> file in current directory.
-
# This allows us to run <tt>rails server</tt> from other directories, but still get
-
# the main <tt>config.ru</tt> and properly set the <tt>tmp</tt> directory.
-
def set_application_directory!
-
Dir.chdir(File.expand_path("../..", APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
-
end
-
-
def require_application_and_environment!
-
require_application!
-
require_environment!
-
end
-
-
def require_application!
-
require ENGINE_PATH if defined?(ENGINE_PATH)
-
-
if defined?(APP_PATH)
-
require APP_PATH
-
end
-
end
-
-
def require_environment!
-
if defined?(APP_PATH)
-
Rails.application.require_environment!
-
end
-
end
-
-
if defined?(ENGINE_PATH)
-
def load_tasks
-
Rake.application.init("rails")
-
Rake.application.load_rakefile
-
end
-
-
def load_generators
-
engine = ::Rails::Engine.find(ENGINE_ROOT)
-
Rails::Generators.namespace = engine.railtie_namespace
-
engine.load_generators
-
end
-
else
-
def load_tasks
-
Rails.application.load_tasks
-
end
-
-
def load_generators
-
Rails.application.load_generators
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "thor"
-
require "erb"
-
-
require "active_support/core_ext/string/filters"
-
require "active_support/core_ext/string/inflections"
-
-
require "rails/command/actions"
-
-
module Rails
-
module Command
-
class Base < Thor
-
class Error < Thor::Error # :nodoc:
-
end
-
-
include Actions
-
-
class << self
-
def exit_on_failure? # :nodoc:
-
false
-
end
-
-
# Returns true when the app is a Rails engine.
-
def engine?
-
defined?(ENGINE_ROOT)
-
end
-
-
# Tries to get the description from a USAGE file one folder above the command
-
# root.
-
def desc(usage = nil, description = nil, options = {})
-
if usage
-
super
-
else
-
@desc ||= ERB.new(File.read(usage_path)).result(binding) if usage_path
-
end
-
end
-
-
# Convenience method to get the namespace from the class name. It's the
-
# same as Thor default except that the Command at the end of the class
-
# is removed.
-
def namespace(name = nil)
-
if name
-
super
-
else
-
@namespace ||= super.chomp("_command").sub(/:command:/, ":")
-
end
-
end
-
-
# Convenience method to hide this command from the available ones when
-
# running rails command.
-
def hide_command!
-
Rails::Command.hidden_commands << self
-
end
-
-
def inherited(base) #:nodoc:
-
super
-
-
if base.name && !base.name.end_with?("Base")
-
Rails::Command.subclasses << base
-
end
-
end
-
-
def perform(command, args, config) # :nodoc:
-
if Rails::Command::HELP_MAPPINGS.include?(args.first)
-
command, args = "help", []
-
end
-
-
dispatch(command, args.dup, nil, config)
-
end
-
-
def printing_commands
-
namespaced_commands
-
end
-
-
def executable
-
"rails #{command_name}"
-
end
-
-
# Use Rails' default banner.
-
def banner(*)
-
"#{executable} #{arguments.map(&:usage).join(' ')} [options]".squish
-
end
-
-
# Sets the base_name taking into account the current class namespace.
-
#
-
# Rails::Command::TestCommand.base_name # => 'rails'
-
def base_name
-
@base_name ||= begin
-
if base = name.to_s.split("::").first
-
base.underscore
-
end
-
end
-
end
-
-
# Return command name without namespaces.
-
#
-
# Rails::Command::TestCommand.command_name # => 'test'
-
def command_name
-
@command_name ||= begin
-
if command = name.to_s.split("::").last
-
command.chomp!("Command")
-
command.underscore
-
end
-
end
-
end
-
-
# Path to lookup a USAGE description in a file.
-
def usage_path
-
if default_command_root
-
path = File.join(default_command_root, "USAGE")
-
path if File.exist?(path)
-
end
-
end
-
-
# Default file root to place extra files a command might need, placed
-
# one folder above the command file.
-
#
-
# For a Rails::Command::TestCommand placed in <tt>rails/command/test_command.rb</tt>
-
# would return <tt>rails/test</tt>.
-
def default_command_root
-
path = File.expand_path(relative_command_path, __dir__)
-
path if File.exist?(path)
-
end
-
-
private
-
# Allow the command method to be called perform.
-
def create_command(meth)
-
if meth == "perform"
-
alias_method command_name, meth
-
else
-
# Prevent exception about command without usage.
-
# Some commands define their documentation differently.
-
@usage ||= ""
-
@desc ||= ""
-
-
super
-
end
-
end
-
-
def command_root_namespace
-
(namespace.split(":") - %w(rails)).join(":")
-
end
-
-
def relative_command_path
-
File.join("../commands", *command_root_namespace.split(":"))
-
end
-
-
def namespaced_commands
-
commands.keys.map do |key|
-
if command_root_namespace.match?(/(\A|\:)#{key}\z/)
-
command_root_namespace
-
else
-
"#{command_root_namespace}:#{key}"
-
end
-
end
-
end
-
end
-
-
def help
-
if command_name = self.class.command_name
-
self.class.command_help(shell, command_name)
-
else
-
super
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
require "active_support"
-
-
16
module Rails
-
16
module Command
-
16
module Behavior #:nodoc:
-
16
extend ActiveSupport::Concern
-
-
16
class_methods do
-
# Remove the color from output.
-
16
def no_color!
-
16
Thor::Base.shell = Thor::Shell::Basic
-
end
-
-
# Track all command subclasses.
-
16
def subclasses
-
23
@subclasses ||= []
-
end
-
-
16
private
-
# Prints a list of generators.
-
16
def print_list(base, namespaces)
-
return if namespaces.empty?
-
puts "#{base.camelize}:"
-
-
namespaces.each do |namespace|
-
puts(" #{namespace}")
-
end
-
-
puts
-
end
-
-
# Receives namespaces in an array and tries to find matching generators
-
# in the load path.
-
16
def lookup(namespaces)
-
paths = namespaces_to_paths(namespaces)
-
-
paths.each do |raw_path|
-
lookup_paths.each do |base|
-
path = "#{base}/#{raw_path}_#{command_type}"
-
-
begin
-
require path
-
return
-
rescue LoadError => e
-
raise unless /#{Regexp.escape(path)}$/.match?(e.message)
-
rescue Exception => e
-
warn "[WARNING] Could not load #{command_type} #{path.inspect}. Error: #{e.message}.\n#{e.backtrace.join("\n")}"
-
end
-
end
-
end
-
end
-
-
# This will try to load any command in the load path to show in help.
-
16
def lookup!
-
$LOAD_PATH.each do |base|
-
Dir[File.join(base, *file_lookup_paths)].each do |path|
-
path = path.delete_prefix("#{base}/")
-
require path
-
rescue Exception
-
# No problem
-
end
-
end
-
end
-
-
# Convert namespaces to paths by replacing ":" for "/" and adding
-
# an extra lookup. For example, "rails:model" should be searched
-
# in both: "rails/model/model_generator" and "rails/model_generator".
-
16
def namespaces_to_paths(namespaces)
-
paths = []
-
namespaces.each do |namespace|
-
pieces = namespace.split(":")
-
path = pieces.join("/")
-
paths << "#{path}/#{pieces.last}"
-
paths << path
-
end
-
paths.uniq!
-
paths
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support"
-
require "active_support/core_ext/class/attribute"
-
-
module Rails
-
module Command
-
module EnvironmentArgument #:nodoc:
-
extend ActiveSupport::Concern
-
-
included do
-
no_commands do
-
class_attribute :environment_desc, default: "Specifies the environment to run this #{self.command_name} under (test/development/production)."
-
end
-
class_option :environment, aliases: "-e", type: :string, desc: environment_desc
-
end
-
-
private
-
def extract_environment_option_from_argument(default_environment: Rails::Command.environment)
-
if options[:environment]
-
self.options = options.merge(environment: acceptable_environment(options[:environment]))
-
else
-
self.options = options.merge(environment: default_environment)
-
end
-
end
-
-
def acceptable_environment(env = nil)
-
if available_environments.include? env
-
env
-
else
-
%w( production development test ).detect { |e| /^#{env}/.match?(e) } || env
-
end
-
end
-
-
def available_environments
-
Dir["config/environments/*.rb"].map { |fname| File.basename(fname, ".*") }
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/encrypted_file"
-
-
module Rails
-
module Command
-
module Helpers
-
module Editor
-
private
-
def ensure_editor_available(command:)
-
if ENV["EDITOR"].to_s.empty?
-
say "No $EDITOR to open file in. Assign one like this:"
-
say ""
-
say %(EDITOR="mate --wait" #{command})
-
say ""
-
say "For editors that fork and exit immediately, it's important to pass a wait flag,"
-
say "otherwise the credentials will be saved immediately with no chance to edit."
-
-
false
-
else
-
true
-
end
-
end
-
-
def catch_editing_exceptions
-
yield
-
rescue Interrupt
-
say "Aborted changing file: nothing saved."
-
rescue ActiveSupport::EncryptedFile::MissingKeyError => error
-
say error.message
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
module Spellchecker # :nodoc:
-
class << self
-
def suggest(word, from:)
-
if defined?(DidYouMean::SpellChecker)
-
DidYouMean::SpellChecker.new(dictionary: from.map(&:to_s)).correct(word).first
-
else
-
from.sort_by { |w| levenshtein_distance(word, w) }.first
-
end
-
end
-
-
private
-
# This code is based directly on the Text gem implementation.
-
# Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
-
#
-
# Returns a value representing the "cost" of transforming str1 into str2.
-
def levenshtein_distance(str1, str2) # :doc:
-
s = str1
-
t = str2
-
n = s.length
-
m = t.length
-
-
return m if 0 == n
-
return n if 0 == m
-
-
d = (0..m).to_a
-
x = nil
-
-
# avoid duplicating an enumerable object in the loop
-
str2_codepoint_enumerable = str2.each_codepoint
-
-
str1.each_codepoint.with_index do |char1, i|
-
e = i + 1
-
-
str2_codepoint_enumerable.with_index do |char2, j|
-
cost = (char1 == char2) ? 0 : 1
-
x = [
-
d[j + 1] + 1, # insertion
-
e + 1, # deletion
-
d[j] + cost # substitution
-
].min
-
d[j] = e
-
e = x
-
end
-
-
d[m] = x
-
end
-
-
x
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/command"
-
-
aliases = {
-
"g" => "generate",
-
"d" => "destroy",
-
"c" => "console",
-
"s" => "server",
-
"db" => "dbconsole",
-
"r" => "runner",
-
"t" => "test"
-
}
-
-
command = ARGV.shift
-
command = aliases[command] || command
-
-
Rails::Command.invoke command, ARGV
-
# frozen_string_literal: true
-
-
require "rails/generators"
-
require "rails/generators/rails/app/app_generator"
-
-
module Rails
-
module Generators
-
class AppGenerator # :nodoc:
-
# We want to exit on failure to be kind to other libraries
-
# This is only when accessing via CLI
-
def self.exit_on_failure?
-
true
-
end
-
end
-
end
-
-
module Command
-
class ApplicationCommand < Base # :nodoc:
-
hide_command!
-
-
def help
-
perform # Punt help output to the generator.
-
end
-
-
def perform(*args)
-
Rails::Generators::AppGenerator.start \
-
Rails::Generators::ARGVScrubber.new(args).prepare!
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "irb"
-
require "irb/completion"
-
-
require "rails/command/environment_argument"
-
-
module Rails
-
class Console
-
module BacktraceCleaner
-
def filter_backtrace(bt)
-
if result = super
-
Rails.backtrace_cleaner.filter([result]).first
-
end
-
end
-
end
-
-
def self.start(*args)
-
new(*args).start
-
end
-
-
attr_reader :options, :app, :console
-
-
def initialize(app, options = {})
-
@app = app
-
@options = options
-
-
app.sandbox = sandbox?
-
-
if sandbox? && app.config.disable_sandbox
-
puts "Error: Unable to start console in sandbox mode as sandbox mode is disabled (config.disable_sandbox is true)."
-
exit 1
-
end
-
-
app.load_console
-
-
@console = app.config.console || IRB
-
-
if @console == IRB
-
IRB::WorkSpace.prepend(BacktraceCleaner)
-
end
-
end
-
-
def sandbox?
-
options[:sandbox]
-
end
-
-
def environment
-
options[:environment]
-
end
-
alias_method :environment?, :environment
-
-
def set_environment!
-
Rails.env = environment
-
end
-
-
def start
-
set_environment! if environment?
-
-
if sandbox?
-
puts "Loading #{Rails.env} environment in sandbox (Rails #{Rails.version})"
-
puts "Any modifications you make will be rolled back on exit"
-
else
-
puts "Loading #{Rails.env} environment (Rails #{Rails.version})"
-
end
-
-
if defined?(console::ExtendCommandBundle)
-
console::ExtendCommandBundle.include(Rails::ConsoleMethods)
-
end
-
console.start
-
end
-
end
-
-
module Command
-
class ConsoleCommand < Base # :nodoc:
-
include EnvironmentArgument
-
-
class_option :sandbox, aliases: "-s", type: :boolean, default: false,
-
desc: "Rollback database modifications on exit."
-
-
def initialize(args = [], local_options = {}, config = {})
-
console_options = []
-
-
# For the same behavior as OptionParser, leave only options after "--" in ARGV.
-
termination = local_options.find_index("--")
-
if termination
-
console_options = local_options[termination + 1..-1]
-
local_options = local_options[0...termination]
-
end
-
-
ARGV.replace(console_options)
-
super(args, local_options, config)
-
end
-
-
def perform
-
extract_environment_option_from_argument
-
-
# RAILS_ENV needs to be set before config/application is required.
-
ENV["RAILS_ENV"] = options[:environment]
-
-
require_application_and_environment!
-
Rails::Console.start(Rails.application, options)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
require "active_support"
-
require "rails/command/helpers/editor"
-
require "rails/command/environment_argument"
-
-
module Rails
-
module Command
-
class CredentialsCommand < Rails::Command::Base # :nodoc:
-
include Helpers::Editor
-
include EnvironmentArgument
-
-
require_relative "credentials_command/diffing"
-
include Diffing
-
-
self.environment_desc = "Uses credentials from config/credentials/:environment.yml.enc encrypted by config/credentials/:environment.key key"
-
-
no_commands do
-
def help
-
say "Usage:\n #{self.class.banner}"
-
say ""
-
say self.class.desc
-
end
-
end
-
-
def edit
-
extract_environment_option_from_argument(default_environment: nil)
-
require_application!
-
-
ensure_editor_available(command: "bin/rails credentials:edit") || (return)
-
-
ensure_encryption_key_has_been_added if credentials.key.nil?
-
ensure_credentials_have_been_added
-
ensure_rails_credentials_driver_is_set
-
-
catch_editing_exceptions do
-
change_credentials_in_system_editor
-
end
-
-
say "File encrypted and saved."
-
rescue ActiveSupport::MessageEncryptor::InvalidMessage
-
say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?"
-
end
-
-
def show
-
extract_environment_option_from_argument(default_environment: nil)
-
require_application!
-
-
say credentials.read.presence || missing_credentials_message
-
end
-
-
option :enroll, type: :boolean, default: false,
-
desc: "Enrolls project in credential file diffing with `git diff`"
-
-
def diff(content_path = nil)
-
if @content_path = content_path
-
extract_environment_option_from_argument(default_environment: extract_environment_from_path(content_path))
-
require_application!
-
-
say credentials.read.presence || credentials.content_path.read
-
else
-
require_application!
-
enroll_project_in_credentials_diffing if options[:enroll]
-
end
-
rescue ActiveSupport::MessageEncryptor::InvalidMessage
-
say credentials.content_path.read
-
end
-
-
private
-
def credentials
-
Rails.application.encrypted(content_path, key_path: key_path)
-
end
-
-
def ensure_encryption_key_has_been_added
-
encryption_key_file_generator.add_key_file(key_path)
-
encryption_key_file_generator.ignore_key_file(key_path)
-
end
-
-
def ensure_credentials_have_been_added
-
if options[:environment]
-
encrypted_file_generator.add_encrypted_file_silently(content_path, key_path)
-
else
-
credentials_generator.add_credentials_file_silently
-
end
-
end
-
-
def change_credentials_in_system_editor
-
credentials.change do |tmp_path|
-
system("#{ENV["EDITOR"]} #{tmp_path}")
-
end
-
end
-
-
def missing_credentials_message
-
if credentials.key.nil?
-
"Missing '#{key_path}' to decrypt credentials. See `rails credentials:help`"
-
else
-
"File '#{content_path}' does not exist. Use `rails credentials:edit` to change that."
-
end
-
end
-
-
-
def content_path
-
@content_path ||= options[:environment] ? "config/credentials/#{options[:environment]}.yml.enc" : "config/credentials.yml.enc"
-
end
-
-
def key_path
-
options[:environment] ? "config/credentials/#{options[:environment]}.key" : "config/master.key"
-
end
-
-
def extract_environment_from_path(path)
-
available_environments.find { |env| path.include? env } if path.end_with?(".yml.enc")
-
end
-
-
def encryption_key_file_generator
-
require "rails/generators"
-
require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
-
-
Rails::Generators::EncryptionKeyFileGenerator.new
-
end
-
-
def encrypted_file_generator
-
require "rails/generators"
-
require "rails/generators/rails/encrypted_file/encrypted_file_generator"
-
-
Rails::Generators::EncryptedFileGenerator.new
-
end
-
-
def credentials_generator
-
require "rails/generators"
-
require "rails/generators/rails/credentials/credentials_generator"
-
-
Rails::Generators::CredentialsGenerator.new
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails::Command::CredentialsCommand::Diffing # :nodoc:
-
def enroll_project_in_credentials_diffing
-
if enrolled?
-
true
-
else
-
gitattributes.write(<<~end_of_template, mode: "a")
-
config/credentials/*.yml.enc diff=rails_credentials
-
config/credentials.yml.enc diff=rails_credentials
-
end_of_template
-
-
say "Project successfully enrolled!"
-
say "Rails ensures the rails_credentials diff driver is set when running `credentials:edit`. See `credentials:help` for more."
-
end
-
end
-
-
def ensure_rails_credentials_driver_is_set
-
set_driver if enrolled? && !driver_configured?
-
end
-
-
private
-
def enrolled?
-
gitattributes.read.match?(/config\/credentials(\/\*)?\.yml\.enc diff=rails_credentials/)
-
rescue Errno::ENOENT
-
false
-
end
-
-
def driver_configured?
-
system "git config --get diff.rails_credentials.textconv", out: File::NULL
-
end
-
-
def set_driver
-
puts "running"
-
system "git config diff.rails_credentials.textconv 'bin/rails credentials:diff'"
-
end
-
-
def gitattributes
-
Rails.root.join(".gitattributes")
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators"
-
require "rails/generators/rails/db/system/change/change_generator"
-
-
module Rails
-
module Command
-
module Db
-
module System
-
class ChangeCommand < Base # :nodoc:
-
class_option :to, desc: "The database system to switch to."
-
-
def initialize(positional_args, option_args, *)
-
@argv = positional_args + option_args
-
super
-
end
-
-
def perform
-
Rails::Generators::Db::System::ChangeGenerator.start(@argv)
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/deprecation"
-
require "active_support/core_ext/string/filters"
-
require "rails/command/environment_argument"
-
-
module Rails
-
class DBConsole
-
def self.start(*args)
-
new(*args).start
-
end
-
-
def initialize(options = {})
-
@options = options
-
end
-
-
def start
-
ENV["RAILS_ENV"] ||= @options[:environment] || environment
-
config = db_config.configuration_hash
-
-
case db_config.adapter
-
when /^(jdbc)?mysql/
-
args = {
-
host: "--host",
-
port: "--port",
-
socket: "--socket",
-
username: "--user",
-
encoding: "--default-character-set",
-
sslca: "--ssl-ca",
-
sslcert: "--ssl-cert",
-
sslcapath: "--ssl-capath",
-
sslcipher: "--ssl-cipher",
-
sslkey: "--ssl-key"
-
}.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
-
-
if config[:password] && @options[:include_password]
-
args << "--password=#{config[:password]}"
-
elsif config[:password] && !config[:password].to_s.empty?
-
args << "-p"
-
end
-
-
args << db_config.database
-
-
find_cmd_and_exec(["mysql", "mysql5"], *args)
-
-
when /^postgres|^postgis/
-
ENV["PGUSER"] = config[:username] if config[:username]
-
ENV["PGHOST"] = config[:host] if config[:host]
-
ENV["PGPORT"] = config[:port].to_s if config[:port]
-
ENV["PGPASSWORD"] = config[:password].to_s if config[:password] && @options[:include_password]
-
find_cmd_and_exec("psql", db_config.database)
-
-
when "sqlite3"
-
args = []
-
-
args << "-#{@options[:mode]}" if @options[:mode]
-
args << "-header" if @options[:header]
-
args << File.expand_path(db_config.database, Rails.respond_to?(:root) ? Rails.root : nil)
-
-
find_cmd_and_exec("sqlite3", *args)
-
-
when "oracle", "oracle_enhanced"
-
logon = ""
-
-
if config[:username]
-
logon = config[:username].dup
-
logon << "/#{config[:password]}" if config[:password] && @options[:include_password]
-
logon << "@#{db_config.database}" if db_config.database
-
end
-
-
find_cmd_and_exec("sqlplus", logon)
-
-
when "sqlserver"
-
args = []
-
-
args += ["-D", "#{db_config.database}"] if db_config.database
-
args += ["-U", "#{config[:username]}"] if config[:username]
-
args += ["-P", "#{config[:password]}"] if config[:password]
-
-
if config[:host]
-
host_arg = +"#{config[:host]}"
-
host_arg << ":#{config[:port]}" if config[:port]
-
args += ["-S", host_arg]
-
end
-
-
find_cmd_and_exec("sqsh", *args)
-
-
else
-
abort "Unknown command-line client for #{db_config.database}."
-
end
-
end
-
-
def config
-
db_config.configuration_hash
-
end
-
deprecate config: "please use db_config.configuration_hash"
-
-
def db_config
-
return @db_config if defined?(@db_config)
-
-
# We need to check whether the user passed the database the
-
# first time around to show a consistent error message to people
-
# relying on 2-level database configuration.
-
-
@db_config = configurations.configs_for(env_name: environment, name: database)
-
-
unless @db_config
-
raise ActiveRecord::AdapterNotSpecified,
-
"'#{database}' database is not configured for '#{environment}'. Available configuration: #{configurations.inspect}"
-
end
-
-
@db_config
-
end
-
-
def environment
-
Rails.respond_to?(:env) ? Rails.env : Rails::Command.environment
-
end
-
-
def database
-
@options.fetch(:database, "primary")
-
end
-
-
private
-
def configurations # :doc:
-
require APP_PATH
-
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
-
ActiveRecord::Base.configurations
-
end
-
-
def find_cmd_and_exec(commands, *args) # :doc:
-
commands = Array(commands)
-
-
dirs_on_path = ENV["PATH"].to_s.split(File::PATH_SEPARATOR)
-
unless (ext = RbConfig::CONFIG["EXEEXT"]).empty?
-
commands = commands.map { |cmd| "#{cmd}#{ext}" }
-
end
-
-
full_path_command = nil
-
found = commands.detect do |cmd|
-
dirs_on_path.detect do |path|
-
full_path_command = File.join(path, cmd)
-
begin
-
stat = File.stat(full_path_command)
-
rescue SystemCallError
-
else
-
stat.file? && stat.executable?
-
end
-
end
-
end
-
-
if found
-
exec full_path_command, *args
-
else
-
abort("Couldn't find database client: #{commands.join(', ')}. Check your $PATH and try again.")
-
end
-
end
-
end
-
-
module Command
-
class DbconsoleCommand < Base # :nodoc:
-
include EnvironmentArgument
-
-
class_option :include_password, aliases: "-p", type: :boolean,
-
desc: "Automatically provide the password from database.yml"
-
-
class_option :mode, enum: %w( html list line column ), type: :string,
-
desc: "Automatically put the sqlite3 database in the specified mode (html, list, line, column)."
-
-
class_option :header, type: :boolean
-
-
class_option :connection, aliases: "-c", type: :string,
-
desc: "Specifies the connection to use."
-
-
class_option :database, aliases: "--db", type: :string,
-
desc: "Specifies the database to use."
-
-
def perform
-
extract_environment_option_from_argument
-
-
# RAILS_ENV needs to be set before config/application is required.
-
ENV["RAILS_ENV"] = options[:environment]
-
-
if options["connection"]
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
-
`connection` option is deprecated and will be removed in Rails 6.1. Please use `database` option instead.
-
MSG
-
options["database"] = options["connection"]
-
end
-
-
require_application_and_environment!
-
Rails::DBConsole.start(options)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators"
-
-
module Rails
-
module Command
-
class DestroyCommand < Base # :nodoc:
-
no_commands do
-
def help
-
require_application_and_environment!
-
load_generators
-
-
Rails::Generators.help self.class.command_name
-
end
-
end
-
-
def perform(*)
-
generator = args.shift
-
return help unless generator
-
-
require_application_and_environment!
-
load_generators
-
-
Rails::Generators.invoke generator, args, behavior: :revoke, destination_root: Rails::Command.root
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/dev_caching"
-
-
module Rails
-
module Command
-
class DevCommand < Base # :nodoc:
-
no_commands do
-
def help
-
say "rails dev:cache # Toggle development mode caching on/off."
-
end
-
end
-
-
def cache
-
Rails::DevCaching.enable_by_file
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
require "active_support"
-
require "rails/command/helpers/editor"
-
-
module Rails
-
module Command
-
class EncryptedCommand < Rails::Command::Base # :nodoc:
-
include Helpers::Editor
-
-
class_option :key, aliases: "-k", type: :string,
-
default: "config/master.key", desc: "The Rails.root relative path to the encryption key"
-
-
no_commands do
-
def help
-
say "Usage:\n #{self.class.banner}"
-
say ""
-
say self.class.desc
-
end
-
end
-
-
def edit(file_path)
-
require_application!
-
encrypted = Rails.application.encrypted(file_path, key_path: options[:key])
-
-
ensure_editor_available(command: "bin/rails encrypted:edit") || (return)
-
ensure_encryption_key_has_been_added(options[:key]) if encrypted.key.nil?
-
ensure_encrypted_file_has_been_added(file_path, options[:key])
-
-
catch_editing_exceptions do
-
change_encrypted_file_in_system_editor(file_path, options[:key])
-
end
-
-
say "File encrypted and saved."
-
rescue ActiveSupport::MessageEncryptor::InvalidMessage
-
say "Couldn't decrypt #{file_path}. Perhaps you passed the wrong key?"
-
end
-
-
def show(file_path)
-
require_application!
-
encrypted = Rails.application.encrypted(file_path, key_path: options[:key])
-
-
say encrypted.read.presence || missing_encrypted_message(key: encrypted.key, key_path: options[:key], file_path: file_path)
-
end
-
-
private
-
def ensure_encryption_key_has_been_added(key_path)
-
encryption_key_file_generator.add_key_file(key_path)
-
encryption_key_file_generator.ignore_key_file(key_path)
-
end
-
-
def ensure_encrypted_file_has_been_added(file_path, key_path)
-
encrypted_file_generator.add_encrypted_file_silently(file_path, key_path)
-
end
-
-
def change_encrypted_file_in_system_editor(file_path, key_path)
-
Rails.application.encrypted(file_path, key_path: key_path).change do |tmp_path|
-
system("#{ENV["EDITOR"]} #{tmp_path}")
-
end
-
end
-
-
-
def encryption_key_file_generator
-
require "rails/generators"
-
require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
-
-
Rails::Generators::EncryptionKeyFileGenerator.new
-
end
-
-
def encrypted_file_generator
-
require "rails/generators"
-
require "rails/generators/rails/encrypted_file/encrypted_file_generator"
-
-
Rails::Generators::EncryptedFileGenerator.new
-
end
-
-
def missing_encrypted_message(key:, key_path:, file_path:)
-
if key.nil?
-
"Missing '#{key_path}' to decrypt data. See `bin/rails encrypted:help`"
-
else
-
"File '#{file_path}' does not exist. Use `bin/rails encrypted:edit #{file_path}` to change that."
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators"
-
-
module Rails
-
module Command
-
class GenerateCommand < Base # :nodoc:
-
no_commands do
-
def help
-
require_application_and_environment!
-
load_generators
-
-
Rails::Generators.help self.class.command_name
-
end
-
end
-
-
def perform(*)
-
generator = args.shift
-
return help unless generator
-
-
require_application_and_environment!
-
load_generators
-
-
ARGV.replace(args) # set up ARGV for third-party libraries
-
-
Rails::Generators.invoke generator, args, behavior: :invoke, destination_root: Rails::Command.root
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
class HelpCommand < Base # :nodoc:
-
hide_command!
-
-
def help(*)
-
say self.class.desc
-
-
Rails::Command.print_commands
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/command/environment_argument"
-
-
module Rails
-
module Command
-
class InitializersCommand < Base # :nodoc:
-
include EnvironmentArgument
-
-
desc "initializers", "Print out all defined initializers in the order they are invoked by Rails."
-
def perform
-
extract_environment_option_from_argument
-
ENV["RAILS_ENV"] = options[:environment]
-
-
require_application_and_environment!
-
-
Rails.application.initializers.tsort_each do |initializer|
-
say "#{initializer.context_class}.#{initializer.name}"
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
class NewCommand < Base # :nodoc:
-
no_commands do
-
def help
-
Rails::Command.invoke :application, [ "--help" ]
-
end
-
end
-
-
def perform(*)
-
say "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n"
-
say "Type 'rails' for help."
-
exit 1
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/source_annotation_extractor"
-
-
module Rails
-
module Command
-
class NotesCommand < Base # :nodoc:
-
class_option :annotations, aliases: "-a", desc: "Filter by specific annotations, e.g. Foobar TODO", type: :array, default: Rails::SourceAnnotationExtractor::Annotation.tags
-
-
def perform(*)
-
require_application_and_environment!
-
-
deprecation_warning
-
display_annotations
-
end
-
-
private
-
def display_annotations
-
annotations = options[:annotations]
-
tag = (annotations.length > 1)
-
-
Rails::SourceAnnotationExtractor.enumerate annotations.join("|"), tag: tag, dirs: directories
-
end
-
-
def directories
-
Rails::SourceAnnotationExtractor::Annotation.directories + source_annotation_directories
-
end
-
-
def deprecation_warning
-
return if source_annotation_directories.empty?
-
ActiveSupport::Deprecation.warn("`SOURCE_ANNOTATION_DIRECTORIES` is deprecated and will be removed in Rails 6.1. You can add default directories by using config.annotations.register_directories instead.")
-
end
-
-
def source_annotation_directories
-
ENV["SOURCE_ANNOTATION_DIRECTORIES"].to_s.split(",")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
class PluginCommand < Base # :nodoc:
-
hide_command!
-
-
def help
-
run_plugin_generator %w( --help )
-
end
-
-
def self.banner(*) # :nodoc:
-
"#{executable} new [options]"
-
end
-
-
class_option :rc, type: :string, default: File.join("~", ".railsrc"),
-
desc: "Initialize the plugin command with previous defaults. Uses .railsrc in your home directory by default."
-
-
class_option :no_rc, desc: "Skip evaluating .railsrc."
-
-
def perform(type = nil, *plugin_args)
-
plugin_args << "--help" unless type == "new"
-
-
unless options.key?("no_rc") # Thor's not so indifferent access hash.
-
railsrc = File.expand_path(options[:rc])
-
-
if File.exist?(railsrc)
-
extra_args = File.read(railsrc).split(/\n+/).flat_map(&:split)
-
say "Using #{extra_args.join(" ")} from #{railsrc}"
-
plugin_args.insert(1, *extra_args)
-
end
-
end
-
-
run_plugin_generator plugin_args
-
end
-
-
private
-
def run_plugin_generator(plugin_args)
-
require "rails/generators"
-
require "rails/generators/rails/plugin/plugin_generator"
-
Rails::Generators::PluginGenerator.start plugin_args
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
class RakeCommand < Base # :nodoc:
-
extend Rails::Command::Actions
-
-
namespace "rake"
-
-
class << self
-
def printing_commands
-
formatted_rake_tasks.map(&:first)
-
end
-
-
def perform(task, args, config)
-
require_rake
-
-
Rake.with_application do |rake|
-
load "rails/tasks.rb"
-
rake.init("rails", [task, *args])
-
rake.load_rakefile
-
if Rails.respond_to?(:root)
-
rake.options.suppress_backtrace_pattern = /\A(?!#{Regexp.quote(Rails.root.to_s)})/
-
end
-
rake.standard_exception_handling { rake.top_level }
-
end
-
end
-
-
private
-
def rake_tasks
-
require_rake
-
-
return @rake_tasks if defined?(@rake_tasks)
-
-
require_application!
-
-
Rake::TaskManager.record_task_metadata = true
-
Rake.application.instance_variable_set(:@name, "rails")
-
load_tasks
-
@rake_tasks = Rake.application.tasks.select(&:comment)
-
end
-
-
def formatted_rake_tasks
-
rake_tasks.map { |t| [ t.name_with_args, t.comment ] }
-
end
-
-
def require_rake
-
require "rake" # Defer booting Rake until we know it's needed.
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/command"
-
-
module Rails
-
module Command
-
class RoutesCommand < Base # :nodoc:
-
class_option :controller, aliases: "-c", desc: "Filter by a specific controller, e.g. PostsController or Admin::PostsController."
-
class_option :grep, aliases: "-g", desc: "Grep routes by a specific pattern."
-
class_option :expanded, type: :boolean, aliases: "-E", desc: "Print routes expanded vertically with parts explained."
-
-
def perform(*)
-
require_application_and_environment!
-
require "action_dispatch/routing/inspector"
-
-
say inspector.format(formatter, routes_filter)
-
end
-
-
private
-
def inspector
-
ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes)
-
end
-
-
def formatter
-
if options.key?("expanded")
-
ActionDispatch::Routing::ConsoleFormatter::Expanded.new
-
else
-
ActionDispatch::Routing::ConsoleFormatter::Sheet.new
-
end
-
end
-
-
def routes_filter
-
options.symbolize_keys.slice(:controller, :grep)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/command/environment_argument"
-
-
module Rails
-
module Command
-
class RunnerCommand < Base # :nodoc:
-
include EnvironmentArgument
-
-
self.environment_desc = "The environment for the runner to operate under (test/development/production)"
-
-
no_commands do
-
def help
-
super
-
say self.class.desc
-
end
-
end
-
-
def self.banner(*)
-
"#{super} [<'Some.ruby(code)'> | <filename.rb> | -]"
-
end
-
-
def perform(code_or_file = nil, *command_argv)
-
extract_environment_option_from_argument
-
-
unless code_or_file
-
help
-
exit 1
-
end
-
-
ENV["RAILS_ENV"] = options[:environment]
-
-
require_application_and_environment!
-
Rails.application.load_runner
-
-
ARGV.replace(command_argv)
-
-
if code_or_file == "-"
-
eval($stdin.read, TOPLEVEL_BINDING, "stdin")
-
elsif File.exist?(code_or_file)
-
$0 = code_or_file
-
Kernel.load code_or_file
-
else
-
begin
-
eval(code_or_file, TOPLEVEL_BINDING, __FILE__, __LINE__)
-
rescue SyntaxError, NameError => e
-
error "Please specify a valid ruby command or the path of a script to run."
-
error "Run '#{self.class.executable} -h' for help."
-
error ""
-
error e
-
exit 1
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support"
-
require "rails/secrets"
-
-
module Rails
-
module Command
-
class SecretsCommand < Rails::Command::Base # :nodoc:
-
no_commands do
-
def help
-
say "Usage:\n #{self.class.banner}"
-
say ""
-
say self.class.desc
-
end
-
end
-
-
def setup
-
deprecate_in_favor_of_credentials_and_exit
-
end
-
-
def edit
-
if ENV["EDITOR"].to_s.empty?
-
say "No $EDITOR to open decrypted secrets in. Assign one like this:"
-
say ""
-
say %(EDITOR="mate --wait" rails secrets:edit)
-
say ""
-
say "For editors that fork and exit immediately, it's important to pass a wait flag,"
-
say "otherwise the secrets will be saved immediately with no chance to edit."
-
-
return
-
end
-
-
require_application_and_environment!
-
-
Rails::Secrets.read_for_editing do |tmp_path|
-
system("#{ENV["EDITOR"]} #{tmp_path}")
-
end
-
-
say "New secrets encrypted and saved."
-
rescue Interrupt
-
say "Aborted changing encrypted secrets: nothing saved."
-
rescue Rails::Secrets::MissingKeyError => error
-
say error.message
-
rescue Errno::ENOENT => error
-
if /secrets\.yml\.enc/.match?(error.message)
-
deprecate_in_favor_of_credentials_and_exit
-
else
-
raise
-
end
-
end
-
-
def show
-
say Rails::Secrets.read
-
end
-
-
private
-
def deprecate_in_favor_of_credentials_and_exit
-
say "Encrypted secrets is deprecated in favor of credentials. Run:"
-
say "rails credentials:help"
-
-
exit 1
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "fileutils"
-
require "action_dispatch"
-
require "rails"
-
require "active_support/deprecation"
-
require "active_support/core_ext/string/filters"
-
require "active_support/core_ext/symbol/starts_ends_with"
-
require "rails/dev_caching"
-
require "rails/command/environment_argument"
-
-
module Rails
-
class Server < ::Rack::Server
-
class Options
-
def parse!(args)
-
Rails::Command::ServerCommand.new([], args).server_options
-
end
-
end
-
-
def initialize(options = nil)
-
@default_options = options || {}
-
super(@default_options)
-
set_environment
-
end
-
-
def opt_parser
-
Options.new
-
end
-
-
def set_environment
-
ENV["RAILS_ENV"] ||= options[:environment]
-
end
-
-
def start(after_stop_callback = nil)
-
trap(:INT) { exit }
-
create_tmp_directories
-
setup_dev_caching
-
log_to_stdout if options[:log_stdout]
-
-
super()
-
ensure
-
after_stop_callback.call if after_stop_callback
-
end
-
-
def serveable? # :nodoc:
-
server
-
true
-
rescue LoadError, NameError
-
false
-
end
-
-
def middleware
-
Hash.new([])
-
end
-
-
def default_options
-
super.merge(@default_options)
-
end
-
-
def served_url
-
"#{options[:SSLEnable] ? 'https' : 'http'}://#{options[:Host]}:#{options[:Port]}" unless use_puma?
-
end
-
-
private
-
def setup_dev_caching
-
if options[:environment] == "development"
-
Rails::DevCaching.enable_by_argument(options[:caching])
-
end
-
end
-
-
def create_tmp_directories
-
%w(cache pids sockets).each do |dir_to_make|
-
FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make))
-
end
-
end
-
-
def log_to_stdout
-
wrapped_app # touch the app so the logger is set up
-
-
console = ActiveSupport::Logger.new(STDOUT)
-
console.formatter = Rails.logger.formatter
-
console.level = Rails.logger.level
-
-
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
-
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
-
end
-
end
-
-
def use_puma?
-
server.to_s == "Rack::Handler::Puma"
-
end
-
end
-
-
module Command
-
class ServerCommand < Base # :nodoc:
-
include EnvironmentArgument
-
-
# Hard-coding a bunch of handlers here as we don't have a public way of
-
# querying them from the Rack::Handler registry.
-
RACK_SERVERS = %w(cgi fastcgi webrick lsws scgi thin puma unicorn falcon)
-
-
DEFAULT_PORT = 3000
-
DEFAULT_PIDFILE = "tmp/pids/server.pid"
-
-
argument :using, optional: true
-
-
class_option :port, aliases: "-p", type: :numeric,
-
desc: "Runs Rails on the specified port - defaults to 3000.", banner: :port
-
class_option :binding, aliases: "-b", type: :string,
-
desc: "Binds Rails to the specified IP - defaults to 'localhost' in development and '0.0.0.0' in other environments'.",
-
banner: :IP
-
class_option :config, aliases: "-c", type: :string, default: "config.ru",
-
desc: "Uses a custom rackup configuration.", banner: :file
-
class_option :daemon, aliases: "-d", type: :boolean, default: false,
-
desc: "Runs server as a Daemon."
-
class_option :using, aliases: "-u", type: :string,
-
desc: "Specifies the Rack server used to run the application (thin/puma/webrick).", banner: :name
-
class_option :pid, aliases: "-P", type: :string,
-
desc: "Specifies the PID file - defaults to #{DEFAULT_PIDFILE}."
-
class_option :dev_caching, aliases: "-C", type: :boolean, default: nil,
-
desc: "Specifies whether to perform caching in development."
-
class_option :restart, type: :boolean, default: nil, hide: true
-
class_option :early_hints, type: :boolean, default: nil, desc: "Enables HTTP/2 early hints."
-
class_option :log_to_stdout, type: :boolean, default: nil, optional: true,
-
desc: "Whether to log to stdout. Enabled by default in development when not daemonized."
-
-
def initialize(args, local_options, *)
-
super
-
-
@original_options = local_options - %w( --restart )
-
deprecate_positional_rack_server_and_rewrite_to_option(@original_options)
-
end
-
-
def perform
-
extract_environment_option_from_argument
-
set_application_directory!
-
prepare_restart
-
-
Rails::Server.new(server_options).tap do |server|
-
# Require application after server sets environment to propagate
-
# the --environment option.
-
require APP_PATH
-
Dir.chdir(Rails.application.root)
-
-
if server.serveable?
-
print_boot_information(server.server, server.served_url)
-
after_stop_callback = -> { say "Exiting" unless options[:daemon] }
-
server.start(after_stop_callback)
-
else
-
say rack_server_suggestion(using)
-
end
-
end
-
end
-
-
no_commands do
-
def server_options
-
{
-
user_supplied_options: user_supplied_options,
-
server: using,
-
log_stdout: log_to_stdout?,
-
Port: port,
-
Host: host,
-
DoNotReverseLookup: true,
-
config: options[:config],
-
environment: environment,
-
daemonize: options[:daemon],
-
pid: pid,
-
caching: options[:dev_caching],
-
restart_cmd: restart_command,
-
early_hints: early_hints
-
}
-
end
-
end
-
-
private
-
def user_supplied_options
-
@user_supplied_options ||= begin
-
# Convert incoming options array to a hash of flags
-
# ["-p3001", "-C", "--binding", "127.0.0.1"] # => {"-p"=>true, "-C"=>true, "--binding"=>true}
-
user_flag = {}
-
@original_options.each do |command|
-
if command.start_with?("--")
-
option = command.split("=")[0]
-
user_flag[option] = true
-
elsif command =~ /\A(-.)/
-
user_flag[Regexp.last_match[0]] = true
-
end
-
end
-
-
# Collect all options that the user has explicitly defined so we can
-
# differentiate them from defaults
-
user_supplied_options = []
-
self.class.class_options.select do |key, option|
-
if option.aliases.any? { |name| user_flag[name] } || user_flag["--#{option.name}"]
-
name = option.name.to_sym
-
case name
-
when :port
-
name = :Port
-
when :binding
-
name = :Host
-
when :dev_caching
-
name = :caching
-
when :daemonize
-
name = :daemon
-
end
-
user_supplied_options << name
-
end
-
end
-
user_supplied_options << :Host if ENV["HOST"] || ENV["BINDING"]
-
user_supplied_options << :Port if ENV["PORT"]
-
user_supplied_options << :pid if ENV["PIDFILE"]
-
user_supplied_options.uniq
-
end
-
end
-
-
def port
-
options[:port] || ENV.fetch("PORT", DEFAULT_PORT).to_i
-
end
-
-
def host
-
if options[:binding]
-
options[:binding]
-
else
-
default_host = environment == "development" ? "localhost" : "0.0.0.0"
-
-
if ENV["HOST"] && !ENV["BINDING"]
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
-
Using the `HOST` environment variable to specify the IP is deprecated and will be removed in Rails 6.1.
-
Please use `BINDING` environment variable instead.
-
MSG
-
-
return ENV["HOST"]
-
end
-
-
ENV.fetch("BINDING", default_host)
-
end
-
end
-
-
def environment
-
options[:environment] || Rails::Command.environment
-
end
-
-
def restart_command
-
"bin/rails server #{@original_options.join(" ")} --restart"
-
end
-
-
def early_hints
-
options[:early_hints]
-
end
-
-
def log_to_stdout?
-
options.fetch(:log_to_stdout) do
-
options[:daemon].blank? && environment == "development"
-
end
-
end
-
-
def pid
-
File.expand_path(options[:pid] || ENV.fetch("PIDFILE", DEFAULT_PIDFILE))
-
end
-
-
def self.banner(*)
-
"rails server -u [thin/puma/webrick] [options]"
-
end
-
-
def prepare_restart
-
FileUtils.rm_f(pid) if options[:restart]
-
end
-
-
def deprecate_positional_rack_server_and_rewrite_to_option(original_options)
-
if using
-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
-
Passing the Rack server name as a regular argument is deprecated
-
and will be removed in the next Rails version. Please, use the -u
-
option instead.
-
MSG
-
-
original_options.concat [ "-u", using ]
-
else
-
# Use positional internally to get around Thor's immutable options.
-
# TODO: Replace `using` occurrences with `options[:using]` after deprecation removal.
-
@using = options[:using]
-
end
-
end
-
-
def rack_server_suggestion(server)
-
if server.in?(RACK_SERVERS)
-
<<~MSG
-
Could not load server "#{server}". Maybe you need to the add it to the Gemfile?
-
-
gem "#{server}"
-
-
Run `bin/rails server --help` for more options.
-
MSG
-
else
-
suggestion = Rails::Command::Spellchecker.suggest(server, from: RACK_SERVERS)
-
suggestion_msg = "Maybe you meant #{suggestion.inspect}?" if suggestion
-
-
<<~MSG
-
Could not find server "#{server}". #{suggestion_msg}
-
Run `bin/rails server --help` for more options.
-
MSG
-
end
-
end
-
-
def print_boot_information(server, url)
-
say <<~MSG
-
=> Booting #{ActiveSupport::Inflector.demodulize(server)}
-
=> Rails #{Rails.version} application starting in #{Rails.env} #{url}
-
=> Run `bin/rails server --help` for more startup options
-
MSG
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Command
-
class VersionCommand < Base # :nodoc:
-
def perform
-
Rails::Command.invoke :application, [ "--version" ]
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/ordered_options"
-
require "active_support/core_ext/object"
-
require "rails/paths"
-
require "rails/rack"
-
-
module Rails
-
module Configuration
-
# MiddlewareStackProxy is a proxy for the Rails middleware stack that allows
-
# you to configure middlewares in your application. It works basically as a
-
# command recorder, saving each command to be applied after initialization
-
# over the default middleware stack, so you can add, swap, or remove any
-
# middleware in Rails.
-
#
-
# You can add your own middlewares by using the +config.middleware.use+ method:
-
#
-
# config.middleware.use Magical::Unicorns
-
#
-
# This will put the <tt>Magical::Unicorns</tt> middleware on the end of the stack.
-
# You can use +insert_before+ if you wish to add a middleware before another:
-
#
-
# config.middleware.insert_before Rack::Head, Magical::Unicorns
-
#
-
# There's also +insert_after+ which will insert a middleware after another:
-
#
-
# config.middleware.insert_after Rack::Head, Magical::Unicorns
-
#
-
# Middlewares can also be completely swapped out and replaced with others:
-
#
-
# config.middleware.swap ActionDispatch::Flash, Magical::Unicorns
-
#
-
# Middlewares can be moved from one place to another:
-
#
-
# config.middleware.move_before ActionDispatch::Flash, Magical::Unicorns
-
#
-
# This will move the <tt>Magical::Unicorns</tt> middleware before the
-
# <tt>ActionDispatch::Flash</tt>. You can also move it after:
-
#
-
# config.middleware.move_after ActionDispatch::Flash, Magical::Unicorns
-
#
-
# And finally they can also be removed from the stack completely:
-
#
-
# config.middleware.delete ActionDispatch::Flash
-
#
-
class MiddlewareStackProxy
-
def initialize(operations = [], delete_operations = [])
-
@operations = operations
-
@delete_operations = delete_operations
-
end
-
-
def insert_before(*args, &block)
-
@operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
ruby2_keywords(:insert_before) if respond_to?(:ruby2_keywords, true)
-
-
alias :insert :insert_before
-
-
def insert_after(*args, &block)
-
@operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
ruby2_keywords(:insert_after) if respond_to?(:ruby2_keywords, true)
-
-
def swap(*args, &block)
-
@operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
ruby2_keywords(:swap) if respond_to?(:ruby2_keywords, true)
-
-
def use(*args, &block)
-
@operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
ruby2_keywords(:use) if respond_to?(:ruby2_keywords, true)
-
-
def delete(*args, &block)
-
@delete_operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
-
def move_before(*args, &block)
-
@delete_operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
-
alias :move :move_before
-
-
def move_after(*args, &block)
-
@delete_operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
-
def unshift(*args, &block)
-
@operations << -> middleware { middleware.send(__method__, *args, &block) }
-
end
-
ruby2_keywords(:unshift) if respond_to?(:ruby2_keywords, true)
-
-
def merge_into(other) #:nodoc:
-
(@operations + @delete_operations).each do |operation|
-
operation.call(other)
-
end
-
-
other
-
end
-
-
def +(other) # :nodoc:
-
MiddlewareStackProxy.new(@operations + other.operations, @delete_operations + other.delete_operations)
-
end
-
-
protected
-
attr_reader :operations, :delete_operations
-
end
-
-
class Generators #:nodoc:
-
attr_accessor :aliases, :options, :templates, :fallbacks, :colorize_logging, :api_only
-
attr_reader :hidden_namespaces, :after_generate_callbacks
-
-
def initialize
-
@aliases = Hash.new { |h, k| h[k] = {} }
-
@options = Hash.new { |h, k| h[k] = {} }
-
@fallbacks = {}
-
@templates = []
-
@colorize_logging = true
-
@api_only = false
-
@hidden_namespaces = []
-
@after_generate_callbacks = []
-
end
-
-
def initialize_copy(source)
-
@aliases = @aliases.deep_dup
-
@options = @options.deep_dup
-
@fallbacks = @fallbacks.deep_dup
-
@templates = @templates.dup
-
end
-
-
def hide_namespace(namespace)
-
@hidden_namespaces << namespace
-
end
-
-
def after_generate(&block)
-
@after_generate_callbacks << block
-
end
-
-
def method_missing(method, *args)
-
method = method.to_s.delete_suffix("=").to_sym
-
-
if args.empty?
-
if method == :rails
-
return @options[method]
-
else
-
return @options[:rails][method]
-
end
-
end
-
-
if method == :rails || args.first.is_a?(Hash)
-
namespace, configuration = method, args.shift
-
else
-
namespace, configuration = args.shift, args.shift
-
namespace = namespace.to_sym if namespace.respond_to?(:to_sym)
-
@options[:rails][method] = namespace
-
end
-
-
if configuration
-
aliases = configuration.delete(:aliases)
-
@aliases[namespace].merge!(aliases) if aliases
-
@options[namespace].merge!(configuration)
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/all"
-
require "action_controller"
-
-
module Rails
-
module ConsoleMethods
-
# reference the global "app" instance, created on demand. To recreate the
-
# instance, pass a non-false value as the parameter.
-
def app(create = false)
-
@app_integration_instance = nil if create
-
@app_integration_instance ||= new_session do |sess|
-
sess.host! "www.example.com"
-
end
-
end
-
-
# create a new session. If a block is given, the new session will be yielded
-
# to the block before being returned.
-
def new_session
-
app = Rails.application
-
session = ActionDispatch::Integration::Session.new(app)
-
yield session if block_given?
-
-
# This makes app.url_for and app.foo_path available in the console
-
session.extend(app.routes.url_helpers)
-
session.extend(app.routes.mounted_helpers)
-
-
session
-
end
-
-
# reloads the environment
-
def reload!(print = true)
-
puts "Reloading..." if print
-
Rails.application.reloader.reload!
-
true
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module ConsoleMethods
-
# Gets the helper methods available to the controller.
-
#
-
# This method assumes an +ApplicationController+ exists, and it extends +ActionController::Base+
-
def helper
-
ApplicationController.helpers
-
end
-
-
# Gets a new instance of a controller object.
-
#
-
# This method assumes an +ApplicationController+ exists, and it extends +ActionController::Base+
-
def controller
-
@controller ||= ApplicationController.new
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "fileutils"
-
-
module Rails
-
module DevCaching # :nodoc:
-
class << self
-
FILE = "tmp/caching-dev.txt"
-
-
def enable_by_file
-
FileUtils.mkdir_p("tmp")
-
-
if File.exist?(FILE)
-
delete_cache_file
-
puts "Development mode is no longer being cached."
-
else
-
create_cache_file
-
puts "Development mode is now being cached."
-
end
-
-
FileUtils.touch "tmp/restart.txt"
-
end
-
-
def enable_by_argument(caching)
-
FileUtils.mkdir_p("tmp")
-
-
if caching
-
create_cache_file
-
elsif caching == false && File.exist?(FILE)
-
delete_cache_file
-
end
-
end
-
-
private
-
def create_cache_file
-
FileUtils.touch FILE
-
end
-
-
def delete_cache_file
-
File.delete FILE
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/railtie"
-
require "rails/engine/railties"
-
require "active_support/core_ext/module/delegation"
-
require "active_support/core_ext/object/try"
-
require "pathname"
-
require "thread"
-
-
module Rails
-
# <tt>Rails::Engine</tt> allows you to wrap a specific Rails application or subset of
-
# functionality and share it with other applications or within a larger packaged application.
-
# Every <tt>Rails::Application</tt> is just an engine, which allows for simple
-
# feature and application sharing.
-
#
-
# Any <tt>Rails::Engine</tt> is also a <tt>Rails::Railtie</tt>, so the same
-
# methods (like <tt>rake_tasks</tt> and +generators+) and configuration
-
# options that are available in railties can also be used in engines.
-
#
-
# == Creating an Engine
-
#
-
# If you want a gem to behave as an engine, you have to specify an +Engine+
-
# for it somewhere inside your plugin's +lib+ folder (similar to how we
-
# specify a +Railtie+):
-
#
-
# # lib/my_engine.rb
-
# module MyEngine
-
# class Engine < Rails::Engine
-
# end
-
# end
-
#
-
# Then ensure that this file is loaded at the top of your <tt>config/application.rb</tt>
-
# (or in your +Gemfile+) and it will automatically load models, controllers and helpers
-
# inside +app+, load routes at <tt>config/routes.rb</tt>, load locales at
-
# <tt>config/locales/*</tt>, and load tasks at <tt>lib/tasks/*</tt>.
-
#
-
# == Configuration
-
#
-
# Like railties, engines can access a config object which contains configuration shared by
-
# all railties and the application.
-
# Additionally, each engine can access <tt>autoload_paths</tt>, <tt>eager_load_paths</tt> and
-
# <tt>autoload_once_paths</tt> settings which are scoped to that engine.
-
#
-
# class MyEngine < Rails::Engine
-
# # Add a load path for this specific Engine
-
# config.autoload_paths << File.expand_path("lib/some/path", __dir__)
-
#
-
# initializer "my_engine.add_middleware" do |app|
-
# app.middleware.use MyEngine::Middleware
-
# end
-
# end
-
#
-
# == Generators
-
#
-
# You can set up generators for engines with <tt>config.generators</tt> method:
-
#
-
# class MyEngine < Rails::Engine
-
# config.generators do |g|
-
# g.orm :active_record
-
# g.template_engine :erb
-
# g.test_framework :test_unit
-
# end
-
# end
-
#
-
# You can also set generators for an application by using <tt>config.app_generators</tt>:
-
#
-
# class MyEngine < Rails::Engine
-
# # note that you can also pass block to app_generators in the same way you
-
# # can pass it to generators method
-
# config.app_generators.orm :datamapper
-
# end
-
#
-
# == Paths
-
#
-
# Applications and engines have flexible path configuration, meaning that you
-
# are not required to place your controllers at <tt>app/controllers</tt>, but
-
# in any place which you find convenient.
-
#
-
# For example, let's suppose you want to place your controllers in <tt>lib/controllers</tt>.
-
# You can set that as an option:
-
#
-
# class MyEngine < Rails::Engine
-
# paths["app/controllers"] = "lib/controllers"
-
# end
-
#
-
# You can also have your controllers loaded from both <tt>app/controllers</tt> and
-
# <tt>lib/controllers</tt>:
-
#
-
# class MyEngine < Rails::Engine
-
# paths["app/controllers"] << "lib/controllers"
-
# end
-
#
-
# The available paths in an engine are:
-
#
-
# class MyEngine < Rails::Engine
-
# paths["app"] # => ["app"]
-
# paths["app/controllers"] # => ["app/controllers"]
-
# paths["app/helpers"] # => ["app/helpers"]
-
# paths["app/models"] # => ["app/models"]
-
# paths["app/views"] # => ["app/views"]
-
# paths["lib"] # => ["lib"]
-
# paths["lib/tasks"] # => ["lib/tasks"]
-
# paths["config"] # => ["config"]
-
# paths["config/initializers"] # => ["config/initializers"]
-
# paths["config/locales"] # => ["config/locales"]
-
# paths["config/routes.rb"] # => ["config/routes.rb"]
-
# end
-
#
-
# The <tt>Application</tt> class adds a couple more paths to this set. And as in your
-
# <tt>Application</tt>, all folders under +app+ are automatically added to the load path.
-
# If you have an <tt>app/services</tt> folder for example, it will be added by default.
-
#
-
# == Endpoint
-
#
-
# An engine can also be a Rack application. It can be useful if you have a Rack application that
-
# you would like to provide with some of the +Engine+'s features.
-
#
-
# To do that, use the +endpoint+ method:
-
#
-
# module MyEngine
-
# class Engine < Rails::Engine
-
# endpoint MyRackApplication
-
# end
-
# end
-
#
-
# Now you can mount your engine in application's routes:
-
#
-
# Rails.application.routes.draw do
-
# mount MyEngine::Engine => "/engine"
-
# end
-
#
-
# == Middleware stack
-
#
-
# As an engine can now be a Rack endpoint, it can also have a middleware
-
# stack. The usage is exactly the same as in <tt>Application</tt>:
-
#
-
# module MyEngine
-
# class Engine < Rails::Engine
-
# middleware.use SomeMiddleware
-
# end
-
# end
-
#
-
# == Routes
-
#
-
# If you don't specify an endpoint, routes will be used as the default
-
# endpoint. You can use them just like you use an application's routes:
-
#
-
# # ENGINE/config/routes.rb
-
# MyEngine::Engine.routes.draw do
-
# get "/" => "posts#index"
-
# end
-
#
-
# == Mount priority
-
#
-
# Note that now there can be more than one router in your application, and it's better to avoid
-
# passing requests through many routers. Consider this situation:
-
#
-
# Rails.application.routes.draw do
-
# mount MyEngine::Engine => "/blog"
-
# get "/blog/omg" => "main#omg"
-
# end
-
#
-
# +MyEngine+ is mounted at <tt>/blog</tt>, and <tt>/blog/omg</tt> points to application's
-
# controller. In such a situation, requests to <tt>/blog/omg</tt> will go through +MyEngine+,
-
# and if there is no such route in +Engine+'s routes, it will be dispatched to <tt>main#omg</tt>.
-
# It's much better to swap that:
-
#
-
# Rails.application.routes.draw do
-
# get "/blog/omg" => "main#omg"
-
# mount MyEngine::Engine => "/blog"
-
# end
-
#
-
# Now, +Engine+ will get only requests that were not handled by +Application+.
-
#
-
# == Engine name
-
#
-
# There are some places where an Engine's name is used:
-
#
-
# * routes: when you mount an Engine with <tt>mount(MyEngine::Engine => '/my_engine')</tt>,
-
# it's used as default <tt>:as</tt> option
-
# * rake task for installing migrations <tt>my_engine:install:migrations</tt>
-
#
-
# Engine name is set by default based on class name. For <tt>MyEngine::Engine</tt> it will be
-
# <tt>my_engine_engine</tt>. You can change it manually using the <tt>engine_name</tt> method:
-
#
-
# module MyEngine
-
# class Engine < Rails::Engine
-
# engine_name "my_engine"
-
# end
-
# end
-
#
-
# == Isolated Engine
-
#
-
# Normally when you create controllers, helpers and models inside an engine, they are treated
-
# as if they were created inside the application itself. This means that all helpers and
-
# named routes from the application will be available to your engine's controllers as well.
-
#
-
# However, sometimes you want to isolate your engine from the application, especially if your engine
-
# has its own router. To do that, you simply need to call +isolate_namespace+. This method requires
-
# you to pass a module where all your controllers, helpers and models should be nested to:
-
#
-
# module MyEngine
-
# class Engine < Rails::Engine
-
# isolate_namespace MyEngine
-
# end
-
# end
-
#
-
# With such an engine, everything that is inside the +MyEngine+ module will be isolated from
-
# the application.
-
#
-
# Consider this controller:
-
#
-
# module MyEngine
-
# class FooController < ActionController::Base
-
# end
-
# end
-
#
-
# If the +MyEngine+ engine is marked as isolated, +FooController+ only has
-
# access to helpers from +MyEngine+, and <tt>url_helpers</tt> from
-
# <tt>MyEngine::Engine.routes</tt>.
-
#
-
# The next thing that changes in isolated engines is the behavior of routes.
-
# Normally, when you namespace your controllers, you also need to namespace
-
# the related routes. With an isolated engine, the engine's namespace is
-
# automatically applied, so you don't need to specify it explicitly in your
-
# routes:
-
#
-
# MyEngine::Engine.routes.draw do
-
# resources :articles
-
# end
-
#
-
# If +MyEngine+ is isolated, the routes above will point to
-
# <tt>MyEngine::ArticlesController</tt>. You also don't need to use longer
-
# URL helpers like +my_engine_articles_path+. Instead, you should simply use
-
# +articles_path+, like you would do with your main application.
-
#
-
# To make this behavior consistent with other parts of the framework,
-
# isolated engines also have an effect on <tt>ActiveModel::Naming</tt>. In a
-
# normal Rails app, when you use a namespaced model such as
-
# <tt>Namespace::Article</tt>, <tt>ActiveModel::Naming</tt> will generate
-
# names with the prefix "namespace". In an isolated engine, the prefix will
-
# be omitted in URL helpers and form fields, for convenience.
-
#
-
# polymorphic_url(MyEngine::Article.new)
-
# # => "articles_path" # not "my_engine_articles_path"
-
#
-
# form_for(MyEngine::Article.new) do
-
# text_field :title # => <input type="text" name="article[title]" id="article_title" />
-
# end
-
#
-
# Additionally, an isolated engine will set its own name according to its
-
# namespace, so <tt>MyEngine::Engine.engine_name</tt> will return
-
# "my_engine". It will also set +MyEngine.table_name_prefix+ to "my_engine_",
-
# meaning for example that <tt>MyEngine::Article</tt> will use the
-
# +my_engine_articles+ database table by default.
-
#
-
# == Using Engine's routes outside Engine
-
#
-
# Since you can now mount an engine inside application's routes, you do not have direct access to +Engine+'s
-
# <tt>url_helpers</tt> inside +Application+. When you mount an engine in an application's routes, a special helper is
-
# created to allow you to do that. Consider such a scenario:
-
#
-
# # config/routes.rb
-
# Rails.application.routes.draw do
-
# mount MyEngine::Engine => "/my_engine", as: "my_engine"
-
# get "/foo" => "foo#index"
-
# end
-
#
-
# Now, you can use the <tt>my_engine</tt> helper inside your application:
-
#
-
# class FooController < ApplicationController
-
# def index
-
# my_engine.root_url # => /my_engine/
-
# end
-
# end
-
#
-
# There is also a <tt>main_app</tt> helper that gives you access to application's routes inside Engine:
-
#
-
# module MyEngine
-
# class BarController
-
# def index
-
# main_app.foo_path # => /foo
-
# end
-
# end
-
# end
-
#
-
# Note that the <tt>:as</tt> option given to mount takes the <tt>engine_name</tt> as default, so most of the time
-
# you can simply omit it.
-
#
-
# Finally, if you want to generate a URL to an engine's route using
-
# <tt>polymorphic_url</tt>, you also need to pass the engine helper. Let's
-
# say that you want to create a form pointing to one of the engine's routes.
-
# All you need to do is pass the helper as the first element in array with
-
# attributes for URL:
-
#
-
# form_for([my_engine, @user])
-
#
-
# This code will use <tt>my_engine.user_path(@user)</tt> to generate the proper route.
-
#
-
# == Isolated engine's helpers
-
#
-
# Sometimes you may want to isolate engine, but use helpers that are defined for it.
-
# If you want to share just a few specific helpers you can add them to application's
-
# helpers in ApplicationController:
-
#
-
# class ApplicationController < ActionController::Base
-
# helper MyEngine::SharedEngineHelper
-
# end
-
#
-
# If you want to include all of the engine's helpers, you can use the #helper method on an engine's
-
# instance:
-
#
-
# class ApplicationController < ActionController::Base
-
# helper MyEngine::Engine.helpers
-
# end
-
#
-
# It will include all of the helpers from engine's directory. Take into account this does
-
# not include helpers defined in controllers with helper_method or other similar solutions,
-
# only helpers defined in the helpers directory will be included.
-
#
-
# == Migrations & seed data
-
#
-
# Engines can have their own migrations. The default path for migrations is exactly the same
-
# as in application: <tt>db/migrate</tt>
-
#
-
# To use engine's migrations in application you can use the rake task below, which copies them to
-
# application's dir:
-
#
-
# rake ENGINE_NAME:install:migrations
-
#
-
# Note that some of the migrations may be skipped if a migration with the same name already exists
-
# in application. In such a situation you must decide whether to leave that migration or rename the
-
# migration in the application and rerun copying migrations.
-
#
-
# If your engine has migrations, you may also want to prepare data for the database in
-
# the <tt>db/seeds.rb</tt> file. You can load that data using the <tt>load_seed</tt> method, e.g.
-
#
-
# MyEngine::Engine.load_seed
-
#
-
# == Loading priority
-
#
-
# In order to change engine's priority you can use +config.railties_order+ in the main application.
-
# It will affect the priority of loading views, helpers, assets, and all the other files
-
# related to engine or application.
-
#
-
# # load Blog::Engine with highest priority, followed by application and other railties
-
# config.railties_order = [Blog::Engine, :main_app, :all]
-
class Engine < Railtie
-
autoload :Configuration, "rails/engine/configuration"
-
-
class << self
-
attr_accessor :called_from, :isolated
-
-
alias :isolated? :isolated
-
alias :engine_name :railtie_name
-
-
delegate :eager_load!, to: :instance
-
-
def inherited(base)
-
unless base.abstract_railtie?
-
Rails::Railtie::Configuration.eager_load_namespaces << base
-
-
base.called_from = begin
-
call_stack = caller_locations.map { |l| l.absolute_path || l.path }
-
-
File.dirname(call_stack.detect { |p| !p.match?(%r[railties[\w.-]*/lib/rails|rack[\w.-]*/lib/rack]) })
-
end
-
end
-
-
super
-
end
-
-
def find_root(from)
-
find_root_with_flag "lib", from
-
end
-
-
def endpoint(endpoint = nil)
-
@endpoint ||= nil
-
@endpoint = endpoint if endpoint
-
@endpoint
-
end
-
-
def isolate_namespace(mod)
-
engine_name(generate_railtie_name(mod.name))
-
-
routes.default_scope = { module: ActiveSupport::Inflector.underscore(mod.name) }
-
self.isolated = true
-
-
unless mod.respond_to?(:railtie_namespace)
-
name, railtie = engine_name, self
-
-
mod.singleton_class.instance_eval do
-
define_method(:railtie_namespace) { railtie }
-
-
unless mod.respond_to?(:table_name_prefix)
-
define_method(:table_name_prefix) { "#{name}_" }
-
end
-
-
unless mod.respond_to?(:use_relative_model_naming?)
-
class_eval "def use_relative_model_naming?; true; end", __FILE__, __LINE__
-
end
-
-
unless mod.respond_to?(:railtie_helpers_paths)
-
define_method(:railtie_helpers_paths) { railtie.helpers_paths }
-
end
-
-
unless mod.respond_to?(:railtie_routes_url_helpers)
-
define_method(:railtie_routes_url_helpers) { |include_path_helpers = true| railtie.routes.url_helpers(include_path_helpers) }
-
end
-
end
-
end
-
end
-
-
# Finds engine with given path.
-
def find(path)
-
expanded_path = File.expand_path path
-
Rails::Engine.subclasses.each do |klass|
-
engine = klass.instance
-
return engine if File.expand_path(engine.root) == expanded_path
-
end
-
nil
-
end
-
end
-
-
delegate :middleware, :root, :paths, to: :config
-
delegate :engine_name, :isolated?, to: :class
-
-
def initialize
-
@_all_autoload_paths = nil
-
@_all_load_paths = nil
-
@app = nil
-
@config = nil
-
@env_config = nil
-
@helpers = nil
-
@routes = nil
-
@app_build_lock = Mutex.new
-
super
-
end
-
-
# Load console and invoke the registered hooks.
-
# Check <tt>Rails::Railtie.console</tt> for more info.
-
def load_console(app = self)
-
require "rails/console/app"
-
require "rails/console/helpers"
-
run_console_blocks(app)
-
self
-
end
-
-
# Load Rails runner and invoke the registered hooks.
-
# Check <tt>Rails::Railtie.runner</tt> for more info.
-
def load_runner(app = self)
-
run_runner_blocks(app)
-
self
-
end
-
-
# Load Rake, railties tasks and invoke the registered hooks.
-
# Check <tt>Rails::Railtie.rake_tasks</tt> for more info.
-
def load_tasks(app = self)
-
require "rake"
-
run_tasks_blocks(app)
-
self
-
end
-
-
# Load Rails generators and invoke the registered hooks.
-
# Check <tt>Rails::Railtie.generators</tt> for more info.
-
def load_generators(app = self)
-
require "rails/generators"
-
run_generators_blocks(app)
-
Rails::Generators.configure!(app.config.generators)
-
self
-
end
-
-
def eager_load!
-
# Already done by Zeitwerk::Loader.eager_load_all. We need this guard to
-
# easily provide a compatible API for both zeitwerk and classic modes.
-
return if Rails.autoloaders.zeitwerk_enabled?
-
-
config.eager_load_paths.each do |load_path|
-
# Starts after load_path plus a slash, ends before ".rb".
-
relname_range = (load_path.to_s.length + 1)...-3
-
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
-
require_dependency file[relname_range]
-
end
-
end
-
end
-
-
def railties
-
@railties ||= Railties.new
-
end
-
-
# Returns a module with all the helpers defined for the engine.
-
def helpers
-
@helpers ||= begin
-
helpers = Module.new
-
all = ActionController::Base.all_helpers_from_path(helpers_paths)
-
ActionController::Base.modules_for_helpers(all).each do |mod|
-
helpers.include(mod)
-
end
-
helpers
-
end
-
end
-
-
# Returns all registered helpers paths.
-
def helpers_paths
-
paths["app/helpers"].existent
-
end
-
-
# Returns the underlying Rack application for this engine.
-
def app
-
@app || @app_build_lock.synchronize {
-
@app ||= begin
-
stack = default_middleware_stack
-
config.middleware = build_middleware.merge_into(stack)
-
config.middleware.build(endpoint)
-
end
-
}
-
end
-
-
# Returns the endpoint for this engine. If none is registered,
-
# defaults to an ActionDispatch::Routing::RouteSet.
-
def endpoint
-
self.class.endpoint || routes
-
end
-
-
# Define the Rack API for this engine.
-
def call(env)
-
req = build_request env
-
app.call req.env
-
end
-
-
# Defines additional Rack env configuration that is added on each call.
-
def env_config
-
@env_config ||= {}
-
end
-
-
# Defines the routes for this engine. If a block is given to
-
# routes, it is appended to the engine.
-
def routes(&block)
-
@routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
-
@routes.append(&block) if block_given?
-
@routes
-
end
-
-
# Define the configuration object for the engine.
-
def config
-
@config ||= Engine::Configuration.new(self.class.find_root(self.class.called_from))
-
end
-
-
# Load data from db/seeds.rb file. It can be used in to load engines'
-
# seeds, e.g.:
-
#
-
# Blog::Engine.load_seed
-
def load_seed
-
seed_file = paths["db/seeds.rb"].existent.first
-
return unless seed_file
-
-
if config.try(:active_job)&.queue_adapter == :async
-
with_inline_jobs { load(seed_file) }
-
else
-
load(seed_file)
-
end
-
end
-
-
initializer :load_environment_config, before: :load_environment_hook, group: :all do
-
paths["config/environments"].existent.each do |environment|
-
require environment
-
end
-
end
-
-
initializer :set_load_path, before: :bootstrap_hook do |app|
-
_all_load_paths(app.config.add_autoload_paths_to_load_path).reverse_each do |path|
-
$LOAD_PATH.unshift(path) if File.directory?(path)
-
end
-
$LOAD_PATH.uniq!
-
end
-
-
# Set the paths from which Rails will automatically load source files,
-
# and the load_once paths.
-
#
-
# This needs to be an initializer, since it needs to run once
-
# per engine and get the engine as a block parameter.
-
initializer :set_autoload_paths, before: :bootstrap_hook do
-
ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
-
ActiveSupport::Dependencies.autoload_once_paths.unshift(*_all_autoload_once_paths)
-
-
config.autoload_paths.freeze
-
config.autoload_once_paths.freeze
-
end
-
-
initializer :set_eager_load_paths, before: :bootstrap_hook do
-
ActiveSupport::Dependencies._eager_load_paths.merge(config.eager_load_paths)
-
config.eager_load_paths.freeze
-
end
-
-
initializer :add_routing_paths do |app|
-
routing_paths = paths["config/routes.rb"].existent
-
external_paths = self.paths["config/routes"].paths
-
routes.draw_paths.concat(external_paths)
-
-
if routes? || routing_paths.any?
-
app.routes_reloader.paths.unshift(*routing_paths)
-
app.routes_reloader.route_sets << routes
-
app.routes_reloader.external_routes.unshift(*external_paths)
-
end
-
end
-
-
# I18n load paths are a special case since the ones added
-
# later have higher priority.
-
initializer :add_locales do
-
config.i18n.railties_load_path << paths["config/locales"]
-
end
-
-
initializer :add_view_paths do
-
views = paths["app/views"].existent
-
unless views.empty?
-
ActiveSupport.on_load(:action_controller) { prepend_view_path(views) if respond_to?(:prepend_view_path) }
-
ActiveSupport.on_load(:action_mailer) { prepend_view_path(views) }
-
end
-
end
-
-
initializer :prepend_helpers_path do |app|
-
if !isolated? || (app == self)
-
app.config.helpers_paths.unshift(*paths["app/helpers"].existent)
-
end
-
end
-
-
initializer :load_config_initializers do
-
config.paths["config/initializers"].existent.sort.each do |initializer|
-
load_config_initializer(initializer)
-
end
-
end
-
-
initializer :engines_blank_point do
-
# We need this initializer so all extra initializers added in engines are
-
# consistently executed after all the initializers above across all engines.
-
end
-
-
rake_tasks do
-
next if is_a?(Rails::Application)
-
next unless has_migrations?
-
-
namespace railtie_name do
-
namespace :install do
-
desc "Copy migrations from #{railtie_name} to application"
-
task :migrations do
-
ENV["FROM"] = railtie_name
-
if Rake::Task.task_defined?("railties:install:migrations")
-
Rake::Task["railties:install:migrations"].invoke
-
else
-
Rake::Task["app:railties:install:migrations"].invoke
-
end
-
end
-
end
-
end
-
end
-
-
def routes? #:nodoc:
-
@routes
-
end
-
-
protected
-
def run_tasks_blocks(*) #:nodoc:
-
super
-
paths["lib/tasks"].existent.sort.each { |ext| load(ext) }
-
end
-
-
private
-
def load_config_initializer(initializer) # :doc:
-
ActiveSupport::Notifications.instrument("load_config_initializer.railties", initializer: initializer) do
-
load(initializer)
-
end
-
end
-
-
def with_inline_jobs
-
queue_adapter = config.active_job.queue_adapter
-
ActiveSupport.on_load(:active_job) do
-
self.queue_adapter = :inline
-
end
-
yield
-
ensure
-
ActiveSupport.on_load(:active_job) do
-
self.queue_adapter = queue_adapter
-
end
-
end
-
-
def has_migrations?
-
paths["db/migrate"].existent.any?
-
end
-
-
def self.find_root_with_flag(flag, root_path, default = nil) #:nodoc:
-
while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
-
parent = File.dirname(root_path)
-
root_path = parent != root_path && parent
-
end
-
-
root = File.exist?("#{root_path}/#{flag}") ? root_path : default
-
raise "Could not find root path for #{self}" unless root
-
-
Pathname.new File.realpath root
-
end
-
-
def default_middleware_stack
-
ActionDispatch::MiddlewareStack.new
-
end
-
-
def _all_autoload_once_paths
-
config.autoload_once_paths
-
end
-
-
def _all_autoload_paths
-
@_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
-
end
-
-
def _all_load_paths(add_autoload_paths_to_load_path)
-
@_all_load_paths ||= begin
-
load_paths = config.paths.load_paths
-
load_paths += _all_autoload_paths if add_autoload_paths_to_load_path
-
load_paths.uniq
-
end
-
end
-
-
def build_request(env)
-
env.merge!(env_config)
-
req = ActionDispatch::Request.new env
-
req.routes = routes
-
req.engine_script_name = req.script_name
-
req
-
end
-
-
def build_middleware
-
config.middleware
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
unless defined?(APP_PATH)
-
if File.exist?(File.expand_path("test/dummy/config/application.rb", ENGINE_ROOT))
-
APP_PATH = File.expand_path("test/dummy/config/application", ENGINE_ROOT)
-
end
-
end
-
-
require "rails/commands"
-
# frozen_string_literal: true
-
-
17
require "rails/railtie/configuration"
-
-
17
module Rails
-
17
class Engine
-
17
class Configuration < ::Rails::Railtie::Configuration
-
17
attr_reader :root
-
17
attr_accessor :middleware, :javascript_path
-
17
attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths
-
-
17
def initialize(root = nil)
-
102
super()
-
102
@root = root
-
102
@generators = app_generators.dup
-
102
@middleware = Rails::Configuration::MiddlewareStackProxy.new
-
102
@javascript_path = "javascript"
-
end
-
-
# Holds generators configuration:
-
#
-
# config.generators do |g|
-
# g.orm :data_mapper, migration: true
-
# g.template_engine :haml
-
# g.test_framework :rspec
-
# end
-
#
-
# If you want to disable color in console, do:
-
#
-
# config.generators.colorize_logging = false
-
#
-
17
def generators
-
32
@generators ||= Rails::Configuration::Generators.new
-
32
yield(@generators) if block_given?
-
32
@generators
-
end
-
-
17
def paths
-
17
@paths ||= begin
-
17
paths = Rails::Paths::Root.new(@root)
-
-
17
paths.add "app", eager_load: true,
-
glob: "{*,*/concerns}",
-
exclude: ["assets", javascript_path]
-
17
paths.add "app/assets", glob: "*"
-
17
paths.add "app/controllers", eager_load: true
-
17
paths.add "app/channels", eager_load: true, glob: "**/*_channel.rb"
-
17
paths.add "app/helpers", eager_load: true
-
17
paths.add "app/models", eager_load: true
-
17
paths.add "app/mailers", eager_load: true
-
17
paths.add "app/views"
-
-
17
paths.add "lib", load_path: true
-
17
paths.add "lib/assets", glob: "*"
-
17
paths.add "lib/tasks", glob: "**/*.rake"
-
-
17
paths.add "config"
-
17
paths.add "config/environments", glob: "#{Rails.env}.rb"
-
17
paths.add "config/initializers", glob: "**/*.rb"
-
17
paths.add "config/locales", glob: "*.{rb,yml}"
-
17
paths.add "config/routes.rb"
-
17
paths.add "config/routes", glob: "**/*.rb"
-
-
17
paths.add "db"
-
17
paths.add "db/migrate"
-
17
paths.add "db/seeds.rb"
-
-
17
paths.add "vendor", load_path: true
-
17
paths.add "vendor/assets", glob: "*"
-
-
17
paths
-
end
-
end
-
-
17
def root=(value)
-
33
@root = paths.path = Pathname.new(value).expand_path
-
end
-
-
17
def eager_load_paths
-
@eager_load_paths ||= paths.eager_load
-
end
-
-
17
def autoload_once_paths
-
@autoload_once_paths ||= paths.autoload_once
-
end
-
-
17
def autoload_paths
-
@autoload_paths ||= paths.autoload_paths
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
class Engine < Railtie
-
class Railties
-
include Enumerable
-
attr_reader :_all
-
-
def initialize
-
@_all ||= ::Rails::Railtie.subclasses.map(&:instance) +
-
::Rails::Engine.subclasses.map(&:instance)
-
end
-
-
def each(*args, &block)
-
_all.each(*args, &block)
-
end
-
-
def -(others)
-
_all - others
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "rails/generators"
-
1
require "rails/generators/rails/plugin/plugin_generator"
-
-
1
module Rails
-
1
class Engine
-
1
class Updater
-
1
class << self
-
1
def generator
-
@generator ||= Rails::Generators::PluginGenerator.new ["plugin"],
-
{ engine: true }, { destination_root: ENGINE_ROOT }
-
end
-
-
1
def run(action)
-
generator.send(action)
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
# Returns the version of the currently loaded Rails as a <tt>Gem::Version</tt>
-
def self.gem_version
-
Gem::Version.new VERSION::STRING
-
end
-
-
module VERSION
-
MAJOR = 6
-
MINOR = 1
-
TINY = 0
-
PRE = "alpha"
-
-
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
-
end
-
end
-
# frozen_string_literal: true
-
-
16
activesupport_path = File.expand_path("../../../activesupport/lib", __dir__)
-
16
$:.unshift(activesupport_path) if File.directory?(activesupport_path) && !$:.include?(activesupport_path)
-
-
16
require "thor/group"
-
16
require "rails/command"
-
-
16
require "active_support/core_ext/array/extract_options"
-
16
require "active_support/core_ext/enumerable"
-
16
require "active_support/core_ext/hash/deep_merge"
-
16
require "active_support/core_ext/module/attribute_accessors"
-
16
require "active_support/core_ext/string/indent"
-
16
require "active_support/core_ext/string/inflections"
-
-
16
module Rails
-
16
module Generators
-
16
include Rails::Command::Behavior
-
-
16
autoload :Actions, "rails/generators/actions"
-
16
autoload :ActiveModel, "rails/generators/active_model"
-
16
autoload :Base, "rails/generators/base"
-
16
autoload :Migration, "rails/generators/migration"
-
16
autoload :Database, "rails/generators/database"
-
16
autoload :AppName, "rails/generators/app_name"
-
16
autoload :NamedBase, "rails/generators/named_base"
-
16
autoload :ResourceHelpers, "rails/generators/resource_helpers"
-
16
autoload :TestCase, "rails/generators/test_case"
-
-
16
mattr_accessor :namespace
-
-
16
DEFAULT_ALIASES = {
-
rails: {
-
actions: "-a",
-
orm: "-o",
-
javascripts: "-j",
-
javascript_engine: "-je",
-
resource_controller: "-c",
-
scaffold_controller: "-c",
-
stylesheets: "-y",
-
stylesheet_engine: "-se",
-
scaffold_stylesheet: "-ss",
-
template_engine: "-e",
-
test_framework: "-t"
-
},
-
-
test_unit: {
-
fixture_replacement: "-r",
-
}
-
}
-
-
16
DEFAULT_OPTIONS = {
-
rails: {
-
api: false,
-
assets: true,
-
force_plural: false,
-
helper: true,
-
integration_tool: nil,
-
orm: false,
-
resource_controller: :controller,
-
resource_route: true,
-
scaffold_controller: :scaffold_controller,
-
stylesheets: true,
-
stylesheet_engine: :css,
-
scaffold_stylesheet: true,
-
system_tests: nil,
-
test_framework: nil,
-
template_engine: :erb
-
}
-
}
-
-
16
class << self
-
16
def configure!(config) #:nodoc:
-
16
api_only! if config.api_only
-
16
no_color! unless config.colorize_logging
-
16
aliases.deep_merge! config.aliases
-
16
options.deep_merge! config.options
-
16
fallbacks.merge! config.fallbacks
-
16
templates_path.concat config.templates
-
16
templates_path.uniq!
-
16
hide_namespaces(*config.hidden_namespaces)
-
16
after_generate_callbacks.replace config.after_generate_callbacks
-
end
-
-
16
def templates_path #:nodoc:
-
55
@templates_path ||= []
-
end
-
-
16
def aliases #:nodoc:
-
204
@aliases ||= DEFAULT_ALIASES.dup
-
end
-
-
16
def options #:nodoc:
-
292
@options ||= DEFAULT_OPTIONS.dup
-
end
-
-
16
def after_generate_callbacks # :nodoc:
-
16
@after_generate_callbacks ||= []
-
end
-
-
# Hold configured generators fallbacks. If a plugin developer wants a
-
# generator group to fallback to another group in case of missing generators,
-
# they can add a fallback.
-
#
-
# For example, shoulda is considered a test_framework and is an extension
-
# of test_unit. However, most part of shoulda generators are similar to
-
# test_unit ones.
-
#
-
# Shoulda then can tell generators to search for test_unit generators when
-
# some of them are not available by adding a fallback:
-
#
-
# Rails::Generators.fallbacks[:shoulda] = :test_unit
-
16
def fallbacks
-
16
@fallbacks ||= {}
-
end
-
-
# Configure generators for API only applications. It basically hides
-
# everything that is usually browser related, such as assets and session
-
# migration generators, and completely disable helpers and assets
-
# so generators such as scaffold won't create them.
-
16
def api_only!
-
hide_namespaces "assets", "helper", "css", "js"
-
-
options[:rails].merge!(
-
api: true,
-
assets: false,
-
helper: false,
-
template_engine: nil
-
)
-
-
options[:mailer] ||= {}
-
options[:mailer][:template_engine] ||= :erb
-
end
-
-
# Returns an array of generator namespaces that are hidden.
-
# Generator namespaces may be hidden for a variety of reasons.
-
# Some are aliased such as "rails:migration" and can be
-
# invoked with the shorter "migration", others are private to other generators
-
# such as "css:scaffold".
-
16
def hidden_namespaces
-
16
@hidden_namespaces ||= begin
-
16
orm = options[:rails][:orm]
-
16
test = options[:rails][:test_framework]
-
16
template = options[:rails][:template_engine]
-
16
css = options[:rails][:stylesheet_engine]
-
-
16
[
-
"rails",
-
"resource_route",
-
"#{orm}:migration",
-
"#{orm}:model",
-
"#{test}:controller",
-
"#{test}:helper",
-
"#{test}:integration",
-
"#{test}:system",
-
"#{test}:mailer",
-
"#{test}:model",
-
"#{test}:scaffold",
-
"#{test}:view",
-
"#{test}:job",
-
"#{template}:controller",
-
"#{template}:scaffold",
-
"#{template}:mailer",
-
"#{css}:scaffold",
-
"#{css}:assets",
-
"css:assets",
-
"css:scaffold",
-
"action_text:install",
-
"action_mailbox:install"
-
]
-
end
-
end
-
-
16
def hide_namespaces(*namespaces)
-
16
hidden_namespaces.concat(namespaces)
-
end
-
16
alias hide_namespace hide_namespaces
-
-
# Show help message with available generators.
-
16
def help(command = "generate")
-
puts "Usage: rails #{command} GENERATOR [args] [options]"
-
puts
-
puts "General options:"
-
puts " -h, [--help] # Print generator's options and usage"
-
puts " -p, [--pretend] # Run but do not make any changes"
-
puts " -f, [--force] # Overwrite files that already exist"
-
puts " -s, [--skip] # Skip files that already exist"
-
puts " -q, [--quiet] # Suppress status output"
-
puts
-
puts "Please choose a generator below."
-
puts
-
-
print_generators
-
end
-
-
16
def public_namespaces
-
lookup!
-
subclasses.map(&:namespace)
-
end
-
-
16
def print_generators
-
sorted_groups.each { |b, n| print_list(b, n) }
-
end
-
-
16
def sorted_groups
-
namespaces = public_namespaces
-
namespaces.sort!
-
-
groups = Hash.new { |h, k| h[k] = [] }
-
namespaces.each do |namespace|
-
base = namespace.split(":").first
-
groups[base] << namespace
-
end
-
-
rails = groups.delete("rails")
-
rails.map! { |n| n.delete_prefix("rails:") }
-
rails.delete("app")
-
rails.delete("plugin")
-
rails.delete("encrypted_secrets")
-
rails.delete("encrypted_file")
-
rails.delete("encryption_key_file")
-
rails.delete("master_key")
-
rails.delete("credentials")
-
rails.delete("db:system:change")
-
-
hidden_namespaces.each { |n| groups.delete(n.to_s) }
-
-
[[ "rails", rails ]] + groups.sort.to_a
-
end
-
-
# Rails finds namespaces similar to Thor, it only adds one rule:
-
#
-
# Generators names must end with "_generator.rb". This is required because Rails
-
# looks in load paths and loads the generator just before it's going to be used.
-
#
-
# find_by_namespace :webrat, :rails, :integration
-
#
-
# Will search for the following generators:
-
#
-
# "rails:webrat", "webrat:integration", "webrat"
-
#
-
# Notice that "rails:generators:webrat" could be loaded as well, what
-
# Rails looks for is the first and last parts of the namespace.
-
16
def find_by_namespace(name, base = nil, context = nil) #:nodoc:
-
lookups = []
-
lookups << "#{base}:#{name}" if base
-
lookups << "#{name}:#{context}" if context
-
-
unless base || context
-
unless name.to_s.include?(?:)
-
lookups << "#{name}:#{name}"
-
lookups << "rails:#{name}"
-
end
-
lookups << "#{name}"
-
end
-
-
lookup(lookups)
-
-
namespaces = subclasses.index_by(&:namespace)
-
lookups.each do |namespace|
-
klass = namespaces[namespace]
-
return klass if klass
-
end
-
-
invoke_fallbacks_for(name, base) || invoke_fallbacks_for(context, name)
-
end
-
-
# Receives a namespace, arguments and the behavior to invoke the generator.
-
# It's used as the default entry point for generate, destroy and update
-
# commands.
-
16
def invoke(namespace, args = ARGV, config = {})
-
names = namespace.to_s.split(":")
-
if klass = find_by_namespace(names.pop, names.any? && names.join(":"))
-
args << "--help" if args.empty? && klass.arguments.any?(&:required?)
-
klass.start(args, config)
-
run_after_generate_callback if config[:behavior] == :invoke
-
else
-
options = sorted_groups.flat_map(&:last)
-
suggestion = Rails::Command::Spellchecker.suggest(namespace.to_s, from: options)
-
suggestion_msg = "Maybe you meant #{suggestion.inspect}?" if suggestion
-
-
puts <<~MSG
-
Could not find generator '#{namespace}'. #{suggestion_msg}
-
Run `bin/rails generate --help` for more options.
-
MSG
-
end
-
end
-
-
16
def add_generated_file(file) # :nodoc:
-
(@@generated_files ||= []) << file
-
file
-
end
-
-
16
private
-
16
def print_list(base, namespaces) # :doc:
-
namespaces = namespaces.reject { |n| hidden_namespaces.include?(n) }
-
super
-
end
-
-
# Try fallbacks for the given base.
-
16
def invoke_fallbacks_for(name, base)
-
return nil unless base && fallbacks[base.to_sym]
-
invoked_fallbacks = []
-
-
Array(fallbacks[base.to_sym]).each do |fallback|
-
next if invoked_fallbacks.include?(fallback)
-
invoked_fallbacks << fallback
-
-
klass = find_by_namespace(name, fallback)
-
return klass if klass
-
end
-
-
nil
-
end
-
-
16
def command_type # :doc:
-
@command_type ||= "generator"
-
end
-
-
16
def lookup_paths # :doc:
-
@lookup_paths ||= %w( rails/generators generators )
-
end
-
-
16
def file_lookup_paths # :doc:
-
@file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_generator.rb" ]
-
end
-
-
16
def run_after_generate_callback
-
if defined?(@@generated_files) && !@@generated_files.empty?
-
@after_generate_callbacks.each do |callback|
-
callback.call(@@generated_files)
-
end
-
@@generated_files = []
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
require "shellwords"
-
16
require "active_support/core_ext/kernel/reporting"
-
16
require "active_support/core_ext/string/strip"
-
-
16
module Rails
-
16
module Generators
-
16
module Actions
-
16
def initialize(*) # :nodoc:
-
super
-
@indentation = 0
-
end
-
-
# Adds an entry into +Gemfile+ for the supplied gem.
-
#
-
# gem "rspec", group: :test
-
# gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/"
-
# gem "rails", "3.0", git: "https://github.com/rails/rails"
-
# gem "RedCloth", ">= 4.1.0", "< 4.2.0"
-
16
def gem(*args)
-
options = args.extract_options!
-
name, *versions = args
-
-
# Set the message to be shown in logs. Uses the git repo if one is given,
-
# otherwise use name (version).
-
parts, message = [ quote(name) ], name.dup
-
-
if versions = versions.any? ? versions : options.delete(:version)
-
_versions = Array(versions)
-
_versions.each do |version|
-
parts << quote(version)
-
end
-
message << " (#{_versions.join(", ")})"
-
end
-
message = options[:git] if options[:git]
-
-
log :gemfile, message
-
-
parts << quote(options) unless options.empty?
-
-
in_root do
-
str = "gem #{parts.join(", ")}"
-
str = indentation + str
-
append_file_with_newline "Gemfile", str, verbose: false
-
end
-
end
-
-
# Wraps gem entries inside a group.
-
#
-
# gem_group :development, :test do
-
# gem "rspec-rails"
-
# end
-
16
def gem_group(*names, &block)
-
options = names.extract_options!
-
str = names.map(&:inspect)
-
str << quote(options) unless options.empty?
-
str = str.join(", ")
-
log :gemfile, "group #{str}"
-
-
in_root do
-
append_file_with_newline "Gemfile", "\ngroup #{str} do", force: true
-
with_indentation(&block)
-
append_file_with_newline "Gemfile", "end", force: true
-
end
-
end
-
-
16
def github(repo, options = {}, &block)
-
str = [quote(repo)]
-
str << quote(options) unless options.empty?
-
str = str.join(", ")
-
log :github, "github #{str}"
-
-
in_root do
-
if @indentation.zero?
-
append_file_with_newline "Gemfile", "\ngithub #{str} do", force: true
-
else
-
append_file_with_newline "Gemfile", "#{indentation}github #{str} do", force: true
-
end
-
with_indentation(&block)
-
append_file_with_newline "Gemfile", "#{indentation}end", force: true
-
end
-
end
-
-
# Add the given source to +Gemfile+
-
#
-
# If block is given, gem entries in block are wrapped into the source group.
-
#
-
# add_source "http://gems.github.com/"
-
#
-
# add_source "http://gems.github.com/" do
-
# gem "rspec-rails"
-
# end
-
16
def add_source(source, options = {}, &block)
-
log :source, source
-
-
in_root do
-
if block
-
append_file_with_newline "Gemfile", "\nsource #{quote(source)} do", force: true
-
with_indentation(&block)
-
append_file_with_newline "Gemfile", "end", force: true
-
else
-
prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false
-
end
-
end
-
end
-
-
# Adds a line inside the Application class for <tt>config/application.rb</tt>.
-
#
-
# If options <tt>:env</tt> is specified, the line is appended to the corresponding
-
# file in <tt>config/environments</tt>.
-
#
-
# environment do
-
# "config.action_controller.asset_host = 'cdn.provider.com'"
-
# end
-
#
-
# environment(nil, env: "development") do
-
# "config.action_controller.asset_host = 'localhost:3000'"
-
# end
-
16
def environment(data = nil, options = {})
-
sentinel = "class Application < Rails::Application\n"
-
env_file_sentinel = "Rails.application.configure do\n"
-
data ||= yield if block_given?
-
-
in_root do
-
if options[:env].nil?
-
inject_into_file "config/application.rb", optimize_indentation(data, 4), after: sentinel, verbose: false
-
else
-
Array(options[:env]).each do |env|
-
inject_into_file "config/environments/#{env}.rb", optimize_indentation(data, 2), after: env_file_sentinel, verbose: false
-
end
-
end
-
end
-
end
-
16
alias :application :environment
-
-
# Run a command in git.
-
#
-
# git :init
-
# git add: "this.file that.rb"
-
# git add: "onefile.rb", rm: "badfile.cxx"
-
16
def git(commands = {})
-
if commands.is_a?(Symbol)
-
run "git #{commands}"
-
else
-
commands.each do |cmd, options|
-
run "git #{cmd} #{options}"
-
end
-
end
-
end
-
-
# Create a new file in the <tt>vendor/</tt> directory. Code can be specified
-
# in a block or a data string can be given.
-
#
-
# vendor("sekrit.rb") do
-
# sekrit_salt = "#{Time.now}--#{3.years.ago}--#{rand}--"
-
# "salt = '#{sekrit_salt}'"
-
# end
-
#
-
# vendor("foreign.rb", "# Foreign code is fun")
-
16
def vendor(filename, data = nil)
-
log :vendor, filename
-
data ||= yield if block_given?
-
create_file("vendor/#{filename}", optimize_indentation(data), verbose: false)
-
end
-
-
# Create a new file in the <tt>lib/</tt> directory. Code can be specified
-
# in a block or a data string can be given.
-
#
-
# lib("crypto.rb") do
-
# "crypted_special_value = '#{rand}--#{Time.now}--#{rand(1337)}--'"
-
# end
-
#
-
# lib("foreign.rb", "# Foreign code is fun")
-
16
def lib(filename, data = nil)
-
log :lib, filename
-
data ||= yield if block_given?
-
create_file("lib/#{filename}", optimize_indentation(data), verbose: false)
-
end
-
-
# Create a new +Rakefile+ with the provided code (either in a block or a string).
-
#
-
# rakefile("bootstrap.rake") do
-
# project = ask("What is the UNIX name of your project?")
-
#
-
# <<-TASK
-
# namespace :#{project} do
-
# task :bootstrap do
-
# puts "I like boots!"
-
# end
-
# end
-
# TASK
-
# end
-
#
-
# rakefile('seed.rake', 'puts "Planting seeds"')
-
16
def rakefile(filename, data = nil)
-
log :rakefile, filename
-
data ||= yield if block_given?
-
create_file("lib/tasks/#{filename}", optimize_indentation(data), verbose: false)
-
end
-
-
# Create a new initializer with the provided code (either in a block or a string).
-
#
-
# initializer("globals.rb") do
-
# data = ""
-
#
-
# ['MY_WORK', 'ADMINS', 'BEST_COMPANY_EVAR'].each do |const|
-
# data << "#{const} = :entp\n"
-
# end
-
#
-
# data
-
# end
-
#
-
# initializer("api.rb", "API_KEY = '123456'")
-
16
def initializer(filename, data = nil)
-
log :initializer, filename
-
data ||= yield if block_given?
-
create_file("config/initializers/#{filename}", optimize_indentation(data), verbose: false)
-
end
-
-
# Generate something using a generator from Rails or a plugin.
-
# The second parameter is the argument string that is passed to
-
# the generator or an Array that is joined.
-
#
-
# generate(:authenticated, "user session")
-
16
def generate(what, *args)
-
log :generate, what
-
-
options = args.extract_options!
-
options[:abort_on_failure] = !options[:inline]
-
-
rails_command "generate #{what} #{args.join(" ")}", options
-
end
-
-
# Runs the supplied rake task (invoked with 'rake ...')
-
#
-
# rake("db:migrate")
-
# rake("db:migrate", env: "production")
-
# rake("gems:install", sudo: true)
-
# rake("gems:install", capture: true)
-
16
def rake(command, options = {})
-
execute_command :rake, command, options
-
end
-
-
# Runs the supplied rake task (invoked with 'rails ...')
-
#
-
# rails_command("db:migrate")
-
# rails_command("db:migrate", env: "production")
-
# rails_command("gems:install", sudo: true)
-
# rails_command("gems:install", capture: true)
-
16
def rails_command(command, options = {})
-
if options[:inline]
-
log :rails, command
-
command, *args = Shellwords.split(command)
-
in_root do
-
silence_warnings do
-
::Rails::Command.invoke(command, args, **options)
-
end
-
end
-
else
-
execute_command :rails, command, options
-
end
-
end
-
-
# Make an entry in Rails routing file <tt>config/routes.rb</tt>
-
#
-
# route "root 'welcome#index'"
-
# route "root 'admin#index'", namespace: :admin
-
16
def route(routing_code, namespace: nil)
-
routing_code = Array(namespace).reverse.reduce(routing_code) do |code, ns|
-
"namespace :#{ns} do\n#{indent(code, 2)}\nend"
-
end
-
-
log :route, routing_code
-
sentinel = /\.routes\.draw do\s*\n/m
-
-
in_root do
-
inject_into_file "config/routes.rb", optimize_indentation(routing_code, 2), after: sentinel, verbose: false, force: false
-
end
-
end
-
-
# Reads the given file at the source root and prints it in the console.
-
#
-
# readme "README"
-
16
def readme(path)
-
log File.read(find_in_source_paths(path))
-
end
-
-
16
private
-
# Define log for backwards compatibility. If just one argument is sent,
-
# invoke say, otherwise invoke say_status. Differently from say and
-
# similarly to say_status, this method respects the quiet? option given.
-
16
def log(*args) # :doc:
-
if args.size == 1
-
say args.first.to_s unless options.quiet?
-
else
-
args << (behavior == :invoke ? :green : :red)
-
say_status(*args)
-
end
-
end
-
-
# Runs the supplied command using either "rake ..." or "rails ..."
-
# based on the executor parameter provided.
-
16
def execute_command(executor, command, options = {}) # :doc:
-
log executor, command
-
sudo = options[:sudo] && !Gem.win_platform? ? "sudo " : ""
-
config = {
-
env: { "RAILS_ENV" => (options[:env] || ENV["RAILS_ENV"] || "development") },
-
verbose: false,
-
capture: options[:capture],
-
abort_on_failure: options[:abort_on_failure],
-
}
-
-
in_root { run("#{sudo}#{extify(executor)} #{command}", config) }
-
end
-
-
# Add an extension to the given name based on the platform.
-
16
def extify(name) # :doc:
-
if Gem.win_platform?
-
"#{name}.bat"
-
else
-
name
-
end
-
end
-
-
# Surround string with single quotes if there is no quotes.
-
# Otherwise fall back to double quotes
-
16
def quote(value) # :doc:
-
if value.respond_to? :each_pair
-
return value.map do |k, v|
-
"#{k}: #{quote(v)}"
-
end.join(", ")
-
end
-
return value.inspect unless value.is_a? String
-
-
if value.include?("'")
-
value.inspect
-
else
-
"'#{value}'"
-
end
-
end
-
-
# Returns optimized string with indentation
-
16
def optimize_indentation(value, amount = 0) # :doc:
-
return "#{value}\n" unless value.is_a?(String)
-
"#{value.strip_heredoc.indent(amount).chomp}\n"
-
end
-
-
# Indent the +Gemfile+ to the depth of @indentation
-
16
def indentation # :doc:
-
" " * @indentation
-
end
-
-
# Manage +Gemfile+ indentation for a DSL action block
-
16
def with_indentation(&block) # :doc:
-
@indentation += 1
-
instance_eval(&block)
-
ensure
-
@indentation -= 1
-
end
-
-
# Append string to a file with a newline if necessary
-
16
def append_file_with_newline(path, str, options = {})
-
gsub_file path, /\n?\z/, options do |match|
-
match.end_with?("\n") ? "" : "\n#{str}\n"
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "fileutils"
-
1
require "thor/actions"
-
-
1
module Rails
-
1
module Generators
-
1
module Actions
-
1
class CreateMigration < Thor::Actions::CreateFile #:nodoc:
-
1
def migration_dir
-
File.dirname(@destination)
-
end
-
-
1
def migration_file_name
-
@base.migration_file_name
-
end
-
-
1
def identical?
-
exists? && File.binread(existing_migration) == render
-
end
-
-
1
def invoke!
-
invoked_file = super
-
File.exist?(@destination) ? invoked_file : relative_existing_migration
-
end
-
-
1
def revoke!
-
say_destination = exists? ? relative_existing_migration : relative_destination
-
say_status :remove, :red, say_destination
-
return unless exists?
-
::FileUtils.rm_rf(existing_migration) unless pretend?
-
existing_migration
-
end
-
-
1
def relative_existing_migration
-
base.relative_to_original_destination_root(existing_migration)
-
end
-
-
1
def existing_migration
-
@existing_migration ||= begin
-
@base.class.migration_exists?(migration_dir, migration_file_name) ||
-
File.exist?(@destination) && @destination
-
end
-
end
-
1
alias :exists? :existing_migration
-
-
1
private
-
1
def on_conflict_behavior # :doc:
-
options = base.options.merge(config)
-
if identical?
-
say_status :identical, :blue, relative_existing_migration
-
elsif options[:force]
-
say_status :remove, :green, relative_existing_migration
-
say_status :create, :green
-
unless pretend?
-
::FileUtils.rm_rf(existing_migration)
-
yield
-
end
-
elsif options[:skip]
-
say_status :skip, :yellow
-
else
-
say_status :conflict, :red
-
raise Error, "Another migration is already named #{migration_file_name}: " \
-
"#{existing_migration}. Use --force to replace this migration " \
-
"or --skip to ignore conflicted file."
-
end
-
end
-
-
1
def say_status(status, color, message = relative_destination) # :doc:
-
base.shell.say_status(status, message, color) if config[:verbose]
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
module Rails
-
3
module Generators
-
# ActiveModel is a class to be implemented by each ORM to allow Rails to
-
# generate customized controller code.
-
#
-
# The API has the same methods as ActiveRecord, but each method returns a
-
# string that matches the ORM API.
-
#
-
# For example:
-
#
-
# ActiveRecord::Generators::ActiveModel.find(Foo, "params[:id]")
-
# # => "Foo.find(params[:id])"
-
#
-
# DataMapper::Generators::ActiveModel.find(Foo, "params[:id]")
-
# # => "Foo.get(params[:id])"
-
#
-
# On initialization, the ActiveModel accepts the instance name that will
-
# receive the calls:
-
#
-
# builder = ActiveRecord::Generators::ActiveModel.new "@foo"
-
# builder.save # => "@foo.save"
-
#
-
# The only exception in ActiveModel for ActiveRecord is the use of self.build
-
# instead of self.new.
-
#
-
3
class ActiveModel
-
3
attr_reader :name
-
-
3
def initialize(name)
-
@name = name
-
end
-
-
# GET index
-
3
def self.all(klass)
-
"#{klass}.all"
-
end
-
-
# GET show
-
# GET edit
-
# PATCH/PUT update
-
# DELETE destroy
-
3
def self.find(klass, params = nil)
-
"#{klass}.find(#{params})"
-
end
-
-
# GET new
-
# POST create
-
3
def self.build(klass, params = nil)
-
if params
-
"#{klass}.new(#{params})"
-
else
-
"#{klass}.new"
-
end
-
end
-
-
# POST create
-
3
def save
-
"#{name}.save"
-
end
-
-
# PATCH/PUT update
-
3
def update(params = nil)
-
"#{name}.update(#{params})"
-
end
-
-
# POST create
-
# PATCH/PUT update
-
3
def errors
-
"#{name}.errors"
-
end
-
-
# DELETE destroy
-
3
def destroy
-
"#{name}.destroy"
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
require "fileutils"
-
3
require "digest/md5"
-
3
require "rails/version" unless defined?(Rails::VERSION)
-
3
require "open-uri"
-
3
require "uri"
-
3
require "rails/generators"
-
3
require "active_support/core_ext/array/extract_options"
-
-
3
module Rails
-
3
module Generators
-
3
class AppBase < Base # :nodoc:
-
3
include Database
-
3
include AppName
-
-
3
attr_accessor :rails_template
-
3
add_shebang_option!
-
-
3
argument :app_path, type: :string
-
-
3
def self.strict_args_position
-
false
-
end
-
-
3
def self.add_shared_options_for(name)
-
4
class_option :template, type: :string, aliases: "-m",
-
desc: "Path to some #{name} template (can be a filesystem path or URL)"
-
-
4
class_option :database, type: :string, aliases: "-d", default: "sqlite3",
-
desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
-
-
4
class_option :skip_gemfile, type: :boolean, default: false,
-
desc: "Don't create a Gemfile"
-
-
4
class_option :skip_git, type: :boolean, aliases: "-G", default: false,
-
desc: "Skip .gitignore file"
-
-
4
class_option :skip_keeps, type: :boolean, default: false,
-
desc: "Skip source control .keep files"
-
-
4
class_option :skip_action_mailer, type: :boolean, aliases: "-M",
-
default: false,
-
desc: "Skip Action Mailer files"
-
-
4
class_option :skip_action_mailbox, type: :boolean, default: false,
-
desc: "Skip Action Mailbox gem"
-
-
4
class_option :skip_action_text, type: :boolean, default: false,
-
desc: "Skip Action Text gem"
-
-
4
class_option :skip_active_record, type: :boolean, aliases: "-O", default: false,
-
desc: "Skip Active Record files"
-
-
4
class_option :skip_active_job, type: :boolean, default: false,
-
desc: "Skip Active Job"
-
-
4
class_option :skip_active_storage, type: :boolean, default: false,
-
desc: "Skip Active Storage files"
-
-
4
class_option :skip_puma, type: :boolean, aliases: "-P", default: false,
-
desc: "Skip Puma related files"
-
-
4
class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false,
-
desc: "Skip Action Cable files"
-
-
4
class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false,
-
desc: "Skip Sprockets files"
-
-
4
class_option :skip_spring, type: :boolean, default: false,
-
desc: "Don't install Spring application preloader"
-
-
4
class_option :skip_listen, type: :boolean, default: false,
-
desc: "Don't generate configuration that depends on the listen gem"
-
-
4
class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin",
-
desc: "Skip JavaScript files"
-
-
4
class_option :skip_turbolinks, type: :boolean, default: false,
-
desc: "Skip turbolinks gem"
-
-
4
class_option :skip_jbuilder, type: :boolean, default: false,
-
desc: "Skip jbuilder gem"
-
-
4
class_option :skip_test, type: :boolean, aliases: "-T", default: false,
-
desc: "Skip test files"
-
-
4
class_option :skip_system_test, type: :boolean, default: false,
-
desc: "Skip system test files"
-
-
4
class_option :skip_bootsnap, type: :boolean, default: false,
-
desc: "Skip bootsnap gem"
-
-
4
class_option :dev, type: :boolean, default: false,
-
desc: "Set up the #{name} with Gemfile pointing to your Rails checkout"
-
-
4
class_option :edge, type: :boolean, default: false,
-
desc: "Set up the #{name} with Gemfile pointing to Rails repository"
-
-
4
class_option :master, type: :boolean, default: false,
-
desc: "Set up the #{name} with Gemfile pointing to Rails repository master branch"
-
-
4
class_option :rc, type: :string, default: nil,
-
desc: "Path to file containing extra configuration options for rails command"
-
-
4
class_option :no_rc, type: :boolean, default: false,
-
desc: "Skip loading of extra configuration options from .railsrc file"
-
-
4
class_option :help, type: :boolean, aliases: "-h", group: :rails,
-
desc: "Show this help message and quit"
-
end
-
-
3
def initialize(*args)
-
@gem_filter = lambda { |gem| true }
-
@extra_entries = []
-
super
-
end
-
-
3
private
-
3
def gemfile_entry(name, *args) # :doc:
-
options = args.extract_options!
-
version = args.first
-
github = options[:github]
-
path = options[:path]
-
-
if github
-
@extra_entries << GemfileEntry.github(name, github)
-
elsif path
-
@extra_entries << GemfileEntry.path(name, path)
-
else
-
@extra_entries << GemfileEntry.version(name, version)
-
end
-
self
-
end
-
-
3
def gemfile_entries # :doc:
-
[rails_gemfile_entry,
-
database_gemfile_entry,
-
web_server_gemfile_entry,
-
assets_gemfile_entry,
-
webpacker_gemfile_entry,
-
javascript_gemfile_entry,
-
jbuilder_gemfile_entry,
-
psych_gemfile_entry,
-
cable_gemfile_entry,
-
@extra_entries].flatten.find_all(&@gem_filter)
-
end
-
-
3
def add_gem_entry_filter # :doc:
-
@gem_filter = lambda { |next_filter, entry|
-
yield(entry) && next_filter.call(entry)
-
}.curry[@gem_filter]
-
end
-
-
3
def builder # :doc:
-
@builder ||= begin
-
builder_class = get_builder_class
-
builder_class.include(ActionMethods)
-
builder_class.new(self)
-
end
-
end
-
-
3
def build(meth, *args) # :doc:
-
builder.send(meth, *args) if builder.respond_to?(meth)
-
end
-
-
3
def create_root # :doc:
-
valid_const?
-
-
empty_directory "."
-
FileUtils.cd(destination_root) unless options[:pretend]
-
end
-
-
3
def apply_rails_template # :doc:
-
apply rails_template if rails_template
-
rescue Thor::Error, LoadError, Errno::ENOENT => e
-
raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}"
-
end
-
-
3
def set_default_accessors! # :doc:
-
self.destination_root = File.expand_path(app_path, destination_root)
-
self.rails_template = \
-
case options[:template]
-
when /^https?:\/\//
-
options[:template]
-
when String
-
File.expand_path(options[:template], Dir.pwd)
-
else
-
options[:template]
-
end
-
end
-
-
3
def database_gemfile_entry # :doc:
-
return [] if options[:skip_active_record]
-
gem_name, gem_version = gem_for_database
-
GemfileEntry.version gem_name, gem_version,
-
"Use #{options[:database]} as the database for Active Record"
-
end
-
-
3
def web_server_gemfile_entry # :doc:
-
return [] if options[:skip_puma]
-
comment = "Use Puma as the app server"
-
GemfileEntry.new("puma", "~> 4.1", comment)
-
end
-
-
3
def include_all_railties? # :doc:
-
[
-
options.values_at(
-
:skip_active_record,
-
:skip_action_mailer,
-
:skip_test,
-
:skip_sprockets,
-
:skip_action_cable,
-
:skip_active_job
-
),
-
skip_active_storage?,
-
skip_action_mailbox?,
-
skip_action_text?
-
].flatten.none?
-
end
-
-
3
def comment_if(value) # :doc:
-
question = "#{value}?"
-
-
comment =
-
if respond_to?(question, true)
-
send(question)
-
else
-
options[value]
-
end
-
-
comment ? "# " : ""
-
end
-
-
3
def keeps? # :doc:
-
!options[:skip_keeps]
-
end
-
-
3
def sqlite3? # :doc:
-
!options[:skip_active_record] && options[:database] == "sqlite3"
-
end
-
-
3
def skip_active_storage? # :doc:
-
options[:skip_active_storage] || options[:skip_active_record]
-
end
-
-
3
def skip_action_mailbox? # :doc:
-
options[:skip_action_mailbox] || skip_active_storage?
-
end
-
-
3
def skip_action_text? # :doc:
-
options[:skip_action_text] || skip_active_storage?
-
end
-
-
3
def skip_dev_gems? # :doc:
-
options[:skip_dev_gems]
-
end
-
-
3
class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out)
-
3
def initialize(name, version, comment, options = {}, commented_out = false)
-
super
-
end
-
-
3
def self.github(name, github, branch = nil, comment = nil)
-
if branch
-
new(name, nil, comment, github: github, branch: branch)
-
else
-
new(name, nil, comment, github: github)
-
end
-
end
-
-
3
def self.version(name, version, comment = nil)
-
new(name, version, comment)
-
end
-
-
3
def self.path(name, path, comment = nil)
-
new(name, nil, comment, path: path)
-
end
-
-
3
def version
-
version = super
-
-
if version.is_a?(Array)
-
version.join("', '")
-
else
-
version
-
end
-
end
-
end
-
-
3
def rails_gemfile_entry
-
if options.dev?
-
[
-
GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH)
-
]
-
elsif options.edge?
-
[
-
GemfileEntry.github("rails", "rails/rails")
-
]
-
elsif options.master?
-
[
-
GemfileEntry.github("rails", "rails/rails", "master")
-
]
-
else
-
[GemfileEntry.version("rails",
-
rails_version_specifier,
-
"Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")]
-
end
-
end
-
-
3
def rails_version_specifier(gem_version = Rails.gem_version)
-
if gem_version.segments.size == 3 || gem_version.release.segments.size == 3
-
# ~> 1.2.3
-
# ~> 1.2.3.pre4
-
"~> #{gem_version}"
-
else
-
# ~> 1.2.3, >= 1.2.3.4
-
# ~> 1.2.3, >= 1.2.3.4.pre5
-
patch = gem_version.segments[0, 3].join(".")
-
["~> #{patch}", ">= #{gem_version}"]
-
end
-
end
-
-
3
def assets_gemfile_entry
-
return [] if options[:skip_sprockets]
-
-
GemfileEntry.version("sass-rails", ">= 6", "Use SCSS for stylesheets")
-
end
-
-
3
def webpacker_gemfile_entry
-
return [] if options[:skip_javascript]
-
-
if options.dev? || options.edge? || options.master?
-
GemfileEntry.github "webpacker", "rails/webpacker", nil, "Use development version of Webpacker"
-
else
-
GemfileEntry.version "webpacker", "~> 5.0", "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker"
-
end
-
end
-
-
3
def jbuilder_gemfile_entry
-
return [] if options[:skip_jbuilder]
-
comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder"
-
GemfileEntry.new "jbuilder", "~> 2.7", comment, {}, options[:api]
-
end
-
-
3
def javascript_gemfile_entry
-
if options[:skip_javascript] || options[:skip_turbolinks]
-
[]
-
else
-
[ GemfileEntry.version("turbolinks", "~> 5",
-
"Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") ]
-
end
-
end
-
-
3
def psych_gemfile_entry
-
return [] unless defined?(Rubinius)
-
-
comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \
-
"data can be read safely from different rubies (see http://git.io/uuLVag)"
-
GemfileEntry.new("psych", "~> 2.0", comment, platforms: :rbx)
-
end
-
-
3
def cable_gemfile_entry
-
return [] if options[:skip_action_cable]
-
comment = "Use Redis adapter to run Action Cable in production"
-
gems = []
-
gems << GemfileEntry.new("redis", "~> 4.0", comment, {}, true)
-
gems
-
end
-
-
3
def bundle_command(command, env = {})
-
say_status :run, "bundle #{command}"
-
-
# We are going to shell out rather than invoking Bundler::CLI.new(command)
-
# because `rails new` loads the Thor gem and on the other hand bundler uses
-
# its own vendored Thor, which could be a different version. Running both
-
# things in the same process is a recipe for a night with paracetamol.
-
#
-
# Thanks to James Tucker for the Gem tricks involved in this call.
-
_bundle_command = Gem.bin_path("bundler", "bundle")
-
-
require "bundler"
-
Bundler.with_original_env do
-
exec_bundle_command(_bundle_command, command, env)
-
end
-
end
-
-
3
def exec_bundle_command(bundle_command, command, env)
-
full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}]
-
if options[:quiet]
-
system(env, full_command, out: File::NULL)
-
else
-
system(env, full_command)
-
end
-
end
-
-
3
def bundle_install?
-
!(options[:skip_gemfile] || options[:skip_bundle] || options[:pretend])
-
end
-
-
3
def spring_install?
-
!options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin")
-
end
-
-
3
def webpack_install?
-
!(options[:skip_javascript] || options[:skip_webpack_install])
-
end
-
-
3
def depends_on_system_test?
-
!(options[:skip_system_test] || options[:skip_test] || options[:api])
-
end
-
-
3
def depend_on_listen?
-
!options[:skip_listen] && os_supports_listen_out_of_the_box?
-
end
-
-
3
def depend_on_bootsnap?
-
!options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION)
-
end
-
-
3
def os_supports_listen_out_of_the_box?
-
/darwin|linux/.match?(RbConfig::CONFIG["host_os"])
-
end
-
-
3
def run_bundle
-
bundle_command("install", "BUNDLE_IGNORE_MESSAGES" => "1") if bundle_install?
-
end
-
-
3
def run_webpack
-
if webpack_install?
-
rails_command "webpacker:install"
-
if options[:webpack] && options[:webpack] != "webpack"
-
rails_command "webpacker:install:#{options[:webpack]}"
-
end
-
end
-
end
-
-
3
def generate_bundler_binstub
-
if bundle_install?
-
bundle_command("binstubs bundler")
-
end
-
end
-
-
3
def generate_spring_binstub
-
if bundle_install? && spring_install?
-
bundle_command("exec spring binstub")
-
end
-
end
-
-
3
def empty_directory_with_keep_file(destination, config = {})
-
empty_directory(destination, config)
-
keep_file(destination)
-
end
-
-
3
def keep_file(destination)
-
create_file("#{destination}/.keep") if keeps?
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
module Rails
-
3
module Generators
-
3
module AppName # :nodoc:
-
3
RESERVED_NAMES = %w(application destroy plugin runner test)
-
-
3
private
-
3
def app_name
-
@app_name ||= original_app_name.tr('\\', "").tr("-. ", "_")
-
end
-
-
3
def original_app_name
-
@original_app_name ||= defined_app_const_base? ? defined_app_name : File.basename(destination_root)
-
end
-
-
3
def defined_app_name
-
defined_app_const_base.underscore
-
end
-
-
3
def defined_app_const_base
-
Rails.respond_to?(:application) && defined?(Rails::Application) &&
-
Rails.application.is_a?(Rails::Application) && Rails.application.class.name.chomp("::Application")
-
end
-
-
3
alias :defined_app_const_base? :defined_app_const_base
-
-
3
def app_const_base
-
@app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, "_").squeeze("_").camelize
-
end
-
3
alias :camelized :app_const_base
-
-
3
def app_const
-
@app_const ||= "#{app_const_base}::Application"
-
end
-
-
3
def valid_const?
-
if /^\d/.match?(app_const)
-
raise Error, "Invalid application name #{original_app_name}. Please give a name which does not start with numbers."
-
elsif RESERVED_NAMES.include?(original_app_name)
-
raise Error, "Invalid application name #{original_app_name}. Please give a " \
-
"name which does not match one of the reserved rails " \
-
"words: #{RESERVED_NAMES.join(", ")}"
-
elsif Object.const_defined?(app_const_base)
-
raise Error, "Invalid application name #{original_app_name}, constant #{app_const_base} is already in use. Please choose another application name."
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
begin
-
16
require "thor/group"
-
rescue LoadError
-
puts "Thor is not available.\nIf you ran this command from a git checkout " \
-
"of Rails, please make sure thor is installed,\nand run this command " \
-
"as `ruby #{$0} #{(ARGV | ['--dev']).join(" ")}`"
-
exit
-
end
-
-
16
module Rails
-
16
module Generators
-
16
class Error < Thor::Error # :nodoc:
-
end
-
-
16
class Base < Thor::Group
-
16
include Thor::Actions
-
16
include Rails::Generators::Actions
-
-
16
class_option :skip_namespace, type: :boolean, default: false,
-
desc: "Skip namespace (affects only isolated engines)"
-
16
class_option :skip_collision_check, type: :boolean, default: false,
-
desc: "Skip collision check"
-
-
16
add_runtime_options!
-
16
strict_args_position!
-
-
16
def self.exit_on_failure? # :nodoc:
-
false
-
end
-
-
# Returns the source root for this generator using default_source_root as default.
-
16
def self.source_root(path = nil)
-
42
@_source_root = path if path
-
42
@_source_root ||= default_source_root
-
end
-
-
# Tries to get the description from a USAGE file one folder above the source
-
# root otherwise uses a default description.
-
16
def self.desc(description = nil)
-
return super if description
-
-
@desc ||= if usage_path
-
ERB.new(File.read(usage_path)).result(binding)
-
else
-
"Description:\n Create #{base_name.humanize.downcase} files for #{generator_name} generator."
-
end
-
end
-
-
# Convenience method to get the namespace from the class name. It's the
-
# same as Thor default except that the Generator at the end of the class
-
# is removed.
-
16
def self.namespace(name = nil)
-
return super if name
-
@namespace ||= super.delete_suffix("_generator").sub(/:generators:/, ":")
-
end
-
-
# Convenience method to hide this generator from the available ones when
-
# running rails generator command.
-
16
def self.hide!
-
Rails::Generators.hide_namespace(namespace)
-
end
-
-
# Invoke a generator based on the value supplied by the user to the
-
# given option named "name". A class option is created when this method
-
# is invoked and you can set a hash to customize it.
-
#
-
# ==== Examples
-
#
-
# module Rails::Generators
-
# class ControllerGenerator < Base
-
# hook_for :test_framework, aliases: "-t"
-
# end
-
# end
-
#
-
# The example above will create a test framework option and will invoke
-
# a generator based on the user supplied value.
-
#
-
# For example, if the user invoke the controller generator as:
-
#
-
# bin/rails generate controller Account --test-framework=test_unit
-
#
-
# The controller generator will then try to invoke the following generators:
-
#
-
# "rails:test_unit", "test_unit:controller", "test_unit"
-
#
-
# Notice that "rails:generators:test_unit" could be loaded as well, what
-
# Rails looks for is the first and last parts of the namespace. This is what
-
# allows any test framework to hook into Rails as long as it provides any
-
# of the hooks above.
-
#
-
# ==== Options
-
#
-
# The first and last part used to find the generator to be invoked are
-
# guessed based on class invokes hook_for, as noticed in the example above.
-
# This can be customized with two options: :in and :as.
-
#
-
# Let's suppose you are creating a generator that needs to invoke the
-
# controller generator from test unit. Your first attempt is:
-
#
-
# class AwesomeGenerator < Rails::Generators::Base
-
# hook_for :test_framework
-
# end
-
#
-
# The lookup in this case for test_unit as input is:
-
#
-
# "test_unit:awesome", "test_unit"
-
#
-
# Which is not the desired lookup. You can change it by providing the
-
# :as option:
-
#
-
# class AwesomeGenerator < Rails::Generators::Base
-
# hook_for :test_framework, as: :controller
-
# end
-
#
-
# And now it will look up at:
-
#
-
# "test_unit:controller", "test_unit"
-
#
-
# Similarly, if you want it to also look up in the rails namespace, you
-
# just need to provide the :in value:
-
#
-
# class AwesomeGenerator < Rails::Generators::Base
-
# hook_for :test_framework, in: :rails, as: :controller
-
# end
-
#
-
# And the lookup is exactly the same as previously:
-
#
-
# "rails:test_unit", "test_unit:controller", "test_unit"
-
#
-
# ==== Switches
-
#
-
# All hooks come with switches for user interface. If you do not want
-
# to use any test framework, you can do:
-
#
-
# bin/rails generate controller Account --skip-test-framework
-
#
-
# Or similarly:
-
#
-
# bin/rails generate controller Account --no-test-framework
-
#
-
# ==== Boolean hooks
-
#
-
# In some cases, you may want to provide a boolean hook. For example, webrat
-
# developers might want to have webrat available on controller generator.
-
# This can be achieved as:
-
#
-
# Rails::Generators::ControllerGenerator.hook_for :webrat, type: :boolean
-
#
-
# Then, if you want webrat to be invoked, just supply:
-
#
-
# bin/rails generate controller Account --webrat
-
#
-
# The hooks lookup is similar as above:
-
#
-
# "rails:generators:webrat", "webrat:generators:controller", "webrat"
-
#
-
# ==== Custom invocations
-
#
-
# You can also supply a block to hook_for to customize how the hook is
-
# going to be invoked. The block receives two arguments, an instance
-
# of the current class and the class to be invoked.
-
#
-
# For example, in the resource generator, the controller should be invoked
-
# with a pluralized class name. But by default it is invoked with the same
-
# name as the resource generator, which is singular. To change this, we
-
# can give a block to customize how the controller can be invoked.
-
#
-
# hook_for :resource_controller do |instance, controller|
-
# instance.invoke controller, [ instance.name.pluralize ]
-
# end
-
#
-
16
def self.hook_for(*names, &block)
-
23
options = names.extract_options!
-
23
in_base = options.delete(:in) || base_name
-
23
as_hook = options.delete(:as) || generator_name
-
-
23
names.each do |name|
-
31
unless class_options.key?(name)
-
24
defaults = if options[:type] == :boolean
-
{}
-
24
elsif [true, false].include?(default_value_for_option(name, options))
-
2
{ banner: "" }
-
else
-
22
{ desc: "#{name.to_s.humanize} to be invoked", banner: "NAME" }
-
end
-
-
24
class_option(name, defaults.merge!(options))
-
end
-
-
31
hooks[name] = [ in_base, as_hook ]
-
31
invoke_from_option(name, options, &block)
-
end
-
end
-
-
# Remove a previously added hook.
-
#
-
# remove_hook_for :orm
-
16
def self.remove_hook_for(*names)
-
1
remove_invocation(*names)
-
-
1
names.each do |name|
-
1
hooks.delete(name)
-
end
-
end
-
-
# Make class option aware of Rails::Generators.options and Rails::Generators.aliases.
-
16
def self.class_option(name, options = {}) #:nodoc:
-
188
options[:desc] = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc)
-
188
options[:aliases] = default_aliases_for_option(name, options)
-
188
options[:default] = default_value_for_option(name, options)
-
188
super(name, options)
-
end
-
-
# Returns the default source root for a given generator. This is used internally
-
# by rails to set its generators source root. If you want to customize your source
-
# root, you should use source_root.
-
16
def self.default_source_root
-
39
return unless base_name && generator_name
-
39
return unless default_generator_root
-
19
path = File.join(default_generator_root, "templates")
-
19
path if File.exist?(path)
-
end
-
-
# Returns the base root for a common set of generators. This is used to dynamically
-
# guess the default source root.
-
16
def self.base_root
-
58
__dir__
-
end
-
-
# Cache source root and add lib/generators/base/generator/templates to
-
# source paths.
-
16
def self.inherited(base) #:nodoc:
-
39
super
-
-
# Invoke source_root so the default_source_root is set.
-
39
base.source_root
-
-
39
if base.name && !base.name.end_with?("Base")
-
23
Rails::Generators.subclasses << base
-
-
23
Rails::Generators.templates_path.each do |path|
-
23
if base.name.include?("::")
-
23
base.source_paths << File.join(path, base.base_name, base.generator_name)
-
else
-
base.source_paths << File.join(path, base.generator_name)
-
end
-
end
-
end
-
end
-
-
16
private
-
# Check whether the given class names are already taken by user
-
# application or Ruby on Rails.
-
16
def class_collisions(*class_names)
-
return unless behavior == :invoke
-
return if options.skip_collision_check?
-
return if options.force?
-
-
class_names.flatten.each do |class_name|
-
class_name = class_name.to_s
-
next if class_name.strip.empty?
-
-
# Split the class from its module nesting
-
nesting = class_name.split("::")
-
last_name = nesting.pop
-
last = extract_last_module(nesting)
-
-
if last && last.const_defined?(last_name.camelize, false)
-
raise Error, "The name '#{class_name}' is either already used in your application " \
-
"or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check " \
-
"or --force to skip this check and run this generator again."
-
end
-
end
-
end
-
-
# Takes in an array of nested modules and extracts the last module
-
16
def extract_last_module(nesting) # :doc:
-
nesting.inject(Object) do |last_module, nest|
-
break unless last_module.const_defined?(nest, false)
-
last_module.const_get(nest)
-
end
-
end
-
-
# Wrap block with namespace of current application
-
# if namespace exists and is not skipped
-
16
def module_namespacing(&block) # :doc:
-
content = capture(&block)
-
content = wrap_with_namespace(content) if namespaced?
-
concat(content)
-
end
-
-
16
def indent(content, multiplier = 2) # :doc:
-
spaces = " " * multiplier
-
content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join
-
end
-
-
16
def wrap_with_namespace(content) # :doc:
-
content = indent(content).chomp
-
"module #{namespace.name}\n#{content}\nend\n"
-
end
-
-
16
def namespace # :doc:
-
Rails::Generators.namespace
-
end
-
-
16
def namespaced? # :doc:
-
!options[:skip_namespace] && namespace
-
end
-
-
16
def namespace_dirs
-
@namespace_dirs ||= namespace.name.split("::").map(&:underscore)
-
end
-
-
16
def namespaced_path # :doc:
-
@namespaced_path ||= namespace_dirs.join("/")
-
end
-
-
# Use Rails default banner.
-
16
def self.banner # :doc:
-
"rails generate #{namespace.delete_prefix("rails:")} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ")
-
end
-
-
# Sets the base_name taking into account the current class namespace.
-
16
def self.base_name # :doc:
-
943
@base_name ||= begin
-
39
if base = name.to_s.split("::").first
-
39
base.underscore
-
end
-
end
-
end
-
-
# Removes the namespaces and get the generator name. For example,
-
# Rails::Generators::ModelGenerator will return "model" as generator name.
-
16
def self.generator_name # :doc:
-
938
@generator_name ||= begin
-
39
if generator = name.to_s.split("::").last
-
39
generator.delete_suffix!("Generator")
-
39
generator.underscore
-
end
-
end
-
end
-
-
# Returns the default value for the option name given doing a lookup in
-
# Rails::Generators.options.
-
16
def self.default_value_for_option(name, options) # :doc:
-
212
default_for_option(Rails::Generators.options, name, options, options[:default])
-
end
-
-
# Returns default aliases for the option name given doing a lookup in
-
# Rails::Generators.aliases.
-
16
def self.default_aliases_for_option(name, options) # :doc:
-
188
default_for_option(Rails::Generators.aliases, name, options, options[:aliases])
-
end
-
-
# Returns default for the option name given doing a lookup in config.
-
16
def self.default_for_option(config, name, options, default) # :doc:
-
400
if generator_name && (c = config[generator_name.to_sym]) && c.key?(name)
-
c[name]
-
400
elsif base_name && (c = config[base_name.to_sym]) && c.key?(name)
-
95
c[name]
-
305
elsif config[:rails].key?(name)
-
config[:rails][name]
-
else
-
305
default
-
end
-
end
-
-
# Keep hooks configuration that are used on prepare_for_invocation.
-
16
def self.hooks #:nodoc:
-
61
@hooks ||= from_superclass(:hooks, {})
-
end
-
-
# Prepare class invocation to search on Rails namespace if a previous
-
# added hook is being used.
-
16
def self.prepare_for_invocation(name, value) #:nodoc:
-
return super unless value.is_a?(String) || value.is_a?(Symbol)
-
-
if value && constants = hooks[name]
-
value = name if TrueClass === value
-
Rails::Generators.find_by_namespace(value, *constants)
-
elsif klass = Rails::Generators.find_by_namespace(value)
-
klass
-
else
-
super
-
end
-
end
-
-
# Small macro to add ruby as an option to the generator with proper
-
# default value plus an instance helper method called shebang.
-
16
def self.add_shebang_option! # :doc:
-
3
class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command,
-
desc: "Path to the Ruby binary of your choice", banner: "PATH"
-
-
3
no_tasks {
-
3
define_method :shebang do
-
@shebang ||= begin
-
command = if options[:ruby] == Thor::Util.ruby_command
-
"/usr/bin/env #{File.basename(Thor::Util.ruby_command)}"
-
else
-
options[:ruby]
-
end
-
"#!#{command}"
-
end
-
end
-
}
-
end
-
-
16
def self.usage_path # :doc:
-
paths = [
-
source_root && File.expand_path("../USAGE", source_root),
-
default_generator_root && File.join(default_generator_root, "USAGE")
-
]
-
paths.compact.detect { |path| File.exist? path }
-
end
-
-
16
def self.default_generator_root # :doc:
-
58
path = File.expand_path(File.join(base_name, generator_name), base_root)
-
58
path if File.exist?(path)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/named_base"
-
-
module Css # :nodoc:
-
module Generators # :nodoc:
-
class AssetsGenerator < Rails::Generators::NamedBase # :nodoc:
-
source_root File.expand_path("templates", __dir__)
-
-
def copy_stylesheet
-
copy_file "stylesheet.css", File.join("app/assets/stylesheets", class_path, "#{file_name}.css")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/named_base"
-
-
module Css # :nodoc:
-
module Generators # :nodoc:
-
class ScaffoldGenerator < Rails::Generators::NamedBase # :nodoc:
-
source_root Rails::Generators::ScaffoldGenerator.source_root
-
-
# In order to allow the Sass generators to pick up the default Rails CSS and
-
# transform it, we leave it in a standard location for the CSS stylesheet
-
# generators to handle. For the simple, default case, just copy it over.
-
def copy_stylesheet
-
copy_file "scaffold.css", "app/assets/stylesheets/scaffold.css"
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
module Rails
-
3
module Generators
-
3
module Database # :nodoc:
-
3
JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc )
-
3
DATABASES = %w( mysql postgresql sqlite3 oracle sqlserver ) + JDBC_DATABASES
-
-
3
def initialize(*)
-
super
-
convert_database_option_for_jruby
-
end
-
-
3
def gem_for_database(database = options[:database])
-
case database
-
when "mysql" then ["mysql2", ["~> 0.5"]]
-
when "postgresql" then ["pg", ["~> 1.1"]]
-
when "sqlite3" then ["sqlite3", ["~> 1.4"]]
-
when "oracle" then ["activerecord-oracle_enhanced-adapter", nil]
-
when "sqlserver" then ["activerecord-sqlserver-adapter", nil]
-
when "jdbcmysql" then ["activerecord-jdbcmysql-adapter", nil]
-
when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil]
-
when "jdbcpostgresql" then ["activerecord-jdbcpostgresql-adapter", nil]
-
when "jdbc" then ["activerecord-jdbc-adapter", nil]
-
else [database, nil]
-
end
-
end
-
-
3
def convert_database_option_for_jruby
-
if defined?(JRUBY_VERSION)
-
opt = options.dup
-
case opt[:database]
-
when "postgresql" then opt[:database] = "jdbcpostgresql"
-
when "mysql" then opt[:database] = "jdbcmysql"
-
when "sqlite3" then opt[:database] = "jdbcsqlite3"
-
end
-
self.options = opt.freeze
-
end
-
end
-
-
3
private
-
3
def mysql_socket
-
@mysql_socket ||= [
-
"/tmp/mysql.sock", # default
-
"/var/run/mysqld/mysqld.sock", # debian/gentoo
-
"/var/tmp/mysql.sock", # freebsd
-
"/var/lib/mysql/mysql.sock", # fedora
-
"/opt/local/lib/mysql/mysql.sock", # fedora
-
"/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
-
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
-
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
-
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
-
].find { |f| File.exist?(f) } unless Gem.win_platform?
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/named_base"
-
-
module Erb # :nodoc:
-
module Generators # :nodoc:
-
class Base < Rails::Generators::NamedBase #:nodoc:
-
private
-
def formats
-
[format]
-
end
-
-
def format
-
:html
-
end
-
-
def handler
-
:erb
-
end
-
-
def filename_with_extensions(name, file_format = format)
-
[name, file_format, handler].compact.join(".")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/erb"
-
-
module Erb # :nodoc:
-
module Generators # :nodoc:
-
class ControllerGenerator < Base # :nodoc:
-
argument :actions, type: :array, default: [], banner: "action action"
-
-
def copy_view_files
-
base_path = File.join("app/views", class_path, file_name)
-
empty_directory base_path
-
-
actions.each do |action|
-
@action = action
-
formats.each do |format|
-
@path = File.join(base_path, filename_with_extensions(action, format))
-
template filename_with_extensions(:view, format), @path
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/erb"
-
-
module Erb # :nodoc:
-
module Generators # :nodoc:
-
class MailerGenerator < Base # :nodoc:
-
argument :actions, type: :array, default: [], banner: "method method"
-
-
def copy_view_files
-
view_base_path = File.join("app/views", class_path, file_name + "_mailer")
-
empty_directory view_base_path
-
-
if behavior == :invoke
-
formats.each do |format|
-
layout_path = File.join("app/views/layouts", class_path, filename_with_extensions("mailer", format))
-
template filename_with_extensions(:layout, format), layout_path unless File.exist?(layout_path)
-
end
-
end
-
-
actions.each do |action|
-
@action = action
-
-
formats.each do |format|
-
@path = File.join(view_base_path, filename_with_extensions(action, format))
-
template filename_with_extensions(:view, format), @path
-
end
-
end
-
end
-
-
private
-
def formats
-
[:text, :html]
-
end
-
-
def file_name
-
@_file_name ||= super.sub(/_mailer\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/erb"
-
require "rails/generators/resource_helpers"
-
-
module Erb # :nodoc:
-
module Generators # :nodoc:
-
class ScaffoldGenerator < Base # :nodoc:
-
include Rails::Generators::ResourceHelpers
-
-
argument :attributes, type: :array, default: [], banner: "field:type field:type"
-
-
def create_root_folder
-
empty_directory File.join("app/views", controller_file_path)
-
end
-
-
def copy_view_files
-
available_views.each do |view|
-
formats.each do |format|
-
filename = filename_with_extensions(view, format)
-
template filename, File.join("app/views", controller_file_path, filename)
-
end
-
end
-
end
-
-
private
-
def available_views
-
%w(index edit show new _form)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
13
require "active_support/time"
-
13
require "active_support/deprecation"
-
-
13
module Rails
-
13
module Generators
-
13
class GeneratedAttribute # :nodoc:
-
13
INDEX_OPTIONS = %w(index uniq)
-
13
UNIQ_INDEX_OPTIONS = %w(uniq)
-
-
13
attr_accessor :name, :type
-
13
attr_reader :attr_options
-
13
attr_writer :index_name
-
-
13
class << self
-
13
def parse(column_definition)
-
name, type, has_index = column_definition.split(":")
-
-
# if user provided "name:index" instead of "name:string:index"
-
# type should be set blank so GeneratedAttribute's constructor
-
# could set it to :string
-
has_index, type = type, nil if INDEX_OPTIONS.include?(type)
-
-
type, attr_options = *parse_type_and_options(type)
-
type = type.to_sym if type
-
-
if type && reference?(type)
-
if UNIQ_INDEX_OPTIONS.include?(has_index)
-
attr_options[:index] = { unique: true }
-
end
-
end
-
-
new(name, type, has_index, attr_options)
-
end
-
-
13
def reference?(type)
-
[:references, :belongs_to].include? type
-
end
-
-
13
private
-
# parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to
-
# when declaring options curly brackets should be used
-
13
def parse_type_and_options(type)
-
case type
-
when /(string|text|binary|integer)\{(\d+)\}/
-
return $1, limit: $2.to_i
-
when /decimal\{(\d+)[,.-](\d+)\}/
-
return :decimal, precision: $1.to_i, scale: $2.to_i
-
when /(references|belongs_to)\{(.+)\}/
-
type = $1
-
provided_options = $2.split(/[,.-]/)
-
options = Hash[provided_options.map { |opt| [opt.to_sym, true] }]
-
-
if options[:required]
-
ActiveSupport::Deprecation.warn("Passing {required} option has no effect on the model generator. It will be removed in Rails 6.1.\n")
-
options.delete(:required)
-
end
-
-
return type, options
-
else
-
return type, {}
-
end
-
end
-
end
-
-
13
def initialize(name, type = nil, index_type = false, attr_options = {})
-
@name = name
-
@type = type || :string
-
@has_index = INDEX_OPTIONS.include?(index_type)
-
@has_uniq_index = UNIQ_INDEX_OPTIONS.include?(index_type)
-
@attr_options = attr_options
-
end
-
-
13
def field_type
-
@field_type ||= case type
-
when :integer then :number_field
-
when :float, :decimal then :text_field
-
when :time then :time_select
-
when :datetime, :timestamp then :datetime_select
-
when :date then :date_select
-
when :text then :text_area
-
when :rich_text then :rich_text_area
-
when :boolean then :check_box
-
when :attachment, :attachments then :file_field
-
else
-
:text_field
-
end
-
end
-
-
13
def default
-
@default ||= case type
-
when :integer then 1
-
when :float then 1.5
-
when :decimal then "9.99"
-
when :datetime, :timestamp, :time then Time.now.to_s(:db)
-
when :date then Date.today.to_s(:db)
-
when :string then name == "type" ? "" : "MyString"
-
when :text then "MyText"
-
when :boolean then false
-
when :references, :belongs_to,
-
:attachment, :attachments,
-
:rich_text then nil
-
else
-
""
-
end
-
end
-
-
13
def plural_name
-
name.delete_suffix("_id").pluralize
-
end
-
-
13
def singular_name
-
name.delete_suffix("_id").singularize
-
end
-
-
13
def human_name
-
name.humanize
-
end
-
-
13
def index_name
-
@index_name ||= if polymorphic?
-
%w(id type).map { |t| "#{name}_#{t}" }
-
else
-
column_name
-
end
-
end
-
-
13
def column_name
-
@column_name ||= reference? ? "#{name}_id" : name
-
end
-
-
13
def foreign_key?
-
name.end_with?("_id")
-
end
-
-
13
def reference?
-
self.class.reference?(type)
-
end
-
-
13
def polymorphic?
-
attr_options[:polymorphic]
-
end
-
-
13
def required?
-
reference? && Rails.application.config.active_record.belongs_to_required_by_default
-
end
-
-
13
def has_index?
-
@has_index
-
end
-
-
13
def has_uniq_index?
-
@has_uniq_index
-
end
-
-
13
def password_digest?
-
name == "password" && type == :digest
-
end
-
-
13
def token?
-
type == :token
-
end
-
-
13
def rich_text?
-
type == :rich_text
-
end
-
-
13
def attachment?
-
type == :attachment
-
end
-
-
13
def attachments?
-
type == :attachments
-
end
-
-
13
def virtual?
-
rich_text? || attachment? || attachments?
-
end
-
-
13
def inject_options
-
(+"").tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } }
-
end
-
-
13
def inject_index_options
-
has_uniq_index? ? ", unique: true" : ""
-
end
-
-
13
def options_for_migration
-
@attr_options.dup.tap do |options|
-
if required?
-
options[:null] = false
-
end
-
-
if reference? && !polymorphic?
-
options[:foreign_key] = true
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "active_support/concern"
-
1
require "rails/generators/actions/create_migration"
-
-
1
module Rails
-
1
module Generators
-
# Holds common methods for migrations. It assumes that migrations have the
-
# [0-9]*_name format and can be used by other frameworks (like Sequel)
-
# just by implementing the next migration version method.
-
1
module Migration
-
1
extend ActiveSupport::Concern
-
1
attr_reader :migration_number, :migration_file_name, :migration_class_name
-
-
1
module ClassMethods #:nodoc:
-
1
def migration_lookup_at(dirname)
-
Dir.glob("#{dirname}/[0-9]*_*.rb")
-
end
-
-
1
def migration_exists?(dirname, file_name)
-
migration_lookup_at(dirname).grep(/\d+_#{file_name}.rb$/).first
-
end
-
-
1
def current_migration_number(dirname)
-
migration_lookup_at(dirname).collect do |file|
-
File.basename(file).split("_").first.to_i
-
end.max.to_i
-
end
-
-
1
def next_migration_number(dirname)
-
raise NotImplementedError
-
end
-
end
-
-
1
def create_migration(destination, data, config = {}, &block)
-
action Rails::Generators::Actions::CreateMigration.new(self, destination, block || data.to_s, config)
-
end
-
-
1
def set_migration_assigns!(destination)
-
destination = File.expand_path(destination, destination_root)
-
-
migration_dir = File.dirname(destination)
-
@migration_number = self.class.next_migration_number(migration_dir)
-
@migration_file_name = File.basename(destination, ".rb")
-
@migration_class_name = @migration_file_name.camelize
-
end
-
-
# Creates a migration template at the given destination. The difference
-
# to the default template method is that the migration version is appended
-
# to the destination file name.
-
#
-
# The migration version, migration file name, migration class name are
-
# available as instance variables in the template to be rendered.
-
#
-
# migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb"
-
1
def migration_template(source, destination, config = {})
-
source = File.expand_path(find_in_source_paths(source.to_s))
-
-
set_migration_assigns!(destination)
-
context = instance_eval("binding")
-
-
dir, base = File.split(destination)
-
numbered_destination = File.join(dir, ["%migration_number%", base].join("_"))
-
-
file = create_migration numbered_destination, nil, config do
-
if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
-
ERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer").result(context)
-
else
-
ERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context)
-
end
-
end
-
Rails::Generators.add_generated_file(file)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
require "rails/generators/active_model"
-
-
3
module Rails
-
3
module Generators
-
3
module ModelHelpers # :nodoc:
-
3
PLURAL_MODEL_NAME_WARN_MESSAGE = "[WARNING] The model name '%s' was recognized as a plural, using the singular '%s' instead. " \
-
"Override with --force-plural or setup custom inflection rules for this noun before running the generator."
-
3
IRREGULAR_MODEL_NAME_WARN_MESSAGE = <<~WARNING
-
[WARNING] Rails cannot recover singular form from its plural form '%s'.
-
Please setup custom inflection rules for this noun before running the generator in config/initializers/inflections.rb.
-
WARNING
-
3
mattr_accessor :skip_warn
-
-
3
def self.included(base) #:nodoc:
-
4
base.class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of the given model name"
-
end
-
-
3
def initialize(args, *_options)
-
super
-
if name == name.pluralize && name.singularize != name.pluralize && !options[:force_plural]
-
singular = name.singularize
-
unless ModelHelpers.skip_warn
-
say PLURAL_MODEL_NAME_WARN_MESSAGE % [name, singular]
-
end
-
name.replace singular
-
assign_names!(name)
-
end
-
if name.singularize != name.pluralize.singularize && ! ModelHelpers.skip_warn
-
say IRREGULAR_MODEL_NAME_WARN_MESSAGE % [name.pluralize]
-
end
-
ModelHelpers.skip_warn = true
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
13
require "rails/generators/base"
-
13
require "rails/generators/generated_attribute"
-
-
13
module Rails
-
13
module Generators
-
13
class NamedBase < Base
-
13
argument :name, type: :string
-
-
13
def initialize(args, *options) #:nodoc:
-
@inside_template = nil
-
# Unfreeze name in case it's given as a frozen string
-
args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
-
super
-
assign_names!(name)
-
parse_attributes! if respond_to?(:attributes)
-
end
-
-
# Overrides <tt>Thor::Actions#template</tt> so it can tell if
-
# a template is currently being created.
-
13
no_tasks do
-
13
def template(source, *args, &block)
-
inside_template do
-
Rails::Generators.add_generated_file(super)
-
end
-
end
-
-
13
def js_template(source, destination)
-
template(source + ".js", destination + ".js")
-
end
-
end
-
-
13
private
-
13
attr_reader :file_name
-
-
# FIXME: We are avoiding to use alias because a bug on thor that make
-
# this method public and add it to the task list.
-
13
def singular_name # :doc:
-
file_name
-
end
-
-
13
def inside_template # :doc:
-
@inside_template = true
-
yield
-
ensure
-
@inside_template = false
-
end
-
-
13
def inside_template? # :doc:
-
@inside_template
-
end
-
-
13
def file_path # :doc:
-
@file_path ||= (class_path + [file_name]).join("/")
-
end
-
-
13
def class_path # :doc:
-
inside_template? || !namespaced? ? regular_class_path : namespaced_class_path
-
end
-
-
13
def regular_class_path # :doc:
-
@class_path
-
end
-
-
13
def namespaced_class_path # :doc:
-
@namespaced_class_path ||= namespace_dirs + @class_path
-
end
-
-
13
def class_name # :doc:
-
(class_path + [file_name]).map!(&:camelize).join("::")
-
end
-
-
13
def human_name # :doc:
-
@human_name ||= singular_name.humanize
-
end
-
-
13
def plural_name # :doc:
-
@plural_name ||= singular_name.pluralize
-
end
-
-
13
def i18n_scope # :doc:
-
@i18n_scope ||= file_path.tr("/", ".")
-
end
-
-
13
def table_name # :doc:
-
@table_name ||= begin
-
base = pluralize_table_names? ? plural_name : singular_name
-
(class_path + [base]).join("_")
-
end
-
end
-
-
13
def uncountable? # :doc:
-
singular_name == plural_name
-
end
-
-
13
def index_helper # :doc:
-
uncountable? ? "#{plural_route_name}_index" : plural_route_name
-
end
-
-
13
def show_helper # :doc:
-
"#{singular_route_name}_url(@#{singular_table_name})"
-
end
-
-
13
def edit_helper # :doc:
-
"edit_#{show_helper}"
-
end
-
-
13
def new_helper # :doc:
-
"new_#{singular_route_name}_url"
-
end
-
-
13
def singular_table_name # :doc:
-
@singular_table_name ||= (pluralize_table_names? ? table_name.singularize : table_name)
-
end
-
-
13
def plural_table_name # :doc:
-
@plural_table_name ||= (pluralize_table_names? ? table_name : table_name.pluralize)
-
end
-
-
13
def plural_file_name # :doc:
-
@plural_file_name ||= file_name.pluralize
-
end
-
-
13
def fixture_file_name # :doc:
-
@fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name)
-
end
-
-
13
def route_url # :doc:
-
@route_url ||= class_path.collect { |dname| "/" + dname }.join + "/" + plural_file_name
-
end
-
-
13
def url_helper_prefix # :doc:
-
@url_helper_prefix ||= (class_path + [file_name]).join("_")
-
end
-
-
# Tries to retrieve the application name or simply return application.
-
13
def application_name # :doc:
-
if defined?(Rails) && Rails.application
-
Rails.application.class.name.split("::").first.underscore
-
else
-
"application"
-
end
-
end
-
-
13
def redirect_resource_name # :doc:
-
model_resource_name(prefix: "@")
-
end
-
-
13
def model_resource_name(prefix: "") # :doc:
-
resource_name = "#{prefix}#{singular_table_name}"
-
if options[:model_name]
-
"[#{controller_class_path.map { |name| ":" + name }.join(", ")}, #{resource_name}]"
-
else
-
resource_name
-
end
-
end
-
-
13
def singular_route_name # :doc:
-
if options[:model_name]
-
"#{controller_class_path.join('_')}_#{singular_table_name}"
-
else
-
singular_table_name
-
end
-
end
-
-
13
def plural_route_name # :doc:
-
if options[:model_name]
-
"#{controller_class_path.join('_')}_#{plural_table_name}"
-
else
-
plural_table_name
-
end
-
end
-
-
13
def assign_names!(name)
-
@class_path = name.include?("/") ? name.split("/") : name.split("::")
-
@class_path.map!(&:underscore)
-
@file_name = @class_path.pop
-
end
-
-
# Convert attributes array into GeneratedAttribute objects.
-
13
def parse_attributes!
-
self.attributes = (attributes || []).map do |attr|
-
Rails::Generators::GeneratedAttribute.parse(attr)
-
end
-
end
-
-
13
def attributes_names # :doc:
-
@attributes_names ||= attributes.each_with_object([]) do |a, names|
-
names << a.column_name
-
names << "password_confirmation" if a.password_digest?
-
names << "#{a.name}_type" if a.polymorphic?
-
end
-
end
-
-
13
def pluralize_table_names? # :doc:
-
!defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names
-
end
-
-
13
def mountable_engine? # :doc:
-
defined?(ENGINE_ROOT) && namespaced?
-
end
-
-
# Add a class collisions name to be checked on class initialization. You
-
# can supply a hash with a :prefix or :suffix to be tested.
-
#
-
# ==== Examples
-
#
-
# check_class_collision suffix: "Decorator"
-
#
-
# If the generator is invoked with class name Admin, it will check for
-
# the presence of "AdminDecorator".
-
#
-
13
def self.check_class_collision(options = {}) # :doc:
-
8
define_method :check_class_collision do
-
name = if respond_to?(:controller_class_name, true) # for ResourceHelpers
-
controller_class_name
-
else
-
class_name
-
end
-
-
class_collisions "#{options[:prefix]}#{name}#{options[:suffix]}"
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
3
require "rails/generators/app_base"
-
-
3
module Rails
-
3
module ActionMethods # :nodoc:
-
3
attr_reader :options
-
-
3
def initialize(generator)
-
@generator = generator
-
@options = generator.options
-
end
-
-
3
private
-
%w(template copy_file directory empty_directory inside
-
3
empty_directory_with_keep_file create_file chmod shebang).each do |method|
-
27
class_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def #{method}(*args, &block)
-
@generator.send(:#{method}, *args, &block)
-
end
-
RUBY
-
end
-
-
3
def method_missing(meth, *args, &block)
-
@generator.send(meth, *args, &block)
-
end
-
end
-
-
# The application builder allows you to override elements of the application
-
# generator without being forced to reverse the operations of the default
-
# generator.
-
#
-
# This allows you to override entire operations, like the creation of the
-
# Gemfile, README, or JavaScript files, without needing to know exactly
-
# what those operations do so you can create another template action.
-
#
-
# class CustomAppBuilder < Rails::AppBuilder
-
# def test
-
# @generator.gem "rspec-rails", group: [:development, :test]
-
# run "bundle install"
-
# generate "rspec:install"
-
# end
-
# end
-
3
class AppBuilder
-
3
def rakefile
-
template "Rakefile"
-
end
-
-
3
def readme
-
copy_file "README.md", "README.md"
-
end
-
-
3
def ruby_version
-
template "ruby-version", ".ruby-version"
-
end
-
-
3
def gemfile
-
template "Gemfile"
-
end
-
-
3
def configru
-
template "config.ru"
-
end
-
-
3
def gitignore
-
template "gitignore", ".gitignore"
-
end
-
-
3
def version_control
-
if !options[:skip_git] && !options[:pretend]
-
run "git init", capture: options[:quiet], abort_on_failure: false
-
end
-
end
-
-
3
def package_json
-
template "package.json"
-
end
-
-
3
def app
-
directory "app"
-
-
empty_directory_with_keep_file "app/assets/images"
-
-
keep_file "app/controllers/concerns"
-
keep_file "app/models/concerns"
-
end
-
-
3
def bin
-
directory "bin" do |content|
-
"#{shebang}\n" + content
-
end
-
chmod "bin", 0755 & ~File.umask, verbose: false
-
end
-
-
3
def bin_when_updating
-
bin
-
-
if options[:skip_javascript]
-
remove_file "bin/yarn"
-
end
-
end
-
-
3
def yarn_when_updating
-
return if File.exist?("bin/yarn")
-
-
template "bin/yarn" do |content|
-
"#{shebang}\n" + content
-
end
-
-
chmod "bin", 0755 & ~File.umask, verbose: false
-
end
-
-
3
def config
-
empty_directory "config"
-
-
inside "config" do
-
template "routes.rb"
-
template "application.rb"
-
template "environment.rb"
-
template "cable.yml" unless options[:skip_action_cable]
-
template "puma.rb" unless options[:skip_puma]
-
template "spring.rb" if spring_install?
-
template "storage.yml" unless skip_active_storage?
-
-
directory "environments"
-
directory "initializers"
-
directory "locales"
-
end
-
end
-
-
3
def config_when_updating
-
cookie_serializer_config_exist = File.exist?("config/initializers/cookies_serializer.rb")
-
action_cable_config_exist = File.exist?("config/cable.yml")
-
active_storage_config_exist = File.exist?("config/storage.yml")
-
rack_cors_config_exist = File.exist?("config/initializers/cors.rb")
-
assets_config_exist = File.exist?("config/initializers/assets.rb")
-
csp_config_exist = File.exist?("config/initializers/content_security_policy.rb")
-
feature_policy_config_exist = File.exist?("config/initializers/feature_policy.rb")
-
-
@config_target_version = Rails.application.config.loaded_config_version || "5.0"
-
-
config
-
-
unless cookie_serializer_config_exist
-
gsub_file "config/initializers/cookies_serializer.rb", /json(?!,)/, "marshal"
-
end
-
-
if !options[:skip_action_cable] && !action_cable_config_exist
-
template "config/cable.yml"
-
end
-
-
if !skip_active_storage? && !active_storage_config_exist
-
template "config/storage.yml"
-
end
-
-
if options[:skip_sprockets] && !assets_config_exist
-
remove_file "config/initializers/assets.rb"
-
end
-
-
unless rack_cors_config_exist
-
remove_file "config/initializers/cors.rb"
-
end
-
-
if options[:api]
-
unless cookie_serializer_config_exist
-
remove_file "config/initializers/cookies_serializer.rb"
-
end
-
-
unless csp_config_exist
-
remove_file "config/initializers/content_security_policy.rb"
-
end
-
-
unless feature_policy_config_exist
-
remove_file "config/initializers/feature_policy.rb"
-
end
-
end
-
end
-
-
3
def master_key
-
return if options[:pretend] || options[:dummy_app]
-
-
require "rails/generators/rails/master_key/master_key_generator"
-
master_key_generator = Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet], force: options[:force])
-
master_key_generator.add_master_key_file_silently
-
master_key_generator.ignore_master_key_file_silently
-
end
-
-
3
def credentials
-
return if options[:pretend] || options[:dummy_app]
-
-
require "rails/generators/rails/credentials/credentials_generator"
-
Rails::Generators::CredentialsGenerator.new([], quiet: options[:quiet]).add_credentials_file_silently
-
end
-
-
3
def database_yml
-
template "config/databases/#{options[:database]}.yml", "config/database.yml"
-
end
-
-
3
def db
-
directory "db"
-
end
-
-
3
def lib
-
empty_directory "lib"
-
empty_directory_with_keep_file "lib/tasks"
-
empty_directory_with_keep_file "lib/assets"
-
end
-
-
3
def log
-
empty_directory_with_keep_file "log"
-
end
-
-
3
def public_directory
-
directory "public", "public", recursive: false
-
end
-
-
3
def storage
-
empty_directory_with_keep_file "storage"
-
empty_directory_with_keep_file "tmp/storage"
-
end
-
-
3
def test
-
empty_directory_with_keep_file "test/fixtures/files"
-
empty_directory_with_keep_file "test/controllers"
-
empty_directory_with_keep_file "test/mailers"
-
empty_directory_with_keep_file "test/models"
-
empty_directory_with_keep_file "test/helpers"
-
empty_directory_with_keep_file "test/integration"
-
-
template "test/channels/application_cable/connection_test.rb"
-
template "test/test_helper.rb"
-
end
-
-
3
def system_test
-
empty_directory_with_keep_file "test/system"
-
-
template "test/application_system_test_case.rb"
-
end
-
-
3
def tmp
-
empty_directory_with_keep_file "tmp"
-
empty_directory_with_keep_file "tmp/pids"
-
empty_directory "tmp/cache"
-
empty_directory "tmp/cache/assets"
-
end
-
-
3
def vendor
-
empty_directory_with_keep_file "vendor"
-
end
-
-
3
def config_target_version
-
defined?(@config_target_version) ? @config_target_version : Rails::VERSION::STRING.to_f
-
end
-
end
-
-
3
module Generators
-
# We need to store the RAILS_DEV_PATH in a constant, otherwise the path
-
# can change in Ruby 1.8.7 when we FileUtils.cd.
-
3
RAILS_DEV_PATH = File.expand_path("../../../../../..", __dir__)
-
-
3
class AppGenerator < AppBase
-
# :stopdoc:
-
-
3
WEBPACKS = %w( react vue angular elm stimulus )
-
-
3
add_shared_options_for "application"
-
-
# Add rails command options
-
3
class_option :version, type: :boolean, aliases: "-v", group: :rails,
-
desc: "Show Rails version number and quit"
-
-
3
class_option :api, type: :boolean,
-
desc: "Preconfigure smaller stack for API only apps"
-
-
3
class_option :minimal, type: :boolean,
-
desc: "Preconfigure a minimal rails app"
-
-
3
class_option :skip_bundle, type: :boolean, aliases: "-B", default: false,
-
desc: "Don't run bundle install"
-
-
3
class_option :webpack, type: :string, aliases: "--webpacker", default: nil,
-
desc: "Preconfigure Webpack with a particular framework (options: #{WEBPACKS.join(", ")})"
-
-
3
class_option :skip_webpack_install, type: :boolean, default: false,
-
desc: "Don't run Webpack install"
-
-
3
def initialize(*args)
-
super
-
-
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
-
raise Error, "Invalid value for --database option. Supported preconfigurations are: #{DATABASES.join(", ")}."
-
end
-
-
# Force sprockets and yarn to be skipped when generating API only apps.
-
# Can't modify options hash as it's frozen by default.
-
if options[:api]
-
self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze
-
end
-
-
if options[:minimal]
-
self.options = options.merge(
-
skip_action_cable: true,
-
skip_action_mailer: true,
-
skip_action_mailbox: true,
-
skip_action_text: true,
-
skip_active_job: true,
-
skip_active_storage: true,
-
skip_bootsnap: true,
-
skip_dev_gems: true,
-
skip_javascript: true,
-
skip_jbuilder: true,
-
skip_spring: true,
-
skip_system_test: true,
-
skip_webpack_install: true,
-
skip_turbolinks: true).tap do |option|
-
if option[:webpack]
-
option[:skip_webpack_install] = false
-
option[:skip_javascript] = false
-
end
-
end.freeze
-
end
-
-
@after_bundle_callbacks = []
-
end
-
-
3
public_task :set_default_accessors!
-
3
public_task :create_root
-
-
3
def create_root_files
-
build(:readme)
-
build(:rakefile)
-
build(:ruby_version)
-
build(:configru)
-
build(:gitignore) unless options[:skip_git]
-
build(:gemfile) unless options[:skip_gemfile]
-
build(:version_control)
-
build(:package_json) unless options[:skip_javascript]
-
end
-
-
3
def create_app_files
-
build(:app)
-
end
-
-
3
def create_bin_files
-
build(:bin)
-
end
-
-
3
def update_bin_files
-
build(:bin_when_updating)
-
end
-
3
remove_task :update_bin_files
-
-
3
def update_bin_yarn
-
build(:yarn_when_updating)
-
end
-
3
remove_task :update_bin_yarn
-
-
3
def update_active_storage
-
unless skip_active_storage?
-
rails_command "active_storage:update", inline: true
-
end
-
end
-
3
remove_task :update_active_storage
-
-
3
def create_config_files
-
build(:config)
-
end
-
-
3
def update_config_files
-
build(:config_when_updating)
-
end
-
3
remove_task :update_config_files
-
-
3
def create_master_key
-
build(:master_key)
-
end
-
-
3
def create_credentials
-
build(:credentials)
-
end
-
-
3
def display_upgrade_guide_info
-
say "\nAfter this, check Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html for more details about upgrading your app."
-
end
-
3
remove_task :display_upgrade_guide_info
-
-
3
def create_boot_file
-
template "config/boot.rb"
-
end
-
-
3
def create_active_record_files
-
return if options[:skip_active_record]
-
build(:database_yml)
-
end
-
-
3
def create_db_files
-
return if options[:skip_active_record]
-
build(:db)
-
end
-
-
3
def create_lib_files
-
build(:lib)
-
end
-
-
3
def create_log_files
-
build(:log)
-
end
-
-
3
def create_public_files
-
build(:public_directory)
-
end
-
-
3
def create_tmp_files
-
build(:tmp)
-
end
-
-
3
def create_vendor_files
-
build(:vendor)
-
end
-
-
3
def create_test_files
-
build(:test) unless options[:skip_test]
-
end
-
-
3
def create_system_test_files
-
build(:system_test) if depends_on_system_test?
-
end
-
-
3
def create_storage_files
-
build(:storage) unless skip_active_storage?
-
end
-
-
3
def delete_app_assets_if_api_option
-
if options[:api]
-
remove_dir "app/assets"
-
remove_dir "lib/assets"
-
remove_dir "tmp/cache/assets"
-
end
-
end
-
-
3
def delete_app_helpers_if_api_option
-
if options[:api]
-
remove_dir "app/helpers"
-
remove_dir "test/helpers"
-
end
-
end
-
-
3
def delete_app_views_if_api_option
-
if options[:api]
-
if options[:skip_action_mailer]
-
remove_dir "app/views"
-
else
-
remove_file "app/views/layouts/application.html.erb"
-
end
-
end
-
end
-
-
3
def delete_public_files_if_api_option
-
if options[:api]
-
remove_file "public/404.html"
-
remove_file "public/422.html"
-
remove_file "public/500.html"
-
remove_file "public/apple-touch-icon-precomposed.png"
-
remove_file "public/apple-touch-icon.png"
-
remove_file "public/favicon.ico"
-
end
-
end
-
-
3
def delete_js_folder_skipping_javascript
-
if options[:skip_javascript] && !options[:minimal]
-
remove_dir "app/javascript"
-
end
-
end
-
-
3
def delete_js_packs_when_minimal_skipping_webpack
-
if options[:minimal] && options[:skip_webpack_install]
-
remove_dir "app/javascript/packs"
-
keep_file "app/javascript"
-
end
-
end
-
-
3
def delete_assets_initializer_skipping_sprockets
-
if options[:skip_sprockets]
-
remove_file "config/initializers/assets.rb"
-
end
-
end
-
-
3
def delete_application_record_skipping_active_record
-
if options[:skip_active_record]
-
remove_file "app/models/application_record.rb"
-
end
-
end
-
-
3
def delete_active_job_folder_if_skipping_active_job
-
if options[:skip_active_job]
-
remove_dir "app/jobs"
-
end
-
end
-
-
3
def delete_action_mailer_files_skipping_action_mailer
-
if options[:skip_action_mailer]
-
remove_file "app/views/layouts/mailer.html.erb"
-
remove_file "app/views/layouts/mailer.text.erb"
-
remove_dir "app/mailers"
-
remove_dir "test/mailers"
-
end
-
end
-
-
3
def delete_action_cable_files_skipping_action_cable
-
if options[:skip_action_cable]
-
remove_dir "app/javascript/channels"
-
remove_dir "app/channels"
-
remove_dir "test/channels"
-
end
-
end
-
-
3
def delete_non_api_initializers_if_api_option
-
if options[:api]
-
remove_file "config/initializers/cookies_serializer.rb"
-
remove_file "config/initializers/content_security_policy.rb"
-
remove_file "config/initializers/feature_policy.rb"
-
end
-
end
-
-
3
def delete_api_initializers
-
unless options[:api]
-
remove_file "config/initializers/cors.rb"
-
end
-
end
-
-
3
def delete_new_framework_defaults
-
unless options[:update]
-
remove_file "config/initializers/new_framework_defaults_6_1.rb"
-
end
-
end
-
-
3
def delete_bin_yarn
-
remove_file "bin/yarn" if options[:skip_javascript]
-
end
-
-
3
def finish_template
-
build(:leftovers)
-
end
-
-
3
public_task :apply_rails_template, :run_bundle
-
3
public_task :generate_bundler_binstub, :generate_spring_binstub
-
3
public_task :run_webpack
-
-
3
def run_after_bundle_callbacks
-
@after_bundle_callbacks.each(&:call)
-
end
-
-
3
def self.banner
-
"rails new #{arguments.map(&:usage).join(' ')} [options]"
-
end
-
-
# :startdoc:
-
-
3
private
-
# Define file as an alias to create_file for backwards compatibility.
-
3
def file(*args, &block)
-
create_file(*args, &block)
-
end
-
-
# Registers a callback to be executed after bundle and spring binstubs
-
# have run.
-
#
-
# after_bundle do
-
# git add: '.'
-
# end
-
3
def after_bundle(&block) # :doc:
-
@after_bundle_callbacks << block
-
end
-
-
3
def get_builder_class
-
defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
-
end
-
end
-
-
# This class handles preparation of the arguments before the AppGenerator is
-
# called. The class provides version or help information if they were
-
# requested, and also constructs the railsrc file (used for extra configuration
-
# options).
-
#
-
# This class should be called before the AppGenerator is required and started
-
# since it configures and mutates ARGV correctly.
-
3
class ARGVScrubber # :nodoc:
-
3
def initialize(argv = ARGV)
-
@argv = argv
-
end
-
-
3
def prepare!
-
handle_version_request!(@argv.first)
-
handle_invalid_command!(@argv.first, @argv) do
-
handle_rails_rc!(@argv.drop(1))
-
end
-
end
-
-
3
def self.default_rc_file
-
File.expand_path("~/.railsrc")
-
end
-
-
3
private
-
3
def handle_version_request!(argument)
-
if ["--version", "-v"].include?(argument)
-
require "rails/version"
-
puts "Rails #{Rails::VERSION::STRING}"
-
exit(0)
-
end
-
end
-
-
3
def handle_invalid_command!(argument, argv)
-
if argument == "new"
-
yield
-
else
-
["--help"] + argv.drop(1)
-
end
-
end
-
-
3
def handle_rails_rc!(argv)
-
if argv.find { |arg| arg == "--no-rc" }
-
argv.reject { |arg| arg == "--no-rc" }
-
else
-
railsrc(argv) { |rc_argv, rc| insert_railsrc_into_argv!(rc_argv, rc) }
-
end
-
end
-
-
3
def railsrc(argv)
-
if (customrc = argv.index { |x| x.include?("--rc=") })
-
fname = File.expand_path(argv[customrc].gsub(/--rc=/, ""))
-
yield(argv.take(customrc) + argv.drop(customrc + 1), fname)
-
else
-
yield argv, self.class.default_rc_file
-
end
-
end
-
-
3
def read_rc_file(railsrc)
-
extra_args = File.readlines(railsrc).flat_map(&:split)
-
puts "Using #{extra_args.join(" ")} from #{railsrc}"
-
extra_args
-
end
-
-
3
def insert_railsrc_into_argv!(argv, railsrc)
-
return argv unless File.exist?(railsrc)
-
extra_args = read_rc_file railsrc
-
argv.take(1) + extra_args + argv.drop(1)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class ApplicationRecordGenerator < Base # :nodoc:
-
1
hook_for :orm, required: true, desc: "ORM to be invoked"
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Generators
-
class AssetsGenerator < NamedBase # :nodoc:
-
class_option :javascripts, type: :boolean, desc: "Generate JavaScripts"
-
class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
-
-
class_option :javascript_engine, desc: "Engine for JavaScripts"
-
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
-
-
private
-
def asset_name
-
file_name
-
end
-
-
hook_for :javascript_engine do |javascript_engine|
-
invoke javascript_engine, [name] if options[:javascripts]
-
end
-
-
hook_for :stylesheet_engine do |stylesheet_engine|
-
invoke stylesheet_engine, [name] if options[:stylesheets]
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/named_base"
-
-
module Rails
-
module Generators
-
class BenchmarkGenerator < NamedBase
-
IPS_GEM_NAME = "benchmark-ips"
-
-
argument :reports, type: :array, default: ["before", "after"]
-
-
def generate_layout
-
add_ips_to_gemfile unless ips_installed?
-
template("benchmark.rb.tt", "script/benchmarks/#{file_name}.rb")
-
end
-
-
private
-
def add_ips_to_gemfile
-
gem(IPS_GEM_NAME, group: [:development, :test])
-
end
-
-
def ips_installed?
-
in_root do
-
return File.read("Gemfile").match?(/gem.*\b#{IPS_GEM_NAME}\b.*/)
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
2
module Rails
-
2
module Generators
-
2
class ControllerGenerator < NamedBase # :nodoc:
-
2
argument :actions, type: :array, default: [], banner: "action action"
-
2
class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb."
-
2
class_option :helper, type: :boolean
-
2
class_option :assets, type: :boolean
-
-
2
check_class_collision suffix: "Controller"
-
-
2
def create_controller_files
-
template "controller.rb", File.join("app/controllers", class_path, "#{file_name}_controller.rb")
-
end
-
-
2
def add_routes
-
return if options[:skip_routes]
-
return if actions.empty?
-
routing_code = actions.map { |action| "get '#{file_name}/#{action}'" }.join("\n")
-
route routing_code, namespace: regular_class_path
-
end
-
-
2
hook_for :template_engine, :test_framework, :helper, :assets do |generator|
-
invoke generator, [ remove_possible_suffix(name), actions ]
-
end
-
-
2
private
-
2
def file_name
-
@_file_name ||= remove_possible_suffix(super)
-
end
-
-
2
def remove_possible_suffix(name)
-
name.sub(/_?controller$/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/base"
-
require "rails/generators/rails/master_key/master_key_generator"
-
require "active_support/encrypted_configuration"
-
-
module Rails
-
module Generators
-
class CredentialsGenerator < Base # :nodoc:
-
def add_credentials_file
-
unless credentials.content_path.exist?
-
template = credentials_template
-
-
say "Adding #{credentials.content_path} to store encrypted credentials."
-
say ""
-
say "The following content has been encrypted with the Rails master key:"
-
say ""
-
say template, :on_green
-
say ""
-
-
add_credentials_file_silently(template)
-
-
say "You can edit encrypted credentials with `bin/rails credentials:edit`."
-
say ""
-
end
-
end
-
-
def add_credentials_file_silently(template = nil)
-
unless credentials.content_path.exist?
-
credentials.write(credentials_template)
-
end
-
end
-
-
private
-
def credentials
-
ActiveSupport::EncryptedConfiguration.new(
-
config_path: "config/credentials.yml.enc",
-
key_path: "config/master.key",
-
env_key: "RAILS_MASTER_KEY",
-
raise_if_missing_key: true
-
)
-
end
-
-
def credentials_template
-
<<~YAML
-
# aws:
-
# access_key_id: 123
-
# secret_access_key: 345
-
-
# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
-
secret_key_base: #{SecureRandom.hex(64)}
-
YAML
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/base"
-
-
module Rails
-
module Generators
-
module Db
-
module System
-
class ChangeGenerator < Base # :nodoc:
-
include Database
-
include AppName
-
-
class_option :to, required: true,
-
desc: "The database system to switch to."
-
-
def self.default_generator_root
-
path = File.expand_path(File.join(base_name, "app"), base_root)
-
path if File.exist?(path)
-
end
-
-
def initialize(*)
-
super
-
-
unless DATABASES.include?(options[:to])
-
raise Error, "Invalid value for --to option. Supported preconfigurations are: #{DATABASES.join(", ")}."
-
end
-
-
opt = options.dup
-
opt[:database] ||= opt[:to]
-
self.options = opt.freeze
-
end
-
-
def edit_database_config
-
template("config/databases/#{options[:database]}.yml", "config/database.yml")
-
end
-
-
def edit_gemfile
-
name, version = gem_for_database
-
gsub_file("Gemfile", all_database_gems_regex, name)
-
gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version))
-
end
-
-
private
-
def all_database_gems
-
DATABASES.map { |database| gem_for_database(database) }
-
end
-
-
def all_database_gems_regex
-
all_database_gem_names = all_database_gems.map(&:first)
-
/(\b#{all_database_gem_names.join('\b|\b')}\b)/
-
end
-
-
def gem_entry_regex_for(gem_name)
-
/^gem.*\b#{gem_name}\b.*/
-
end
-
-
def gem_entry_for(*gem_name_and_version)
-
gem_name_and_version.map! { |segment| "'#{segment}'" }
-
"gem #{gem_name_and_version.join(", ")}"
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/base"
-
require "active_support/encrypted_file"
-
-
module Rails
-
module Generators
-
class EncryptedFileGenerator < Base # :nodoc:
-
def add_encrypted_file_silently(file_path, key_path, template = encrypted_file_template)
-
unless File.exist?(file_path)
-
ActiveSupport::EncryptedFile.new(
-
content_path: file_path,
-
key_path: key_path,
-
env_key: "RAILS_MASTER_KEY",
-
raise_if_missing_key: true
-
).write(template)
-
end
-
end
-
-
private
-
def encrypted_file_template
-
<<~YAML
-
# aws:
-
# access_key_id: 123
-
# secret_access_key: 345
-
-
YAML
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
require "rails/generators/base"
-
require "active_support/encrypted_file"
-
-
module Rails
-
module Generators
-
class EncryptionKeyFileGenerator < Base # :nodoc:
-
def add_key_file(key_path)
-
key_path = Pathname.new(key_path)
-
-
unless key_path.exist?
-
key = ActiveSupport::EncryptedFile.generate_key
-
-
log "Adding #{key_path} to store the encryption key: #{key}"
-
log ""
-
log "Save this in a password manager your team can access."
-
log ""
-
log "If you lose the key, no one, including you, can access anything encrypted with it."
-
-
log ""
-
add_key_file_silently(key_path, key)
-
log ""
-
end
-
end
-
-
def add_key_file_silently(key_path, key = nil)
-
create_file key_path, key || ActiveSupport::EncryptedFile.generate_key
-
key_path.chmod 0600
-
end
-
-
def ignore_key_file(key_path, ignore: key_ignore(key_path))
-
if File.exist?(".gitignore")
-
unless File.read(".gitignore").include?(ignore)
-
log "Ignoring #{key_path} so it won't end up in Git history:"
-
log ""
-
append_to_file ".gitignore", ignore
-
log ""
-
end
-
else
-
log "IMPORTANT: Don't commit #{key_path}. Add this to your ignore file:"
-
log ignore, :on_green
-
log ""
-
end
-
end
-
-
def ignore_key_file_silently(key_path, ignore: key_ignore(key_path))
-
append_to_file ".gitignore", ignore if File.exist?(".gitignore")
-
end
-
-
private
-
def key_ignore(key_path)
-
[ "", "/#{key_path}", "" ].join("\n")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class GeneratorGenerator < NamedBase # :nodoc:
-
1
check_class_collision suffix: "Generator"
-
-
1
class_option :namespace, type: :boolean, default: true,
-
desc: "Namespace generator under lib/generators/name"
-
-
1
def create_generator_files
-
directory ".", generator_dir
-
end
-
-
1
hook_for :test_framework
-
-
1
private
-
1
def generator_dir
-
if options[:namespace]
-
File.join("lib", "generators", regular_class_path, file_name)
-
else
-
File.join("lib", "generators", regular_class_path)
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class HelperGenerator < NamedBase # :nodoc:
-
1
check_class_collision suffix: "Helper"
-
-
1
def create_helper_files
-
template "helper.rb", File.join("app/helpers", class_path, "#{file_name}_helper.rb")
-
end
-
-
1
hook_for :test_framework
-
-
1
private
-
1
def file_name
-
@_file_name ||= super.sub(/_helper\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class IntegrationTestGenerator < NamedBase # :nodoc:
-
1
hook_for :integration_tool, as: :integration
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
require "rails/generators/base"
-
require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
-
require "active_support/encrypted_file"
-
-
module Rails
-
module Generators
-
class MasterKeyGenerator < Base # :nodoc:
-
MASTER_KEY_PATH = Pathname.new("config/master.key")
-
-
def add_master_key_file
-
unless MASTER_KEY_PATH.exist?
-
key = ActiveSupport::EncryptedFile.generate_key
-
-
log "Adding #{MASTER_KEY_PATH} to store the master encryption key: #{key}"
-
log ""
-
log "Save this in a password manager your team can access."
-
log ""
-
log "If you lose the key, no one, including you, can access anything encrypted with it."
-
-
log ""
-
add_master_key_file_silently(key)
-
log ""
-
end
-
end
-
-
def add_master_key_file_silently(key = nil)
-
unless MASTER_KEY_PATH.exist?
-
key_file_generator.add_key_file_silently(MASTER_KEY_PATH, key)
-
end
-
end
-
-
def ignore_master_key_file
-
key_file_generator.ignore_key_file(MASTER_KEY_PATH, ignore: key_ignore)
-
end
-
-
def ignore_master_key_file_silently
-
key_file_generator.ignore_key_file_silently(MASTER_KEY_PATH, ignore: key_ignore)
-
end
-
-
private
-
def key_file_generator
-
EncryptionKeyFileGenerator.new([], options)
-
end
-
-
def key_ignore
-
[ "", "# Ignore master key for decrypting credentials and more.", "/#{MASTER_KEY_PATH}", "" ].join("\n")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
2
module Rails
-
2
module Generators
-
2
class MigrationGenerator < NamedBase # :nodoc:
-
2
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
-
2
hook_for :orm, required: true, desc: "ORM to be invoked"
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
2
require "rails/generators/model_helpers"
-
-
2
module Rails
-
2
module Generators
-
2
class ModelGenerator < NamedBase # :nodoc:
-
2
include Rails::Generators::ModelHelpers
-
-
2
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
-
2
hook_for :orm, required: true, desc: "ORM to be invoked"
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "active_support/core_ext/hash/except"
-
1
require "rails/generators/rails/app/app_generator"
-
1
require "date"
-
-
1
module Rails
-
# The plugin builder allows you to override elements of the plugin
-
# generator without being forced to reverse the operations of the default
-
# generator.
-
#
-
# This allows you to override entire operations, like the creation of the
-
# Gemfile, \README, or JavaScript files, without needing to know exactly
-
# what those operations do so you can create another template action.
-
1
class PluginBuilder
-
1
def rakefile
-
template "Rakefile"
-
end
-
-
1
def app
-
if mountable?
-
if api?
-
directory "app", exclude_pattern: %r{app/(views|helpers)}
-
else
-
directory "app"
-
empty_directory_with_keep_file "app/assets/images/#{namespaced_name}"
-
end
-
-
remove_dir "app/mailers" if options[:skip_action_mailer]
-
remove_dir "app/jobs" if options[:skip_active_job]
-
elsif full?
-
empty_directory_with_keep_file "app/models"
-
empty_directory_with_keep_file "app/controllers"
-
empty_directory_with_keep_file "app/mailers" unless options[:skip_action_mailer]
-
empty_directory_with_keep_file "app/jobs" unless options[:skip_active_job]
-
-
unless api?
-
empty_directory_with_keep_file "app/assets/images/#{namespaced_name}"
-
empty_directory_with_keep_file "app/helpers"
-
empty_directory_with_keep_file "app/views"
-
end
-
end
-
end
-
-
1
def readme
-
template "README.md"
-
end
-
-
1
def gemfile
-
template "Gemfile"
-
end
-
-
1
def license
-
template "MIT-LICENSE"
-
end
-
-
1
def gemspec
-
template "%name%.gemspec"
-
end
-
-
1
def gitignore
-
template "gitignore", ".gitignore"
-
end
-
-
1
def version_control
-
if !options[:skip_git] && !options[:pretend]
-
run "git init", capture: options[:quiet], abort_on_failure: false
-
end
-
end
-
-
1
def lib
-
template "lib/%namespaced_name%.rb"
-
template "lib/tasks/%namespaced_name%_tasks.rake"
-
template "lib/%namespaced_name%/version.rb"
-
-
if engine?
-
template "lib/%namespaced_name%/engine.rb"
-
else
-
template "lib/%namespaced_name%/railtie.rb"
-
end
-
end
-
-
1
def config
-
template "config/routes.rb" if engine?
-
end
-
-
1
def test
-
template "test/test_helper.rb"
-
template "test/%namespaced_name%_test.rb"
-
append_file "Rakefile", <<-EOF
-
-
#{rakefile_test_tasks}
-
task default: :test
-
EOF
-
if engine?
-
template "test/integration/navigation_test.rb"
-
end
-
end
-
-
1
DUMMY_IGNORE_OPTIONS = %i[dev edge master template]
-
-
1
def generate_test_dummy(force = false)
-
opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
-
opts[:force] = force
-
opts[:skip_bundle] = true
-
opts[:skip_listen] = true
-
opts[:skip_git] = true
-
opts[:skip_turbolinks] = true
-
opts[:skip_webpack_install] = true
-
opts[:dummy_app] = true
-
-
invoke Rails::Generators::AppGenerator,
-
[ File.expand_path(dummy_path, destination_root) ], opts
-
end
-
-
1
def test_dummy_config
-
template "rails/boot.rb", "#{dummy_path}/config/boot.rb", force: true
-
-
insert_into_file "#{dummy_path}/config/application.rb", <<~RUBY, after: /^Bundler\.require.+\n/
-
require #{namespaced_name.inspect}
-
RUBY
-
-
if mountable?
-
template "rails/routes.rb", "#{dummy_path}/config/routes.rb", force: true
-
end
-
end
-
-
1
def test_dummy_assets
-
template "rails/javascripts.js", "#{dummy_path}/app/javascript/packs/application.js", force: true
-
template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
-
template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
-
end
-
-
1
def test_dummy_clean
-
inside dummy_path do
-
remove_file ".ruby-version"
-
remove_file "db/seeds.rb"
-
remove_file "Gemfile"
-
remove_file "lib/tasks"
-
remove_file "public/robots.txt"
-
remove_file "README.md"
-
remove_file "test"
-
remove_file "vendor"
-
end
-
end
-
-
1
def assets_manifest
-
template "rails/engine_manifest.js", "app/assets/config/#{underscored_name}_manifest.js"
-
end
-
-
1
def stylesheets
-
if mountable?
-
copy_file "rails/stylesheets.css",
-
"app/assets/stylesheets/#{namespaced_name}/application.css"
-
elsif full?
-
empty_directory_with_keep_file "app/assets/stylesheets/#{namespaced_name}"
-
end
-
end
-
-
1
def bin(force = false)
-
bin_file = engine? ? "bin/rails.tt" : "bin/test.tt"
-
template bin_file, force: force do |content|
-
"#{shebang}\n" + content
-
end
-
chmod "bin", 0755, verbose: false
-
end
-
-
1
def gemfile_entry
-
return unless inside_application?
-
-
gemfile_in_app_path = File.join(rails_app_path, "Gemfile")
-
if File.exist? gemfile_in_app_path
-
entry = "\ngem '#{name}', path: '#{relative_path}'"
-
append_file gemfile_in_app_path, entry
-
end
-
end
-
end
-
-
1
module Generators
-
1
class PluginGenerator < AppBase # :nodoc:
-
1
add_shared_options_for "plugin"
-
-
1
alias_method :plugin_path, :app_path
-
-
1
class_option :dummy_path, type: :string, default: "test/dummy",
-
desc: "Create dummy application at given path"
-
-
1
class_option :full, type: :boolean, default: false,
-
desc: "Generate a rails engine with bundled Rails application for testing"
-
-
1
class_option :mountable, type: :boolean, default: false,
-
desc: "Generate mountable isolated engine"
-
-
1
class_option :skip_gemspec, type: :boolean, default: false,
-
desc: "Skip gemspec file"
-
-
1
class_option :skip_gemfile_entry, type: :boolean, default: false,
-
desc: "If creating plugin in application's directory " \
-
"skip adding entry to Gemfile"
-
-
1
class_option :api, type: :boolean, default: false,
-
desc: "Generate a smaller stack for API application plugins"
-
-
1
def initialize(*args)
-
@dummy_path = nil
-
super
-
end
-
-
1
public_task :set_default_accessors!
-
1
public_task :create_root
-
-
1
def create_root_files
-
build(:readme)
-
build(:rakefile)
-
build(:gemspec) unless options[:skip_gemspec]
-
build(:license)
-
build(:gitignore) unless options[:skip_git]
-
build(:gemfile) unless options[:skip_gemfile]
-
build(:version_control)
-
end
-
-
1
def create_app_files
-
build(:app)
-
end
-
-
1
def create_config_files
-
build(:config)
-
end
-
-
1
def create_lib_files
-
build(:lib)
-
end
-
-
1
def create_assets_manifest_file
-
build(:assets_manifest) if !api? && engine?
-
end
-
-
1
def create_public_stylesheets_files
-
build(:stylesheets) unless api?
-
end
-
-
1
def create_bin_files
-
build(:bin)
-
end
-
-
1
def create_test_files
-
build(:test) unless options[:skip_test]
-
end
-
-
1
def create_test_dummy_files
-
return unless with_dummy_app?
-
create_dummy_app
-
end
-
-
1
def update_gemfile
-
build(:gemfile_entry) unless options[:skip_gemfile_entry]
-
end
-
-
1
def finish_template
-
build(:leftovers)
-
end
-
-
1
public_task :apply_rails_template
-
-
1
def name
-
@name ||= begin
-
# same as ActiveSupport::Inflector#underscore except not replacing '-'
-
underscored = original_name.dup
-
underscored.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
-
underscored.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
-
underscored.downcase!
-
-
underscored
-
end
-
end
-
-
1
def underscored_name
-
@underscored_name ||= original_name.underscore
-
end
-
-
1
def namespaced_name
-
@namespaced_name ||= name.tr("-", "/")
-
end
-
-
1
private
-
1
def create_dummy_app(path = nil)
-
dummy_path(path) if path
-
-
say_status :vendor_app, dummy_path
-
mute do
-
build(:generate_test_dummy)
-
build(:test_dummy_config)
-
build(:test_dummy_assets)
-
build(:test_dummy_clean)
-
# ensure that bin/rails has proper dummy_path
-
build(:bin, true)
-
end
-
end
-
-
1
def engine?
-
full? || mountable? || options[:engine]
-
end
-
-
1
def full?
-
options[:full]
-
end
-
-
1
def mountable?
-
options[:mountable]
-
end
-
-
1
def skip_git?
-
options[:skip_git]
-
end
-
-
1
def with_dummy_app?
-
options[:skip_test].blank? || options[:dummy_path] != "test/dummy"
-
end
-
-
1
def api?
-
options[:api]
-
end
-
-
1
def self.banner
-
"rails plugin new #{arguments.map(&:usage).join(' ')} [options]"
-
end
-
-
1
def original_name
-
@original_name ||= File.basename(destination_root)
-
end
-
-
1
def modules
-
@modules ||= namespaced_name.camelize.split("::")
-
end
-
-
1
def wrap_in_modules(unwrapped_code)
-
unwrapped_code = "#{unwrapped_code}".strip.gsub(/\s$\n/, "")
-
modules.reverse.inject(unwrapped_code) do |content, mod|
-
str = +"module #{mod}\n"
-
str << content.lines.map { |line| " #{line}" }.join
-
str << (content.present? ? "\nend" : "end")
-
end
-
end
-
-
1
def camelized_modules
-
@camelized_modules ||= namespaced_name.camelize
-
end
-
-
1
def humanized
-
@humanized ||= original_name.underscore.humanize
-
end
-
-
1
def camelized
-
@camelized ||= name.gsub(/\W/, "_").squeeze("_").camelize
-
end
-
-
1
def author
-
default = "TODO: Write your name"
-
if skip_git?
-
@author = default
-
else
-
@author = `git config user.name`.chomp rescue default
-
end
-
end
-
-
1
def email
-
default = "TODO: Write your email address"
-
if skip_git?
-
@email = default
-
else
-
@email = `git config user.email`.chomp rescue default
-
end
-
end
-
-
1
def valid_const?
-
if /-\d/.match?(original_name)
-
raise Error, "Invalid plugin name #{original_name}. Please give a name which does not contain a namespace starting with numeric characters."
-
elsif /[^\w-]+/.match?(original_name)
-
raise Error, "Invalid plugin name #{original_name}. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters."
-
elsif /^\d/.match?(camelized)
-
raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers."
-
elsif RESERVED_NAMES.include?(name)
-
raise Error, "Invalid plugin name #{original_name}. Please give a " \
-
"name which does not match one of the reserved rails " \
-
"words: #{RESERVED_NAMES.join(", ")}"
-
elsif Object.const_defined?(camelized)
-
raise Error, "Invalid plugin name #{original_name}, constant #{camelized} is already in use. Please choose another plugin name."
-
end
-
end
-
-
1
def get_builder_class
-
defined?(::PluginBuilder) ? ::PluginBuilder : Rails::PluginBuilder
-
end
-
-
1
def rakefile_test_tasks
-
<<-RUBY
-
require "rake/testtask"
-
-
Rake::TestTask.new(:test) do |t|
-
t.libs << 'test'
-
t.pattern = 'test/**/*_test.rb'
-
t.verbose = false
-
end
-
RUBY
-
end
-
-
1
def dummy_path(path = nil)
-
@dummy_path = path if path
-
@dummy_path || options[:dummy_path]
-
end
-
-
1
def mute(&block)
-
shell.mute(&block)
-
end
-
-
1
def rails_app_path
-
APP_PATH.sub("/config/application", "") if defined?(APP_PATH)
-
end
-
-
1
def inside_application?
-
rails_app_path && destination_root.start_with?(rails_app_path.to_s)
-
end
-
-
1
def relative_path
-
return unless inside_application?
-
app_path.delete_prefix("#{rails_app_path}/")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "rails/generators/resource_helpers"
-
1
require "rails/generators/rails/model/model_generator"
-
-
1
module Rails
-
1
module Generators
-
1
class ResourceGenerator < ModelGenerator # :nodoc:
-
1
include ResourceHelpers
-
-
1
hook_for :resource_controller, required: true do |controller|
-
invoke controller, [ controller_name, options[:actions] ]
-
end
-
-
1
class_option :actions, type: :array, banner: "ACTION ACTION", default: [],
-
desc: "Actions for the resource controller"
-
-
1
hook_for :resource_route, required: true
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
module Rails
-
module Generators
-
class ResourceRouteGenerator < NamedBase # :nodoc:
-
# Properly nests namespaces passed into a generator
-
#
-
# $ bin/rails generate resource admin/users/products
-
#
-
# should give you
-
#
-
# namespace :admin do
-
# namespace :users do
-
# resources :products
-
# end
-
# end
-
def add_resource_route
-
return if options[:actions].present?
-
route "resources :#{file_name.pluralize}", namespace: regular_class_path
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "rails/generators/rails/resource/resource_generator"
-
-
1
module Rails
-
1
module Generators
-
1
class ScaffoldGenerator < ResourceGenerator # :nodoc:
-
1
remove_hook_for :resource_controller
-
1
remove_class_option :actions
-
-
1
class_option :api, type: :boolean
-
1
class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
-
1
class_option :stylesheet_engine, desc: "Engine for Stylesheets"
-
1
class_option :assets, type: :boolean
-
1
class_option :resource_route, type: :boolean
-
1
class_option :scaffold_stylesheet, type: :boolean
-
-
1
def handle_skip
-
@options = @options.merge(stylesheets: false) unless options[:assets]
-
@options = @options.merge(stylesheet_engine: false) unless options[:stylesheets] && options[:scaffold_stylesheet]
-
end
-
-
1
hook_for :scaffold_controller, required: true
-
-
1
hook_for :assets do |assets|
-
invoke assets, [controller_name]
-
end
-
-
1
hook_for :stylesheet_engine do |stylesheet_engine|
-
if behavior == :invoke
-
invoke stylesheet_engine, [controller_name]
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
require "rails/generators/resource_helpers"
-
-
1
module Rails
-
1
module Generators
-
1
class ScaffoldControllerGenerator < NamedBase # :nodoc:
-
1
include ResourceHelpers
-
-
1
check_class_collision suffix: "Controller"
-
-
1
class_option :helper, type: :boolean
-
1
class_option :orm, banner: "NAME", type: :string, required: true,
-
desc: "ORM to generate the controller for"
-
1
class_option :api, type: :boolean,
-
desc: "Generates API controller"
-
-
1
class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb."
-
-
1
argument :attributes, type: :array, default: [], banner: "field:type field:type"
-
-
1
def create_controller_files
-
template_file = options.api? ? "api_controller.rb" : "controller.rb"
-
template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb")
-
end
-
-
1
hook_for :template_engine, as: :scaffold do |template_engine|
-
invoke template_engine unless options.api?
-
end
-
-
1
hook_for :resource_route, required: true do |route|
-
invoke route unless options.skip_routes?
-
end
-
-
1
hook_for :test_framework, as: :scaffold
-
-
# Invoke the helper using the controller name (pluralized)
-
1
hook_for :helper, as: :scaffold do |invoked|
-
invoke invoked, [ controller_name ]
-
end
-
-
1
private
-
1
def permitted_params
-
attachments, others = attributes_names.partition { |name| attachments?(name) }
-
params = others.map { |name| ":#{name}" }
-
params += attachments.map { |name| "#{name}: []" }
-
params.join(", ")
-
end
-
-
1
def attachments?(name)
-
attribute = attributes.find { |attr| attr.name == name }
-
attribute&.attachments?
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class SystemTestGenerator < NamedBase # :nodoc:
-
1
hook_for :system_tests, as: :system
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
1
module Rails
-
1
module Generators
-
1
class TaskGenerator < NamedBase # :nodoc:
-
1
argument :actions, type: :array, default: [], banner: "action action"
-
-
1
def create_task_files
-
template "task.rb", File.join("lib/tasks", "#{file_name}.rake")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
2
require "rails/generators/active_model"
-
2
require "rails/generators/model_helpers"
-
-
2
module Rails
-
2
module Generators
-
# Deal with controller names on scaffold and add some helpers to deal with
-
# ActiveModel.
-
2
module ResourceHelpers # :nodoc:
-
2
def self.included(base) #:nodoc:
-
2
base.include(Rails::Generators::ModelHelpers)
-
2
base.class_option :model_name, type: :string, desc: "ModelName to be used"
-
end
-
-
# Set controller variables on initialization.
-
2
def initialize(*args) #:nodoc:
-
super
-
controller_name = name
-
if options[:model_name]
-
self.name = options[:model_name]
-
assign_names!(name)
-
end
-
-
assign_controller_names!(controller_name.pluralize)
-
end
-
-
2
private
-
2
attr_reader :controller_name, :controller_file_name
-
-
2
def controller_class_path
-
if options[:model_name]
-
@controller_class_path
-
else
-
class_path
-
end
-
end
-
-
2
def assign_controller_names!(name)
-
@controller_name = name
-
@controller_class_path = name.include?("/") ? name.split("/") : name.split("::")
-
@controller_class_path.map!(&:underscore)
-
@controller_file_name = @controller_class_path.pop
-
end
-
-
2
def controller_file_path
-
@controller_file_path ||= (controller_class_path + [controller_file_name]).join("/")
-
end
-
-
2
def controller_class_name
-
(controller_class_path + [controller_file_name]).map!(&:camelize).join("::")
-
end
-
-
2
def controller_i18n_scope
-
@controller_i18n_scope ||= controller_file_path.tr("/", ".")
-
end
-
-
# Loads the ORM::Generators::ActiveModel class. This class is responsible
-
# to tell scaffold entities how to generate a specific method for the
-
# ORM. Check Rails::Generators::ActiveModel for more information.
-
2
def orm_class
-
@orm_class ||= begin
-
# Raise an error if the class_option :orm was not defined.
-
unless self.class.class_options[:orm]
-
raise "You need to have :orm as class option to invoke orm_class and orm_instance"
-
end
-
-
begin
-
"#{options[:orm].to_s.camelize}::Generators::ActiveModel".constantize
-
rescue NameError
-
Rails::Generators::ActiveModel
-
end
-
end
-
end
-
-
# Initialize ORM::Generators::ActiveModel to access instance methods.
-
2
def orm_instance(name = singular_table_name)
-
@orm_instance ||= orm_class.new(name)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
require "rails/generators"
-
16
require "rails/generators/testing/behaviour"
-
16
require "rails/generators/testing/setup_and_teardown"
-
16
require "rails/generators/testing/assertions"
-
16
require "fileutils"
-
-
16
module Rails
-
16
module Generators
-
# Disable color in output. Easier to debug.
-
16
no_color!
-
-
# This class provides a TestCase for testing generators. To set up, you need
-
# just to configure the destination and set which generator is being tested:
-
#
-
# class AppGeneratorTest < Rails::Generators::TestCase
-
# tests AppGenerator
-
# destination File.expand_path("../tmp", __dir__)
-
# end
-
#
-
# If you want to ensure your destination root is clean before running each test,
-
# you can set a setup callback:
-
#
-
# class AppGeneratorTest < Rails::Generators::TestCase
-
# tests AppGenerator
-
# destination File.expand_path("../tmp", __dir__)
-
# setup :prepare_destination
-
# end
-
16
class TestCase < ActiveSupport::TestCase
-
16
include Rails::Generators::Testing::Behaviour
-
16
include Rails::Generators::Testing::SetupAndTeardown
-
16
include Rails::Generators::Testing::Assertions
-
16
include FileUtils
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/named_base"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class Base < Rails::Generators::NamedBase # :nodoc:
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class ControllerGenerator < Base # :nodoc:
-
argument :actions, type: :array, default: [], banner: "action action"
-
class_option :skip_routes, type: :boolean
-
-
check_class_collision suffix: "ControllerTest"
-
-
def create_test_files
-
template "functional_test.rb",
-
File.join("test/controllers", class_path, "#{file_name}_controller_test.rb")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class GeneratorGenerator < Base # :nodoc:
-
check_class_collision suffix: "GeneratorTest"
-
-
class_option :namespace, type: :boolean, default: true,
-
desc: "Namespace generator under lib/generators/name"
-
-
def create_generator_files
-
template "generator_test.rb", File.join("test/lib/generators", class_path, "#{file_name}_generator_test.rb")
-
end
-
-
private
-
def generator_path
-
if options[:namespace]
-
File.join("generators", regular_class_path, file_name, "#{file_name}_generator")
-
else
-
File.join("generators", regular_class_path, "#{file_name}_generator")
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class HelperGenerator < Base # :nodoc:
-
# Rails does not generate anything here.
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class IntegrationGenerator < Base # :nodoc:
-
check_class_collision suffix: "Test"
-
-
def create_test_files
-
template "integration_test.rb", File.join("test/integration", class_path, "#{file_name}_test.rb")
-
end
-
-
private
-
def file_name
-
@_file_name ||= super.sub(/_test\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class JobGenerator < Base # :nodoc:
-
check_class_collision suffix: "JobTest"
-
-
def create_test_file
-
template "unit_test.rb", File.join("test/jobs", class_path, "#{file_name}_job_test.rb")
-
end
-
-
private
-
def file_name
-
@_file_name ||= super.sub(/_job\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class MailerGenerator < Base # :nodoc:
-
argument :actions, type: :array, default: [], banner: "method method"
-
-
def check_class_collision
-
class_collisions "#{class_name}MailerTest", "#{class_name}MailerPreview"
-
end
-
-
def create_test_files
-
template "functional_test.rb", File.join("test/mailers", class_path, "#{file_name}_mailer_test.rb")
-
end
-
-
def create_preview_files
-
template "preview.rb", File.join("test/mailers/previews", class_path, "#{file_name}_mailer_preview.rb")
-
end
-
-
private
-
def file_name
-
@_file_name ||= super.sub(/_mailer\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class ModelGenerator < Base # :nodoc:
-
RESERVED_YAML_KEYWORDS = %w(y yes n no true false on off null)
-
-
argument :attributes, type: :array, default: [], banner: "field:type field:type"
-
class_option :fixture, type: :boolean
-
-
check_class_collision suffix: "Test"
-
-
def create_test_file
-
template "unit_test.rb", File.join("test/models", class_path, "#{file_name}_test.rb")
-
end
-
-
hook_for :fixture_replacement
-
-
def create_fixture_file
-
if options[:fixture] && options[:fixture_replacement].nil?
-
template "fixtures.yml", File.join("test/fixtures", class_path, "#{fixture_file_name}.yml")
-
end
-
end
-
-
private
-
def yaml_key_value(key, value)
-
if RESERVED_YAML_KEYWORDS.include?(key.downcase)
-
"'#{key}': #{value}"
-
else
-
"#{key}: #{value}"
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class PluginGenerator < Base # :nodoc:
-
check_class_collision suffix: "Test"
-
-
def create_test_files
-
directory ".", "test"
-
end
-
end
-
end
-
end
-
require "active_support/testing/autorun"
-
require "active_support"
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
require "rails/generators/resource_helpers"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class ScaffoldGenerator < Base # :nodoc:
-
include Rails::Generators::ResourceHelpers
-
-
check_class_collision suffix: "ControllerTest"
-
-
class_option :api, type: :boolean,
-
desc: "Generates API functional tests"
-
-
class_option :system_tests, type: :string,
-
desc: "Skip system test files"
-
-
argument :attributes, type: :array, default: [], banner: "field:type field:type"
-
-
def create_test_files
-
template_file = options.api? ? "api_functional_test.rb" : "functional_test.rb"
-
template template_file,
-
File.join("test/controllers", controller_class_path, "#{controller_file_name}_controller_test.rb")
-
-
if !options.api? && options[:system_tests]
-
template "system_test.rb", File.join("test/system", class_path, "#{file_name.pluralize}_test.rb")
-
end
-
end
-
-
def fixture_name
-
@fixture_name ||=
-
if mountable_engine?
-
(namespace_dirs + [table_name]).join("_")
-
else
-
table_name
-
end
-
end
-
-
private
-
def attributes_string
-
attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ")
-
end
-
-
def attributes_hash
-
return {} if attributes_names.empty?
-
-
attributes_names.map do |name|
-
if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?)
-
["#{name}", "'secret'"]
-
elsif !virtual?(name)
-
["#{name}", "@#{singular_table_name}.#{name}"]
-
end
-
end.compact.sort.to_h
-
end
-
-
def boolean?(name)
-
attribute = attributes.find { |attr| attr.name == name }
-
attribute&.type == :boolean
-
end
-
-
def virtual?(name)
-
attribute = attributes.find { |attr| attr.name == name }
-
attribute&.virtual?
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/generators/test_unit"
-
-
module TestUnit # :nodoc:
-
module Generators # :nodoc:
-
class SystemGenerator < Base # :nodoc:
-
check_class_collision suffix: "Test"
-
-
def create_test_files
-
if !File.exist?(File.join("test/application_system_test_case.rb"))
-
template "application_system_test_case.rb", File.join("test", "application_system_test_case.rb")
-
end
-
-
template "system_test.rb", File.join("test/system", class_path, "#{file_name.pluralize}_test.rb")
-
end
-
-
private
-
def file_name
-
@_file_name ||= super.sub(/_test\z/i, "")
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
module Rails
-
16
module Generators
-
16
module Testing
-
16
module Assertions
-
# Asserts a given file exists. You need to supply an absolute path or a path relative
-
# to the configured destination:
-
#
-
# assert_file "config/environment.rb"
-
#
-
# You can also give extra arguments. If the argument is a regexp, it will check if the
-
# regular expression matches the given file content. If it's a string, it compares the
-
# file with the given string:
-
#
-
# assert_file "config/environment.rb", /initialize/
-
#
-
# Finally, when a block is given, it yields the file content:
-
#
-
# assert_file "app/controllers/products_controller.rb" do |controller|
-
# assert_instance_method :index, controller do |index|
-
# assert_match(/Product\.all/, index)
-
# end
-
# end
-
16
def assert_file(relative, *contents)
-
absolute = File.expand_path(relative, destination_root)
-
assert File.exist?(absolute), "Expected file #{relative.inspect} to exist, but does not"
-
-
read = File.read(absolute) if block_given? || !contents.empty?
-
assert_nothing_raised { yield read } if block_given?
-
-
contents.each do |content|
-
case content
-
when String
-
assert_equal content, read
-
when Regexp
-
assert_match content, read
-
end
-
end
-
end
-
16
alias :assert_directory :assert_file
-
-
# Asserts a given file does not exist. You need to supply an absolute path or a
-
# path relative to the configured destination:
-
#
-
# assert_no_file "config/random.rb"
-
16
def assert_no_file(relative)
-
absolute = File.expand_path(relative, destination_root)
-
assert !File.exist?(absolute), "Expected file #{relative.inspect} to not exist, but does"
-
end
-
16
alias :assert_no_directory :assert_no_file
-
-
# Asserts a given migration exists. You need to supply an absolute path or a
-
# path relative to the configured destination:
-
#
-
# assert_migration "db/migrate/create_products.rb"
-
#
-
# This method manipulates the given path and tries to find any migration which
-
# matches the migration name. For example, the call above is converted to:
-
#
-
# assert_file "db/migrate/003_create_products.rb"
-
#
-
# Consequently, assert_migration accepts the same arguments has assert_file.
-
16
def assert_migration(relative, *contents, &block)
-
file_name = migration_file_name(relative)
-
assert file_name, "Expected migration #{relative} to exist, but was not found"
-
assert_file file_name, *contents, &block
-
end
-
-
# Asserts a given migration does not exist. You need to supply an absolute path or a
-
# path relative to the configured destination:
-
#
-
# assert_no_migration "db/migrate/create_products.rb"
-
16
def assert_no_migration(relative)
-
file_name = migration_file_name(relative)
-
assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
-
end
-
-
# Asserts the given class method exists in the given content. This method does not detect
-
# class methods inside (class << self), only class methods which starts with "self.".
-
# When a block is given, it yields the content of the method.
-
#
-
# assert_migration "db/migrate/create_products.rb" do |migration|
-
# assert_class_method :up, migration do |up|
-
# assert_match(/create_table/, up)
-
# end
-
# end
-
16
def assert_class_method(method, content, &block)
-
assert_instance_method "self.#{method}", content, &block
-
end
-
-
# Asserts the given method exists in the given content. When a block is given,
-
# it yields the content of the method.
-
#
-
# assert_file "app/controllers/products_controller.rb" do |controller|
-
# assert_instance_method :index, controller do |index|
-
# assert_match(/Product\.all/, index)
-
# end
-
# end
-
16
def assert_instance_method(method, content)
-
assert content =~ /(\s+)def #{method}(\(.+\))?(.*?)\n\1end/m, "Expected to have method #{method}"
-
assert_nothing_raised { yield $3.strip } if block_given?
-
end
-
16
alias :assert_method :assert_instance_method
-
-
# Asserts the given attribute type gets translated to a field type
-
# properly:
-
#
-
# assert_field_type :date, :date_select
-
16
def assert_field_type(attribute_type, field_type)
-
assert_equal(field_type, create_generated_attribute(attribute_type).field_type)
-
end
-
-
# Asserts the given attribute type gets a proper default value:
-
#
-
# assert_field_default_value :string, "MyString"
-
16
def assert_field_default_value(attribute_type, value)
-
if value.nil?
-
assert_nil(create_generated_attribute(attribute_type).default)
-
else
-
assert_equal(value, create_generated_attribute(attribute_type).default)
-
end
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
require "active_support/core_ext/class/attribute"
-
16
require "active_support/core_ext/module/delegation"
-
16
require "active_support/core_ext/hash/reverse_merge"
-
16
require "active_support/core_ext/kernel/reporting"
-
16
require "active_support/testing/stream"
-
16
require "active_support/concern"
-
16
require "rails/generators"
-
-
16
module Rails
-
16
module Generators
-
16
module Testing
-
16
module Behaviour
-
16
extend ActiveSupport::Concern
-
16
include ActiveSupport::Testing::Stream
-
-
16
included do
-
# Generators frequently change the current path using +FileUtils.cd+.
-
# So we need to store the path at file load and revert back to it after each test.
-
16
class_attribute :current_path, default: File.expand_path(Dir.pwd)
-
16
class_attribute :default_arguments, default: []
-
16
class_attribute :destination_root
-
16
class_attribute :generator_class
-
end
-
-
16
module ClassMethods
-
# Sets which generator should be tested:
-
#
-
# tests AppGenerator
-
16
def tests(klass)
-
22
self.generator_class = klass
-
end
-
-
# Sets default arguments on generator invocation. This can be overwritten when
-
# invoking it.
-
#
-
# arguments %w(app_name --skip-active-record)
-
16
def arguments(array)
-
14
self.default_arguments = array
-
end
-
-
# Sets the destination of generator files:
-
#
-
# destination File.expand_path("../tmp", __dir__)
-
16
def destination(path)
-
19
self.destination_root = path
-
end
-
end
-
-
# Runs the generator configured for this class. The first argument is an array like
-
# command line arguments:
-
#
-
# class AppGeneratorTest < Rails::Generators::TestCase
-
# tests AppGenerator
-
# destination File.expand_path("../tmp", __dir__)
-
# setup :prepare_destination
-
#
-
# test "database.yml is not created when skipping Active Record" do
-
# run_generator %w(myapp --skip-active-record)
-
# assert_no_file "config/database.yml"
-
# end
-
# end
-
#
-
# You can provide a configuration hash as second argument. This method returns the output
-
# printed by the generator.
-
16
def run_generator(args = default_arguments, config = {})
-
capture(:stdout) do
-
args += ["--skip-bundle"] unless args.include? "--dev"
-
args |= ["--skip-bootsnap"] unless args.include? "--no-skip-bootsnap"
-
args |= ["--skip-webpack-install"] unless args.include? "--no-skip-webpack-install"
-
-
generator_class.start(args, config.reverse_merge(destination_root: destination_root))
-
end
-
end
-
-
# Instantiate the generator.
-
16
def generator(args = default_arguments, options = {}, config = {})
-
@generator ||= generator_class.new(args, options, config.reverse_merge(destination_root: destination_root))
-
end
-
-
# Create a Rails::Generators::GeneratedAttribute by supplying the
-
# attribute type and, optionally, the attribute name:
-
#
-
# create_generated_attribute(:string, 'name')
-
16
def create_generated_attribute(attribute_type, name = "test", index = nil)
-
Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(":"))
-
end
-
-
16
private
-
16
def destination_root_is_set?
-
raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root
-
end
-
-
16
def ensure_current_path
-
cd current_path
-
end
-
-
# Clears all files and directories in destination.
-
16
def prepare_destination # :doc:
-
rm_rf(destination_root)
-
mkdir_p(destination_root)
-
end
-
-
16
def migration_file_name(relative)
-
absolute = File.expand_path(relative, destination_root)
-
dirname, file_name = File.dirname(absolute), File.basename(absolute).delete_suffix(".rb")
-
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
16
module Rails
-
16
module Generators
-
16
module Testing
-
16
module SetupAndTeardown
-
16
def setup # :nodoc:
-
destination_root_is_set?
-
ensure_current_path
-
super
-
end
-
-
16
def teardown # :nodoc:
-
ensure_current_path
-
super
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "cgi"
-
-
module Rails
-
# This module helps build the runtime properties that are displayed in
-
# Rails::InfoController responses. These include the active Rails version,
-
# Ruby version, Rack version, and so on.
-
module Info
-
mattr_accessor :properties, default: []
-
-
class << @@properties
-
def names
-
map(&:first)
-
end
-
-
def value_for(property_name)
-
if property = assoc(property_name)
-
property.last
-
end
-
end
-
end
-
-
class << self #:nodoc:
-
def property(name, value = nil)
-
value ||= yield
-
properties << [name, value] if value
-
rescue Exception
-
end
-
-
def to_s
-
column_width = properties.names.map(&:length).max
-
info = properties.map do |name, value|
-
value = value.join(", ") if value.is_a?(Array)
-
"%-#{column_width}s %s" % [name, value]
-
end
-
info.unshift "About your application's environment"
-
info * "\n"
-
end
-
-
alias inspect to_s
-
-
def to_html
-
(+"<table>").tap do |table|
-
properties.each do |(name, value)|
-
table << %(<tr><td class="name">#{CGI.escapeHTML(name.to_s)}</td>)
-
formatted_value = if value.kind_of?(Array)
-
"<ul>" + value.map { |v| "<li>#{CGI.escapeHTML(v.to_s)}</li>" }.join + "</ul>"
-
else
-
CGI.escapeHTML(value.to_s)
-
end
-
table << %(<td class="value">#{formatted_value}</td></tr>)
-
end
-
table << "</table>"
-
end
-
end
-
end
-
-
# The Rails version.
-
property "Rails version" do
-
Rails.version.to_s
-
end
-
-
# The Ruby version and platform, e.g. "2.0.0-p247 (x86_64-darwin12.4.0)".
-
property "Ruby version" do
-
RUBY_DESCRIPTION
-
end
-
-
# The RubyGems version, if it's installed.
-
property "RubyGems version" do
-
Gem::VERSION
-
end
-
-
property "Rack version" do
-
::Rack.release
-
end
-
-
property "JavaScript Runtime" do
-
ExecJS.runtime.name
-
end
-
-
property "Middleware" do
-
Rails.configuration.middleware.map(&:inspect)
-
end
-
-
# The application's location on the filesystem.
-
property "Application root" do
-
File.expand_path(Rails.root)
-
end
-
-
# The current Rails environment (development, test, or production).
-
property "Environment" do
-
Rails.env
-
end
-
-
# The name of the database adapter for the current environment.
-
property "Database adapter" do
-
ActiveRecord::Base.connection.pool.db_config.adapter
-
end
-
-
property "Database schema version" do
-
ActiveRecord::Base.connection.migration_context.current_version rescue nil
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/application_controller"
-
require "action_dispatch/routing/inspector"
-
-
class Rails::InfoController < Rails::ApplicationController # :nodoc:
-
prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATH
-
layout -> { request.xhr? ? false : "application" }
-
-
before_action :require_local!
-
-
def index
-
redirect_to action: :routes
-
end
-
-
def properties
-
@info = Rails::Info.to_html
-
@page_title = "Properties"
-
end
-
-
def routes
-
if path = params[:path]
-
path = URI::DEFAULT_PARSER.escape path
-
normalized_path = with_leading_slash path
-
render json: {
-
exact: match_route { |it| it.match normalized_path },
-
fuzzy: match_route { |it| it.spec.to_s.match path }
-
}
-
else
-
@routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes)
-
@page_title = "Routes"
-
end
-
end
-
-
private
-
def match_route
-
_routes.routes.select { |route|
-
yield route.path
-
}.map { |route| route.path.spec.to_s }
-
end
-
-
def with_leading_slash(path)
-
("/" + path).squeeze("/")
-
end
-
end
-
# frozen_string_literal: true
-
-
require "tsort"
-
-
module Rails
-
module Initializable
-
def self.included(base) #:nodoc:
-
base.extend ClassMethods
-
end
-
-
class Initializer
-
attr_reader :name, :block
-
-
def initialize(name, context, options, &block)
-
options[:group] ||= :default
-
@name, @context, @options, @block = name, context, options, block
-
end
-
-
def before
-
@options[:before]
-
end
-
-
def after
-
@options[:after]
-
end
-
-
def belongs_to?(group)
-
@options[:group] == group || @options[:group] == :all
-
end
-
-
def run(*args)
-
@context.instance_exec(*args, &block)
-
end
-
-
def bind(context)
-
return self if @context
-
Initializer.new(@name, context, @options, &block)
-
end
-
-
def context_class
-
@context.class
-
end
-
end
-
-
class Collection < Array
-
include TSort
-
-
alias :tsort_each_node :each
-
def tsort_each_child(initializer, &block)
-
select { |i| i.before == initializer.name || i.name == initializer.after }.each(&block)
-
end
-
-
def +(other)
-
Collection.new(to_a + other.to_a)
-
end
-
end
-
-
def run_initializers(group = :default, *args)
-
return if instance_variable_defined?(:@ran)
-
initializers.tsort_each do |initializer|
-
initializer.run(*args) if initializer.belongs_to?(group)
-
end
-
@ran = true
-
end
-
-
def initializers
-
@initializers ||= self.class.initializers_for(self)
-
end
-
-
module ClassMethods
-
def initializers
-
@initializers ||= Collection.new
-
end
-
-
def initializers_chain
-
initializers = Collection.new
-
ancestors.reverse_each do |klass|
-
next unless klass.respond_to?(:initializers)
-
initializers = initializers + klass.initializers
-
end
-
initializers
-
end
-
-
def initializers_for(binding)
-
Collection.new(initializers_chain.map { |i| i.bind(binding) })
-
end
-
-
def initializer(name, opts = {}, &blk)
-
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
-
opts[:after] ||= initializers.last.name unless initializers.empty? || initializers.find { |i| i.name == opts[:before] }
-
initializers << Initializer.new(name, nil, opts, &blk)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/application_controller"
-
-
class Rails::MailersController < Rails::ApplicationController # :nodoc:
-
prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATH
-
-
around_action :set_locale, only: :preview
-
before_action :find_preview, only: :preview
-
before_action :require_local!, unless: :show_previews?
-
-
helper_method :part_query, :locale_query
-
-
content_security_policy(false)
-
-
def index
-
@previews = ActionMailer::Preview.all
-
@page_title = "Mailer Previews"
-
end
-
-
def preview
-
if params[:path] == @preview.preview_name
-
@page_title = "Mailer Previews for #{@preview.preview_name}"
-
render action: "mailer"
-
else
-
@email_action = File.basename(params[:path])
-
-
if @preview.email_exists?(@email_action)
-
@page_title = "Mailer Preview for #{@preview.preview_name}##{@email_action}"
-
@email = @preview.call(@email_action, params)
-
-
if params[:part]
-
part_type = Mime::Type.lookup(params[:part])
-
-
if part = find_part(part_type)
-
response.content_type = part_type
-
render plain: part.respond_to?(:decoded) ? part.decoded : part
-
else
-
raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{@email_action}"
-
end
-
else
-
@part = find_preferred_part(request.format, Mime[:html], Mime[:text])
-
render action: "email", layout: false, formats: [:html]
-
end
-
else
-
raise AbstractController::ActionNotFound, "Email '#{@email_action}' not found in #{@preview.name}"
-
end
-
end
-
end
-
-
private
-
def show_previews? # :doc:
-
ActionMailer::Base.show_previews
-
end
-
-
def find_preview # :doc:
-
candidates = []
-
params[:path].to_s.scan(%r{/|$}) { candidates << $` }
-
preview = candidates.detect { |candidate| ActionMailer::Preview.exists?(candidate) }
-
-
if preview
-
@preview = ActionMailer::Preview.find(preview)
-
else
-
raise AbstractController::ActionNotFound, "Mailer preview '#{params[:path]}' not found"
-
end
-
end
-
-
def find_preferred_part(*formats) # :doc:
-
formats.each do |format|
-
if part = @email.find_first_mime_type(format)
-
return part
-
end
-
end
-
-
if formats.any? { |f| @email.mime_type == f }
-
@email
-
end
-
end
-
-
def find_part(format) # :doc:
-
if part = @email.find_first_mime_type(format)
-
part
-
elsif @email.mime_type == format
-
@email
-
end
-
end
-
-
def part_query(mime_type)
-
request.query_parameters.merge(part: mime_type).to_query
-
end
-
-
def locale_query(locale)
-
request.query_parameters.merge(locale: locale).to_query
-
end
-
-
def set_locale
-
I18n.with_locale(params[:locale] || I18n.default_locale) do
-
yield
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "pathname"
-
-
module Rails
-
module Paths
-
# This object is an extended hash that behaves as root of the <tt>Rails::Paths</tt> system.
-
# It allows you to collect information about how you want to structure your application
-
# paths through a Hash-like API. It requires you to give a physical path on initialization.
-
#
-
# root = Root.new "/rails"
-
# root.add "app/controllers", eager_load: true
-
#
-
# The above command creates a new root object and adds "app/controllers" as a path.
-
# This means we can get a <tt>Rails::Paths::Path</tt> object back like below:
-
#
-
# path = root["app/controllers"]
-
# path.eager_load? # => true
-
# path.is_a?(Rails::Paths::Path) # => true
-
#
-
# The +Path+ object is simply an enumerable and allows you to easily add extra paths:
-
#
-
# path.is_a?(Enumerable) # => true
-
# path.to_ary.inspect # => ["app/controllers"]
-
#
-
# path << "lib/controllers"
-
# path.to_ary.inspect # => ["app/controllers", "lib/controllers"]
-
#
-
# Notice that when you add a path using +add+, the path object created already
-
# contains the path with the same path value given to +add+. In some situations,
-
# you may not want this behavior, so you can give <tt>:with</tt> as option.
-
#
-
# root.add "config/routes", with: "config/routes.rb"
-
# root["config/routes"].inspect # => ["config/routes.rb"]
-
#
-
# The +add+ method accepts the following options as arguments:
-
# eager_load, autoload, autoload_once, and glob.
-
#
-
# Finally, the +Path+ object also provides a few helpers:
-
#
-
# root = Root.new "/rails"
-
# root.add "app/controllers"
-
#
-
# root["app/controllers"].expanded # => ["/rails/app/controllers"]
-
# root["app/controllers"].existent # => ["/rails/app/controllers"]
-
#
-
# Check the <tt>Rails::Paths::Path</tt> documentation for more information.
-
class Root
-
attr_accessor :path
-
-
def initialize(path)
-
@path = path
-
@root = {}
-
end
-
-
def []=(path, value)
-
glob = self[path] ? self[path].glob : nil
-
add(path, with: value, glob: glob)
-
end
-
-
def add(path, options = {})
-
with = Array(options.fetch(:with, path))
-
@root[path] = Path.new(self, path, with, options)
-
end
-
-
def [](path)
-
@root[path]
-
end
-
-
def values
-
@root.values
-
end
-
-
def keys
-
@root.keys
-
end
-
-
def values_at(*list)
-
@root.values_at(*list)
-
end
-
-
def all_paths
-
values.tap(&:uniq!)
-
end
-
-
def autoload_once
-
filter_by(&:autoload_once?)
-
end
-
-
def eager_load
-
filter_by(&:eager_load?)
-
end
-
-
def autoload_paths
-
filter_by(&:autoload?)
-
end
-
-
def load_paths
-
filter_by(&:load_path?)
-
end
-
-
private
-
def filter_by(&block)
-
all_paths.find_all(&block).flat_map { |path|
-
paths = path.existent
-
paths - path.children.flat_map { |p| yield(p) ? [] : p.existent }
-
}.uniq
-
end
-
end
-
-
class Path
-
include Enumerable
-
-
attr_accessor :glob
-
-
def initialize(root, current, paths, options = {})
-
@paths = paths
-
@current = current
-
@root = root
-
@glob = options[:glob]
-
@exclude = options[:exclude]
-
-
options[:autoload_once] ? autoload_once! : skip_autoload_once!
-
options[:eager_load] ? eager_load! : skip_eager_load!
-
options[:autoload] ? autoload! : skip_autoload!
-
options[:load_path] ? load_path! : skip_load_path!
-
end
-
-
def absolute_current # :nodoc:
-
File.expand_path(@current, @root.path)
-
end
-
-
def children
-
keys = @root.keys.find_all { |k|
-
k.start_with?(@current) && k != @current
-
}
-
@root.values_at(*keys.sort)
-
end
-
-
def first
-
expanded.first
-
end
-
-
def last
-
expanded.last
-
end
-
-
%w(autoload_once eager_load autoload load_path).each do |m|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def #{m}! # def eager_load!
-
@#{m} = true # @eager_load = true
-
end # end
-
#
-
def skip_#{m}! # def skip_eager_load!
-
@#{m} = false # @eager_load = false
-
end # end
-
#
-
def #{m}? # def eager_load?
-
@#{m} # @eager_load
-
end # end
-
RUBY
-
end
-
-
def each(&block)
-
@paths.each(&block)
-
end
-
-
def <<(path)
-
@paths << path
-
end
-
alias :push :<<
-
-
def concat(paths)
-
@paths.concat paths
-
end
-
-
def unshift(*paths)
-
@paths.unshift(*paths)
-
end
-
-
def to_ary
-
@paths
-
end
-
-
def paths
-
raise "You need to set a path root" unless @root.path
-
-
map do |p|
-
Pathname.new(@root.path).join(p)
-
end
-
end
-
-
def extensions # :nodoc:
-
$1.split(",") if @glob =~ /\{([\S]+)\}/
-
end
-
-
# Expands all paths against the root and return all unique values.
-
def expanded
-
raise "You need to set a path root" unless @root.path
-
result = []
-
-
each do |path|
-
path = File.expand_path(path, @root.path)
-
-
if @glob && File.directory?(path)
-
result.concat files_in(path)
-
else
-
result << path
-
end
-
end
-
-
result.uniq!
-
result
-
end
-
-
# Returns all expanded paths but only if they exist in the filesystem.
-
def existent
-
expanded.select do |f|
-
does_exist = File.exist?(f)
-
-
if !does_exist && File.symlink?(f)
-
raise "File #{f.inspect} is a symlink that does not point to a valid file"
-
end
-
does_exist
-
end
-
end
-
-
def existent_directories
-
expanded.select { |d| File.directory?(d) }
-
end
-
-
alias to_a expanded
-
-
private
-
def files_in(path)
-
files = Dir.glob(@glob, base: path)
-
files -= @exclude if @exclude
-
files.map! { |file| File.join(path, file) }
-
files.sort
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/test_unit/runner"
-
require "rails/test_unit/reporter"
-
-
Rails::TestUnitReporter.executable = "bin/test"
-
-
Rails::TestUnit::Runner.parse_options(ARGV)
-
Rails::TestUnit::Runner.run(ARGV)
-
# frozen_string_literal: true
-
-
module Rails
-
module Rack
-
autoload :Logger, "rails/rack/logger"
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/core_ext/time/conversions"
-
require "active_support/core_ext/object/blank"
-
require "active_support/log_subscriber"
-
require "action_dispatch/http/request"
-
require "rack/body_proxy"
-
-
module Rails
-
module Rack
-
# Sets log tags, logs the request, calls the app, and flushes the logs.
-
#
-
# Log tags (+taggers+) can be an Array containing: methods that the +request+
-
# object responds to, objects that respond to +to_s+ or Proc objects that accept
-
# an instance of the +request+ object.
-
class Logger < ActiveSupport::LogSubscriber
-
def initialize(app, taggers = nil)
-
@app = app
-
@taggers = taggers || []
-
end
-
-
def call(env)
-
request = ActionDispatch::Request.new(env)
-
-
if logger.respond_to?(:tagged)
-
logger.tagged(compute_tags(request)) { call_app(request, env) }
-
else
-
call_app(request, env)
-
end
-
end
-
-
private
-
def call_app(request, env) # :doc:
-
instrumenter = ActiveSupport::Notifications.instrumenter
-
instrumenter.start "request.action_dispatch", request: request
-
logger.info { started_request_message(request) }
-
status, headers, body = @app.call(env)
-
body = ::Rack::BodyProxy.new(body) { finish(request) }
-
[status, headers, body]
-
rescue Exception
-
finish(request)
-
raise
-
ensure
-
ActiveSupport::LogSubscriber.flush_all!
-
end
-
-
# Started GET "/session/new" for 127.0.0.1 at 2012-09-26 14:51:42 -0700
-
def started_request_message(request) # :doc:
-
'Started %s "%s" for %s at %s' % [
-
request.request_method,
-
request.filtered_path,
-
request.remote_ip,
-
Time.now.to_default_s ]
-
end
-
-
def compute_tags(request) # :doc:
-
@taggers.collect do |tag|
-
case tag
-
when Proc
-
tag.call(request)
-
when Symbol
-
request.send(tag)
-
else
-
tag
-
end
-
end
-
end
-
-
def finish(request)
-
instrumenter = ActiveSupport::Notifications.instrumenter
-
instrumenter.finish "request.action_dispatch", request: request
-
end
-
-
def logger
-
Rails.logger
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/initializable"
-
require "active_support/inflector"
-
require "active_support/core_ext/module/introspection"
-
require "active_support/core_ext/module/delegation"
-
-
module Rails
-
# <tt>Rails::Railtie</tt> is the core of the Rails framework and provides
-
# several hooks to extend Rails and/or modify the initialization process.
-
#
-
# Every major component of Rails (Action Mailer, Action Controller, Active
-
# Record, etc.) implements a railtie. Each of them is responsible for their
-
# own initialization. This makes Rails itself absent of any component hooks,
-
# allowing other components to be used in place of any of the Rails defaults.
-
#
-
# Developing a Rails extension does _not_ require implementing a railtie, but
-
# if you need to interact with the Rails framework during or after boot, then
-
# a railtie is needed.
-
#
-
# For example, an extension doing any of the following would need a railtie:
-
#
-
# * creating initializers
-
# * configuring a Rails framework for the application, like setting a generator
-
# * adding <tt>config.*</tt> keys to the environment
-
# * setting up a subscriber with <tt>ActiveSupport::Notifications</tt>
-
# * adding Rake tasks
-
#
-
# == Creating a Railtie
-
#
-
# To extend Rails using a railtie, create a subclass of <tt>Rails::Railtie</tt>.
-
# This class must be loaded during the Rails boot process, and is conventionally
-
# called <tt>MyNamespace::Railtie</tt>.
-
#
-
# The following example demonstrates an extension which can be used with or
-
# without Rails.
-
#
-
# # lib/my_gem/railtie.rb
-
# module MyGem
-
# class Railtie < Rails::Railtie
-
# end
-
# end
-
#
-
# # lib/my_gem.rb
-
# require "my_gem/railtie" if defined?(Rails::Railtie)
-
#
-
# == Initializers
-
#
-
# To add an initialization step to the Rails boot process from your railtie, just
-
# define the initialization code with the +initializer+ macro:
-
#
-
# class MyRailtie < Rails::Railtie
-
# initializer "my_railtie.configure_rails_initialization" do
-
# # some initialization behavior
-
# end
-
# end
-
#
-
# If specified, the block can also receive the application object, in case you
-
# need to access some application-specific configuration, like middleware:
-
#
-
# class MyRailtie < Rails::Railtie
-
# initializer "my_railtie.configure_rails_initialization" do |app|
-
# app.middleware.use MyRailtie::Middleware
-
# end
-
# end
-
#
-
# Finally, you can also pass <tt>:before</tt> and <tt>:after</tt> as options to
-
# +initializer+, in case you want to couple it with a specific step in the
-
# initialization process.
-
#
-
# == Configuration
-
#
-
# Railties can access a config object which contains configuration shared by all
-
# railties and the application:
-
#
-
# class MyRailtie < Rails::Railtie
-
# # Customize the ORM
-
# config.app_generators.orm :my_railtie_orm
-
#
-
# # Add a to_prepare block which is executed once in production
-
# # and before each request in development.
-
# config.to_prepare do
-
# MyRailtie.setup!
-
# end
-
# end
-
#
-
# == Loading Rake Tasks and Generators
-
#
-
# If your railtie has Rake tasks, you can tell Rails to load them through the method
-
# +rake_tasks+:
-
#
-
# class MyRailtie < Rails::Railtie
-
# rake_tasks do
-
# load "path/to/my_railtie.tasks"
-
# end
-
# end
-
#
-
# By default, Rails loads generators from your load path. However, if you want to place
-
# your generators at a different location, you can specify in your railtie a block which
-
# will load them during normal generators lookup:
-
#
-
# class MyRailtie < Rails::Railtie
-
# generators do
-
# require "path/to/my_railtie_generator"
-
# end
-
# end
-
#
-
# Since filenames on the load path are shared across gems, be sure that files you load
-
# through a railtie have unique names.
-
#
-
# == Application and Engine
-
#
-
# An engine is nothing more than a railtie with some initializers already set. And since
-
# <tt>Rails::Application</tt> is an engine, the same configuration described here can be
-
# used in both.
-
#
-
# Be sure to look at the documentation of those specific classes for more information.
-
class Railtie
-
autoload :Configuration, "rails/railtie/configuration"
-
-
include Initializable
-
-
ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Engine Rails::Application)
-
-
class << self
-
private :new
-
delegate :config, to: :instance
-
-
def subclasses
-
@subclasses ||= []
-
end
-
-
def inherited(base)
-
unless base.abstract_railtie?
-
subclasses << base
-
end
-
end
-
-
def rake_tasks(&blk)
-
register_block_for(:rake_tasks, &blk)
-
end
-
-
def console(&blk)
-
register_block_for(:load_console, &blk)
-
end
-
-
def runner(&blk)
-
register_block_for(:runner, &blk)
-
end
-
-
def generators(&blk)
-
register_block_for(:generators, &blk)
-
end
-
-
def abstract_railtie?
-
ABSTRACT_RAILTIES.include?(name)
-
end
-
-
def railtie_name(name = nil)
-
@railtie_name = name.to_s if name
-
@railtie_name ||= generate_railtie_name(self.name)
-
end
-
-
# Since Rails::Railtie cannot be instantiated, any methods that call
-
# +instance+ are intended to be called only on subclasses of a Railtie.
-
def instance
-
@instance ||= new
-
end
-
-
# Allows you to configure the railtie. This is the same method seen in
-
# Railtie::Configurable, but this module is no longer required for all
-
# subclasses of Railtie so we provide the class method here.
-
def configure(&block)
-
instance.configure(&block)
-
end
-
-
private
-
def generate_railtie_name(string)
-
ActiveSupport::Inflector.underscore(string).tr("/", "_")
-
end
-
-
def respond_to_missing?(name, _)
-
instance.respond_to?(name) || super
-
end
-
-
# If the class method does not have a method, then send the method call
-
# to the Railtie instance.
-
def method_missing(name, *args, &block)
-
if instance.respond_to?(name)
-
instance.public_send(name, *args, &block)
-
else
-
super
-
end
-
end
-
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
-
-
# receives an instance variable identifier, set the variable value if is
-
# blank and append given block to value, which will be used later in
-
# `#each_registered_block(type, &block)`
-
def register_block_for(type, &blk)
-
var_name = "@#{type}"
-
blocks = instance_variable_defined?(var_name) ? instance_variable_get(var_name) : instance_variable_set(var_name, [])
-
blocks << blk if blk
-
blocks
-
end
-
end
-
-
delegate :railtie_name, to: :class
-
-
def initialize #:nodoc:
-
if self.class.abstract_railtie?
-
raise "#{self.class.name} is abstract, you cannot instantiate it directly."
-
end
-
end
-
-
def configure(&block) #:nodoc:
-
instance_eval(&block)
-
end
-
-
# This is used to create the <tt>config</tt> object on Railties, an instance of
-
# Railtie::Configuration, that is used by Railties and Application to store
-
# related configuration.
-
def config
-
@config ||= Railtie::Configuration.new
-
end
-
-
def railtie_namespace #:nodoc:
-
@railtie_namespace ||= self.class.module_parents.detect { |n| n.respond_to?(:railtie_namespace) }
-
end
-
-
protected
-
def run_console_blocks(app) #:nodoc:
-
each_registered_block(:console) { |block| block.call(app) }
-
end
-
-
def run_generators_blocks(app) #:nodoc:
-
each_registered_block(:generators) { |block| block.call(app) }
-
end
-
-
def run_runner_blocks(app) #:nodoc:
-
each_registered_block(:runner) { |block| block.call(app) }
-
end
-
-
def run_tasks_blocks(app) #:nodoc:
-
extend Rake::DSL
-
each_registered_block(:rake_tasks) { |block| instance_exec(app, &block) }
-
end
-
-
private
-
# run `&block` in every registered block in `#register_block_for`
-
def each_registered_block(type, &block)
-
klass = self.class
-
while klass.respond_to?(type)
-
klass.public_send(type).each(&block)
-
klass = klass.superclass
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/concern"
-
-
module Rails
-
class Railtie
-
module Configurable
-
extend ActiveSupport::Concern
-
-
module ClassMethods
-
delegate :config, to: :instance
-
-
def inherited(base)
-
raise "You cannot inherit from a #{superclass.name} child"
-
end
-
-
def instance
-
@instance ||= new
-
end
-
-
def respond_to?(*args)
-
super || instance.respond_to?(*args)
-
end
-
-
def configure(&block)
-
class_eval(&block)
-
end
-
-
private
-
def method_missing(*args, &block)
-
instance.send(*args, &block)
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/configuration"
-
require "active_support/core_ext/symbol/starts_ends_with"
-
-
module Rails
-
class Railtie
-
class Configuration
-
def initialize
-
@@options ||= {}
-
end
-
-
# Expose the eager_load_namespaces at "module" level for convenience.
-
def self.eager_load_namespaces #:nodoc:
-
@@eager_load_namespaces ||= []
-
end
-
-
# All namespaces that are eager loaded
-
def eager_load_namespaces
-
@@eager_load_namespaces ||= []
-
end
-
-
# Add files that should be watched for change.
-
def watchable_files
-
@@watchable_files ||= []
-
end
-
-
# Add directories that should be watched for change.
-
# The key of the hashes should be directories and the values should
-
# be an array of extensions to match in each directory.
-
def watchable_dirs
-
@@watchable_dirs ||= {}
-
end
-
-
# This allows you to modify the application's middlewares from Engines.
-
#
-
# All operations you run on the app_middleware will be replayed on the
-
# application once it is defined and the default_middlewares are
-
# created
-
def app_middleware
-
@@app_middleware ||= Rails::Configuration::MiddlewareStackProxy.new
-
end
-
-
# This allows you to modify application's generators from Railties.
-
#
-
# Values set on app_generators will become defaults for application, unless
-
# application overwrites them.
-
def app_generators
-
@@app_generators ||= Rails::Configuration::Generators.new
-
yield(@@app_generators) if block_given?
-
@@app_generators
-
end
-
-
# First configurable block to run. Called before any initializers are run.
-
def before_configuration(&block)
-
ActiveSupport.on_load(:before_configuration, yield: true, &block)
-
end
-
-
# Third configurable block to run. Does not run if +config.eager_load+
-
# set to false.
-
def before_eager_load(&block)
-
ActiveSupport.on_load(:before_eager_load, yield: true, &block)
-
end
-
-
# Second configurable block to run. Called before frameworks initialize.
-
def before_initialize(&block)
-
ActiveSupport.on_load(:before_initialize, yield: true, &block)
-
end
-
-
# Last configurable block to run. Called after frameworks initialize.
-
def after_initialize(&block)
-
ActiveSupport.on_load(:after_initialize, yield: true, &block)
-
end
-
-
# Array of callbacks defined by #to_prepare.
-
def to_prepare_blocks
-
@@to_prepare_blocks ||= []
-
end
-
-
# Defines generic callbacks to run before #after_initialize. Useful for
-
# Rails::Railtie subclasses.
-
def to_prepare(&blk)
-
to_prepare_blocks << blk if blk
-
end
-
-
def respond_to?(name, include_private = false)
-
super || @@options.key?(name.to_sym)
-
end
-
-
private
-
def method_missing(name, *args, &blk)
-
if name.end_with?("=")
-
@@options[:"#{name[0..-2]}"] = args.first
-
elsif @@options.key?(name)
-
@@options[name]
-
else
-
super
-
end
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5.0") && RUBY_ENGINE == "ruby"
-
desc = defined?(RUBY_DESCRIPTION) ? RUBY_DESCRIPTION : "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})"
-
abort <<-end_message
-
-
Rails 6 requires Ruby 2.5.0 or newer.
-
-
You're running
-
#{desc}
-
-
Please upgrade to Ruby 2.5.0 or newer to continue.
-
-
end_message
-
end
-
# frozen_string_literal: true
-
-
require "yaml"
-
require "active_support/message_encryptor"
-
-
module Rails
-
# Greatly inspired by Ara T. Howard's magnificent sekrets gem. 😘
-
class Secrets # :nodoc:
-
class MissingKeyError < RuntimeError
-
def initialize
-
super(<<-end_of_message.squish)
-
Missing encryption key to decrypt secrets with.
-
Ask your team for your master key and put it in ENV["RAILS_MASTER_KEY"]
-
end_of_message
-
end
-
end
-
-
@cipher = "aes-128-gcm"
-
@root = File # Wonky, but ensures `join` uses the current directory.
-
-
class << self
-
attr_writer :root
-
-
def parse(paths, env:)
-
paths.each_with_object(Hash.new) do |path, all_secrets|
-
require "erb"
-
-
secrets = YAML.load(ERB.new(preprocess(path)).result) || {}
-
all_secrets.merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
-
all_secrets.merge!(secrets[env].deep_symbolize_keys) if secrets[env]
-
end
-
end
-
-
def key
-
ENV["RAILS_MASTER_KEY"] || read_key_file || handle_missing_key
-
end
-
-
def encrypt(data)
-
encryptor.encrypt_and_sign(data)
-
end
-
-
def decrypt(data)
-
encryptor.decrypt_and_verify(data)
-
end
-
-
def read
-
decrypt(IO.binread(path))
-
end
-
-
def write(contents)
-
IO.binwrite("#{path}.tmp", encrypt(contents))
-
FileUtils.mv("#{path}.tmp", path)
-
end
-
-
def read_for_editing(&block)
-
writing(read, &block)
-
end
-
-
private
-
def handle_missing_key
-
raise MissingKeyError
-
end
-
-
def read_key_file
-
if File.exist?(key_path)
-
IO.binread(key_path).strip
-
end
-
end
-
-
def key_path
-
@root.join("config", "secrets.yml.key")
-
end
-
-
def path
-
@root.join("config", "secrets.yml.enc").to_s
-
end
-
-
def preprocess(path)
-
if path.end_with?(".enc")
-
decrypt(IO.binread(path))
-
else
-
IO.read(path)
-
end
-
end
-
-
def writing(contents)
-
tmp_file = "#{File.basename(path)}.#{Process.pid}"
-
tmp_path = File.join(Dir.tmpdir, tmp_file)
-
IO.binwrite(tmp_path, contents)
-
-
yield tmp_path
-
-
updated_contents = IO.binread(tmp_path)
-
-
write(updated_contents) if updated_contents != contents
-
ensure
-
FileUtils.rm(tmp_path) if File.exist?(tmp_path)
-
end
-
-
def encryptor
-
@encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: @cipher)
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
17
require "active_support/deprecation"
-
-
17
module Rails
-
# Implements the logic behind <tt>Rails::Command::NotesCommand</tt>. See <tt>rails notes --help</tt> for usage information.
-
#
-
# Annotation objects are triplets <tt>:line</tt>, <tt>:tag</tt>, <tt>:text</tt> that
-
# represent the line where the annotation lives, its tag, and its text. Note
-
# the filename is not stored.
-
#
-
# Annotations are looked for in comments and modulus whitespace they have to
-
# start with the tag optionally followed by a colon. Everything up to the end
-
# of the line (or closing ERB comment tag) is considered to be their text.
-
17
class SourceAnnotationExtractor
-
17
class Annotation < Struct.new(:line, :tag, :text)
-
17
def self.directories
-
@@directories ||= %w(app config db lib test)
-
end
-
-
# Registers additional directories to be included
-
# Rails::SourceAnnotationExtractor::Annotation.register_directories("spec", "another")
-
17
def self.register_directories(*dirs)
-
directories.push(*dirs)
-
end
-
-
17
def self.tags
-
@@tags ||= %w(OPTIMIZE FIXME TODO)
-
end
-
-
# Registers additional tags
-
# Rails::SourceAnnotationExtractor::Annotation.register_tags("TESTME", "DEPRECATEME")
-
17
def self.register_tags(*additional_tags)
-
tags.push(*additional_tags)
-
end
-
-
17
def self.extensions
-
51
@@extensions ||= {}
-
end
-
-
# Registers new Annotations File Extensions
-
# Rails::SourceAnnotationExtractor::Annotation.register_extensions("css", "scss", "sass", "less", "js") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ }
-
17
def self.register_extensions(*exts, &block)
-
51
extensions[/\.(#{exts.join("|")})$/] = block
-
end
-
-
17
register_extensions("builder", "rb", "rake", "yml", "yaml", "ruby") { |tag| /#\s*(#{tag}):?\s*(.*)$/ }
-
17
register_extensions("css", "js") { |tag| /\/\/\s*(#{tag}):?\s*(.*)$/ }
-
17
register_extensions("erb") { |tag| /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/ }
-
-
# Returns a representation of the annotation that looks like this:
-
#
-
# [126] [TODO] This algorithm is simple and clearly correct, make it faster.
-
#
-
# If +options+ has a flag <tt>:tag</tt> the tag is shown as in the example above.
-
# Otherwise the string contains just line and text.
-
17
def to_s(options = {})
-
s = +"[#{line.to_s.rjust(options[:indent])}] "
-
s << "[#{tag}] " if options[:tag]
-
s << text
-
end
-
-
# Used in annotations.rake
-
#:nodoc:
-
17
def self.notes_task_deprecation_warning
-
ActiveSupport::Deprecation.warn("This rake task is deprecated and will be removed in Rails 6.1. \nRefer to `rails notes --help` for more information.\n")
-
puts "\n"
-
end
-
end
-
-
# Prints all annotations with tag +tag+ under the root directories +app+,
-
# +config+, +db+, +lib+, and +test+ (recursively).
-
#
-
# If +tag+ is <tt>nil</tt>, annotations with either default or registered tags are printed.
-
#
-
# Specific directories can be explicitly set using the <tt>:dirs</tt> key in +options+.
-
#
-
# Rails::SourceAnnotationExtractor.enumerate 'TODO|FIXME', dirs: %w(app lib), tag: true
-
#
-
# If +options+ has a <tt>:tag</tt> flag, it will be passed to each annotation's +to_s+.
-
#
-
# See <tt>#find_in</tt> for a list of file extensions that will be taken into account.
-
#
-
# This class method is the single entry point for the `rails notes` command.
-
17
def self.enumerate(tag = nil, options = {})
-
tag ||= Annotation.tags.join("|")
-
extractor = new(tag)
-
dirs = options.delete(:dirs) || Annotation.directories
-
extractor.display(extractor.find(dirs), options)
-
end
-
-
17
attr_reader :tag
-
-
17
def initialize(tag)
-
@tag = tag
-
end
-
-
# Returns a hash that maps filenames under +dirs+ (recursively) to arrays
-
# with their annotations.
-
17
def find(dirs)
-
dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
-
end
-
-
# Returns a hash that maps filenames under +dir+ (recursively) to arrays
-
# with their annotations. Files with extensions registered in
-
# <tt>Rails::SourceAnnotationExtractor::Annotation.extensions</tt> are
-
# taken into account. Only files with annotations are included.
-
17
def find_in(dir)
-
results = {}
-
-
Dir.glob("#{dir}/*") do |item|
-
next if File.basename(item).start_with?(".")
-
-
if File.directory?(item)
-
results.update(find_in(item))
-
else
-
extension = Annotation.extensions.detect do |regexp, _block|
-
regexp.match(item)
-
end
-
-
if extension
-
pattern = extension.last.call(tag)
-
results.update(extract_annotations_from(item, pattern)) if pattern
-
end
-
end
-
end
-
-
results
-
end
-
-
# If +file+ is the filename of a file that contains annotations this method returns
-
# a hash with a single entry that maps +file+ to an array of its annotations.
-
# Otherwise it returns an empty hash.
-
17
def extract_annotations_from(file, pattern)
-
lineno = 0
-
result = File.readlines(file, encoding: Encoding::BINARY).inject([]) do |list, line|
-
lineno += 1
-
next list unless line =~ pattern
-
list << Annotation.new(lineno, $1, $2)
-
end
-
result.empty? ? {} : { file => result }
-
end
-
-
# Prints the mapping from filenames to annotations in +results+ ordered by filename.
-
# The +options+ hash is passed to each annotation's +to_s+.
-
17
def display(results, options = {})
-
options[:indent] = results.flat_map { |f, a| a.map(&:line) }.max.to_s.size
-
results.keys.sort.each do |file|
-
puts "#{file}:"
-
results[file].each do |note|
-
puts " * #{note.to_s(options)}"
-
end
-
puts
-
end
-
end
-
end
-
end
-
-
# Remove this deprecated class in the next minor version
-
#:nodoc:
-
17
SourceAnnotationExtractor = ActiveSupport::Deprecation::DeprecatedConstantProxy.
-
new("SourceAnnotationExtractor", "Rails::SourceAnnotationExtractor")
-
# frozen_string_literal: true
-
-
require "rake"
-
-
# Load Rails Rakefile extensions
-
%w(
-
annotations
-
dev
-
framework
-
initializers
-
log
-
middleware
-
misc
-
restart
-
routes
-
tmp
-
yarn
-
zeitwerk
-
).tap { |arr|
-
arr << "statistics" if Rake.application.current_scope.empty?
-
}.each do |task|
-
load "rails/tasks/#{task}.rake"
-
end
-
# frozen_string_literal: true
-
-
# Make double-sure the RAILS_ENV is not set to production,
-
# so fixtures aren't loaded into that environment
-
abort("Abort testing: Your Rails environment is running in production mode!") if Rails.env.production?
-
-
require "active_support/test_case"
-
require "action_controller"
-
require "action_controller/test_case"
-
require "action_dispatch/testing/integration"
-
require "rails/generators/test_case"
-
-
require "active_support/testing/autorun"
-
-
if defined?(ActiveRecord::Base)
-
begin
-
ActiveRecord::Migration.maintain_test_schema!
-
rescue ActiveRecord::PendingMigrationError => e
-
puts e.to_s.strip
-
exit 1
-
end
-
-
ActiveSupport.on_load(:active_support_test_case) do
-
include ActiveRecord::TestDatabases
-
include ActiveRecord::TestFixtures
-
-
self.fixture_path = "#{Rails.root}/test/fixtures/"
-
self.file_fixture_path = fixture_path + "files"
-
end
-
-
ActiveSupport.on_load(:action_dispatch_integration_test) do
-
self.fixture_path = ActiveSupport::TestCase.fixture_path
-
end
-
end
-
-
# :enddoc:
-
-
ActiveSupport.on_load(:action_controller_test_case) do
-
def before_setup # :nodoc:
-
@routes = Rails.application.routes
-
super
-
end
-
end
-
-
ActiveSupport.on_load(:action_dispatch_integration_test) do
-
def before_setup # :nodoc:
-
@routes = Rails.application.routes
-
super
-
end
-
end
-
# frozen_string_literal: true
-
-
17
require "rails/test_unit/runner"
-
-
17
module Rails
-
17
module LineFiltering # :nodoc:
-
17
def run(reporter, options = {})
-
options[:filter] = Rails::TestUnit::Runner.compose_filter(self, options[:filter])
-
-
super
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
17
require "rails/test_unit/line_filtering"
-
-
17
if defined?(Rake.application) && Rake.application.top_level_tasks.grep(/^(default$|test(:|$))/).any?
-
ENV["RAILS_ENV"] ||= Rake.application.options.show_tasks ? "development" : "test"
-
end
-
-
17
module Rails
-
17
class TestUnitRailtie < Rails::Railtie
-
17
config.app_generators do |c|
-
17
c.test_framework :test_unit, fixture: true,
-
fixture_replacement: nil
-
-
17
c.integration_tool :test_unit
-
17
c.system_tests :test_unit
-
end
-
-
17
initializer "test_unit.line_filtering" do
-
ActiveSupport.on_load(:active_support_test_case) {
-
ActiveSupport::TestCase.extend Rails::LineFiltering
-
}
-
end
-
-
17
rake_tasks do
-
load "rails/test_unit/testing.rake"
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require "active_support/core_ext/class/attribute"
-
require "minitest"
-
-
module Rails
-
class TestUnitReporter < Minitest::StatisticsReporter
-
class_attribute :app_root
-
class_attribute :executable, default: "rails test"
-
-
def record(result)
-
super
-
-
if options[:verbose]
-
io.puts color_output(format_line(result), by: result)
-
else
-
io.print color_output(result.result_code, by: result)
-
end
-
-
if output_inline? && result.failure && (!result.skipped? || options[:verbose])
-
io.puts
-
io.puts
-
io.puts color_output(result, by: result)
-
io.puts
-
io.puts format_rerun_snippet(result)
-
io.puts
-
end
-
-
if fail_fast? && result.failure && !result.skipped?
-
raise Interrupt
-
end
-
end
-
-
def report
-
return if output_inline? || filtered_results.empty?
-
io.puts
-
io.puts "Failed tests:"
-
io.puts
-
io.puts aggregated_results
-
end
-
-
def aggregated_results # :nodoc:
-
filtered_results.map { |result| format_rerun_snippet(result) }.join "\n"
-
end
-
-
def filtered_results
-
if options[:verbose]
-
results
-
else
-
results.reject(&:skipped?)
-
end
-
end
-
-
def relative_path_for(file)
-
file.sub(/^#{app_root}\/?/, "")
-
end
-
-
private
-
def output_inline?
-
options[:output_inline]
-
end
-
-
def fail_fast?
-
options[:fail_fast]
-
end
-
-
def format_line(result)
-
klass = result.respond_to?(:klass) ? result.klass : result.class
-
"%s#%s = %.2f s = %s" % [klass, result.name, result.time, result.result_code]
-
end
-
-
def format_rerun_snippet(result)
-
location, line = if result.respond_to?(:source_location)
-
result.source_location
-
else
-
result.method(result.name).source_location
-
end
-
-
"#{executable} #{relative_path_for(location)}:#{line}"
-
end
-
-
def app_root
-
@app_root ||= self.class.app_root ||
-
if defined?(ENGINE_ROOT)
-
ENGINE_ROOT
-
elsif Rails.respond_to?(:root)
-
Rails.root
-
end
-
end
-
-
def colored_output?
-
options[:color] && io.respond_to?(:tty?) && io.tty?
-
end
-
-
codes = { red: 31, green: 32, yellow: 33 }
-
COLOR_BY_RESULT_CODE = {
-
"." => codes[:green],
-
"E" => codes[:red],
-
"F" => codes[:red],
-
"S" => codes[:yellow]
-
}
-
-
def color_output(string, by:)
-
if colored_output?
-
"\e[#{COLOR_BY_RESULT_CODE[by.result_code]}m#{string}\e[0m"
-
else
-
string
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
17
require "shellwords"
-
17
require "method_source"
-
17
require "rake/file_list"
-
17
require "active_support/core_ext/module/attribute_accessors"
-
-
17
module Rails
-
17
module TestUnit
-
17
class Runner
-
17
mattr_reader :filters, default: []
-
-
17
class << self
-
17
def attach_before_load_options(opts)
-
opts.on("--warnings", "-w", "Run with Ruby warnings enabled") { }
-
opts.on("-e", "--environment ENV", "Run tests in the ENV environment") { }
-
end
-
-
17
def parse_options(argv)
-
# Perform manual parsing and cleanup since option parser raises on unknown options.
-
env_index = argv.index("--environment") || argv.index("-e")
-
if env_index
-
argv.delete_at(env_index)
-
environment = argv.delete_at(env_index).strip
-
end
-
ENV["RAILS_ENV"] = environment || "test"
-
-
w_index = argv.index("--warnings") || argv.index("-w")
-
$VERBOSE = argv.delete_at(w_index) if w_index
-
end
-
-
17
def rake_run(argv = [])
-
ARGV.replace Shellwords.split(ENV["TESTOPTS"] || "")
-
-
run(argv)
-
end
-
-
17
def run(argv = [])
-
load_tests(argv)
-
-
require "active_support/testing/autorun"
-
end
-
-
17
def load_tests(argv)
-
patterns = extract_filters(argv)
-
-
-
tests = Rake::FileList[patterns.any? ? patterns : default_test_glob]
-
tests.exclude(default_test_exclude_glob) if patterns.empty?
-
-
tests.to_a.each { |path| require File.expand_path(path) }
-
end
-
-
17
def compose_filter(runnable, filter)
-
if filters.any? { |_, lines| lines.any? }
-
CompositeFilter.new(runnable, filter, filters)
-
else
-
filter
-
end
-
end
-
-
17
private
-
17
def extract_filters(argv)
-
# Extract absolute and relative paths but skip -n /.*/ regexp filters.
-
argv.select { |arg| path_argument?(arg) && !regexp_filter?(arg) }.map do |path|
-
path = path.tr("\\", "/")
-
case
-
when /(:\d+)+$/.match?(path)
-
file, *lines = path.split(":")
-
filters << [ file, lines ]
-
file
-
when Dir.exist?(path)
-
"#{path}/**/*_test.rb"
-
else
-
filters << [ path, [] ]
-
path
-
end
-
end
-
end
-
-
17
def default_test_glob
-
ENV["DEFAULT_TEST"] || "test/**/*_test.rb"
-
end
-
-
17
def default_test_exclude_glob
-
ENV["DEFAULT_TEST_EXCLUDE"] || "test/{system,dummy}/**/*_test.rb"
-
end
-
-
17
def regexp_filter?(arg)
-
arg.start_with?("/") && arg.end_with?("/")
-
end
-
-
17
def path_argument?(arg)
-
%r"^[/\\]?\w+[/\\]".match?(arg)
-
end
-
end
-
end
-
-
17
class CompositeFilter # :nodoc:
-
17
attr_reader :named_filter
-
-
17
def initialize(runnable, filter, patterns)
-
@runnable = runnable
-
@named_filter = derive_named_filter(filter)
-
@filters = [ @named_filter, *derive_line_filters(patterns) ].compact
-
end
-
-
# minitest uses === to find matching filters.
-
17
def ===(method)
-
@filters.any? { |filter| filter === method }
-
end
-
-
17
private
-
17
def derive_named_filter(filter)
-
if filter.respond_to?(:named_filter)
-
filter.named_filter
-
elsif filter =~ %r%/(.*)/% # Regexp filtering copied from minitest.
-
Regexp.new $1
-
elsif filter.is_a?(String)
-
filter
-
end
-
end
-
-
17
def derive_line_filters(patterns)
-
patterns.flat_map do |file, lines|
-
if lines.empty?
-
Filter.new(@runnable, file, nil) if file
-
else
-
lines.map { |line| Filter.new(@runnable, file, line) }
-
end
-
end
-
end
-
end
-
-
17
class Filter # :nodoc:
-
17
def initialize(runnable, file, line)
-
@runnable, @file = runnable, File.expand_path(file)
-
@line = line.to_i if line
-
end
-
-
17
def ===(method)
-
return unless @runnable.method_defined?(method)
-
-
if @line
-
test_file, test_range = definition_for(@runnable.instance_method(method))
-
test_file == @file && test_range.include?(@line)
-
else
-
@runnable.instance_method(method).source_location.first == @file
-
end
-
end
-
-
17
private
-
17
def definition_for(method)
-
file, start_line = method.source_location
-
end_line = method.source.count("\n") + start_line - 1
-
-
return file, start_line..end_line
-
end
-
end
-
end
-
end
-
# frozen_string_literal: true
-
-
require_relative "gem_version"
-
-
module Rails
-
# Returns the version of the currently loaded Rails as a string.
-
def self.version
-
VERSION::STRING
-
end
-
end
-
# frozen_string_literal: true
-
-
require "rails/application_controller"
-
-
class Rails::WelcomeController < Rails::ApplicationController # :nodoc:
-
layout false
-
-
def index
-
end
-
end