hamlbars 1.0.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/History.md +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +129 -0
- data/lib/hamlbars/ext/closure.rb +43 -0
- data/lib/hamlbars/ext/compiler.rb +45 -0
- data/lib/hamlbars/ext/precompiler.rb +71 -0
- data/lib/hamlbars/ext/rails_helper.rb +38 -0
- data/lib/hamlbars/ext.rb +8 -0
- data/lib/hamlbars/template.rb +207 -0
- data/lib/hamlbars/version.rb +3 -0
- data/lib/hamlbars.rb +22 -0
- data/vendor/javascripts/handlebars.js +1610 -0
- data/vendor/javascripts/precompiler.js +33 -0
- metadata +171 -0
data/History.md
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008-2010 Justin French
|
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,129 @@
|
|
1
|
+
# Hamlbars
|
2
|
+
|
3
|
+
[](http://travis-ci.org/jamesotron/hamlbars)
|
4
|
+
[](https://gemnasium.com/jamesotron/hamlbars)
|
5
|
+
|
6
|
+
[Hamlbars](https://github.com/jamesotron/hamlbars) is a Ruby gem which allows you to easily generate [Handlebar](http://handlebarsjs.com) templates using [Haml](http://www.haml-lang.com).
|
7
|
+
|
8
|
+
# Demo Site
|
9
|
+
|
10
|
+
If you're unsure how all the pieces fit together then take a quick look at the [demo site](http://hamlbars-demo.herokuapp.com/).
|
11
|
+
|
12
|
+
# Attribute bindings
|
13
|
+
|
14
|
+
You can easily add attribute bindings by adding a `:bind` hash to the tag attributes, like so:
|
15
|
+
|
16
|
+
%div{ :class => 'widget', :bind => { :title => 'App.widgetController.title' }
|
17
|
+
|
18
|
+
Which will generate the following output:
|
19
|
+
|
20
|
+
<div class="widget" {{bindAttr title="App.widgetController.title"}}></div>
|
21
|
+
|
22
|
+
# Event bindings
|
23
|
+
|
24
|
+
You can add one or more event actions by adding an event hash or array or event hashes to the tag options:
|
25
|
+
|
26
|
+
%a{ :event => { :on => 'click', :action => 'clicked' } } Click
|
27
|
+
|
28
|
+
or
|
29
|
+
|
30
|
+
%div{ :events => [ { :on => 'mouseover', :action => 'highlightView' }, { :on => 'mouseout', :action => 'disableViewHighlight' } ] }
|
31
|
+
|
32
|
+
Note that the default event is `click`, so it's not necessary to specify it:
|
33
|
+
|
34
|
+
%a{ :event => { :action => 'clicked' } } Click
|
35
|
+
|
36
|
+
# Handlebar helper
|
37
|
+
|
38
|
+
You can use the `handlebars` helper (or just `hb` for short) to generate both Handlebar blocks and expressions.
|
39
|
+
|
40
|
+
## Expressions
|
41
|
+
|
42
|
+
Generating Handlebars expressions is as simple as using the `handlebars` helper and providing the expression as a string argument:
|
43
|
+
|
44
|
+
= hb 'App.widgetController.title'
|
45
|
+
|
46
|
+
which will will generate:
|
47
|
+
|
48
|
+
{{App.widgetController.title}}
|
49
|
+
|
50
|
+
## Blocks
|
51
|
+
|
52
|
+
Whereas passing a block to the `handlebars` helper will create a Handlebars block expression:
|
53
|
+
|
54
|
+
%ul.authors
|
55
|
+
= hb 'each authors' do
|
56
|
+
%li<
|
57
|
+
= succeed ',' do
|
58
|
+
= hb 'lastName'
|
59
|
+
= hb 'firstName'
|
60
|
+
|
61
|
+
will result in the following markup:
|
62
|
+
|
63
|
+
<ul class="authors">
|
64
|
+
{{#each authors}}
|
65
|
+
<li>{{lastName}}, {{firstName}}</li>
|
66
|
+
{{/each}}
|
67
|
+
</ul>
|
68
|
+
|
69
|
+
## Options
|
70
|
+
|
71
|
+
The `hb` helper can take an optional hash of options which will be rendered inside the expression:
|
72
|
+
|
73
|
+
= hb 'view App.InfoView', :tagName => 'span'
|
74
|
+
|
75
|
+
will result in:
|
76
|
+
|
77
|
+
{{view App.InfoView tagName="span"}}
|
78
|
+
|
79
|
+
## Tripple-stash
|
80
|
+
|
81
|
+
You can use the `handlebars!` or `hb!` variant of the `handlebars` helper to output "tripple-stash" expressions within which Handlebars does not escape the output.
|
82
|
+
|
83
|
+
# Configuring template output:
|
84
|
+
|
85
|
+
`hamlbars` has three configuration options, which pertain to the generated JavaScript:
|
86
|
+
|
87
|
+
Hamlbars::Template.template_destination # default 'Handlebars.templates'
|
88
|
+
Hamlbars::Template.template_compiler # default 'Handlebars.compile'
|
89
|
+
Hamlbars::Template.template_partial_method # default 'Handlebars.registerPartial'
|
90
|
+
|
91
|
+
These settings will work find by default if you are using Handlebars as a standalone JavaScript library, however if you are using something that embeds Handlebars within it then you'll have to change these.
|
92
|
+
|
93
|
+
If you're using [Ember.js](http://www.emberjs.com) then you can use:
|
94
|
+
|
95
|
+
Hamlbars::Template.render_templates_for :ember
|
96
|
+
|
97
|
+
Which is effectively the same as:
|
98
|
+
|
99
|
+
Hamlbars::Template.template_destination = 'Ember.TEMPLATES'
|
100
|
+
Hamlbars::Template.template_compiler = 'Ember.Handlebars.compile'
|
101
|
+
Hamlbars::Template.template_partial_method = 'Ember.Handlebars.registerPartial'
|
102
|
+
|
103
|
+
The good news is that if you're using the [emberjs-rails](http://www.rubygems.org/gems/emberjs-rails) gem then it will automatically detect hamlbars and change it for you. Magic!
|
104
|
+
|
105
|
+
If you're using [ember-rails](http://rubygems.org/gems/ember-rails) then you'll need to put this in a initializer.
|
106
|
+
|
107
|
+
# Configuring JavaScript output:
|
108
|
+
|
109
|
+
As of version 2012.3.21 `hamlbars` has experimental support for template precompilation using [ExecJS](http://rubygems.org/gems/execjs). If you want to enable this support you can use:
|
110
|
+
|
111
|
+
Hamlbars::Template.enable_precompiler!
|
112
|
+
|
113
|
+
You can also disable enclosification (which is enabled by default) using:
|
114
|
+
|
115
|
+
Hamlbars::Template.disable_closures!
|
116
|
+
|
117
|
+
# Asset pipeline
|
118
|
+
|
119
|
+
Hamlbars is specifically designed for use with Rails 3.1's asset pipeline. Simply create templates ending in `.js.hamlbars` and Sprockets will know what to do.
|
120
|
+
|
121
|
+
# Rails helpers
|
122
|
+
|
123
|
+
You can enable support by calling `Hamlbars::Template.enable_rails_helpers!`. Probably the best way to do this is to create an initializer. This is dangerous and possibly stupid as a large number of Rails' helpers require access to the request object, which is not present when compiling assets.
|
124
|
+
|
125
|
+
**Use at your own risk. You have been warned.**
|
126
|
+
|
127
|
+
# License and Copyright.
|
128
|
+
|
129
|
+
Hamlbars is Copyright © 2012 [Sociable Limited](http://sociable.co.nz/) and licensed under the terms of the MIT License.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Hamlbars
|
2
|
+
module Ext
|
3
|
+
module Closure
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
# Wraps the JavaScript generated by Haml::Template#evaluate
|
10
|
+
# in a JavaScript closure.
|
11
|
+
def evaluate_with_closure(scope, locals, &block)
|
12
|
+
self.class.closures_enabled? ? enclosify { evaluate_without_closure(scope,locals,&block) } : evaluate_without_closure(scope,locals,&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def enclosify
|
18
|
+
"(function() { #{yield} }).call(this)"
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
# Enables closure wrapping for rendered templates.
|
23
|
+
def enable_closures!
|
24
|
+
@enable_closures = true
|
25
|
+
unless public_method_defined? :evaluate_without_closure
|
26
|
+
alias_method :evaluate_without_closure, :evaluate
|
27
|
+
alias_method :evaluate, :evaluate_with_closure
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def closures_enabled?
|
32
|
+
!!@enable_closures
|
33
|
+
end
|
34
|
+
|
35
|
+
# Disables closure wrapping for rendered templates.
|
36
|
+
def disable_closures!
|
37
|
+
@enable_closures = false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Hamlbars
|
2
|
+
module Ext
|
3
|
+
module Compiler
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Haml
|
9
|
+
module Compiler
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Overload build_attributes in Haml::Compiler to allow
|
13
|
+
# for the creation of handlebars bound attributes by
|
14
|
+
# adding :bind hash to the tag attributes.
|
15
|
+
def build_attributes_with_handlebars_attributes (is_html, attr_wrapper, escape_attrs, attributes={})
|
16
|
+
attributes[:bind] = attributes.delete('bind') if attributes['bind']
|
17
|
+
attributes[:event] = attributes.delete('event') if attributes['event']
|
18
|
+
attributes[:events] = attributes.delete('events') if attributes['events']
|
19
|
+
attributes[:events] ||= []
|
20
|
+
attributes[:events] << attributes.delete(:event) if attributes[:event]
|
21
|
+
|
22
|
+
handlebars_rendered_attributes = []
|
23
|
+
handlebars_rendered_attributes << handlebars_attributes('bindAttr', attributes.delete(:bind)) if attributes[:bind]
|
24
|
+
attributes[:events].each do |event|
|
25
|
+
event[:on] = event.delete('on') || event.delete(:on) || 'click'
|
26
|
+
action = event.delete('action') || event.delete(:action)
|
27
|
+
handlebars_rendered_attributes << handlebars_attributes("action \"#{action}\"", event)
|
28
|
+
end
|
29
|
+
attributes.delete(:events)
|
30
|
+
|
31
|
+
(handlebars_rendered_attributes * '') +
|
32
|
+
build_attributes_without_handlebars_attributes(is_html, attr_wrapper, escape_attrs, attributes)
|
33
|
+
end
|
34
|
+
alias build_attributes_without_handlebars_attributes build_attributes
|
35
|
+
alias build_attributes build_attributes_with_handlebars_attributes
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def handlebars_attributes(helper, attributes)
|
40
|
+
rendered_attributes = [].tap { |r|attributes.each { |k,v| r << "#{k}=\"#{v}\"" } }.join(' ')
|
41
|
+
" {{#{helper} #{rendered_attributes}}}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'execjs'
|
2
|
+
|
3
|
+
module Hamlbars
|
4
|
+
module Ext
|
5
|
+
module Precompiler
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
# Takes the rendered template and compiles it using the Handlebars
|
12
|
+
# compiler via ExecJS.
|
13
|
+
def evaluate_with_precompiler(scope, locals, &block)
|
14
|
+
if self.class.precompiler_enabled?
|
15
|
+
precompile { evaluate_without_precompiler(scope,locals,&block) }
|
16
|
+
else
|
17
|
+
evaluate_without_precompiler(scope,locals,&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def precompile
|
24
|
+
str = yield
|
25
|
+
str.gsub(Regexp.new("(#{Hamlbars::Template.template_compiler})\((.+)\)")) do |match|
|
26
|
+
# No named groups. WAT!
|
27
|
+
compiler = $1
|
28
|
+
template = $2
|
29
|
+
if compiler =~ /\.compile$/
|
30
|
+
"#{compiler.gsub(/\.compile$/, '.template')}(#{runtime.call('Hamlbars.precompile', template)})"
|
31
|
+
else
|
32
|
+
# Unable to precompile.
|
33
|
+
match
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def runtime
|
39
|
+
Thread.current[:hamlbars_js_runtime] ||= ExecJS.compile(js)
|
40
|
+
end
|
41
|
+
|
42
|
+
def js
|
43
|
+
[ 'handlebars.js', 'precompiler.js' ].map do |name|
|
44
|
+
File.read(File.expand_path("../../../../vendor/javascripts/#{name}", __FILE__))
|
45
|
+
end.join("\n")
|
46
|
+
end
|
47
|
+
|
48
|
+
module ClassMethods
|
49
|
+
|
50
|
+
# Enables use of the Handlebars compiler when rendering
|
51
|
+
# templates.
|
52
|
+
def enable_precompiler!
|
53
|
+
@precompiler_enabled = true
|
54
|
+
unless public_method_defined? :evaluate_without_precompiler
|
55
|
+
alias_method :evaluate_without_precompiler, :evaluate
|
56
|
+
alias_method :evaluate, :evaluate_with_precompiler
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def precompiler_enabled?
|
61
|
+
!!@precompiler_enabled
|
62
|
+
end
|
63
|
+
|
64
|
+
def disable_precompiler!
|
65
|
+
@precompiler_enabled = false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hamlbars
|
2
|
+
module Ext
|
3
|
+
module RailsHelper
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(scope,locals,&block)
|
10
|
+
scope = scope.dup
|
11
|
+
|
12
|
+
scope.class.send(:include, ActionView::Helpers) if defined?(::ActionView)
|
13
|
+
if defined?(::Rails)
|
14
|
+
scope.class.send(:include, Rails.application.helpers)
|
15
|
+
scope.class.send(:include, Rails.application.routes.url_helpers)
|
16
|
+
scope.default_url_options = Rails.application.config.action_controller.default_url_options || {}
|
17
|
+
end
|
18
|
+
super(scope, locals, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
def enable_rails_helpers!
|
23
|
+
(Rails.env == 'development' ? Logger.new(STDOUT) : Rails.logger).warn "WARNING (hamlbars): Enabling helpers in assets can have unintended consequences and violates separation of concerns. You have been warned."
|
24
|
+
@enable_rails_helpers = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def rails_helpers_enabled?
|
28
|
+
!!@enable_rails_helpers
|
29
|
+
end
|
30
|
+
|
31
|
+
def disable_rails_helpers!
|
32
|
+
@enable_rails_helpers = false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/hamlbars/ext.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
module Hamlbars
|
2
|
+
module Ext
|
3
|
+
autoload :Compiler, File.expand_path('../ext/compiler.rb', __FILE__)
|
4
|
+
autoload :Precompiler, File.expand_path('../ext/precompiler.rb', __FILE__)
|
5
|
+
autoload :Closure, File.expand_path('../ext/closure.rb', __FILE__)
|
6
|
+
autoload :RailsHelper, File.expand_path('../ext/rails_helper.rb', __FILE__)
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
|
3
|
+
module Hamlbars
|
4
|
+
class Template < Tilt::Template
|
5
|
+
include Ext::Closure
|
6
|
+
enable_closures! # Enable closures by default.
|
7
|
+
include Ext::Precompiler
|
8
|
+
if defined? Rails
|
9
|
+
include Ext::RailsHelper
|
10
|
+
enable_precompiler! if Rails.env.production?
|
11
|
+
end
|
12
|
+
|
13
|
+
JS_ESCAPE_MAP = {
|
14
|
+
"\r\n" => '\n',
|
15
|
+
"\n" => '\n',
|
16
|
+
"\r" => '\n',
|
17
|
+
'"' => '\\"',
|
18
|
+
"'" => "\\'"
|
19
|
+
}
|
20
|
+
|
21
|
+
# Used to change the asset path into a string which is
|
22
|
+
# safe to use as a JavaScript object property.
|
23
|
+
def self.path_translator(path)
|
24
|
+
path.downcase.gsub(/[^a-z0-9\/]/, '_')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Handy helper to preconfigure Hamlbars to render for
|
28
|
+
# either :handlebars (default) or :ember.
|
29
|
+
def self.render_templates_for(whom=:handlebars)
|
30
|
+
if whom == :handlebars
|
31
|
+
self.template_destination = 'Handlebars.templates'
|
32
|
+
self.template_compiler = 'Handlebars.compile'
|
33
|
+
self.template_partial_method = 'Handlebars.registerPartial'
|
34
|
+
elsif whom == :ember
|
35
|
+
self.template_destination = 'Ember.TEMPLATES'
|
36
|
+
self.template_compiler = 'Ember.Handlebars.compile'
|
37
|
+
self.template_partial_method = 'Ember.Handlebars.registerPartial'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The target object where the rendered template will
|
42
|
+
# be stored on the client side.
|
43
|
+
# Defaults to 'Handlebars.templates'
|
44
|
+
def self.template_destination
|
45
|
+
@template_destination ||= 'Handlebars.templates'
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.template_destination=(x)
|
49
|
+
@template_destination = x
|
50
|
+
end
|
51
|
+
|
52
|
+
# The JavaScript function used to compile the HTML
|
53
|
+
# string into a usable Handlebars template.
|
54
|
+
def self.template_compiler
|
55
|
+
@template_compiler ||= 'Handlebars.compile'
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.template_compiler=(x)
|
59
|
+
@template_compiler = x
|
60
|
+
end
|
61
|
+
|
62
|
+
# The JavaScript function used on the compile side to
|
63
|
+
# register the template as a partial on the client side.
|
64
|
+
def self.template_partial_method
|
65
|
+
@template_partial_method ||= 'Handlebars.registerPartial'
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.template_partial_method=(x)
|
69
|
+
@template_partial_method = x
|
70
|
+
end
|
71
|
+
|
72
|
+
self.default_mime_type = 'application/javascript'
|
73
|
+
|
74
|
+
def self.engine_initialized?
|
75
|
+
defined? ::Haml::Engine
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize_engine
|
79
|
+
require_template_library 'haml'
|
80
|
+
end
|
81
|
+
|
82
|
+
def prepare
|
83
|
+
options = @options.merge(:filename => eval_file, :line => line)
|
84
|
+
@engine = ::Haml::Engine.new(data, options)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Uses Haml to render the template into an HTML string, then
|
88
|
+
# wraps it in the neccessary JavaScript to serve to the client.
|
89
|
+
def evaluate(scope, locals, &block)
|
90
|
+
template = if @engine.respond_to?(:precompiled_method_return_value, true)
|
91
|
+
super(scope, locals, &block)
|
92
|
+
else
|
93
|
+
@engine.render(scope, locals, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
if scope.respond_to? :logical_path
|
97
|
+
path = scope.logical_path
|
98
|
+
else
|
99
|
+
path = basename
|
100
|
+
end
|
101
|
+
|
102
|
+
if basename =~ /^_/
|
103
|
+
name = partial_path_translator(path)
|
104
|
+
"#{self.class.template_partial_method}('#{name}', '#{template.strip.gsub(/(\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }}');\n"
|
105
|
+
else
|
106
|
+
name = self.class.path_translator(path)
|
107
|
+
"#{self.class.template_destination}[\"#{name}\"] = #{self.class.template_compiler}(\"#{template.strip.gsub(/(\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }}\");\n"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Used to change the asset path into a string which is
|
112
|
+
# safe to use as a JavaScript object property. When
|
113
|
+
# the template is a partial (ie starts with a '_')
|
114
|
+
def partial_path_translator(path)
|
115
|
+
path = remove_underscore_from_partial_path(path)
|
116
|
+
self.class.path_translator(path).gsub(%r{/}, '.')
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def remove_underscore_from_partial_path(path)
|
122
|
+
path.sub(/(.*)(\/|^)_(.+?)$/, '\1\2\3')
|
123
|
+
end
|
124
|
+
|
125
|
+
# Precompiled Haml source. Taken from the precompiled_with_ambles
|
126
|
+
# method in Haml::Precompiler:
|
127
|
+
# http://github.com/nex3/haml/blob/master/lib/haml/precompiler.rb#L111-126
|
128
|
+
def precompiled_template(locals)
|
129
|
+
@engine.precompiled
|
130
|
+
end
|
131
|
+
|
132
|
+
def precompiled_preamble(locals)
|
133
|
+
local_assigns = super
|
134
|
+
@engine.instance_eval do
|
135
|
+
<<-RUBY
|
136
|
+
begin
|
137
|
+
extend Haml::Helpers
|
138
|
+
_hamlout = @haml_buffer = Haml::Buffer.new(@haml_buffer, #{options_for_buffer.inspect})
|
139
|
+
_erbout = _hamlout.buffer
|
140
|
+
__in_erb_template = true
|
141
|
+
_haml_locals = locals
|
142
|
+
#{local_assigns}
|
143
|
+
RUBY
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def precompiled_postamble(locals)
|
148
|
+
@engine.instance_eval do
|
149
|
+
<<-RUBY
|
150
|
+
#{precompiled_method_return_value}
|
151
|
+
ensure
|
152
|
+
@haml_buffer = @haml_buffer.upper
|
153
|
+
end
|
154
|
+
RUBY
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
module Haml
|
161
|
+
module Helpers
|
162
|
+
|
163
|
+
module HamlbarsExtensions
|
164
|
+
# Used to create handlebars expressions within HAML,
|
165
|
+
# if you pass a block then it will create a Handlebars
|
166
|
+
# block helper (ie "{{#expression}}..{{/expression}}"
|
167
|
+
# otherwise it will create an expression
|
168
|
+
# (ie "{{expression}}").
|
169
|
+
def handlebars(expression, options={}, &block)
|
170
|
+
express(['{{','}}'],expression,options,&block)
|
171
|
+
end
|
172
|
+
alias hb handlebars
|
173
|
+
|
174
|
+
# The same as #handlebars except that it outputs "triple-stash"
|
175
|
+
# expressions, which means that Handlebars won't escape the output.
|
176
|
+
def handlebars!(expression, options={}, &block)
|
177
|
+
express(['{{{','}}}'],expression,options,&block)
|
178
|
+
end
|
179
|
+
alias hb! handlebars!
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def make(expression, options)
|
184
|
+
if options.any?
|
185
|
+
expression << " " << options.map {|key, value| "#{key}=\"#{value}\"" }.join(' ')
|
186
|
+
else
|
187
|
+
expression
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def express(demarcation,expression,options={},&block)
|
192
|
+
if block.respond_to? :call
|
193
|
+
content = capture_haml(&block)
|
194
|
+
output = "#{demarcation.first}##{make(expression, options)}#{demarcation.last}#{content.strip}#{demarcation.first}/#{expression.split(' ').first}#{demarcation.last}"
|
195
|
+
else
|
196
|
+
output = "#{demarcation.first}#{make(expression, options)}#{demarcation.last}"
|
197
|
+
end
|
198
|
+
|
199
|
+
output = Haml::Util.html_safe(output) if Haml::Util.rails_xss_safe?
|
200
|
+
output
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
include HamlbarsExtensions
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
data/lib/hamlbars.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'haml'
|
2
|
+
require 'sprockets'
|
3
|
+
|
4
|
+
module Hamlbars
|
5
|
+
|
6
|
+
if defined? Rails
|
7
|
+
class Engine < Rails::Engine
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
12
|
+
|
13
|
+
autoload :Ext, File.join(ROOT, 'hamlbars', 'ext')
|
14
|
+
autoload :Template, File.join(ROOT, 'hamlbars', 'template')
|
15
|
+
|
16
|
+
Haml::Compiler.send(:include, Ext::Compiler)
|
17
|
+
|
18
|
+
if defined? Sprockets
|
19
|
+
Sprockets.register_engine '.hamlbars', Template
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|