Extract internal ActiveSupport::ConfigurationFile object
Rails has a number of places where a YAML configuration file is read, then ERB is evaluated and finally the YAML is parsed. This consolidates that into one common class. Co-authored-by: Kasper Timm Hansen <kaspth@gmail.com>
This commit is contained in:
parent
a6cf649250
commit
ef7599fe91
@ -1,7 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "erb"
|
||||
require "yaml"
|
||||
require "active_support/configuration_file"
|
||||
|
||||
module ActiveRecord
|
||||
class FixtureSet
|
||||
@ -51,24 +50,14 @@ def config_row
|
||||
|
||||
def raw_rows
|
||||
@raw_rows ||= begin
|
||||
data = YAML.load(render(IO.read(@file)))
|
||||
data = ActiveSupport::ConfigurationFile.parse(@file, context:
|
||||
ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding)
|
||||
data ? validate(data).to_a : []
|
||||
rescue ArgumentError, Psych::SyntaxError => error
|
||||
raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at https://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
|
||||
rescue RuntimeError => error
|
||||
raise Fixture::FormatError, error.message
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_erb(content)
|
||||
erb = ERB.new(content)
|
||||
erb.filename = @file
|
||||
erb
|
||||
end
|
||||
|
||||
def render(content)
|
||||
context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new
|
||||
prepare_erb(content).result(context.get_binding)
|
||||
end
|
||||
|
||||
# Validate our unmarshalled data.
|
||||
def validate(data)
|
||||
unless Hash === data || YAML::Omap === data
|
||||
|
@ -1,6 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "active_record"
|
||||
require "active_support/configuration_file"
|
||||
|
||||
databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
|
||||
|
||||
@ -369,7 +370,7 @@ db_namespace = namespace :db do
|
||||
base_dir = ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
||||
|
||||
Dir["#{base_dir}/**/*.yml"].each do |file|
|
||||
if data = YAML.load(ERB.new(IO.read(file)).result)
|
||||
if data = ActiveSupport::ConfigurationFile.parse(file)
|
||||
data.each_key do |key|
|
||||
key_id = ActiveRecord::FixtureSet.identify(key)
|
||||
|
||||
|
@ -137,12 +137,6 @@ def test_extracts_model_class_from_config_row
|
||||
end
|
||||
end
|
||||
|
||||
def test_erb_filename
|
||||
filename = "filename.yaml"
|
||||
erb = File.new(filename).send(:prepare_erb, "<% Rails.env %>\n")
|
||||
assert_equal erb.filename, filename
|
||||
end
|
||||
|
||||
private
|
||||
def tmp_yaml(name, contents)
|
||||
t = Tempfile.new name
|
||||
|
@ -1,9 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "yaml"
|
||||
require "erb"
|
||||
require "fileutils"
|
||||
require "pathname"
|
||||
require "active_support/configuration_file"
|
||||
|
||||
module ARTest
|
||||
class << self
|
||||
@ -21,8 +20,7 @@ def read_config
|
||||
FileUtils.cp TEST_ROOT + "/config.example.yml", config_file
|
||||
end
|
||||
|
||||
erb = ERB.new(config_file.read)
|
||||
expand_config(YAML.parse(erb.result(binding)).transform)
|
||||
expand_config ActiveSupport::ConfigurationFile.parse(config_file)
|
||||
end
|
||||
|
||||
def expand_config(config)
|
||||
|
@ -106,17 +106,10 @@ class Engine < Rails::Engine # :nodoc:
|
||||
ActiveSupport.on_load(:active_storage_blob) do
|
||||
configs = Rails.configuration.active_storage.service_configurations ||=
|
||||
begin
|
||||
config_file = Pathname.new(Rails.root.join("config/storage.yml"))
|
||||
config_file = Rails.root.join("config/storage.yml")
|
||||
raise("Couldn't find Active Storage configuration in #{config_file}") unless config_file.exist?
|
||||
|
||||
require "yaml"
|
||||
require "erb"
|
||||
|
||||
YAML.load(ERB.new(config_file.read).result) || {}
|
||||
rescue Psych::SyntaxError => e
|
||||
raise "YAML syntax error occurred while parsing #{config_file}. " \
|
||||
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
||||
"Error: #{e.message}"
|
||||
ActiveSupport::ConfigurationFile.parse(config_file)
|
||||
end
|
||||
|
||||
ActiveStorage::Blob.services = ActiveStorage::Service::Registry.new(configs)
|
||||
|
@ -8,6 +8,7 @@
|
||||
require "active_support/test_case"
|
||||
require "active_support/core_ext/object/try"
|
||||
require "active_support/testing/autorun"
|
||||
require "active_support/configuration_file"
|
||||
require "active_storage/service/mirror_service"
|
||||
require "image_processing/mini_magick"
|
||||
|
||||
@ -23,11 +24,8 @@
|
||||
# Filter out the backtrace from minitest while preserving the one from other libraries.
|
||||
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
||||
|
||||
require "yaml"
|
||||
SERVICE_CONFIGURATIONS = begin
|
||||
erb = ERB.new(Pathname.new(File.expand_path("service/configurations.yml", __dir__)).read)
|
||||
configuration = YAML.load(erb.result) || {}
|
||||
configuration.deep_symbolize_keys
|
||||
ActiveSupport::ConfigurationFile.parse(File.expand_path("service/configurations.yml", __dir__)).deep_symbolize_keys
|
||||
rescue Errno::ENOENT
|
||||
puts "Missing service configuration file in test/service/configurations.yml"
|
||||
{}
|
||||
|
@ -35,6 +35,7 @@ module ActiveSupport
|
||||
|
||||
autoload :Concern
|
||||
autoload :ActionableError
|
||||
autoload :ConfigurationFile
|
||||
autoload :CurrentAttributes
|
||||
autoload :Dependencies
|
||||
autoload :DescendantsTracker
|
||||
|
42
activesupport/lib/active_support/configuration_file.rb
Normal file
42
activesupport/lib/active_support/configuration_file.rb
Normal file
@ -0,0 +1,42 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ActiveSupport
|
||||
# Reads a YAML configuration file, evaluating any ERB, then
|
||||
# parsing the resulting YAML.
|
||||
#
|
||||
# Warns in case of YAML confusing characters, like invisible
|
||||
# non-breaking spaces.
|
||||
class ConfigurationFile # :nodoc:
|
||||
class FormatError < StandardError; end
|
||||
|
||||
def initialize(content_path)
|
||||
@content_path = content_path
|
||||
@content = read content_path
|
||||
end
|
||||
|
||||
def self.parse(content_path, **options)
|
||||
new(content_path).parse(**options)
|
||||
end
|
||||
|
||||
def parse(context: nil, **options)
|
||||
yaml = context ? ERB.new(@content).result(context) : ERB.new(@content).result
|
||||
YAML.load(yaml, **options) || {}
|
||||
rescue Psych::SyntaxError => error
|
||||
raise "YAML syntax error occurred while parsing #{@content_path}. " \
|
||||
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
||||
"Error: #{error.message}"
|
||||
end
|
||||
|
||||
private
|
||||
def read(content_path)
|
||||
require "yaml"
|
||||
require "erb"
|
||||
|
||||
File.read(content_path).tap do |content|
|
||||
if content.match?(/\U+A0/)
|
||||
warn "File contains invisible non-breaking spaces, you may want to remove those"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -8,6 +8,7 @@
|
||||
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"
|
||||
|
||||
@ -224,7 +225,7 @@ def config_for(name, env: Rails.env)
|
||||
|
||||
if yaml.exist?
|
||||
require "erb"
|
||||
all_configs = YAML.load(ERB.new(yaml.read).result, symbolize_names: true) || {}
|
||||
all_configs = ActiveSupport::ConfigurationFile.parse(yaml, symbolize_names: true)
|
||||
config, shared = all_configs[env.to_sym], all_configs[:shared]
|
||||
|
||||
if config.is_a?(Hash)
|
||||
@ -235,10 +236,6 @@ def config_for(name, env: Rails.env)
|
||||
else
|
||||
raise "Could not load configuration. No such file - #{yaml}"
|
||||
end
|
||||
rescue Psych::SyntaxError => error
|
||||
raise "YAML syntax error occurred while parsing #{yaml}. " \
|
||||
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
||||
"Error: #{error.message}"
|
||||
end
|
||||
|
||||
# Stores some of the Rails initial environment parameters which
|
||||
|
@ -3,6 +3,7 @@
|
||||
require "ipaddr"
|
||||
require "active_support/core_ext/kernel/reporting"
|
||||
require "active_support/file_update_checker"
|
||||
require "active_support/configuration_file"
|
||||
require "rails/engine/configuration"
|
||||
require "rails/source_annotation_extractor"
|
||||
|
||||
@ -247,12 +248,9 @@ def database_configuration
|
||||
path = paths["config/database"].existent.first
|
||||
yaml = Pathname.new(path) if path
|
||||
|
||||
config = if yaml && yaml.exist?
|
||||
require "yaml"
|
||||
require "erb"
|
||||
loaded_yaml = YAML.load(ERB.new(yaml.read).result) || {}
|
||||
shared = loaded_yaml.delete("shared")
|
||||
if shared
|
||||
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
|
||||
@ -267,10 +265,6 @@ def database_configuration
|
||||
end
|
||||
|
||||
config
|
||||
rescue Psych::SyntaxError => e
|
||||
raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \
|
||||
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
|
||||
"Error: #{e.message}"
|
||||
rescue => e
|
||||
raise e, "Cannot load database configuration:\n#{e.message}", e.backtrace
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user