dry_haml_handlebars 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.project ADDED
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>dry_haml_handlebars</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>com.aptana.ide.core.unifiedBuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.radrails.rails.core.railsnature</nature>
16
+ <nature>com.aptana.ruby.core.rubynature</nature>
17
+ </natures>
18
+ </projectDescription>
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.2-p180@dry_haml_handlebars --create
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dry_haml_handlebars.gemspec
4
+ gemspec
5
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ **NOTE** this gem is work in progress, I'll flesh out the instructions once it's stabilized
2
+
3
+ dry_haml_handlebars plugin
4
+ ============
5
+
6
+ This gem may be of use to you if:
7
+
8
+ * angle brackets burn your eyes (read: you like using haml)
9
+ * NOTE: if you're fine with angle brackets, stop reading, you're probably better off just using mustache
10
+ * see http://railscasts.com/episodes/295-sharing-mustache-templates
11
+ * you want your app to consume its own API and do most rendering clientside (e.g. using backbone.js, spine.js etc.)
12
+ * but you still need to render server-side (so the googlebot and paranoid no-js people can see your lovely, lovely content)
13
+ * and, importantly, you prefer DRY apps to WET ones (i.e. you don't want to write equivalent clientside and serverside templates)
14
+
15
+ Still here? Ok, this gem lets you:
16
+
17
+ * write templates using a haml/handlebars.js hybrid
18
+ * the haml describes the structure of the document while the handlebars syntax is used for substitution and logical flow
19
+ * it assumes you are using the rabl gem to generate JSON data for your view
20
+
21
+ What it does is:
22
+
23
+ * convert your hybrid templates to valid haml in which the handlebars markup is just treated as text
24
+ * then runs that through the standard haml handler to generate regular handlebars templates (html + curly braces)
25
+ * when rendering serverside it uses execjs and your rabl-generated JSON to render the template
26
+ * but it also ships pre-compiled versions of your templates and JSON data to the client (using the gon gem) so that you can switch to clientside rendering for subsequent requests
27
+
28
+ Installation
29
+ =======
30
+
31
+ Add this to your Gemfile if using Bundler: `gem 'dry_haml_handlebars'`
32
+
33
+ Or install the gem from the command line: `gem install dry_haml_handlebars`
34
+
35
+ Setup
36
+ =======
37
+
38
+ Usage
39
+ =====
40
+
41
+ Hybrid haml/handlebars syntax
42
+ -----------------------------
43
+
44
+ The syntax for your templates is a readable mix of haml and handlebars:
45
+
46
+ ```haml
47
+ .entry
48
+ .h1 {{title}}
49
+ {{#if subtitle}}
50
+ .h2 {{subtitle}}
51
+ {{/if}}
52
+ .h3 By
53
+ = link_to "{{author.name}}", user_path("{{author.id}}"), 'data-remote' => true
54
+ posted at {{localize created_at}}
55
+ .body
56
+ {{{body}}}
57
+ ```
58
+
59
+ Benefits:
60
+
61
+ * the brevity and structural clarity that haml provides
62
+ * the ability to use standard rails helpers to generate html
63
+ * concise flow constrol and substitution via handlebars
64
+ * the ability to use custom handlebars helpers (e.g. localize)
65
+ * seamless integration with your JSON API - structure the JSON (via rabl), then structure the view around it
66
+
67
+ *more to follow...*
68
+
69
+ Acknowledgements
70
+ ================
71
+
72
+ Thanks to the authors of:
73
+
74
+ * the handlebars gem (made server side compilation easy)
75
+
76
+ Copyright (c) 2012 PeepAll Ltd, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dry_haml_handlebars/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "dry_haml_handlebars"
7
+ s.version = DryHamlHandlebars::VERSION
8
+ s.authors = ["Jonathan Chambers"]
9
+ s.email = ["j.chambers@gmx.net"]
10
+ s.homepage = "https://github.com/jmchambers/dry_haml_handlebars"
11
+ s.summary = "Write haml templates, use both server and clientside (via handlebars.js)"
12
+ s.description = "Write haml views once, and then use them for both server and clientside rendering (using automagically precompiled handlebars templates)"
13
+
14
+ s.rubyforge_project = "dry_haml_handlebars"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "rails", "~> 3.2.0"
22
+ s.add_dependency "therubyracer"
23
+ s.add_dependency "haml-rails", "~> 0.3.4"
24
+ s.add_dependency "handlebars_assets", "~> 0.4.4" # was "~> 0.4.4"
25
+ s.add_dependency "rabl", "0.7.1" # "0.6.12" #this is locked down because the author's minor increments consistently break everything, grrrrr!
26
+ s.add_dependency "gon", "~> 3.0.2"
27
+
28
+ s.license = 'MIT'
29
+
30
+ end
@@ -0,0 +1,80 @@
1
+ module ActionController
2
+ class Base
3
+
4
+ def render_extra_content_for(*args)
5
+ options = args.extract_options!
6
+ args.each do |identifier|
7
+ name, path = get_content_for_name_and_path(identifier, options)
8
+ DryHamlHandlebars.content_cache.add_item(name, path)
9
+ end
10
+
11
+ end
12
+
13
+ private
14
+
15
+ def get_content_for_name_and_path(identifier, options)
16
+
17
+ case identifier
18
+ when Symbol
19
+
20
+ name = identifier
21
+
22
+ possible_folders = [
23
+ Rails.root.join( *%w[app views] << params[:controller] ).to_s,
24
+ Rails.root.join( *%w[app views application] ).to_s
25
+ ]
26
+
27
+ if folders = options[:prepend_search_folders]
28
+ possible_folders = folders + possible_folders
29
+ end
30
+
31
+ if folders = options[:append_search_folders]
32
+ possible_folders += folders
33
+ end
34
+
35
+ possible_filenames = [
36
+ "#{params[:action]}_#{name}.html.haml",
37
+ "#{name}.html.haml",
38
+ "#{params[:action]}_content_for_#{name}.html.haml",
39
+ "content_for_#{name}.html.haml"
40
+ ]
41
+
42
+ possible_paths = []
43
+
44
+ possible_folders.each do |folder|
45
+ possible_filenames.each do |fname|
46
+ possible_paths << File.join( folder, fname )
47
+ end
48
+ end
49
+
50
+ path = possible_paths.find { |p| File.exist?(p) }
51
+ raise "couldn't find any of the following expected files:\n#{possible_paths.join("\n")}" if path.nil?
52
+
53
+ when Array
54
+
55
+ path = Rails.root.join( *%w[app views] << "#{identifier.last}.html.haml" ).to_s
56
+ name = identifier.first.to_sym
57
+
58
+ when String
59
+
60
+ path = Rails.root.join( *%w[app views] << "#{identifier}.html.haml" ).to_s
61
+ name_match = identifier.match(/.*content_for_(?<name>\w*)/)
62
+ if name_match
63
+ name = name_match[:name].to_sym
64
+ else
65
+ name = identifier
66
+ end
67
+
68
+ else
69
+ raise ArgumentError, "expected identifier to be a Array, Symbol or String, but got #{identifier}"
70
+ end
71
+
72
+ raise "the file #{path} does not exist" unless File.exist?(path)
73
+
74
+ return name, path
75
+
76
+ end
77
+
78
+
79
+ end
80
+ end
@@ -0,0 +1,31 @@
1
+ module ActionView
2
+ class Base
3
+
4
+ def handlebars_render(*args, &block)
5
+
6
+ #we simply wrap render so that we can detect that 'handlebars_render' was the calling function
7
+ #we do this by adding a local variable :handlebars_partial => true
8
+
9
+ if args.first.is_a?(Hash)
10
+
11
+ options = args.first
12
+ options[:locals] ||= {}
13
+ options[:locals].merge!(:__handlebars_partial => true)
14
+
15
+ elsif args.last.is_a?(Hash)
16
+
17
+ locals = args.last
18
+ locals[:__handlebars_partial] = true
19
+
20
+ else
21
+
22
+ args << {:__handlebars_partial => true}
23
+
24
+ end
25
+
26
+ render(*args, &block)
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module ActionView
2
+ module Helpers
3
+ module CaptureHelper
4
+
5
+ # WARNING: content_for is ignored in caches. So you shouldn't use it
6
+ # for elements that will be fragment cached.
7
+ def handlebars_content_for(name, content = nil, flush = false)
8
+
9
+ if content
10
+ flush ? @view_flow.set(name, content) : @view_flow.append(name, content)
11
+ nil
12
+ else
13
+ @view_flow.get(name)
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,395 @@
1
+ module DryHamlHandlebars
2
+
3
+ INDENT = /\A(?<indent>\s*)/
4
+ CONTENT = /#{INDENT}\S+.*\Z/
5
+ BLOCK_START = /(?<start>#{INDENT}{{#(?<keyword>\w+))/
6
+
7
+ require 'haml/template/plugin'
8
+
9
+ def self.dedent_hbs(source)
10
+ lines = source.lines.to_a
11
+ mod_lines = lines.clone
12
+ lines.each_with_index do |line1, i1|
13
+
14
+ if (l1_match = line1.match BLOCK_START)
15
+
16
+ l1_index = i1
17
+ l1_indent = l1_match[:indent] ? l1_match[:indent].length : 0
18
+ l1_text = l1_match[:start]
19
+
20
+ #binding.pry if i1 == 7
21
+
22
+ next_match = nil
23
+ next_line = lines[l1_index+1..-1].detect { |l| next_match = l.match(CONTENT) }
24
+
25
+ next unless next_match
26
+ next_line_indent = next_match[:indent] ? next_match[:indent].length : 0
27
+ next unless (indent = next_line_indent - l1_indent) > 0
28
+
29
+
30
+ l2_text = l1_text.sub("{{#", "{{/")
31
+ else_text = " " * l1_indent + "{{else}}"
32
+ else_index = nil
33
+ l2_index = lines[l1_index+1..-1].each_with_index.each do |line2, i2|
34
+ else_index = i2 if line2.starts_with? else_text
35
+ break i2 + l1_index+1 if line2.starts_with? l2_text
36
+ end
37
+
38
+ (l1_index+1..l2_index-1).each_with_index do |index, i|
39
+ next if i == else_index
40
+ mod_lines[index] = mod_lines[index][indent..-1]
41
+ end
42
+
43
+ end
44
+ end
45
+ mod_lines.join
46
+ end
47
+
48
+ class << self
49
+ attr_accessor :on_next_request
50
+ end
51
+
52
+ class Handler < Haml::Plugin
53
+
54
+ class << self
55
+
56
+ def call(template, options = {})
57
+
58
+ view_match = template.identifier.match(/^#{Rails.root.join('app', 'views')}[\/](?<view_path>[\/\w]+)[\/](?<view_name>\w+).html/)
59
+ relative_view_path = view_match[:view_path]
60
+ view_name = view_match[:view_name]
61
+ view_type = get_view_type(template, relative_view_path, view_name)
62
+
63
+ env = Rails.env.to_sym
64
+ out = []
65
+
66
+ #when in dev mode we can set this variable to true on each request (in the app controller)
67
+ #and we scan for all changed partials (whether needed for the current view or not)
68
+ #this is intended to ensure that all changes are picked up ready for deployment
69
+ #even if the dev forgets to run the view that requires a changed partial
70
+ #the rule is, render ANY page, and ALL partials should be re-compiled (if needed)
71
+ #while for changed templates, you MUST run the view that you have changed
72
+ if DryHamlHandlebars.on_next_request.values.any?
73
+ DryHamlHandlebars.on_next_request.keys.each do |method|
74
+ DryHamlHandlebars.on_next_request[method] = false
75
+ case method
76
+ when :compile_all_partials
77
+ out += compile_and_load_all_partials
78
+ else
79
+ DryHamlHandlebars.send method
80
+ end
81
+ end
82
+ end
83
+
84
+ if [:layout, :ignored_partial].include? view_type
85
+ out << super(template)
86
+ return out.join("\n")
87
+ end
88
+
89
+ partial_name = [relative_view_path.gsub('/', '_'), view_name[1..-1]].join('_')
90
+ rabl_path, template_path, compiled_template_path = generate_file_names(relative_view_path, view_name)
91
+ if options[:force_handlebars_compile] or !File.exist?(compiled_template_path) or ( [:development, :test].include?(env) and ( File.mtime(compiled_template_path) < File.mtime(template.identifier) ) )
92
+ source = template.source
93
+ source = DryHamlHandlebars.dedent_hbs(source)
94
+ template.instance_variable_set "@source", source
95
+ rendered_haml = <<-RUBY
96
+ rendered_haml = eval(%q( #{super(template)} )).html_safe
97
+ RUBY
98
+ else
99
+ rendered_haml = nil
100
+ end
101
+
102
+ runner = Runner.new(
103
+ template,
104
+ rendered_haml,
105
+ view_type,
106
+ view_name,
107
+ partial_name,
108
+ relative_view_path,
109
+ rabl_path,
110
+ template_path,
111
+ compiled_template_path
112
+ )
113
+
114
+ out << runner.run
115
+ out.join("\n")
116
+
117
+ end
118
+
119
+ def compile_and_load_all_partials
120
+ partials = Dir.glob(Rails.root.join('app', 'views', '**', '_*.html.haml'))
121
+ out = []
122
+ partials.each do |fname|
123
+ File.open(fname) do |file|
124
+ source = file.read
125
+ next unless source.starts_with?('-#handlebars_partial')
126
+ source = DryHamlHandlebars.dedent_hbs(source)
127
+ template = ActionView::Template.new(source, fname, nil, {:locals => ["__handlebars_partial"]})
128
+ out << call(template, :force_handlebars_compile => true)
129
+ end
130
+ end
131
+ out
132
+ end
133
+
134
+ def get_view_type(template, relative_view_path, view_name)
135
+
136
+ #we have 4 types of view;
137
+ # 1) layout - always handled by haml, no hbs/js versions are generated
138
+ # 2) template - rendered as handlebars, we expect there to be html.haml AND .rabl for the JSON
139
+ # 3) partial - pulled into view by handlebars syntax {{>name}}
140
+ # 4) ignored_partial - a regular partial, it will be rendered by Haml, with no handlebars-related processing
141
+
142
+ if relative_view_path == 'layouts'
143
+ :layout
144
+ elsif template.locals.include?("__handlebars_partial")
145
+ :partial
146
+ elsif view_name.starts_with? "_"
147
+ :ignored_partial
148
+ else
149
+ :template
150
+ end
151
+
152
+ end
153
+
154
+ def generate_file_names(relative_view_path, view_name)
155
+
156
+ template_partial_path = Rails.root.join( *%w(app assets templates) << "#{relative_view_path}" )
157
+ compiled_template_partial_path = Rails.root.join( *%w(app assets compiled_templates) << "#{relative_view_path}" )
158
+
159
+ rabl_path = Rails.root.join( 'app', 'views', relative_view_path, "#{view_name}.rabl" )
160
+ template_path = File.join( template_partial_path, "#{view_name}.hbs" )
161
+ compiled_template_path = File.join( compiled_template_partial_path, "#{view_name}.js" )
162
+
163
+ FileUtils.mkdir_p template_partial_path unless File.directory? template_partial_path
164
+ FileUtils.mkdir_p compiled_template_partial_path unless File.directory? compiled_template_partial_path
165
+
166
+ return rabl_path, template_path, compiled_template_path
167
+
168
+ end
169
+
170
+ end
171
+
172
+ end
173
+
174
+ class Runner
175
+
176
+ def initialize(template, rendered_haml = nil, view_type, view_name, partial_name, relative_view_path, rabl_path, template_path, compiled_template_path)
177
+ @template = template
178
+ @rendered_haml = rendered_haml
179
+ @view_type = view_type
180
+ @view_name = view_name
181
+ @partial_name = partial_name
182
+ @relative_view_path = relative_view_path
183
+ @rabl_path = rabl_path
184
+ @template_path = template_path
185
+ @compiled_template_path = compiled_template_path
186
+ end
187
+
188
+ def run
189
+
190
+ content_cache = DryHamlHandlebars.content_cache
191
+ out = []
192
+
193
+ if @rendered_haml
194
+
195
+ out << @rendered_haml
196
+ out << compile_hbs
197
+
198
+ case @view_type
199
+ when :template
200
+
201
+ out << name_template
202
+ out << gen_template_loader
203
+
204
+ when :partial
205
+
206
+ out << name_partial
207
+ out << gen_partial_loader
208
+
209
+ end
210
+
211
+ out << write_asset_files
212
+ out << get_hbs_context
213
+ out << load_template
214
+
215
+ else #if we don't have any rendered haml (we're probably in production)
216
+
217
+ out << get_hbs_context
218
+ out << name_template
219
+
220
+ end
221
+
222
+ out << set_locale if defined? SimplesIdeias::I18n
223
+
224
+ case @view_type
225
+ when :template
226
+
227
+ out << render_rabl
228
+ out << set_gon_variable
229
+
230
+ if content_cache.store.present? #do we need to render some content for another view?
231
+
232
+ content_cache.store.each do |item|
233
+
234
+ name = item.name
235
+ path = item.path
236
+ content_cache.remove_item(item)
237
+
238
+ #NOTE: this call will overwrite all eval'd variables set below, except for template_names
239
+ #we store this in a stack and pop the last name when we get to render_template()
240
+ #it doesn't matter about the other variables as we're finished with them by this stage
241
+ #and it keeps the eval code simpler if we just reuse them
242
+
243
+ out << render_content_for(name, path)
244
+
245
+ end
246
+ content_cache.clear #just to be sure
247
+
248
+ end
249
+
250
+ out << render_template
251
+
252
+ when :partial
253
+
254
+ out << render_handlebars_partial_command
255
+
256
+ end
257
+
258
+ out.join("\n")
259
+
260
+
261
+ end
262
+
263
+ def compile_hbs
264
+ <<-RUBY
265
+ compiled_hbs = HandlebarsAssets::Handlebars.precompile( rendered_haml )
266
+ RUBY
267
+ end
268
+
269
+ def name_template
270
+ <<-RUBY
271
+ template_names ||= []
272
+ template_names << '#{File.join(@relative_view_path, @view_name).to_s}'
273
+ RUBY
274
+ end
275
+
276
+ def name_partial
277
+ <<-RUBY
278
+ partial_name = '#{@partial_name}'
279
+ RUBY
280
+ end
281
+
282
+ def gen_template_loader
283
+ <<-'RUBY'
284
+ hbs_loader = "(function() {
285
+ this.HandlebarsTemplates || (this.HandlebarsTemplates = {});
286
+ this.HandlebarsTemplates['#{template_names.last}'] = Handlebars.template(#{compiled_hbs});
287
+ return HandlebarsTemplates['#{template_names.last}'];
288
+ }).call(this)"
289
+ RUBY
290
+ end
291
+
292
+ def gen_partial_loader
293
+ <<-'RUBY'
294
+ hbs_loader = "(function() {
295
+ this.Handlebars.registerPartial('#{partial_name}', Handlebars.template(#{compiled_hbs}));
296
+ }).call(this)"
297
+ RUBY
298
+ end
299
+
300
+ def write_asset_files
301
+ <<-RUBY
302
+ File.open('#{@template_path}', 'w+') {|f| f.write(rendered_haml) }
303
+ File.open('#{@compiled_template_path}', 'w+') {|f| f.write(hbs_loader) }
304
+ RUBY
305
+ end
306
+
307
+ def get_hbs_context
308
+ <<-RUBY
309
+ hbs_context = HandlebarsAssets::Handlebars.send(:context)
310
+ RUBY
311
+ end
312
+
313
+ def set_locale
314
+ <<-RUBY
315
+ hbs_context.eval("I18n.locale = '#{I18n.locale.to_s}'")
316
+ RUBY
317
+ end
318
+
319
+ def load_template
320
+ <<-RUBY
321
+ File.open('#{@compiled_template_path}') do |file|
322
+ hbs_context.eval(file.read, '#{@view_name}.js')
323
+ end
324
+ RUBY
325
+ end
326
+
327
+ def render_rabl
328
+
329
+ if File.exist? @rabl_path
330
+
331
+ rabl_handler = ActionView::Template.handler_for_extension :rabl
332
+ rabl_source = File.read(@rabl_path)
333
+ rabl_template = ActionView::Template.new(rabl_source, @rabl_path, rabl_handler, {:locals => @template.locals})
334
+ rabl_call = rabl_handler.call rabl_template
335
+
336
+ <<-RUBY
337
+ rabl_call_str = %q( #{rabl_call} )
338
+ rendered_rabl = eval(rabl_call_str).html_safe
339
+ RUBY
340
+
341
+ else
342
+
343
+ <<-RUBY
344
+ rendered_rabl ||= '{}'.html_safe
345
+ RUBY
346
+
347
+ end
348
+
349
+ end
350
+
351
+ def set_gon_variable
352
+ <<-'RUBY'
353
+ Gon::Request.id = request.object_id
354
+ Gon::Request.env = request.env
355
+ Gon.view_data ||= JSON.parse(rendered_rabl)
356
+ RUBY
357
+ end
358
+
359
+ def render_template
360
+ <<-'RUBY'
361
+ current_template_name = template_names.pop
362
+ hbs_context.eval( "HandlebarsTemplates['#{current_template_name}'](#{rendered_rabl})" )
363
+ RUBY
364
+ end
365
+
366
+ def render_handlebars_partial_command
367
+ <<-RUBY
368
+ '{{> #{@partial_name}}}'.html_safe
369
+ RUBY
370
+ end
371
+
372
+ def render_content_for(name, path)
373
+
374
+ haml_handler = ActionView::Template.handler_for_extension :haml
375
+ haml_source = File.read(path)
376
+ haml_template = ActionView::Template.new(haml_source, path, haml_handler, {})
377
+ haml_call = haml_handler.call haml_template
378
+
379
+ <<-RUBY
380
+ @view_flow.set( :#{name}, eval(%q( #{haml_call} )).html_safe )
381
+ RUBY
382
+
383
+ end
384
+
385
+
386
+ end
387
+
388
+ end
389
+
390
+
391
+
392
+
393
+
394
+
395
+