roadie 3.5.1 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +43 -0
  3. data/.rubocop.yml +5 -0
  4. data/.solargraph.yml +16 -0
  5. data/Changelog.md +30 -4
  6. data/Gemfile +7 -2
  7. data/README.md +12 -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 +10 -11
  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 +43 -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 +47 -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,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
@@ -1,4 +1,6 @@
1
- require 'set'
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
2
4
 
3
5
  module Roadie
4
6
  # @api private
@@ -21,8 +23,15 @@ module Roadie
21
23
  # @option url_options [String] :scheme URL scheme ("http" is default)
22
24
  # @option url_options [String] :protocol alias for :scheme
23
25
  def initialize(url_options)
24
- raise ArgumentError, "No URL options were specified" unless url_options
25
- raise ArgumentError, "No :host was specified; options are: #{url_options.inspect}" unless url_options[:host]
26
+ unless url_options
27
+ raise ArgumentError, "No URL options were specified"
28
+ end
29
+
30
+ unless url_options[:host]
31
+ raise ArgumentError,
32
+ "No :host was specified; options were: #{url_options.inspect}"
33
+ end
34
+
26
35
  validate_options url_options
27
36
 
28
37
  @url_options = url_options
@@ -56,7 +65,7 @@ module Roadie
56
65
  # @param [String] base The base which the relative path comes from
57
66
  # @return [String] an absolute URL
58
67
  def generate_url(path, base = "/")
59
- return root_uri.to_s if path.nil? or path.empty?
68
+ return root_uri.to_s if path.nil? || path.empty?
60
69
  return path if path_is_anchor?(path)
61
70
  return add_scheme(path) if path_is_schemeless?(path)
62
71
  return path if Utils.path_is_absolute?(path)
@@ -65,13 +74,20 @@ module Roadie
65
74
  end
66
75
 
67
76
  protected
77
+
68
78
  attr_reader :root_uri, :scheme
69
79
 
70
80
  private
81
+
71
82
  def build_root_uri
72
83
  path = make_absolute url_options[:path]
73
84
  port = parse_port url_options[:port]
74
- URI::Generic.build(scheme: scheme, host: url_options[:host], port: port, path: path)
85
+ URI::Generic.build(
86
+ scheme: scheme,
87
+ host: url_options[:host],
88
+ port: port,
89
+ path: path
90
+ )
75
91
  end
76
92
 
77
93
  def add_scheme(path)
@@ -96,7 +112,7 @@ module Roadie
96
112
 
97
113
  # Strip :// from any scheme, if present
98
114
  def normalize_scheme(scheme)
99
- return 'http' unless scheme
115
+ return "http" unless scheme
100
116
  scheme.to_s[/^\w+/]
101
117
  end
102
118
 
@@ -117,7 +133,7 @@ module Roadie
117
133
  end
118
134
 
119
135
  def path_is_anchor?(path)
120
- path.start_with? '#'
136
+ path.start_with? "#"
121
137
  end
122
138
 
123
139
  VALID_OPTIONS = Set[:host, :port, :path, :protocol, :scheme].freeze
@@ -125,7 +141,9 @@ module Roadie
125
141
  def validate_options(options)
126
142
  keys = Set.new(options.keys)
127
143
  unless keys.subset? VALID_OPTIONS
128
- raise ArgumentError, "Passed invalid options: #{(keys - VALID_OPTIONS).to_a}, valid options are: #{VALID_OPTIONS.to_a}"
144
+ raise ArgumentError,
145
+ "Passed invalid options: #{(keys - VALID_OPTIONS).to_a}, " \
146
+ "valid options are: #{VALID_OPTIONS.to_a}"
129
147
  end
130
148
  end
131
149
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  # @api private
3
5
  #
@@ -23,9 +25,9 @@ module Roadie
23
25
  dom.css(
24
26
  "a[href]:not([data-roadie-ignore]), " \
25
27
  "img[src]:not([data-roadie-ignore]), " \
26
- "*[style]:not([data-roadie-ignore])",
28
+ "*[style]:not([data-roadie-ignore])"
27
29
  ).each do |element|
28
- transform_element_style element if element.has_attribute?('style')
30
+ transform_element_style element if element.has_attribute?("style")
29
31
  transform_element element
30
32
  end
31
33
  nil
@@ -35,20 +37,22 @@ module Roadie
35
37
  #
36
38
  # This will make all URLs inside url() absolute.
37
39
  #
38
- # [nil] is returned so no one can misunderstand that this method mutates
39
- # the passed string.
40
+ # Copy of CSS that is mutated is returned, passed string is not mutated.
40
41
  #
41
42
  # @param [String] css the css to mutate
42
- # @return [nil] css is mutated
43
+ # @return [String] copy of css that is mutated
43
44
  def transform_css(css)
44
- css.gsub!(CSS_URL_REGEXP) do
45
+ css.gsub(CSS_URL_REGEXP) do
45
46
  matches = Regexp.last_match
46
47
  "url(#{matches[:quote]}#{generate_url(matches[:url])}#{matches[:quote]})"
47
48
  end
48
49
  end
49
50
 
50
51
  private
51
- def generate_url(*args) @generator.generate_url(*args) end
52
+
53
+ def generate_url(*args)
54
+ @generator.generate_url(*args)
55
+ end
52
56
 
53
57
  # Regexp matching all the url() declarations in CSS
54
58
  #
@@ -81,8 +85,7 @@ module Roadie
81
85
  # We need to use a setter for Nokogiri to detect the string mutation.
82
86
  # If nokogiri used "dumber" data structures, this would all be redundant.
83
87
  css = element["style"]
84
- transform_css css
85
- element["style"] = css
88
+ element["style"] = transform_css(css)
86
89
  end
87
90
  end
88
91
  end
data/lib/roadie/utils.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Roadie
2
4
  module Utils
3
5
  # @api private
@@ -8,7 +10,7 @@ module Roadie
8
10
  #
9
11
  # URLs that start with double slashes (//css/app.css) are also absolute
10
12
  # in modern browsers, but most email clients do not understand them.
11
- return true if path =~ %r{^(\w+:|//)}
13
+ return true if %r{^(\w+:|//)}.match?(path)
12
14
 
13
15
  begin
14
16
  !URI.parse(path).relative?