roadie 3.5.1 → 5.1.0

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +46 -0
  3. data/.rubocop.yml +5 -0
  4. data/.solargraph.yml +16 -0
  5. data/Changelog.md +35 -4
  6. data/Gemfile +7 -2
  7. data/README.md +14 -14
  8. data/Rakefile +4 -3
  9. data/lib/roadie/asset_provider.rb +5 -1
  10. data/lib/roadie/asset_scanner.rb +8 -6
  11. data/lib/roadie/cached_provider.rb +3 -0
  12. data/lib/roadie/deduplicator.rb +3 -0
  13. data/lib/roadie/document.rb +24 -17
  14. data/lib/roadie/errors.rb +22 -16
  15. data/lib/roadie/filesystem_provider.rb +15 -3
  16. data/lib/roadie/inliner.rb +51 -19
  17. data/lib/roadie/markup_improver.rb +24 -31
  18. data/lib/roadie/net_http_provider.rb +27 -12
  19. data/lib/roadie/null_provider.rb +20 -5
  20. data/lib/roadie/null_url_rewriter.rb +11 -3
  21. data/lib/roadie/path_rewriter_provider.rb +6 -1
  22. data/lib/roadie/provider_list.rb +17 -11
  23. data/lib/roadie/rspec/asset_provider.rb +6 -1
  24. data/lib/roadie/rspec/cache_store.rb +2 -0
  25. data/lib/roadie/rspec.rb +4 -2
  26. data/lib/roadie/selector.rb +18 -5
  27. data/lib/roadie/style_attribute_builder.rb +4 -1
  28. data/lib/roadie/style_block.rb +5 -3
  29. data/lib/roadie/style_property.rb +5 -2
  30. data/lib/roadie/stylesheet.rb +4 -13
  31. data/lib/roadie/url_generator.rb +26 -8
  32. data/lib/roadie/url_rewriter.rb +12 -9
  33. data/lib/roadie/utils.rb +3 -1
  34. data/lib/roadie/version.rb +1 -1
  35. data/lib/roadie.rb +25 -23
  36. data/roadie.gemspec +23 -23
  37. data/spec/hash_as_cache_store_spec.rb +3 -1
  38. data/spec/integration_spec.rb +75 -44
  39. data/spec/lib/roadie/asset_scanner_spec.rb +11 -5
  40. data/spec/lib/roadie/cached_provider_spec.rb +6 -4
  41. data/spec/lib/roadie/css_not_found_spec.rb +10 -5
  42. data/spec/lib/roadie/deduplicator_spec.rb +5 -3
  43. data/spec/lib/roadie/document_spec.rb +57 -28
  44. data/spec/lib/roadie/filesystem_provider_spec.rb +10 -11
  45. data/spec/lib/roadie/inliner_spec.rb +42 -45
  46. data/spec/lib/roadie/markup_improver_spec.rb +19 -26
  47. data/spec/lib/roadie/net_http_provider_spec.rb +16 -14
  48. data/spec/lib/roadie/null_provider_spec.rb +4 -3
  49. data/spec/lib/roadie/null_url_rewriter_spec.rb +4 -3
  50. data/spec/lib/roadie/path_rewriter_provider_spec.rb +6 -4
  51. data/spec/lib/roadie/provider_list_spec.rb +27 -22
  52. data/spec/lib/roadie/selector_spec.rb +7 -5
  53. data/spec/lib/roadie/style_attribute_builder_spec.rb +7 -5
  54. data/spec/lib/roadie/style_block_spec.rb +3 -2
  55. data/spec/lib/roadie/style_property_spec.rb +10 -8
  56. data/spec/lib/roadie/stylesheet_spec.rb +4 -21
  57. data/spec/lib/roadie/test_provider_spec.rb +6 -4
  58. data/spec/lib/roadie/url_generator_spec.rb +3 -2
  59. data/spec/lib/roadie/url_rewriter_spec.rb +10 -7
  60. data/spec/lib/roadie/utils_spec.rb +2 -0
  61. data/spec/shared_examples/asset_provider.rb +2 -0
  62. data/spec/shared_examples/url_rewriter.rb +5 -3
  63. data/spec/spec_helper.rb +10 -8
  64. data/spec/support/have_attribute_matcher.rb +3 -2
  65. data/spec/support/have_node_matcher.rb +5 -3
  66. data/spec/support/have_selector_matcher.rb +4 -3
  67. data/spec/support/have_styling_matcher.rb +12 -11
  68. data/spec/support/have_xpath_matcher.rb +4 -3
  69. data/spec/support/test_provider.rb +2 -0
  70. metadata +24 -8
  71. data/.travis.yml +0 -22
