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.
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 61 62 63 |
# File 'lib/liquid/context.rb', line 27 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 = {} @expression_cache = LruRedux::ThreadSafeCache.new(1000) # 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.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def environment @environment end |
#environments ⇒ Object (readonly)
Returns the value of attribute environments.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def environments @environments end |
#errors ⇒ Object
Returns the value of attribute errors.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def errors @errors end |
#exception_renderer ⇒ Object
Returns the value of attribute exception_renderer.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def exception_renderer @exception_renderer end |
#global_filter ⇒ Object
Returns the value of attribute global_filter.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def global_filter @global_filter end |
#partial ⇒ Object
Returns the value of attribute partial.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def partial @partial end |
#registers ⇒ Object (readonly)
Returns the value of attribute registers.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def registers @registers end |
#resource_limits ⇒ Object (readonly)
Returns the value of attribute resource_limits.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def resource_limits @resource_limits end |
#scopes ⇒ Object (readonly)
Returns the value of attribute scopes.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def scopes @scopes end |
#static_environments ⇒ Object (readonly)
Returns the value of attribute static_environments.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def static_environments @static_environments end |
#static_registers ⇒ Object (readonly)
Returns the value of attribute static_registers.
19 20 21 |
# File 'lib/liquid/context.rb', line 19 def static_registers @static_registers end |
#strainer ⇒ Object
70 71 72 |
# File 'lib/liquid/context.rb', line 70 def strainer @strainer ||= @environment.create_strainer(self, @filters) end |
#strict_filters ⇒ Object
Returns the value of attribute strict_filters.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def strict_filters @strict_filters end |
#strict_variables ⇒ Object
Returns the value of attribute strict_variables.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def strict_variables @strict_variables end |
#template_name ⇒ Object
Returns the value of attribute template_name.
20 21 22 |
# File 'lib/liquid/context.rb', line 20 def template_name @template_name end |
#warnings ⇒ Object
rubocop:enable Metrics/ParameterLists
66 67 68 |
# File 'lib/liquid/context.rb', line 66 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
23 24 25 |
# File 'lib/liquid/context.rb', line 23 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?
185 186 187 |
# File 'lib/liquid/context.rb', line 185 def [](expression) evaluate(Expression.parse(expression, @string_scanner, @expression_cache)) end |
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
173 174 175 |
# File 'lib/liquid/context.rb', line 173 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
78 79 80 81 82 |
# File 'lib/liquid/context.rb', line 78 def add_filters(filters) filters = [filters].flatten.compact @filters += filters @strainer = nil end |
#apply_global_filter(obj) ⇒ Object
84 85 86 |
# File 'lib/liquid/context.rb', line 84 def apply_global_filter(obj) global_filter.nil? ? obj : global_filter.call(obj) end |
#clear_instance_assigns ⇒ Object
168 169 170 |
# File 'lib/liquid/context.rb', line 168 def clear_instance_assigns @scopes[0] = {} end |
#evaluate(object) ⇒ Object
193 194 195 |
# File 'lib/liquid/context.rb', line 193 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
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/liquid/context.rb', line 198 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
103 104 105 106 107 108 109 |
# File 'lib/liquid/context.rb', line 103 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?
89 90 91 |
# File 'lib/liquid/context.rb', line 89 def interrupt? !@interrupts.empty? end |
#invoke(method, *args) ⇒ Object
111 112 113 |
# File 'lib/liquid/context.rb', line 111 def invoke(method, *args) strainer.invoke(method, *args).to_liquid end |
#key?(key) ⇒ Boolean
189 190 191 |
# File 'lib/liquid/context.rb', line 189 def key?(key) self[key] != nil end |
#lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/liquid/context.rb', line 219 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
122 123 124 |
# File 'lib/liquid/context.rb', line 122 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.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/liquid/context.rb', line 149 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. = end end |
#pop ⇒ Object
Pop from the stack. use Context#stack
instead
127 128 129 130 |
# File 'lib/liquid/context.rb', line 127 def pop raise ContextError if @scopes.size == 1 @scopes.shift end |
#pop_interrupt ⇒ Object
pop an interrupt from the stack
99 100 101 |
# File 'lib/liquid/context.rb', line 99 def pop_interrupt @interrupts.pop end |
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack. use Context#stack
instead
116 117 118 119 |
# File 'lib/liquid/context.rb', line 116 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.
94 95 96 |
# File 'lib/liquid/context.rb', line 94 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
140 141 142 143 144 145 |
# File 'lib/liquid/context.rb', line 140 def stack(new_scope = {}) push(new_scope) yield ensure pop end |
#tag_disabled?(tag_name) ⇒ Boolean
244 245 246 |
# File 'lib/liquid/context.rb', line 244 def tag_disabled?(tag_name) .fetch(tag_name, 0) > 0 end |
#with_disabled_tags(tag_names) ⇒ Object
233 234 235 236 237 238 239 240 241 242 |
# File 'lib/liquid/context.rb', line 233 def (tag_names) tag_names.each do |name| [name] = .fetch(name, 0) + 1 end yield ensure tag_names.each do |name| [name] -= 1 end end |