haml 6.1.2 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f721367f32b443559aa0aa20e75bd7b9d179fffbfff06873cca328f26ae70689
4
- data.tar.gz: dc52332427ab542277bb52374e6c20ba696180caad8a86cd04eee247c6c0f9bb
3
+ metadata.gz: c1374065239926b78aa88c8a9669a4a97ea937ba078f4794be6d3d34c072472e
4
+ data.tar.gz: a99b6d11b903d2d9985e6e89d857b24c4ca5c31efe2a0c09d29cfea7b58a2057
5
5
  SHA512:
6
- metadata.gz: 13197f48f55be37cec0eb76bc6b9c2e32d37cc1b3e430a509bb9c362fbb1e8f44fb858f1d39b22a0b2c654dfb6b2c237756a08a4495cf31c42eae59a6ea15c77
7
- data.tar.gz: 073bc4c02899dea76c285bb8561df5631e3553fc3d939e30f94fe1671814ca5c3c812c3bcec251b3f0a562c03a2db606ef9b7e37b3014c50638cf2e29c44c465
6
+ metadata.gz: '05423907d445d38fbba24d1b08f6812b43a8bca544554b5ecc1d1190e87842cedf888cd4759f6d568cb861a0f6983e06610d57daa2233feafb0e29cce92c71b1'
7
+ data.tar.gz: e88712e3391749f5c893512eb595c912718476a7128773b4edd4aa19b191837ff3d6d154a18a0c8a42a107d6c04ce4ee6cd3189d6270210d9b4b5ded33def0dc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Haml Changelog
2
2
 
