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,106 @@
|
|
1
|
+
require 'temple'
|
2
|
+
require_relative 'escapable'
|
3
|
+
require_relative 'generator'
|
4
|
+
|
5
|
+
module EZML
|
6
|
+
class TemplateEngine < Temple::Engine
|
7
|
+
define_options(
|
8
|
+
attr_wrapper: "'",
|
9
|
+
autoclose: %w(area base basefont br col command embed frame
|
10
|
+
hr img input isindex keygen link menuitem meta
|
11
|
+
param source track wbr),
|
12
|
+
encoding: nil,
|
13
|
+
escape_attrs: true,
|
14
|
+
escape_html: false,
|
15
|
+
filename: '(ezml)',
|
16
|
+
format: :html5,
|
17
|
+
hyphenate_data_attrs: true,
|
18
|
+
line: 1,
|
19
|
+
mime_type: 'text/html',
|
20
|
+
preserve: %w(textarea pre code),
|
21
|
+
remove_whitespace: false,
|
22
|
+
suppress_eval: false,
|
23
|
+
cdata: false,
|
24
|
+
parser_class: ::EZML::Parser,
|
25
|
+
compiler_class: ::EZML::Compiler,
|
26
|
+
trace: false,
|
27
|
+
filters: {},
|
28
|
+
)
|
29
|
+
|
30
|
+
use :Parser, -> { options[:parser_class] }
|
31
|
+
use :Compiler, -> { options[:compiler_class] }
|
32
|
+
use Escapable
|
33
|
+
filter :ControlFlow
|
34
|
+
filter :MultiFlattener
|
35
|
+
filter :StaticMerger
|
36
|
+
use Generator
|
37
|
+
|
38
|
+
def compile(template)
|
39
|
+
initialize_encoding(template, options[:encoding])
|
40
|
+
@precompiled = call(template)
|
41
|
+
end
|
42
|
+
|
43
|
+
def precompiled
|
44
|
+
encoding = Encoding.find(@encoding || '')
|
45
|
+
return @precompiled.dup.force_encoding(encoding) if encoding == Encoding::ASCII_8BIT
|
46
|
+
return @precompiled.encode(encoding)
|
47
|
+
end
|
48
|
+
|
49
|
+
def precompiled_with_return_value
|
50
|
+
"#{precompiled};#{precompiled_method_return_value}".dup
|
51
|
+
end
|
52
|
+
|
53
|
+
def precompiled_with_ambles(local_names, after_preamble: '')
|
54
|
+
preamble = <<END.tr("\n", ';')
|
55
|
+
begin
|
56
|
+
extend EZML::Helpers
|
57
|
+
_ezmlout = @ezml_buffer = EZML::Buffer.new(ezml_buffer, #{Options.new(options).for_buffer.inspect})
|
58
|
+
_erbout = _ezmlout.buffer
|
59
|
+
#{after_preamble}
|
60
|
+
END
|
61
|
+
postamble = <<END.tr("\n", ';')
|
62
|
+
#{precompiled_method_return_value}
|
63
|
+
ensure
|
64
|
+
@ezml_buffer = @ezml_buffer.upper if @ezml_buffer
|
65
|
+
end
|
66
|
+
END
|
67
|
+
"#{preamble}#{locals_code(local_names)}#{precompiled}#{postamble}".dup
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def initialize_encoding(template, given_value)
|
73
|
+
if given_value
|
74
|
+
@encoding = given_value
|
75
|
+
else
|
76
|
+
@encoding = Encoding.default_internal || template.encoding
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def precompiled_method_return_value
|
81
|
+
"_erbout"
|
82
|
+
end
|
83
|
+
|
84
|
+
def locals_code(names)
|
85
|
+
names = names.keys if Hash === names
|
86
|
+
|
87
|
+
names.map do |name|
|
88
|
+
# Can't use || because someone might explicitly pass in false with a symbol
|
89
|
+
sym_local = "_ezml_locals[#{inspect_obj(name.to_sym)}]"
|
90
|
+
str_local = "_ezml_locals[#{inspect_obj(name.to_s)}]"
|
91
|
+
"#{name} = #{sym_local}.nil? ? #{str_local} : #{sym_local};"
|
92
|
+
end.join
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect_obj(obj)
|
96
|
+
case obj
|
97
|
+
when String
|
98
|
+
%Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.inspect[1...-1]}}"!
|
99
|
+
when Symbol
|
100
|
+
":#{inspect_obj(obj.to_s)}"
|
101
|
+
else
|
102
|
+
obj.inspect
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module EZML
|
2
|
+
module TempleLineCounter
|
3
|
+
class UnexpectedExpression < StandardError; end
|
4
|
+
|
5
|
+
def self.count_lines(exp)
|
6
|
+
type, *args = exp
|
7
|
+
case type
|
8
|
+
when :multi
|
9
|
+
args.map { |a| count_lines(a) }.reduce(:+) || 0
|
10
|
+
when :dynamic, :code
|
11
|
+
args.first.count("\n")
|
12
|
+
when :static
|
13
|
+
0 # It has not real newline "\n" but escaped "\\n".
|
14
|
+
when :case
|
15
|
+
arg, *cases = args
|
16
|
+
arg.count("\n") + cases.map do |cond, e|
|
17
|
+
(cond == :else ? 0 : cond.count("\n")) + count_lines(e)
|
18
|
+
end.reduce(:+)
|
19
|
+
when :escape
|
20
|
+
count_lines(args[1])
|
21
|
+
else
|
22
|
+
raise UnexpectedExpression.new("[EZML BUG] Unexpected Temple expression '#{type}' is given!")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/ezml/util.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'stringio'
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module EZML
|
6
|
+
module Util
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def silence_warnings
|
10
|
+
the_real_stderr, $stderr = $stderr, StringIO.new
|
11
|
+
yield
|
12
|
+
ensure
|
13
|
+
$stderr = the_real_stderr
|
14
|
+
end
|
15
|
+
|
16
|
+
def html_safe(text)
|
17
|
+
return unless text
|
18
|
+
text.html_safe
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_encoding(str)
|
22
|
+
if str.valid_encoding?
|
23
|
+
# Get rid of the Unicode BOM if possible
|
24
|
+
# Shortcut for UTF-8 which might be the majority case
|
25
|
+
if str.encoding == Encoding::UTF_8
|
26
|
+
return str.gsub(/\A\uFEFF/, '')
|
27
|
+
elsif str.encoding.name =~ /^UTF-(16|32)(BE|LE)?$/
|
28
|
+
return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding)), '')
|
29
|
+
else
|
30
|
+
return str
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
encoding = str.encoding
|
35
|
+
newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding(Encoding::ASCII_8BIT))
|
36
|
+
str.force_encoding(Encoding::ASCII_8BIT).split(newlines).each_with_index do |line, i|
|
37
|
+
begin
|
38
|
+
line.encode(encoding)
|
39
|
+
rescue Encoding::UndefinedConversionError => e
|
40
|
+
yield <<MSG.rstrip, i + 1
|
41
|
+
Invalid #{encoding.name} character #{e.error_char.dump}
|
42
|
+
MSG
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return str
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_ezml_encoding(str, &block)
|
49
|
+
str = str.dup if str.frozen?
|
50
|
+
|
51
|
+
bom, encoding = parse_ezml_magic_comment(str)
|
52
|
+
if encoding; str.force_encoding(encoding)
|
53
|
+
elsif bom; str.force_encoding(Encoding::UTF_8)
|
54
|
+
end
|
55
|
+
|
56
|
+
return check_encoding(str, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect_obj(obj)
|
60
|
+
case obj
|
61
|
+
when String
|
62
|
+
%Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.dump[1...-1]}}"!
|
63
|
+
when Symbol
|
64
|
+
":#{inspect_obj(obj.to_s)}"
|
65
|
+
else
|
66
|
+
obj.inspect
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_interpolation(str)
|
71
|
+
scan = StringScanner.new(str)
|
72
|
+
yield scan while scan.scan(/(.*?)(\\*)#([\{@$])/)
|
73
|
+
scan.rest
|
74
|
+
end
|
75
|
+
|
76
|
+
def balance(scanner, start, finish, count = 0)
|
77
|
+
str = ''.dup
|
78
|
+
scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
|
79
|
+
regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
|
80
|
+
while scanner.scan(regexp)
|
81
|
+
str << scanner.matched
|
82
|
+
count += 1 if scanner.matched[-1] == start
|
83
|
+
count -= 1 if scanner.matched[-1] == finish
|
84
|
+
return [str.strip, scanner.rest] if count == 0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def human_indentation(indentation)
|
89
|
+
if !indentation.include?(?\t)
|
90
|
+
noun = 'space'
|
91
|
+
elsif !indentation.include?(?\s)
|
92
|
+
noun = 'tab'
|
93
|
+
else
|
94
|
+
return indentation.inspect
|
95
|
+
end
|
96
|
+
|
97
|
+
singular = indentation.length == 1
|
98
|
+
"#{indentation.length} #{noun}#{'s' unless singular}"
|
99
|
+
end
|
100
|
+
|
101
|
+
def contains_interpolation?(str)
|
102
|
+
/#[\{$@]/ === str
|
103
|
+
end
|
104
|
+
|
105
|
+
def unescape_interpolation(str, escape_html = nil)
|
106
|
+
res = ''.dup
|
107
|
+
rest = Haml::Util.handle_interpolation str.dump do |scan|
|
108
|
+
escapes = (scan[2].size - 1) / 2
|
109
|
+
char = scan[3] # '{', '@' or '$'
|
110
|
+
res << scan.matched[0...-3 - escapes]
|
111
|
+
if escapes % 2 == 1
|
112
|
+
res << "\##{char}"
|
113
|
+
else
|
114
|
+
interpolated = if char == '{'
|
115
|
+
balance(scan, ?{, ?}, 1)[0][0...-1]
|
116
|
+
else
|
117
|
+
scan.scan(/\w+/)
|
118
|
+
end
|
119
|
+
content = eval("\"#{interpolated}\"")
|
120
|
+
content.prepend(char) if char == '@' || char == '$'
|
121
|
+
content = "Haml::Helpers.html_escape((#{content}))" if escape_html
|
122
|
+
|
123
|
+
res << "\#{#{content}}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
res + rest
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def parse_ezml_magic_comment(str)
|
132
|
+
scanner = StringScanner.new(str.dup.force_encoding(Encoding::ASCII_8BIT))
|
133
|
+
bom = scanner.scan(/\xEF\xBB\xBF/n)
|
134
|
+
return bom unless scanner.scan(/-\s*#\s*/n)
|
135
|
+
if coding = try_parse_ezml_emacs_magic_comment(scanner)
|
136
|
+
return bom, coding
|
137
|
+
end
|
138
|
+
|
139
|
+
return bom unless scanner.scan(/.*?coding[=:]\s*([\w-]+)/in)
|
140
|
+
return bom, scanner[1]
|
141
|
+
end
|
142
|
+
|
143
|
+
def try_parse_ezml_emacs_magic_comment(scanner)
|
144
|
+
pos = scanner.pos
|
145
|
+
return unless scanner.scan(/.*?-\*-\s*/n)
|
146
|
+
# From Ruby's parse.y
|
147
|
+
return unless scanner.scan(/([^\s'":;]+)\s*:\s*("(?:\\.|[^"])*"|[^"\s;]+?)[\s;]*-\*-/n)
|
148
|
+
name, val = scanner[1], scanner[2]
|
149
|
+
return unless name =~ /(en)?coding/in
|
150
|
+
val = $1 if val =~ /^"(.*)"$/n
|
151
|
+
return val
|
152
|
+
ensure
|
153
|
+
scanner.pos = pos
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
data/lib/ezml/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ezml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Storm Burpee
|
8
|
+
- Jared Bowers
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-07-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.16'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.16'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: temple
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.8.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.8.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: tilt
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rails
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 4.0.0
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 4.0.0
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rbench
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: nokogiri
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: |
|
127
|
+
EZML (EZ Markup Language) is an elegant and fast templating engine.
|
128
|
+
EZML is a layer built on top of HTML to dramatically reduce the time
|
129
|
+
taken to develop HTML projects. EZML Was developed as a internal tool
|
130
|
+
for AppFlow to develop their websites. Once we saw how much time was
|
131
|
+
reduced, we decided to provide this to the public.
|
132
|
+
email:
|
133
|
+
- storm@appflow.com.au
|
134
|
+
- jared@appflow.com.au
|
135
|
+
executables:
|
136
|
+
- ezml
|
137
|
+
extensions: []
|
138
|
+
extra_rdoc_files: []
|
139
|
+
files:
|
140
|
+
- ".DS_Store"
|
141
|
+
- ".gitignore"
|
142
|
+
- ".rspec"
|
143
|
+
- ".travis.yml"
|
144
|
+
- CODE_OF_CONDUCT.md
|
145
|
+
- Gemfile
|
146
|
+
- Gemfile.lock
|
147
|
+
- LICENSE.txt
|
148
|
+
- README.md
|
149
|
+
- Rakefile
|
150
|
+
- bin/ezml
|
151
|
+
- examples/helloworld.ezml
|
152
|
+
- examples/helloworld.html
|
153
|
+
- examples/template.ezml
|
154
|
+
- examples/template.html
|
155
|
+
- ezml.gemspec
|
156
|
+
- lib/ezml.rb
|
157
|
+
- lib/ezml/attribute_builder.rb
|
158
|
+
- lib/ezml/attribute_compiler.rb
|
159
|
+
- lib/ezml/attribute_parser.rb
|
160
|
+
- lib/ezml/buffer.rb
|
161
|
+
- lib/ezml/compiler.rb
|
162
|
+
- lib/ezml/engine.rb
|
163
|
+
- lib/ezml/error.rb
|
164
|
+
- lib/ezml/escapable.rb
|
165
|
+
- lib/ezml/exec.rb
|
166
|
+
- lib/ezml/filters.rb
|
167
|
+
- lib/ezml/generator.rb
|
168
|
+
- lib/ezml/helpers.rb
|
169
|
+
- lib/ezml/options.rb
|
170
|
+
- lib/ezml/parser.rb
|
171
|
+
- lib/ezml/template_engine.rb
|
172
|
+
- lib/ezml/temple_line_counter.rb
|
173
|
+
- lib/ezml/util.rb
|
174
|
+
- lib/ezml/version.rb
|
175
|
+
homepage: https://ezml.appflow.com.au
|
176
|
+
licenses:
|
177
|
+
- MIT
|
178
|
+
metadata: {}
|
179
|
+
post_install_message:
|
180
|
+
rdoc_options: []
|
181
|
+
require_paths:
|
182
|
+
- lib
|
183
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
requirements: []
|
194
|
+
rubyforge_project:
|
195
|
+
rubygems_version: 2.7.6
|
196
|
+
signing_key:
|
197
|
+
specification_version: 4
|
198
|
+
summary: An elegant, fast HTML templating engine.
|
199
|
+
test_files: []
|