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 52 53 54 55 |
# 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].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(Template.default_resource_limits) @base_scope_depth = 0 @interrupts = [] @filters = [] @global_filter = nil @disabled_tags = {} @registers.static[:cached_partials] ||= {} @registers.static[:file_system] ||= Liquid::Template.file_system @registers.static[:template_factory] ||= Liquid::TemplateFactory.new 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
62 63 64 |
# File 'lib/liquid/context.rb', line 62 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
58 59 60 |
# File 'lib/liquid/context.rb', line 58 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?
176 177 178 |
# File 'lib/liquid/context.rb', line 176 def [](expression) evaluate(Expression.parse(expression)) end |
#[]=(key, value) ⇒ Object
Only allow String, Numeric, Hash, Array, Proc, Boolean or Liquid::Drop
164 165 166 |
# File 'lib/liquid/context.rb', line 164 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
70 71 72 73 74 |
# File 'lib/liquid/context.rb', line 70 def add_filters(filters) filters = [filters].flatten.compact @filters += filters @strainer = nil end |
#apply_global_filter(obj) ⇒ Object
76 77 78 |
# File 'lib/liquid/context.rb', line 76 def apply_global_filter(obj) global_filter.nil? ? obj : global_filter.call(obj) end |
#clear_instance_assigns ⇒ Object
159 160 161 |
# File 'lib/liquid/context.rb', line 159 def clear_instance_assigns @scopes[0] = {} end |
#evaluate(object) ⇒ Object
184 185 186 |
# File 'lib/liquid/context.rb', line 184 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
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/liquid/context.rb', line 189 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
95 96 97 98 99 100 101 |
# File 'lib/liquid/context.rb', line 95 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?
81 82 83 |
# File 'lib/liquid/context.rb', line 81 def interrupt? !@interrupts.empty? end |
#invoke(method, *args) ⇒ Object
103 104 105 |
# File 'lib/liquid/context.rb', line 103 def invoke(method, *args) strainer.invoke(method, *args).to_liquid end |
#key?(key) ⇒ Boolean
180 181 182 |
# File 'lib/liquid/context.rb', line 180 def key?(key) self[key] != nil end |
#lookup_and_evaluate(obj, key, raise_on_not_found: true) ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/liquid/context.rb', line 210 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
114 115 116 |
# File 'lib/liquid/context.rb', line 114 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.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/liquid/context.rb', line 141 def new_isolated_subcontext check_overflow self.class.build( 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
119 120 121 122 |
# File 'lib/liquid/context.rb', line 119 def pop raise ContextError if @scopes.size == 1 @scopes.shift end |
#pop_interrupt ⇒ Object
pop an interrupt from the stack
91 92 93 |
# File 'lib/liquid/context.rb', line 91 def pop_interrupt @interrupts.pop end |
#push(new_scope = {}) ⇒ Object
Push new local scope on the stack. use Context#stack
instead
108 109 110 111 |
# File 'lib/liquid/context.rb', line 108 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.
86 87 88 |
# File 'lib/liquid/context.rb', line 86 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
132 133 134 135 136 137 |
# File 'lib/liquid/context.rb', line 132 def stack(new_scope = {}) push(new_scope) yield ensure pop end |
#tag_disabled?(tag_name) ⇒ Boolean
235 236 237 |
# File 'lib/liquid/context.rb', line 235 def tag_disabled?(tag_name) @disabled_tags.fetch(tag_name, 0) > 0 end |
#with_disabled_tags(tag_names) ⇒ Object
224 225 226 227 228 229 230 231 232 233 |
# File 'lib/liquid/context.rb', line 224 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 |