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
-
#environment ⇒ Object
Returns the value of attribute environment.
-
#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(environment: Environment.default, 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 = {}, environment = Environment.default) {|_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 = {}, environment = Environment.default) {|_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 52 53 54 55 56 57 58 59 60 |
# File 'lib/liquid/context.rb', line 25 def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil, static_environments = {}, environment = Environment.default) @environment = environment @environments = [environments] @environments.flatten! @static_environments = [static_environments].flatten(1).freeze @scopes = [outer_scope || {}] @registers = registers.is_a?(Registers) ? registers : Registers.new(registers) @errors = [] @partial = false @strict_variables = false @resource_limits = resource_limits || ResourceLimits.new(environment.default_resource_limits) @base_scope_depth = 0 @interrupts = [] @filters = [] @global_filter = nil @disabled_tags = {} # Instead of constructing new StringScanner objects for each Expression parse, # we recycle the same one. @string_scanner = StringScanner.new("") @registers.static[:cached_partials] ||= {} @registers.static[:file_system] ||= environment.file_system @registers.static[:template_factory] ||= Liquid::TemplateFactory.new self.exception_renderer = environment.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
#environment ⇒ Object
Returns the value of attribute environment.
18 19 20 |
# File 'lib/liquid/context.rb', line 18 def environment @environment end |
#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
67 68 69 |
# File 'lib/liquid/context.rb', line 67 def strainer @strainer ||= @environment.create_strainer(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
63 64 65 |
# File 'lib/liquid/context.rb', line 63 def warnings @warnings ||= [] end |
Class Method Details
.build(environment: Environment.default, 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(environment: Environment.default, environments: {}, outer_scope: {}, registers: {}, rethrow_errors: false, resource_limits: nil, static_environments: {}, &block) new(environments, outer_scope, registers, rethrow_errors, resource_limits, static_environments, environment, &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?
182 183 184 |
# File 'lib/liquid/context.rb', line 182 def [](expression) evaluate(Expression.parse(expression, @string_scanner)) end |
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
170 171 172 |
# File 'lib/liquid/context.rb', line 170 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
75 76 77 78 79 |
# File 'lib/liquid/context.rb', line 75 def add_filters(filters) filters = [filters].flatten.compact @filters += filters @strainer = nil end |
#apply_global_filter(obj) ⇒ Object
81 82 83 |
# File 'lib/liquid/context.rb', line 81 def apply_global_filter(obj) global_filter.nil? ? obj : global_filter.call(obj) end |
#clear_instance_assigns ⇒ Object
165 166 167 |
# File 'lib/liquid/context.rb', line 165 def clear_instance_assigns @scopes[0] = {} end |
#evaluate(object) ⇒ Object
190 191 192 |
# File 'lib/liquid/context.rb', line 190 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
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/liquid/context.rb', line 195 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 # update variable's context before invoking #to_liquid variable.context = self if variable.respond_to?(:context=) liquid_variable = variable.to_liquid liquid_variable.context = self if variable != liquid_variable && liquid_variable.respond_to?(:context=) liquid_variable end |
#handle_error(e, line_number = nil) ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/liquid/context.rb', line 100 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?
86 87 88 |
# File 'lib/liquid/context.rb', line 86 def interrupt? !@interrupts.empty? end |
#invoke(method, *args) ⇒ Object
108 109 110 |
# File 'lib/liquid/context.rb', line 108 def invoke(method, *args) strainer.invoke(method, *args).to_liquid end |
#key?(key) ⇒ Boolean
186 187 188 |
# File 'lib/liquid/context.rb', line 186 def key?(key) self[key] != nil end |
#lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/liquid/context.rb', line 216 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
119 120 121 |
# File 'lib/liquid/context.rb', line 119 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.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/liquid/context.rb', line 146 def new_isolated_subcontext check_overflow self.class.build( environment: @environment, resource_limits: resource_limits, static_environments: static_environments, registers: Registers.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
124 125 126 127 |
# File 'lib/liquid/context.rb', line 124 def pop raise ContextError if @scopes.size == 1 @scopes.shift end |
#pop_interrupt ⇒ Object
pop an interrupt from the stack
96 97 98 |
# File 'lib/liquid/context.rb', line 96 def pop_interrupt @interrupts.pop end |
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack. use Context#stack
instead
113 114 115 116 |
# File 'lib/liquid/context.rb', line 113 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.
91 92 93 |
# File 'lib/liquid/context.rb', line 91 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
137 138 139 140 141 142 |
# File 'lib/liquid/context.rb', line 137 def stack(new_scope = {}) push(new_scope) yield ensure pop end |
#tag_disabled?(tag_name) ⇒ Boolean
241 242 243 |
# File 'lib/liquid/context.rb', line 241 def tag_disabled?(tag_name) @disabled_tags.fetch(tag_name, 0) > 0 end |
#with_disabled_tags(tag_names) ⇒ Object
230 231 232 233 234 235 236 237 238 239 |
# File 'lib/liquid/context.rb', line 230 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 |