liquor 0.1.1 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -9
  5. data/Gemfile +7 -0
  6. data/Guardfile +11 -0
  7. data/MIT-LICENSE +6 -2
  8. data/README.md +4 -122
  9. data/Rakefile +20 -23
  10. data/doc/language-spec.html +768 -0
  11. data/doc/language-spec.md +698 -0
  12. data/lib/liquor.rb +39 -68
  13. data/lib/liquor/ast_tools.rb +28 -0
  14. data/lib/liquor/compiler.rb +110 -0
  15. data/lib/liquor/context.rb +76 -254
  16. data/lib/liquor/diagnostics.rb +151 -0
  17. data/lib/liquor/drop/drop.rb +168 -0
  18. data/lib/liquor/drop/drop_delegation.rb +24 -0
  19. data/lib/liquor/drop/drop_scope.rb +118 -0
  20. data/lib/liquor/drop/dropable.rb +17 -0
  21. data/lib/liquor/emitter.rb +313 -0
  22. data/lib/liquor/extensions/kaminari.rb +14 -0
  23. data/lib/liquor/extensions/pagination.rb +235 -0
  24. data/lib/liquor/extensions/rails.rb +97 -0
  25. data/lib/liquor/extensions/thinking_sphinx.rb +14 -0
  26. data/lib/liquor/extensions/tire.rb +30 -0
  27. data/lib/liquor/external.rb +79 -0
  28. data/lib/liquor/function.rb +94 -0
  29. data/lib/liquor/grammar/lexer.rb +1223 -0
  30. data/lib/liquor/grammar/lexer.rl +297 -0
  31. data/lib/liquor/grammar/parser.racc +288 -0
  32. data/lib/liquor/grammar/parser.rb +885 -0
  33. data/lib/liquor/library.rb +41 -0
  34. data/lib/liquor/manager.rb +146 -0
  35. data/lib/liquor/runtime.rb +167 -0
  36. data/lib/liquor/stdlib/builtin_functions.rb +315 -0
  37. data/lib/liquor/stdlib/builtin_tags.rb +228 -0
  38. data/lib/liquor/stdlib/html_truncater.rb +162 -0
  39. data/lib/liquor/stdlib/partial_tags.rb +76 -0
  40. data/lib/liquor/tag.rb +83 -14
  41. data/lib/liquor/version.rb +1 -1
  42. data/liquor.gemspec +29 -6
  43. data/spec/builtins_spec.rb +264 -0
  44. data/spec/compiler_spec.rb +136 -0
  45. data/spec/context_spec.rb +49 -0
  46. data/spec/drop_delegation_spec.rb +21 -0
  47. data/spec/drop_spec.rb +222 -0
  48. data/spec/errors_spec.rb +40 -0
  49. data/spec/external_spec.rb +207 -0
  50. data/spec/function_spec.rb +80 -0
  51. data/spec/lexer_spec.rb +173 -0
  52. data/spec/library_spec.rb +18 -0
  53. data/spec/manager_spec.rb +84 -0
  54. data/spec/parser_spec.rb +381 -0
  55. data/spec/partials_spec.rb +74 -0
  56. data/spec/runtime_spec.rb +97 -0
  57. data/spec/spec_helper.rb +94 -0
  58. data/spec/tag_spec.rb +7 -0
  59. metadata +216 -173
  60. data/AUTHORS +0 -2
  61. data/CHANGELOG +0 -48
  62. data/Gemfile.lock +0 -91
  63. data/History.txt +0 -44
  64. data/LICENSE +0 -23
  65. data/example/server/example_servlet.rb +0 -37
  66. data/example/server/liquid_servlet.rb +0 -28
  67. data/example/server/liquor_servlet.rb +0 -28
  68. data/example/server/server.rb +0 -12
  69. data/example/server/templates/index.liquid +0 -6
  70. data/example/server/templates/index.liquor +0 -6
  71. data/example/server/templates/products.liquid +0 -45
  72. data/example/server/templates/products.liquor +0 -45
  73. data/init.rb +0 -8
  74. data/lib/extras/liquid_view.rb +0 -51
  75. data/lib/extras/liquor_view.rb +0 -51
  76. data/lib/liquor/block.rb +0 -101
  77. data/lib/liquor/condition.rb +0 -120
  78. data/lib/liquor/document.rb +0 -17
  79. data/lib/liquor/drop.rb +0 -256
  80. data/lib/liquor/errors.rb +0 -11
  81. data/lib/liquor/extensions.rb +0 -72
  82. data/lib/liquor/file_system.rb +0 -62
  83. data/lib/liquor/htmltags.rb +0 -74
  84. data/lib/liquor/module_ex.rb +0 -60
  85. data/lib/liquor/standardfilters.rb +0 -315
  86. data/lib/liquor/strainer.rb +0 -58
  87. data/lib/liquor/tags/assign.rb +0 -33
  88. data/lib/liquor/tags/capture.rb +0 -35
  89. data/lib/liquor/tags/case.rb +0 -83
  90. data/lib/liquor/tags/comment.rb +0 -9
  91. data/lib/liquor/tags/content_for.rb +0 -54
  92. data/lib/liquor/tags/cycle.rb +0 -59
  93. data/lib/liquor/tags/for.rb +0 -136
  94. data/lib/liquor/tags/if.rb +0 -80
  95. data/lib/liquor/tags/ifchanged.rb +0 -20
  96. data/lib/liquor/tags/include.rb +0 -56
  97. data/lib/liquor/tags/unless.rb +0 -33
  98. data/lib/liquor/tags/yield.rb +0 -49
  99. data/lib/liquor/template.rb +0 -181
  100. data/lib/liquor/variable.rb +0 -52
  101. data/performance/shopify.rb +0 -92
  102. data/performance/shopify/comment_form.rb +0 -33
  103. data/performance/shopify/database.rb +0 -45
  104. data/performance/shopify/json_filter.rb +0 -7
  105. data/performance/shopify/liquid.rb +0 -18
  106. data/performance/shopify/liquor.rb +0 -18
  107. data/performance/shopify/money_filter.rb +0 -18
  108. data/performance/shopify/paginate.rb +0 -93
  109. data/performance/shopify/shop_filter.rb +0 -98
  110. data/performance/shopify/tag_filter.rb +0 -25
  111. data/performance/shopify/vision.database.yml +0 -945
  112. data/performance/shopify/weight_filter.rb +0 -11
  113. data/performance/tests/dropify/article.liquid +0 -74
  114. data/performance/tests/dropify/blog.liquid +0 -33
  115. data/performance/tests/dropify/cart.liquid +0 -66
  116. data/performance/tests/dropify/collection.liquid +0 -22
  117. data/performance/tests/dropify/index.liquid +0 -47
  118. data/performance/tests/dropify/page.liquid +0 -8
  119. data/performance/tests/dropify/product.liquid +0 -68
  120. data/performance/tests/dropify/theme.liquid +0 -105
  121. data/performance/tests/ripen/article.liquid +0 -74
  122. data/performance/tests/ripen/blog.liquid +0 -13
  123. data/performance/tests/ripen/cart.liquid +0 -54
  124. data/performance/tests/ripen/collection.liquid +0 -29
  125. data/performance/tests/ripen/index.liquid +0 -32
  126. data/performance/tests/ripen/page.liquid +0 -4
  127. data/performance/tests/ripen/product.liquid +0 -75
  128. data/performance/tests/ripen/theme.liquid +0 -85
  129. data/performance/tests/tribble/404.liquid +0 -56
  130. data/performance/tests/tribble/article.liquid +0 -98
  131. data/performance/tests/tribble/blog.liquid +0 -41
  132. data/performance/tests/tribble/cart.liquid +0 -134
  133. data/performance/tests/tribble/collection.liquid +0 -70
  134. data/performance/tests/tribble/index.liquid +0 -94
  135. data/performance/tests/tribble/page.liquid +0 -56
  136. data/performance/tests/tribble/product.liquid +0 -116
  137. data/performance/tests/tribble/search.liquid +0 -51
  138. data/performance/tests/tribble/theme.liquid +0 -90
  139. data/performance/tests/vogue/article.liquid +0 -66
  140. data/performance/tests/vogue/blog.liquid +0 -32
  141. data/performance/tests/vogue/cart.liquid +0 -58
  142. data/performance/tests/vogue/collection.liquid +0 -19
  143. data/performance/tests/vogue/index.liquid +0 -22
  144. data/performance/tests/vogue/page.liquid +0 -3
  145. data/performance/tests/vogue/product.liquid +0 -62
  146. data/performance/tests/vogue/theme.liquid +0 -122
  147. data/test/assign_test.rb +0 -11
  148. data/test/block_test.rb +0 -58
  149. data/test/capture_test.rb +0 -41
  150. data/test/condition_test.rb +0 -115
  151. data/test/content_for_test.rb +0 -15
  152. data/test/context_test.rb +0 -479
  153. data/test/drop_test.rb +0 -162
  154. data/test/error_handling_test.rb +0 -89
  155. data/test/extra/breakpoint.rb +0 -547
  156. data/test/extra/caller.rb +0 -80
  157. data/test/file_system_test.rb +0 -30
  158. data/test/filter_test.rb +0 -147
  159. data/test/helper.rb +0 -24
  160. data/test/html_tag_test.rb +0 -31
  161. data/test/if_else_test.rb +0 -139
  162. data/test/include_tag_test.rb +0 -129
  163. data/test/module_ex_test.rb +0 -89
  164. data/test/output_test.rb +0 -121
  165. data/test/parsing_quirks_test.rb +0 -54
  166. data/test/regexp_test.rb +0 -45
  167. data/test/security_test.rb +0 -41
  168. data/test/standard_filter_test.rb +0 -170
  169. data/test/standard_tag_test.rb +0 -405
  170. data/test/statements_test.rb +0 -137
  171. data/test/strainer_test.rb +0 -27
  172. data/test/template_test.rb +0 -82
  173. data/test/test_helper.rb +0 -28
  174. data/test/unless_else_test.rb +0 -27
  175. data/test/variable_test.rb +0 -173
  176. data/test/yield_test.rb +0 -24
