liquid-blocks 0.2.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/LICENSE +22 -0
- data/lib/liquid_blocks.rb +9 -0
- data/lib/liquid_blocks/block.rb +56 -0
- data/lib/liquid_blocks/extends.rb +101 -0
- data/lib/liquid_blocks/version.rb +3 -0
- data/test/test_liquid_blocks.rb +161 -0
- metadata +121 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Dan Webb
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module LiquidBlocks
|
2
|
+
|
3
|
+
class BlockDrop < ::Liquid::Drop
|
4
|
+
def initialize(block)
|
5
|
+
@block = block
|
6
|
+
end
|
7
|
+
|
8
|
+
def super
|
9
|
+
@block.call_super(@context)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Block < ::Liquid::Block
|
14
|
+
Syntax = /(\w)+/
|
15
|
+
|
16
|
+
attr_accessor :parent
|
17
|
+
attr_reader :name
|
18
|
+
|
19
|
+
def initialize(tag_name, markup, tokens)
|
20
|
+
if markup =~ Syntax
|
21
|
+
@name = $1
|
22
|
+
else
|
23
|
+
raise Liquid::SyntaxError.new("Syntax Error in 'block' - Valid syntax: block [name]")
|
24
|
+
end
|
25
|
+
|
26
|
+
super if tokens
|
27
|
+
end
|
28
|
+
|
29
|
+
def render(context)
|
30
|
+
context.stack do
|
31
|
+
context['block'] = BlockDrop.new(self)
|
32
|
+
|
33
|
+
render_all(@nodelist, context)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_parent(nodelist)
|
38
|
+
if parent
|
39
|
+
parent.add_parent(nodelist)
|
40
|
+
else
|
41
|
+
self.parent = Block.new(@tag_name, @name, nil)
|
42
|
+
parent.nodelist = nodelist
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def call_super(context)
|
47
|
+
if parent
|
48
|
+
parent.render(context)
|
49
|
+
else
|
50
|
+
''
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module LiquidBlocks
|
2
|
+
|
3
|
+
class Extends < ::Liquid::Block
|
4
|
+
Syntax = /(#{Liquid::QuotedFragment}+)/
|
5
|
+
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
if markup =~ Syntax
|
8
|
+
@template_name = $1
|
9
|
+
else
|
10
|
+
raise Liquid::SyntaxError.new("Syntax Error in 'extends' - Valid syntax: extends [template]")
|
11
|
+
end
|
12
|
+
|
13
|
+
super
|
14
|
+
|
15
|
+
@blocks = @nodelist.inject({}) do |m, node|
|
16
|
+
m[node.name] = node if node.is_a?(::LiquidBlocks::Block); m
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse(tokens)
|
21
|
+
parse_all(tokens)
|
22
|
+
end
|
23
|
+
|
24
|
+
def render(context)
|
25
|
+
template = load_template(context)
|
26
|
+
parent_blocks = find_blocks(template.root)
|
27
|
+
|
28
|
+
@blocks.each do |name, block|
|
29
|
+
if pb = parent_blocks[name]
|
30
|
+
pb.parent = block.parent
|
31
|
+
pb.add_parent(pb.nodelist)
|
32
|
+
pb.nodelist = block.nodelist
|
33
|
+
else
|
34
|
+
if is_extending?(template)
|
35
|
+
template.root.nodelist << block
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
template.render(context)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def parse_all(tokens)
|
46
|
+
@nodelist ||= []
|
47
|
+
@nodelist.clear
|
48
|
+
|
49
|
+
while token = tokens.shift
|
50
|
+
case token
|
51
|
+
when /^#{Liquid::TagStart}/
|
52
|
+
if token =~ /^#{Liquid::TagStart}\s*(\w+)\s*(.*)?#{Liquid::TagEnd}$/
|
53
|
+
# fetch the tag from registered blocks
|
54
|
+
if tag = Liquid::Template.tags[$1]
|
55
|
+
@nodelist << tag.new($1, $2, tokens)
|
56
|
+
else
|
57
|
+
# this tag is not registered with the system
|
58
|
+
# pass it to the current block for special handling or error reporting
|
59
|
+
unknown_tag($1, $2, tokens)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
raise Liquid::SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{Liquid::TagEnd.inspect}"
|
63
|
+
end
|
64
|
+
when /^#{Liquid::VariableStart}/
|
65
|
+
@nodelist << create_variable(token)
|
66
|
+
when ''
|
67
|
+
# pass
|
68
|
+
else
|
69
|
+
@nodelist << token
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_template(context)
|
75
|
+
source = Liquid::Template.file_system.read_template_file(@template_name[1..-2], context)
|
76
|
+
Liquid::Template.parse(source)
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_blocks(node, blocks={})
|
80
|
+
if node.respond_to?(:nodelist) && !node.nodelist.nil?
|
81
|
+
node.nodelist.inject(blocks) do |b, node|
|
82
|
+
if node.is_a?(LiquidBlocks::Block)
|
83
|
+
b[node.name] = node
|
84
|
+
else
|
85
|
+
find_blocks(node, b)
|
86
|
+
end
|
87
|
+
|
88
|
+
b
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
blocks
|
93
|
+
end
|
94
|
+
|
95
|
+
def is_extending?(template)
|
96
|
+
template.root.nodelist.any? { |node| node.is_a?(Extends) }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'liquid_blocks'
|
3
|
+
|
4
|
+
class TestFileSystem
|
5
|
+
def read_template_file(path, context)
|
6
|
+
if path == 'simple'
|
7
|
+
'test'
|
8
|
+
elsif path == 'complex'
|
9
|
+
%{
|
10
|
+
beginning
|
11
|
+
|
12
|
+
{% block thing %}
|
13
|
+
rarrgh
|
14
|
+
{% endblock %}
|
15
|
+
|
16
|
+
{% block another %}
|
17
|
+
bum
|
18
|
+
{% endblock %}
|
19
|
+
|
20
|
+
end
|
21
|
+
}
|
22
|
+
elsif path == 'nested'
|
23
|
+
%{
|
24
|
+
{% extends 'complex' %}
|
25
|
+
|
26
|
+
{% block thing %}
|
27
|
+
from nested
|
28
|
+
{% endblock %}
|
29
|
+
|
30
|
+
{% block another %}
|
31
|
+
from nested (another)
|
32
|
+
{% endblock %}
|
33
|
+
}
|
34
|
+
else
|
35
|
+
%{
|
36
|
+
{% extends 'complex' %}
|
37
|
+
|
38
|
+
{% block thing %}
|
39
|
+
from nested
|
40
|
+
{% endblock %}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Liquid::Template.file_system = TestFileSystem.new
|
47
|
+
|
48
|
+
class LiquidBlocksTest < Test::Unit::TestCase
|
49
|
+
def test_output_the_contents_of_the_extended_template
|
50
|
+
template = Liquid::Template.parse %{
|
51
|
+
{% extends 'simple' %}
|
52
|
+
|
53
|
+
{% block thing %}
|
54
|
+
yeah
|
55
|
+
{% endblock %}
|
56
|
+
}
|
57
|
+
|
58
|
+
assert_match /test/, template.render
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_render_original_content_of_block_if_no_child_block_given
|
62
|
+
template = Liquid::Template.parse %{
|
63
|
+
{% extends 'complex' %}
|
64
|
+
}
|
65
|
+
|
66
|
+
assert_match /rarrgh/, template.render
|
67
|
+
assert_match /bum/, template.render
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_render_child_content_of_block_if_child_block_given
|
71
|
+
template = Liquid::Template.parse %{
|
72
|
+
{% extends 'complex' %}
|
73
|
+
|
74
|
+
{% block thing %}
|
75
|
+
booyeah
|
76
|
+
{% endblock %}
|
77
|
+
}
|
78
|
+
|
79
|
+
assert_match /booyeah/, template.render
|
80
|
+
assert_match /bum/, template.render
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_render_child_content_of_blocks_if_multiple_child_blocks_given
|
84
|
+
template = Liquid::Template.parse %{
|
85
|
+
{% extends 'complex' %}
|
86
|
+
|
87
|
+
{% block thing %}
|
88
|
+
booyeah
|
89
|
+
{% endblock %}
|
90
|
+
|
91
|
+
{% block another %}
|
92
|
+
blurb
|
93
|
+
{% endblock %}
|
94
|
+
}
|
95
|
+
|
96
|
+
assert_match /booyeah/, template.render
|
97
|
+
assert_match /blurb/, template.render
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_remember_context_of_child_template
|
101
|
+
template = Liquid::Template.parse %{
|
102
|
+
{% extends 'complex' %}
|
103
|
+
|
104
|
+
{% block thing %}
|
105
|
+
booyeah
|
106
|
+
{% endblock %}
|
107
|
+
|
108
|
+
{% block another %}
|
109
|
+
{{ a }}
|
110
|
+
{% endblock %}
|
111
|
+
}
|
112
|
+
|
113
|
+
res = template.render 'a' => 1234
|
114
|
+
|
115
|
+
assert_match /booyeah/, res
|
116
|
+
assert_match /1234/, res
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_work_with_nested_templates
|
120
|
+
template = Liquid::Template.parse %{
|
121
|
+
{% extends 'nested' %}
|
122
|
+
|
123
|
+
{% block thing %}
|
124
|
+
booyeah
|
125
|
+
{% endblock %}
|
126
|
+
}
|
127
|
+
|
128
|
+
res = template.render 'a' => 1234
|
129
|
+
|
130
|
+
assert_match /booyeah/, res
|
131
|
+
assert_match /from nested/, res
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_work_with_nested_templates_if_middle_template_skips_a_block
|
135
|
+
template = Liquid::Template.parse %{
|
136
|
+
{% extends 'nested2' %}
|
137
|
+
|
138
|
+
{% block another %}
|
139
|
+
win
|
140
|
+
{% endblock %}
|
141
|
+
}
|
142
|
+
|
143
|
+
res = template.render
|
144
|
+
|
145
|
+
assert_match /win/, res
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_render_parent_for_block_super
|
149
|
+
template = Liquid::Template.parse %{
|
150
|
+
{% extends 'complex' %}
|
151
|
+
|
152
|
+
{% block thing %}
|
153
|
+
{{ block.super }}
|
154
|
+
{% endblock %}
|
155
|
+
}
|
156
|
+
|
157
|
+
res = template.render 'a' => 1234
|
158
|
+
|
159
|
+
assert_match /rarrgh/, res
|
160
|
+
end
|
161
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: liquid-blocks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dan Webb
|
9
|
+
- Silas Sewell
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-08-09 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: liquid
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: bundler
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 1.0.0
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 1.0.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: test-unit
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
description: Django-style template inheritance for Liquid
|
80
|
+
email:
|
81
|
+
- silas@sewell.org
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- lib/liquid_blocks.rb
|
87
|
+
- lib/liquid_blocks/block.rb
|
88
|
+
- lib/liquid_blocks/extends.rb
|
89
|
+
- lib/liquid_blocks/version.rb
|
90
|
+
- LICENSE
|
91
|
+
- test/test_liquid_blocks.rb
|
92
|
+
homepage: https://github.com/silas/liquid-blocks
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
hash: -4152518546430610030
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 1.3.6
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project: liquid-blocks
|
116
|
+
rubygems_version: 1.8.23
|
117
|
+
signing_key:
|
118
|
+
specification_version: 3
|
119
|
+
summary: Liquid Blocks
|
120
|
+
test_files:
|
121
|
+
- test/test_liquid_blocks.rb
|