liquid-blocks 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ require 'liquid'
2
+
3
+ module LiquidBlocks
4
+ autoload :Extends, 'liquid_blocks/extends'
5
+ autoload :Block, 'liquid_blocks/block'
6
+ end
7
+
8
+ Liquid::Template.register_tag(:extends, LiquidBlocks::Extends)
9
+ Liquid::Template.register_tag(:block, LiquidBlocks::Block)
@@ -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,3 @@
1
+ module LiquidBlocks
2
+ VERSION = '0.2.0'
3
+ 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