3
+ ## 6.2.0
4
+
5
+ * Drop the C extension [#1146](https://github.com/haml/haml/issues/1146)
6
+
7
+ ## 6.1.4
8
+
9
+ * Let `Haml::Util.escape_html` use `ERB::Escape` if available [#1145](https://github.com/haml/haml/issues/1145)
10
+
11
+ ## 6.1.3
12
+
13
+ * Add `Haml::RailsTemplate#default_format` for Turbo compatibility [#1144](https://github.com/haml/haml/issues/1144)
14
+
15
+ ## 6.1.2
16
+
17
+ * Use the rails template path as `filename` [#1140](https://github.com/haml/haml/issues/1140)
18
+
3
19
  ## 6.1.1
4
20
 
5
21
  * Fix an empty output of Ruby 3.1's Hash shorthand syntax [#1083](https://github.com/haml/haml/issues/1083)
@@ -102,6 +118,12 @@ Released on September 21, 2022
102
118
  `list_of`, `non_haml`, `precede`, `succeed`, `surround`, `tab_down`, `tab_up`, `with_tabs`
103
119
  * `:ruby` filter
104
120
  * Removed: `haml_io`
121
+ * Alternatives to the removed helpers:
122
+ * Some simple ones could work by copying [the original definition](https://github.com/haml/haml/blob/v5.2.2/lib/haml/helpers.rb).
123
+ * For helpers generating general HTML tags, also consider using what your framework provides, e.g. Rails `content_tag`.
124
+ Same applies to `capture_haml`, e.g. Rails `capture`.
125
+ * Ones that rely on `Haml::Buffer` have no direct alternative by design. They existed at the cost of performance.
126
+ You need to define a helper, instantiate a String buffer in it, append stuff to it, and call it inside `=`.
105
127
  * Only the following attributes and `aria`/`data` attributes are considered boolean attributes:
106
128
  * `allowfullscreen`, `async`, `autobuffer`, `autofocus`, `autoplay`, `checked`, `controls`, `default`,
107
129
  `defer`, `disabled`, `download`, `formnovalidate`, `hidden`, `inert`, `ismap`, `itemscope`, `loop`,
data/Rakefile CHANGED
@@ -1,39 +1,5 @@
1
1
  require 'bundler/gem_tasks'
2
-
3
- #
4
- # Prepend DevKit into compilation phase
5
- #
6
- if Gem.win_platform?
7
- desc 'Activates DevKit'
8
- task :devkit do
9
- begin
10
- require 'devkit'
11
- rescue LoadError
12
- abort 'Failed to load DevKit required for compilation'
13
- end
14
- end
15
- task compile: :devkit
16
- end
17
-
18
2
  require 'rake/testtask'
19
- if /java/ === RUBY_PLATFORM
20
- # require 'rake/javaextensiontask'
21
- # Rake::JavaExtensionTask.new(:haml) do |ext|
22
- # ext.ext_dir = 'ext/java'
23
- # ext.lib_dir = 'lib/haml'
24
- # end
25
-
26
- task :compile do
27
- # dummy for now
28
- end
29
- else
30
- require 'rake/extensiontask'
31
- Rake::ExtensionTask.new(:haml) do |ext|
32
- ext.lib_dir = 'lib/haml'
33
- end
34
- end
35
-
36
- Dir['benchmark/*.rake'].each { |b| import(b) }
37
3
 
38
4
  Rake::TestTask.new do |t|
39
5
  t.libs << 'lib' << 'test'
@@ -42,10 +8,10 @@ Rake::TestTask.new do |t|
42
8
  t.test_files = files
43
9
  t.verbose = true
44
10
  end
45
- task test: :compile
11
+ task :test
46
12
 
47
13
  desc 'bench task for CI'
48
- task bench: :compile do
14
+ task :bench do
49
15
  if ENV['SLIM_BENCH'] == '1'
50
16
  cmd = %w[bundle exec ruby benchmark/slim/run-benchmarks.rb]
51
17
  else
@@ -79,4 +45,4 @@ task(:doc => 'doc:sass') {sh "yard"}
79
45
  desc "Generate documentation incrementally"
80
46
  task(:redoc) {sh "yard -c"}
81
47
 
82
- task default: %w[compile test]
48
+ task default: :test
data/haml.gemspec CHANGED
@@ -21,12 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.metadata = { 'rubygems_mfa_required' => 'true' }
23
23
 
24
- if /java/ === RUBY_PLATFORM
25
- spec.platform = 'java'
26
- else
27
- spec.extensions = ['ext/haml/extconf.rb']
28
- spec.required_ruby_version = '>= 2.1.0'
29
- end
24
+ spec.required_ruby_version = '>= 2.1.0'
30
25
 
31
26
  spec.add_dependency 'temple', '>= 0.8.2'
32
27
  spec.add_dependency 'thor'
@@ -41,7 +36,6 @@ Gem::Specification.new do |spec|
41
36
  spec.add_development_dependency 'minitest-reporters', '~> 1.1'
42
37
  spec.add_development_dependency 'rails', '>= 4.0'
43
38
  spec.add_development_dependency 'rake'
44
- spec.add_development_dependency 'rake-compiler'
45
39
  spec.add_development_dependency 'sass'
46
40
  spec.add_development_dependency 'slim'
47
41
  spec.add_development_dependency 'string_template'
@@ -9,166 +9,159 @@ module Haml::AttributeBuilder
9
9
  itemscope allowfullscreen default inert sortable
10
10
  truespeed typemustmatch download].freeze
11
11
 
12
- # For JRuby, TruffleRuby, and Wasm, fallback to Ruby implementation.
13
- if /java|wasm/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby'
14
- class << self
15
- def build(escape_attrs, quote, format, boolean_attributes, object_ref, *hashes)
16
- hashes << Haml::ObjectRef.parse(object_ref) if object_ref
17
- buf = []
18
- hash = merge_all_attrs(hashes)
19
-
20
- keys = hash.keys.sort!
21
- keys.each do |key|
22
- case key
23
- when 'id'.freeze
24
- buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
25
- when 'class'.freeze
26
- buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
27
- when 'data'.freeze
28
- buf << build_data(escape_attrs, quote, *hash[key])
29
- when *boolean_attributes, /\Adata-/
30
- build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
31
- else
32
- buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
33
- end
12
+ class << self
13
+ def build(escape_attrs, quote, format, boolean_attributes, object_ref, *hashes)
14
+ hashes << Haml::ObjectRef.parse(object_ref) if object_ref
15
+ buf = []
16
+ hash = merge_all_attrs(hashes)
17
+
18
+ keys = hash.keys.sort!
19
+ keys.each do |key|
20
+ case key
21
+ when 'id'.freeze
22
+ buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
23
+ when 'class'.freeze
24
+ buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
25
+ when 'data'.freeze
26
+ buf << build_data(escape_attrs, quote, *hash[key])
27
+ when *boolean_attributes, /\Adata-/
28
+ build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
29
+ else
30
+ buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
34
31
  end
35
- buf.join
36
32
  end
33
+ buf.join
34
+ end
37
35
 
38
- def build_id(escape_attrs, *values)
39
- escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
40
- end
36
+ def build_id(escape_attrs, *values)
37
+ escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
38
+ end
41
39
 
42
- def build_class(escape_attrs, *values)
43
- if values.size == 1
44
- value = values.first
45
- case
46
- when value.is_a?(String)
47
- # noop
48
- when value.is_a?(Array)
49
- value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
50
- when value
51
- value = value.to_s
52
- else
53
- return ''
54
- end
55
- return escape_html(escape_attrs, value)
40
+ def build_class(escape_attrs, *values)
41
+ if values.size == 1
42
+ value = values.first
43
+ case
44
+ when value.is_a?(String)
45
+ # noop
46
+ when value.is_a?(Array)
47
+ value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
48
+ when value
49
+ value = value.to_s
50
+ else
51
+ return ''
56
52
  end
53
+ return escape_html(escape_attrs, value)
54
+ end
57
55
 
58
- classes = []
59
- values.each do |value|
60
- case
61
- when value.is_a?(String)
62
- classes += value.split(' ')
63
- when value.is_a?(Array)
64
- classes += value.select { |v| v }
65
- when value
66
- classes << value.to_s
67
- end
56
+ classes = []
57
+ values.each do |value|
58
+ case
59
+ when value.is_a?(String)
60
+ classes += value.split(' ')
61
+ when value.is_a?(Array)
62
+ classes += value.select { |v| v }
63
+ when value
64
+ classes << value.to_s
68
65
  end
69
- escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' '))
70
66
  end
67
+ escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' '))
68
+ end
71
69
 