@@ -1,19 +1,28 @@
1
- require 'set'
2
- require 'nokogiri'
3
- require 'uri'
4
- require 'css_parser'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "nokogiri"
5
+ require "uri"
6
+ require "css_parser"
5
7
 
6
8
  module Roadie
7
9
  # @api private
8
10
  # The Inliner inlines stylesheets to the elements of the DOM.
9
11
  #
10
12
  # Inlining means that {StyleBlock}s and a DOM tree are combined:
11
- # a { color: red; } # StyleBlock
12
- # <a href="/"></a> # DOM
13
+ #
14
+ # ```css
15
+ # a { color: red; } # StyleBlock
16
+ # ```
17
+ # ```html
18
+ # <a href="/"></a> # DOM
19
+ # ```
13
20
  #
14
21
  # becomes
15
22
  #
16
- # <a href="/" style="color:red"></a>
23
+ # ```html
24
+ # <a href="/" style="color:red"></a>
25
+ # ```
17
26
  class Inliner
18
27
  # @param [Array<Stylesheet>] stylesheets the stylesheets to use in the inlining
19
28
  # @param [Nokogiri::HTML::Document] dom
@@ -45,9 +54,11 @@ module Roadie
45
54
  end
46
55
 
47
56
  protected
57
+
48
58
  attr_reader :stylesheets, :dom
49
59
 
50
60
  private
61
+
51
62
  def consume_stylesheets
52
63
  style_map = StyleMap.new
53
64
  extra_blocks = []
@@ -89,12 +100,18 @@ module Roadie
89
100
  # with having to rescue errors.
90
101
  # Pseudo selectors that are known to be bad are skipped automatically but
91
102
  # this will catch the rest.
92
- rescue Nokogiri::XML::XPath::SyntaxError, Nokogiri::CSS::SyntaxError => error
93
- Utils.warn "Cannot inline #{selector.inspect} from \"#{stylesheet.name}\" stylesheet. If this is valid CSS, please report a bug."
103
+ rescue Nokogiri::XML::XPath::SyntaxError, Nokogiri::CSS::SyntaxError
104
+ Utils.warn(
105
+ "Cannot inline #{selector.inspect} from \"#{stylesheet.name}\" " \
106
+ "stylesheet. If this is valid CSS, please report a bug."
107
+ )
94
108
  nil
95
109
  rescue => error
96
- Utils.warn "Got error when looking for #{selector.inspect} (from \"#{stylesheet.name}\" stylesheet): #{error}"
97
- raise unless error.message.include?('XPath')
110
+ Utils.warn(
111
+ "Got error when looking for #{selector.inspect} " \
112
+ "(from \"#{stylesheet.name}\" stylesheet): #{error}"
113
+ )
114
+ raise unless error.message.include?("XPath")
98
115
  nil
99
116
  end
100
117
 
@@ -120,12 +137,12 @@ module Roadie
120
137
  end
121
138
 
122
139
  def find_head
123
- dom.at_xpath('html/head')
140
+ dom.at_xpath("html/head")
124
141
  end
125
142
 
126
143
  def create_style_element(style_blocks, parent, merge_media_queries)
127
144
  return unless parent
128
- element = Nokogiri::XML::Node.new('style', parent.document)
145
+ element = Nokogiri::XML::Node.new("style", parent.document)
129
146
 
130
147
  element.content =
131
148
  if merge_media_queries
@@ -139,17 +156,23 @@ module Roadie
139
156
  # For performance reasons, we should group styles with the same media types within
140
157
  # one media query instead of creating thousands of media queries.
141
158
  # https://github.com/artifex404/media-queries-benchmark
