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.
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module EZML
2
+ VERSION = "0.1.1"
3
+ end
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: []