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,38 @@
1
+ module EZML
2
+ class Generator
3
+ include Temple::Mixins::CompiledDispatcher
4
+ include Temple::Mixins::Options
5
+
6
+ define_options freeze_static: RUBY_VERSION >= '2.1'
7
+
8
+ def call(exp)
9
+ compile(exp)
10
+ end
11
+
12
+ def on_multi(*exp)
13
+ exp.map { |e| compile(e) }.join('; ')
14
+ end
15
+
16
+ def on_static(text)
17
+ concat(options[:freeze_static] ? "#{Util.inspect_obj(text)}.freeze" : Util.inspect_obj(text))
18
+ end
19
+
20
+ def on_dynamic(code)
21
+ concat(code)
22
+ end
23
+
24
+ def on_code(exp)
25
+ exp
26
+ end
27
+
28
+ def on_newline
29
+ "\n"
30
+ end
31
+
32
+ private
33
+
34
+ def concat(str)
35
+ "_ezmlout.buffer << (#{str});"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,299 @@
1
+ require 'erb'
2
+
3
+ module EZML
4
+ module Helpers
5
+
6
+ class ErrorReturn
7
+ def initialize(method)
8
+ @message = <<MESSAGE
9
+ #{method} outputs directly to the EZML template.
10
+ Disregard its return value and use the - operator,
11
+ or use capture_ezml to get the value as a String.
12
+ MESSAGE
13
+ end
14
+
15
+ def to_s
16
+ raise EZML::Error.new(@message)
17
+ rescue EZML::Error => e
18
+ e.backtrace.shift
19
+
20
+ if e.backtrace.first =~ /^\(eval\):\d+:in `format_script/
21
+ e.backtrace.shift
22
+ e.backtrace.first.gsub!(/^\(ezml\):(\d+)/) {|s| "(ezml):#{$1.to_i - 1}"}
23
+ end
24
+ raise e
25
+ end
26
+
27
+ def inspect
28
+ "EZML::Helpers::ErrorReturn(#{@message.inspect})"
29
+ end
30
+ end
31
+
32
+ self.extend self
33
+
34
+ @@action_view_defined = false
35
+
36
+ def self.action_view?
37
+ @@action_view_defined
38
+ end
39
+
40
+ def init_ezml_helpers
41
+ @ezml_buffer = EZML::Buffer.new(ezml_buffer, Options.new.for_buffer)
42
+ nil
43
+ end
44
+
45
+ def non_ezml
46
+ was_active = @ezml_buffer.active?
47
+ @ezml_buffer.active = false
48
+ yield
49
+ ensure
50
+ @ezml_buffer.active = was_active
51
+ end
52
+
53
+ def find_and_preserve(input = nil, tags = ezml_buffer.options[:preserve], &block)
54
+ return find_and_preserve(capture_ezml(&block), input || tags) if block
55
+ tags = tags.map { |tag| Regexp.escape(tag) }.join('|')
56
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
57
+ input.to_s.gsub(re) do |s|
58
+ s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
59
+ "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
60
+ end
61
+ end
62
+
63
+ def preserve(input = nil, &block)
64
+ return preserve(capture_ezml(&block)) if block
65
+ s = input.to_s.chomp("\n")
66
+ s.gsub!(/\n/, '&#x000A;')
67
+ s.delete!("\r")
68
+ s
69
+ end
70
+ alias_method :flatten, :preserve
71
+
72
+ def list_of(enum, opts={}, &block)
73
+ opts_attributes = opts.map { |k, v| " #{k}='#{v}'" }.join
74
+ enum.map do |i|
75
+ result = capture_ezml(i, &block)
76
+
77
+ if result.count("\n") > 1
78
+ result.gsub!("\n", "\n ")
79
+ result = "\n #{result.strip}\n"
80
+ else
81
+ result.strip!
82
+ end
83
+
84
+ %Q!<li#{opts_attributes}>#{result}</li>!
85
+ end.join("\n")
86
+ end
87
+
88
+ def html_attrs(lang = 'en-US')
89
+ if ezml_buffer.options[:format] == :xhtml
90
+ {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
91
+ else
92
+ {:lang => lang}
93
+ end
94
+ end
95
+
96
+ def tab_up(i = 1)
97
+ ezml_buffer.tabulation += i
98
+ end
99
+
100
+ def tab_down(i = 1)
101
+ ezml_buffer.tabulation -= i
102
+ end
103
+
104
+ def with_tabs(i)
105
+ old_tabs = ezml_buffer.tabulation
106
+ ezml_buffer.tabulation = i
107
+ yield
108
+ ensure
109
+ ezml_buffer.tabulation = old_tabs
110
+ end
111
+
112
+ def surround(front, back = front, &block)
113
+ output = capture_ezml(&block)
114
+
115
+ "#{front}#{output.chomp}#{back}\n"
116
+ end
117
+
118
+ def precede(str, &block)
119
+ "#{str}#{capture_ezml(&block).chomp}\n"
120
+ end
121
+
122
+ def succeed(str, &block)
123
+ "#{capture_ezml(&block).chomp}#{str}\n"
124
+ end
125
+
126
+ def capture_ezml(*args, &block)
127
+ buffer = eval('if defined? _ezmlout then _ezmlout else nil end', block.binding) || ezml_buffer
128
+ with_ezml_buffer(buffer) do
129
+ position = ezml_buffer.buffer.length
130
+
131
+ ezml_buffer.capture_position = position
132
+ value = block.call(*args)
133
+
134
+ captured = ezml_buffer.buffer.slice!(position..-1)
135
+
136
+ if captured == '' and value != ezml_buffer.buffer
137
+ captured = (value.is_a?(String) ? value : nil)
138
+ end
139
+
140
+ captured
141
+ end
142
+ ensure
143
+ ezml_buffer.capture_position = nil
144
+ end
145
+
146
+ def ezml_concat(text = "")
147
+ ezml_internal_concat text
148
+ ErrorReturn.new("ezml_concat")
149
+ end
150
+
151
+ def ezml_internal_concat(text = "", newline = true, indent = true)
152
+ if ezml_buffer.tabulation == 0
153
+ ezml_buffer.buffer << "#{text}#{"\n" if newline}"
154
+ else
155
+ ezml_buffer.buffer << %[#{ezml_indent if indent}#{text.to_s.gsub("\n", "\n#{ezml_indent}")}#{"\n" if newline}]
156
+ end
157
+ end
158
+ private :ezml_internal_concat
159
+
160
+ alias :ezml_internal_concat_raw :ezml_internal_concat
161
+
162
+ def ezml_indent
163
+ ' ' * ezml_buffer.tabulation
164
+ end
165
+
166
+ def ezml_tag(name, *rest, &block)
167
+ ret = ErrorReturn.new("ezml_tag")
168
+
169
+ text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
170
+ flags = []
171
+ flags << rest.shift while rest.first.is_a? Symbol
172
+ attrs = (rest.shift || {})
173
+ attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
174
+ name, attrs = merge_name_and_attributes(name.to_s, attrs)
175
+
176
+ attributes = EZML::AttributeBuilder.build_attributes(ezml_buffer.html?,
177
+ ezml_buffer.options[:attr_wrapper],
178
+ ezml_buffer.options[:escape_attrs],
179
+ ezml_buffer.options[:hyphenate_data_attrs],
180
+ attrs)
181
+
182
+ if text.nil? && block.nil? && (ezml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
183
+ ezml_internal_concat_raw "<#{name}#{attributes}#{' /' if ezml_buffer.options[:format] == :xhtml}>"
184
+ return ret
185
+ end
186
+
187
+ if flags.include?(:/)
188
+ raise Error.new(Error.message(:self_closing_content)) if text
189
+ raise Error.new(Error.message(:illegal_nesting_self_closing)) if block
190
+ end
191
+
192
+ tag = "<#{name}#{attributes}>"
193
+ end_tag = "</#{name}>"
194
+ if block.nil?
195
+ text = text.to_s
196
+ if text.include?("\n")
197
+ ezml_internal_concat_raw tag
198
+ tab_up
199
+ ezml_internal_concat text
200
+ tab_down
201
+ ezml_internal_concat_raw end_tag
202
+ else
203
+ ezml_internal_concat_raw tag, false
204
+ ezml_internal_concat text, false, false
205
+ ezml_internal_concat_raw end_tag, true, false
206
+ end
207
+ return ret
208
+ end
209
+
210
+ if text
211
+ raise Error.new(Error.message(:illegal_nesting_line, name))
212
+ end
213
+
214
+ if flags.include?(:<)
215
+ ezml_internal_concat_raw tag, false
216
+ ezml_internal_concat "#{capture_ezml(&block).strip}", false, false
217
+ ezml_internal_concat_raw end_tag, true, false
218
+ return ret
219
+ end
220
+
221
+ ezml_internal_concat_raw tag
222
+ tab_up
223
+ block.call
224
+ tab_down
225
+ ezml_internal_concat_raw end_tag
226
+
227
+ ret
228
+ end
229
+
230
+ def ezml_tag_if(condition, *tag)
231
+ if condition
232
+ ezml_tag(*tag){ yield }
233
+ else
234
+ yield
235
+ end
236
+ ErrorReturn.new("ezml_tag_if")
237
+ end
238
+
239
+ HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#39;' }
240
+
241
+ HTML_ESCAPE_REGEX = /['"><&]/
242
+
243
+ def html_escape(text)
244
+ ERB::Util.html_escape(text)
245
+ end
246
+
247
+ HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
248
+
249
+ def escape_once(text)
250
+ text = text.to_s
251
+ text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
252
+ end
253
+
254
+ def is_ezml?
255
+ !@ezml_buffer.nil? && @ezml_buffer.active?
256
+ end
257
+
258
+ def block_is_ezml?(block)
259
+ eval('!!defined?(_ezmlout)', block.binding)
260
+ end
261
+
262
+ private
263
+
264
+ def merge_name_and_attributes(name, attributes_hash = {})
265
+ return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
266
+
267
+ return $1 || "div", AttributeBuilder.merge_attributes!(
268
+ EZML::Parser.parse_class_and_id($2), attributes_hash)
269
+ end
270
+
271
+ def with_ezml_buffer(buffer)
272
+ @ezml_buffer, old_buffer = buffer, @ezml_buffer
273
+ old_buffer.active, old_was_active = false, old_buffer.active? if old_buffer
274
+ @ezml_buffer.active, was_active = true, @ezml_buffer.active?
275
+ yield
276
+ ensure
277
+ @ezml_buffer.active = was_active
278
+ old_buffer.active = old_was_active if old_buffer
279
+ @ezml_buffer = old_buffer
280
+ end
281
+
282
+ def ezml_buffer
283
+ @ezml_buffer if defined? @ezml_buffer
284
+ end
285
+
286
+ def ezml_bind_proc(&proc)
287
+ _ezmlout = ezml_buffer
288
+ #double assignment is to avoid warnings
289
+ _erbout = _erbout = _ezmlout.buffer
290
+ proc { |*args| proc.call(*args) }
291
+ end
292
+ end
293
+ end
294
+
295
+ class Object
296
+ def is_ezml?
297
+ false
298
+ end
299
+ end
@@ -0,0 +1,142 @@
1
+ module EZML
2
+
3
+ class Options
4
+
5
+ @valid_formats = [:html4, :html5, :xhtml]
6
+
7
+ @buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :format,
8
+ :encoding, :escape_html, :escape_attrs, :hyphenate_data_attrs, :cdata]
9
+
10
+ def self.defaults
11
+ @defaults ||= EZML::TemplateEngine.options.to_hash.merge(encoding: 'UTF-8')
12
+ end
13
+
14
+ def self.valid_formats
15
+ @valid_formats
16
+ end
17
+
18
+ def self.buffer_option_keys
19
+ @buffer_option_keys
20
+ end
21
+
22
+ def self.buffer_defaults
23
+ @buffer_defaults ||= buffer_option_keys.inject({}) do |hash, key|
24
+ hash.merge(key => defaults[key])
25
+ end
26
+ end
27
+
28
+ def self.wrap(options)
29
+ if options.is_a?(Options)
30
+ options
31
+ else
32
+ Options.new(options)
33
+ end
34
+ end
35
+
36
+ attr_reader :attr_wrapper
37
+ attr_accessor :autoclose
38
+ attr_reader :encoding
39
+ attr_accessor :escape_attrs
40
+ attr_accessor :escape_html
41
+ attr_accessor :filename
42
+ attr_accessor :hyphenate_data_attrs
43
+ attr_accessor :line
44
+ attr :format
45
+ attr_accessor :mime_type
46
+ attr_accessor :preserve
47
+ attr_reader :remove_whitespace
48
+ attr_accessor :suppress_eval
49
+ attr_accessor :cdata
50
+ attr_accessor :parser_class
51
+ attr_accessor :compiler_class
52
+ attr_accessor :trace
53
+ attr_accessor :filters
54
+
55
+ def initialize(values = {}, &block)
56
+ defaults.each {|k, v| instance_variable_set :"@#{k}", v}
57
+ values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
58
+ yield if block_given?
59
+ end
60
+
61
+ def [](key)
62
+ send key
63
+ end
64
+
65
+ def []=(key, value)
66
+ send "#{key}=", value
67
+ end
68
+
69
+ [:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval].each do |method|
70
+ class_eval(<<-END)
71
+ def #{method}?
72
+ !! @#{method}
73
+ end
74
+ END
75
+ end
76
+
77
+ def xhtml?
78
+ not html?
79
+ end
80
+
81
+ def html?
82
+ html4? or html5?
83
+ end
84
+
85
+ def html4?
86
+ format == :html4
87
+ end
88
+
89
+ def html5?
90
+ format == :html5
91
+ end
92
+
93
+ def attr_wrapper=(value)
94
+ @attr_wrapper = value || self.class.defaults[:attr_wrapper]
95
+ end
96
+
97
+ undef :format
98
+ def format
99
+ mime_type == "text/xml" ? :xhtml : @format
100
+ end
101
+
102
+ def format=(value)
103
+ unless self.class.valid_formats.include?(value)
104
+ raise EZML::Error, "Invalid output format #{value.inspect}"
105
+ end
106
+ @format = value
107
+ end
108
+
109
+ undef :cdata
110
+ def cdata
111
+ xhtml? || @cdata
112
+ end
113
+
114
+ def remove_whitespace=(value)
115
+ @remove_whitespace = value
116
+ end
117
+
118
+ def encoding=(value)
119
+ return unless value
120
+ @encoding = value.is_a?(Encoding) ? value.name : value.to_s
121
+ @encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
122
+ end
123
+
124
+ def for_buffer
125
+ self.class.buffer_option_keys.inject({}) do |hash, key|
126
+ value = public_send(key)
127
+ if self.class.buffer_defaults[key] != value
128
+ hash[key] = value
129
+ end
130
+ hash
131
+ end
132
+ end
133
+
134
+ private
135
+
136
+ def defaults
137
+ self.class.defaults
138
+ end
139
+
140
+ end
141
+
142
+ end