142
- # Example result: ["@media(max-width: 600px) { .col-12 { display: block; } }"]
159
+ #
160
+ # Example result:
161
+ #
162
+ # ```ruby
163
+ # ["@media(max-width: 600px) { .col-12 { display: block; } }"]
164
+ # ```
165
+ #
143
166
  # @param {Array<StyleBlock>} style_blocks Style blocks that could not be inlined
144
167
  # @return {Array<String>}
145
168
  def styles_in_shared_media_queries(style_blocks)
146
169
  style_blocks.group_by(&:media).map do |media_types, blocks|
147
170
  css_rules = blocks.map(&:to_s).join("\n")
148
171
 
149
- if media_types == ['all']
172
+ if media_types == ["all"]
150
173
  css_rules
151
174
  else
152
- "@media #{media_types.join(', ')} {\n#{css_rules}\n}"
175
+ "@media #{media_types.join(", ")} {\n#{css_rules}\n}"
153
176
  end
154
177
  end
155
178
  end
@@ -157,27 +180,36 @@ module Roadie
157
180
  # Some users might prefer to not group rules within media queries because
158
181
  # it will result in rules getting reordered.
159
182
  # e.g.
183
+ #
184
+ # ```css
160
185
  # @media(max-width: 600px) { .col-6 { display: block; } }
161
186
  # @media(max-width: 400px) { .col-12 { display: inline-block; } }
162
187
  # @media(max-width: 600px) { .col-12 { display: block; } }
188
+ # ````
189
+ #
163
190
  # will become
191
+ #
192
+ # ```css
164
193
  # @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
165
194
  # @media(max-width: 400px) { .col-12 { display: inline-block; } }
195
+ # ```
196
+ #
197
+ #
166
198
  # which would change the styling on the page
167
199
  # (before it would've yielded display: block; for .col-12 at max-width: 600px
168
200
  # and now it yields inline-block;)
169
201
  #
170
202
  # If merge_media_queries is set to false,
171
- # we will generate #{style_blocks.size} media queries, potentially
203
+ # we will generate `style_blocks.size` media queries, potentially
172
204
  # causing performance issues.
173
205
  # @param {Array<StyleBlock>} style_blocks All style blocks
174
206
  # @return {Array<String>}
175
207
  def styles_in_individual_media_queries(style_blocks)
176
208
  style_blocks.map do |css_rule|
177
- if css_rule.media == ['all']
209
+ if css_rule.media == ["all"]
178
210
  css_rule
179
211
  else
180
- "@media #{css_rule.media.join(', ')} {\n#{css_rule}\n}"
212
+ "@media #{css_rule.media.join(", ")} {\n#{css_rule}\n}"
181
213
  end
182
214
  end
183
215
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api private
3
5
  # Class that improves the markup of a HTML DOM tree
@@ -5,13 +7,10 @@ module Roadie
5
7
  # This class will improve the following aspects of the DOM:
6
8
  # * A HTML5 doctype will be added if missing, other doctypes will be left as-is.
7
9
  # * Basic HTML elements will be added if missing.
8
- # * +<html>+
9
- # * +<head>+
10
- # * +<body>+
11
- # * +<meta>+ declaring charset and content-type (text/html)
12
- #
13
- # @note Due to a Nokogiri bug, the HTML5 doctype cannot be added under JRuby. No doctype is outputted under JRuby.
14
- # See https://github.com/sparklemotion/nokogiri/issues/984
10
+ # * `<html>`
11
+ # * `<head>`
12
+ # * `<body>`
13
+ # * `<meta>` declaring charset and content-type (text/html)
15
14
  class MarkupImprover
16
15
  # The original HTML must also be passed in in order to handle the doctypes
17
16
  # since a +Nokogiri::HTML::Document+ will always have a doctype, no matter if
@@ -31,45 +30,39 @@ module Roadie
31
30
  end
32
31
 
33
32
  protected
33
+
34
34
  attr_reader :dom
35
35
 
36
36
  private
37
+
37
38
  def ensure_doctype_present
38
- return if uses_buggy_jruby?
39
- return if @html.include?('<!DOCTYPE ')
39
+ return if @html.include?("<!DOCTYPE ")
40
40
  # Nokogiri adds a "default" doctype to the DOM, which we will remove
