haml 5.1.1 → 5.2.2

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: b452821b37a39c122c73b034833f334367ea652bcbc9c8166fb4b146622766a2
4
- data.tar.gz: 41b11d87fa61bc35507519f25843284e07a6610bcc65e1beef5302590d925556
3
+ metadata.gz: ec6cbb2e4023f397f1d7b6d84f06d78ab492a61e88c3f16496f39d0baeb47a83
4
+ data.tar.gz: 004c2dd34697cb61a8c12854bf4b99abb3cab5195f28922b813ee299225e7663
5
5
  SHA512:
6
- metadata.gz: c68926aed4f1615985b6da508e8eafb4951162ab1064b94f5d2c17978390d82d2912098bdf74b90acfea1df1a21d711c0e3d14315394ebc7fa60341dd2c61975
7
- data.tar.gz: 499700814e3f72d7d7f033b80b9cd6b701ef07bcf46f1399ece0cf0dad5ddea6bbdff912775c3cd4e1506735cb7fd85cd1666903e69706968874b80788a2a9a7
6
+ metadata.gz: a7430b4e42cf809f847448a9e04623b4b58878e44facedef5e43714820e8068f0bb853772564d5545936cdad8346f0c33abfc11642a3737d91c9a1f6242b3e41
7
+ data.tar.gz: 8a91df0cb185014512ee473a21755ba41edb06e835b29740e8e46c76287a81405b2706d8a10ea148893a9429de306c67584ac1c286637c0812a5562cf149431b
@@ -0,0 +1,36 @@
1
+ name: test
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ pull_request:
7
+ types:
8
+ - opened
9
+ - synchronize
10
+ - reopened
11
+ jobs:
12
+ test:
13
+ name: 'Ruby: ${{ matrix.ruby }}, Rails: ${{ matrix.rails }}'
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby: [2.6, 2.7, 3.0, jruby-9.2]
19
+ rails: [5.2.x, 6.0.x, 6.1.x, rails-edge]
20
+ steps:
21
+ - uses: actions/checkout@v2
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+ - uses: actions/cache@v2
27
+ with:
28
+ path: vendor/bundle
29
+ key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }}
30
+ restore-keys: ${{ runner.os }}-gems-
31
+ - name: bundle install --gemfile=test/gemfiles/Gemfile.rails-${{matrix.rails}}.x
32
+ run: bundle config path vendor/bundle && bundle install -j$(nproc) --retry 3
33
+ - name: rake test
34
+ run: bundle exec rake test submodules
35
+ env:
36
+ RUBYOPT: "--enable-frozen-string-literal"
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /.idea
1
2
  /.yardoc
2
3
  /coverage
3
4
  /doc
data/CHANGELOG.md CHANGED
@@ -1,11 +1,42 @@
1
1
  # Haml Changelog
2
2
 