72
- def build_data(escape_attrs, quote, *hashes)
73
- build_data_attribute(:data, escape_attrs, quote, *hashes)
74
- end
70
+ def build_data(escape_attrs, quote, *hashes)
71
+ build_data_attribute(:data, escape_attrs, quote, *hashes)
72
+ end
75
73
 
76
- def build_aria(escape_attrs, quote, *hashes)
77
- build_data_attribute(:aria, escape_attrs, quote, *hashes)
78
- end
74
+ def build_aria(escape_attrs, quote, *hashes)
75
+ build_data_attribute(:aria, escape_attrs, quote, *hashes)
76
+ end
79
77
 
80
- private
78
+ private
81
79
 
82
- def build_data_attribute(key, escape_attrs, quote, *hashes)
83
- attrs = []
84
- if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
85
- data_value = merge_all_attrs(hashes)
86
- else
87
- data_value = hashes.last
88
- end
89
- hash = flatten_attributes(key => data_value)
90
-
91
- hash.sort_by(&:first).each do |key, value|
92
- case value
93
- when true
94
- attrs << " #{key}"
95
- when nil, false
96
- # noop
97
- else
98
- attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
99
- end
100
- end
101
- attrs.join
80
+ def build_data_attribute(key, escape_attrs, quote, *hashes)
81
+ attrs = []
82
+ if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
83
+ data_value = merge_all_attrs(hashes)
84
+ else
85
+ data_value = hashes.last
102
86
  end
87
+ hash = flatten_attributes(key => data_value)
103
88
 
104
- def flatten_attributes(attributes)
105
- flattened = {}
106
-
107
- attributes.each do |key, value|
108
- case value
109
- when attributes
110
- when Hash
111
- flatten_attributes(value).each do |k, v|
112
- if k.nil?
113
- flattened[key] = v
114
- else
115
- flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
116
- end
117
- end
118
- else
119
- flattened[key] = value if value
120
- end
89
+ hash.sort_by(&:first).each do |key, value|
90
+ case value
91
+ when true
92
+ attrs << " #{key}"
93
+ when nil, false
94
+ # noop
95
+ else
96
+ attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
121
97
  end
122
- flattened
123
98
  end
99
+ attrs.join
100
+ end
101
+
102
+ def flatten_attributes(attributes)
103
+ flattened = {}
124
104
 
125
- def merge_all_attrs(hashes)
126
- merged = {}
127
- hashes.each do |hash|
128
- hash.each do |key, value|
129
- key = key.to_s
130
- case key
131
- when 'id'.freeze, 'class'.freeze, 'data'.freeze
132
- merged[key] ||= []
133
- merged[key] << value
105
+ attributes.each do |key, value|
106
+ case value
107
+ when attributes
108
+ when Hash
109
+ flatten_attributes(value).each do |k, v|
110
+ if k.nil?
111
+ flattened[key] = v
134
112
  else
135
- merged[key] = value
113
+ flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
136
114
  end
137
115
  end
116
+ else
117
+ flattened[key] = value if value
138
118
  end
139
- merged
140
119
  end
120
+ flattened
121
+ end
141
122
 
142
- def build_boolean!(escape_attrs, quote, format, buf, key, value)
143
- case value
144
- when true
145
- case format
146
- when :xhtml
147
- buf << " #{key}=#{quote}#{key}#{quote}"
123
+ def merge_all_attrs(hashes)
124
+ merged = {}
125
+ hashes.each do |hash|
126
+ unless hash.is_a?(Hash)
127
+ raise ArgumentError, "Non-hash object is given to attributes!"
128
+ end
129
+ hash.each do |key, value|
130
+ key = key.to_s
131
+ case key
132
+ when 'id'.freeze, 'class'.freeze, 'data'.freeze
133
+ merged[key] ||= []
134
+ merged[key] << value
148
135
  else
149
- buf << " #{key}"
136
+ merged[key] = value
150
137
  end
151
- when false, nil
152
- # omitted
153
- else
154
- buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
155
138
  end
156
139
  end
140
+ merged
141
+ end
157
142
 
158
- def escape_html(escape_attrs, str)
159
- if escape_attrs
160
- Haml::Util.escape_html(str)
143
+ def build_boolean!(escape_attrs, quote, format, buf, key, value)
144
+ case value
145
+ when true
146
+ case format
147
+ when :xhtml
148
+ buf << " #{key}=#{quote}#{key}#{quote}"
161
149
  else
162
- str
150
+ buf << " #{key}"
163
151
  end