41
- dom.internal_subset.remove unless dom.internal_subset.nil?
42
- dom.create_internal_subset 'html', nil, nil
43
- end
44
-
45
- # JRuby up to at least 1.6.0 has a bug where the doctype of a document cannot be changed.
46
- # See https://github.com/sparklemotion/nokogiri/issues/984
47
- def uses_buggy_jruby?
48
- # No reason to check for version yet since no existing version has a fix.
49
- defined?(JRuby)
41
+ dom.internal_subset&.remove
42
+ dom.create_internal_subset "html", nil, nil
50
43
  end
51
44
 
52
45
  def ensure_html_element_present
53
- return if dom.at_xpath('html')
54
- html = Nokogiri::XML::Node.new 'html', dom
46
+ return if dom.at_xpath("html")
47
+ html = Nokogiri::XML::Node.new "html", dom
55
48
  dom << html
56
49
  end
57
50
 
58
51
  def ensure_head_element_present
59
- if (head = dom.at_xpath('html/head'))
52
+ if (head = dom.at_xpath("html/head"))
60
53
  head
61
54
  else
62
- create_head_element dom.at_xpath('html')
55
+ create_head_element dom.at_xpath("html")
63
56
  end
64
57
  end
65
58
 
66
59
  def create_head_element(parent)
67
- head = Nokogiri::XML::Node.new 'head', dom
68
- unless parent.children.empty?
60
+ head = Nokogiri::XML::Node.new "head", dom
61
+ if parent.children.empty?
62
+ parent << head
63
+ else
69
64
  # Crashes when no children are present
70
65
  parent.children.before head
71
- else
72
- parent << head
73
66
  end
74
67
  head
75
68
  end
@@ -81,15 +74,15 @@ module Roadie
81
74
  end
82
75
 
83
76
  def content_type_meta_element_missing?
84
- dom.xpath('html/head/meta').none? do |meta|
85
- meta['http-equiv'].to_s.downcase == 'content-type'
77
+ dom.xpath("html/head/meta").none? do |meta|
78
+ meta["http-equiv"].to_s.downcase == "content-type"
86
79
  end
87
80
  end
88
81
 
89
82
  def make_content_type_element
90
- meta = Nokogiri::XML::Node.new('meta', dom)
91
- meta['http-equiv'] = 'Content-Type'
92
- meta['content'] = 'text/html; charset=UTF-8'
83
+ meta = Nokogiri::XML::Node.new("meta", dom)
84
+ meta["http-equiv"] = "Content-Type"
85
+ meta["content"] = "text/html; charset=UTF-8"
93
86
  meta
94
87
  end
95
88
  end
@@ -1,7 +1,8 @@
1
- # encoding: UTF-8
2
- require 'set'
3
- require 'uri'
4
- require 'net/http'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "uri"
5
+ require "net/http"
5
6
 
6
7
  module Roadie
7
8
  # @api public
@@ -33,19 +34,29 @@ module Roadie
33
34
 
34
35
  def find_stylesheet!(url)
35
36
  response = download(url)
36
- if response.kind_of? Net::HTTPSuccess
37
+ if response.is_a? Net::HTTPSuccess
37
38
  Stylesheet.new(url, response_body(response))
38
39
  else
39
- raise CssNotFound.new(url, "Server returned #{response.code}: #{truncate response.body}", self)
40
+ raise CssNotFound.new(
41
+ css_name: url,
42
+ message: "Server returned #{response.code}: #{truncate response.body}",
43
+ provider: self
44
+ )
40
45
  end
41
46
  rescue Timeout::Error
42
- raise CssNotFound.new(url, "Timeout", self)
47
+ raise CssNotFound.new(css_name: url, message: "Timeout", provider: self)
43
48
  end
44
49
 
45
- def to_s() inspect end
46
- def inspect() "#<#{self.class} whitelist: #{whitelist.inspect}>" end
50
+ def to_s
51
+ inspect
52
+ end
53
+
54
+ def inspect
55
+ "#<#{self.class} whitelist: #{whitelist.inspect}>"
56
+ end
47
57
 
