undies 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/undies/{tag.rb → element.rb} +38 -18
- data/lib/undies/node.rb +38 -0
- data/lib/undies/node_list.rb +28 -0
- data/lib/undies/partial.rb +20 -0
- data/lib/undies/partial_data.rb +32 -0
- data/lib/undies/source.rb +12 -10
- data/lib/undies/template.rb +100 -8
- data/lib/undies/version.rb +1 -1
- data/test/{tag_test.rb → element_test.rb} +58 -26
- data/test/node_list_test.rb +48 -0
- data/test/node_test.rb +24 -0
- data/test/partial_data_test.rb +100 -0
- data/test/partial_test.rb +41 -0
- data/test/source_test.rb +14 -5
- data/test/template_test.rb +128 -4
- data/test/templates/index.html.rb +0 -0
- metadata +23 -12
- data/lib/undies/buffer.rb +0 -81
- data/test/buffer_test.rb +0 -79
- /data/test/{test_template.html.rb → templates/test.html.rb} +0 -0
data/Gemfile.lock
CHANGED
@@ -1,17 +1,30 @@
|
|
1
|
-
require 'undies/
|
1
|
+
require 'undies/node'
|
2
|
+
require 'undies/node_list'
|
2
3
|
|
3
4
|
module Undies
|
4
|
-
class
|
5
|
+
class Element < Node
|
5
6
|
|
6
|
-
attr_reader :attrs
|
7
|
+
attr_reader :name, :attrs
|
8
|
+
attr_accessor :nodes
|
7
9
|
|
8
|
-
def initialize(name
|
9
|
-
super
|
10
|
-
@
|
10
|
+
def initialize(stack, name, attrs={}, &block)
|
11
|
+
super(@nodes = NodeList.new)
|
12
|
+
@stack = stack
|
13
|
+
@name = name.to_s
|
11
14
|
@attrs = attrs
|
15
|
+
@content_writes = 0
|
12
16
|
self.content = block
|
13
17
|
end
|
14
18
|
|
19
|
+
def start_tag
|
20
|
+
"<#{@name}#{html_attrs(@attrs)}" + (@content_writes > 0 ? ">" : " />")
|
21
|
+
end
|
22
|
+
|
23
|
+
def end_tag
|
24
|
+
@content_writes > 0 ? "</#{@name}>" : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# CSS proxy methods ============================================
|
15
28
|
ID_METH_REGEX = /^([^_].+)!$/
|
16
29
|
CLASS_METH_REGEX = /^([^_].+)$/
|
17
30
|
|
@@ -32,17 +45,22 @@ module Undies
|
|
32
45
|
super
|
33
46
|
end
|
34
47
|
end
|
48
|
+
# ==============================================================
|
35
49
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
def ==(other)
|
51
|
+
other.name == self.name &&
|
52
|
+
other.attrs == self.attrs &&
|
53
|
+
other.nodes == self.nodes
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_str(*args)
|
57
|
+
"Undies::Element:#{self.object_id} " +
|
58
|
+
"@name=#{@name.inspect}, @attrs=#{@attrs.inspect}, @nodes=#{@nodes.inspect}"
|
59
|
+
end
|
60
|
+
alias_method :inspect, :to_str
|
61
|
+
|
62
|
+
def to_ary(*args)
|
63
|
+
@nodes
|
46
64
|
end
|
47
65
|
|
48
66
|
protected
|
@@ -78,8 +96,10 @@ module Undies
|
|
78
96
|
|
79
97
|
def content=(block)
|
80
98
|
if block
|
81
|
-
@
|
82
|
-
|
99
|
+
@content_writes += 1
|
100
|
+
@stack.push(self)
|
101
|
+
block.call
|
102
|
+
@stack.pop
|
83
103
|
end
|
84
104
|
end
|
85
105
|
|
data/lib/undies/node.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Undies
|
2
|
+
class Node
|
3
|
+
|
4
|
+
attr_reader :content
|
5
|
+
|
6
|
+
def initialize(content)
|
7
|
+
@content = content
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_tag
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def end_tag
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s(pp_level=0, pp_indent=nil)
|
19
|
+
[ self.start_tag,
|
20
|
+
self.content,
|
21
|
+
self.end_tag
|
22
|
+
].compact.collect do |item|
|
23
|
+
pretty_print(item, pp_level, pp_indent)
|
24
|
+
end.join
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def pretty_print(data, level, indent)
|
30
|
+
if data.kind_of? NodeList
|
31
|
+
data.to_s(level+1, indent)
|
32
|
+
else
|
33
|
+
indent ? "#{' '*level*indent}#{data}\n" : data
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "undies/node"
|
2
|
+
|
3
|
+
module Undies
|
4
|
+
class NodeList < ::Array
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
#always initialize empty
|
8
|
+
super()
|
9
|
+
end
|
10
|
+
|
11
|
+
def append(node)
|
12
|
+
self << node
|
13
|
+
node
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(item)
|
17
|
+
unless item.kind_of?(Node)
|
18
|
+
raise ArgumentError, 'you can only append nodes to a NodeList'
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s(pp_level=0, pp_indent=nil)
|
24
|
+
self.collect{|n| n.to_s(pp_level, pp_indent)}.join
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'undies/partial_data'
|
2
|
+
require 'undies/template'
|
3
|
+
|
4
|
+
module Undies
|
5
|
+
class Partial < Template
|
6
|
+
|
7
|
+
def initialize(path, object=nil, locals={})
|
8
|
+
data = PartialData.new(path)
|
9
|
+
data.object, data.values = object_locals(object, locals)
|
10
|
+
super(path, data)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def object_locals(o, l)
|
16
|
+
o && o.kind_of?(::Hash) ? [nil, o] : [o, l || {}]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Undies
|
2
|
+
class PartialData < ::Hash
|
3
|
+
|
4
|
+
attr_reader :path, :name
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
self.path = path
|
8
|
+
super()
|
9
|
+
end
|
10
|
+
|
11
|
+
def path=(value)
|
12
|
+
raise ArgumentError, "partial path required" if value.nil?
|
13
|
+
@path = value
|
14
|
+
@name = File.basename(@path.to_s).split(".").first.gsub(/^[^A-Za-z]+/, '')
|
15
|
+
end
|
16
|
+
|
17
|
+
def values=(value)
|
18
|
+
raise ArgumentError if !value.kind_of?(::Hash)
|
19
|
+
if value.has_key?(@name.to_sym)
|
20
|
+
value[@name] = value.delete(@name.to_sym)
|
21
|
+
end
|
22
|
+
self.merge!(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def object=(value)
|
26
|
+
if value
|
27
|
+
self[@name] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/lib/undies/source.rb
CHANGED
@@ -1,24 +1,26 @@
|
|
1
1
|
module Undies
|
2
2
|
class Source
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :source, :data
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
raise ArgumentError, "file or block required" if
|
6
|
+
def initialize(source=nil)
|
7
|
+
raise ArgumentError, "file or block required" if source.nil?
|
8
8
|
|
9
|
-
@
|
10
|
-
|
9
|
+
@source = source
|
10
|
+
if self.file? && !File.exists?(@source.to_s)
|
11
|
+
raise ArgumentError, "no template file '#{@source}'"
|
12
|
+
end
|
11
13
|
|
12
|
-
# load
|
13
|
-
@data =
|
14
|
-
File.binread
|
14
|
+
# load source data and prepare (uses binread to avoid encoding issues)
|
15
|
+
@data = if self.file?
|
16
|
+
File.send(File.respond_to?(:binread) ? :binread : :read, @source.to_s)
|
15
17
|
else
|
16
|
-
|
18
|
+
@source
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
def file?
|
21
|
-
|
23
|
+
!@source.kind_of?(::Proc)
|
22
24
|
end
|
23
25
|
|
24
26
|
end
|
data/lib/undies/template.rb
CHANGED
@@ -1,22 +1,114 @@
|
|
1
1
|
require 'undies/source'
|
2
|
-
require 'undies/
|
3
|
-
require 'undies/
|
2
|
+
require 'undies/node'
|
3
|
+
require 'undies/element'
|
4
4
|
|
5
5
|
module Undies
|
6
|
-
class Template
|
6
|
+
class Template
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
attr_accessor :nodes
|
9
|
+
|
10
|
+
def initialize(*args, &block)
|
11
|
+
@nodes = NodeList.new
|
12
|
+
@stack = [self]
|
13
|
+
self.data, @source = data_source(args, block)
|
14
|
+
|
15
|
+
if (@source).file?
|
16
|
+
instance_eval(@source.data, @source.source, 1)
|
12
17
|
else
|
13
18
|
instance_eval(&@source.data)
|
14
19
|
end
|
15
20
|
end
|
16
21
|
|
17
22
|
def to_s(pp_indent=nil)
|
18
|
-
|
23
|
+
@nodes.collect{|n| n.to_s(0, pp_indent)}.join
|
24
|
+
end
|
25
|
+
|
26
|
+
# Add a text node (data escaped) to the nodes of the current node
|
27
|
+
def _(data)
|
28
|
+
@stack.last.nodes.append(Node.new(escape_html(data.to_s)))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Add a text node with the data un-escaped
|
32
|
+
def __(data)
|
33
|
+
@stack.last.nodes.append(Node.new(data.to_s))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Add an element to the nodes of the current node
|
37
|
+
def element(name, attrs={}, &block)
|
38
|
+
@stack.last.nodes.append(Element.new(@stack, name, attrs, &block))
|
39
|
+
end
|
40
|
+
alias_method :tag, :element
|
41
|
+
|
42
|
+
# Element proxy methods ('_<element>'') ========================
|
43
|
+
ELEM_METH_REGEX = /^_(.+)$/
|
44
|
+
|
45
|
+
def method_missing(meth, *args, &block)
|
46
|
+
if meth.to_s =~ ELEM_METH_REGEX
|
47
|
+
element($1, *args, &block)
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def respond_to?(*args)
|
54
|
+
if args.first.to_s =~ ELEM_METH_REGEX
|
55
|
+
true
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
19
59
|
end
|
60
|
+
# ==============================================================
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def data=(data)
|
65
|
+
raise ArgumentError if !data.kind_of?(::Hash)
|
66
|
+
data.each do |key, value|
|
67
|
+
metaclass do
|
68
|
+
define_method(key) { value }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def source
|
74
|
+
@source
|
75
|
+
end
|
76
|
+
|
77
|
+
def stack
|
78
|
+
@stack
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def data_source(args, block)
|
84
|
+
[ args.last.kind_of?(::Hash) ? args.pop : {},
|
85
|
+
Source.new(block || args.first.to_s)
|
86
|
+
]
|
87
|
+
end
|
88
|
+
|
89
|
+
def metaclass(&block)
|
90
|
+
metaclass = class << self; self; end
|
91
|
+
metaclass.class_eval(&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Ripped from Rack v1.3.0 ======================================
|
95
|
+
# => ripped b/c I don't want a dependency on Rack for just this
|
96
|
+
ESCAPE_HTML = {
|
97
|
+
"&" => "&",
|
98
|
+
"<" => "<",
|
99
|
+
">" => ">",
|
100
|
+
"'" => "'",
|
101
|
+
'"' => """,
|
102
|
+
"/" => "/"
|
103
|
+
}
|
104
|
+
ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
|
105
|
+
|
106
|
+
# Escape ampersands, brackets and quotes to their HTML/XML entities.
|
107
|
+
def escape_html(string)
|
108
|
+
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
109
|
+
end
|
110
|
+
# end Rip from Rack v1.3.0 =====================================
|
111
|
+
|
20
112
|
|
21
113
|
end
|
22
114
|
end
|
data/lib/undies/version.rb
CHANGED
@@ -1,16 +1,47 @@
|
|
1
1
|
require "test/helper"
|
2
|
-
require "undies/
|
2
|
+
require "undies/element"
|
3
3
|
|
4
|
-
class Undies::
|
4
|
+
class Undies::Element
|
5
5
|
|
6
6
|
|
7
7
|
|
8
8
|
class BasicTest < Test::Unit::TestCase
|
9
9
|
include TestBelt
|
10
10
|
|
11
|
-
context '
|
12
|
-
subject { Undies::
|
13
|
-
should
|
11
|
+
context 'an element'
|
12
|
+
subject { Undies::Element.new([], :div) }
|
13
|
+
should have_readers :name, :attrs
|
14
|
+
should have_accessor :nodes
|
15
|
+
|
16
|
+
should "be a Node" do
|
17
|
+
assert_kind_of Undies::Node, subject
|
18
|
+
end
|
19
|
+
|
20
|
+
should "store it's name as a string" do
|
21
|
+
assert_equal "div", subject.name
|
22
|
+
end
|
23
|
+
|
24
|
+
should "have a NodeList as its nodes" do
|
25
|
+
assert_kind_of Undies::NodeList, subject.nodes
|
26
|
+
end
|
27
|
+
|
28
|
+
should "have its nodes be its content" do
|
29
|
+
assert_equal subject.nodes.object_id, subject.content.object_id
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
class EmptyTest < Test::Unit::TestCase
|
37
|
+
include TestBelt
|
38
|
+
context 'an empty element'
|
39
|
+
subject { Undies::Element.new([], :br) }
|
40
|
+
|
41
|
+
should "have no nodes" do
|
42
|
+
assert_equal([], subject.nodes)
|
43
|
+
end
|
44
|
+
|
14
45
|
end
|
15
46
|
|
16
47
|
|
@@ -44,27 +75,28 @@ class Undies::Tag
|
|
44
75
|
|
45
76
|
|
46
77
|
class SerializeTest < BasicTest
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
tag = Undies::Tag.new(:br)
|
51
|
-
assert_equal "<br />", tag.to_s
|
78
|
+
should "serialize with no child elements" do
|
79
|
+
element = Undies::Element.new([], :br)
|
80
|
+
assert_equal "<br />", element.to_s
|
52
81
|
end
|
53
82
|
|
54
|
-
should "
|
55
|
-
|
56
|
-
assert_equal '<br class="big" />',
|
83
|
+
should "serialize with attrs" do
|
84
|
+
element = Undies::Element.new([], :br, {:class => 'big'})
|
85
|
+
assert_equal '<br class="big" />', element.to_s
|
57
86
|
end
|
58
87
|
|
59
|
-
should "
|
60
|
-
|
61
|
-
|
88
|
+
should "serialize with attrs and content" do
|
89
|
+
templ = Undies::Template.new do
|
90
|
+
element(:strong, {:class => 'big'}) { __ "Loud Noises!" }
|
91
|
+
end
|
92
|
+
assert_equal '<strong class="big">Loud Noises!</strong>', templ.to_s
|
62
93
|
end
|
63
94
|
end
|
64
95
|
|
65
96
|
|
66
97
|
|
67
98
|
class CSSProxyTest < BasicTest
|
99
|
+
|
68
100
|
should "respond to any method ending in '!' as an id proxy" do
|
69
101
|
assert subject.respond_to?(:asdgasdg!)
|
70
102
|
end
|
@@ -75,11 +107,11 @@ class Undies::Tag
|
|
75
107
|
}, subject.thing1!.attrs)
|
76
108
|
end
|
77
109
|
|
78
|
-
should "nest
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
110
|
+
should "nest elements from proxy id call" do
|
111
|
+
templ = Undies::Template.new do
|
112
|
+
element(:div).thing1! { _ "stuff" }
|
113
|
+
end
|
114
|
+
assert_equal "<div id=\"thing1\">stuff</div>", templ.to_s
|
83
115
|
end
|
84
116
|
|
85
117
|
should "proxy id attr with last method call ending in '!'" do
|
@@ -110,11 +142,11 @@ class Undies::Tag
|
|
110
142
|
}, subject.thing.attrs)
|
111
143
|
end
|
112
144
|
|
113
|
-
should "nest
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
145
|
+
should "nest elements from proxy class call" do
|
146
|
+
templ = Undies::Template.new do
|
147
|
+
element(:div).thing { _ "stuff" }
|
148
|
+
end
|
149
|
+
assert_equal "<div class=\"thing\">stuff</div>", templ.to_s
|
118
150
|
end
|
119
151
|
|
120
152
|
should "proxy multi html class attrs" do
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "test/helper"
|
2
|
+
require "undies/node_list"
|
3
|
+
require "undies/node"
|
4
|
+
|
5
|
+
class Undies::NodeList
|
6
|
+
|
7
|
+
class BasicTest < Test::Unit::TestCase
|
8
|
+
include TestBelt
|
9
|
+
|
10
|
+
context 'a node list'
|
11
|
+
subject { Undies::NodeList.new }
|
12
|
+
should have_instance_method :append
|
13
|
+
|
14
|
+
should "be an Array" do
|
15
|
+
assert_kind_of ::Array, subject
|
16
|
+
end
|
17
|
+
|
18
|
+
should "always init empty" do
|
19
|
+
assert_equal 0, subject.size
|
20
|
+
assert_equal 0, Undies::NodeList.new([1,2,3]).size
|
21
|
+
end
|
22
|
+
|
23
|
+
should "complain if you try to append something other than a node" do
|
24
|
+
assert_raises ArgumentError do
|
25
|
+
subject.append('hey!')
|
26
|
+
end
|
27
|
+
assert_raises ArgumentError do
|
28
|
+
subject << 'hey!'
|
29
|
+
end
|
30
|
+
assert_nothing_raised do
|
31
|
+
subject.append(Undies::Node.new('hey!'))
|
32
|
+
subject << Undies::Node.new('hey!')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
should "append nodes with the 'append' method" do
|
37
|
+
subject.append(Undies::Node.new "hey!")
|
38
|
+
assert_equal 1, subject.size
|
39
|
+
end
|
40
|
+
|
41
|
+
should "return the node when appending" do
|
42
|
+
node = Undies::Node.new "hey!"
|
43
|
+
assert_equal node.object_id, subject.append(node).object_id
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/test/node_test.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "test/helper"
|
2
|
+
require "undies/node"
|
3
|
+
|
4
|
+
class Undies::Node
|
5
|
+
|
6
|
+
class BasicTest < Test::Unit::TestCase
|
7
|
+
include TestBelt
|
8
|
+
|
9
|
+
context 'a node'
|
10
|
+
subject { Undies::Node.new("a text node here") }
|
11
|
+
should have_instance_method :to_s, :start_tag, :end_tag
|
12
|
+
should have_reader :content
|
13
|
+
|
14
|
+
should "know it's content" do
|
15
|
+
assert_equal "a text node here", subject.content.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
should "know how to serialize itself" do
|
19
|
+
assert_equal "a text node here", subject.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "test/helper"
|
2
|
+
require "undies/partial_data"
|
3
|
+
|
4
|
+
class Undies::PartialData
|
5
|
+
|
6
|
+
class BasicTest < Test::Unit::TestCase
|
7
|
+
include TestBelt
|
8
|
+
|
9
|
+
context 'partial data'
|
10
|
+
subject { Undies::PartialData.new 'test/templates/index.html.rb' }
|
11
|
+
should have_readers :path, :name
|
12
|
+
|
13
|
+
should "be a kind of Hash" do
|
14
|
+
assert subject.kind_of?(::Hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "complain if now path given" do
|
18
|
+
assert_raises ArgumentError do
|
19
|
+
Undies::PartialData.new
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class NameTest < BasicTest
|
26
|
+
|
27
|
+
should "know its name given a file" do
|
28
|
+
data = Undies::PartialData.new('test/templates/current.html.rb')
|
29
|
+
assert_equal 'current', data.name
|
30
|
+
end
|
31
|
+
|
32
|
+
should "know its name given a file name with a leading char" do
|
33
|
+
data = Undies::PartialData.new('test/templates/_partial.html.rb')
|
34
|
+
assert_equal 'partial', data.name
|
35
|
+
end
|
36
|
+
|
37
|
+
should "know its name given a file name with multiple leading chars" do
|
38
|
+
data = Undies::PartialData.new('test/templates/__partial.html.rb')
|
39
|
+
assert_equal 'partial', data.name
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class ValuesTest < BasicTest
|
45
|
+
before do
|
46
|
+
@path = 'test/templates/index.html.rb'
|
47
|
+
end
|
48
|
+
subject { Undies::PartialData.new(@path) }
|
49
|
+
|
50
|
+
should "not have any values by default" do
|
51
|
+
assert_equal({}, subject)
|
52
|
+
end
|
53
|
+
|
54
|
+
should "know its values" do
|
55
|
+
subject.values = {:name => 'A Name'}
|
56
|
+
assert_equal({:name => "A Name"}, subject)
|
57
|
+
end
|
58
|
+
|
59
|
+
should "complain when values not given as a hash" do
|
60
|
+
assert_raises ArgumentError do
|
61
|
+
subject.values = "some data"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
should "force its object value to a string key" do
|
66
|
+
assert !subject.has_key?(:index)
|
67
|
+
assert !subject.has_key?('index')
|
68
|
+
subject.object = "thing"
|
69
|
+
assert !subject.has_key?(:index)
|
70
|
+
assert subject.has_key?('index')
|
71
|
+
end
|
72
|
+
|
73
|
+
should "force its name value to a string key" do
|
74
|
+
assert !subject.has_key?(:index)
|
75
|
+
assert !subject.has_key?('index')
|
76
|
+
subject.values = {:index => 'thing'}
|
77
|
+
assert !subject.has_key?(:index)
|
78
|
+
assert subject.has_key?('index')
|
79
|
+
end
|
80
|
+
|
81
|
+
should "set its values to its object" do
|
82
|
+
subject.object = "thing"
|
83
|
+
assert_equal({'index' => "thing"}, subject)
|
84
|
+
end
|
85
|
+
|
86
|
+
should "merge its object into the values" do
|
87
|
+
subject.object = "thing"
|
88
|
+
subject.values = {:color => "#FFF"}
|
89
|
+
assert_equal({'index' => "thing", :color => "#FFF"}, subject)
|
90
|
+
end
|
91
|
+
|
92
|
+
should "overwrite its object with the values if needed" do
|
93
|
+
subject.object = "thing"
|
94
|
+
subject.values = {'index' => "#FFF"}
|
95
|
+
assert_equal({'index' => "#FFF"}, subject)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "test/helper"
|
2
|
+
require "undies/partial"
|
3
|
+
|
4
|
+
class Undies::Partial
|
5
|
+
|
6
|
+
class BasicTest < Test::Unit::TestCase
|
7
|
+
include TestBelt
|
8
|
+
|
9
|
+
context 'partial'
|
10
|
+
subject { Undies::Partial.new 'test/templates/index.html.rb' }
|
11
|
+
|
12
|
+
should "be a kind of Template" do
|
13
|
+
assert subject.kind_of?(Undies::Template)
|
14
|
+
end
|
15
|
+
|
16
|
+
should "complain if no path given" do
|
17
|
+
assert_raises ArgumentError do
|
18
|
+
Undies::Partial.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class LocalsTest < BasicTest
|
25
|
+
before do
|
26
|
+
@path = 'test/templates/index.html.rb'
|
27
|
+
end
|
28
|
+
|
29
|
+
should "know its data" do
|
30
|
+
partial = Undies::Partial.new(@path, :name => 'A Name')
|
31
|
+
assert_equal("A Name", partial.name)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "know its object" do
|
35
|
+
partial = Undies::Partial.new(@path, "thing")
|
36
|
+
assert_equal("thing", partial.index)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/test/source_test.rb
CHANGED
@@ -7,36 +7,45 @@ class Undies::Source
|
|
7
7
|
include TestBelt
|
8
8
|
|
9
9
|
context 'a source'
|
10
|
-
subject { Undies::Source.new(
|
10
|
+
subject { Undies::Source.new(Proc.new {}) }
|
11
|
+
should have_readers :source, :data
|
11
12
|
should have_instance_method :file?
|
12
|
-
should have_readers :file, :block, :data
|
13
13
|
|
14
|
-
should "
|
14
|
+
should "complain if no file or block given" do
|
15
15
|
assert_raises ArgumentError do
|
16
16
|
Undies::Source.new
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
should "complain if no block given and file does not exist" do
|
21
|
+
assert_raises ArgumentError do
|
22
|
+
Undies::Template.new "noexist.html.rb"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
19
26
|
end
|
20
27
|
|
21
28
|
class BlockTest < BasicTest
|
22
29
|
context 'from a block'
|
23
|
-
subject { Undies::Source.new(
|
30
|
+
subject { Undies::Source.new(Proc.new {}) }
|
24
31
|
|
25
32
|
should "not be a file source" do
|
26
33
|
assert !subject.file?
|
27
34
|
end
|
35
|
+
|
28
36
|
end
|
29
37
|
|
30
38
|
class FileTest < BasicTest
|
31
39
|
context 'from a file'
|
32
40
|
subject do
|
33
|
-
file = 'test/
|
41
|
+
file = 'test/templates/test.html.rb'
|
34
42
|
Undies::Source.new(File.expand_path(file))
|
35
43
|
end
|
36
44
|
|
37
45
|
should "be a file source" do
|
38
46
|
assert subject.file?
|
39
47
|
end
|
48
|
+
|
40
49
|
end
|
41
50
|
|
42
51
|
end
|
data/test/template_test.rb
CHANGED
@@ -6,12 +6,136 @@ class Undies::Template
|
|
6
6
|
class BasicTest < Test::Unit::TestCase
|
7
7
|
include TestBelt
|
8
8
|
|
9
|
-
context 'template'
|
9
|
+
context 'a template'
|
10
10
|
subject { Undies::Template.new {} }
|
11
|
-
should
|
11
|
+
should have_instance_method :to_s
|
12
|
+
should have_instance_methods :_, :__, :element, :tag
|
13
|
+
should have_accessor :nodes
|
14
|
+
|
15
|
+
should "have a NodeList as its nodes" do
|
16
|
+
assert_kind_of Undies::NodeList, subject.nodes
|
17
|
+
end
|
18
|
+
|
12
19
|
end
|
13
20
|
|
21
|
+
|
22
|
+
|
23
|
+
class NodeTest < BasicTest
|
24
|
+
context "with text data"
|
25
|
+
before do
|
26
|
+
@data = "stuff & <em>more stuff</em>"
|
27
|
+
end
|
28
|
+
|
29
|
+
should "return a text node using the '__' and '_' methods" do
|
30
|
+
assert_kind_of Undies::Node, subject.__(@data)
|
31
|
+
assert_kind_of Undies::Node, subject._(@data)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "also add the node using the '__' and '_' methods" do
|
35
|
+
subject.__(@data)
|
36
|
+
assert_equal 1, subject.nodes.size
|
37
|
+
subject._(@data)
|
38
|
+
assert_equal 2, subject.nodes.size
|
39
|
+
end
|
40
|
+
|
41
|
+
should "add the text un-escaped using the '__' method" do
|
42
|
+
assert_equal @data, subject.__(@data).to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
should "add the text escaped using the '_' method" do
|
46
|
+
assert_equal subject.send(:escape_html, @data), subject._(@data).to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
class ElementTest < BasicTest
|
54
|
+
context "using the 'element' helper"
|
55
|
+
|
56
|
+
should "return an Element object" do
|
57
|
+
assert_equal Undies::Element.new([], :br), subject.element(:br)
|
58
|
+
end
|
59
|
+
|
60
|
+
should "alias it with 'tag'" do
|
61
|
+
assert_equal subject.element(:br), subject.tag(:br)
|
62
|
+
end
|
63
|
+
|
64
|
+
should "add a new Element object" do
|
65
|
+
subject.element(:br)
|
66
|
+
assert_equal 1, subject.nodes.size
|
67
|
+
assert_equal Undies::Element.new([], :br), subject.nodes.first
|
68
|
+
end
|
69
|
+
|
70
|
+
should "respond to underscore-prefix methods" do
|
71
|
+
assert subject.respond_to?(:_div)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "respond to underscore-prefix methods as element methods" do
|
75
|
+
assert_equal subject._div, subject.element(:div)
|
76
|
+
end
|
77
|
+
|
78
|
+
should "not respond to element methods without an underscore-prefix" do
|
79
|
+
assert !subject.respond_to?(:div)
|
80
|
+
assert_raises NoMethodError do
|
81
|
+
subject.div
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
class DataTest < BasicTest
|
90
|
+
|
91
|
+
should "only accept the data if it is a Hash" do
|
92
|
+
assert_raises NoMethodError do
|
93
|
+
(Undies::Template.new("some_data") {}).some
|
94
|
+
end
|
95
|
+
assert_raises NoMethodError do
|
96
|
+
(Undies::Template.new('test/templates/test.html.rb', "some_data")).some
|
97
|
+
end
|
98
|
+
assert_respond_to(
|
99
|
+
(Undies::Template.new(:some => "data") {}),
|
100
|
+
:some
|
101
|
+
)
|
102
|
+
assert_respond_to(
|
103
|
+
Undies::Template.new('test/templates/test.html.rb', :some => "data"),
|
104
|
+
:some
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
should "respond to each data key with its value" do
|
109
|
+
templ = Undies::Template.new(:some => "data") {}
|
110
|
+
assert_equal "data", templ.some
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
|
14
117
|
class DefinitionTest < BasicTest
|
118
|
+
|
119
|
+
should "maintain the template's scope throughout content blocks" do
|
120
|
+
templ = Undies::Template.new do
|
121
|
+
_div {
|
122
|
+
_div {
|
123
|
+
__ self.object_id
|
124
|
+
}
|
125
|
+
}
|
126
|
+
end
|
127
|
+
assert_equal "<div><div>#{templ.object_id}</div></div>", templ.to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
should "be able to access its data in the template definition" do
|
131
|
+
templ = Undies::Template.new(:name => "awesome") do
|
132
|
+
_div {
|
133
|
+
_div { _ name }
|
134
|
+
}
|
135
|
+
end
|
136
|
+
assert_equal "<div><div>awesome</div></div>", templ.to_s
|
137
|
+
end
|
138
|
+
|
15
139
|
should "generate markup given a block" do
|
16
140
|
assert_equal(
|
17
141
|
"<html><head></head><body><div class=\"loud element\" id=\"header\">YEA!!</div></body></html>",
|
@@ -29,7 +153,7 @@ class Undies::Template
|
|
29
153
|
end
|
30
154
|
|
31
155
|
should "generate markup given a file" do
|
32
|
-
file = 'test/
|
156
|
+
file = 'test/templates/test.html.rb'
|
33
157
|
assert_equal(
|
34
158
|
"<html><head></head><body><div class=\"file\">FILE!!</div></body></html>",
|
35
159
|
Undies::Template.new(File.expand_path(file)).to_s
|
@@ -37,7 +161,7 @@ class Undies::Template
|
|
37
161
|
end
|
38
162
|
|
39
163
|
should "generate pretty printed markup" do
|
40
|
-
file = 'test/
|
164
|
+
file = 'test/templates/test.html.rb'
|
41
165
|
assert_equal(
|
42
166
|
%{<html>
|
43
167
|
<head>
|
File without changes
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: undies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
+
- 1
|
7
8
|
- 0
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.1
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kelly D. Redding
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-25 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
requirement: &id001 !ruby/object:Gem::Requirement
|
@@ -64,18 +64,25 @@ files:
|
|
64
64
|
- README.rdoc
|
65
65
|
- Rakefile
|
66
66
|
- lib/undies.rb
|
67
|
-
- lib/undies/
|
67
|
+
- lib/undies/element.rb
|
68
|
+
- lib/undies/node.rb
|
69
|
+
- lib/undies/node_list.rb
|
70
|
+
- lib/undies/partial.rb
|
71
|
+
- lib/undies/partial_data.rb
|
68
72
|
- lib/undies/source.rb
|
69
|
-
- lib/undies/tag.rb
|
70
73
|
- lib/undies/template.rb
|
71
74
|
- lib/undies/version.rb
|
72
|
-
- test/
|
75
|
+
- test/element_test.rb
|
73
76
|
- test/env.rb
|
74
77
|
- test/helper.rb
|
78
|
+
- test/node_list_test.rb
|
79
|
+
- test/node_test.rb
|
80
|
+
- test/partial_data_test.rb
|
81
|
+
- test/partial_test.rb
|
75
82
|
- test/source_test.rb
|
76
|
-
- test/tag_test.rb
|
77
83
|
- test/template_test.rb
|
78
|
-
- test/
|
84
|
+
- test/templates/index.html.rb
|
85
|
+
- test/templates/test.html.rb
|
79
86
|
- undies.gemspec
|
80
87
|
homepage: http://github.com/kelredd/undies
|
81
88
|
licenses: []
|
@@ -111,10 +118,14 @@ signing_key:
|
|
111
118
|
specification_version: 3
|
112
119
|
summary: A pure-Ruby HTML templating DSL.
|
113
120
|
test_files:
|
114
|
-
- test/
|
121
|
+
- test/element_test.rb
|
115
122
|
- test/env.rb
|
116
123
|
- test/helper.rb
|
124
|
+
- test/node_list_test.rb
|
125
|
+
- test/node_test.rb
|
126
|
+
- test/partial_data_test.rb
|
127
|
+
- test/partial_test.rb
|
117
128
|
- test/source_test.rb
|
118
|
-
- test/tag_test.rb
|
119
129
|
- test/template_test.rb
|
120
|
-
- test/
|
130
|
+
- test/templates/index.html.rb
|
131
|
+
- test/templates/test.html.rb
|
data/lib/undies/buffer.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
module Undies
|
2
|
-
class Buffer < ::Array
|
3
|
-
|
4
|
-
def initialize(*args)
|
5
|
-
super()
|
6
|
-
end
|
7
|
-
|
8
|
-
# Add data and don't escape it
|
9
|
-
def __(data="")
|
10
|
-
append_item(data)
|
11
|
-
end
|
12
|
-
# Add data and escape it
|
13
|
-
def _(data="")
|
14
|
-
append_item(escape_html(data))
|
15
|
-
end
|
16
|
-
|
17
|
-
TAG_METH_REGEX = /^_(.+)$/
|
18
|
-
|
19
|
-
def method_missing(meth, *args, &block)
|
20
|
-
if meth.to_s =~ TAG_METH_REGEX
|
21
|
-
tag($1, *args, &block)
|
22
|
-
else
|
23
|
-
super
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def respond_to?(*args)
|
28
|
-
if args.first.to_s =~ TAG_METH_REGEX
|
29
|
-
true
|
30
|
-
else
|
31
|
-
super
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def tag(name, attrs={}, &block)
|
36
|
-
append_item(new_tag=Tag.new(name, attrs, &block))
|
37
|
-
new_tag
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s(pp_level=0, pp_indent=nil)
|
41
|
-
self.collect do |i|
|
42
|
-
begin
|
43
|
-
i.to_s(pp_level, pp_indent)
|
44
|
-
rescue ArgumentError => err
|
45
|
-
pretty_print(i.to_s, pp_level, pp_indent)
|
46
|
-
end
|
47
|
-
end.join
|
48
|
-
end
|
49
|
-
|
50
|
-
protected
|
51
|
-
|
52
|
-
def pretty_print(data, level, indent)
|
53
|
-
indent ? "#{' '*level*indent}#{data}\n" : data
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def append_item(data)
|
59
|
-
self << data
|
60
|
-
end
|
61
|
-
|
62
|
-
# Ripped from Rack v1.3.0 ======================================
|
63
|
-
# => ripped b/c I don't want a dependency on Rack for just this
|
64
|
-
ESCAPE_HTML = {
|
65
|
-
"&" => "&",
|
66
|
-
"<" => "<",
|
67
|
-
">" => ">",
|
68
|
-
"'" => "'",
|
69
|
-
'"' => """,
|
70
|
-
"/" => "/"
|
71
|
-
}
|
72
|
-
ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
|
73
|
-
|
74
|
-
# Escape ampersands, brackets and quotes to their HTML/XML entities.
|
75
|
-
def escape_html(string)
|
76
|
-
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
77
|
-
end
|
78
|
-
# end Rip from Rack v1.3.0 =====================================
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
data/test/buffer_test.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require "test/helper"
|
2
|
-
require "undies/buffer"
|
3
|
-
require "undies/tag"
|
4
|
-
|
5
|
-
class Undies::Buffer
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
class BasicTest < Test::Unit::TestCase
|
11
|
-
include TestBelt
|
12
|
-
|
13
|
-
context 'a buffer'
|
14
|
-
subject { Undies::Buffer.new }
|
15
|
-
should have_instance_methods :to_s, :_, :__, :tag
|
16
|
-
|
17
|
-
should "be a kind of ::Array" do
|
18
|
-
assert subject.kind_of?(::Array)
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
class DataTest < BasicTest
|
26
|
-
context "with data"
|
27
|
-
before do
|
28
|
-
@data = "stuff & <em>more stuff</em>"
|
29
|
-
end
|
30
|
-
|
31
|
-
should "add it un-escaped using the '__' method" do
|
32
|
-
subject.__ @data
|
33
|
-
assert_equal "stuff & <em>more stuff</em>", subject.to_s
|
34
|
-
end
|
35
|
-
|
36
|
-
should "add it escaped using the '_' method" do
|
37
|
-
subject._ @data
|
38
|
-
assert_equal "stuff & <em>more stuff</em>", subject.to_s
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
class TagTest < BasicTest
|
46
|
-
context "when using the tag method"
|
47
|
-
|
48
|
-
should "return a new Tag object" do
|
49
|
-
assert_equal Undies::Tag.new(:br), subject.tag(:br)
|
50
|
-
end
|
51
|
-
|
52
|
-
should "add a new Tag object" do
|
53
|
-
subject.tag(:br)
|
54
|
-
assert_equal Undies::Tag.new(:br), subject.first
|
55
|
-
end
|
56
|
-
|
57
|
-
should "respond to any underscore prefix method" do
|
58
|
-
assert subject.respond_to?(:_div)
|
59
|
-
end
|
60
|
-
|
61
|
-
should "not respond to tag methods without an underscore prefix" do
|
62
|
-
assert !subject.respond_to?(:div)
|
63
|
-
assert_raises NoMethodError do
|
64
|
-
subject.div
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
should "interpret underscore prefix methods as a tag" do
|
69
|
-
assert_equal subject._div, subject.tag(:div)
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# TODO: pretty printing
|
77
|
-
|
78
|
-
|
79
|
-
end
|
File without changes
|