152
+ when false, nil
153
+ # omitted
154
+ else
155
+ buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
156
+ end
157
+ end
158
+
159
+ def escape_html(escape_attrs, str)
160
+ if escape_attrs
161
+ Haml::Util.escape_html(str)
162
+ else
163
+ str
164
164
  end
165
165
  end
166
- else
167
- # Haml::AttributeBuilder.build
168
- # Haml::AttributeBuilder.build_id
169
- # Haml::AttributeBuilder.build_class
170
- # Haml::AttributeBuilder.build_data
171
- # Haml::AttributeBuilder.build_aria
172
- require 'haml/haml'
173
166
  end
174
167
  end
@@ -48,6 +48,11 @@ module Haml
48
48
  Engine.new(options).call(source)
49
49
  end
50
50
 
51
+ # Rails Turbo looks for this
52
+ def default_format
53
+ :html
54
+ end
55
+
51
56
  def supports_streaming?
52
57
  RailsTemplate.options[:streaming]
53
58
  end
data/lib/haml/util.rb CHANGED
@@ -14,15 +14,16 @@ module Haml
14
14
  module Util
15
15
  extend self
16
16
 
17
- # For JRuby, TruffleRuby, and Wasm, fallback to Ruby implementation.
18
- if /java|wasm/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby'
17
+ begin # Ruby 3.2+ or ERB 4+
18
+ require 'erb/escape'
19
+
20
+ define_singleton_method(:escape_html, ERB::Escape.instance_method(:html_escape))
21
+ rescue LoadError
19
22
  require 'cgi/escape'
20
23
 
21
24
  def self.escape_html(html)
22
25
  CGI.escapeHTML(html.to_s)
23
26
  end
24
- else
25
- require 'haml/haml' # Haml::Util.escape_html
26
27
  end
27
28
 
28
29
  # TODO: Remove unescape_interpolation's workaround and get rid of `respond_to?`.
data/lib/haml/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Haml
3
- VERSION = '6.1.2'
3
+ VERSION = '6.2.0'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.2
4
+ version: 6.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Natalie Weizenbaum
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: exe
14
14
  cert_chain: []
15
- date: 2023-08-12 00:00:00.000000000 Z
15
+ date: 2023-09-27 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: temple
@@ -182,20 +182,6 @@ dependencies:
182
182
  - - ">="
183
183
  - !ruby/object:Gem::Version
184
184
  version: '0'
185
- - !ruby/object:Gem::Dependency
186
- name: rake-compiler
187
- requirement: !ruby/object:Gem::Requirement
188
- requirements:
189
- - - ">="
190
- - !ruby/object:Gem::Version
191
- version: '0'
192
- type: :development
193
- prerelease: false
194
- version_requirements: !ruby/object:Gem::Requirement
195
- requirements:
196
- - - ">="
197
- - !ruby/object:Gem::Version
198
- version: '0'
199
185
  - !ruby/object:Gem::Dependency
200
186
  name: sass
201
187
  requirement: !ruby/object:Gem::Requirement
@@ -258,8 +244,7 @@ email:
258
244
  - ronnie@dio.jp
259
245
  executables:
260
246
  - haml
261
- extensions:
262
- - ext/haml/extconf.rb
247
+ extensions: []
263
248
  extra_rdoc_files: []
264
249
  files:
265
250
  - ".github/FUNDING.yml"
@@ -280,10 +265,6 @@ files:
280
265
  - bin/stackprof
281
266
  - bin/test
282
267
  - exe/haml
283
- - ext/haml/extconf.rb
284
- - ext/haml/haml.c
285
- - ext/haml/hescape.c
286
- - ext/haml/hescape.h
287
268
  - haml.gemspec
288
269
  - lib/haml.rb
289
270
  - lib/haml/ambles.rb
@@ -356,7 +337,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
356
337
  - !ruby/object:Gem::Version
357
338
  version: '0'
358
339
  requirements: []
359
- rubygems_version: 3.4.1
340
+ rubygems_version: 3.4.10
360
341
  signing_key:
361
342
  specification_version: 4
362
343
  summary: An elegant, structured (X)HTML/XML templating engine.