3
+ ## 5.2.2
4
+ Released on July 27, 2021
5
+ ([diff](https://github.com/haml/haml/compare/v5.2.1...v5.2.2)).
6
+
7
+ * Support for adding Annotations to Haml output (a Rails feature 6.1+)
8
+ * Expanded test matrix to include Ruby 3.0 and Rails 6.1
9
+ * Only testing Ruby 2.7+ and Rails 5.2+
10
+
11
+ ## 5.2.1
12
+
13
+ Released on November 30, 2020
14
+ ([diff](https://github.com/haml/haml/compare/v5.2.0...v5.2.1)).
15
+
16
+ * Add in improved "multiline" support for attributes [#1043](https://github.com/haml/haml/issues/1043)
17
+
18
+ ## 5.2
19
+
20
+ Released on September 28, 2020
21
+ ([diff](https://github.com/haml/haml/compare/v5.1.2...v5.2.0)).
22
+
23
+ * Fix crash in the attribute optimizer when `#inspect` is overridden in TrueClass / FalseClass [#972](https://github.com/haml/haml/issues/972)
24
+ * Do not HTML-escape templates that are declared to be plaintext [#1014](https://github.com/haml/haml/issues/1014) (Thanks [@cesarizu](https://github.com/cesarizu))
25
+ * Class names are no longer ordered alphabetically, and now follow a new specification as laid out in REFERENCE [#306](https://github.com/haml/haml/issues/306)
26
+
27
+ ## 5.1.2
28
+
29
+ Released on August 6, 2019
30
+ ([diff](https://github.com/haml/haml/compare/v5.1.1...v5.1.2)).
31
+
32
+ * Fix crash in some environments such as New Relic by unfreezing string literals for ParseNode#inspect. [#1016](https://github.com/haml/haml/pull/1016) (thanks [Jalyna](https://github.com/jalyna))
33
+
3
34
  ## 5.1.1
4
35
 
5
36
  Released on May 25, 2019
6
37
  ([diff](https://github.com/haml/haml/compare/v5.1.0...v5.1.1)).
7
38
 
8
- * Fix NameError bug for that happens on ruby 2.6.1-2.6.3 + haml 5.1.0 + rails 4.2.x + erubi. (Akira Matsuda)
39
+ * Fix NameError bug that happens on ruby 2.6.1-2.6.3 + haml 5.1.0 + rails < 5.1 + erubi. (Akira Matsuda)
9
40
 
10
41
  ## 5.1.0
11
42
 
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ gemspec
3
3
 
4
4
  gem "m"
5
5
  gem "pry"
6
+ gem "simplecov"
6
7
 
7
8
  group :docs do
8
9
  gem "yard"
@@ -13,7 +14,3 @@ end
13
14
  platform :mri do
14
15
  gem "ruby-prof"
15
16
  end
16
-
17
- platform :mri_21 do
18
- gem "simplecov"
19
- end
data/README.md CHANGED
@@ -1,9 +1,8 @@
1
1
  # Haml
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/haml.svg)](http://rubygems.org/gems/haml)
4
- [![Build Status](https://travis-ci.org/haml/haml.svg?branch=master)](http://travis-ci.org/haml/haml)
4
+ [![Build Status](https://travis-ci.org/haml/haml.svg?branch=main)](http://travis-ci.org/haml/haml)
5
5
  [![Code Climate](https://codeclimate.com/github/haml/haml/badges/gpa.svg)](https://codeclimate.com/github/haml/haml)
6
- [![Coverage Status](http://img.shields.io/coveralls/haml/haml.svg)](https://coveralls.io/r/haml/haml)
7
6
  [![Inline docs](http://inch-ci.org/github/haml/haml.png)](http://inch-ci.org/github/haml/haml)
8
7
 
9
8
  Haml is a templating engine for HTML. It's designed to make it both easier and
@@ -11,6 +10,13 @@ more pleasant to write HTML documents, by eliminating redundancy, reflecting the
11
10
  underlying structure that the document represents, and providing an elegant syntax
12
11
  that's both powerful and easy to understand.
13
12
 
13
+ ### Supported Versions
14
+
15
+ * Ruby 2.6+
16
+ * Rails 5.1+
17
+
18
+ Other versions may likely work, but we don't test against them.
19
+
14
20
  ## Basic Usage
15
21
 
16
22
  Haml can be used from the command line or as part of a Ruby web framework. The
@@ -32,7 +38,7 @@ to compile it to HTML. For more information on these commands, check out
32
38
  haml --help
33
39
  ~~~
34
40
 
35
- To use Haml programatically, check out the [YARD documentation](http://haml.info/docs/yardoc/).
41
+ To use Haml programmatically, check out the [YARD documentation](http://haml.info/docs/yardoc/).
36
42
 
37
43
  ## Using Haml with Rails
38
44
 
@@ -163,35 +169,34 @@ on a specific area:
163
169
  ruby -Itest test/helper_test.rb -n test_buffer_access
164
170
  ~~~
165
171
 
166
- Haml currently supports Ruby 2.0.0 and higher, so please make sure your changes run on 2.0+.
172
+ Haml currently supports Ruby 2.7.0 and higher, so please make sure your changes run on 2.7+.
167
173
 
168
174
  ## Team
169
175
 
170
176
  ### Current Maintainers
171
177
 
172
- * [Akira Matsuda](https://github.com/amatsuda)
173
- * [Matt Wildig](https://github.com/mattwildig)
174
- * [Tee Parham](https://github.com/teeparham)
178
+ * [Hampton Catlin](https://github.com/hcatlin)
175
179
  * [Takashi Kokubun](https://github.com/k0kubun)
180
+ * [Akira Matsuda](https://github.com/amatsuda)
176
181
 
177
182
  ### Alumni
178
183
 
179
184
  Haml was created by [Hampton Catlin](http://hamptoncatlin.com), the author of
180
- the original implementation. Hampton is no longer involved in day-to-day coding,
181
- but still consults on language issues.
185
+ the original implementation.
182
186
 
183
- [Natalie Weizenbaum](http://nex-3.com) was for many years the primary developer
187
+ [Natalie Weizenbaum](https://github.com/nex3) was for many years the primary developer
184
188
  and architect of the "modern" Ruby implementation of Haml.
185
189
 
186
- [Norman Clarke](http://github.com/norman) was the primary maintainer of Haml from 2012 to 2016.
187
-
188
- ## License
190
+ This project's been around for many years, and we have many amazing people who kept the project
191
+ alive! as former maintainers like:
189
192
 
190
- Some of Natalie's work on Haml was supported by Unspace Interactive.
193
+ [Norman Clarke](http://github.com/norman)
194
+ [Matt Wildig](https://github.com/mattwildig)
195
+ [Tee Parham](https://github.com/teeparham)
191
196
 
192
- Beyond that, the implementation is licensed under the MIT License.
197
+ ## License
193
198
 
194
- Copyright (c) 2006-2019 Hampton Catlin, Natalie Weizenbaum and the Haml team
199
+ Copyright (c) 2006-2021 Hampton Catlin, Natalie Weizenbaum and the Haml team
195
200
 
196
201
  Permission is hereby granted, free of charge, to any person obtaining a copy of
197
202
  this software and associated documentation files (the "Software"), to deal in
data/REFERENCE.md CHANGED
@@ -107,13 +107,20 @@ output.
107
107
  In Rails, options can be set by setting the {Haml::Template#options Haml::Template.options}
108
108
  hash in an initializer:
109
109
 
110
- # config/initializers/haml.rb
111
- Haml::Template.options[:format] = :html5
110
+ ```ruby
111
+ # config/initializers/haml.rb
112
+ Haml::Template.options[:format] = :html5
113
+
114
+ # Avoid escaping attributes which are already escaped
115
+ Haml::Template.options[:escape_attrs] = :once
116
+ ```
112
117
 
113
118
  Outside Rails, you can set them by configuring them globally in
114
119
  Haml::Options.defaults:
115
120
 
116
- Haml::Options.defaults[:format] = :html5
121
+ ```ruby
122
+ Haml::Options.defaults[:format] = :html5
123
+ ```
117
124
 
118
125
  In sinatra specifically, you can set them in global config with:
119
126
  ```ruby
@@ -228,15 +235,19 @@ is compiled to:
228
235
  <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'></html>
229
236
 
230
237
  Attribute hashes can also be stretched out over multiple lines to accommodate
231
- many attributes. However, newlines may only be placed immediately after commas.
232
- For example:
238
+ many attributes.
233
239
 
234
- %script{:type => "text/javascript",
235
- :src => "javascripts/script_#{2 + 7}"}
240
+ %script{
241
+ "type": text/javascript",
242
+ "src": javascripts/script_#{2 + 7}",
243
+ "data": {
244
+ "controller": "reporter",
245
+ },
246
+ }
236
247
 
237
248
  is compiled to:
238
249
 
239
- <script src='javascripts/script_9' type='text/javascript'></script>
250
+ <script src='javascripts/script_9' type='text/javascript' data-controller='reporter'></script>
240
251
 
241
252
  #### `:class` and `:id` Attributes {#class-and-id-attributes}
242
253
 
@@ -517,6 +528,24 @@ and is compiled to:
517
528
  </div>
518
529
  </div>
519
530
 
531
+ #### Class Name Merging and Ordering
532
+
533
+ Class names are ordered in the following way:
534
+
535
+ 1) Tag identifiers in order (aka, ".alert.me" => "alert me")
536
+ 2) Classes appearing in HTML-style attributes
537
+ 3) Classes appearing in Hash-style attributes
538
+
539
+ For instance, this is a complicated and unintuitive test case illustrating the ordering
540
+
541
+ .foo.moo{:class => ['bar', 'alpha']}(class='baz')
542
+
543
+ The resulting HTML would be as follows:
544
+
545
+ <div class='foo moo baz bar alpha'></div>
546
+
547
+ *Versions of Haml prior to 5.0 would alphabetically sort class names.*
548
+
520
549
  ### Empty (void) Tags: `/`
521
550
 
522
551
  The forward slash character, when placed at the end of a tag definition, causes
@@ -853,7 +882,7 @@ is compiled to:
853
882
 
854
883
  ## Ruby Evaluation
855
884
 
856
- ### Inserting Ruby: `=`
885
+ ### Inserting Ruby: `=` {#inserting_ruby}
857
886
 
858
887
  The equals character is followed by Ruby code. This code is evaluated and the
859
888
  output is inserted into the document. For example:
@@ -1323,7 +1352,7 @@ that just need a lot of template information.
1323
1352
  So data structures and functions that require lots of arguments
1324
1353
  can be wrapped over multiple lines,
1325
1354
  as long as each line but the last ends in a comma
1326
- (see [Inserting Ruby](#inserting_ruby_)).
1355
+ (see [Inserting Ruby](#inserting_ruby)).
1327
1356
 
1328
1357
  ## Whitespace Preservation
1329
1358
 
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ isolated_test = Rake::TestTask.new do |t|
14
14
  end
15
15
  Rake::TestTask.new do |t|
16
16
  t.libs << 'test'
17
- t.test_files = Dir['test/*_test.rb'] + Dir['test/haml-spec/*_test.rb'] - isolated_test.file_list
17
+ t.test_files = Dir['test/*_test.rb'] + Dir['test/haml-spec/*_test.rb'] + Dir['test/cases/*_test.rb'] - isolated_test.file_list
18
18
  t.warning = true
19
19
  t.verbose = true
20
20
  end
@@ -26,13 +26,6 @@ task :benchmark do
26
26
  sh "ruby benchmark.rb #{ENV['TIMES']}"
27
27
  end
28
28
 
29
- task :set_coverage_env do
30
- ENV["COVERAGE"] = "true"
31
- end
32
-
33
- desc "Run Simplecov"
34
- task :coverage => [:set_coverage_env, :test]
35
-
36
29
  task :submodules do
37
30
  if File.exist?(File.dirname(__FILE__) + "/.git")
38
31
  sh %{git submodule sync}
@@ -88,11 +81,7 @@ task :profile do
88
81
  end
89
82
 
90
83
  def gemfiles
91
- @gemfiles ||= begin
92
- Dir[File.dirname(__FILE__) + '/test/gemfiles/Gemfile.*'].
93
- reject {|f| f =~ /\.lock$/}.
94
- reject {|f| RUBY_VERSION < '1.9.3' && f =~ /Gemfile.rails-(\d+).\d+.x/ && $1.to_i > 3}
95
- end
84
+ @gemfiles ||= Dir[File.dirname(__FILE__) + '/test/gemfiles/Gemfile.*'].reject {|f| f =~ /\.lock$/}
96
85
  end
97
86
 
98
87
  def with_each_gemfile
data/haml.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.license = "MIT"
17
17
  spec.metadata = {
18
18
  "bug_tracker_uri" => "https://github.com/haml/haml/issues",
19
- "changelog_uri" => "https://github.com/haml/haml/blob/master/CHANGELOG.md",
19
+ "changelog_uri" => "https://github.com/haml/haml/blob/main/CHANGELOG.md",
20
20
  "documentation_uri" => "http://haml.info/docs.html",
21
21
  "homepage_uri" => "http://haml.info",
22
22
  "mailing_list_uri" => "https://groups.google.com/forum/?fromgroups#!forum/haml",
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency 'rbench'
33
33
  spec.add_development_dependency 'minitest', '>= 4.0'
34
34
  spec.add_development_dependency 'nokogiri'
35
+ spec.add_development_dependency 'simplecov'
35
36
 
36
37
  spec.description = <<-END
37
38
  Haml (HTML Abstraction Markup Language) is a layer on top of HTML or XML that's
@@ -6,6 +6,17 @@ module Haml
6
6
  INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
7
7
 
8
8
  class << self
9
+ def build(class_id, obj_ref, is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, *attributes_hashes)
10
+ attributes = class_id
11
+ attributes_hashes.each do |old|
12
+ result = {}
13
+ old.each { |k, v| result[k.to_s] = v }
14
+ merge_attributes!(attributes, result)
15
+ end
16
+ merge_attributes!(attributes, parse_object_ref(obj_ref)) if obj_ref
17
+ build_attributes(is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, attributes)
18
+ end
19
+
9
20
  def build_attributes(is_html, attr_wrapper, escape_attrs, hyphenate_data_attrs, attributes = {})
10
21
  # @TODO this is an absolutely ridiculous amount of arguments. At least
11
22
  # some of this needs to be moved into an instance method.
@@ -36,9 +47,9 @@ module Haml
36
47
 
37
48
  value =
38
49
  if escape_attrs == :once
39
- Haml::Helpers.escape_once(value.to_s)
50
+ Haml::Helpers.escape_once_without_haml_xss(value.to_s)
40
51
  elsif escape_attrs
41
- Haml::Helpers.html_escape(value.to_s)
52
+ Haml::Helpers.html_escape_without_haml_xss(value.to_s)
42
53
  else
43
54
  value.to_s
44
55
  end
@@ -126,7 +137,7 @@ module Haml
126
137
  elsif key == 'class'
127
138
  merged_class = filter_and_join(from, ' ')
128
139
  if to && merged_class
129
- merged_class = (merged_class.split(' ') | to.split(' ')).sort.join(' ')
140
+ merged_class = (to.split(' ') | merged_class.split(' ')).join(' ')
130
141
  elsif to || merged_class
131
142
  merged_class ||= to
132
143
  end
@@ -159,6 +170,50 @@ module Haml
159
170
  hash.merge! flatten_data_attributes(v, joined, join_char, seen)
160
171
  end
161
172
  end
173
+
174
+ # Takes an array of objects and uses the class and id of the first
175
+ # one to create an attributes hash.
176
+ # The second object, if present, is used as a prefix,
177
+ # just like you can do with `dom_id()` and `dom_class()` in Rails
178
+ def parse_object_ref(ref)
179
+ prefix = ref[1]
180
+ ref = ref[0]
181
+ # Let's make sure the value isn't nil. If it is, return the default Hash.
182
+ return {} if ref.nil?
183
+ class_name =
184
+ if ref.respond_to?(:haml_object_ref)
185
+ ref.haml_object_ref
186
+ else
187
+ underscore(ref.class)
188
+ end
189
+ ref_id =
190
+ if ref.respond_to?(:to_key)
191
+ key = ref.to_key
192
+ key.join('_') unless key.nil?
193
+ else
194
+ ref.id
195
+ end
196
+ id = "#{class_name}_#{ref_id || 'new'}"
197
+ if prefix
198
+ class_name = "#{ prefix }_#{ class_name}"
199
+ id = "#{ prefix }_#{ id }"
200
+ end
201
+
202
+ { 'id'.freeze => id, 'class'.freeze => class_name }
203
+ end
204
+
205
+ # Changes a word from camel case to underscores.
206
+ # Based on the method of the same name in Rails' Inflector,
207
+ # but copied here so it'll run properly without Rails.
208
+ def underscore(camel_cased_word)
209
+ word = camel_cased_word.to_s.dup
210
+ word.gsub!(/::/, '_')
211
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
212
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
213
+ word.tr!('-', '_')
214
+ word.downcase!
215
+ word
216
+ end
162
217
  end
163
218
  end
164
219
  end
@@ -7,27 +7,7 @@ module Haml
7
7
  # @param type [Symbol] :static or :dynamic
8
8
  # @param key [String]
9
9
  # @param value [String] Actual string value for :static type, value's Ruby literal for :dynamic type.
10
- AttributeValue = Struct.new(:type, :key, :value) do
11
- # @return [String] A Ruby literal of value.
12
- def to_literal
13
- case type
14
- when :static
15
- Haml::Util.inspect_obj(value)
16
- when :dynamic
17
- value
18
- end
19
- end
20
- end
21
-
22
- # Returns a script to render attributes on runtime.
23
- #
24
- # @param attributes [Hash]
25
- # @param object_ref [String,:nil]
26
- # @param dynamic_attributes [DynamicAttributes]
27
- # @return [String] Attributes rendering code
28
- def self.runtime_build(attributes, object_ref, dynamic_attributes)
29
- "_hamlout.attributes(#{Haml::Util.inspect_obj(attributes)}, #{object_ref},#{dynamic_attributes.to_literal})"
30
- end
10
+ AttributeValue = Struct.new(:type, :key, :value)
31
11
 
32
12
  # @param options [Haml::Options]
33
13
  def initialize(options)
@@ -41,16 +21,16 @@ module Haml
41
21
  #
42
22
  # @param attributes [Hash]
43
23
  # @param object_ref [String,:nil]
44
- # @param dynamic_attributes [DynamicAttributes]
24
+ # @param dynamic_attributes [Haml::Parser::DynamicAttributes]
45
25
  # @return [Array] Temple expression
46
26
  def compile(attributes, object_ref, dynamic_attributes)
47
27
  if object_ref != :nil || !AttributeParser.available?
48
- return [:dynamic, AttributeCompiler.runtime_build(attributes, object_ref, dynamic_attributes)]
28
+ return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
49
29
  end
50
30
 
51
31
  parsed_hashes = [dynamic_attributes.new, dynamic_attributes.old].compact.map do |attribute_hash|
52
32
  unless (hash = AttributeParser.parse(attribute_hash))
53
- return [:dynamic, AttributeCompiler.runtime_build(attributes, object_ref, dynamic_attributes)]
33
+ return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
54
34
  end
55
35
  hash
56
36
  end
@@ -64,6 +44,17 @@ module Haml
64
44
 
65
45
  private
66
46
 
47
+ # Returns a script to render attributes on runtime.
48
+ #
49
+ # @param attributes [Hash]
50
+ # @param object_ref [String,:nil]
51
+ # @param dynamic_attributes [Haml::Parser::DynamicAttributes]
52
+ # @return [String] Attributes rendering code
53
+ def compile_runtime_build(attributes, object_ref, dynamic_attributes)
54
+ arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs].map(&method(:to_literal)).join(', ')
55
+ "::Haml::AttributeBuilder.build(#{to_literal(attributes)}, #{object_ref}, #{arguments}, #{dynamic_attributes.to_literal})"
56
+ end
57
+
67
58
  # Build array of grouped values whose sort order may go back and forth, which is also sorted with key name.
68
59
  # This method needs to group values with the same start because it can be changed in `Haml::AttributeBuidler#build_data_keys`.
69
60
  # @param values [Array<Haml::AttributeCompiler::AttributeValue>]
@@ -116,7 +107,8 @@ module Haml
116
107
  hash_content = values.group_by(&:key).map do |key, values_for_key|
117
108
  "#{frozen_string(key)} => #{merged_value(key, values_for_key)}"
118
109
  end.join(', ')
119
- [:dynamic, "_hamlout.attributes({ #{hash_content} }, nil)"]
110
+ arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs].map(&method(:to_literal)).join(', ')
111
+ [:dynamic, "::Haml::AttributeBuilder.build({ #{hash_content} }, nil, #{arguments})"]
120
112
  end
121
113
 
122
114
  # Renders attribute values statically.
@@ -130,7 +122,7 @@ module Haml
130
122
 
131
123
  arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs]
132
124
  code = "::Haml::AttributeBuilder.build_attributes"\
133
- "(#{arguments.map { |a| Haml::Util.inspect_obj(a) }.join(', ')}, { #{hash_content} })"
125
+ "(#{arguments.map(&method(:to_literal)).join(', ')}, { #{hash_content} })"
134
126
  [:static, eval(code).to_s]
135
127
  end
136
128
 
@@ -139,16 +131,16 @@ module Haml
139
131
  # @return [String]
140
132
  def merged_value(key, values)
141
133
  if values.size == 1
142
- values.first.to_literal
134
+ attr_literal(values.first)
143
135
  else
144
- "::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(&:to_literal).join(', ')})"
136
+ "::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(&method(:attr_literal)).join(', ')})"
145
137
  end
146
138
  end
147
139
 
148
140
  # @param str [String]
149
141
  # @return [String]
150
142
  def frozen_string(str)
151
- "#{Haml::Util.inspect_obj(str)}.freeze"
143
+ "#{to_literal(str)}.freeze"
152
144
  end
153
145
 
154
146
  # Compiles attribute values for one key to Temple expression that generates ` key='value'`.
@@ -157,7 +149,7 @@ module Haml
157
149
  # @param values [Array<AttributeValue>]
158
150
  # @return [Array] Temple expression
159
151
  def compile_attribute(key, values)
160
- if values.all? { |v| Temple::StaticAnalyzer.static?(v.to_literal) }
152
+ if values.all? { |v| Temple::StaticAnalyzer.static?(attr_literal(v)) }
161
153
  return static_build(values)
162
154
  end
163
155
 
@@ -181,7 +173,7 @@ module Haml
181
173
  ['false, nil', [:multi]],
182
174
  [:else, [:multi,
183
175
  [:static, " #{id_or_class}=#{@attr_wrapper}"],
184
- [:escape, @escape_attrs, [:dynamic, var]],
176
+ [:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
185
177
  [:static, @attr_wrapper]],
186
178
  ]
187
179
  ],
@@ -201,7 +193,7 @@ module Haml
201
193
  ['false, nil', [:multi]],
202
194
  [:else, [:multi,
203
195
  [:static, " #{key}=#{@attr_wrapper}"],
204
- [:escape, @escape_attrs, [:dynamic, var]],
196
+ [:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
205
197
  [:static, @attr_wrapper]],
206
198
  ]
207
199
  ],
@@ -220,5 +212,26 @@ module Haml
220
212
  @unique_name ||= 0
221
213
  "_haml_attribute_compiler#{@unique_name += 1}"
222
214
  end
215
+
216
+ # @param [Haml::AttributeCompiler::AttributeValue] attr
217
+ def attr_literal(attr)
218
+ case attr.type
219
+ when :static
220
+ to_literal(attr.value)
221
+ when :dynamic
222
+ attr.value
223
+ end
224
+ end
225
+
226
+ # For haml/haml#972
227
+ # @param [Object] value
228
+ def to_literal(value)
229
+ case value
230
+ when true, false
231
+ value.to_s
232
+ else
233
+ Haml::Util.inspect_obj(value)
234
+ end
235
+ end
223
236
  end
224
237
  end