@@ -0,0 +1,228 @@
1
+ module Liquor
2
+ module Builtins
3
+ include Library
4
+
5
+ tag "declare" do |emit, context, node|
6
+ arg, kw = check_args node,
7
+ :ident,
8
+ :"=" => :expr
9
+
10
+ var_name, = nvalue(arg)
11
+ expr = kw[:"="]
12
+
13
+ expr_result = emit.expr(expr)
14
+
15
+ context.declare var_name, nloc(arg)
16
+ emit.out! %Q|#{context.access(var_name)} = #{expr_result}\n|
17
+ end
18
+
19
+ tag "assign" do |emit, context, node|
20
+ arg, kw = check_args node,
21
+ :ident,
22
+ :"=" => :expr
23
+
24
+ var_name, = nvalue(arg)
25
+ expr = kw[:"="]
26
+
27
+ expr_result = emit.expr(expr)
28
+
29
+ unless context.variable? var_name
30
+ context.declare var_name, nloc(arg)
31
+ end
32
+
33
+ emit.out! %Q|#{context.access(var_name)} = #{expr_result}\n|
34
+ end
35
+
36
+ class ForLoop
37
+ include Liquor::External
38
+
39
+ def initialize(length)
40
+ @length = length
41
+ @index = 0
42
+ end
43
+
44
+ attr_reader :length
45
+ attr_accessor :index
46
+
47
+ def next!
48
+ @index += 1
49
+ end
50
+
51
+ def rindex
52
+ @length - @index - 1
53
+ end
54
+
55
+ def is_first
56
+ @index == 0
57
+ end
58
+
59
+ def is_last
60
+ @index == @length - 1
61
+ end
62
+
63
+ export :length, :index, :rindex, :is_first, :is_last
64
+ end
65
+
66
+ tag "for" do |emit, context, node|
67
+ name, arg, *kwargs = nvalue(node)
68
+
69
+ if kwargs.empty?
70
+ raise SyntaxError.new("unexpected end of tag, expecting one of: `in:', `from:'.", nloc(node))
71
+ elsif kwname(kwargs[0]) == 'in'
72
+ arg, kw = check_args node,
73
+ :ident,
74
+ :in => :expr,
75
+ :do => :block
76
+ elsif kwname(kwargs[0]) == 'from'
77
+ arg, kw = check_args node,
78
+ :ident,
79
+ :from => :expr,
80
+ :to => :expr,
81
+ :do => :block
82
+ else
83
+ raise SyntaxError.new("unexpected `#{kwname(kwargs[0])}:', expecting one of: `in:', `from:'.", nloc(kwargs[0]))
84
+ end
85
+
86
+ var_name, = nvalue(arg)
87
+ indexer_name = "#{var_name}_loop"
88
+
89
+ context.nest do
90
+ if kw[:in]
91
+ indexer = %{Liquor::Builtins::ForLoop.new(#{emit.check_tuple(kw[:in])}.size)}
92
+ seq = emit.check_tuple(kw[:in])
93
+ elsif kw[:from]
94
+ indexer = %{Liquor::Builtins::ForLoop.new(#{emit.check_integer(kw[:to])} - #{emit.check_integer(kw[:from])})}
95
+ from, to = emit.check_integer(kw[:from]), emit.check_integer(kw[:to])
96
+ end
97
+
98
+ context.declare var_name, nloc(arg)
99
+ context.declare indexer_name
100
+
101
+ if kw[:in]
102
+ emit.out! %Q|#{context.access indexer_name} = #{indexer}\n|
103
+ emit.out! %Q|for #{context.access(var_name)} in #{seq}\n|
104
+ elsif kw[:from]
105
+ emit.out! %Q|#{context.access indexer_name} = #{indexer}\n|
106
+ emit.out! %Q<#{from}.upto(#{to}) do |#{context.access(var_name)}|\n>
107
+ end
108
+
109
+ emit.compile_block kw[:do]
110
+
111
+ emit.out! %Q|#{context.access indexer_name}.next!\n|
112
+ emit.out! %Q|end\n|
113
+ end
114
+ end
115
+
116
+ tag "if", continuations: %w(elsif) do |emit, context, node|
117
+ tag_name, arg, *kwargs = nvalue(node)
118
+
119
+ state = :begin
120
+ while state
121
+ case state
122
+ when :begin
123
+ if arg.nil?
124
+ if kwargs.empty?
125
+ raise SyntaxError.new("unexpected end of tag, expecting `expression'", nloc(node))
126
+ else
127
+ raise SyntaxError.new("unexpected `#{kwname(kwargs[0])}:', expecting `expression'", nloc(kwargs[0]))
128
+ end
129
+ end
130
+
131
+ emit.out! %Q|if #{emit.convert_boolean(arg)}\n|
132
+ state = :then
133
+
134
+ when :elsif
135
+ kwarg = kwargs.shift
136
+
137
+ if kwarg.nil?
138
+ state = nil
139
+ elsif kwname(kwarg) == 'elsif'
140
+ check_arg_type(kwarg, :expr)
141
+
142
+ emit.out! %Q|elsif #{emit.convert_boolean(kwvalue(kwarg))}\n|
143
+ state = :then
144
+ elsif kwname(kwarg) == 'else'
145
+ check_arg_type(kwarg, :block)
146
+
147
+ emit.out! %Q|else\n|
148
+ emit.compile_block kwvalue(kwarg)
149
+ state = :end
150
+ else
151
+ raise SyntaxError.new("unexpected `#{kwname(kwarg)}', expecting one of: `elsif:', `else:'")
152
+ end
153
+
154
+ when :then
155
+ kwarg = kwargs.shift
156
+ if kwarg.nil?
157
+ raise SyntaxError.new("unexpected end of tag, expecting `then:'", nloc(node))
158
+ elsif kwname(kwarg) != 'then'
159
+ raise SyntaxError.new("unexpected `#{kwname(kwarg)}', expecting `then:'", nloc(kwarg))
160
+ end
161
+
162
+ check_arg_type(kwarg, :block)
163
+
164
+ emit.compile_block kwvalue(kwarg)
165
+ state = :elsif
166
+
167
+ when :end
168
+ if kwargs.any?
169
+ raise SyntaxError.new("unexpected `#{kwname(kwargs.first)}', expecting end of tag", nloc(kwarg))
170
+ end
171
+
172
+ state = nil
173
+ end
174
+ end
175
+
176
+ emit.out! %Q|end\n|
177
+ end
178
+
179
+ tag "unless" do |emit, context, node|
180
+ arg, kw = check_args node,
181
+ :expr,
182
+ :then => :block
183
+
184
+ emit.out! %Q|unless #{emit.convert_boolean(arg)}\n|
185
+ emit.compile_block kw[:then]
186
+ emit.out! %Q|end\n|
187
+ end
188
+
189
+ tag "capture" do |emit, context, node|
190
+ tag, arg, *kwargs = nvalue(node)
191
+
192
+ if kwargs.count == 1 && kwname(kwargs.first) == 'yield'
193
+ arg, kw = check_args node,
194
+ :ident,
195
+ :yield => :string
196
+
197
+ var_name, = nvalue(arg)
198
+ fragment = kw[:yield]
199
+
200
+ context.declare var_name, nloc(arg)
201
+ access_var_name = context.access(var_name)
202
+
203
+ context.nest do
204
+ emit.out! %Q|#{access_var_name} = #{emit.storage}[#{emit.expr(fragment)}].to_s\n|
205
+ end
206
+ else
207
+ arg, kw = check_args node,
208
+ :ident,
209
+ :"=" => :block
210
+
211
+ var_name, = nvalue(arg)
212
+ block = kw[:"="]
213
+
214
+ context.declare var_name, nloc(arg)
215
+ access_var_name = context.access(var_name)
216
+
217
+ context.nest do
218
+ capture_var_name = emit.capture do
219
+ emit.compile_block block
220
+ end
221
+
222
+ emit.out! %Q|#{access_var_name} = #{capture_var_name}\n|
223
+ end
224
+ end
225
+ end
226
+
227
+ end
228
+ end
@@ -0,0 +1,162 @@
1
+ # Thanks to https://gist.github.com/101410 and other sources
2
+
3
+ module Liquor::HTMLTruncater
4
+ extend self
5
+
6
+ def truncate(input, number = 300, truncate_string = "...")
7
+ doc = Nokogiri::HTML(input.to_s, nil, "UTF-8")
8
+
9
+ current = doc.children.first
10
+ count = 0
11
+
12
+ while true
13
+ # we found a text node
14
+ if current.is_a?(Nokogiri::XML::Text)
15
+ count += current.text.mb_chars.length
16
+ # we reached our limit, let's get outta here!
17
+ break if count > number
18
+ previous = current
19
+ end
20
+
21
+ if current.children.length > 0
22
+ # this node has children, can't be a text node,
23
+ # lets descend and look for text nodes
24
+ current = current.children.first
25
+ elsif !current.next.nil?
26
+ #this has no children, but has a sibling, let's check it out
27
+ current = current.next
28
+ else
29
+ # we are the last child, we need to ascend until we are
30
+ # either done or find a sibling to continue on to
31
+ n = current
32
+ while !n.is_a?(Nokogiri::HTML::Document) and n.parent.next.nil?
33
+ n = n.parent
34
+ end
35
+
36
+ # we've reached the top and found no more text nodes, break
37
+ if n.is_a?(Nokogiri::HTML::Document)
38
+ break;
39
+ else
40
+ current = n.parent.next
41
+ end
42
+ end
43
+ end
44
+
45
+ if count >= number
46
+ unless count == number
47
+ new_content = current.text.mb_chars
48
+
49
+ index = number-(count-new_content.length)-1
50
+ if index >= 0
51
+ new_content = new_content[0..index]
52
+ current.send(:native_content=, new_content + truncate_string)
53
+ else
54
+ current = previous
55
+ current.send(:native_content=, current.content + truncate_string)
56
+ end
57
+ end
58
+
59
+ # remove everything else
60
+ while !current.is_a?(Nokogiri::HTML::Document)
61
+ while !current.next.nil?
62
+ current.next.remove
63
+ end
64
+ current = current.parent
65
+ end
66
+ end
67
+
68
+ # now we grab the html and not the text.
69
+ # we do first because nokogiri adds html and body tags
70
+ # which we don't want
71
+ if doc.root.present?
72
+ doc.root.children.first.inner_html
73
+ else # no root element present (probably empty?), will return the first element
74
+ doc.children.first.inner_html
75
+ end
76
+ end
77
+
78
+ def truncate_words(input, num_words, truncate_string = "...")
79
+ doc = Nokogiri::HTML(input)
80
+
81
+ current = doc.children.first
82
+ count = 0
83
+
84
+ while true
85
+ # we found a text node
86
+ if current.is_a?(Nokogiri::XML::Text)
87
+ count += current.text.split.length
88
+ # we reached our limit, let's get outta here!
89
+ break if count > num_words
90
+ previous = current
91
+ end
92
+
93
+ if current.children.length > 0
94
+ # this node has children, can't be a text node,
95
+ # lets descend and look for text nodes
96
+ current = current.children.first
97
+ elsif !current.next.nil?
98
+ #this has no children, but has a sibling, let's check it out
99
+ current = current.next
100
+ else
101
+ # we are the last child, we need to ascend until we are
102
+ # either done or find a sibling to continue on to
103
+ n = current
104
+ while !n.is_a?(Nokogiri::HTML::Document) and n.parent.next.nil?
105
+ n = n.parent
106
+ end
107
+
108
+ # we've reached the top and found no more text nodes, break
109
+ if n.is_a?(Nokogiri::HTML::Document)
110
+ break;
111
+ else
112
+ current = n.parent.next
113
+ end
114
+ end
115
+ end
116
+
117
+ if count >= num_words
118
+ unless count == num_words
119
+ new_content = current.text.split
120
+
121
+ # If we're here, the last text node we counted eclipsed the number of words
122
+ # that we want, so we need to cut down on words. The easiest way to think about
123
+ # this is that without this node we'd have fewer words than the limit, so all
124
+ # the previous words plus a limited number of words from this node are needed.
125
+ # We simply need to figure out how many words are needed and grab that many.
126
+ # Then we need to -subtract- an index, because the first word would be index zero.
127
+
128
+ # For example, given:
129
+ # <p>Testing this HTML truncater.</p><p>To see if its working.</p>
130
+ # Let's say I want 6 words. The correct returned string would be:
131
+ # <p>Testing this HTML truncater.</p><p>To see...</p>
132
+ # All the words in both paragraphs = 9
133
+ # The last paragraph is the one that breaks the limit. How many words would we
134
+ # have without it? 4. But we want up to 6, so we might as well get that many.
135
+ # 6 - 4 = 2, so we get 2 words from this node, but words #1-2 are indices #0-1, so
136
+ # we subtract 1. If this gives us -1, we want nothing from this node. So go back to
137
+ # the previous node instead.
138
+ index = num_words-(count-new_content.length)-1
139
+ if index >= 0
140
+ new_content = new_content[0..index]
141
+ current.content = new_content.join(' ') + truncate_string
142
+ else
143
+ current = previous
144
+ current.content = current.content + truncate_string
145
+ end
146
+ end
147
+
148
+ # remove everything else
149
+ while !current.is_a?(Nokogiri::HTML::Document)
150
+ while !current.next.nil?
151
+ current.next.remove
152
+ end
153
+ current = current.parent
154
+ end
155
+ end
156
+
157
+ # now we grab the html and not the text.
158
+ # we do first because nokogiri adds html and body tags
159
+ # which we don't want
160
+ doc.root.children.first.inner_html
161
+ end
162
+ end
@@ -0,0 +1,76 @@
1
+ module Liquor
2
+ module Partials
3
+ include Library
4
+
5
+ tag "yield" do |emit, context, node|
6
+ tag, arg, *kwargs = nvalue(node)
7
+
8
+ if arg.nil? # {% yield %}
9
+ check_args node,
10
+ nil
11
+
12
+ emit.cat! context.access('_inner_template')
13
+ else
14
+ if kwargs.count == 0
15
+ # {% yield "name" %}
16
+ arg, kw = check_args node,
17
+ :string
18
+
19
+ name, = nvalue(arg)
20
+
21
+ emit.cat! %Q|#{emit.storage}[#{name.inspect}].to_s|
22
+ else
23
+ # {% yield "name" if_none: %} block {% end yield %}
24
+ arg, kw = check_args node,
25
+ :string,
26
+ :if_none => :block
27
+
28
+ name, = nvalue(arg)
29
+
30
+ emit.out! %Q|if #{emit.storage}.include?(#{name.inspect})\n|
31
+ emit.cat! %Q| #{emit.storage}[#{name.inspect}].to_s|
32
+ emit.out! %Q|else\n|
33
+ emit.compile_block kw[:if_none]
34
+ emit.out! %Q|end\n|
35
+ end
36
+ end
37
+ end
38
+
39
+ tag "content_for" do |emit, context, node|
40
+ arg, kw = check_args node,
41
+ :string,
42
+ :"capture" => :block
43
+
44
+ name, = nvalue(arg)
45
+ block = kw[:"capture"]
46
+
47
+ context.nest do
48
+ capture_var_name = emit.capture do
49
+ emit.compile_block block
50
+ end
51
+
52
+ emit.out! %Q|#{emit.storage}[#{name.inspect}] = #{capture_var_name}\n|
53
+ end
54
+ end
55
+
56
+ tag "include" do |emit, context, node|
57
+ arg, kw = check_args node,
58
+ :string
59
+
60
+ name, = nvalue(arg)
61
+
62
+ context.nest do
63
+ manager = context.compiler.manager
64
+
65
+ source = manager.fetch_partial "_#{name}"
66
+ if source.nil?
67
+ raise ArgumentError.new("partial `#{name}' does not exist", nloc(arg))
68
+ elsif source == :syntax_error
69
+ # Do nothing. The manager has already reported the error.
70
+ else
71
+ emit.compile_block source
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end