mullet 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/mullet.rb +8 -0
- data/lib/mullet/container.rb +33 -0
- data/lib/mullet/default_model.rb +67 -0
- data/lib/mullet/default_nested_model.rb +49 -0
- data/lib/mullet/html/attribute_command.rb +32 -0
- data/lib/mullet/html/command.rb +29 -0
- data/lib/mullet/html/template_builder.rb +142 -0
- data/lib/mullet/html/template_loader.rb +55 -0
- data/lib/mullet/model.rb +14 -0
- data/lib/mullet/render_context.rb +84 -0
- data/lib/mullet/template_error.rb +6 -0
- data/lib/mullet/version.rb +3 -0
- metadata +81 -0
data/lib/mullet.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mullet
|
2
|
+
|
3
|
+
# Collection of renderers which will be rendered in the order they were added.
|
4
|
+
module Container
|
5
|
+
def initialize()
|
6
|
+
super if defined?(super)
|
7
|
+
@children = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_child(child)
|
11
|
+
@children << child
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete_child(child)
|
15
|
+
@children.delete(child);
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear_children()
|
19
|
+
@children.clear()
|
20
|
+
end
|
21
|
+
|
22
|
+
# Renders children in order they were added.
|
23
|
+
#
|
24
|
+
# @param [RenderContext] renderContext
|
25
|
+
# render context
|
26
|
+
def render_children(renderContext)
|
27
|
+
@children.each do |child|
|
28
|
+
child.render(renderContext)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'mullet/model'
|
2
|
+
|
3
|
+
module Mullet
|
4
|
+
|
5
|
+
# Default model implementation which resolves variable names to values by
|
6
|
+
# reading from a data object. Given a variable name _key_, the following
|
7
|
+
# mechanisms are tried in this order:
|
8
|
+
#
|
9
|
+
# * If the variable name is `this`, then return the object.
|
10
|
+
# * If the object is a `Hash`, then use _key_ as the key to retrieve the
|
11
|
+
# value from the hash.
|
12
|
+
# * If the object has a method named _key_ taking no parameters, then use
|
13
|
+
# the value returned from calling the method.
|
14
|
+
# * If the object has an instance variable named @_key_, then use the
|
15
|
+
# variable value.
|
16
|
+
#
|
17
|
+
# If the value is a Proc, then use the value returned from calling it.
|
18
|
+
class DefaultModel
|
19
|
+
include Model
|
20
|
+
|
21
|
+
def initialize(data)
|
22
|
+
@data = data
|
23
|
+
end
|
24
|
+
|
25
|
+
def fetch_impl(key)
|
26
|
+
if key == :this
|
27
|
+
return @data
|
28
|
+
end
|
29
|
+
|
30
|
+
# Is the variable name a key in a Hash?
|
31
|
+
if @data.respond_to?(:fetch)
|
32
|
+
# Call the block if the key is not found.
|
33
|
+
return @data.fetch(key) {|k| @data.fetch(k.to_s(), NOT_FOUND) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# Does the variable name match a method name in the object?
|
37
|
+
if @data.respond_to?(key)
|
38
|
+
method = @data.method(key)
|
39
|
+
if method.arity == 0
|
40
|
+
return method.call()
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Does the variable name match an instance variable name in the object?
|
45
|
+
variable = :"@#{key}"
|
46
|
+
if @data.instance_variable_defined?(variable)
|
47
|
+
return @data.instance_variable_get(variable)
|
48
|
+
end
|
49
|
+
|
50
|
+
return NOT_FOUND
|
51
|
+
end
|
52
|
+
|
53
|
+
# Resolves variable name to value.
|
54
|
+
#
|
55
|
+
# @param [Symbol] key
|
56
|
+
# variable name
|
57
|
+
# @return variable value
|
58
|
+
def fetch(key)
|
59
|
+
value = fetch_impl(key)
|
60
|
+
if value.is_a?(Proc)
|
61
|
+
value = value.call()
|
62
|
+
end
|
63
|
+
return value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'mullet/default_model'
|
2
|
+
|
3
|
+
module Mullet
|
4
|
+
|
5
|
+
# Composite model that combines models in nested scopes. Tries each model in
|
6
|
+
# sequence until a value is successfully resolved.
|
7
|
+
class DefaultNestedModel
|
8
|
+
include Model
|
9
|
+
|
10
|
+
# Constructor
|
11
|
+
#
|
12
|
+
# @param dataObjects
|
13
|
+
# scopes in outer to inner order
|
14
|
+
def initialize(*dataObjects)
|
15
|
+
@scopes = []
|
16
|
+
dataObjects.each {|data| push_scope(data) }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Resolves variable name to value.
|
20
|
+
#
|
21
|
+
# @param [Symbol] key
|
22
|
+
# variable name
|
23
|
+
# @return variable value
|
24
|
+
def fetch(key)
|
25
|
+
@scopes.reverse_each do |scope|
|
26
|
+
value = scope.fetch(key)
|
27
|
+
if value != Model::NOT_FOUND
|
28
|
+
return value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
return Model::NOT_FOUND
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds a nested scope to search in subsequent lookups.
|
36
|
+
#
|
37
|
+
# @param data
|
38
|
+
# data object
|
39
|
+
def push_scope(data)
|
40
|
+
@scopes.push(data.is_a?(Model) ? data : DefaultModel.new(data))
|
41
|
+
end
|
42
|
+
|
43
|
+
# Removes innermost nested scope.
|
44
|
+
def pop_scope()
|
45
|
+
@scopes.pop()
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mullet
|
2
|
+
|
3
|
+
# Operation to set attribute value.
|
4
|
+
module AttributeCommand
|
5
|
+
|
6
|
+
# Constructor
|
7
|
+
#
|
8
|
+
# @param [Symbol] attribute_name
|
9
|
+
# name of attribute this command sets
|
10
|
+
def initialize(attribute_name)
|
11
|
+
@attribute_name = attribute_name
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sets attribute in the _attributecommand.
|
15
|
+
#
|
16
|
+
# @param [RenderContext] render_context
|
17
|
+
# render context
|
18
|
+
# @param [Attributes] attributes
|
19
|
+
# attributes to update
|
20
|
+
def execute(render_context, attributes)
|
21
|
+
value = get_value(render_context)
|
22
|
+
if value == Model::NOT_FOUND || value == nil
|
23
|
+
# Value not found. Do not render the attribute.
|
24
|
+
attributes.delete(@attribute_name)
|
25
|
+
else
|
26
|
+
escaped_value = render_context.escape_xml(value)
|
27
|
+
attributes.store(@attribute_name, escaped_value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Mullet
|
2
|
+
|
3
|
+
# Recognized template commands
|
4
|
+
module Command
|
5
|
+
PREFIX = 'mullet:'
|
6
|
+
NAMESPACE_URI = 'http://pukkaone.github.com/mullet/1'
|
7
|
+
|
8
|
+
ACTION = 'action'
|
9
|
+
ALT = 'alt'
|
10
|
+
ALT_MESSAGE = 'alt-message'
|
11
|
+
ATTR = 'attr'
|
12
|
+
ATTR_MESSAGE = 'attr-message'
|
13
|
+
ESCAPE_XML = 'escape-xml'
|
14
|
+
FOR = 'for'
|
15
|
+
HREF = 'href'
|
16
|
+
IF = 'if'
|
17
|
+
INCLUDE = 'include'
|
18
|
+
REMOVE = 'remove'
|
19
|
+
SRC = 'src'
|
20
|
+
TEXT = 'text'
|
21
|
+
TEXT_MESSAGE = 'text-message'
|
22
|
+
TITLE = 'title'
|
23
|
+
TITLE_MESSAGE = 'title-message'
|
24
|
+
UNLESS = 'unless'
|
25
|
+
VALUE = 'value'
|
26
|
+
VALUE_MESSAGE = 'value-message'
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'mullet/html/command'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Mullet; module HTML
|
6
|
+
|
7
|
+
# Handles SAX events to build a template.
|
8
|
+
class TemplateBuilder < Nokogiri::XML::SAX::Document
|
9
|
+
include Command
|
10
|
+
|
11
|
+
XMLNS_ATTRIBUTE_PREFIX = "xmlns:"
|
12
|
+
COMMANDS = [
|
13
|
+
ATTRIBUTE,
|
14
|
+
ATTRIBUTE_MESSAGE,
|
15
|
+
CONTENT,
|
16
|
+
ESCAPE_XML,
|
17
|
+
FOR,
|
18
|
+
IF,
|
19
|
+
INCLUDE,
|
20
|
+
TEXT,
|
21
|
+
TEXT_MESSAGE,
|
22
|
+
UNLESS].to_set
|
23
|
+
START_CDATA = "<![CDATA["
|
24
|
+
END_CDATA = "]]>"
|
25
|
+
|
26
|
+
@loader = nil
|
27
|
+
|
28
|
+
# This is a stack of elements where this handler has seen the start tag and
|
29
|
+
# not yet seen the end tag.
|
30
|
+
@openElements = []
|
31
|
+
|
32
|
+
# stack of current containers to add renderers to
|
33
|
+
@containers = []
|
34
|
+
|
35
|
+
@staticText = ""
|
36
|
+
@template = nil
|
37
|
+
|
38
|
+
# Constructor
|
39
|
+
#
|
40
|
+
# @param [TemplateLoader] loader
|
41
|
+
# template loader to use to load included template files
|
42
|
+
def initialize(loader)
|
43
|
+
@loader = loader
|
44
|
+
end
|
45
|
+
|
46
|
+
# Adds renderer to current container.
|
47
|
+
#
|
48
|
+
# @param [#render] renderer
|
49
|
+
# renderer to add
|
50
|
+
def add_child(renderer)
|
51
|
+
@containers.last.add_child(renderer)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Deletes renderer from current container.
|
55
|
+
#
|
56
|
+
# @param [#render] renderer
|
57
|
+
# renderer to delete
|
58
|
+
def delete_child(renderer)
|
59
|
+
@containers.last.delete_child(renderer)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Partitions the attributes into ordinary and command attributes.
|
63
|
+
#
|
64
|
+
# @param [Array] attributes
|
65
|
+
# input attributes
|
66
|
+
# @param [Hash] ns
|
67
|
+
# hash of namespace prefix to uri mappings
|
68
|
+
# @param [#store] ordinaryAttributes
|
69
|
+
# hash will receive name to value mappings for ordinary attributes
|
70
|
+
# @param [#store] commandAttributes
|
71
|
+
# hash will receive name to value mappings for command attributes
|
72
|
+
# @return [Boolean] true if any command attribute found
|
73
|
+
def find_commands(attributes, ns, ordinaryAttributes, commandAttributes)
|
74
|
+
foundCommand = false
|
75
|
+
attributes.each do |attr|
|
76
|
+
if attr.uri == NAMESPACE_URI
|
77
|
+
commandName = attr.localname
|
78
|
+
if !COMMANDS.contains(commandName)
|
79
|
+
raise TemplateException("invalid command '#{commandName}'")
|
80
|
+
end
|
81
|
+
commandAttributes.store(commandName, attr.value)
|
82
|
+
foundCommand = true
|
83
|
+
else
|
84
|
+
attributeName = [attr.prefix, attr.localname].compact.join(':')
|
85
|
+
ordinaryAttributes.store(attributeName, attr.value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
ns.each do |prefix, uri|
|
90
|
+
if uri != NAMESPACE_URI
|
91
|
+
attributeName = ['xmlns', prefix].compact.join(':')
|
92
|
+
ordinaryAttributes.store(attributeName, uri)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
return foundCommand
|
97
|
+
end
|
98
|
+
|
99
|
+
def render_start_tag(name, attributes, prefix, uri, namespaceDecls)
|
100
|
+
tag = "<"
|
101
|
+
if prefix
|
102
|
+
tag << prefix << ":"
|
103
|
+
end
|
104
|
+
tag << name
|
105
|
+
|
106
|
+
attributes.each do |attribute|
|
107
|
+
tag << " "
|
108
|
+
if attribute.prefix
|
109
|
+
tag << attribute.prefix << ":"
|
110
|
+
end
|
111
|
+
tag = attribute.localname << '="' << attribute.value << '"'
|
112
|
+
end
|
113
|
+
|
114
|
+
namespaceDecls.each do |namespaceDecl|
|
115
|
+
uri = namespaceDecl[1]
|
116
|
+
if uri != TEMPLATE_NAMESPACE_URI
|
117
|
+
tag << " xmlns:" << namespaceDecl[0] << '="' << uri << '"'
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
tag << ">"
|
122
|
+
return tag
|
123
|
+
end
|
124
|
+
|
125
|
+
def start_element_namespace(name, attributes, prefix, uri, ns)
|
126
|
+
puts "start element #{name} #{attributes} #{prefix} #{uri} #{ns}"
|
127
|
+
templateAttributes = attributes.select do |attribute|
|
128
|
+
attribute.uri == TEMPLATE_NAMESPACE_URI
|
129
|
+
end
|
130
|
+
if templateAttributes.empty?
|
131
|
+
puts render_start_tag(name, attributes, prefix, uri, ns)
|
132
|
+
else
|
133
|
+
puts "attributes #{templateAttributes}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def end_document
|
138
|
+
puts "the document has ended"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end; end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Mullet
|
4
|
+
|
5
|
+
class TemplateDocument < Nokogiri::XML::SAX::Document
|
6
|
+
TEMPLATE_NAMESPACE_URI = "http://pukkaone.github.com/mullet/1"
|
7
|
+
|
8
|
+
def render_start_tag(name, attributes, prefix, uri, namespaceDecls)
|
9
|
+
tag = "<"
|
10
|
+
if prefix
|
11
|
+
tag << prefix << ":"
|
12
|
+
end
|
13
|
+
tag << name
|
14
|
+
|
15
|
+
attributes.each do |attribute|
|
16
|
+
tag << " "
|
17
|
+
if attribute.prefix
|
18
|
+
tag << attribute.prefix << ":"
|
19
|
+
end
|
20
|
+
tag = attribute.localname << '="' << attribute.value << '"'
|
21
|
+
end
|
22
|
+
|
23
|
+
namespaceDecls.each do |namespaceDecl|
|
24
|
+
uri = namespaceDecl[1]
|
25
|
+
if uri != TEMPLATE_NAMESPACE_URI
|
26
|
+
tag << " xmlns:" << namespaceDecl[0] << '="' << uri << '"'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
tag << ">"
|
31
|
+
return tag
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_element_namespace(name, attributes, prefix, uri, ns)
|
35
|
+
puts "start element #{name} #{attributes} #{prefix} #{uri} #{ns}"
|
36
|
+
templateAttributes = attributes.select do |attribute|
|
37
|
+
attribute.uri == TEMPLATE_NAMESPACE_URI
|
38
|
+
end
|
39
|
+
if templateAttributes.empty?
|
40
|
+
puts render_start_tag(name, attributes, prefix, uri, ns)
|
41
|
+
else
|
42
|
+
puts "attributes #{templateAttributes}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def end_document
|
47
|
+
puts "the document has ended"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
parser = Nokogiri::HTML::SAX::Parser.new(TemplateDocument.new)
|
52
|
+
f = File.open("login.html")
|
53
|
+
parser.parse(f)
|
54
|
+
f.close
|
55
|
+
end
|
data/lib/mullet/model.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Mullet
|
2
|
+
|
3
|
+
# A model responds to the method `fetch` taking a variable name argument and
|
4
|
+
# returning the variable value. If the variable name is not found, it
|
5
|
+
# returns the value `NOT_FOUND` instead of raising an exception. A model
|
6
|
+
# class must include this module because the implementation calls
|
7
|
+
# `is_a?(Model)` to determine if an object satisfies the concept of a model.
|
8
|
+
module Model
|
9
|
+
|
10
|
+
# special value indicating variable name was not found
|
11
|
+
NOT_FOUND = Object.new()
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Mullet
|
2
|
+
|
3
|
+
# Holds the rendering context to reduce the number of parameters passed to
|
4
|
+
# render methods.
|
5
|
+
class RenderContext
|
6
|
+
attr_accessor :escapeXmlEnabled
|
7
|
+
|
8
|
+
# Constructor.
|
9
|
+
#
|
10
|
+
# @param [Model] model
|
11
|
+
# provides data to render
|
12
|
+
# @param [Proc] missingValueStrategy
|
13
|
+
# executed on attempt to render a variable that was not found
|
14
|
+
# @param [Proc] nilValueStrategy
|
15
|
+
# executed on attempt to render nil value
|
16
|
+
# @param [#<<] output
|
17
|
+
# where rendered output will be written
|
18
|
+
def initialize(model, missingValueStrategy, nilValueStrategy, output)
|
19
|
+
@model = model
|
20
|
+
@missingValueStrategy = missingValueStrategy
|
21
|
+
@nilValueStrategy = nilValueStrategy
|
22
|
+
@output = output
|
23
|
+
@escapeXmlEnabled = true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Escapes characters that could be interpreted as XML markup if enabled.
|
27
|
+
#
|
28
|
+
# @param [String] input
|
29
|
+
# input string
|
30
|
+
# @return escaped string, or the input string if escaping is disabled.
|
31
|
+
def escape_xml(key)
|
32
|
+
return @escapeXmlEnabled ? CGI.escape_html(input) : input
|
33
|
+
end
|
34
|
+
|
35
|
+
# Resolves variable name to value.
|
36
|
+
#
|
37
|
+
# @param [Symbol] key
|
38
|
+
# variable name
|
39
|
+
# @return value
|
40
|
+
def fetch(key)
|
41
|
+
return @model.fetch(key)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Adds a nested scope to search in subsequent lookups.
|
45
|
+
#
|
46
|
+
# @param data
|
47
|
+
# data object
|
48
|
+
def push_scope(data)
|
49
|
+
@model.push_scope(data)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Removes innermost nested scope.
|
53
|
+
def pop_scope()
|
54
|
+
@model.pop_scope()
|
55
|
+
end
|
56
|
+
|
57
|
+
# Gets model value that is intended for display in the rendered output.
|
58
|
+
# Applies configured strategies for handling missing and nil values.
|
59
|
+
#
|
60
|
+
# @param [Symbol] key
|
61
|
+
# variable name
|
62
|
+
def get_display_value(key)
|
63
|
+
value = @model.fetch(key)
|
64
|
+
if value == Model::NOT_FOUND
|
65
|
+
value = @missingValueStrategy.call(key)
|
66
|
+
end
|
67
|
+
if value == nil
|
68
|
+
value = @nilValueStrategy.call(key)
|
69
|
+
end
|
70
|
+
return value
|
71
|
+
end
|
72
|
+
|
73
|
+
# Writes rendered output.
|
74
|
+
#
|
75
|
+
# @param [String] str
|
76
|
+
# string to write
|
77
|
+
# @return this object
|
78
|
+
def <<(str)
|
79
|
+
@output << str
|
80
|
+
return self
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mullet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chin Huang
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: &2152289140 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152289140
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: yard
|
27
|
+
requirement: &2152288740 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2152288740
|
36
|
+
description: ! "It's like mustache but in HTML syntax.\n\n * Extremely simple variable
|
37
|
+
syntax is incapable of expressing logic in the\n templates.\n * Templates are
|
38
|
+
clean HTML. Your HTML authoring tool and browser will\n correctly display the
|
39
|
+
templates while you prototype your user interface.\n"
|
40
|
+
email: pukkaone@gmail.com
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- lib/mullet/container.rb
|
46
|
+
- lib/mullet/default_model.rb
|
47
|
+
- lib/mullet/default_nested_model.rb
|
48
|
+
- lib/mullet/html/attribute_command.rb
|
49
|
+
- lib/mullet/html/command.rb
|
50
|
+
- lib/mullet/html/template_builder.rb
|
51
|
+
- lib/mullet/html/template_loader.rb
|
52
|
+
- lib/mullet/model.rb
|
53
|
+
- lib/mullet/render_context.rb
|
54
|
+
- lib/mullet/template_error.rb
|
55
|
+
- lib/mullet/version.rb
|
56
|
+
- lib/mullet.rb
|
57
|
+
homepage: http://pukkaone.github.com/mullet/
|
58
|
+
licenses: []
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.9'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project: nowarning
|
77
|
+
rubygems_version: 1.8.11
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Logic-less HTML template engine
|
81
|
+
test_files: []
|