ezml 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +149 -0
- data/LICENSE.txt +21 -0
- data/README.md +140 -0
- data/Rakefile +6 -0
- data/bin/ezml +9 -0
- data/examples/helloworld.ezml +44 -0
- data/examples/helloworld.html +61 -0
- data/examples/template.ezml +69 -0
- data/examples/template.html +102 -0
- data/ezml.gemspec +40 -0
- data/lib/ezml.rb +8 -0
- data/lib/ezml/attribute_builder.rb +141 -0
- data/lib/ezml/attribute_compiler.rb +172 -0
- data/lib/ezml/attribute_parser.rb +133 -0
- data/lib/ezml/buffer.rb +166 -0
- data/lib/ezml/compiler.rb +322 -0
- data/lib/ezml/engine.rb +107 -0
- data/lib/ezml/error.rb +59 -0
- data/lib/ezml/escapable.rb +46 -0
- data/lib/ezml/exec.rb +348 -0
- data/lib/ezml/filters.rb +249 -0
- data/lib/ezml/generator.rb +38 -0
- data/lib/ezml/helpers.rb +299 -0
- data/lib/ezml/options.rb +142 -0
- data/lib/ezml/parser.rb +826 -0
- data/lib/ezml/template_engine.rb +106 -0
- data/lib/ezml/temple_line_counter.rb +26 -0
- data/lib/ezml/util.rb +156 -0
- data/lib/ezml/version.rb +3 -0
- metadata +199 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title Hello, World!
|
5
|
+
%link{:rel => "stylesheet", :href => "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css"}
|
6
|
+
%body.content.container
|
7
|
+
%h1.title.is-1 I am a big header
|
8
|
+
%h2.subtitle.is-2 Slightly smaller header
|
9
|
+
%h3.title.is-3 An even smaller header
|
10
|
+
%span
|
11
|
+
I am inside a span element
|
12
|
+
%div
|
13
|
+
A div element
|
14
|
+
%p
|
15
|
+
A paragraph of text
|
16
|
+
%ul
|
17
|
+
%li First unordered item
|
18
|
+
%li Second unordered item
|
19
|
+
%table.table
|
20
|
+
%tbody
|
21
|
+
%tr
|
22
|
+
%td I am Cell 1
|
23
|
+
%td I am Cell 2
|
24
|
+
%div#example
|
25
|
+
I'm a div with an ID!
|
26
|
+
#example2
|
27
|
+
If you don't specify, I'm automatically a div!, so easy speed yes ok
|
28
|
+
%div.box
|
29
|
+
I'm a div with a class called box yey
|
30
|
+
%div.box.blue
|
31
|
+
Hey now I have two classes!
|
32
|
+
#collection
|
33
|
+
.item
|
34
|
+
.description
|
35
|
+
I think it's cool you don't need to specify div, saves time yes
|
36
|
+
/ this is also a super cool comment
|
37
|
+
/
|
38
|
+
comments can also wrap multiple lines with tabs
|
39
|
+
like this, im still a comment yay
|
40
|
+
-# these types of comments dont go to html
|
41
|
+
%br/
|
42
|
+
%strong
|
43
|
+
-# you can insert ruby code as well!
|
44
|
+
= ['Storm', 'is', 'a', 'god.'].join " "
|
@@ -0,0 +1,61 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Hello, World!</title>
|
5
|
+
<link href='https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css' rel='stylesheet'>
|
6
|
+
</head>
|
7
|
+
<body class='content container'>
|
8
|
+
<h1 class='title is-1'>I am a big header</h1>
|
9
|
+
<h2 class='subtitle is-2'>Slightly smaller header</h2>
|
10
|
+
<h3 class='title is-3'>An even smaller header</h3>
|
11
|
+
<span>
|
12
|
+
I am inside a span element
|
13
|
+
</span>
|
14
|
+
<div>
|
15
|
+
A div element
|
16
|
+
</div>
|
17
|
+
<p>
|
18
|
+
A paragraph of text
|
19
|
+
</p>
|
20
|
+
<ul>
|
21
|
+
<li>First unordered item</li>
|
22
|
+
<li>Second unordered item</li>
|
23
|
+
</ul>
|
24
|
+
<table class='table'>
|
25
|
+
<tbody>
|
26
|
+
<tr>
|
27
|
+
<td>I am Cell 1</td>
|
28
|
+
<td>I am Cell 2</td>
|
29
|
+
</tr>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
<div id='example'>
|
33
|
+
I'm a div with an ID!
|
34
|
+
</div>
|
35
|
+
<div id='example2'>
|
36
|
+
If you don't specify, I'm automatically a div!, so easy speed yes ok
|
37
|
+
</div>
|
38
|
+
<div class='box'>
|
39
|
+
I'm a div with a class called box yey
|
40
|
+
</div>
|
41
|
+
<div class='box blue'>
|
42
|
+
Hey now I have two classes!
|
43
|
+
</div>
|
44
|
+
<div id='collection'>
|
45
|
+
<div class='item'>
|
46
|
+
<div class='description'>
|
47
|
+
I think it's cool you don't need to specify div, saves time yes
|
48
|
+
</div>
|
49
|
+
</div>
|
50
|
+
</div>
|
51
|
+
<!-- this is also a super cool comment -->
|
52
|
+
<!--
|
53
|
+
comments can also wrap multiple lines with tabs
|
54
|
+
like this, im still a comment yay
|
55
|
+
-->
|
56
|
+
<br>
|
57
|
+
<strong>
|
58
|
+
Storm is a god.
|
59
|
+
</strong>
|
60
|
+
</body>
|
61
|
+
</html>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
!!! 5
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title AppFlow WebsiteTemplate
|
5
|
+
%meta{:charset => "utf-8"}
|
6
|
+
%meta{:name => "viewport", :content => "width=device-width, initial-scale=1, viewport-fit=cover"}
|
7
|
+
%meta{:name => "description", :content=>"Template for AppFlow Client Websites"}
|
8
|
+
%link{:rel => "stylesheet", :href => "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css"}
|
9
|
+
%body
|
10
|
+
%section.hero.is-medium.is-primary
|
11
|
+
.hero-body
|
12
|
+
.container
|
13
|
+
.columns
|
14
|
+
.column.is-8-desktop.is-offset-2-desktop
|
15
|
+
%h1.title.is-2.is-spaced AppFlow Template
|
16
|
+
%h2.subtitle.is-4
|
17
|
+
this is our
|
18
|
+
%strong AppFlow
|
19
|
+
Base Template!
|
20
|
+
%br/
|
21
|
+
It Includes everything we need to
|
22
|
+
%strong start building our
|
23
|
+
next website
|
24
|
+
%section.section
|
25
|
+
.container
|
26
|
+
.columns
|
27
|
+
.column.is-8-desktop.is-offset-2-desktop
|
28
|
+
.content
|
29
|
+
%h3 What's included
|
30
|
+
%p
|
31
|
+
The included
|
32
|
+
%code code
|
33
|
+
files included are:
|
34
|
+
%ul
|
35
|
+
%li
|
36
|
+
%code ./index.html
|
37
|
+
\ - the base file for our websites
|
38
|
+
%li
|
39
|
+
%code ./css/style.css
|
40
|
+
\ - the base file used for styling
|
41
|
+
%li
|
42
|
+
%code ./js/main.js
|
43
|
+
\ - the base file used for adding javascript
|
44
|
+
%p Apart from the code files, the following framework is included:
|
45
|
+
%ul
|
46
|
+
%li
|
47
|
+
%a{:href=>"https://bulma.io/documentation/"} Bulma
|
48
|
+
%h3 Get Started
|
49
|
+
%p We're ready to create our own designs using this Template. Just edit or duplicate this page, or simply create a new one!
|
50
|
+
%br/
|
51
|
+
.content
|
52
|
+
%p For ease of development, I've chosen to go with the Bulma framework.
|
53
|
+
%p This is a CSS only framework which includes components to help us develop websites quickly with ease.
|
54
|
+
%p If you want to learn more, follow these links:
|
55
|
+
.field.is-grouped
|
56
|
+
%p.control
|
57
|
+
%a.button.is-medium.is-primary{:href=>"http://bulma.io"}
|
58
|
+
%strong.has-text-weight-semibold Bulma Homepage
|
59
|
+
%p.control
|
60
|
+
%a.button.is-medium.is-link{:href=>"http://bulma.io/documentation/overview/start/"}
|
61
|
+
%strong.has-text-weight-semibold Documentation
|
62
|
+
%footer.footer.has-text-centered
|
63
|
+
.container
|
64
|
+
.columns
|
65
|
+
.column.is-8-desktop.is-offset-2-desktop
|
66
|
+
%p
|
67
|
+
%strong This is some footer text
|
68
|
+
%p
|
69
|
+
%small Mad with love by AppFlow.
|
@@ -0,0 +1,102 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>AppFlow WebsiteTemplate</title>
|
5
|
+
<meta charset='utf-8'>
|
6
|
+
<meta content='width=device-width, initial-scale=1, viewport-fit=cover' name='viewport'>
|
7
|
+
<meta content='Template for AppFlow Client Websites' name='description'>
|
8
|
+
<link href='https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css' rel='stylesheet'>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<section class='hero is-medium is-primary'>
|
12
|
+
<div class='hero-body'>
|
13
|
+
<div class='container'>
|
14
|
+
<div class='columns'>
|
15
|
+
<div class='column is-8-desktop is-offset-2-desktop'>
|
16
|
+
<h1 class='title is-2 is-spaced'>AppFlow Template</h1>
|
17
|
+
<h2 class='subtitle is-4'>
|
18
|
+
this is our
|
19
|
+
<strong>AppFlow</strong>
|
20
|
+
Base Template!
|
21
|
+
<br>
|
22
|
+
It Includes everything we need to
|
23
|
+
<strong>start building our</strong>
|
24
|
+
next website
|
25
|
+
</h2>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</section>
|
31
|
+
<section class='section'>
|
32
|
+
<div class='container'>
|
33
|
+
<div class='columns'>
|
34
|
+
<div class='column is-8-desktop is-offset-2-desktop'>
|
35
|
+
<div class='content'>
|
36
|
+
<h3>What's included</h3>
|
37
|
+
<p>
|
38
|
+
The included
|
39
|
+
<code>code</code>
|
40
|
+
files included are:
|
41
|
+
</p>
|
42
|
+
<ul>
|
43
|
+
<li>
|
44
|
+
<code>./index.html</code>
|
45
|
+
- the base file for our websites
|
46
|
+
</li>
|
47
|
+
<li>
|
48
|
+
<code>./css/style.css</code>
|
49
|
+
- the base file used for styling
|
50
|
+
</li>
|
51
|
+
<li>
|
52
|
+
<code>./js/main.js</code>
|
53
|
+
- the base file used for adding javascript
|
54
|
+
</li>
|
55
|
+
</ul>
|
56
|
+
<p>Apart from the code files, the following framework is included:</p>
|
57
|
+
<ul>
|
58
|
+
<li>
|
59
|
+
<a href='https://bulma.io/documentation/'>Bulma</a>
|
60
|
+
</li>
|
61
|
+
</ul>
|
62
|
+
<h3>Get Started</h3>
|
63
|
+
<p>We're ready to create our own designs using this Template. Just edit or duplicate this page, or simply create a new one!</p>
|
64
|
+
<br>
|
65
|
+
</div>
|
66
|
+
<div class='content'>
|
67
|
+
<p>For ease of development, I've chosen to go with the Bulma framework.</p>
|
68
|
+
<p>This is a CSS only framework which includes components to help us develop websites quickly with ease.</p>
|
69
|
+
<p>If you want to learn more, follow these links:</p>
|
70
|
+
</div>
|
71
|
+
<div class='field is-grouped'>
|
72
|
+
<p class='control'>
|
73
|
+
<a class='button is-medium is-primary' href='http://bulma.io'>
|
74
|
+
<strong class='has-text-weight-semibold'>Bulma Homepage</strong>
|
75
|
+
</a>
|
76
|
+
</p>
|
77
|
+
<p class='control'>
|
78
|
+
<a class='button is-medium is-link' href='http://bulma.io/documentation/overview/start/'>
|
79
|
+
<strong class='has-text-weight-semibold'>Documentation</strong>
|
80
|
+
</a>
|
81
|
+
</p>
|
82
|
+
</div>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
</section>
|
87
|
+
<footer class='footer has-text-centered'>
|
88
|
+
<div class='container'>
|
89
|
+
<div class='columns'>
|
90
|
+
<div class='column is-8-desktop is-offset-2-desktop'>
|
91
|
+
<p>
|
92
|
+
<strong>This is some footer text</strong>
|
93
|
+
</p>
|
94
|
+
<p>
|
95
|
+
<small>Mad with love by AppFlow.</small>
|
96
|
+
</p>
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
</footer>
|
101
|
+
</body>
|
102
|
+
</html>
|
data/ezml.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "ezml/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ezml"
|
8
|
+
spec.version = EZML::VERSION
|
9
|
+
spec.authors = ["Storm Burpee", "Jared Bowers"]
|
10
|
+
spec.email = ["storm@appflow.com.au", "jared@appflow.com.au"]
|
11
|
+
|
12
|
+
spec.summary = "An elegant, fast HTML templating engine."
|
13
|
+
spec.description = <<-END
|
14
|
+
EZML (EZ Markup Language) is an elegant and fast templating engine.
|
15
|
+
EZML is a layer built on top of HTML to dramatically reduce the time
|
16
|
+
taken to develop HTML projects. EZML Was developed as a internal tool
|
17
|
+
for AppFlow to develop their websites. Once we saw how much time was
|
18
|
+
reduced, we decided to provide this to the public.
|
19
|
+
END
|
20
|
+
|
21
|
+
spec.homepage = "https://ezml.appflow.com.au"
|
22
|
+
spec.license = "MIT"
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
f.match(%r{^(test|spec|features)/})
|
26
|
+
end
|
27
|
+
spec.executables = ['ezml']
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
|
34
|
+
spec.add_dependency 'temple', '>= 0.8.0'
|
35
|
+
spec.add_dependency 'tilt'
|
36
|
+
|
37
|
+
spec.add_development_dependency 'rails', '>= 4.0.0'
|
38
|
+
spec.add_development_dependency 'rbench'
|
39
|
+
spec.add_development_dependency 'nokogiri'
|
40
|
+
end
|
data/lib/ezml.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
module EZML
|
2
|
+
|
3
|
+
module AttributeBuilder
|
4
|
+
|
5
|
+
INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def build_attributes(is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, attributes = {})
|
10
|
+
# @TODO this is an absolutely ridiculous amount of arguments. At least
|
11
|
+
# some of this needs to be moved into an instance method.
|
12
|
+
join_char = hyphenate_data_attrs ? '-' : '_'
|
13
|
+
|
14
|
+
attributes.each do |key, value|
|
15
|
+
if value.is_a?(Hash)
|
16
|
+
data_attributes = attributes.delete(key)
|
17
|
+
data_attributes = flatten_data_attributes(data_attributes, '', join_char)
|
18
|
+
data_attributes = build_data_keys(data_attributes, hyphenate_data_attrs, key)
|
19
|
+
verify_attribute_names!(data_attributes.keys)
|
20
|
+
attributes = data_attributes.merge(attributes)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
result = attributes.collect do |attr, value|
|
25
|
+
next if value.nil?
|
26
|
+
|
27
|
+
value = filter_and_join(value, ' ') if attr == 'class'
|
28
|
+
value = filter_and_join(value, '_') if attr == 'id'
|
29
|
+
|
30
|
+
if value == true
|
31
|
+
next " #{attr}" if is_html
|
32
|
+
next " #{attr}=#{attr_wrapper}#{attr}#{attr_wrapper}"
|
33
|
+
elsif value == false
|
34
|
+
next
|
35
|
+
end
|
36
|
+
|
37
|
+
value =
|
38
|
+
if escape_attrs == :once
|
39
|
+
EZML::Helpers.escape_once(value.to_s)
|
40
|
+
elsif escape_attrs
|
41
|
+
EZML::Helpers.html_escape(value.to_s)
|
42
|
+
else
|
43
|
+
value.to_s
|
44
|
+
end
|
45
|
+
" #{attr}=#{attr_wrapper}#{value}#{attr_wrapper}"
|
46
|
+
end
|
47
|
+
result.compact!
|
48
|
+
result.sort!
|
49
|
+
result.join
|
50
|
+
end
|
51
|
+
|
52
|
+
def filter_and_join(value, separator)
|
53
|
+
return '' if (value.respond_to?(:empty?) && value.empty?)
|
54
|
+
|
55
|
+
if value.is_a?(Array)
|
56
|
+
value = value.flatten
|
57
|
+
value.map! {|item| item ? item.to_s : nil}
|
58
|
+
value.compact!
|
59
|
+
value = value.join(separator)
|
60
|
+
else
|
61
|
+
value = value ? value.to_s : nil
|
62
|
+
end
|
63
|
+
!value.nil? && !value.empty? && value
|
64
|
+
end
|
65
|
+
|
66
|
+
def merge_attributes!(to, from)
|
67
|
+
from.keys.each do |key|
|
68
|
+
to[key] = merge_value(key, to[key], from[key])
|
69
|
+
end
|
70
|
+
to
|
71
|
+
end
|
72
|
+
|
73
|
+
def merge_values(key, *values)
|
74
|
+
values.inject(nil) do |to, from|
|
75
|
+
merge_value(key, to, from)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def verify_attribute_names!(attribute_names)
|
80
|
+
attribute_names.each do |attribute_name|
|
81
|
+
if attribute_name =~ INVALID_ATTRIBUTE_NAME_REGEX
|
82
|
+
raise InvalidAttributeNameError.new("Invalid attribute name '#{attribute_name}' was rendered")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def merge_value(key, to, from)
|
90
|
+
if from.kind_of?(Hash) || to.kind_of?(Hash)
|
91
|
+
from = { nil => from } if !from.is_a?(Hash)
|
92
|
+
to = { nil => to } if !to.is_a?(Hash)
|
93
|
+
to.merge(from)
|
94
|
+
elsif key == 'id'
|
95
|
+
merged_id = filter_and_join(from, '_')
|
96
|
+
if to && merged_id
|
97
|
+
merged_id = "#{to}_#{merged_id}"
|
98
|
+
elsif to || merged_id
|
99
|
+
merged_id ||= to
|
100
|
+
end
|
101
|
+
merged_id
|
102
|
+
elsif key == 'class'
|
103
|
+
merged_class = filter_and_join(from, ' ')
|
104
|
+
if to && merged_class
|
105
|
+
merged_class = (merged_class.split(' ') | to.split(' ')).sort.join(' ')
|
106
|
+
elsif to || merged_class
|
107
|
+
merged_class ||= to
|
108
|
+
end
|
109
|
+
merged_class
|
110
|
+
else
|
111
|
+
from
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def build_data_keys(data_hash, hyphenate, attr_name="data")
|
116
|
+
Hash[data_hash.map do |name, value|
|
117
|
+
if name == nil
|
118
|
+
[attr_name, value]
|
119
|
+
elsif hyphenate
|
120
|
+
["#{attr_name}-#{name.to_s.tr('_', '-')}", value]
|
121
|
+
else
|
122
|
+
["#{attr_name}-#{name}", value]
|
123
|
+
end
|
124
|
+
end]
|
125
|
+
end
|
126
|
+
|
127
|
+
def flatten_data_attributes(data, key, join_char, seen = [])
|
128
|
+
return {key => data} unless data.is_a?(Hash)
|
129
|
+
|
130
|
+
return {key => nil} if seen.include? data.object_id
|
131
|
+
seen << data.object_id
|
132
|
+
|
133
|
+
data.sort {|x, y| x[0].to_s <=> y[0].to_s}.inject({}) do |hash, (k, v)|
|
134
|
+
joined = key == '' ? k : [key, k].join(join_char)
|
135
|
+
hash.merge! flatten_data_attributes(v, joined, join_char, seen)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|