data/ext/haml/extconf.rb DELETED
@@ -1,10 +0,0 @@
1
- require 'mkmf'
2
-
3
- $CFLAGS << ' -Wall -Wextra'
4
-
5
- $srcs = %w[
6
- haml.c
7
- hescape.c
8
- ]
9
-
10
- create_makefile('haml/haml')
data/ext/haml/haml.c DELETED
@@ -1,537 +0,0 @@
1
- #include <ruby.h>
2
- #include <ruby/encoding.h>
3
- #ifndef TRUFFLERUBY
4
- #include "hescape.h"
5
- #include "string.h"
6
-
7
- VALUE mAttributeBuilder, mObjectRef;
8
- static ID id_flatten, id_keys, id_parse, id_prepend, id_tr, id_uniq_bang;
9
- static ID id_xhtml;
10
-
11
- static VALUE str_aria, str_data, str_equal, str_hyphen, str_space, str_underscore;
12
-
13
- static void
14
- delete_falsey_values(VALUE values)
15
- {
16
- VALUE value;
17
- long i;
18
-
19
- for (i = RARRAY_LEN(values) - 1; 0 <= i; i--) {
20
- value = rb_ary_entry(values, i);
21
- if (!RTEST(value)) {
22
- rb_ary_delete_at(values, i);
23
- }
24
- }
25
- }
26
-
27
- static int
28
- str_eq(VALUE str, const char *cstr, long n)
29
- {
30
- return RSTRING_LEN(str) == n && memcmp(RSTRING_PTR(str), cstr, n) == 0;
31
- }
32
-
33
- static VALUE
34
- to_s(VALUE value)
35
- {
36
- return rb_convert_type(value, T_STRING, "String", "to_s");
37
- }
38
-
39
- static VALUE
40
- hyphenate(VALUE str)
41
- {
42
- long i;
43
-
44
- if (OBJ_FROZEN(str)) str = rb_str_dup(str);
45
-
46
- for (i = 0; i < RSTRING_LEN(str); i++) {
47
- if (RSTRING_PTR(str)[i] == '_') {
48
- rb_str_update(str, i, 1, str_hyphen);
49
- }
50
- }
51
- return str;
52
- }
53
-
54
- static VALUE
55
- escape_html(VALUE str)
56
- {
57
- char *buf;
58
- unsigned int size;
59
- Check_Type(str, T_STRING);
60
-
61
- size = hesc_escape_html(&buf, RSTRING_PTR(str), RSTRING_LEN(str));
62
- if (size > RSTRING_LEN(str)) {
63
- str = rb_enc_str_new(buf, size, rb_utf8_encoding());
64
- free((void *)buf);
65
- }
66
-
67
- return str;
68
- }
69
-
70
- static VALUE
71
- escape_attribute(VALUE escape_attrs, VALUE str)
72
- {
73
- if (RTEST(escape_attrs)) {
74
- return escape_html(str);
75
- } else {
76
- return str;
77
- }
78
- }
79
-
80
- static VALUE
81
- rb_escape_html(RB_UNUSED_VAR(VALUE self), VALUE value)
82
- {
83
- return escape_html(to_s(value));
84
- }
85
-
86
- static VALUE
87
- haml_build_id(VALUE escape_attrs, VALUE values)
88
- {
89
- VALUE attr_value;
90
-
91
- values = rb_funcall(values, id_flatten, 0);
92
- delete_falsey_values(values);
93
-
94
- attr_value = rb_ary_join(values, str_underscore);
95
- return escape_attribute(escape_attrs, attr_value);
96
- }
97
-
98
- static VALUE
99
- haml_build_single_class(VALUE escape_attrs, VALUE value)
100
- {
101
- switch (TYPE(value)) {
102
- case T_STRING:
103
- break;
104
- case T_ARRAY:
105
- value = rb_funcall(value, id_flatten, 0);
106
- delete_falsey_values(value);
107
- value = rb_ary_join(value, str_space);
108
- break;
109
- default:
110
- if (RTEST(value)) {
111
- value = to_s(value);
112
- } else {
113
- return rb_str_new_cstr("");
114
- }
115
- break;
116
- }
117
- return escape_attribute(escape_attrs, value);
118
- }
119
-
120
- static VALUE
121
- haml_build_multi_class(VALUE escape_attrs, VALUE values)
122
- {
123
- long i, j;
124
- VALUE value, buf;
125
-
126
- buf = rb_ary_new2(RARRAY_LEN(values));
127
-
128
- for (i = 0; i < RARRAY_LEN(values); i++) {
129
- value = rb_ary_entry(values, i);
130
- switch (TYPE(value)) {
131
- case T_STRING:
132
- rb_ary_concat(buf, rb_str_split(value, " "));
133
- break;
134
- case T_ARRAY:
135
- value = rb_funcall(value, id_flatten, 0);
136
- delete_falsey_values(value);
137
- for (j = 0; j < RARRAY_LEN(value); j++) {
138
- rb_ary_push(buf, to_s(rb_ary_entry(value, j)));
139
- }
140
- break;
141
- default:
142
- if (RTEST(value)) {
143
- rb_ary_push(buf, to_s(value));
144
- }
145
- break;
146
- }
147
- }
148
-
149
- rb_funcall(buf, id_uniq_bang, 0);
150
-
151
- return escape_attribute(escape_attrs, rb_ary_join(buf, str_space));
152
- }
153
-
154
- static VALUE
155
- haml_build_class(VALUE escape_attrs, VALUE array)
156
- {
157
- if (RARRAY_LEN(array) == 1) {
158
- return haml_build_single_class(escape_attrs, rb_ary_entry(array, 0));
159
- } else {
160
- return haml_build_multi_class(escape_attrs, array);
161
- }
162
- }
163
-
164
- struct merge_data_attrs_var {
165
- VALUE merged;
166
- VALUE key_str;
167
- };
168
-
169
- static int
170
- merge_data_attrs_i(VALUE key, VALUE value, VALUE ptr)
171
- {
172
- struct merge_data_attrs_var *arg = (struct merge_data_attrs_var *)ptr;
173
- VALUE merged = arg->merged;
174
- VALUE key_str = arg->key_str;
175
-
176
- if (NIL_P(key)) {
177
- rb_hash_aset(merged, key_str, value);
178
- } else {
179
- key = rb_str_concat(rb_str_concat(rb_str_dup(key_str), rb_str_new_cstr("-")), to_s(key));
180
- rb_hash_aset(merged, key, value);
181
- }
182
- return ST_CONTINUE;
183
- }
184
-
185
- static VALUE
186
- merge_data_attrs(VALUE values, VALUE key_str)
187
- {
188
- long i;
189
- VALUE value, merged = rb_hash_new();
190
-
191
- for (i = 0; i < RARRAY_LEN(values); i++) {
192
- struct merge_data_attrs_var arg;
193
- arg.merged = merged;
194
- arg.key_str = key_str;
195
-
196
- value = rb_ary_entry(values, i);
197
- switch (TYPE(value)) {
198
- case T_HASH:
199
- rb_hash_foreach(value, merge_data_attrs_i, (VALUE)&arg);
200
- break;
201
- default:
202
- rb_hash_aset(merged, key_str, value);
203
- break;
204
- }
205
- }
206
- return merged;
207
- }
208
-
209
- struct flatten_data_attrs_i2_arg {
210
- VALUE flattened;
211
- VALUE key;
212
- };
213
-
214
- static int
215
- flatten_data_attrs_i2(VALUE k, VALUE v, VALUE ptr)
216
- {
217
- VALUE key;
218
- struct flatten_data_attrs_i2_arg *arg = (struct flatten_data_attrs_i2_arg *)ptr;
219
-
220
- if (!RTEST(v)) return ST_CONTINUE;
221
-
222
- if (k == Qnil) {
223
- rb_hash_aset(arg->flattened, arg->key, v);
224
- } else {
225
- key = rb_str_dup(arg->key);
226
- rb_str_cat(key, "-", 1);
227
- rb_str_concat(key, to_s(k));
228
-
229
- rb_hash_aset(arg->flattened, key, v);
230
- }
231
- return ST_CONTINUE;
232
- }
233
-
234
- static VALUE flatten_data_attrs(VALUE attrs);
235
-
236
- static int
237
- flatten_data_attrs_i(VALUE key, VALUE value, VALUE flattened)
238
- {
239
- struct flatten_data_attrs_i2_arg arg;
240
- key = hyphenate(to_s(key));
241
-
242
- switch (TYPE(value)) {
243
- case T_HASH:
244
- value = flatten_data_attrs(value);
245
- arg.key = key;
246
- arg.flattened = flattened;
247
- rb_hash_foreach(value, flatten_data_attrs_i2, (VALUE)(&arg));
248
- break;
249
- default:
250
- if (RTEST(value)) rb_hash_aset(flattened, key, value);
251
- break;
252
- }
253
- return ST_CONTINUE;
254
- }
255
-
256
- static VALUE
257
- flatten_data_attrs(VALUE attrs)
258
- {
259
- VALUE flattened = rb_hash_new();
260
- rb_hash_foreach(attrs, flatten_data_attrs_i, flattened);
261
-
262
- return flattened;
263
- }
264
-
265
- static VALUE
266
- haml_build_data(VALUE escape_attrs, VALUE quote, VALUE values, VALUE key_str)
267
- {
268
- long i;
269
- VALUE attrs, buf, keys, key, value;
270
-
271
- attrs = merge_data_attrs(values, key_str);
272
- attrs = flatten_data_attrs(attrs);
273
- keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
274
- buf = rb_str_new("", 0);
275
-
276
- for (i = 0; i < RARRAY_LEN(keys); i++) {
277
- key = rb_ary_entry(keys, i);
278
- value = rb_hash_aref(attrs, key);
279
-
280
- switch (value) {
281
- case Qtrue:
282
- rb_str_concat(buf, str_space);
283
- rb_str_concat(buf, key);
284
- break;
285
- case Qnil:
286
- break; // noop
287
- case Qfalse:
288
- break; // noop
289
- default:
290
- rb_str_concat(buf, str_space);
291
- rb_str_concat(buf, key);
292
- rb_str_concat(buf, str_equal);
293
- rb_str_concat(buf, quote);
294
- rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
295
- rb_str_concat(buf, quote);
296
- break;
297
- }
298
- }
299
-
300
- return buf;
301
- }
302
-
303
- static VALUE
304
- parse_object_ref(VALUE object_ref)
305
- {
306
- return rb_funcall(mObjectRef, id_parse, 1, object_ref);
307
- }
308
-
309
- static int
310
- merge_all_attrs_i(VALUE key, VALUE value, VALUE merged)
311
- {
312
- VALUE array;
313
-
314
- key = to_s(key);
315
- if (str_eq(key, "id", 2) || str_eq(key, "class", 5) || str_eq(key, "data", 4) || str_eq(key, "aria", 4)) {
316
- array = rb_hash_aref(merged, key);
317
- if (NIL_P(array)) {
318
- array = rb_ary_new2(1);
319
- rb_hash_aset(merged, key, array);
320
- }
321
- rb_ary_push(array, value);
322
- } else {
323
- rb_hash_aset(merged, key, value);
324
- }
325
- return ST_CONTINUE;
326
- }
327
-
328
- static VALUE
329
- merge_all_attrs(VALUE hashes)
330
- {
331
- long i;
332
- VALUE hash, merged = rb_hash_new();
333
-
334
- for (i = 0; i < RARRAY_LEN(hashes); i++) {
335
- hash = rb_ary_entry(hashes, i);
336
- if (!RB_TYPE_P(hash, T_HASH)) {
337
- rb_raise(rb_eArgError, "Non-hash object is given to attributes!");
338
- }
339
- rb_hash_foreach(hash, merge_all_attrs_i, merged);
340
- }
341
- return merged;
342
- }
343
-
344
- int
345
- is_boolean_attribute(VALUE key, VALUE boolean_attributes)
346
- {
347
- if (str_eq(rb_str_substr(key, 0, 5), "data-", 5)) return 1;
348
- if (str_eq(rb_str_substr(key, 0, 5), "aria-", 5)) return 1;
349
- return RTEST(rb_ary_includes(boolean_attributes, key));
350
- }
351
-
352
- void
353
- haml_build_for_id(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
354
- {
355
- rb_str_cat(buf, " id=", 4);
356
- rb_str_concat(buf, quote);
357
- rb_str_concat(buf, haml_build_id(escape_attrs, values));
358
- rb_str_concat(buf, quote);
359
- }
360
-
361
- void
362
- haml_build_for_class(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
363
- {
364
- rb_str_cat(buf, " class=", 7);
365
- rb_str_concat(buf, quote);
366
- rb_str_concat(buf, haml_build_class(escape_attrs, values));
367
- rb_str_concat(buf, quote);
368
- }
369
-
370
- void
371
- haml_build_for_data(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
372
- {
373
- rb_str_concat(buf, haml_build_data(escape_attrs, quote, values, str_data));
374
- }
375
-
376
- void
377
- haml_build_for_aria(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE values)
378
- {
379
- rb_str_concat(buf, haml_build_data(escape_attrs, quote, values, str_aria));
380
- }
381
-
382
- void
383
- haml_build_for_others(VALUE escape_attrs, VALUE quote, VALUE buf, VALUE key, VALUE value)
384
- {
385
- rb_str_cat(buf, " ", 1);
386
- rb_str_concat(buf, key);
387
- rb_str_cat(buf, "=", 1);
388
- rb_str_concat(buf, quote);
389
- rb_str_concat(buf, escape_attribute(escape_attrs, to_s(value)));
390
- rb_str_concat(buf, quote);
391
- }
392
-
393
- void
394
- haml_build_for_boolean(VALUE escape_attrs, VALUE quote, VALUE format, VALUE buf, VALUE key, VALUE value)
395
- {
396
- switch (value) {
397
- case Qtrue:
398
- rb_str_cat(buf, " ", 1);
399
- rb_str_concat(buf, key);
400
- if ((TYPE(format) == T_SYMBOL || TYPE(format) == T_STRING) && rb_to_id(format) == id_xhtml) {
401
- rb_str_cat(buf, "=", 1);
402
- rb_str_concat(buf, quote);
403
- rb_str_concat(buf, key);
404
- rb_str_concat(buf, quote);
405
- }
406
- break;
407
- case Qfalse:
408
- break; // noop
409
- case Qnil:
410
- break; // noop
411
- default:
412
- haml_build_for_others(escape_attrs, quote, buf, key, value);
413
- break;
414
- }
415
- }
416
-
417
- static VALUE
418
- haml_build(VALUE escape_attrs, VALUE quote, VALUE format, VALUE boolean_attributes, VALUE object_ref, VALUE hashes)
419
- {
420
- long i;
421
- VALUE attrs, buf, key, keys, value;
422
-
423
- if (!NIL_P(object_ref)) rb_ary_push(hashes, parse_object_ref(object_ref));
424
- attrs = merge_all_attrs(hashes);
425
- buf = rb_str_new("", 0);
426
- keys = rb_ary_sort_bang(rb_funcall(attrs, id_keys, 0));
427
-
428
- for (i = 0; i < RARRAY_LEN(keys); i++) {
429
- key = rb_ary_entry(keys, i);
430
- value = rb_hash_aref(attrs, key);
431
- if (str_eq(key, "id", 2)) {
432
- haml_build_for_id(escape_attrs, quote, buf, value);
433
- } else if (str_eq(key, "class", 5)) {
434
- haml_build_for_class(escape_attrs, quote, buf, value);
435
- } else if (str_eq(key, "data", 4)) {
436
- haml_build_for_data(escape_attrs, quote, buf, value);
437
- } else if (str_eq(key, "aria", 4)) {
438
- haml_build_for_aria(escape_attrs, quote, buf, value);
439
- } else if (is_boolean_attribute(key, boolean_attributes)) {
440
- haml_build_for_boolean(escape_attrs, quote, format, buf, key, value);
441
- } else {
442
- haml_build_for_others(escape_attrs, quote, buf, key, value);
443
- }
444
- }
445
-
446
- return buf;
447
- }
448
-
449
- static VALUE
450
- rb_haml_build_id(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
451
- {
452
- VALUE array;
453
-
454
- rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
455
- rb_scan_args(argc - 1, argv + 1, "*", &array);
456
-
457
- return haml_build_id(argv[0], array);
458
- }
459
-
460
- static VALUE
461
- rb_haml_build_class(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
462
- {
463
- VALUE array;
464
-
465
- rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
466
- rb_scan_args(argc - 1, argv + 1, "*", &array);
467
-
468
- return haml_build_class(argv[0], array);
469
- }
470
-
471
- static VALUE
472
- rb_haml_build_aria(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
473
- {
474
- VALUE array;
475
-
476
- rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
477
- rb_scan_args(argc - 2, argv + 2, "*", &array);
478
-
479
- return haml_build_data(argv[0], argv[1], array, str_aria);
480
- }
481
-
482
- static VALUE
483
- rb_haml_build_data(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
484
- {
485
- VALUE array;
486
-
487
- rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
488
- rb_scan_args(argc - 2, argv + 2, "*", &array);
489
-
490
- return haml_build_data(argv[0], argv[1], array, str_data);
491
- }
492
-
493
- static VALUE
494
- rb_haml_build(int argc, VALUE *argv, RB_UNUSED_VAR(VALUE self))
495
- {
496
- VALUE array;
497
-
498
- rb_check_arity(argc, 5, UNLIMITED_ARGUMENTS);
499
- rb_scan_args(argc - 5, argv + 5, "*", &array);
500
-
501
- return haml_build(argv[0], argv[1], argv[2], argv[3], argv[4], array);
502
- }
503
-
504
- void
505
- Init_haml(void)
506
- {
507
- VALUE mHaml, mUtil;
508
-
509
- mHaml = rb_define_module("Haml");
510
- mObjectRef = rb_define_module_under(mHaml, "ObjectRef");
511
- mUtil = rb_define_module_under(mHaml, "Util");
512
- mAttributeBuilder = rb_define_module_under(mHaml, "AttributeBuilder");
513
-
514
- rb_define_singleton_method(mUtil, "escape_html", rb_escape_html, 1);
515
- rb_define_singleton_method(mAttributeBuilder, "build", rb_haml_build, -1);
516
- rb_define_singleton_method(mAttributeBuilder, "build_id", rb_haml_build_id, -1);
517
- rb_define_singleton_method(mAttributeBuilder, "build_class", rb_haml_build_class, -1);
518
- rb_define_singleton_method(mAttributeBuilder, "build_aria", rb_haml_build_aria, -1);
519
- rb_define_singleton_method(mAttributeBuilder, "build_data", rb_haml_build_data, -1);
520
-
521
- id_flatten = rb_intern("flatten");
522
- id_keys = rb_intern("keys");
523
- id_parse = rb_intern("parse");
524
- id_prepend = rb_intern("prepend");
525
- id_tr = rb_intern("tr");
526
- id_uniq_bang = rb_intern("uniq!");
527
- id_xhtml = rb_intern("xhtml");
528
-
529
- // Consider using rb_interned_str() once we stop supporting Ruby 2.7.
530
- rb_gc_register_mark_object(str_aria = rb_obj_freeze(rb_str_new_cstr("aria")));
531
- rb_gc_register_mark_object(str_data = rb_obj_freeze(rb_str_new_cstr("data")));
532
- rb_gc_register_mark_object(str_equal = rb_obj_freeze(rb_str_new_cstr("=")));
533
- rb_gc_register_mark_object(str_hyphen = rb_obj_freeze(rb_str_new_cstr("-")));
534
- rb_gc_register_mark_object(str_space = rb_obj_freeze(rb_str_new_cstr(" ")));
535
- rb_gc_register_mark_object(str_underscore = rb_obj_freeze(rb_str_new_cstr("_")));
536
- }
537
- #endif
data/ext/haml/hescape.c DELETED
@@ -1,108 +0,0 @@
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
- "&quot;",
9
- "&amp;",
10
- "&#39;",
11
- "&lt;",
12
- "&gt;",
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 (&quot;)
23
- * & (38) => 2 (&amp;)
24
- * ' (39) => 3 (&#39;)
25
- * < (60) => 4 (&lt;)
26
- * > (62) => 5 (&gt;)
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
- }
data/ext/haml/hescape.h DELETED
@@ -1,20 +0,0 @@
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
- * " => &quot;
11
- * & => &amp;
12
- * ' => &#39;
13
- * < => &lt;
14
- * > => &gt;
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