-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add concept of
Liquid::Environment
(#1815)
* Add concept of `Liquid::World` * Rename `World` to `Environment`
- Loading branch information
Showing
38 changed files
with
459 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
module Liquid | ||
module Const | ||
EMPTY_HASH = {}.freeze | ||
EMPTY_ARRAY = [].freeze | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
require "set" | ||
|
||
module Liquid | ||
class Deprecations | ||
class << self | ||
attr_accessor :warned | ||
|
||
Deprecations.warned = Set.new | ||
|
||
def warn(name, alternative) | ||
return if warned.include?(name) | ||
|
||
warned << name | ||
|
||
caller_location = caller_locations(2, 1).first | ||
Warning.warn("[DEPRECATION] #{name} is deprecated. Use #{alternative} instead. Called from #{caller_location}\n") | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# frozen_string_literal: true | ||
|
||
module Liquid | ||
# The Environment is the container for all configuration options of Liquid, such as | ||
# the registered tags, filters, and the default error mode. | ||
class Environment | ||
# The default error mode for all templates. This can be overridden on a | ||
# per-template basis. | ||
attr_accessor :error_mode | ||
|
||
# The tags that are available to use in the template. | ||
attr_accessor :tags | ||
|
||
# The strainer template which is used to store filters that are available to | ||
# use in templates. | ||
attr_accessor :strainer_template | ||
|
||
# The exception renderer that is used to render exceptions that are raised | ||
# when rendering a template | ||
attr_accessor :exception_renderer | ||
|
||
# The default file system that is used to load templates from. | ||
attr_accessor :file_system | ||
|
||
# The default resource limits that are used to limit the resources that a | ||
# template can consume. | ||
attr_accessor :default_resource_limits | ||
|
||
class << self | ||
# Creates a new environment instance. | ||
# | ||
# @param tags [Hash] The tags that are available to use in | ||
# the template. | ||
# @param file_system The default file system that is used | ||
# to load templates from. | ||
# @param error_mode [Symbol] The default error mode for all templates | ||
# (either :strict, :warn, or :lax). | ||
# @param exception_renderer [Proc] The exception renderer that is used to | ||
# render exceptions. | ||
# @yieldparam environment [Environment] The environment instance that is being built. | ||
# @return [Environment] The new environment instance. | ||
def build(tags: nil, file_system: nil, error_mode: nil, exception_renderer: nil) | ||
ret = new | ||
ret.tags = Template::TagRegistry.new(tags) if tags | ||
ret.file_system = file_system if file_system | ||
ret.error_mode = error_mode if error_mode | ||
ret.exception_renderer = exception_renderer if exception_renderer | ||
yield ret if block_given? | ||
ret.freeze | ||
end | ||
|
||
# Returns the default environment instance. | ||
# | ||
# @return [Environment] The default environment instance. | ||
def default | ||
@default ||= new | ||
end | ||
|
||
# Sets the default environment instance for the duration of the block | ||
# | ||
# @param environment [Environment] The environment instance to use as the default for the | ||
# duration of the block. | ||
# @yield | ||
# @return [Object] The return value of the block. | ||
def dangerously_override(environment) | ||
original_default = @default | ||
@default = environment | ||
yield | ||
ensure | ||
@default = original_default | ||
end | ||
end | ||
|
||
# Initializes a new environment instance. | ||
# @api private | ||
def initialize | ||
@tags = Template::TagRegistry.new(Tags::STANDARD_TAGS) | ||
@error_mode = :lax | ||
@strainer_template = Class.new(StrainerTemplate).tap do |klass| | ||
klass.add_filter(StandardFilters) | ||
end | ||
@exception_renderer = ->(exception) { exception } | ||
@file_system = BlankFileSystem.new | ||
@default_resource_limits = Const::EMPTY_HASH | ||
@strainer_template_class_cache = {} | ||
end | ||
|
||
# Registers a new tag with the environment. | ||
# | ||
# @param name [String] The name of the tag. | ||
# @param klass [Liquid::Tag] The class that implements the tag. | ||
# @return [void] | ||
def register_tag(name, klass) | ||
@tags[name] = klass | ||
end | ||
|
||
# Registers a new filter with the environment. | ||
# | ||
# @param filter [Module] The module that contains the filter methods. | ||
# @return [void] | ||
def register_filter(filter) | ||
@strainer_template_class_cache.clear | ||
@strainer_template.add_filter(filter) | ||
end | ||
|
||
# Registers multiple filters with this environment. | ||
# | ||
# @param filters [Array<Module>] The modules that contain the filter methods. | ||
# @return [self] | ||
def register_filters(filters) | ||
@strainer_template_class_cache.clear | ||
filters.each { |f| @strainer_template.add_filter(f) } | ||
self | ||
end | ||
|
||
# Creates a new strainer instance with the given filters, caching the result | ||
# for faster lookup. | ||
# | ||
# @param context [Liquid::Context] The context that the strainer will be | ||
# used in. | ||
# @param filters [Array<Module>] The filters that the strainer will have | ||
# access to. | ||
# @return [Liquid::Strainer] The new strainer instance. | ||
def create_strainer(context, filters = Const::EMPTY_ARRAY) | ||
return @strainer_template.new(context) if filters.empty? | ||
|
||
strainer_template = @strainer_template_class_cache[filters] ||= begin | ||
klass = Class.new(@strainer_template) | ||
filters.each { |f| klass.add_filter(f) } | ||
klass | ||
end | ||
|
||
strainer_template.new(context) | ||
end | ||
|
||
# Returns the names of all the filter methods that are available to use in | ||
# the strainer template. | ||
# | ||
# @return [Array<String>] The names of all the filter methods. | ||
def filter_method_names | ||
@strainer_template.filter_method_names | ||
end | ||
|
||
# Returns the tag class for the given tag name. | ||
# | ||
# @param name [String] The name of the tag. | ||
# @return [Liquid::Tag] The tag class. | ||
def tag_for_name(name) | ||
@tags[name] | ||
end | ||
|
||
def freeze | ||
@tags.freeze | ||
# TODO: freeze the tags, currently this is not possible because of liquid-c | ||
# @strainer_template.freeze | ||
super | ||
end | ||
end | ||
end |
Oops, something went wrong.