Class: Undies::Template

Inherits:
Object
  • Object
show all
Defined in:
lib/undies/template.rb

Constant Summary collapse

ELEM_METH_REGEX =

Element proxy methods (‘_<element>”) ========================

/^_(.+)$/
ESCAPE_HTML =

Ripped from Rack v1.3.0 ======================================

> ripped b/c I don’t want a dependency on Rack for just this

{
  "&" => "&amp;",
  "<" => "&lt;",
  ">" => "&gt;",
  "'" => "&#x27;",
  '"' => "&quot;",
  "/" => "&#x2F;"
}
ESCAPE_HTML_PATTERN =
Regexp.union(*ESCAPE_HTML.keys)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Template

Returns a new instance of Template.



22
23
24
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
# File 'lib/undies/template.rb', line 22

def initialize(*args)
  output = if args.last.kind_of?(Output)
    args.pop
  else
    raise ArgumentError, "please provide an Output object"
  end
  data = args.last.kind_of?(::Hash) ? args.pop : {}
  source = args.last.kind_of?(Source) ? args.pop : Source.new(Proc.new {})

  # setup the source stack and output objects
  @_undies_source_stack = SourceStack.new(source)

  # apply data to template scope
  if (data.keys.map(&:to_s) & self.public_methods.map(&:to_s)).size > 0
    raise ArgumentError, "data conflicts with template public methods."
  end
  metaclass = class << self; self; end
  data.each {|key, value| metaclass.class_eval { define_method(key){value} }}

  # save off the output obj for streaming
  @_undies_output = output

  # yield to recursivley render the source stack
  self.__yield

  # flush any remaining output to the stream
  self.class.flush(self)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/undies/template.rb', line 86

def method_missing(meth, *args, &block)
  if meth.to_s =~ ELEM_METH_REGEX
    element($1, *args, &block)
  else
    super
  end
end

Class Method Details

.flush(template) ⇒ Object



18
19
20
# File 'lib/undies/template.rb', line 18

def self.flush(template)
  template.instance_variable_get("@_undies_output").flush
end

.output(template) ⇒ Object

have as many methods on the class level as possible to keep from polluting the public instance methods, the instance scope, and to maximize the effectiveness of the Template#method_missing logic



14
15
16
# File 'lib/undies/template.rb', line 14

def self.output(template)
  template.instance_variable_get("@_undies_output")
end

Instance Method Details

#_(data = "") ⇒ Object

Add a text node (data escaped) to the nodes of the current node



70
# File 'lib/undies/template.rb', line 70

def _(data=""); self.__ self.escape_html(data.to_s); end

#__(data = "") ⇒ Object

Add a text node with the data un-escaped



73
# File 'lib/undies/template.rb', line 73

def __(data=""); @_undies_output.node(Node.new(data.to_s)); end

#___(data = "") ⇒ Object

Add a text node with the data un-escaped, forcing pp output



76
77
78
# File 'lib/undies/template.rb', line 76

def ___(data="")
  @_undies_output.node(Node.new(data.to_s, :force_pp => true))
end

#__partial(source, data) ⇒ Object

call this to render partial source embedded in a template partial source is rendered with its own scope/data but shares its parent template’s output object



65
66
67
# File 'lib/undies/template.rb', line 65

def __partial(source, data)
  Undies::Template.new(source, data, @_undies_output)
end

#__yieldObject

call this to render template source use this method in layouts to insert a layout’s content source



53
54
55
56
57
58
59
60
# File 'lib/undies/template.rb', line 53

def __yield
  return if @_undies_source_stack.nil? || (source = @_undies_source_stack.pop).nil?
  if source.file?
    instance_eval(source.data, source.source, 1)
  else
    instance_eval(&source.data)
  end
end

#element(*args, &block) ⇒ Object Also known as: tag

Add an element to the nodes of the current node



81
# File 'lib/undies/template.rb', line 81

def element(*args, &block); @_undies_output.node(Element.new(*args, &block)); end

#escape_html(string) ⇒ Object

Escape ampersands, brackets and quotes to their HTML/XML entities.



114
115
116
# File 'lib/undies/template.rb', line 114

def escape_html(string)
  string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
end

#respond_to?(*args) ⇒ Boolean

Returns:

  • (Boolean)


93
94
95
96
97
98
99
# File 'lib/undies/template.rb', line 93

def respond_to?(*args)
  if args.first.to_s =~ ELEM_METH_REGEX
    true
  else
    super
  end
end