Class: Liquid::Context
- Inherits:
-
Object
- Object
- Liquid::Context
- Includes:
- ContextProfilingHook
- Defined in:
- lib/liquid/context.rb
Overview
Context keeps the variable stack and resolves variables, as well as keywords
context['variable'] = 'testing'
context['variable'] #=> 'testing'
context['true'] #=> true
context['10.2232'] #=> 10.2232
context.stack do
context['bob'] = 'bobsen'
end
context['bob'] #=> nil class Context
Instance Attribute Summary collapse
-
#environments ⇒ Object
readonly
Returns the value of attribute environments.
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#exception_renderer ⇒ Object
Returns the value of attribute exception_renderer.
-
#global_filter ⇒ Object
Returns the value of attribute global_filter.
-
#partial ⇒ Object
Returns the value of attribute partial.
-
#registers ⇒ Object
readonly
Returns the value of attribute registers.
-
#resource_limits ⇒ Object
readonly
Returns the value of attribute resource_limits.
-
#scopes ⇒ Object
readonly
Returns the value of attribute scopes.
-
#static_environments ⇒ Object
readonly
Returns the value of attribute static_environments.
-
#static_registers ⇒ Object
readonly
Returns the value of attribute static_registers.
- #strainer ⇒ Object readonly
-
#strict_filters ⇒ Object
Returns the value of attribute strict_filters.
-
#strict_variables ⇒ Object
Returns the value of attribute strict_variables.
-
#template_name ⇒ Object
Returns the value of attribute template_name.
-
#warnings ⇒ Object
readonly
rubocop:enable Metrics/ParameterLists.
Attributes included from ContextProfilingHook
Class Method Summary collapse
-
.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {}, &block) ⇒ Object
rubocop:disable Metrics/ParameterLists.
Instance Method Summary collapse
-
#[](expression) ⇒ Object
Look up variable, either resolve directly after considering the name.
-
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or
Liquid::Drop
. -
#add_filters(filters) ⇒ Object
Adds filters to this context.
- #apply_global_filter(obj) ⇒ Object
- #clear_instance_assigns ⇒ Object
- #evaluate(object) ⇒ Object
-
#find_variable(key, raise_on_not_found: true) ⇒ Object
Fetches an object starting at the local scope and then moving up the hierachy.
- #handle_error(e, line_number = nil) ⇒ Object
-
#initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {}) {|_self| ... } ⇒ Context
constructor
A new instance of Context.
-
#interrupt? ⇒ Boolean
are there any not handled interrupts?.
- #invoke(method, *args) ⇒ Object
- #key?(key) ⇒ Boolean
- #lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
-
#merge(new_scopes) ⇒ Object
Merge a hash of variables in the current local scope.
-
#new_isolated_subcontext ⇒ Object
Creates a new context inheriting resource limits, filters, environment etc., but with an isolated scope.
-
#pop ⇒ Object
Pop from the stack.
-
#pop_interrupt ⇒ Object
pop an interrupt from the stack.
-
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack.
-
#push_interrupt(e) ⇒ Object
push an interrupt to the stack.
-
#stack(new_scope = {}) ⇒ Object
Pushes a new local scope on the stack, pops it at the end of the block.
- #tag_disabled?(tag_name) ⇒ Boolean
- #with_disabled_tags(tag_names) ⇒ Object
Constructor Details
#initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {}) {|_self| ... } ⇒ Context
Returns a new instance of Context.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/liquid/context.rb', line 25 def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {}) @environments = [environments] @environments.flatten! @static_environments = [static_environments].flat_map(&:freeze).freeze @scopes = [(outer_scope || {})] @registers = registers @errors = [] @partial = false @strict_variables = false @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits) @base_scope_depth = 0 @interrupts = [] @filters = [] @global_filter = nil @disabled_tags = {} self.exception_renderer = Template.default_exception_renderer if rethrow_errors self.exception_renderer = Liquid::RAISE_EXCEPTION_LAMBDA end yield self if block_given? # Do this last, since it could result in this object being passed to a Proc in the environment squash_instance_assigns_with_environments end |
Instance Attribute Details
#environments ⇒ Object (readonly)
Returns the value of attribute environments.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def environments @environments end |
#errors ⇒ Object
Returns the value of attribute errors.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def errors @errors end |
#exception_renderer ⇒ Object
Returns the value of attribute exception_renderer.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def exception_renderer @exception_renderer end |
#global_filter ⇒ Object
Returns the value of attribute global_filter.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def global_filter @global_filter end |
#partial ⇒ Object
Returns the value of attribute partial.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def partial @partial end |
#registers ⇒ Object (readonly)
Returns the value of attribute registers.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def registers @registers end |
#resource_limits ⇒ Object (readonly)
Returns the value of attribute resource_limits.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def resource_limits @resource_limits end |
#scopes ⇒ Object (readonly)
Returns the value of attribute scopes.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def scopes @scopes end |
#static_environments ⇒ Object (readonly)
Returns the value of attribute static_environments.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def static_environments @static_environments end |
#static_registers ⇒ Object (readonly)
Returns the value of attribute static_registers.
17 18 19 |
# File 'lib/liquid/context.rb', line 17 def static_registers @static_registers end |
#strainer ⇒ Object
58 59 60 |
# File 'lib/liquid/context.rb', line 58 def strainer @strainer ||= StrainerFactory.create(self, @filters) end |
#strict_filters ⇒ Object
Returns the value of attribute strict_filters.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def strict_filters @strict_filters end |
#strict_variables ⇒ Object
Returns the value of attribute strict_variables.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def strict_variables @strict_variables end |
#template_name ⇒ Object
Returns the value of attribute template_name.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def template_name @template_name end |
#warnings ⇒ Object
rubocop:enable Metrics/ParameterLists
54 55 56 |
# File 'lib/liquid/context.rb', line 54 def warnings @warnings ||= [] end |
Class Method Details
.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {}, &block) ⇒ Object
rubocop:disable Metrics/ParameterLists
21 22 23 |
# File 'lib/liquid/context.rb', line 21 def self.build(environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {}, &block) new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_environments, &block) end |
Instance Method Details
#[](expression) ⇒ Object
Look up variable, either resolve directly after considering the name. We can directly handle Strings, digits, floats and booleans (true,false). If no match is made we lookup the variable in the current scope and later move up to the parent blocks to see if we can resolve the variable somewhere up the tree. Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
Example:
products == empty #=> products.empty?
172 173 174 |
# File 'lib/liquid/context.rb', line 172 def [](expression) evaluate(Expression.parse(expression)) end |
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
160 161 162 |
# File 'lib/liquid/context.rb', line 160 def []=(key, value) @scopes[0][key] = value end |
#add_filters(filters) ⇒ Object
Adds filters to this context.
Note that this does not register the filters with the main Template object. see Template.register_filter
for that
66 67 68 69 70 |
# File 'lib/liquid/context.rb', line 66 def add_filters(filters) filters = [filters].flatten.compact @filters += filters @strainer = nil end |
#apply_global_filter(obj) ⇒ Object
72 73 74 |
# File 'lib/liquid/context.rb', line 72 def apply_global_filter(obj) global_filter.nil? ? obj : global_filter.call(obj) end |
#clear_instance_assigns ⇒ Object
155 156 157 |
# File 'lib/liquid/context.rb', line 155 def clear_instance_assigns @scopes[0] = {} end |
#evaluate(object) ⇒ Object
180 181 182 |
# File 'lib/liquid/context.rb', line 180 def evaluate(object) object.respond_to?(:evaluate) ? object.evaluate(self) : object end |
#find_variable(key, raise_on_not_found: true) ⇒ Object
Fetches an object starting at the local scope and then moving up the hierachy
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/liquid/context.rb', line 185 def find_variable(key, raise_on_not_found: true) # This was changed from find() to find_index() because this is a very hot # path and find_index() is optimized in MRI to reduce object allocation index = @scopes.find_index { |s| s.key?(key) } variable = if index lookup_and_evaluate(@scopes[index], key, raise_on_not_found: raise_on_not_found) else try_variable_find_in_environments(key, raise_on_not_found: raise_on_not_found) end variable = variable.to_liquid variable.context = self if variable.respond_to?(:context=) variable end |
#handle_error(e, line_number = nil) ⇒ Object
91 92 93 94 95 96 97 |
# File 'lib/liquid/context.rb', line 91 def handle_error(e, line_number = nil) e = internal_error unless e.is_a?(Liquid::Error) e.template_name ||= template_name e.line_number ||= line_number errors.push(e) exception_renderer.call(e).to_s end |
#interrupt? ⇒ Boolean
are there any not handled interrupts?
77 78 79 |
# File 'lib/liquid/context.rb', line 77 def interrupt? !@interrupts.empty? end |
#invoke(method, *args) ⇒ Object
99 100 101 |
# File 'lib/liquid/context.rb', line 99 def invoke(method, *args) strainer.invoke(method, *args).to_liquid end |
#key?(key) ⇒ Boolean
176 177 178 |
# File 'lib/liquid/context.rb', line 176 def key?(key) self[key] != nil end |
#lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/liquid/context.rb', line 202 def lookup_and_evaluate(obj, key, raise_on_not_found: true) if @strict_variables && raise_on_not_found && obj.respond_to?(:key?) && !obj.key?(key) raise Liquid::UndefinedVariable, "undefined variable #{key}" end value = obj[key] if value.is_a?(Proc) && obj.respond_to?(:[]=) obj[key] = value.arity == 0 ? value.call : value.call(self) else value end end |
#merge(new_scopes) ⇒ Object
Merge a hash of variables in the current local scope
110 111 112 |
# File 'lib/liquid/context.rb', line 110 def merge(new_scopes) @scopes[0].merge!(new_scopes) end |
#new_isolated_subcontext ⇒ Object
Creates a new context inheriting resource limits, filters, environment etc., but with an isolated scope.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/liquid/context.rb', line 137 def new_isolated_subcontext check_overflow self.class.build( resource_limits: resource_limits, static_environments: static_environments, registers: StaticRegisters.new(registers) ).tap do |subcontext| subcontext.base_scope_depth = base_scope_depth + 1 subcontext.exception_renderer = exception_renderer subcontext.filters = @filters subcontext.strainer = nil subcontext.errors = errors subcontext.warnings = warnings subcontext. = @disabled_tags end end |
#pop ⇒ Object
Pop from the stack. use Context#stack
instead
115 116 117 118 |
# File 'lib/liquid/context.rb', line 115 def pop raise ContextError if @scopes.size == 1 @scopes.shift end |
#pop_interrupt ⇒ Object
pop an interrupt from the stack
87 88 89 |
# File 'lib/liquid/context.rb', line 87 def pop_interrupt @interrupts.pop end |
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack. use Context#stack
instead
104 105 106 107 |
# File 'lib/liquid/context.rb', line 104 def push(new_scope = {}) @scopes.unshift(new_scope) check_overflow end |
#push_interrupt(e) ⇒ Object
push an interrupt to the stack. this interrupt is considered not handled.
82 83 84 |
# File 'lib/liquid/context.rb', line 82 def push_interrupt(e) @interrupts.push(e) end |
#stack(new_scope = {}) ⇒ Object
Pushes a new local scope on the stack, pops it at the end of the block
Example:
context.stack do
context['var'] = 'hi'
end
context['var'] #=> nil
128 129 130 131 132 133 |
# File 'lib/liquid/context.rb', line 128 def stack(new_scope = {}) push(new_scope) yield ensure pop end |
#tag_disabled?(tag_name) ⇒ Boolean
227 228 229 |
# File 'lib/liquid/context.rb', line 227 def tag_disabled?(tag_name) @disabled_tags.fetch(tag_name, 0) > 0 end |
#with_disabled_tags(tag_names) ⇒ Object
216 217 218 219 220 221 222 223 224 225 |
# File 'lib/liquid/context.rb', line 216 def (tag_names) tag_names.each do |name| @disabled_tags[name] = @disabled_tags.fetch(name, 0) + 1 end yield ensure tag_names.each do |name| @disabled_tags[name] -= 1 end end |