hamlit 2.9.3
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/.gitignore +16 -0
- data/.travis.yml +45 -0
- data/CHANGELOG.md +676 -0
- data/Gemfile +28 -0
- data/LICENSE.txt +44 -0
- data/README.md +150 -0
- data/REFERENCE.md +266 -0
- data/Rakefile +117 -0
- data/benchmark/boolean_attribute.haml +6 -0
- data/benchmark/class_attribute.haml +5 -0
- data/benchmark/common_attribute.haml +3 -0
- data/benchmark/data_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/boolean_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/class_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/common_attribute.haml +2 -0
- data/benchmark/dynamic_attributes/data_attribute.haml +2 -0
- data/benchmark/dynamic_attributes/id_attribute.haml +2 -0
- data/benchmark/dynamic_boolean_attribute.haml +4 -0
- data/benchmark/etc/attribute_builder.haml +5 -0
- data/benchmark/etc/real_sample.haml +888 -0
- data/benchmark/etc/real_sample.rb +11 -0
- data/benchmark/etc/static_analyzer.haml +1 -0
- data/benchmark/etc/string_interpolation.haml +2 -0
- data/benchmark/etc/tags.haml +3 -0
- data/benchmark/etc/tags_loop.haml +2 -0
- data/benchmark/ext/build_data.rb +17 -0
- data/benchmark/ext/build_id.rb +13 -0
- data/benchmark/id_attribute.haml +3 -0
- data/benchmark/plain.haml +4 -0
- data/benchmark/script.haml +4 -0
- data/benchmark/slim/LICENSE +21 -0
- data/benchmark/slim/context.rb +11 -0
- data/benchmark/slim/run-benchmarks.rb +94 -0
- data/benchmark/slim/view.erb +23 -0
- data/benchmark/slim/view.haml +18 -0
- data/benchmark/slim/view.slim +17 -0
- data/benchmark/utils/benchmark_ips_extension.rb +43 -0
- data/bin/bench +77 -0
- data/bin/console +11 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/bin/test +24 -0
- data/exe/hamlit +6 -0
- data/ext/hamlit/extconf.rb +10 -0
- data/ext/hamlit/hamlit.c +553 -0
- data/ext/hamlit/hescape.c +108 -0
- data/ext/hamlit/hescape.h +20 -0
- data/hamlit.gemspec +45 -0
- data/lib/hamlit.rb +11 -0
- data/lib/hamlit/attribute_builder.rb +173 -0
- data/lib/hamlit/attribute_compiler.rb +123 -0
- data/lib/hamlit/attribute_parser.rb +110 -0
- data/lib/hamlit/cli.rb +130 -0
- data/lib/hamlit/compiler.rb +97 -0
- data/lib/hamlit/compiler/children_compiler.rb +112 -0
- data/lib/hamlit/compiler/comment_compiler.rb +36 -0
- data/lib/hamlit/compiler/doctype_compiler.rb +46 -0
- data/lib/hamlit/compiler/script_compiler.rb +102 -0
- data/lib/hamlit/compiler/silent_script_compiler.rb +24 -0
- data/lib/hamlit/compiler/tag_compiler.rb +74 -0
- data/lib/hamlit/engine.rb +37 -0
- data/lib/hamlit/error.rb +15 -0
- data/lib/hamlit/escapable.rb +13 -0
- data/lib/hamlit/filters.rb +75 -0
- data/lib/hamlit/filters/base.rb +12 -0
- data/lib/hamlit/filters/cdata.rb +20 -0
- data/lib/hamlit/filters/coffee.rb +17 -0
- data/lib/hamlit/filters/css.rb +33 -0
- data/lib/hamlit/filters/erb.rb +10 -0
- data/lib/hamlit/filters/escaped.rb +22 -0
- data/lib/hamlit/filters/javascript.rb +33 -0
- data/lib/hamlit/filters/less.rb +20 -0
- data/lib/hamlit/filters/markdown.rb +10 -0
- data/lib/hamlit/filters/plain.rb +29 -0
- data/lib/hamlit/filters/preserve.rb +22 -0
- data/lib/hamlit/filters/ruby.rb +10 -0
- data/lib/hamlit/filters/sass.rb +15 -0
- data/lib/hamlit/filters/scss.rb +15 -0
- data/lib/hamlit/filters/text_base.rb +25 -0
- data/lib/hamlit/filters/tilt_base.rb +49 -0
- data/lib/hamlit/force_escapable.rb +29 -0
- data/lib/hamlit/helpers.rb +15 -0
- data/lib/hamlit/html.rb +14 -0
- data/lib/hamlit/identity.rb +13 -0
- data/lib/hamlit/object_ref.rb +30 -0
- data/lib/hamlit/parser.rb +49 -0
- data/lib/hamlit/parser/MIT-LICENSE +20 -0
- data/lib/hamlit/parser/README.md +30 -0
- data/lib/hamlit/parser/haml_buffer.rb +348 -0
- data/lib/hamlit/parser/haml_compiler.rb +553 -0
- data/lib/hamlit/parser/haml_error.rb +61 -0
- data/lib/hamlit/parser/haml_helpers.rb +727 -0
- data/lib/hamlit/parser/haml_options.rb +286 -0
- data/lib/hamlit/parser/haml_parser.rb +800 -0
- data/lib/hamlit/parser/haml_util.rb +288 -0
- data/lib/hamlit/parser/haml_xss_mods.rb +109 -0
- data/lib/hamlit/rails_helpers.rb +51 -0
- data/lib/hamlit/rails_template.rb +59 -0
- data/lib/hamlit/railtie.rb +10 -0
- data/lib/hamlit/ruby_expression.rb +32 -0
- data/lib/hamlit/string_splitter.rb +88 -0
- data/lib/hamlit/template.rb +28 -0
- data/lib/hamlit/utils.rb +18 -0
- data/lib/hamlit/version.rb +4 -0
- metadata +361 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <string.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include "hescape.h"
|
5
|
+
|
6
|
+
static const char *ESCAPED_STRING[] = {
|
7
|
+
"",
|
8
|
+
""",
|
9
|
+
"&",
|
10
|
+
"'",
|
11
|
+
"<",
|
12
|
+
">",
|
13
|
+
};
|
14
|
+
|
15
|
+
// This is strlen(ESCAPED_STRING[x]) optimized specially.
|
16
|
+
// Mapping: 1 => 6, 2 => 5, 3 => 5, 4 => 4, 5 => 4
|
17
|
+
#define ESC_LEN(x) ((13 - x) / 2)
|
18
|
+
|
19
|
+
/*
|
20
|
+
* Given ASCII-compatible character, return index of ESCAPED_STRING.
|
21
|
+
*
|
22
|
+
* " (34) => 1 (")
|
23
|
+
* & (38) => 2 (&)
|
24
|
+
* ' (39) => 3 (')
|
25
|
+
* < (60) => 4 (<)
|
26
|
+
* > (62) => 5 (>)
|
27
|
+
*/
|
28
|
+
static const char HTML_ESCAPE_TABLE[] = {
|
29
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
30
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
31
|
+
0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
|
32
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 0,
|
33
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
34
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
35
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
36
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
37
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
38
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
39
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
40
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
41
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
42
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
43
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
44
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
45
|
+
};
|
46
|
+
|
47
|
+
static char*
|
48
|
+
ensure_allocated(char *buf, size_t size, size_t *asize)
|
49
|
+
{
|
50
|
+
size_t new_size;
|
51
|
+
|
52
|
+
if (size < *asize)
|
53
|
+
return buf;
|
54
|
+
|
55
|
+
if (*asize == 0) {
|
56
|
+
new_size = size;
|
57
|
+
} else {
|
58
|
+
new_size = *asize;
|
59
|
+
}
|
60
|
+
|
61
|
+
// Increase buffer size by 1.5x if realloced multiple times.
|
62
|
+
while (new_size < size)
|
63
|
+
new_size = (new_size << 1) - (new_size >> 1);
|
64
|
+
|
65
|
+
// Round allocation up to multiple of 8.
|
66
|
+
new_size = (new_size + 7) & ~7;
|
67
|
+
|
68
|
+
*asize = new_size;
|
69
|
+
return realloc(buf, new_size);
|
70
|
+
}
|
71
|
+
|
72
|
+
size_t
|
73
|
+
hesc_escape_html(char **dest, const char *buf, size_t size)
|
74
|
+
{
|
75
|
+
size_t asize = 0, esc_i = 0, esize = 0, i = 0, rbuf_end = 0;
|
76
|
+
const char *esc;
|
77
|
+
char *rbuf = NULL;
|
78
|
+
|
79
|
+
while (i < size) {
|
80
|
+
// Loop here to skip non-escaped characters fast.
|
81
|
+
while (i < size && (esc_i = HTML_ESCAPE_TABLE[(unsigned char)buf[i]]) == 0)
|
82
|
+
i++;
|
83
|
+
|
84
|
+
if (i < size && esc_i) {
|
85
|
+
esc = ESCAPED_STRING[esc_i];
|
86
|
+
rbuf = ensure_allocated(rbuf, sizeof(char) * (size + esize + ESC_LEN(esc_i) + 1), &asize);
|
87
|
+
|
88
|
+
// Copy pending characters and escaped string.
|
89
|
+
memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), i - (rbuf_end - esize));
|
90
|
+
memmove(rbuf + i + esize, esc, ESC_LEN(esc_i));
|
91
|
+
rbuf_end = i + esize + ESC_LEN(esc_i);
|
92
|
+
esize += ESC_LEN(esc_i) - 1;
|
93
|
+
}
|
94
|
+
i++;
|
95
|
+
}
|
96
|
+
|
97
|
+
if (rbuf_end == 0) {
|
98
|
+
// Return given buf and size if there are no escaped characters.
|
99
|
+
*dest = (char *)buf;
|
100
|
+
return size;
|
101
|
+
} else {
|
102
|
+
// Copy pending characters including NULL character.
|
103
|
+
memmove(rbuf + rbuf_end, buf + (rbuf_end - esize), (size + 1) - (rbuf_end - esize));
|
104
|
+
|
105
|
+
*dest = rbuf;
|
106
|
+
return size + esize;
|
107
|
+
}
|
108
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#ifndef HESCAPE_H
|
2
|
+
#define HESCAPE_H
|
3
|
+
|
4
|
+
#include <sys/types.h>
|
5
|
+
|
6
|
+
/*
|
7
|
+
* Replace characters according to the following rules.
|
8
|
+
* Note that this function can handle only ASCII-compatible string.
|
9
|
+
*
|
10
|
+
* " => "
|
11
|
+
* & => &
|
12
|
+
* ' => '
|
13
|
+
* < => <
|
14
|
+
* > => >
|
15
|
+
*
|
16
|
+
* @return size of dest. If it's larger than len, dest is required to be freed.
|
17
|
+
*/
|
18
|
+
extern size_t hesc_escape_html(char **dest, const char *src, size_t size);
|
19
|
+
|
20
|
+
#endif
|
data/hamlit.gemspec
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hamlit/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'hamlit'
|
8
|
+
spec.version = Hamlit::VERSION
|
9
|
+
spec.authors = ['Takashi Kokubun']
|
10
|
+
spec.email = ['takashikkbn@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = %q{High Performance Haml Implementation}
|
13
|
+
spec.description = %q{High Performance Haml Implementation}
|
14
|
+
spec.homepage = 'https://github.com/k0kubun/hamlit'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sample)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
if /java/ === RUBY_PLATFORM
|
23
|
+
spec.platform = 'java'
|
24
|
+
else
|
25
|
+
spec.extensions = ['ext/hamlit/extconf.rb']
|
26
|
+
spec.required_ruby_version = '>= 2.1.0'
|
27
|
+
end
|
28
|
+
|
29
|
+
spec.add_dependency 'temple', '>= 0.8.0'
|
30
|
+
spec.add_dependency 'thor'
|
31
|
+
spec.add_dependency 'tilt'
|
32
|
+
|
33
|
+
spec.add_development_dependency 'bundler'
|
34
|
+
spec.add_development_dependency 'coffee-script'
|
35
|
+
spec.add_development_dependency 'erubi'
|
36
|
+
spec.add_development_dependency 'haml', '>= 5'
|
37
|
+
spec.add_development_dependency 'less'
|
38
|
+
spec.add_development_dependency 'minitest-reporters', '~> 1.1'
|
39
|
+
spec.add_development_dependency 'rails', '>= 4.0.0'
|
40
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
41
|
+
spec.add_development_dependency 'rake-compiler'
|
42
|
+
spec.add_development_dependency 'sass'
|
43
|
+
spec.add_development_dependency 'slim'
|
44
|
+
spec.add_development_dependency 'unindent'
|
45
|
+
end
|
data/lib/hamlit.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hamlit/object_ref'
|
3
|
+
|
4
|
+
module Hamlit::AttributeBuilder
|
5
|
+
BOOLEAN_ATTRIBUTES = %w[disabled readonly multiple checked autobuffer
|
6
|
+
autoplay controls loop selected hidden scoped async
|
7
|
+
defer reversed ismap seamless muted required
|
8
|
+
autofocus novalidate formnovalidate open pubdate
|
9
|
+
itemscope allowfullscreen default inert sortable
|
10
|
+
truespeed typemustmatch download].freeze
|
11
|
+
|
12
|
+
if /java/ === RUBY_PLATFORM # JRuby
|
13
|
+
class << self
|
14
|
+
def build(escape_attrs, quote, format, object_ref, *hashes)
|
15
|
+
hashes << Hamlit::ObjectRef.parse(object_ref) if object_ref
|
16
|
+
buf = []
|
17
|
+
hash = merge_all_attrs(hashes)
|
18
|
+
|
19
|
+
keys = hash.keys.sort!
|
20
|
+
keys.each do |key|
|
21
|
+
case key
|
22
|
+
when 'id'.freeze
|
23
|
+
buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
|
24
|
+
when 'class'.freeze
|
25
|
+
buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
|
26
|
+
when 'data'.freeze
|
27
|
+
buf << build_data(escape_attrs, quote, *hash[key])
|
28
|
+
when *BOOLEAN_ATTRIBUTES, /\Adata-/
|
29
|
+
build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
|
30
|
+
else
|
31
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
buf.join
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_id(escape_attrs, *values)
|
38
|
+
escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_class(escape_attrs, *values)
|
42
|
+
if values.size == 1
|
43
|
+
value = values.first
|
44
|
+
case
|
45
|
+
when value.is_a?(String)
|
46
|
+
# noop
|
47
|
+
when value.is_a?(Array)
|
48
|
+
value = value.flatten.select { |v| v }.map(&:to_s).sort.uniq.join(' ')
|
49
|
+
when value
|
50
|
+
value = value.to_s
|
51
|
+
else
|
52
|
+
return ''
|
53
|
+
end
|
54
|
+
return escape_html(escape_attrs, value)
|
55
|
+
end
|
56
|
+
|
57
|
+
classes = []
|
58
|
+
values.each do |value|
|
59
|
+
case
|
60
|
+
when value.is_a?(String)
|
61
|
+
classes += value.split(' ')
|
62
|
+
when value.is_a?(Array)
|
63
|
+
classes += value.select { |v| v }
|
64
|
+
when value
|
65
|
+
classes << value.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
escape_html(escape_attrs, classes.map(&:to_s).sort.uniq.join(' '))
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_data(escape_attrs, quote, *hashes)
|
72
|
+
build_data_attribute(:data, escape_attrs, quote, *hashes)
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_aria(escape_attrs, quote, *hashes)
|
76
|
+
build_data_attribute(:aria, escape_attrs, quote, *hashes)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def build_data_attribute(key, escape_attrs, quote, *hashes)
|
82
|
+
attrs = []
|
83
|
+
if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
|
84
|
+
data_value = merge_all_attrs(hashes)
|
85
|
+
else
|
86
|
+
data_value = hashes.last
|
87
|
+
end
|
88
|
+
hash = flatten_attributes(key => data_value)
|
89
|
+
|
90
|
+
hash.sort_by(&:first).each do |key, value|
|
91
|
+
case value
|
92
|
+
when true
|
93
|
+
attrs << " #{key}"
|
94
|
+
when nil, false
|
95
|
+
# noop
|
96
|
+
else
|
97
|
+
attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
attrs.join
|
101
|
+
end
|
102
|
+
|
103
|
+
def flatten_attributes(attributes)
|
104
|
+
flattened = {}
|
105
|
+
|
106
|
+
attributes.each do |key, value|
|
107
|
+
case value
|
108
|
+
when attributes
|
109
|
+
when Hash
|
110
|
+
flatten_attributes(value).each do |k, v|
|
111
|
+
if k.nil?
|
112
|
+
flattened[key] = v
|
113
|
+
else
|
114
|
+
flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
|
115
|
+
end
|
116
|
+
end
|
117
|
+
else
|
118
|
+
flattened[key] = value if value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
flattened
|
122
|
+
end
|
123
|
+
|
124
|
+
def merge_all_attrs(hashes)
|
125
|
+
merged = {}
|
126
|
+
hashes.each do |hash|
|
127
|
+
hash.each do |key, value|
|
128
|
+
key = key.to_s
|
129
|
+
case key
|
130
|
+
when 'id'.freeze, 'class'.freeze, 'data'.freeze
|
131
|
+
merged[key] ||= []
|
132
|
+
merged[key] << value
|
133
|
+
else
|
134
|
+
merged[key] = value
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
merged
|
139
|
+
end
|
140
|
+
|
141
|
+
def build_boolean!(escape_attrs, quote, format, buf, key, value)
|
142
|
+
case value
|
143
|
+
when true
|
144
|
+
case format
|
145
|
+
when :xhtml
|
146
|
+
buf << " #{key}=#{quote}#{key}#{quote}"
|
147
|
+
else
|
148
|
+
buf << " #{key}"
|
149
|
+
end
|
150
|
+
when false, nil
|
151
|
+
# omitted
|
152
|
+
else
|
153
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def escape_html(escape_attrs, str)
|
158
|
+
if escape_attrs
|
159
|
+
Hamlit::Utils.escape_html(str)
|
160
|
+
else
|
161
|
+
str
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
else
|
166
|
+
# Hamlit::AttributeBuilder.build
|
167
|
+
# Hamlit::AttributeBuilder.build_id
|
168
|
+
# Hamlit::AttributeBuilder.build_class
|
169
|
+
# Hamlit::AttributeBuilder.build_data
|
170
|
+
# Hamlit::AttributeBuilder.build_aria
|
171
|
+
require 'hamlit/hamlit'
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'hamlit/attribute_builder'
|
3
|
+
require 'hamlit/attribute_parser'
|
4
|
+
require 'hamlit/ruby_expression'
|
5
|
+
|
6
|
+
module Hamlit
|
7
|
+
class AttributeCompiler
|
8
|
+
def initialize(identity, options)
|
9
|
+
@identity = identity
|
10
|
+
@quote = options[:attr_quote]
|
11
|
+
@format = options[:format]
|
12
|
+
@escape_attrs = options[:escape_attrs]
|
13
|
+
end
|
14
|
+
|
15
|
+
def compile(node)
|
16
|
+
hashes = []
|
17
|
+
return runtime_compile(node) if node.value[:object_ref] != :nil
|
18
|
+
node.value[:attributes_hashes].each do |attribute_str|
|
19
|
+
hash = AttributeParser.parse(attribute_str)
|
20
|
+
return runtime_compile(node) unless hash
|
21
|
+
hashes << hash
|
22
|
+
end
|
23
|
+
static_compile(node.value[:attributes], hashes)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def runtime_compile(node)
|
29
|
+
attrs = node.value[:attributes_hashes]
|
30
|
+
attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {}
|
31
|
+
|
32
|
+
args = [@escape_attrs.inspect, "#{@quote.inspect}.freeze", @format.inspect].push(node.value[:object_ref]) + attrs
|
33
|
+
[:html, :attrs, [:dynamic, "::Hamlit::AttributeBuilder.build(#{args.join(', ')})"]]
|
34
|
+
end
|
35
|
+
|
36
|
+
def static_compile(static_hash, dynamic_hashes)
|
37
|
+
temple = [:html, :attrs]
|
38
|
+
keys = [*static_hash.keys, *dynamic_hashes.map(&:keys).flatten].uniq.sort
|
39
|
+
keys.each do |key|
|
40
|
+
values = [[:static, static_hash[key]], *dynamic_hashes.map { |h| [:dynamic, h[key]] }]
|
41
|
+
values.select! { |_, exp| exp != nil }
|
42
|
+
|
43
|
+
case key
|
44
|
+
when 'id'
|
45
|
+
compile_id!(temple, key, values)
|
46
|
+
when 'class'
|
47
|
+
compile_class!(temple, key, values)
|
48
|
+
when 'data', 'aria'
|
49
|
+
compile_data!(temple, key, values)
|
50
|
+
when *AttributeBuilder::BOOLEAN_ATTRIBUTES, /\Adata-/, /\Aaria-/
|
51
|
+
compile_boolean!(temple, key, values)
|
52
|
+
else
|
53
|
+
compile_common!(temple, key, values)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
temple
|
57
|
+
end
|
58
|
+
|
59
|
+
def compile_id!(temple, key, values)
|
60
|
+
build_code = attribute_builder(:id, values)
|
61
|
+
if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) }
|
62
|
+
temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
|
63
|
+
else
|
64
|
+
temple << [:html, :attr, key, [:dynamic, build_code]]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def compile_class!(temple, key, values)
|
69
|
+
build_code = attribute_builder(:class, values)
|
70
|
+
if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) }
|
71
|
+
temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
|
72
|
+
else
|
73
|
+
temple << [:html, :attr, key, [:dynamic, build_code]]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def compile_data!(temple, key, values)
|
78
|
+
args = [@escape_attrs.inspect, "#{@quote.inspect}.freeze", values.map { |v| literal_for(v) }]
|
79
|
+
build_code = "::Hamlit::AttributeBuilder.build_#{key}(#{args.join(', ')})"
|
80
|
+
|
81
|
+
if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) }
|
82
|
+
temple << [:static, eval(build_code).to_s]
|
83
|
+
else
|
84
|
+
temple << [:dynamic, build_code]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def compile_boolean!(temple, key, values)
|
89
|
+
exp = literal_for(values.last)
|
90
|
+
|
91
|
+
if Temple::StaticAnalyzer.static?(exp)
|
92
|
+
value = eval(exp)
|
93
|
+
case value
|
94
|
+
when true then temple << [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]
|
95
|
+
when false, nil
|
96
|
+
else temple << [:html, :attr, key, [:fescape, @escape_attrs, [:static, value.to_s]]]
|
97
|
+
end
|
98
|
+
else
|
99
|
+
var = @identity.generate
|
100
|
+
temple << [
|
101
|
+
:case, "(#{var} = (#{exp}))",
|
102
|
+
['true', [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]],
|
103
|
+
['false, nil', [:multi]],
|
104
|
+
[:else, [:multi, [:static, " #{key}=#{@quote}"], [:fescape, @escape_attrs, [:dynamic, var]], [:static, @quote]]],
|
105
|
+
]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def compile_common!(temple, key, values)
|
110
|
+
temple << [:html, :attr, key, [:fescape, @escape_attrs, values.last]]
|
111
|
+
end
|
112
|
+
|
113
|
+
def attribute_builder(type, values)
|
114
|
+
args = [@escape_attrs.inspect, *values.map { |v| literal_for(v) }]
|
115
|
+
"::Hamlit::AttributeBuilder.build_#{type}(#{args.join(', ')})"
|
116
|
+
end
|
117
|
+
|
118
|
+
def literal_for(value)
|
119
|
+
type, exp = value
|
120
|
+
type == :static ? "#{exp.inspect}.freeze" : exp
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|