Class: Mustache::Context

Inherits:
Object
  • Object
show all
Defined in:
lib/mustache/context.rb,
lib/mustache/context_miss.rb

Overview

A Context represents the context which a Mustache template is executed within. All Mustache tags reference keys in the Context.

Instance Method Summary collapse

Constructor Details

#initialize(mustache) ⇒ Context

Initializes a Mustache::Context.

Parameters:

  • mustache (Mustache)

    A Mustache instance.



14
15
16
17
# File 'lib/mustache/context.rb', line 14

def initialize(mustache)
  @stack = [mustache]
  @partial_template_cache = {}
end

Instance Method Details

#[](name) ⇒ Object

Alias for fetch.



93
94
95
# File 'lib/mustache/context.rb', line 93

def [](name)
  fetch(name, nil)
end

#[]=(name, value) ⇒ Object

Can be used to add a value to the context in a hash-like way.

context = "Chris"



88
89
90
# File 'lib/mustache/context.rb', line 88

def []=(name, value)
  push(name => value)
end

#context_level_violation(message, default = nil) ⇒ Object

Raises ContextLevelViolation or returns default depending on raise_on_context_miss

Parameters:

  • message (String)

    The error message if raise_on_context_miss is set

  • default (Object) (defaults to: nil)

    An optional default value, to return if the key is not found.

Returns:

  • (Object)

    The default value if errors are not raised

Raises:



33
34
35
36
# File 'lib/mustache/context_miss.rb', line 33

def context_level_violation(message, default = nil)
  return default unless mustache_in_stack.raise_on_context_miss?
  raise ContextLevelViolation.new(message)
end

#currentObject



172
173
174
# File 'lib/mustache/context.rb', line 172

def current
  @stack.first
end

#escape(value) ⇒ String

Allows customization of how Mustache escapes things.

Parameters:

  • value (Object)

    Value to escape.

Returns:

  • (String)

    Escaped string.



58
59
60
# File 'lib/mustache/context.rb', line 58

def escape(value)
  mustache_in_stack.escape(value)
end

#fetch(name, default = :__raise) ⇒ Object

Similar to Hash#fetch, finds a value by name in the context's stack. You may specify the default return value by passing a second parameter.

If no second parameter is passed (or raise_on_context_miss is set to true), will raise a ContextMiss exception on miss.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/mustache/context.rb', line 111

def fetch(name, default = :__raise)
  @stack.each do |frame|
    # Prevent infinite recursion.
    next if frame == self

    value = find(frame, name, :__missing)
    return value if :__missing != value
  end

  if default == :__raise || mustache_in_stack.raise_on_context_miss?
    raise ContextMiss.new("Can't find #{name} in #{@stack.inspect}")
  else
    default
  end
end

#find(obj, key, default = nil) ⇒ Object

Finds a key in an object, using whatever method is most appropriate. If the object is a hash, does a simple hash lookup. If it's an object that responds to the key as a method call, invokes that method. You get the idea.

Parameters:

  • obj (Object)

    The object to perform the lookup on.

  • key (String, Symbol)

    The key whose value you want

  • default (Object) (defaults to: nil)

    An optional default value, to return if the key is not found.

Returns:

  • (Object)

    The value of key in object if it is found, and default otherwise.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/mustache/context.rb', line 138

def find(obj, key, default = nil)

  if mustache_in_stack.context_access_security_level == 5 and !obj.instance_of?(Hash)
    # on level 5, object must be exactly Hash
    return context_level_violation("Detected key access attempt for a non-Hash object using '#{key}'", default)
  end

  return find_in_hash(obj.to_hash, key, default) if obj.respond_to?(:to_hash)

  if mustache_in_stack.context_access_security_level >= 4
    # on levels 4 and 5, method access is not allowed
    return context_level_violation("Detected method access attempt using '#{key}'", default)
  end

  unless obj.respond_to?(key)
    # no match for the key, but it may include a hyphen, so try again replacing hyphens with underscores.
    key = key.to_s.tr('-', '_')
    return default unless obj.respond_to?(key)
  end

  if mustache_in_stack.context_access_security_level >= 3 && !obj.class.instance_methods(false).include?(key.to_sym)
    # on level 3, inherited methods are blocked
    return context_level_violation("Detected inherited method '#{key}'", default)
  end

  if mustache_in_stack.context_access_security_level >= 2 && MethodBlacklist.include?(key.to_s)
    # on levels 2 and 3, reflection-based methods are blacklisted
    return context_level_violation("Detected blacklisted reflection-related key '#{key}'", default)
  end

  meth = obj.method(key) rescue proc { obj.send(key) }
  meth.arity == 1 ? meth.to_proc : meth.call
end

#has_key?(key) ⇒ Boolean

Do we know about a particular key? In other words, will calling context[key] give us a result that was set. Basically.

Returns:

  • (Boolean)


99
100
101
102
103
# File 'lib/mustache/context.rb', line 99

def has_key?(key)
  fetch(key, false)
rescue ContextMiss
  false
end

#mustache_in_stackMustache

Find the first Mustache in the stack.

If we're being rendered inside a Mustache object as a context, we'll use that one.

Returns:

  • (Mustache)

    First Mustache in the stack.



48
49
50
# File 'lib/mustache/context.rb', line 48

def mustache_in_stack
  @mustache_in_stack ||= @stack.find { |frame| frame.is_a?(Mustache) }
end

#partial(name, indentation = '') ⇒ Object

A {>partial} tag translates into a call to the context's partial method, which would be this sucker right here.

If the Mustache view handling the rendering (e.g. the view representing your profile page or some other template) responds to partial, we call it and render the result.



26
27
28
29
30
31
32
33
34
35
# File 'lib/mustache/context.rb', line 26

def partial(name, indentation = '')
  # Look for the first Mustache in the stack.
  mustache = mustache_in_stack

  # Indent the partial template by the given indentation.
  part = mustache.partial(name).to_s.gsub(/^/, indentation)

  # Get a template object for the partial and render the result.
  template_for_partial(part).render(self)
end

#popContext

Removes the most recently added object from the context's internal stack.

Returns:

  • (Context)

    Returns the Context.



79
80
81
82
83
# File 'lib/mustache/context.rb', line 79

def pop
  @stack.shift
  @mustache_in_stack = nil
  self
end

#push(new_obj) ⇒ Context

Adds a new object to the context's internal stack.

Parameters:

  • new_obj (Object)

    Object to be added to the internal stack.

Returns:

  • (Context)

    Returns the Context.



68
69
70
71
72
# File 'lib/mustache/context.rb', line 68

def push(new_obj)
  @stack.unshift(new_obj)
  @mustache_in_stack = nil
  self
end

#template_for_partial(partial) ⇒ Object



37
38
39
# File 'lib/mustache/context.rb', line 37

def template_for_partial(partial)
  @partial_template_cache[partial] ||= Template.new(partial)
end