48
58
  private
59
+
49
60
  def host_set(hosts)
50
61
  hosts.each { |host| validate_host(host) }.to_set
51
62
  end
@@ -62,7 +73,11 @@ module Roadie
62
73
  if access_granted_to?(uri.host)
63
74
  get_response(uri)
64
75
  else
65
- raise CssNotFound.new(url, "#{uri.host} is not part of whitelist!", self)
76
+ raise CssNotFound.new(
77
+ css_name: url,
78
+ message: "#{uri.host} is not part of whitelist!",
79
+ provider: self
80
+ )
66
81
  end
67
82
  end
68
83
 
@@ -70,7 +85,7 @@ module Roadie
70
85
  if RUBY_VERSION >= "2.0.0"
71
86
  Net::HTTP.get_response(uri)
72
87
  else
73
- Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
88
+ Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == "https")) do |http|
74
89
  http.request(Net::HTTP::Get.new(uri.request_uri))
75
90
  end
76
91
  end
@@ -91,7 +106,7 @@ module Roadie
91
106
  def response_body(response)
92
107
  # Make sure we respect encoding because Net:HTTP will encode body as ASCII by default
93
108
  # which will break if the response is not compatible.
94
- supplied_charset = response.type_params['charset']
109
+ supplied_charset = response.type_params["charset"]
95
110
  body = response.body
96
111
 
97
112
  if supplied_charset
@@ -1,16 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # An asset provider that returns empty stylesheets for any name.
3
5
  #
4
6
  # Use it to ignore missing assets or in your tests when you need a provider
5
7
  # but you do not care what it contains or that it is even referenced at all.
6
8
  class NullProvider
7
- def find_stylesheet(name) empty_stylesheet end
8
- def find_stylesheet!(name) empty_stylesheet end
9
+ def find_stylesheet(name)
10
+ empty_stylesheet
11
+ end
12
+
13
+ def find_stylesheet!(name)
14
+ empty_stylesheet
15
+ end
9
16
 
10
- def to_s() inspect end
11
- def inspect() "#<#{self.class}>" end
17
+ def to_s
18
+ inspect
19
+ end
20
+
21
+ def inspect
22
+ "#<#{self.class}>"
23
+ end
12
24
 
13
25
  private
14
- def empty_stylesheet() Stylesheet.new "(null)", "" end
26
+
27
+ def empty_stylesheet
28
+ Stylesheet.new "(null)", ""
29
+ end
15
30
  end
16
31
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api private
3
5
  # Null Object for the URL rewriter role.
@@ -5,8 +7,14 @@ module Roadie
5
7
  # Used whenever client does not pass any URL options and no URL rewriting
6
8
  # should take place.
7
9
  class NullUrlRewriter
8
- def initialize(generator = nil) end
9
- def transform_dom(dom) end
10
- def transform_css(css) end
10
+ def initialize(generator = nil)
11
+ end
12
+
13
+ def transform_dom(dom)
14
+ end
15
+
16
+ def transform_css(css)
17
+ css
18
+ end
11
19
  end
12
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api public
3
5
  # This provider acts a bit like a pipeline in normal UNIX parlour by enabling
@@ -57,7 +59,10 @@ module Roadie
57
59
  if new_path
58
60
  provider.find_stylesheet!(new_path)
59
61
  else
60
- raise CssNotFound, "Filter returned #{new_path.inspect}"
62
+ raise CssNotFound.new(
63
+ css_name: path,
64
+ message: "Filter returned #{new_path.inspect}"
65
+ )
61
66
  end
62
67
  end
63
68
  end
@@ -1,4 +1,6 @@
1
- require 'forwardable'
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
2
4
 
3
5
  module Roadie
4
6
  # An asset provider that just composes a list of other asset providers.
@@ -23,7 +25,7 @@ module Roadie
23
25
  # @overload wrap(provider1, provider2, ...)
24
26
  # @return a new {ProviderList} with all the passed providers in it.
25
27
  def self.wrap(*providers)
26
- if providers.size == 1 && providers.first.class == self
28
+ if providers.size == 1 && providers.first.instance_of?(self)
27
29
  providers.first
