haml2erb 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/README.rdoc +58 -0
- data/haml2erb.gemspec +23 -0
- data/lib/haml2erb.rb +15 -0
- data/lib/haml2erb/erb_writer.rb +51 -0
- data/lib/haml2erb/lexer.rb +28 -0
- data/lib/haml2erb/mixins/comerging.rb +22 -0
- data/lib/haml2erb/parser.rb +69 -0
- data/lib/haml2erb/railtie.rb +7 -0
- data/lib/haml2erb/tokens.rb +110 -0
- data/lib/haml2erb/version.rb +3 -0
- data/tasks/haml2erb.rake +7 -0
- metadata +89 -0
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= haml2erb Rails Plugin
|
2
|
+
|
3
|
+
haml2erb is a tool for converting {Haml markup}[http://haml-lang.com/] to Erb markup.
|
4
|
+
|
5
|
+
<b>Latest version:</b> 0.2.0
|
6
|
+
|
7
|
+
* API documentation (coming soon)
|
8
|
+
* {Source code} [http://github.com/cgoddard/haml2erb/]
|
9
|
+
* {Bug tracker} [http://github.com/cgoddard/haml2erb/issues]
|
10
|
+
|
11
|
+
Tested on Ruby 1.9.1 and Ruby 1.8.7
|
12
|
+
|
13
|
+
=== Installing and loading haml2erb
|
14
|
+
|
15
|
+
haml2erb is currently distributed as a Rails plugin.
|
16
|
+
|
17
|
+
Simply move the main haml2erb directory into the vendor/plugins directory of your Rails application.
|
18
|
+
|
19
|
+
=== Using haml2erb
|
20
|
+
|
21
|
+
From the Rails console or application, call the Haml2Erb.convert method to have haml
|
22
|
+
markup translated into erb.
|
23
|
+
|
24
|
+
==== Example: Simple conversion
|
25
|
+
Haml2Erb.convert('.foo')
|
26
|
+
# => "<div class='foo'>\n</div>\n"
|
27
|
+
|
28
|
+
=== Not supported yet
|
29
|
+
|
30
|
+
Parsing of tag internal string interpolations, such as:
|
31
|
+
#my_div{ class: "box #{extra_classes}" }
|
32
|
+
|
33
|
+
Coming soon though ...
|
34
|
+
|
35
|
+
== Licenses
|
36
|
+
|
37
|
+
==== haml2erb code and documentation (MIT license)
|
38
|
+
|
39
|
+
Copyright (c) 2010 Chris Goddard
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
42
|
+
a copy of this software and associated documentation files (the
|
43
|
+
"Software"), to deal in the Software without restriction, including
|
44
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
45
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
46
|
+
permit persons to whom the Software is furnished to do so, subject to
|
47
|
+
the following conditions:
|
48
|
+
|
49
|
+
The above copyright notice and this permission notice shall be
|
50
|
+
included in all copies or substantial portions of the Software.
|
51
|
+
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
55
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
56
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
57
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
58
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/haml2erb.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
|
5
|
+
require 'haml2erb/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "haml2erb"
|
9
|
+
s.version = Haml2Erb::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = 'Louis Sivillo'
|
12
|
+
s.email = ['louis.sivillo@gmail.com']
|
13
|
+
|
14
|
+
s.summary = 'Haml to ERB Converter'
|
15
|
+
s.description = 'Haml to ERB Converter'
|
16
|
+
|
17
|
+
s.required_rubygems_version = ">= 1.3.6"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'mixology'
|
23
|
+
end
|
data/lib/haml2erb.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'haml2erb/railtie' if defined?(Rails::Railtie)
|
2
|
+
require 'haml2erb/erb_writer'
|
3
|
+
require 'haml2erb/parser'
|
4
|
+
require 'haml2erb/version'
|
5
|
+
|
6
|
+
module Haml2Erb
|
7
|
+
|
8
|
+
def self.convert(text)
|
9
|
+
parser = Haml2Erb::HamlParser.new
|
10
|
+
writer = Haml2Erb::ErbWriter.new
|
11
|
+
parser.parse(text, writer)
|
12
|
+
writer.output_to_string
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Haml2Erb
|
2
|
+
class ErbWriter
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@processed = ''
|
6
|
+
@tag_stack = [ ]
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(line_options)
|
10
|
+
|
11
|
+
close_tags(line_options[:indent])
|
12
|
+
@tag_stack.push(line_options[:element_type]) if line_options[:element_type]
|
13
|
+
|
14
|
+
@processed << (" " * line_options[:indent]) if line_options[:indent]
|
15
|
+
@processed << "<#{line_options[:element_type].to_s}" if line_options[:element_type]
|
16
|
+
@processed << " id='#{line_options[:element_id].to_s}'" if line_options[:element_id]
|
17
|
+
@processed << " class='#{[*line_options[:element_class]].join(' ')}'" if line_options[:element_class]
|
18
|
+
line_options[:element_attributes] && line_options[:element_attributes].keys.each do |attribute_key|
|
19
|
+
@processed << " #{attribute_key}='#{line_options[:element_attributes][attribute_key]}'"
|
20
|
+
end
|
21
|
+
@processed << ">" if line_options[:element_type]
|
22
|
+
|
23
|
+
case(line_options[:content_type])
|
24
|
+
when :text
|
25
|
+
@processed << (line_options[:contents] || "")
|
26
|
+
when :ruby
|
27
|
+
@processed << ("<%= " + line_options[:contents] + " %>")
|
28
|
+
when :mixed
|
29
|
+
@processed << ('<%= "' + line_options[:contents] + '" %>')
|
30
|
+
end
|
31
|
+
|
32
|
+
close_tags(line_options[:indent], :separate_line => false) if line_options[:contents]
|
33
|
+
@processed << "\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def output_to_string
|
37
|
+
close_tags(0)
|
38
|
+
@processed
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def close_tags(current_indent, options = { :separate_line => true })
|
44
|
+
while(@tag_stack.size > current_indent)
|
45
|
+
@processed << (" " * (@tag_stack.size - 1)) if options[:separate_line] == true
|
46
|
+
@processed << "</#{@tag_stack.pop.to_s}>"
|
47
|
+
@processed << "\n" if options[:separate_line] == true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'haml2erb/tokens'
|
2
|
+
|
3
|
+
module Haml2Erb
|
4
|
+
class HamlLexer
|
5
|
+
|
6
|
+
attr_reader :input
|
7
|
+
|
8
|
+
def load_input(text)
|
9
|
+
@input = text
|
10
|
+
end
|
11
|
+
|
12
|
+
def peek(klass)
|
13
|
+
#puts "peek #{klass} #{@input}"
|
14
|
+
klass.match(@input)
|
15
|
+
end
|
16
|
+
|
17
|
+
def pop(klass)
|
18
|
+
#puts "pop #{klass} #{@input}"
|
19
|
+
token = klass.match(@input)
|
20
|
+
@input.gsub!(/^#{Regexp.escape(token.matched)}/, '') # removed matched portion from the string
|
21
|
+
token
|
22
|
+
end
|
23
|
+
|
24
|
+
def end_input?
|
25
|
+
@input.strip.empty? ? true : false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Haml2Erb
|
2
|
+
module Mixins
|
3
|
+
module CoMerging
|
4
|
+
def comerge
|
5
|
+
# NOT IMPLEMENTED YET
|
6
|
+
fail "comerge command not implemented yet"
|
7
|
+
end
|
8
|
+
|
9
|
+
# inclusive merge that combines results of two hashes when merging
|
10
|
+
def comerge! hash_b
|
11
|
+
hash_a = self
|
12
|
+
hash_b.respond_to?(:each_pair) && hash_b.each_pair do |k,v|
|
13
|
+
hash_a[k] = hash_a[k] ?
|
14
|
+
(hash_a[k].respond_to?(:push) ?
|
15
|
+
hash_a[k].push(v) :
|
16
|
+
[ hash_a[k], v ]) :
|
17
|
+
v
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'haml2erb/lexer'
|
2
|
+
require 'haml2erb/tokens'
|
3
|
+
require 'haml2erb/mixins/comerging'
|
4
|
+
require 'mixology'
|
5
|
+
|
6
|
+
module Haml2Erb
|
7
|
+
class HamlParser
|
8
|
+
|
9
|
+
ParsingError = Class.new(StandardError)
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@lexer = Haml2Erb::HamlLexer.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(unprocessed, writer)
|
16
|
+
@line_number = 0
|
17
|
+
# process incoming text one line at a time
|
18
|
+
unprocessed.each_line do |line|
|
19
|
+
@line_number += 1
|
20
|
+
options = { }.mixin Haml2Erb::Mixins::CoMerging
|
21
|
+
@lexer.load_input(line)
|
22
|
+
|
23
|
+
# handle indent
|
24
|
+
if(@lexer.peek(Haml2Erb::Tokens::Indent))
|
25
|
+
options.merge!(@lexer.pop(Haml2Erb::Tokens::Indent).options)
|
26
|
+
end
|
27
|
+
options.merge!(:indent => 0) unless options[:indent]
|
28
|
+
|
29
|
+
# handle initial tag attributes
|
30
|
+
while(@lexer.peek(Haml2Erb::Tokens::InitialAttribute))
|
31
|
+
options.comerge!(@lexer.pop(Haml2Erb::Tokens::InitialAttribute).options)
|
32
|
+
end
|
33
|
+
options[:element_type] = :div if((options[:element_id] || options[:element_class]) && !options[:element_type])
|
34
|
+
|
35
|
+
# handle interior element attributes
|
36
|
+
if(@lexer.peek(Haml2Erb::Tokens::AttributesStart))
|
37
|
+
@lexer.pop(Haml2Erb::Tokens::AttributesStart)
|
38
|
+
options[:element_attributes] = { }
|
39
|
+
while(!@lexer.peek(Haml2Erb::Tokens::AttributesEnd))
|
40
|
+
if(@lexer.peek(Haml2Erb::Tokens::InnerAttributeQuoted))
|
41
|
+
options[:element_attributes].merge!(@lexer.pop(Haml2Erb::Tokens::InnerAttributeQuoted).options[:element_attribute])
|
42
|
+
elsif(@lexer.peek(Haml2Erb::Tokens::InnerAttributeRuby))
|
43
|
+
options[:element_attributes].merge!(@lexer.pop(Haml2Erb::Tokens::InnerAttributeRuby).options[:element_attribute])
|
44
|
+
elsif(@lexer.peek(Haml2Erb::Tokens::InnerAttributeNumber))
|
45
|
+
options[:element_attributes].merge!(@lexer.pop(Haml2Erb::Tokens::InnerAttributeNumber).options[:element_attribute])
|
46
|
+
else
|
47
|
+
raise 'unrecognized inner attribute'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
@lexer.pop(Haml2Erb::Tokens::AttributesEnd)
|
51
|
+
end
|
52
|
+
|
53
|
+
# handle element contents
|
54
|
+
if(@lexer.peek(Haml2Erb::Tokens::ContentsStart))
|
55
|
+
options.merge!(@lexer.pop(Haml2Erb::Tokens::ContentsStart).options)
|
56
|
+
end
|
57
|
+
options[:content_type] = :text unless options[:content_type]
|
58
|
+
|
59
|
+
if(@lexer.peek(Haml2Erb::Tokens::Contents))
|
60
|
+
options.merge!(:contents => @lexer.pop(Haml2Erb::Tokens::Contents).matched)
|
61
|
+
end
|
62
|
+
|
63
|
+
writer << options
|
64
|
+
end
|
65
|
+
rescue => error
|
66
|
+
raise ParsingError, "Haml2Erb had trouble parsing line #{@line_number} with input '#{@lexer.input}' remaining: #{error.to_s}", error.backtrace
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Haml2Erb
|
2
|
+
module Tokens
|
3
|
+
|
4
|
+
class Token
|
5
|
+
attr_reader :options, :matched
|
6
|
+
|
7
|
+
def initialize(matched, options = {})
|
8
|
+
@matched = matched
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.match(text)
|
13
|
+
match_data = @regex.match(text)
|
14
|
+
match_data ? self.new(match_data.to_s) : nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Indent < Token
|
19
|
+
@regex = /^(\s\s)+/
|
20
|
+
|
21
|
+
def self.match(text)
|
22
|
+
match_data = @regex.match(text)
|
23
|
+
match_data ? self.new(match_data.to_s, :indent => (match_data.to_s.size / 2)) : nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class AttributesStart < Token
|
28
|
+
@regex = /^\{\s*/
|
29
|
+
end
|
30
|
+
|
31
|
+
class AttributesEnd < Token
|
32
|
+
@regex = /^\s*\}/
|
33
|
+
end
|
34
|
+
|
35
|
+
class ContentsStart < Token
|
36
|
+
@regex = /^((\s+)|(==\s*)|(=\s*))/
|
37
|
+
|
38
|
+
def self.match(text)
|
39
|
+
match_data = @regex.match(text)
|
40
|
+
if match_data
|
41
|
+
@return_token = case match_data[1][0,1]
|
42
|
+
when ' ' then self.new(match_data.to_s, :content_type => :text)
|
43
|
+
when '='
|
44
|
+
match_data[1][1,1] == '=' ? self.new(match_data.to_s, :content_type => :mixed) : self.new(match_data.to_s, :content_type => :ruby)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@return_token = nil
|
48
|
+
end
|
49
|
+
@return_token
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Contents < Token
|
54
|
+
@regex = /^.+$/
|
55
|
+
|
56
|
+
def self.match(text)
|
57
|
+
text.gsub!(/\\\-/, "-")
|
58
|
+
match_data = @regex.match(text)
|
59
|
+
match_data ? self.new(match_data.to_s) : nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class InitialAttribute < Token
|
64
|
+
@regex = /^([%#\.])(\w+)/
|
65
|
+
|
66
|
+
def self.match(text)
|
67
|
+
match_data = @regex.match(text)
|
68
|
+
if match_data
|
69
|
+
@return_token = case match_data[1]
|
70
|
+
when '%' then self.new(match_data.to_s, :element_type => match_data[2])
|
71
|
+
when '#' then self.new(match_data.to_s, :element_id => match_data[2])
|
72
|
+
when '.' then self.new(match_data.to_s, :element_class => match_data[2])
|
73
|
+
end
|
74
|
+
else
|
75
|
+
@return_token = nil
|
76
|
+
end
|
77
|
+
@return_token
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class InnerAttributeQuoted < Token
|
82
|
+
@regex = /^,?\s*:?['"]?([\w-]+)['"]?(:|(\s*=>))\s*['"]([^'"]+)['"]\s*/
|
83
|
+
def self.match(text)
|
84
|
+
match_data = @regex.match(text)
|
85
|
+
if(match_data)
|
86
|
+
value = match_data[4].gsub(/#\{([^\}]+?)\}/, '<%= \1 %>') # replace #{ value } with <%= value %>
|
87
|
+
self.new(match_data.to_s, :element_attribute => { match_data[1] => value })
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class InnerAttributeRuby < Token
|
95
|
+
@regex = /^,?\s*:?['"]?([\w-]+)['"]?(:|(\s*=>))\s*([^'"\s][^,\s]+)\s*/
|
96
|
+
def self.match(text)
|
97
|
+
match_data = @regex.match(text)
|
98
|
+
match_data ? self.new(match_data.to_s, :element_attribute => { match_data[1] => "<%= #{match_data[4]} %>" }) : nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class InnerAttributeNumber < Token
|
103
|
+
@regex = /^,?\s*:?['"]?([\w-]+)['"]?(:|(\s*=>))\s*(\d+)\s*/
|
104
|
+
def self.match(text)
|
105
|
+
match_data = @regex.match(text)
|
106
|
+
match_data ? self.new(match_data.to_s, :element_attribute => { match_data[1] => match_data[4] }) : nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/tasks/haml2erb.rake
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
desc "This task will take the supplied .haml input file and convert it to .erb. It will remove the original .haml file and create a new .erb file"
|
2
|
+
task :haml2erb, :filename, :needs => :environment do |t, args|
|
3
|
+
output_file = args[:filename].gsub(/\.haml/, '.erb')
|
4
|
+
p output_file
|
5
|
+
File.open(output_file, 'w') { |f| f.write Haml2Erb.convert(File.open(args[:filename], 'r').read) }
|
6
|
+
FileUtils.rm_r args[:filename]
|
7
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: haml2erb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Louis Sivillo
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-04-08 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: mixology
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Haml to ERB Converter
|
34
|
+
email:
|
35
|
+
- louis.sivillo@gmail.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files: []
|
41
|
+
|
42
|
+
files:
|
43
|
+
- README.rdoc
|
44
|
+
- haml2erb.gemspec
|
45
|
+
- lib/haml2erb.rb
|
46
|
+
- lib/haml2erb/erb_writer.rb
|
47
|
+
- lib/haml2erb/lexer.rb
|
48
|
+
- lib/haml2erb/mixins/comerging.rb
|
49
|
+
- lib/haml2erb/parser.rb
|
50
|
+
- lib/haml2erb/railtie.rb
|
51
|
+
- lib/haml2erb/tokens.rb
|
52
|
+
- lib/haml2erb/version.rb
|
53
|
+
- tasks/haml2erb.rake
|
54
|
+
has_rdoc: true
|
55
|
+
homepage:
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
segments:
|
77
|
+
- 1
|
78
|
+
- 3
|
79
|
+
- 6
|
80
|
+
version: 1.3.6
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.7
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Haml to ERB Converter
|
88
|
+
test_files: []
|
89
|
+
|