roadie 3.5.1 → 5.0.1

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 +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?