28
30
  else
29
31
  new(providers.flatten)
@@ -31,7 +33,9 @@ module Roadie
31
33
  end
32
34
 
33
35
  # Returns a new empty list.
34
- def self.empty() new([]) end
36
+ def self.empty
37
+ new([])
38
+ end
35
39
 
36
40
  def initialize(providers)
37
41
  @providers = providers
@@ -53,13 +57,13 @@ module Roadie
53
57
  def find_stylesheet!(name)
54
58
  errors = []
55
59
  @providers.each do |provider|
56
- begin
57
- return provider.find_stylesheet!(name)
58
- rescue CssNotFound => error
59
- errors << error
60
- end
60
+ return provider.find_stylesheet!(name)
61
+ rescue CssNotFound => error
62
+ errors << error
61
63
  end
62
- raise ProvidersFailed.new(name, self, errors)
64
+ raise ProvidersFailed.new(
65
+ css_name: name, providers: self, errors: errors
66
+ )
63
67
  end
64
68
 
65
69
  def to_s
@@ -67,12 +71,14 @@ module Roadie
67
71
  # Indent every line one level
68
72
  provider.to_s.split("\n").join("\n\t")
69
73
  }
70
- "ProviderList: [\n\t#{list.join(",\n\t")}\n]"
74
+ "ProviderList: [\n\t#{list.join(",\n\t")}\n]\n"
71
75
  end
72
76
 
73
77
  # ProviderList can be coerced to an array. This makes Array#flatten work
74
78
  # with it, among other things.
75
- def to_ary() to_a end
79
+ def to_ary
80
+ to_a
81
+ end
76
82
 
77
83
  # @!method each
78
84
  # @see Array#each
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for "roadie asset provider" do |options|
2
4
  valid_name = options[:valid_name] or raise "You must provide a :valid_name option to the shared examples"
3
5
  invalid_name = options[:invalid_name] or raise "You must provide an :invalid_name option to the shared examples"
@@ -43,7 +45,10 @@ shared_examples_for "roadie asset provider" do |options|
43
45
  it "raises Roadie::CssNotFound on invalid stylesheets" do
44
46
  expect {
45
47
  subject.find_stylesheet!(invalid_name)
46
- }.to raise_error Roadie::CssNotFound, Regexp.new(Regexp.quote(invalid_name))
48
+ }.to raise_error(
49
+ Roadie::CssNotFound,
50
+ Regexp.new(Regexp.quote(invalid_name))
51
+ )
47
52
  end
48
53
  end
49
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  shared_examples_for "roadie cache store" do
2
4
  it "allows storing Stylesheets" do
3
5
  stylesheet = Roadie::Stylesheet.new("foo.css", "body { color: green; }")
data/lib/roadie/rspec.rb CHANGED
@@ -1,2 +1,4 @@
1
- require 'roadie/rspec/asset_provider'
2
- require 'roadie/rspec/cache_store'
1
+ # frozen_string_literal: true
2
+
3
+ require "roadie/rspec/asset_provider"
4
+ require "roadie/rspec/cache_store"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api private
3
5
  #
@@ -35,9 +37,17 @@ module Roadie
35
37
  !(pseudo_element? || at_rule? || pseudo_function?)
36
38
  end
37
39
 
38
- def to_s() selector end
39
- def to_str() to_s end
40
- def inspect() selector.inspect end
40
+ def to_s
41
+ selector
42
+ end
43
+
44
+ def to_str
45
+ to_s
46
+ end
47
+
48
+ def inspect
49
+ selector.inspect
50
+ end
41
51
 
42
52
  # {Selector}s are equal to other {Selector}s if, and only if, their string
43
53
  # representations are equal.
@@ -50,22 +60,25 @@ module Roadie
50
60
  end
51
61
 
52
62
  protected
63
+
53
64
  attr_reader :selector
54
65
 
55
66
  private
67
+
56
68
  BAD_PSEUDO_FUNCTIONS = %w[
57
69
  :active :focus :hover :link :target :visited
58
70
  :-ms-input-placeholder :-moz-placeholder
59
71
  :before :after
60
72
  :enabled :disabled :checked
73
+ :host
61
74
  ].freeze
