Skip to content

Commit

Permalink
Merge pull request #3178 from mamhoff/config-object
Browse files Browse the repository at this point in the history
Add Alchemy.config and DSL for type-safe configuration
  • Loading branch information
tvdeyen authored Feb 10, 2025
2 parents d2cf3f4 + 19f2f7c commit 6ca28c5
Show file tree
Hide file tree
Showing 72 changed files with 1,458 additions and 428 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ log
.sass-cache
spec/dummy/app/assets/builds/*
!spec/dummy/app/assets/builds/.keep
spec/dummy/config/alchemy/config.yml
spec/dummy/db/*.sqlite3*
spec/dummy/postcss.config.js
spec/dummy/public/assets/
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ $ bin/rake alchemy:upgrade
Alchemy will print out useful information after running the automated tasks that help a smooth upgrade path.
So please **take your time and read them**.

Always be sure to keep an eye on the `config/alchemy/config.yml.defaults` file and update your `config/alchemy/config.yml` accordingly.
Always be sure to keep an eye on the output of your Rails app when starting. There will probably be useful information about deprecations.

Also, `git diff` is your friend.

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/alchemy/admin/languages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def index
def new
@language = Language.new(
site: @current_site,
page_layout: Config.get(:default_language)["page_layout"]
page_layout: Alchemy.config.get(:default_language)["page_layout"]
)
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/alchemy/admin/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def show
Current.preview_page = @page
# Setting the locale to pages language, so the page content has it's correct translations.
::I18n.locale = @page.language.locale
render(layout: Alchemy::Config.get(:admin_page_preview_layout) || "application")
render(layout: Alchemy.config.get(:admin_page_preview_layout) || "application")
end

def info
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/alchemy/admin/resources_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,11 @@ def permitted_ransack_search_fields

def items_per_page
cookies[:alchemy_items_per_page] =
params[:per_page] || cookies[:alchemy_items_per_page] || Alchemy::Config.get(:items_per_page)
params[:per_page] || cookies[:alchemy_items_per_page] || Alchemy.config.get(:items_per_page)
end

def items_per_page_options
per_page = Alchemy::Config.get(:items_per_page)
per_page = Alchemy.config.get(:items_per_page)
[per_page, per_page * 2, per_page * 4]
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/alchemy/messages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def create # :nodoc:
private

def mailer_config
Alchemy::Config.get(:mailer)
Alchemy.config.get(:mailer)
end

def mail_to
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/alchemy/admin/base_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def clipboard_select_tag_options(items)

# Returns the regular expression used for external url validation in link dialog.
def link_url_regexp
Alchemy::Config.get(:format_matchers)["link_url"] || /^(mailto:|\/|[a-z]+:\/\/)/
Alchemy.config.get(:format_matchers)["link_url"] || /^(mailto:|\/|[a-z]+:\/\/)/
end

# Renders a hint with tooltip
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/alchemy/admin/pages_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module PagesHelper
# You can configure the screen sizes in your +config/alchemy/config.yml+.
#
def preview_sizes_for_select
Alchemy::Config.get(:page_preview_sizes).map do |size|
Alchemy.config.get(:page_preview_sizes).map do |size|
[Alchemy.t(size, scope: "preview_sizes"), size]
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/alchemy/attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ def searchable_alchemy_resource_attributes
end

def allowed_filetypes
Config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/attachments", [])
Alchemy.config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/attachments", [])
end
end

validates_presence_of :file
validates_size_of :file, maximum: Config.get(:uploader)["file_size_limit"].megabytes
validates_size_of :file, maximum: Alchemy.config.get(:uploader)["file_size_limit"].megabytes
validates_property :ext,
of: :file,
in: allowed_filetypes,
Expand Down
2 changes: 2 additions & 0 deletions app/models/alchemy/base_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ def self.table_name_prefix
end

class BaseRecord < ActiveRecord::Base
include ConfigMissing
extend ConfigMissing
extend Alchemy::SearchableResource

self.abstract_class = true
Expand Down
8 changes: 6 additions & 2 deletions app/models/alchemy/ingredient_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ def validate_uniqueness(*)
end

def validate_format(format)
matcher = Alchemy::Config.get("format_matchers")[format] || format
if !ingredient.value.to_s.match?(Regexp.new(matcher))
matcher = if format.is_a?(String) || format.is_a?(Symbol)
Alchemy.config.get("format_matchers").get(format)
else
format
end
if !ingredient.value.to_s.match?(matcher)
ingredient.errors.add(:value, :invalid)
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/alchemy/message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Message
include ActiveModel::Model

def self.config
Alchemy::Config.get(:mailer)
Alchemy.config.get(:mailer)
end

attr_accessor :contact_form_id, :ip
Expand All @@ -32,7 +32,7 @@ def self.config
case field.to_sym
when /email/
validates_format_of field,
with: Alchemy::Config.get("format_matchers")["email"],
with: Alchemy.config.get("format_matchers")["email"],
if: -> { send(field).present? }
when :email_confirmation
validates_confirmation_of :email
Expand Down
2 changes: 1 addition & 1 deletion app/models/alchemy/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def all_from_clipboard_for_select(clipboard, language_id, layoutpages: false)

def link_target_options
options = [[Alchemy.t(:default, scope: "link_target_options"), ""]]
link_target_options = Config.get(:link_target_options)
link_target_options = Alchemy.config.get(:link_target_options)
link_target_options.each do |option|
# add an underscore to the options to provide the default syntax
# @link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#target
Expand Down
2 changes: 1 addition & 1 deletion app/models/alchemy/page/page_natures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def cache_page?
private

def caching_enabled?
Alchemy::Config.get(:cache_pages) &&
Alchemy.config.get(:cache_pages) &&
Rails.application.config.action_controller.perform_caching
end
end
Expand Down
10 changes: 5 additions & 5 deletions app/models/alchemy/picture.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ def self.preprocessor_class=(klass)
# We need to define this method here to have it available in the validations below.
class << self
def allowed_filetypes
Config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/pictures", [])
Alchemy.config.get(:uploader).fetch("allowed_filetypes", {}).fetch("alchemy/pictures", [])
end
end

validates_presence_of :image_file
validates_size_of :image_file, maximum: Config.get(:uploader)["file_size_limit"].megabytes
validates_size_of :image_file, maximum: Alchemy.config.get(:uploader)["file_size_limit"].megabytes
validates_property :format,
of: :image_file,
in: allowed_filetypes,
Expand Down Expand Up @@ -260,7 +260,7 @@ def humanized_name
#
def default_render_format
if convertible?
Config.get(:image_output_format)
Alchemy.config.get(:image_output_format)
else
image_file_format
end
Expand All @@ -272,8 +272,8 @@ def default_render_format
# image has not a convertible file format (i.e. SVG) this returns +false+
#
def convertible?
Config.get(:image_output_format) &&
Config.get(:image_output_format) != "original" &&
Alchemy.config.get(:image_output_format) &&
Alchemy.config.get(:image_output_format) != "original" &&
has_convertible_format?
end

Expand Down
4 changes: 2 additions & 2 deletions app/models/alchemy/picture/preprocessor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ def initialize(image_file)

# Preprocess images after upload
#
# Define preprocessing options in the Alchemy::Config
# Define preprocessing options in the Alchemy.config
#
# preprocess_image_resize [String] - Downsizing example: '1000x1000>'
#
def call
max_image_size = Alchemy::Config.get(:preprocess_image_resize)
max_image_size = Alchemy.config.get(:preprocess_image_resize)
image_file.thumb!(max_image_size) if max_image_size.present?
# Auto orient the image so EXIF orientation data is taken into account
image_file.auto_orient!
Expand Down
2 changes: 1 addition & 1 deletion app/models/alchemy/picture_variant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def encoded_image(image, options = {})
convert_format = render_format.sub("jpeg", "jpg") != picture.image_file_format.sub("jpeg", "jpg")

if encodable_image? && (convert_format || options[:quality])
quality = options[:quality] || Config.get(:output_image_quality)
quality = options[:quality] || Alchemy.config.get(:output_image_quality)
encoding_options << "-quality #{quality}"
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/concerns/alchemy/picture_thumbnails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module PictureThumbnails
#
# @option options format [String]
# The format the picture should be rendered in.
# Defaults to the +image_output_format+ from the +Alchemy::Config+.
# Defaults to the +image_output_format+ from the +Alchemy.config+.
#
# @option options crop [Boolean]
# If set to true the picture will be cropped to fit the size value.
Expand Down
7 changes: 5 additions & 2 deletions app/views/alchemy/admin/languages/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@
<%== Alchemy.t('alchemy/language', scope: :no_resource_found) %>
<% end %>
<%= render 'form', language: Alchemy::Language.new(
Alchemy::Config.get(:default_language).merge(
name: Alchemy.config.default_language.name,
code: Alchemy.config.default_language.code,
page_layout: Alchemy.config.default_language.page_layout,
frontpage_name: Alchemy.config.default_language.frontpage_name,
site: Alchemy::Current.site,
default: true,
public: true
)
) %>
%>
</div>
<% end %>
</div>
6 changes: 5 additions & 1 deletion app/views/alchemy/admin/sites/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@
<%= render_message do %>
<%== Alchemy.t('alchemy/site', scope: :no_resource_found) %>
<% end %>
<%= render 'form', site: Alchemy::Site.new(Alchemy::Config.get(:default_site).merge(public: true)) %>
<%= render 'form', site: Alchemy::Site.new(
name: Alchemy.config.default_site.name,
host: Alchemy.config.default_site.host,
public: true
) %>
</div>
<% end %>
</div>
13 changes: 13 additions & 0 deletions lib/alchemy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

require "alchemy/admin/preview_url"
require "importmap-rails"
require "alchemy/configurations/main"
require "alchemy/config_missing"

module Alchemy
include Alchemy::ConfigMissing
extend Alchemy::ConfigMissing

YAML_PERMITTED_CLASSES = %w[Symbol Date Regexp]

def self.config
@_config ||= Alchemy::Configurations::Main.new
end

def self.configure(&blk)
yield config
end

# Define page preview sources
#
# A preview source is a Ruby class returning an URL
Expand Down
9 changes: 4 additions & 5 deletions lib/alchemy/admin/preview_url.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ def initialize(routes:)

def url_for(page)
@preview_config = preview_config_for(page)

if @preview_config && uri
uri_class.build(
host: uri.host,
Expand All @@ -60,10 +59,10 @@ def url_for(page)
attr_reader :routes

def preview_config_for(page)
preview_config = Alchemy::Config.get(:preview)
preview_config = Alchemy.config.preview
return unless preview_config

preview_config[page.site.name] || preview_config
preview_config.for_site(page.site) || preview_config
end

def uri
Expand All @@ -81,8 +80,8 @@ def uri_class
end

def userinfo
auth = @preview_config["auth"]
auth ? "#{auth["username"]}:#{auth["password"]}" : nil
auth = @preview_config.auth
auth.username ? "#{auth["username"]}:#{auth["password"]}" : nil
end
end
end
Expand Down
Loading

0 comments on commit 6ca28c5

Please sign in to comment.