ezml 0.1.1
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 +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
|