62
75
 
63
76
  def pseudo_element?
64
- selector.include? '::'
77
+ selector.include? "::"
65
78
  end
66
79
 
67
80
  def at_rule?
68
- selector[0, 1] == '@'
81
+ selector[0, 1] == "@"
69
82
  end
70
83
 
71
84
  def pseudo_function?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  class StyleAttributeBuilder
3
5
  def initialize
@@ -9,10 +11,11 @@ module Roadie
9
11
  end
10
12
 
11
13
  def attribute_string
12
- Deduplicator.apply(stable_sort(@styles).map(&:to_s)).join(';')
14
+ Deduplicator.apply(stable_sort(@styles).map(&:to_s)).join(";")
13
15
  end
14
16
 
15
17
  private
18
+
16
19
  def stable_sort(list)
17
20
  # Ruby's sort is unstable for performance reasons. We need it to be
18
21
  # stable, e.g. to preserve order of elements that are compared equal in
@@ -1,4 +1,6 @@
1
- require 'forwardable'
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
2
4
 
3
5
  module Roadie
4
6
  # @api private
@@ -37,7 +39,7 @@ module Roadie
37
39
  # @return {String}
38
40
  def to_s
39
41
  # NB - leave off redundant final semicolon - see https://www.w3.org/TR/CSS2/syndata.html#declaration
40
- "#{selector}{#{properties.map(&:to_s).join(';')}}"
42
+ "#{selector}{#{properties.map(&:to_s).join(";")}}"
41
43
  end
42
44
 
43
45
  private
@@ -47,7 +49,7 @@ module Roadie
47
49
  # @media only screen and (max-width: 600px) {...} cannot be inlined
48
50
  # @return {Boolean}
49
51
  def inlinable_media?
50
- @media.none? { |media_query| media_query.include? '(' }
52
+ @media.none? { |media_query| media_query.include? "(" }
51
53
  end
52
54
  end
53
55
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api private
3
5
  # Domain object for a CSS property such as "color: red !important".
@@ -36,14 +38,15 @@ module Roadie
36
38
  end
37
39
 
38
40
  def to_s
39
- [property, value_with_important].join(':')
41
+ [property, value_with_important].join(":")
40
42
  end
41
43
 
42
44
  def inspect
43
- "#{to_s} (#{specificity})"
45
+ "#{self} (#{specificity})"
44
46
  end
45
47
 
46
48
  private
49
+
47
50
  def value_with_important
48
51
  if important
49
52
  "#{value} !important"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # Domain object that represents a stylesheet (from disc, perhaps).
3
5
  #
@@ -6,7 +8,7 @@ module Roadie
6
8
  # @attr_reader [String] name the name of the stylesheet ("stylesheets/main.css", "Admin user styles", etc.). The name of the stylesheet will be visible if any errors occur.
7
9
  # @attr_reader [Array<StyleBlock>] blocks
8
10
  class Stylesheet
9
- BOM = "\xEF\xBB\xBF".force_encoding('UTF-8').freeze
11
+ BOM = (+"\xEF\xBB\xBF").force_encoding("UTF-8").freeze
10
12
 
11
13
  attr_reader :name, :blocks
12
14
 
@@ -19,23 +21,12 @@ module Roadie
19
21
  @blocks = parse_blocks(css.sub(BOM, ""))
20
22
  end
21
23
 
22
- # @yield [selector, properties]
23
- # @yieldparam [Selector] selector
24
- # @yieldparam [Array<StyleProperty>] properties
25
- # @deprecated Iterate over the #{blocks} instead. Will be removed on version 4.0.
26
- def each_inlinable_block(&block)
27
- # #map and then #each in order to support chained enumerations, etc. if
28
- # no block is provided
29
- inlinable_blocks.map { |style_block|
30
- [style_block.selector, style_block.properties]
31
- }.each(&block)
32
- end
33
-
34
24
  def to_s
35
25
  blocks.join("\n")
36
26
  end
37
27
 
38
28
  private
29
+
39
30
  def inlinable_blocks
40
31
  blocks.select(&:inlinable?)
41
32
  end