Class: Liquid::Context
- Inherits:
-
Object
- Object
- Liquid::Context
- 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.
-
#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.
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) ⇒ 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.
-
#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 = nil) ⇒ Object
Pushes a new local scope on the stack, pops it at the end of the block.
- #strainer ⇒ Object
- #warnings ⇒ Object
Constructor Details
#initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil) ⇒ Context
Returns a new instance of Context.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/liquid/context.rb', line 18 def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = nil) @environments = [environments].flatten @scopes = [(outer_scope || {})] @registers = registers @errors = [] @partial = false @strict_variables = false @resource_limits = resource_limits || ResourceLimits.new(Template.default_resource_limits) squash_instance_assigns_with_environments @this_stack_used = false self.exception_renderer = Template.default_exception_renderer if rethrow_errors self.exception_renderer = ->(e) { raise } end @interrupts = [] @filters = [] @global_filter = nil end |
Instance Attribute Details
#environments ⇒ Object (readonly)
Returns the value of attribute environments.
15 16 17 |
# File 'lib/liquid/context.rb', line 15 def environments @environments end |
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
15 16 17 |
# File 'lib/liquid/context.rb', line 15 def errors @errors end |
#exception_renderer ⇒ Object
Returns the value of attribute exception_renderer.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def exception_renderer @exception_renderer end |
#global_filter ⇒ Object
Returns the value of attribute global_filter.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def global_filter @global_filter end |
#partial ⇒ Object
Returns the value of attribute partial.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def partial @partial end |
#registers ⇒ Object (readonly)
Returns the value of attribute registers.
15 16 17 |
# File 'lib/liquid/context.rb', line 15 def registers @registers end |
#resource_limits ⇒ Object (readonly)
Returns the value of attribute resource_limits.
15 16 17 |
# File 'lib/liquid/context.rb', line 15 def resource_limits @resource_limits end |
#scopes ⇒ Object (readonly)
Returns the value of attribute scopes.
15 16 17 |
# File 'lib/liquid/context.rb', line 15 def scopes @scopes end |
#strict_filters ⇒ Object
Returns the value of attribute strict_filters.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def strict_filters @strict_filters end |
#strict_variables ⇒ Object
Returns the value of attribute strict_variables.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def strict_variables @strict_variables end |
#template_name ⇒ Object
Returns the value of attribute template_name.
16 17 18 |
# File 'lib/liquid/context.rb', line 16 def template_name @template_name 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?
150 151 152 |
# File 'lib/liquid/context.rb', line 150 def [](expression) evaluate(Expression.parse(expression)) end |
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
134 135 136 137 138 139 140 |
# File 'lib/liquid/context.rb', line 134 def []=(key, value) unless @this_stack_used @this_stack_used = true push({}) end @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
52 53 54 55 56 |
# File 'lib/liquid/context.rb', line 52 def add_filters(filters) filters = [filters].flatten.compact @filters += filters @strainer = nil end |
#apply_global_filter(obj) ⇒ Object
58 59 60 |
# File 'lib/liquid/context.rb', line 58 def apply_global_filter(obj) global_filter.nil? ? obj : global_filter.call(obj) end |
#clear_instance_assigns ⇒ Object
129 130 131 |
# File 'lib/liquid/context.rb', line 129 def clear_instance_assigns @scopes[0] = {} end |
#evaluate(object) ⇒ Object
158 159 160 |
# File 'lib/liquid/context.rb', line 158 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
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/liquid/context.rb', line 163 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) } scope = @scopes[index] if index variable = nil if scope.nil? @environments.each do |e| variable = lookup_and_evaluate(e, key, raise_on_not_found: raise_on_not_found) # When lookup returned a value OR there is no value but the lookup also did not raise # then it is the value we are looking for. if !variable.nil? || @strict_variables && raise_on_not_found scope = e break end end end scope ||= @environments.last || @scopes.last variable ||= lookup_and_evaluate(scope, key, raise_on_not_found: raise_on_not_found) variable = variable.to_liquid variable.context = self if variable.respond_to?(:context=) variable end |
#handle_error(e, line_number = nil) ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/liquid/context.rb', line 77 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?
63 64 65 |
# File 'lib/liquid/context.rb', line 63 def interrupt? !@interrupts.empty? end |
#invoke(method, *args) ⇒ Object
85 86 87 |
# File 'lib/liquid/context.rb', line 85 def invoke(method, *args) strainer.invoke(method, *args).to_liquid end |
#key?(key) ⇒ Boolean
154 155 156 |
# File 'lib/liquid/context.rb', line 154 def key?(key) self[key] != nil end |
#lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/liquid/context.rb', line 192 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
96 97 98 |
# File 'lib/liquid/context.rb', line 96 def merge(new_scopes) @scopes[0].merge!(new_scopes) end |
#pop ⇒ Object
Pop from the stack. use Context#stack
instead
101 102 103 104 |
# File 'lib/liquid/context.rb', line 101 def pop raise ContextError if @scopes.size == 1 @scopes.shift end |
#pop_interrupt ⇒ Object
pop an interrupt from the stack
73 74 75 |
# File 'lib/liquid/context.rb', line 73 def pop_interrupt @interrupts.pop end |
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack. use Context#stack
instead
90 91 92 93 |
# File 'lib/liquid/context.rb', line 90 def push(new_scope = {}) @scopes.unshift(new_scope) raise StackLevelError, "Nesting too deep".freeze if @scopes.length > Block::MAX_DEPTH end |
#push_interrupt(e) ⇒ Object
push an interrupt to the stack. this interrupt is considered not handled.
68 69 70 |
# File 'lib/liquid/context.rb', line 68 def push_interrupt(e) @interrupts.push(e) end |
#stack(new_scope = nil) ⇒ 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
114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/liquid/context.rb', line 114 def stack(new_scope = nil) old_stack_used = @this_stack_used if new_scope push(new_scope) @this_stack_used = true else @this_stack_used = false end yield ensure pop if @this_stack_used @this_stack_used = old_stack_used end |
#strainer ⇒ Object
44 45 46 |
# File 'lib/liquid/context.rb', line 44 def strainer @strainer ||= Strainer.create(self, @filters) end |
#warnings ⇒ Object
40 41 42 |
# File 'lib/liquid/context.rb', line 40 def warnings @warnings ||= [] end |