Class: Ruty::Context
Overview
represents the internal namespace used by ruty It basically works like a hash just that it has multiple layers which can be pushed and popped. That feature is used by the template engine in loops, blocks and other block elements which set variables.
Instance Method Summary collapse
-
#[](name) ⇒ Object
start a recursive lookup for name.
-
#[]=(name, value) ⇒ Object
manipulate the outermost hash.
-
#apply_filters(value, filters) ⇒ Object
apply filters on a value.
-
#each(&block) ⇒ Object
call a block for each item in the context.
-
#has_key?(key) ⇒ Boolean
checks if the key exists in one of the hashes.
-
#initialize(initial = nil) ⇒ Context
constructor
create a new context instance.
-
#pop ⇒ Object
pop the outermost hash from the stack and return it.
-
#pretty_print(q) ⇒ Object
overrides pretty print so that the output for the debug tag looks nicer.
-
#push(hash = nil) ⇒ Object
push a new empty or given hash to the stack.
-
#resolve(path) ⇒ Object
method that resolves dotted names.
Constructor Details
#initialize(initial = nil) ⇒ Context
create a new context instance. initial can be a hash which represents the initial root stack which cannot be popped.
24 25 26 |
# File 'lib/ruty/context.rb', line 24 def initialize initial=nil @stack = [initial || {}] end |
Instance Method Details
#[](name) ⇒ Object
start a recursive lookup for name.
46 47 48 49 50 51 52 |
# File 'lib/ruty/context.rb', line 46 def [] name @stack.each do |hash| val = hash[name] return val if not val.nil? end nil end |
#[]=(name, value) ⇒ Object
manipulate the outermost hash.
41 42 43 |
# File 'lib/ruty/context.rb', line 41 def []= name, value @stack[-1][name] = value end |
#apply_filters(value, filters) ⇒ Object
apply filters on a value
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/ruty/context.rb', line 131 def apply_filters value, filters filters.each do |filter| name, args = filter[0], filter[1..-1] filter = Filters[name] raise TemplateRuntimeError, "filter '#{name}' missing" if filter.nil? args.map! do |arg| if arg.kind_of?(Symbol) resolve(arg) else arg end end value = filter.call(self, value, *args) end value end |
#each(&block) ⇒ Object
call a block for each item in the context. if an item exists in two layers, only the item from the higher layer is yielded.
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/ruty/context.rb', line 62 def each &block found = {} @stack.reverse_each do |hash| hash.each do |key, value| next if found.include?(key) found[key] = hash block.call(key, value) end end end |
#has_key?(key) ⇒ Boolean
checks if the key exists in one of the hashes.
55 56 57 |
# File 'lib/ruty/context.rb', line 55 def has_key? key not send(:[], key).nil? end |
#pop ⇒ Object
pop the outermost hash from the stack and return it. The root hash is never popped, in that case the method returns nil.
36 37 38 |
# File 'lib/ruty/context.rb', line 36 def pop @stack.pop if @stack.size > 1 end |
#pretty_print(q) ⇒ Object
overrides pretty print so that the output for the debug tag looks nicer
75 76 77 78 79 80 81 |
# File 'lib/ruty/context.rb', line 75 def pretty_print q t = {} each do |key, value| t[key] = value end q.pp_hash(t) end |
#push(hash = nil) ⇒ Object
push a new empty or given hash to the stack.
29 30 31 |
# File 'lib/ruty/context.rb', line 29 def push hash=nil @stack << (hash or {}) end |
#resolve(path) ⇒ Object
method that resolves dotted names. Internal it first tries to access hash keys, later array indices and if this also does not work it looks for a ruty_safe? function on the object, calls it with the current part of the dotted name, and if it returns true it calls it without arguments and uses the output as new object for the next part.
{{ foo.bar.blah.42 }}
could for example resolve this:
{{ foo['bar']['blah'][42] }}
call this method only with symbols, numbers and strings are meant to be catched somewhere first.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ruty/context.rb', line 99 def resolve path # start a recursive lookup# current = self path.to_s.split(/\./).each do |part| part_sym = part.to_sym # try hash like objects (with has_key? and []) if current.respond_to?(:has_key?) and tmp = current[part_sym] current = tmp # try hash like objects with integers and array. If this # fails we don't try any longer because method names which # start with numbers are illegal. elsif part =~ /^-?\d+$/ if current.respond_to?(:fetch) or current.respond_to?(:has_key?) \ and tmp = current[part.to_i] current = tmp else return nil end # try method calls on objects with ruty_safe? methods elsif current.respond_to?(:ruty_safe?) and current.ruty_safe?(part_sym) current = current.send(part_sym) # fail with nil in all other cases. else return nil end end current end |