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 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