haml_user_tags 0.9.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.
- checksums.yaml +15 -0
- data/.gitignore +24 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +45 -0
- data/bin/hamlut +12 -0
- data/features/define_tag.feature +94 -0
- data/features/engine.feature +56 -0
- data/features/include_tags.feature +79 -0
- data/features/step_definitions.rb +37 -0
- data/haml_user_tags.gemspec +35 -0
- data/lib/haml_user_tags/compiler.rb +50 -0
- data/lib/haml_user_tags/engine.rb +18 -0
- data/lib/haml_user_tags/helpers.rb +62 -0
- data/lib/haml_user_tags/rails/helpers.rb +21 -0
- data/lib/haml_user_tags/rails/reloader.rb +11 -0
- data/lib/haml_user_tags/version.rb +3 -0
- data/lib/haml_user_tags.rb +17 -0
- data/site/_bootstrap.html.haml +32 -0
- data/site/_haml_user_tags.html.haml +34 -0
- data/site/controller.rb +14 -0
- data/site/download.html.haml +13 -0
- data/site/examples.html.haml +108 -0
- data/site/index.html.haml +98 -0
- data/site/layout.html.haml +44 -0
- data/site/style.css.less +80 -0
- data/site/tutorial.html.haml +185 -0
- metadata +216 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MTY2YzM3MWE1NmUyY2M1MDQ0YmYzZDIxNTE2YmYxOWIwMTk0NjhkMw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjQ5YzM4ODRmZTY4MTE5ZTAzZjE5MGFkNTNiMDM0MDE0MjA1NjZiOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MWRkNDEyMjQ2ZmQ5MTAxZjAxNTUxNzg0Y2E5ODM2MDZhZjQ3Yzc1YjRhYTli
|
10
|
+
N2NlMzE4MDA5OTZkZmEzM2RhNGM4MjQ1ZGIzYzNlNzY5NGE2MDNiYjc3MDk4
|
11
|
+
Nzc1NGRlOTVhY2Y3MmEzMzM5YzhiOWZiOGVjOTRlN2Y1NWNhNjc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YmYyMzllODZkYzMzZjg2YzM2NjY5YWUwNjI1NmQ1NWZlOWFiZTRjZjliYzAz
|
14
|
+
ZDY5ZmE0OWVjMzQwNGQ0ZDcxMTA3NDM1MDhiZmFjNjZjOWE1OWZmYWU3MzQz
|
15
|
+
MzM1MDk0ZmIxZjcxNTQzNGVmZmY5YTAwZTBjMjYwYzNhNDhjNDI=
|
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
/site/public
|
24
|
+
/publish
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ryan Patterson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# HamlUserTags
|
2
|
+
|
3
|
+
Define reusable functions in Haml that can be called with native Haml syntax.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Native Haml syntax for calling helper functions
|
8
|
+
- Ability to define helper functions using Haml
|
9
|
+
- Ability to include user tags from one Haml file in another
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
gem 'haml_user_tags'
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install haml_user_tags
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
TODO: Write usage instructions here
|
28
|
+
|
29
|
+
## TODO
|
30
|
+
|
31
|
+
- Verify it works on Ruby 1.9.7 / Rails 3.2.9
|
32
|
+
- Find best use cases inside SI code and bring in
|
33
|
+
- Explain the lazy evaluation of content
|
34
|
+
- Document how to migrate from partials
|
35
|
+
- Create a wrapper around render :partial to set it as a custom tag.
|
36
|
+
|
37
|
+
It should ensure that tags in the partial don't get included. Potentially use
|
38
|
+
Haml::to_method or whatever to do the defining.
|
39
|
+
|
40
|
+
## Motivation
|
41
|
+
|
42
|
+
Guy Steele's [Growing a Language](http://www.cs.virginia.edu/~evans/cs655/readings/steele.pdf) ([Video](https://www.youtube.com/watch?v=_ahvzDzKdB0)) gives a great demonstration of why user tags in Haml are an essential feature.
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it ( https://github.com/[my-github-username]/haml_user_tags/fork )
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'cucumber/rake/task'
|
3
|
+
|
4
|
+
task :site => 'site:publish'
|
5
|
+
namespace :site do
|
6
|
+
desc "Build web site and commit to gh-pages"
|
7
|
+
task :publish do
|
8
|
+
`git diff --exit-code && git diff --cached --exit-code`
|
9
|
+
unless $?.success?
|
10
|
+
warn "Publish the site from a clean working directory"
|
11
|
+
raise "Exiting"
|
12
|
+
end
|
13
|
+
local_commit = `git rev-parse HEAD`
|
14
|
+
cmd = [
|
15
|
+
'cd site',
|
16
|
+
'stasis',
|
17
|
+
'cd ..',
|
18
|
+
"( [ -d publish ] || git clone -sn --branch gh-pages #{File.dirname __FILE__} publish )",
|
19
|
+
'cp -R site/public/ publish',
|
20
|
+
'cd publish',
|
21
|
+
'git add -A .',
|
22
|
+
"git commit -m 'Exported site from #{local_commit}'",
|
23
|
+
'git push origin gh-pages'
|
24
|
+
].join " &&\n"
|
25
|
+
`#{cmd}`
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Spawn a local server for the site"
|
29
|
+
task :dev do
|
30
|
+
pid = spawn "cd site && ( stasis -d & python -m SimpleHTTPServer )"
|
31
|
+
begin
|
32
|
+
Process.wait pid
|
33
|
+
rescue Interrupt
|
34
|
+
Process.kill pid
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :publish
|
39
|
+
end
|
40
|
+
|
41
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
42
|
+
t.cucumber_opts = "features --format pretty"
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :features
|
data/bin/hamlut
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# The command line Haml parser, augmented with HamlUserTags.
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
5
|
+
require 'haml_user_tags'
|
6
|
+
require 'haml/exec'
|
7
|
+
|
8
|
+
opts = Haml::Exec::Haml.new(ARGV)
|
9
|
+
opts.instance_eval do
|
10
|
+
@options[:for_engine][:compiler_class] = HamlUserTags::Compiler
|
11
|
+
end
|
12
|
+
opts.parse!
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Feature: Define user tags
|
2
|
+
HamlUserTags allows you to define a helper function directly in a Haml
|
3
|
+
template. The helper function will be accessible to the template it was
|
4
|
+
included from.
|
5
|
+
|
6
|
+
Scenario: Basic user tags
|
7
|
+
Given a file named "template.haml" that contains:
|
8
|
+
"""haml
|
9
|
+
- define_tag :Tag do
|
10
|
+
%p This is Tag.
|
11
|
+
%Tag
|
12
|
+
%Tag
|
13
|
+
"""
|
14
|
+
When I render the template "template.haml"
|
15
|
+
Then the output should be:
|
16
|
+
"""html
|
17
|
+
<p>This is Tag.</p>
|
18
|
+
<p>This is Tag.</p>
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: User tags with attributes
|
22
|
+
Given a file named "template.haml" that contains:
|
23
|
+
"""haml
|
24
|
+
- define_tag :Tag do |attributes|
|
25
|
+
%p= attributes.inspect
|
26
|
+
%Tag{ :foo => :bar }
|
27
|
+
%Tag#first_tag.cls
|
28
|
+
%Tag.a{ :class => "b" }
|
29
|
+
"""
|
30
|
+
When I render the template "template.haml"
|
31
|
+
Then the output should be:
|
32
|
+
"""html
|
33
|
+
<p>{"foo"=>"bar"}</p>
|
34
|
+
<p>{"id"=>"first_tag", "class"=>"cls"}</p>
|
35
|
+
<p>{"class"=>"a b"}</p>
|
36
|
+
"""
|
37
|
+
|
38
|
+
Scenario: User tags with content
|
39
|
+
Given a file named "template.haml" that contains:
|
40
|
+
"""haml
|
41
|
+
- define_tag :Tag do |attributes, content|
|
42
|
+
%p= content
|
43
|
+
%Tag inline content
|
44
|
+
%Tag
|
45
|
+
%strong
|
46
|
+
nested content
|
47
|
+
"""
|
48
|
+
When I render the template "template.haml"
|
49
|
+
Then the output should be:
|
50
|
+
"""html
|
51
|
+
<p>inline content</p>
|
52
|
+
<p>
|
53
|
+
<strong>
|
54
|
+
nested content
|
55
|
+
</strong>
|
56
|
+
</p>
|
57
|
+
"""
|
58
|
+
|
59
|
+
Scenario: Lazy evaluation of content
|
60
|
+
Given a file named "template.haml" that contains:
|
61
|
+
"""haml
|
62
|
+
- define_tag :Tag do |attributes, content|
|
63
|
+
- begin
|
64
|
+
= content
|
65
|
+
- rescue
|
66
|
+
Caught an exception!
|
67
|
+
%Tag
|
68
|
+
- raise "Threw an exception!"
|
69
|
+
"""
|
70
|
+
When I render the template "template.haml"
|
71
|
+
Then the output should be:
|
72
|
+
"""html
|
73
|
+
Caught an exception!
|
74
|
+
"""
|
75
|
+
|
76
|
+
Scenario: Pass content through multiple user tags
|
77
|
+
Given a file named "template.haml" that contains:
|
78
|
+
"""haml
|
79
|
+
- define_tag :A do |attributes, content|
|
80
|
+
%p= content
|
81
|
+
- define_tag :B do |attributes, content|
|
82
|
+
%A
|
83
|
+
= content
|
84
|
+
- define_tag :C do |attributes, content|
|
85
|
+
%A= content
|
86
|
+
%B foo
|
87
|
+
%C bar
|
88
|
+
"""
|
89
|
+
When I render the template "template.haml"
|
90
|
+
Then the output should be:
|
91
|
+
"""html
|
92
|
+
<p>foo</p>
|
93
|
+
<p>bar</p>
|
94
|
+
"""
|
@@ -0,0 +1,56 @@
|
|
1
|
+
Feature: Call functions from Haml
|
2
|
+
HamlUserTags allows you to call helper functions that have a special signature using standard Haml tag syntax.
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given a helper module that contains:
|
6
|
+
"""ruby
|
7
|
+
def CustomTag attributes, &block
|
8
|
+
content = capture_haml &block if block
|
9
|
+
"CustomTag called with #{attributes.inspect}, #{content.inspect}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def class_name
|
13
|
+
"class_name"
|
14
|
+
end
|
15
|
+
"""
|
16
|
+
|
17
|
+
Scenario: Basic user tags
|
18
|
+
Given a file named "template.haml" that contains:
|
19
|
+
"""haml
|
20
|
+
%CustomTag
|
21
|
+
"""
|
22
|
+
When I render the template "template.haml"
|
23
|
+
Then the output should be:
|
24
|
+
"""html
|
25
|
+
CustomTag called with {}, nil
|
26
|
+
"""
|
27
|
+
|
28
|
+
Scenario: User tags with attribute
|
29
|
+
Given a file named "template.haml" that contains:
|
30
|
+
"""haml
|
31
|
+
%CustomTag#id.c1.c2{ :class => class_name, :title => 'Title' }
|
32
|
+
"""
|
33
|
+
When I render the template "template.haml"
|
34
|
+
Then the output should be:
|
35
|
+
"""html
|
36
|
+
CustomTag called with {"id"=>"id", "class"=>"c1 c2 class_name", "title"=>"Title"}, nil
|
37
|
+
"""
|
38
|
+
|
39
|
+
Scenario: User tags with content
|
40
|
+
Given a file named "template.haml" that contains:
|
41
|
+
"""haml
|
42
|
+
%CustomTag
|
43
|
+
%CustomTag inline content
|
44
|
+
%CustomTag= "Ruby content"
|
45
|
+
%CustomTag
|
46
|
+
= "Ruby"
|
47
|
+
and normal
|
48
|
+
"""
|
49
|
+
When I render the template "template.haml"
|
50
|
+
Then the output should be:
|
51
|
+
"""html
|
52
|
+
CustomTag called with {}, nil
|
53
|
+
CustomTag called with {}, "inline content"
|
54
|
+
CustomTag called with {}, "Ruby content"
|
55
|
+
CustomTag called with {}, "Ruby\nand normal\n"
|
56
|
+
"""
|
@@ -0,0 +1,79 @@
|
|
1
|
+
Feature: Include tags in Haml templates
|
2
|
+
Once you have created a template that defines some tags in Haml, those tags can be imported into other templates and reused.
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given a file named "helper.haml" that contains:
|
6
|
+
"""haml
|
7
|
+
- define_tag :RemoteTag do
|
8
|
+
%p Remote tag
|
9
|
+
|
10
|
+
Output from the helper file is discarded
|
11
|
+
"""
|
12
|
+
|
13
|
+
Scenario: Importing directly into a template
|
14
|
+
Given a file named "template.haml" that contains:
|
15
|
+
"""haml
|
16
|
+
- include_tags "helper.haml"
|
17
|
+
%RemoteTag
|
18
|
+
%RemoteTag
|
19
|
+
"""
|
20
|
+
When I render the template "template.haml"
|
21
|
+
Then the output should be:
|
22
|
+
"""html
|
23
|
+
<p>Remote tag</p>
|
24
|
+
<p>Remote tag</p>
|
25
|
+
"""
|
26
|
+
|
27
|
+
Scenario: Importing into a helper
|
28
|
+
Given a helper module that contains:
|
29
|
+
"""ruby
|
30
|
+
extend HamlUserTags::Helpers
|
31
|
+
include_tags "helper.haml"
|
32
|
+
"""
|
33
|
+
And a file named "template.haml" that contains:
|
34
|
+
"""haml
|
35
|
+
%RemoteTag
|
36
|
+
%RemoteTag
|
37
|
+
"""
|
38
|
+
When I render the template "template.haml"
|
39
|
+
Then the output should be:
|
40
|
+
"""html
|
41
|
+
<p>Remote tag</p>
|
42
|
+
<p>Remote tag</p>
|
43
|
+
"""
|
44
|
+
|
45
|
+
Scenario: Calling user tags from outside Haml
|
46
|
+
Given a helper module that contains:
|
47
|
+
"""ruby
|
48
|
+
extend HamlUserTags::Helpers
|
49
|
+
include_tags "helper.haml"
|
50
|
+
"""
|
51
|
+
When I evaluate the ruby code:
|
52
|
+
"""ruby
|
53
|
+
foo = Class.new do
|
54
|
+
include CucumberHelper
|
55
|
+
end.new
|
56
|
+
foo.RemoteTag
|
57
|
+
"""
|
58
|
+
Then the output should be:
|
59
|
+
"""html
|
60
|
+
<p>Remote tag</p>
|
61
|
+
"""
|
62
|
+
|
63
|
+
Scenario: Binding to the importing context
|
64
|
+
Given a file named "helper.haml" that contains:
|
65
|
+
"""haml
|
66
|
+
- define_tag :DebugSelf do |attributes|
|
67
|
+
= (attributes["target"].equal?(self)).inspect
|
68
|
+
"""
|
69
|
+
And a file named "template.haml" that contains:
|
70
|
+
"""haml
|
71
|
+
- include_tags "helper.haml"
|
72
|
+
%DebugSelf{ "target" => self }
|
73
|
+
"""
|
74
|
+
When I render the template "template.haml"
|
75
|
+
Then the output should be:
|
76
|
+
"""
|
77
|
+
true
|
78
|
+
"""
|
79
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'haml_user_tags'
|
2
|
+
require 'rspec/expectations'
|
3
|
+
require 'fakefs/safe'
|
4
|
+
|
5
|
+
World(RSpec::Matchers)
|
6
|
+
|
7
|
+
Before do
|
8
|
+
module CucumberHelper
|
9
|
+
end
|
10
|
+
FakeFS.activate!
|
11
|
+
end
|
12
|
+
|
13
|
+
After do
|
14
|
+
Object.send(:remove_const, :CucumberHelper)
|
15
|
+
FakeFS.deactivate!
|
16
|
+
end
|
17
|
+
|
18
|
+
Given(/^a helper module that contains:$/) do |string|
|
19
|
+
CucumberHelper.module_eval string
|
20
|
+
end
|
21
|
+
|
22
|
+
Given(/^a file named "(.*?)" that contains:$/) do |name, content|
|
23
|
+
File.write(name, content)
|
24
|
+
end
|
25
|
+
|
26
|
+
When(/^I render the template "(.*?)"$/) do |filename|
|
27
|
+
template = "- extend CucumberHelper\n#{File.read(filename)}"
|
28
|
+
@output = HamlUserTags::Engine.new(template).to_html
|
29
|
+
end
|
30
|
+
|
31
|
+
When(/^I evaluate the ruby code:$/) do |string|
|
32
|
+
@output = eval(string).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
Then(/^the output should be:$/) do |string|
|
36
|
+
expect(@output).to be == "#{string}\n"
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'haml_user_tags/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "haml_user_tags"
|
8
|
+
spec.version = HamlUserTags::VERSION
|
9
|
+
spec.authors = ["Ryan Patterson"]
|
10
|
+
spec.email = ["cgamesplay@cgamesplay.com"]
|
11
|
+
spec.summary = %q{Define reusable functions in Haml that can be called with native Haml syntax.}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_runtime_dependency "haml", "~> 4.0"
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
|
25
|
+
# Site dependencies
|
26
|
+
spec.add_development_dependency "stasis"
|
27
|
+
spec.add_development_dependency "therubyracer"
|
28
|
+
spec.add_development_dependency "less"
|
29
|
+
spec.add_development_dependency "pygments.rb"
|
30
|
+
|
31
|
+
# Test dependencies
|
32
|
+
spec.add_development_dependency "cucumber"
|
33
|
+
spec.add_development_dependency "rspec-expectations"
|
34
|
+
spec.add_development_dependency "fakefs"
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module HamlUserTags
|
2
|
+
class Compiler < Haml::Compiler
|
3
|
+
def compile(node)
|
4
|
+
if node.type == :tag and node.value[:name] =~ HamlUserTags::TAG_NAME_REGEX
|
5
|
+
node = convert_user_tag_to_script node
|
6
|
+
end
|
7
|
+
super node
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def convert_user_tag_to_script(node)
|
12
|
+
t = node.value
|
13
|
+
attributes = t[:attributes]
|
14
|
+
attributes_hashes = t[:attributes_hashes]
|
15
|
+
object_ref = t[:object_ref]
|
16
|
+
|
17
|
+
if object_ref == "nil" and attributes.length == 0 and attributes_hashes.empty?
|
18
|
+
attributes = "{}"
|
19
|
+
else
|
20
|
+
if attributes_hashes.empty?
|
21
|
+
attributes_hashes = ''
|
22
|
+
elsif attributes_hashes.size == 1
|
23
|
+
attributes_hashes = ", #{attributes_hashes.first}"
|
24
|
+
else
|
25
|
+
attributes_hashes = ", #{attributes_hashes.join(", ")}"
|
26
|
+
end
|
27
|
+
attributes = "HamlUserTags::Helpers.attributes_hash(#{inspect_obj(t[:attributes])}, #{object_ref}#{attributes_hashes})"
|
28
|
+
end
|
29
|
+
|
30
|
+
if node.children.length > 0
|
31
|
+
contents = " do"
|
32
|
+
elsif t[:value] and t[:parse]
|
33
|
+
contents = " { _hamlout.push_text(#{t[:value]}, 0, false) }"
|
34
|
+
elsif t[:value] and not t[:parse]
|
35
|
+
contents = " { _hamlout.push_text(#{inspect_obj t[:value]}, 0, false) }"
|
36
|
+
end
|
37
|
+
|
38
|
+
code = "#{t[:name]}(#{attributes})#{contents}"
|
39
|
+
script_value = t.clone.update({
|
40
|
+
:text => code,
|
41
|
+
:escape_html => false,
|
42
|
+
:preserve => false,
|
43
|
+
:keyword => nil,
|
44
|
+
:value => nil,
|
45
|
+
:parse => nil,
|
46
|
+
})
|
47
|
+
Haml::Parser::ParseNode.new(:script, node.line, script_value, node.parent, node.children)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module HamlUserTags
|
2
|
+
class Engine < Haml::Engine
|
3
|
+
def initialize(template, options = {})
|
4
|
+
options = options.clone.update(:compiler_class => HamlUserTags::Compiler)
|
5
|
+
super template, options
|
6
|
+
end
|
7
|
+
|
8
|
+
# Defines a method for each user tag in the template that renders the tag
|
9
|
+
# and returns the result as a string.
|
10
|
+
def extend_object obj
|
11
|
+
mod = Module.new
|
12
|
+
mod.send :include, Haml::Helpers
|
13
|
+
render mod
|
14
|
+
method = obj.is_a?(Module) ? :include : :extend
|
15
|
+
obj.send method, mod
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module HamlUserTags
|
4
|
+
module Helpers
|
5
|
+
# Same as Haml::Buffer.attributes, but returns the hash instead of writing
|
6
|
+
# the attributes to the buffer.
|
7
|
+
def self.attributes_hash(class_id, obj_ref, *attributes_hashes)
|
8
|
+
attributes = class_id
|
9
|
+
attributes_hashes.each do |old|
|
10
|
+
Haml::Buffer.merge_attrs(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
|
11
|
+
end
|
12
|
+
Haml::Buffer.merge_attrs(attributes, Haml::Buffer.new.parse_object_ref(obj_ref)) if obj_ref
|
13
|
+
attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
def define_tag name, &tag
|
17
|
+
unless name =~ HamlUserTags::TAG_NAME_REGEX
|
18
|
+
raise "define_tag: #{name.inspect} is not a valid user tag name. It must match #{HamlUserTags::TAG_NAME_REGEX}"
|
19
|
+
end
|
20
|
+
|
21
|
+
func = proc do |attributes = {}, &contents|
|
22
|
+
@haml_buffer ||= Haml::Buffer.new(nil, Haml::Options.defaults)
|
23
|
+
tag.binding.eval("proc { |v| _hamlout = v }").call @haml_buffer
|
24
|
+
# Use a proxy String class that will only evaluate its contents once
|
25
|
+
# it is referenced. This make the behavior similar to how "yield"
|
26
|
+
# would be in a ruby helper.
|
27
|
+
content_getter = LazyContents.new { capture_haml(&contents) || "" } if contents
|
28
|
+
capture_haml { instance_exec attributes, content_getter, &tag }
|
29
|
+
end
|
30
|
+
|
31
|
+
define_singleton_method name, &func
|
32
|
+
if self.is_a?(Module)
|
33
|
+
define_method name, &func
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def include_tags path
|
38
|
+
source = File.read path
|
39
|
+
HamlUserTags::Engine.new(source).extend_object self
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class LazyContents < DelegateClass(String)
|
45
|
+
def initialize(&generator)
|
46
|
+
@generator = generator
|
47
|
+
end
|
48
|
+
|
49
|
+
def __getobj__
|
50
|
+
unless @results
|
51
|
+
@results, @generator = @generator.call, nil
|
52
|
+
end
|
53
|
+
@results
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Haml
|
59
|
+
module Helpers
|
60
|
+
include HamlUserTags::Helpers
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HamlUserTags
|
2
|
+
module Helpers
|
3
|
+
alias_method :include_tags_without_rails, :include_tags
|
4
|
+
# Override the base include_tags to take advantage of Rails' template
|
5
|
+
# location features
|
6
|
+
def include_tags path
|
7
|
+
view_paths = ActionController::Base._view_paths
|
8
|
+
lookup_context = ActionView::LookupContext.new(view_paths, {}, [])
|
9
|
+
template = lookup_context.find_template(path, [], true)
|
10
|
+
HamlUserTags::Engine.new(template.source).extend_object self
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def attributes_hash_with_indifference *args
|
16
|
+
ActiveSupport::HashWithIndifferentAccess.new attributes_hash_without_indifference *args
|
17
|
+
end
|
18
|
+
alias_method_chain :attributes_hash, :indifference
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module HamlUserTags
|
2
|
+
class Reloader < Rails::Railtie
|
3
|
+
initializer "haml_user_tags.enable_reloading" do
|
4
|
+
watcher = ActiveSupport::FileUpdateChecker.new([], "#{Rails.root}/app/views/helpers" => %w{haml}) {}
|
5
|
+
Rails.application.reloaders << watcher
|
6
|
+
ActionDispatch::Reloader.to_prepare do
|
7
|
+
watcher.execute_if_updated
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "haml"
|
2
|
+
require "haml_user_tags/version"
|
3
|
+
require "haml_user_tags/compiler"
|
4
|
+
require "haml_user_tags/engine"
|
5
|
+
require "haml_user_tags/helpers"
|
6
|
+
|
7
|
+
module HamlUserTags
|
8
|
+
TAG_NAME_REGEX = /^[A-Z][a-zA-Z]*$/
|
9
|
+
end
|
10
|
+
|
11
|
+
if defined? ActiveSupport
|
12
|
+
require 'haml_user_tags/rails/helpers'
|
13
|
+
require "haml_user_tags/rails/reloader"
|
14
|
+
|
15
|
+
# Set up Haml to use HamlUserTags by default
|
16
|
+
Haml::Template.options[:compiler_class] = HamlUserTags::Compiler
|
17
|
+
end
|