Mange / roadie
Showing 49 of 60 files from the diff.
Other files ignored by Codecov

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'set'
3 +
require "set"
4 4
5 5
module Roadie
6 6
  # @api private
@@ -23,8 +23,15 @@
Loading
23 23
    # @option url_options [String] :scheme URL scheme ("http" is default)
24 24
    # @option url_options [String] :protocol alias for :scheme
25 25
    def initialize(url_options)
26 -
      raise ArgumentError, "No URL options were specified" unless url_options
27 -
      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 +
28 35
      validate_options url_options
29 36
30 37
      @url_options = url_options
@@ -58,7 +65,7 @@
Loading
58 65
    # @param [String] base The base which the relative path comes from
59 66
    # @return [String] an absolute URL
60 67
    def generate_url(path, base = "/")
61 -
      return root_uri.to_s if path.nil? or path.empty?
68 +
      return root_uri.to_s if path.nil? || path.empty?
62 69
      return path if path_is_anchor?(path)
63 70
      return add_scheme(path) if path_is_schemeless?(path)
64 71
      return path if Utils.path_is_absolute?(path)
@@ -67,13 +74,20 @@
Loading
67 74
    end
68 75
69 76
    protected
77 +
70 78
    attr_reader :root_uri, :scheme
71 79
72 80
    private
81 +
73 82
    def build_root_uri
74 83
      path = make_absolute url_options[:path]
75 84
      port = parse_port url_options[:port]
76 -
      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 +
      )
77 91
    end
78 92
79 93
    def add_scheme(path)
@@ -98,7 +112,7 @@
Loading
98 112
99 113
    # Strip :// from any scheme, if present
100 114
    def normalize_scheme(scheme)
101 -
      return 'http' unless scheme
115 +
      return "http" unless scheme
102 116
      scheme.to_s[/^\w+/]
103 117
    end
104 118
@@ -119,7 +133,7 @@
Loading
119 133
    end
120 134
121 135
    def path_is_anchor?(path)
122 -
      path.start_with? '#'
136 +
      path.start_with? "#"
123 137
    end
124 138
125 139
    VALID_OPTIONS = Set[:host, :port, :path, :protocol, :scheme].freeze
@@ -127,7 +141,9 @@
Loading
127 141
    def validate_options(options)
128 142
      keys = Set.new(options.keys)
129 143
      unless keys.subset? VALID_OPTIONS
130 -
        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}"
131 147
      end
132 148
    end
133 149
  end

@@ -1,8 +1,8 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
5 -
require 'shared_examples/asset_provider'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 +
require "shared_examples/asset_provider"
6 6
7 7
module Roadie
8 8
  describe PathRewriterProvider do
@@ -10,7 +10,7 @@
Loading
10 10
11 11
    subject(:provider) do
12 12
      PathRewriterProvider.new(upstream) do |path|
13 -
        path.gsub('well', 'good')
13 +
        path.gsub("well", "good")
14 14
      end
15 15
    end
16 16

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 3
RSpec::Matchers.define :have_attribute do |attribute|
4 -
  @selector = 'body > *:first'
4 +
  @selector = "body > *:first"
5 5
6 6
  chain :at_selector do |selector|
7 7
    @selector = selector
@@ -27,4 +27,3 @@
Loading
27 27
    node && node[attribute_name]
28 28
  end
29 29
end
30 -

@@ -7,13 +7,10 @@
Loading
7 7
  # This class will improve the following aspects of the DOM:
8 8
  # * A HTML5 doctype will be added if missing, other doctypes will be left as-is.
9 9
  # * Basic HTML elements will be added if missing.
10 -
  #   * +<html>+
11 -
  #   * +<head>+
12 -
  #   * +<body>+
13 -
  #   * +<meta>+ declaring charset and content-type (text/html)
14 -
  #
15 -
  # @note Due to a Nokogiri bug, the HTML5 doctype cannot be added under JRuby. No doctype is outputted under JRuby.
16 -
  #   See https://github.com/sparklemotion/nokogiri/issues/984
10 +
  #   * `<html>`
11 +
  #   * `<head>`
12 +
  #   * `<body>`
13 +
  #   * `<meta>` declaring charset and content-type (text/html)
17 14
  class MarkupImprover
18 15
    # The original HTML must also be passed in in order to handle the doctypes
19 16
    # since a +Nokogiri::HTML::Document+ will always have a doctype, no matter if
@@ -33,45 +30,39 @@
Loading
33 30
    end
34 31
35 32
    protected
33 +
36 34
    attr_reader :dom
37 35
38 36
    private
37 +
39 38
    def ensure_doctype_present
40 -
      return if uses_buggy_jruby?
41 -
      return if @html.include?('<!DOCTYPE ')
39 +
      return if @html.include?("<!DOCTYPE ")
42 40
      # Nokogiri adds a "default" doctype to the DOM, which we will remove
43 -
      dom.internal_subset.remove unless dom.internal_subset.nil?
44 -
      dom.create_internal_subset 'html', nil, nil
45 -
    end
46 -
47 -
    # JRuby up to at least 1.6.0 has a bug where the doctype of a document cannot be changed.
48 -
    # See https://github.com/sparklemotion/nokogiri/issues/984
49 -
    def uses_buggy_jruby?
50 -
      # No reason to check for version yet since no existing version has a fix.
51 -
      defined?(JRuby)
41 +
      dom.internal_subset&.remove
42 +
      dom.create_internal_subset "html", nil, nil
52 43
    end
53 44
54 45
    def ensure_html_element_present
55 -
      return if dom.at_xpath('html')
56 -
      html = Nokogiri::XML::Node.new 'html', dom
46 +
      return if dom.at_xpath("html")
47 +
      html = Nokogiri::XML::Node.new "html", dom
57 48
      dom << html
58 49
    end
59 50
60 51
    def ensure_head_element_present
61 -
      if (head = dom.at_xpath('html/head'))
52 +
      if (head = dom.at_xpath("html/head"))
62 53
        head
63 54
      else
64 -
        create_head_element dom.at_xpath('html')
55 +
        create_head_element dom.at_xpath("html")
65 56
      end
66 57
    end
67 58
68 59
    def create_head_element(parent)
69 -
      head = Nokogiri::XML::Node.new 'head', dom
70 -
      unless parent.children.empty?
60 +
      head = Nokogiri::XML::Node.new "head", dom
61 +
      if parent.children.empty?
62 +
        parent << head
63 +
      else
71 64
        # Crashes when no children are present
72 65
        parent.children.before head
73 -
      else
74 -
        parent << head
75 66
      end
76 67
      head
77 68
    end
@@ -83,15 +74,15 @@
Loading
83 74
    end
84 75
85 76
    def content_type_meta_element_missing?
86 -
      dom.xpath('html/head/meta').none? do |meta|
87 -
        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"
88 79
      end
89 80
    end
90 81
91 82
    def make_content_type_element
92 -
      meta = Nokogiri::XML::Node.new('meta', dom)
93 -
      meta['http-equiv'] = 'Content-Type'
94 -
      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"
95 86
      meta
96 87
    end
97 88
  end

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'shared_examples/url_rewriter'
3 +
require "spec_helper"
4 +
require "shared_examples/url_rewriter"
5 5
6 6
module Roadie
7 7
  describe NullUrlRewriter do

@@ -1,13 +1,13 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
5 -
require 'shared_examples/asset_provider'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 +
require "shared_examples/asset_provider"
6 6
7 7
module Roadie
8 8
  describe CachedProvider do
9 9
    let(:upstream) { TestProvider.new("good.css" => "body { color: green; }") }
10 -
    let(:cache) { Hash.new }
10 +
    let(:cache) { {} }
11 11
    subject(:provider) { CachedProvider.new(upstream, cache) }
12 12
13 13
    it_behaves_like "roadie asset provider", valid_name: "good.css", invalid_name: "bad.css"

@@ -38,14 +38,15 @@
Loading
38 38
    end
39 39
40 40
    def to_s
41 -
      [property, value_with_important].join(':')
41 +
      [property, value_with_important].join(":")
42 42
    end
43 43
44 44
    def inspect
45 -
      "#{to_s} (#{specificity})"
45 +
      "#{self} (#{specificity})"
46 46
    end
47 47
48 48
    private
49 +
49 50
    def value_with_important
50 51
      if important
51 52
        "#{value} !important"

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe UrlGenerator do

@@ -11,10 +11,11 @@
Loading
11 11
    end
12 12
13 13
    def attribute_string
14 -
      Deduplicator.apply(stable_sort(@styles).map(&:to_s)).join(';')
14 +
      Deduplicator.apply(stable_sort(@styles).map(&:to_s)).join(";")
15 15
    end
16 16
17 17
    private
18 +
18 19
    def stable_sort(list)
19 20
      # Ruby's sort is unstable for performance reasons. We need it to be
20 21
      # stable, e.g. to preserve order of elements that are compared equal in

@@ -1,13 +1,13 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe StyleProperty do
7 7
    it "is initialized with a property, value, if it is marked as important, and the specificity" do
8 -
      StyleProperty.new('color', 'green', true, 45).tap do |declaration|
9 -
        expect(declaration.property).to eq('color')
10 -
        expect(declaration.value).to eq('green')
8 +
      StyleProperty.new("color", "green", true, 45).tap do |declaration|
9 +
        expect(declaration.property).to eq("color")
10 +
        expect(declaration.value).to eq("green")
11 11
        expect(declaration).to be_important
12 12
        expect(declaration.specificity).to eq(45)
13 13
      end
@@ -15,18 +15,18 @@
Loading
15 15
16 16
    describe "string representation" do
17 17
      it "is the property and the value joined with a colon" do
18 -
        expect(StyleProperty.new('color', 'green', false, 1).to_s).to eq('color:green')
19 -
        expect(StyleProperty.new('font-size', '1.1em', false, 1).to_s).to eq('font-size:1.1em')
18 +
        expect(StyleProperty.new("color", "green", false, 1).to_s).to eq("color:green")
19 +
        expect(StyleProperty.new("font-size", "1.1em", false, 1).to_s).to eq("font-size:1.1em")
20 20
      end
21 21
22 22
      it "contains the !important flag when set" do
23 -
        expect(StyleProperty.new('color', 'green', true, 1).to_s).to eq('color:green !important')
23 +
        expect(StyleProperty.new("color", "green", true, 1).to_s).to eq("color:green !important")
24 24
      end
25 25
    end
26 26
27 27
    describe "comparing" do
28 28
      def declaration(specificity, important = false)
29 -
        StyleProperty.new('color', 'green', important, specificity)
29 +
        StyleProperty.new("color", "green", important, specificity)
30 30
      end
31 31
32 32
      it "compares on specificity" do

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe StyleAttributeBuilder do
@@ -17,8 +17,8 @@
Loading
17 17
    it "preserves the order of added attributes with the same specificity" do
18 18
      builder = StyleAttributeBuilder.new
19 19
20 -
      builder << StyleProperty.new("color", "pink",  false, 50)
21 -
      builder << StyleProperty.new("color", "red",   false, 50)
20 +
      builder << StyleProperty.new("color", "pink", false, 50)
21 +
      builder << StyleProperty.new("color", "red", false, 50)
22 22
      builder << StyleProperty.new("color", "green", false, 50)
23 23
24 24
      # We need one different element to trigger the problem with Ruby's
@@ -31,9 +31,9 @@
Loading
31 31
    it "removes duplicate properties" do
32 32
      builder = StyleAttributeBuilder.new
33 33
34 -
      builder << StyleProperty.new("color", "pink",  false, 10)
34 +
      builder << StyleProperty.new("color", "pink", false, 10)
35 35
      builder << StyleProperty.new("color", "green", false, 20)
36 -
      builder << StyleProperty.new("color", "pink",  false, 50)
36 +
      builder << StyleProperty.new("color", "pink", false, 50)
37 37
38 38
      expect(builder.attribute_string).to eq "color:green;color:pink"
39 39
    end

@@ -1,24 +1,24 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe CssNotFound do
7 7
    it "is initialized with a name" do
8 -
      error = CssNotFound.new('style.css')
9 -
      expect(error.css_name).to eq('style.css')
8 +
      error = CssNotFound.new("style.css")
9 +
      expect(error.css_name).to eq("style.css")
10 10
      expect(error.message).to eq('Could not find stylesheet "style.css"')
11 11
    end
12 12
13 13
    it "can be initialized with an extra message" do
14 -
      expect(CssNotFound.new('file.css', "directory is missing").message).to eq(
14 +
      expect(CssNotFound.new("file.css", "directory is missing").message).to eq(
15 15
        'Could not find stylesheet "file.css": directory is missing'
16 16
      )
17 17
    end
18 18
19 19
    it "shows information about used provider when given" do
20 20
      provider = double("Some cool provider")
21 -
      expect(CssNotFound.new('style.css', nil, provider).message).to eq(
21 +
      expect(CssNotFound.new("style.css", nil, provider).message).to eq(
22 22
        %(Could not find stylesheet "style.css"\nUsed provider:\n#{provider})
23 23
      )
24 24
    end

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe Stylesheet do
@@ -18,7 +18,7 @@
Loading
18 18
      expect(stylesheet.blocks.map(&:to_s)).to eq([
19 19
        "body{color:green !important;font-size:200%}",
20 20
        "a{color:red}",
21 -
        "i{color:red}",
21 +
        "i{color:red}"
22 22
      ])
23 23
    end
24 24

@@ -1,8 +1,8 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
5 -
require 'shared_examples/asset_provider'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 +
require "shared_examples/asset_provider"
6 6
7 7
module Roadie
8 8
  describe NetHttpProvider do
@@ -12,7 +12,7 @@
Loading
12 12
      WebMock.allow_net_connect!
13 13
    end
14 14
15 -
    url = "http://example.com/style.css".freeze
15 +
    url = "http://example.com/style.css"
16 16
17 17
    it_behaves_like(
18 18
      "roadie asset provider",
@@ -51,7 +51,7 @@
Loading
51 51
      # use when trying to make sense of these bytes.
52 52
      stub_request(:get, url).and_return(
53 53
        body: (+%(p::before { content: "l\xF6ve" })).force_encoding("US-ASCII"),
54 -
        headers: {"Content-Type" => "text/css;charset=ISO-8859-1"},
54 +
        headers: {"Content-Type" => "text/css;charset=ISO-8859-1"}
55 55
      )
56 56
57 57
      # Seems like CssParser strips out the non-ascii character for some
@@ -67,7 +67,7 @@
Loading
67 67
    it "assumes UTF-8 encoding if server headers do not specify a charset" do
68 68
      stub_request(:get, url).and_return(
69 69
        body: (+%(p::before { content: "Åh nej" })).force_encoding("US-ASCII"),
70 -
        headers: {"Content-Type" => "text/css"},
70 +
        headers: {"Content-Type" => "text/css"}
71 71
      )
72 72
73 73
      # Seems like CssParser strips out the non-ascii characters for some
@@ -119,10 +119,10 @@
Loading
119 119
        provider = NetHttpProvider.new(whitelist: ["whitelisted.example.com"])
120 120
121 121
        whitelisted_url = "http://whitelisted.example.com/style.css"
122 -
        other_url       = "http://www.example.com/style.css"
122 +
        other_url = "http://www.example.com/style.css"
123 123
124 124
        whitelisted_request = stub_request(:get, whitelisted_url).and_return(body: +"x")
125 -
        other_request       = stub_request(:get, other_url).and_return(body: +"x")
125 +
        other_request = stub_request(:get, other_url).and_return(body: +"x")
126 126
127 127
        expect(provider.find_stylesheet(other_url)).to be_nil
128 128
        expect {

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'shared_examples/asset_provider'
3 +
require "spec_helper"
4 +
require "shared_examples/asset_provider"
5 5
6 6
module Roadie
7 7
  describe NullProvider do

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'forwardable'
3 +
require "forwardable"
4 4
5 5
module Roadie
6 6
  # @api private
@@ -39,7 +39,7 @@
Loading
39 39
    # @return {String}
40 40
    def to_s
41 41
      # NB - leave off redundant final semicolon - see https://www.w3.org/TR/CSS2/syndata.html#declaration
42 -
      "#{selector}{#{properties.map(&:to_s).join(';')}}"
42 +
      "#{selector}{#{properties.map(&:to_s).join(";")}}"
43 43
    end
44 44
45 45
    private
@@ -49,7 +49,7 @@
Loading
49 49
    # @media only screen and (max-width: 600px) {...} cannot be inlined
50 50
    # @return {Boolean}
51 51
    def inlinable_media?
52 -
      @media.none? { |media_query| media_query.include? '(' }
52 +
      @media.none? { |media_query| media_query.include? "(" }
53 53
    end
54 54
  end
55 55
end

@@ -69,6 +69,7 @@
Loading
69 69
    end
70 70
71 71
    private
72 +
72 73
    def cache_fetch(name)
73 74
      cache[name] || cache[name] = yield
74 75
    rescue CssNotFound

@@ -2,7 +2,6 @@
Loading
2 2
3 3
RSpec::Matchers.define :have_selector do |selector|
4 4
  match { |document| !document.css(selector).empty? }
5 -
  failure_message { "expected document to have selector #{selector.inspect}"}
6 -
  failure_message_when_negated { "expected document to not have selector #{selector.inspect}"}
5 +
  failure_message { "expected document to have selector #{selector.inspect}" }
6 +
  failure_message_when_negated { "expected document to not have selector #{selector.inspect}" }
7 7
end
8 -

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
describe "Roadie functionality" do
6 6
  describe "on full documents" do
@@ -13,14 +13,7 @@
Loading
13 13
      document = Roadie::Document.new(html)
14 14
      result = document.transform
15 15
16 -
      unless defined?(JRuby)
17 -
        # JRuby has a bug that makes DTD manipulation impossible
18 -
        # See Nokogiri bugs #984 and #985
19 -
        # https://github.com/sparklemotion/nokogiri/issues/984
20 -
        # https://github.com/sparklemotion/nokogiri/issues/985
21 -
        expect(result).to include("<!DOCTYPE html>")
22 -
      end
23 -
16 +
      expect(result).to include("<!DOCTYPE html>")
24 17
      expect(result).to include("<html>")
25 18
      expect(result).to include("<head>")
26 19
      expect(result).to include("<body>")
@@ -47,8 +40,8 @@
Loading
47 40
      CSS
48 41
49 42
      result = parse_html document.transform
50 -
      expect(result).to have_styling('text-align' => 'center').at_selector('h1')
51 -
      expect(result).to have_styling('color' => 'red').at_selector('p > em')
43 +
      expect(result).to have_styling("text-align" => "center").at_selector("h1")
44 +
      expect(result).to have_styling("color" => "red").at_selector("p > em")
52 45
    end
53 46
54 47
    it "stores styles that cannot be inlined in the <head>" do
@@ -112,7 +105,7 @@
Loading
112 105
      HTML
113 106
114 107
      result = parse_html document.transform
115 -
      expect(result).to have_styling('font-size' => '200%').at_selector('p > em')
108 +
      expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
116 109
    end
117 110
118 111
    it "crashes when stylesheets cannot be found, unless using NullProvider" do
@@ -151,8 +144,8 @@
Loading
151 144
      document.external_asset_providers = []
152 145
153 146
      result = parse_html document.transform
154 -
      expect(result).to have_selector('head > link')
155 -
      expect(result).to have_styling([]).at_selector('p > em')
147 +
      expect(result).to have_selector("head > link")
148 +
      expect(result).to have_styling([]).at_selector("p > em")
156 149
    end
157 150
158 151
    it "inlines external css if configured" do
@@ -175,8 +168,8 @@
Loading
175 168
      )
176 169
177 170
      result = parse_html document.transform
178 -
      expect(result).to have_styling('font-size' => '200%').at_selector('p > em')
179 -
      expect(result).to_not have_selector('head > link')
171 +
      expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
172 +
      expect(result).to_not have_selector("head > link")
180 173
    end
181 174
182 175
    it "does not inline the same properties several times" do
@@ -197,8 +190,8 @@
Loading
197 190
198 191
      result = parse_html document.transform
199 192
      expect(result).to have_styling([
200 -
        ['color', 'red']
201 -
      ]).at_selector('p')
193 +
        ["color", "red"]
194 +
      ]).at_selector("p")
202 195
    end
203 196
204 197
    it "makes URLs absolute" do
@@ -232,7 +225,7 @@
Loading
232 225
      ).at_selector("body")
233 226
234 227
      expect(result).to have_styling(
235 -
        "background" => 'url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)'
228 +
        "background" => "url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)"
236 229
      ).at_selector("a")
237 230
    end
238 231
@@ -324,10 +317,10 @@
Loading
324 317
      )
325 318
326 319
      result = parse_html document.transform
327 -
      expect(result).to have_styling('color' => 'green').at_selector('.colorful')
320 +
      expect(result).to have_styling("color" => "green").at_selector(".colorful")
328 321
    end
329 322
330 -
    it 'puts non-inlineable media queries in the head' do
323 +
    it "puts non-inlineable media queries in the head" do
331 324
      document = Roadie::Document.new <<-HTML
332 325
        <html>
333 326
          <head>
@@ -353,18 +346,18 @@
Loading
353 346
354 347
      result = parse_html document.transform
355 348
356 -
      styles = result.at_css('html > head > style').text
349 +
      styles = result.at_css("html > head > style").text
357 350
      expected_result = <<-CSS
358 351
        @media screen and (max-width 800px) { .colorful{color:blue} }
359 352
        @media screen, print and (max-width 800px) { .colorful{color:blue} }
360 353
      CSS
361 -
      expected_result = expected_result.gsub(/[\s]+/, ' ').strip
362 -
      actual_result = styles.gsub(/[\s]+/, ' ').strip
354 +
      expected_result = expected_result.gsub(/\s+/, " ").strip
355 +
      actual_result = styles.gsub(/\s+/, " ").strip
363 356
364 357
      expect(actual_result).to eq(expected_result)
365 358
    end
366 359
367 -
    it 'groups non-inlineable media queries in the head by default' do
360 +
    it "groups non-inlineable media queries in the head by default" do
368 361
      document = Roadie::Document.new <<-HTML
369 362
        <html>
370 363
          <head>
@@ -390,20 +383,20 @@
Loading
390 383
391 384
      result = parse_html document.transform
392 385
393 -
      styles = result.at_css('html > head > style').text
386 +
      styles = result.at_css("html > head > style").text
394 387
      expected_result = <<-CSS
395 388
        @media screen and (max-width 600px) {
396 389
          .colorful{color:red;width:600px}
397 390
          .colorful-2{color:red;width:600px}
398 391
        }
399 392
      CSS
400 -
      expected_result = expected_result.gsub(/[\s]+/, ' ').strip
401 -
      actual_result = styles.gsub(/[\s]+/, ' ').strip
393 +
      expected_result = expected_result.gsub(/\s+/, " ").strip
394 +
      actual_result = styles.gsub(/\s+/, " ").strip
402 395
403 396
      expect(actual_result).to eq(expected_result)
404 397
    end
405 398
406 -
    describe 'if merge_media_queries is set to false' do
399 +
    describe "if merge_media_queries is set to false" do
407 400
      it "doesn't group non-inlineable media queries in the head" do
408 401
        document = Roadie::Document.new <<-HTML
409 402
          <html>
@@ -432,7 +425,7 @@
Loading
432 425
433 426
        result = parse_html document.transform
434 427
435 -
        styles = result.at_css('html > head > style').text
428 +
        styles = result.at_css("html > head > style").text
436 429
        expected_result = <<-CSS
437 430
          @media screen and (max-width 600px) {
438 431
            .colorful{color:red;width:600px}
@@ -441,8 +434,8 @@
Loading
441 434
            .colorful-2{color:red;width:600px}
442 435
          }
443 436
        CSS
444 -
        expected_result = expected_result.gsub(/[\s]+/, ' ').strip
445 -
        actual_result = styles.gsub(/[\s]+/, ' ').strip
437 +
        expected_result = expected_result.gsub(/\s+/, " ").strip
438 +
        actual_result = styles.gsub(/\s+/, " ").strip
446 439
447 440
        expect(actual_result).to eq(expected_result)
448 441
      end
@@ -474,8 +467,8 @@
Loading
474 467
      CSS
475 468
476 469
      result = parse_html document.transform_partial
477 -
      expect(result).to have_styling('text-align' => 'center').at_selector('h1')
478 -
      expect(result).to have_styling('color' => 'red').at_selector('p > em')
470 +
      expect(result).to have_styling("text-align" => "center").at_selector("h1")
471 +
      expect(result).to have_styling("color" => "red").at_selector("p > em")
479 472
    end
480 473
481 474
    it "stores styles that cannot be inlined in a new <style> element" do
@@ -523,7 +516,7 @@
Loading
523 516
      HTML
524 517
525 518
      result = parse_html document.transform_partial
526 -
      expect(result).to have_styling('font-size' => '200%').at_selector('p > em')
519 +
      expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
527 520
    end
528 521
529 522
    it "crashes when stylesheets cannot be found, unless using NullProvider" do
@@ -547,8 +540,8 @@
Loading
547 540
      document.external_asset_providers = []
548 541
549 542
      result = parse_html document.transform_partial
550 -
      expect(result).to have_xpath('./link')
551 -
      expect(result).to have_styling([]).at_selector('p > em')
543 +
      expect(result).to have_xpath("./link")
544 +
      expect(result).to have_styling([]).at_selector("p > em")
552 545
    end
553 546
554 547
    it "inlines external css if configured" do
@@ -563,8 +556,8 @@
Loading
563 556
      )
564 557
565 558
      result = parse_html document.transform_partial
566 -
      expect(result).to have_styling('font-size' => '200%').at_selector('p > em')
567 -
      expect(result).to_not have_xpath('./link')
559 +
      expect(result).to have_styling("font-size" => "200%").at_selector("p > em")
560 +
      expect(result).to_not have_xpath("./link")
568 561
    end
569 562
570 563
    it "does not inline the same properties several times" do
@@ -581,8 +574,8 @@
Loading
581 574
582 575
      result = parse_html document.transform_partial
583 576
      expect(result).to have_styling([
584 -
        ['color', 'red']
585 -
      ]).at_selector('p')
577 +
        ["color", "red"]
578 +
      ]).at_selector("p")
586 579
    end
587 580
588 581
    it "makes URLs absolute" do
@@ -615,7 +608,7 @@
Loading
615 608
      ).at_selector("div")
616 609
617 610
      expect(result).to have_styling(
618 -
        "background" => 'url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)'
611 +
        "background" => "url(https://myapp.com/rails/app/assets/link-abcdef1234567890.png)"
619 612
      ).at_selector("a")
620 613
    end
621 614

@@ -1,11 +1,13 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe Inliner do
7 -
    before { @stylesheet = "".freeze }
8 -
    def use_css(css) @stylesheet = Stylesheet.new("example", css) end
7 +
    before { @stylesheet = "" }
8 +
    def use_css(css)
9 +
      @stylesheet = Stylesheet.new("example", css)
10 +
    end
9 11
10 12
    def rendering(html, stylesheet = @stylesheet)
11 13
      dom = Nokogiri::HTML.parse html
@@ -15,17 +17,17 @@
Loading
15 17
16 18
    describe "inlining styles" do
17 19
      it "inlines simple attributes" do
18 -
        use_css 'p { color: green }'
19 -
        expect(rendering('<p></p>')).to have_styling('color' => 'green')
20 +
        use_css "p { color: green }"
21 +
        expect(rendering("<p></p>")).to have_styling("color" => "green")
20 22
      end
21 23
22 24
      it "keeps multiple versions of the same property to support progressive enhancement" do
23 25
        # https://github.com/premailer/css_parser/issues/44
24 26
        pending "css_parser issue #44"
25 27
26 -
        use_css 'p { color: #eee; color: rgba(255, 255, 255, 0.9); }'
27 -
        expect(rendering('<p></p>')).to have_styling(
28 -
          [['color', 'green'], ['color', 'rgba(255, 255, 255, 0.9)']]
28 +
        use_css "p { color: #eee; color: rgba(255, 255, 255, 0.9); }"
29 +
        expect(rendering("<p></p>")).to have_styling(
30 +
          [["color", "green"], ["color", "rgba(255, 255, 255, 0.9)"]]
29 31
        )
30 32
      end
31 33
@@ -36,35 +38,35 @@
Loading
36 38
          .positive { color: green; }
37 39
        '
38 40
        expect(rendering('<p class="message positive"></p>')).to have_styling(
39 -
          [['color', 'blue'], ['color', 'green']]
41 +
          [["color", "blue"], ["color", "green"]]
40 42
        )
41 43
      end
42 44
43 45
      it "inlines browser-prefixed attributes" do
44 -
        use_css 'p { -vendor-color: green }'
45 -
        expect(rendering('<p></p>')).to have_styling('-vendor-color' => 'green')
46 +
        use_css "p { -vendor-color: green }"
47 +
        expect(rendering("<p></p>")).to have_styling("-vendor-color" => "green")
46 48
      end
47 49
48 50
      it "inlines CSS3 attributes" do
49 -
        use_css 'p { border-radius: 2px; }'
50 -
        expect(rendering('<p></p>')).to have_styling('border-radius' => '2px')
51 +
        use_css "p { border-radius: 2px; }"
52 +
        expect(rendering("<p></p>")).to have_styling("border-radius" => "2px")
51 53
      end
52 54
53 55
      it "keeps the order of the styles that are inlined" do
54 -
        use_css 'h1 { padding: 2px; margin: 5px; }'
55 -
        expect(rendering('<h1></h1>')).to have_styling([['padding', '2px'], ['margin', '5px']])
56 +
        use_css "h1 { padding: 2px; margin: 5px; }"
57 +
        expect(rendering("<h1></h1>")).to have_styling([["padding", "2px"], ["margin", "5px"]])
56 58
      end
57 59
58 60
      it "combines multiple selectors into one" do
59 61
        use_css 'p { color: green; }
60 62
                .tip { float: right; }'
61 -
        expect(rendering('<p class="tip"></p>')).to have_styling([['color', 'green'], ['float', 'right']])
63 +
        expect(rendering('<p class="tip"></p>')).to have_styling([["color", "green"], ["float", "right"]])
62 64
      end
63 65
64 66
      it "uses the attributes with the highest specificity when conflicts arises" do
65 67
        use_css ".safe { color: green; }
66 68
                p { color: red; }"
67 -
        expect(rendering('<p class="safe"></p>')).to have_styling([['color', 'red'], ['color', 'green']])
69 +
        expect(rendering('<p class="safe"></p>')).to have_styling([["color", "red"], ["color", "green"]])
68 70
      end
69 71
70 72
      it "sorts styles by specificity order" do
@@ -82,10 +84,10 @@
Loading
82 84
      end
83 85
84 86
      it "supports multiple selectors for the same rules" do
85 -
        use_css 'p, a { color: green; }'
86 -
        rendering('<p></p><a></a>').tap do |document|
87 -
          expect(document).to have_styling('color' => 'green').at_selector('p')
88 -
          expect(document).to have_styling('color' => 'green').at_selector('a')
87 +
        use_css "p, a { color: green; }"
88 +
        rendering("<p></p><a></a>").tap do |document|
89 +
          expect(document).to have_styling("color" => "green").at_selector("p")
90 +
          expect(document).to have_styling("color" => "green").at_selector("a")
89 91
        end
90 92
      end
91 93
@@ -93,22 +95,22 @@
Loading
93 95
        use_css "a { text-decoration: underline !important; }
94 96
                 a.hard-to-spot { text-decoration: none; }"
95 97
        expect(rendering('<a class="hard-to-spot"></a>')).to have_styling([
96 -
          ['text-decoration', 'none'], ['text-decoration', 'underline !important']
98 +
          ["text-decoration", "none"], ["text-decoration", "underline !important"]
97 99
        ])
98 100
      end
99 101
100 102
      it "combines with already present inline styles" do
101 103
        use_css "p { color: green }"
102 -
        expect(rendering('<p style="font-size: 1.1em"></p>')).to have_styling([['color', 'green'], ['font-size', '1.1em']])
104 +
        expect(rendering('<p style="font-size: 1.1em"></p>')).to have_styling([["color", "green"], ["font-size", "1.1em"]])
103 105
      end
104 106
105 107
      it "does not override inline styles" do
106 108
        use_css "p { text-transform: uppercase; color: red }"
107 109
        # The two color properties are kept to make css fallbacks work correctly
108 110
        expect(rendering('<p style="color: green"></p>')).to have_styling([
109 -
          ['text-transform', 'uppercase'],
110 -
          ['color', 'red'],
111 -
          ['color', 'green'],
111 +
          ["text-transform", "uppercase"],
112 +
          ["color", "red"],
113 +
          ["color", "green"]
112 114
        ])
113 115
      end
114 116
@@ -123,7 +125,7 @@
Loading
123 125
124 126
          p.active { width: 100%; }
125 127
        "
126 -
        expect(rendering('<p class="active"></p>')).to have_styling('width' => '100%')
128 +
        expect(rendering('<p class="active"></p>')).to have_styling("width" => "100%")
127 129
      end
128 130
129 131
      it "does not crash on any pseudo element selectors" do
@@ -131,7 +133,7 @@
Loading
131 133
          p.some-element { width: 100%; }
132 134
          p::some-element { color: red; }
133 135
        "
134 -
        expect(rendering('<p class="some-element"></p>')).to have_styling('width' => '100%')
136 +
        expect(rendering('<p class="some-element"></p>')).to have_styling("width" => "100%")
135 137
      end
136 138
137 139
      it "warns on selectors that crash Nokogiri" do
@@ -140,7 +142,7 @@
Loading
140 142
        stylesheet = Stylesheet.new "foo.css", "p[%^=foo] { color: red; }"
141 143
        inliner = Inliner.new([stylesheet], dom)
142 144
        expect(Utils).to receive(:warn).with(
143 -
          %{Cannot inline "p[%^=foo]" from "foo.css" stylesheet. If this is valid CSS, please report a bug.}
145 +
          %(Cannot inline "p[%^=foo]" from "foo.css" stylesheet. If this is valid CSS, please report a bug.)
144 146
        )
145 147
        inliner.inline
146 148
      end
@@ -152,8 +154,8 @@
Loading
152 154
        "
153 155
        result = rendering("<p></p> <p></p>")
154 156
155 -
        expect(result).to have_styling([['color', 'red']]).at_selector('p:first')
156 -
        expect(result).to have_styling([['color', 'red'], ['color', 'green']]).at_selector('p:last')
157 +
        expect(result).to have_styling([["color", "red"]]).at_selector("p:first")
158 +
        expect(result).to have_styling([["color", "red"], ["color", "green"]]).at_selector("p:last")
157 159
      end
158 160
159 161
      context "with uninlinable selectors" do
@@ -162,7 +164,7 @@
Loading
162 164
        end
163 165
164 166
        it "puts them in a new <style> element in the <head>" do
165 -
          use_css 'a:hover { color: red; }'
167 +
          use_css "a:hover { color: red; }"
166 168
          result = rendering("
167 169
            <html>
168 170
              <head></head>
@@ -174,7 +176,7 @@
Loading
174 176
        end
175 177
176 178
        it "puts them in <head> on unexpected inlining problems" do
177 -
          use_css 'p:some-future-thing { color: red; }'
179 +
          use_css "p:some-future-thing { color: red; }"
178 180
          result = rendering("
179 181
            <html>
180 182
              <head></head>
@@ -198,15 +200,9 @@
Loading
198 200
          }'
199 201
200 202
          use_css css
201 -
          result = rendering('<p></p>')
203 +
          result = rendering("<p></p>")
202 204
203 205
          expect(result).to have_styling([]).at_selector("p")
204 -
205 -
          # css_parser actually sees an empty @keyframes on JRuby, and nothing
206 -
          # on the others
207 -
          if (style_element = result.at_css("head > style"))
208 -
            expect(style_element.text).to_not include "background-position"
209 -
          end
210 206
        end
211 207
212 208
        it "ignores them if told not to keep them" do
@@ -225,14 +221,14 @@
Loading
225 221
        end
226 222
227 223
        it "puts the <style> element at the root when told so" do
228 -
          stylesheet = use_css 'a:hover { color: red; }'
224 +
          stylesheet = use_css "a:hover { color: red; }"
229 225
          dom = Nokogiri::HTML.fragment("
230 226
            <a></a>
231 227
          ")
232 228
233 229
          Inliner.new([stylesheet], dom).inline(
234 230
            keep_uninlinable_css: true,
235 -
            keep_uninlinable_in: :root,
231 +
            keep_uninlinable_in: :root
236 232
          )
237 233
238 234
          expect(dom).to have_xpath("./a")
@@ -240,7 +236,7 @@
Loading
240 236
        end
241 237
242 238
        it "raises error when told to save styles in an unknown place" do
243 -
          stylesheet = use_css 'a:hover { color: red; }'
239 +
          stylesheet = use_css "a:hover { color: red; }"
244 240
          dom = Nokogiri::HTML.fragment("
245 241
            <a></a>
246 242
          ")
@@ -249,7 +245,7 @@
Loading
249 245
          expect {
250 246
            inliner.inline(
251 247
              keep_uninlinable_css: true,
252 -
              keep_uninlinable_in: :unknown_place,
248 +
              keep_uninlinable_in: :unknown_place
253 249
            )
254 250
          }.to raise_error(ArgumentError, /:unknown_place/)
255 251
        end

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 5
6 6
module Roadie
7 7
  describe ProviderList do
@@ -69,16 +69,16 @@
Loading
69 69
      provider = double("Provider", to_s: "Some provider")
70 70
      sublist = ProviderList.new([provider, provider])
71 71
      list = ProviderList.new([provider, sublist, provider])
72 -
      expect(list.to_s).to eql(
73 -
        "ProviderList: [\n" +
74 -
          "\tSome provider,\n" +
75 -
          "\tProviderList: [\n" +
76 -
            "\t\tSome provider,\n" +
77 -
            "\t\tSome provider\n" +
78 -
          "\t],\n" +
79 -
          "\tSome provider\n" +
80 -
        "]"
81 -
      )
72 +
      expect(list.to_s).to eq(<<~TEXT)
73 +
        ProviderList: [
74 +
        \tSome provider,
75 +
        \tProviderList: [
76 +
        \t\tSome provider,
77 +
        \t\tSome provider
78 +
        \t],
79 +
        \tSome provider
80 +
        ]
81 +
      TEXT
82 82
    end
83 83
84 84
    it "raises a readable error message" do
@@ -91,14 +91,14 @@
Loading
91 91
      list = ProviderList.new([provider, sublist, provider])
92 92
93 93
      expect { list.find_stylesheet!("style.css") }.to raise_error { |error|
94 -
        expect(error.message).to eq(
95 -
          "Could not find stylesheet \"style.css\": All providers failed\n" +
96 -
          "Used providers:\n" +
97 -
            "\tSome provider: I tripped\n" +
98 -
            "\tSome provider: I tripped\n" +
99 -
            "\tSome provider: I tripped\n" +
100 -
            "\tSome provider: I tripped\n"
101 -
        )
94 +
        expect(error.message).to eq(<<~TEXT)
95 +
          Could not find stylesheet "style.css": All providers failed
96 +
          Used providers:
97 +
          \tSome provider: I tripped
98 +
          \tSome provider: I tripped
99 +
          \tSome provider: I tripped
100 +
          \tSome provider: I tripped
101 +
        TEXT
102 102
      }
103 103
    end
104 104

@@ -3,30 +3,30 @@
Loading
3 3
module Roadie
4 4
end
5 5
6 -
require 'roadie/version'
7 -
require 'roadie/errors'
6 +
require "roadie/version"
7 +
require "roadie/errors"
8 8
9 -
require 'roadie/utils'
10 -
require 'roadie/deduplicator'
9 +
require "roadie/utils"
10 +
require "roadie/deduplicator"
11 11
12 -
require 'roadie/stylesheet'
13 -
require 'roadie/selector'
14 -
require 'roadie/style_property'
15 -
require 'roadie/style_attribute_builder'
16 -
require 'roadie/style_block'
12 +
require "roadie/stylesheet"
13 +
require "roadie/selector"
14 +
require "roadie/style_property"
15 +
require "roadie/style_attribute_builder"
16 +
require "roadie/style_block"
17 17
18 -
require 'roadie/asset_provider'
19 -
require 'roadie/provider_list'
20 -
require 'roadie/filesystem_provider'
21 -
require 'roadie/null_provider'
22 -
require 'roadie/net_http_provider'
23 -
require 'roadie/cached_provider'
24 -
require 'roadie/path_rewriter_provider'
18 +
require "roadie/asset_provider"
19 +
require "roadie/provider_list"
20 +
require "roadie/filesystem_provider"
21 +
require "roadie/null_provider"
22 +
require "roadie/net_http_provider"
23 +
require "roadie/cached_provider"
24 +
require "roadie/path_rewriter_provider"
25 25
26 -
require 'roadie/asset_scanner'
27 -
require 'roadie/markup_improver'
28 -
require 'roadie/url_generator'
29 -
require 'roadie/url_rewriter'
30 -
require 'roadie/null_url_rewriter'
31 -
require 'roadie/inliner'
32 -
require 'roadie/document'
26 +
require "roadie/asset_scanner"
27 +
require "roadie/markup_improver"
28 +
require "roadie/url_generator"
29 +
require "roadie/url_rewriter"
30 +
require "roadie/null_url_rewriter"
31 +
require "roadie/inliner"
32 +
require "roadie/document"

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'forwardable'
3 +
require "forwardable"
4 4
5 5
module Roadie
6 6
  # An asset provider that just composes a list of other asset providers.
@@ -25,7 +25,7 @@
Loading
25 25
    # @overload wrap(provider1, provider2, ...)
26 26
    #   @return a new {ProviderList} with all the passed providers in it.
27 27
    def self.wrap(*providers)
28 -
      if providers.size == 1 && providers.first.class == self
28 +
      if providers.size == 1 && providers.first.instance_of?(self)
29 29
        providers.first
30 30
      else
31 31
        new(providers.flatten)
@@ -33,7 +33,9 @@
Loading
33 33
    end
34 34
35 35
    # Returns a new empty list.
36 -
    def self.empty() new([]) end
36 +
    def self.empty
37 +
      new([])
38 +
    end
37 39
38 40
    def initialize(providers)
39 41
      @providers = providers
@@ -55,11 +57,9 @@
Loading
55 57
    def find_stylesheet!(name)
56 58
      errors = []
57 59
      @providers.each do |provider|
58 -
        begin
59 -
          return provider.find_stylesheet!(name)
60 -
        rescue CssNotFound => error
61 -
          errors << error
62 -
        end
60 +
        return provider.find_stylesheet!(name)
61 +
      rescue CssNotFound => error
62 +
        errors << error
63 63
      end
64 64
      raise ProvidersFailed.new(name, self, errors)
65 65
    end
@@ -69,12 +69,14 @@
Loading
69 69
        # Indent every line one level
70 70
        provider.to_s.split("\n").join("\n\t")
71 71
      }
72 -
      "ProviderList: [\n\t#{list.join(",\n\t")}\n]"
72 +
      "ProviderList: [\n\t#{list.join(",\n\t")}\n]\n"
73 73
    end
74 74
75 75
    # ProviderList can be coerced to an array. This makes Array#flatten work
76 76
    # with it, among other things.
77 -
    def to_ary() to_a end
77 +
    def to_ary
78 +
      to_a
79 +
    end
78 80
79 81
    # @!method each
80 82
    #   @see Array#each

@@ -36,10 +36,16 @@
Loading
36 36
      end
37 37
    end
38 38
39 -
    def to_s() inspect end
40 -
    def inspect() "#<#{self.class} #@path>" end
39 +
    def to_s
40 +
      inspect
41 +
    end
42 +
43 +
    def inspect
44 +
      "#<#{self.class} #{@path}>"
45 +
    end
41 46
42 47
    private
48 +
43 49
    def build_file_path(name)
44 50
      raise InsecurePathError, name if name.include?("..")
45 51
      File.join(@path, name[/^([^?]+)/])

@@ -1,4 +1,4 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'roadie/rspec/asset_provider'
4 -
require 'roadie/rspec/cache_store'
3 +
require "roadie/rspec/asset_provider"
4 +
require "roadie/rspec/cache_store"

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 5
6 6
describe TestProvider do
7 7
  subject(:provider) { TestProvider.new }
@@ -13,7 +13,7 @@
Loading
13 13
  it "finds styles from a predefined hash" do
14 14
    provider = TestProvider.new({
15 15
      "foo.css" => "a { color: red; }",
16 -
      "bar.css" => "body { color: green; }",
16 +
      "bar.css" => "body { color: green; }"
17 17
    })
18 18
    expect(provider.find_stylesheet("foo.css").to_s).not_to include("body")
19 19
    expect(provider.find_stylesheet("bar.css").to_s).to include("body")
@@ -23,7 +23,7 @@
Loading
23 23
  it "can have a default for missing entries" do
24 24
    provider = TestProvider.new({
25 25
      "foo.css" => "a { color: red; }",
26 -
      :default  => "body { color: green; }",
26 +
      :default => "body { color: green; }"
27 27
    })
28 28
    expect(provider.find_stylesheet("foo.css").to_s).not_to include("body")
29 29
    expect(provider.find_stylesheet("bar.css").to_s).to include("body")

@@ -37,9 +37,17 @@
Loading
37 37
      !(pseudo_element? || at_rule? || pseudo_function?)
38 38
    end
39 39
40 -
    def to_s() selector end
41 -
    def to_str() to_s end
42 -
    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
43 51
44 52
    # {Selector}s are equal to other {Selector}s if, and only if, their string
45 53
    # representations are equal.
@@ -52,9 +60,11 @@
Loading
52 60
    end
53 61
54 62
    protected
63 +
55 64
    attr_reader :selector
56 65
57 66
    private
67 +
58 68
    BAD_PSEUDO_FUNCTIONS = %w[
59 69
      :active :focus :hover :link :target :visited
60 70
      :-ms-input-placeholder :-moz-placeholder
@@ -63,11 +73,11 @@
Loading
63 73
    ].freeze
64 74
65 75
    def pseudo_element?
66 -
      selector.include? '::'
76 +
      selector.include? "::"
67 77
    end
68 78
69 79
    def at_rule?
70 -
      selector[0, 1] == '@'
80 +
      selector[0, 1] == "@"
71 81
    end
72 82
73 83
    def pseudo_function?

@@ -2,7 +2,6 @@
Loading
2 2
3 3
RSpec::Matchers.define :have_xpath do |xpath|
4 4
  match { |document| !document.xpath(xpath).empty? }
5 -
  failure_message { "expected document to have xpath #{xpath.inspect}"}
6 -
  failure_message_when_negated { "expected document to not have xpath #{xpath.inspect}"}
5 +
  failure_message { "expected document to have xpath #{xpath.inspect}" }
6 +
  failure_message_when_negated { "expected document to not have xpath #{xpath.inspect}" }
7 7
end
8 -

@@ -11,11 +11,11 @@
Loading
11 11
    end
12 12
  end
13 13
14 -
  failure_message { "expected document to #{name_to_sentence}#{expected_to_sentence}"}
15 -
  failure_message_when_negated { "expected document to not #{name_to_sentence}#{expected_to_sentence}"}
14 +
  failure_message { "expected document to #{name_to_sentence}#{expected_to_sentence}" }
15 +
  failure_message_when_negated { "expected document to not #{name_to_sentence}#{expected_to_sentence}" }
16 16
17 17
  def match_attributes(node_attributes)
18 -
    attributes = Hash[node_attributes.map { |name, attribute| [name, attribute.value] }]
18 +
    attributes = node_attributes.map { |name, attribute| [name, attribute.value] }.to_h
19 19
    @attributes == attributes
20 20
  end
21 21
end

@@ -1,8 +1,8 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'set'
4 -
require 'uri'
5 -
require 'net/http'
3 +
require "set"
4 +
require "uri"
5 +
require "net/http"
6 6
7 7
module Roadie
8 8
  # @api public
@@ -34,7 +34,7 @@
Loading
34 34
35 35
    def find_stylesheet!(url)
36 36
      response = download(url)
37 -
      if response.kind_of? Net::HTTPSuccess
37 +
      if response.is_a? Net::HTTPSuccess
38 38
        Stylesheet.new(url, response_body(response))
39 39
      else
40 40
        raise CssNotFound.new(url, "Server returned #{response.code}: #{truncate response.body}", self)
@@ -43,10 +43,16 @@
Loading
43 43
      raise CssNotFound.new(url, "Timeout", self)
44 44
    end
45 45
46 -
    def to_s() inspect end
47 -
    def inspect() "#<#{self.class} whitelist: #{whitelist.inspect}>" end
46 +
    def to_s
47 +
      inspect
48 +
    end
49 +
50 +
    def inspect
51 +
      "#<#{self.class} whitelist: #{whitelist.inspect}>"
52 +
    end
48 53
49 54
    private
55 +
50 56
    def host_set(hosts)
51 57
      hosts.each { |host| validate_host(host) }.to_set
52 58
    end
@@ -71,7 +77,7 @@
Loading
71 77
      if RUBY_VERSION >= "2.0.0"
72 78
        Net::HTTP.get_response(uri)
73 79
      else
74 -
        Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
80 +
        Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == "https")) do |http|
75 81
          http.request(Net::HTTP::Get.new(uri.request_uri))
76 82
        end
77 83
      end
@@ -92,7 +98,7 @@
Loading
92 98
    def response_body(response)
93 99
      # Make sure we respect encoding because Net:HTTP will encode body as ASCII by default
94 100
      # which will break if the response is not compatible.
95 -
      supplied_charset = response.type_params['charset']
101 +
      supplied_charset = response.type_params["charset"]
96 102
      body = response.body
97 103
98 104
      if supplied_charset

@@ -43,15 +43,15 @@
Loading
43 43
    # @see #find_css
44 44
    # @return [Enumerable<Stylesheet>] every extracted stylesheet
45 45
    def extract_css
46 -
      stylesheets = @dom.css(STYLE_ELEMENT_QUERY).map { |element|
46 +
      @dom.css(STYLE_ELEMENT_QUERY).map { |element|
47 47
        stylesheet = read_stylesheet(element)
48 48
        element.remove if stylesheet
49 49
        stylesheet
50 50
      }.compact
51 -
      stylesheets
52 51
    end
53 52
54 53
    private
54 +
55 55
    STYLE_ELEMENT_QUERY = (
56 56
      "style:not([data-roadie-ignore]), " +
57 57
      # TODO: When using Nokogiri 1.6.1 and later; we may use a double :not here
@@ -75,7 +75,7 @@
Loading
75 75
    def read_stylesheet(element)
76 76
      if element.name == "style"
77 77
        read_style_element element
78 -
      elsif element.name == "link" && element['media'] != "print" && element["href"]
78 +
      elsif element.name == "link" && element["media"] != "print" && element["href"]
79 79
        read_link_element element
80 80
      end
81 81
    end
@@ -86,14 +86,14 @@
Loading
86 86
87 87
    def read_link_element(element)
88 88
      if Utils.path_is_absolute?(element["href"])
89 -
        external_asset_provider.find_stylesheet! element['href'] if should_find_external?
89 +
        external_asset_provider.find_stylesheet! element["href"] if should_find_external?
90 90
      else
91 -
        normal_asset_provider.find_stylesheet! element['href']
91 +
        normal_asset_provider.find_stylesheet! element["href"]
92 92
      end
93 93
    end
94 94
95 95
    def clean_css(css)
96 -
      css.gsub(CLEANING_MATCHER, '')
96 +
      css.gsub(CLEANING_MATCHER, "")
97 97
    end
98 98
99 99
    def should_find_external?

@@ -26,6 +26,7 @@
Loading
26 26
    end
27 27
28 28
    private
29 +
29 30
    attr_reader :input, :latest_occurance
30 31
31 32
    def has_duplicates?

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe StyleBlock do

@@ -7,8 +7,12 @@
Loading
7 7
  # Used whenever client does not pass any URL options and no URL rewriting
8 8
  # should take place.
9 9
  class NullUrlRewriter
10 -
    def initialize(generator = nil) end
11 -
    def transform_dom(dom) end
10 +
    def initialize(generator = nil)
11 +
    end
12 +
13 +
    def transform_dom(dom)
14 +
    end
15 +
12 16
    def transform_css(css)
13 17
      css
14 18
    end

@@ -18,10 +18,10 @@
Loading
18 18
19 19
    def initialize(given_path, cause = nil)
20 20
      @cause = cause
21 -
      if cause
22 -
        cause_message = " Caused by: #{cause}"
21 +
      cause_message = if cause
22 +
        " Caused by: #{cause}"
23 23
      else
24 -
        cause_message = ""
24 +
        ""
25 25
      end
26 26
      super "Cannot use path \"#{given_path}\" in URL generation.#{cause_message}"
27 27
    end
@@ -52,11 +52,13 @@
Loading
52 52
    end
53 53
54 54
    protected
55 +
55 56
    def error_row
56 57
      "#{provider || "Unknown provider"}: #{extra_message || message}"
57 58
    end
58 59
59 60
    private
61 +
60 62
    # Redundant method argument is to keep API compatability without major version bump.
61 63
    # TODO: Remove argument on version 4.0.
62 64
    def build_message(extra_message = @extra_message)
@@ -76,6 +78,7 @@
Loading
76 78
    end
77 79
78 80
    private
81 +
79 82
    def build_message(extra_message)
80 83
      message = +%(Could not find stylesheet "#{css_name}": #{extra_message}\nUsed providers:\n)
81 84
      each_error_row(errors) do |row|

@@ -6,13 +6,26 @@
Loading
6 6
  # Use it to ignore missing assets or in your tests when you need a provider
7 7
  # but you do not care what it contains or that it is even referenced at all.
8 8
  class NullProvider
9 -
    def find_stylesheet(name) empty_stylesheet end
10 -
    def find_stylesheet!(name) empty_stylesheet end
9 +
    def find_stylesheet(name)
10 +
      empty_stylesheet
11 +
    end
11 12
12 -
    def to_s() inspect end
13 -
    def inspect() "#<#{self.class}>" end
13 +
    def find_stylesheet!(name)
14 +
      empty_stylesheet
15 +
    end
16 +
17 +
    def to_s
18 +
      inspect
19 +
    end
20 +
21 +
    def inspect
22 +
      "#<#{self.class}>"
23 +
    end
14 24
15 25
    private
16 -
    def empty_stylesheet() Stylesheet.new "(null)", "" end
26 +
27 +
    def empty_stylesheet
28 +
      Stylesheet.new "(null)", ""
29 +
    end
17 30
  end
18 31
end

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe Document do
@@ -94,8 +94,8 @@
Loading
94 94
    describe "transforming" do
95 95
      it "runs the before and after callbacks" do
96 96
        document = Document.new "<body></body>"
97 -
        before = ->{}
98 -
        after = ->{}
97 +
        before = -> {}
98 +
        after = -> {}
99 99
        document.before_transformation = before
100 100
        document.after_transformation = after
101 101
@@ -109,8 +109,8 @@
Loading
109 109
      # TODO: Remove on next major version.
110 110
      it "works on callables that don't expect more than one argument" do
111 111
        document = Document.new "<body></body>"
112 -
        document.before_transformation = ->(first) { }
113 -
        document.after_transformation = ->(first = nil) { }
112 +
        document.before_transformation = ->(first) {}
113 +
        document.after_transformation = ->(first = nil) {}
114 114
115 115
        expect { document.transform }.to_not raise_error
116 116
@@ -135,7 +135,7 @@
Loading
135 135
          document = Document.new "<img src='https://google.com/image.png'></img>"
136 136
          document.mode = :xml
137 137
138 -
          expect(document.transform_partial).to end_with('</img>')
138 +
          expect(document.transform_partial).to end_with("</img>")
139 139
        end
140 140
141 141
        it "does not escape curly braces" do
@@ -149,21 +149,21 @@
Loading
149 149
    describe "partial transforming" do
150 150
      it "runs the before and after callbacks" do
151 151
        document = Document.new "<p></p>"
152 -
        before = ->{}
153 -
        after = ->{}
152 +
        before = -> {}
153 +
        after = -> {}
154 154
        document.before_transformation = before
155 155
        document.after_transformation = after
156 156
157 157
        expect(before).to receive(:call).with(
158 158
          instance_of(Nokogiri::HTML::DocumentFragment),
159 -
          document,
159 +
          document
160 160
        ).ordered
161 161
162 162
        expect(Inliner).to receive(:new).ordered.and_return double.as_null_object
163 163
164 164
        expect(after).to receive(:call).with(
165 165
          instance_of(Nokogiri::HTML::DocumentFragment),
166 -
          document,
166 +
          document
167 167
        ).ordered
168 168
169 169
        document.transform_partial
@@ -183,7 +183,7 @@
Loading
183 183
          document = Document.new "<img src='https://google.com/image.png'></img>"
184 184
          document.mode = :xml
185 185
186 -
          expect(document.transform_partial).to end_with('</img>')
186 +
          expect(document.transform_partial).to end_with("</img>")
187 187
        end
188 188
189 189
        it "does not escape curly braces" do
@@ -212,11 +212,11 @@
Loading
212 212
213 213
      result = Nokogiri::HTML.parse document.transform
214 214
215 -
      expect(result).to have_selector('html > head > title')
216 -
      expect(result.at_css('title').text).to eq("Greetings")
215 +
      expect(result).to have_selector("html > head > title")
216 +
      expect(result.at_css("title").text).to eq("Greetings")
217 217
218 -
      expect(result).to have_selector('html > body > p')
219 -
      paragraph = result.at_css('p')
218 +
      expect(result).to have_selector("html > body > p")
219 +
      paragraph = result.at_css("p")
220 220
      expect(paragraph.text).to eq("Hello, world!")
221 221
      expect(paragraph.to_xml).to eq('<p style="color:green">Hello, world!</p>')
222 222
    end
@@ -235,7 +235,7 @@
Loading
235 235
      HTML
236 236
237 237
      document.asset_providers = TestProvider.new({
238 -
        "/sample.css" => "p { color: red; text-align: right; }",
238 +
        "/sample.css" => "p { color: red; text-align: right; }"
239 239
      })
240 240
241 241
      document.add_css "p { color: green; text-size: 2em; }"

@@ -25,9 +25,9 @@
Loading
25 25
      dom.css(
26 26
        "a[href]:not([data-roadie-ignore]), " \
27 27
          "img[src]:not([data-roadie-ignore]), " \
28 -
          "*[style]:not([data-roadie-ignore])",
28 +
          "*[style]:not([data-roadie-ignore])"
29 29
      ).each do |element|
30 -
        transform_element_style element if element.has_attribute?('style')
30 +
        transform_element_style element if element.has_attribute?("style")
31 31
        transform_element element
32 32
      end
33 33
      nil
@@ -49,7 +49,10 @@
Loading
49 49
    end
50 50
51 51
    private
52 -
    def generate_url(*args) @generator.generate_url(*args) end
52 +
53 +
    def generate_url(*args)
54 +
      @generator.generate_url(*args)
55 +
    end
53 56
54 57
    # Regexp matching all the url() declarations in CSS
55 58
    #

@@ -152,6 +152,7 @@
Loading
152 152
    end
153 153
154 154
    private
155 +
155 156
    VALID_MODES = %i[html xhtml xml].freeze
156 157
    private_constant :VALID_MODES
157 158
@@ -169,7 +170,7 @@
Loading
169 170
      Inliner.new(dom_stylesheets + [stylesheet], dom).inline(
170 171
        keep_uninlinable_css: keep_uninlinable_css,
171 172
        keep_uninlinable_in: keep_uninlinable_in,
172 -
        merge_media_queries: merge_media_queries,
173 +
        merge_media_queries: merge_media_queries
173 174
      )
174 175
    end
175 176
@@ -183,7 +184,7 @@
Loading
183 184
      format = {
184 185
        html: save_options::AS_HTML,
185 186
        xhtml: save_options::AS_XHTML,
186 -
        xml: save_options::AS_XML,
187 +
        xml: save_options::AS_XML
187 188
      }.fetch(mode)
188 189
189 190
      dom.dup.to_html(
@@ -191,7 +192,7 @@
Loading
191 192
          save_options::NO_DECLARATION |
192 193
          save_options::NO_EMPTY_TAGS |
193 194
          format
194 -
        ),
195 +
        )
195 196
      )
196 197
    end
197 198
@@ -208,9 +209,9 @@
Loading
208 209
        # Arity checking is to support the API without bumping a major version.
209 210
        # TODO: Remove on next major version (v4.0)
210 211
        if !callable.respond_to?(:parameters) || callable.parameters.size == 1
211 -
          callable.(dom)
212 +
          callable.call(dom)
212 213
        else
213 -
          callable.(dom, self)
214 +
          callable.call(dom, self)
214 215
        end
215 216
      end
216 217
    end

@@ -1,7 +1,7 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'shared_examples/url_rewriter'
3 +
require "spec_helper"
4 +
require "shared_examples/url_rewriter"
5 5
6 6
module Roadie
7 7
  describe UrlRewriter do
@@ -11,7 +11,9 @@
Loading
11 11
    it_behaves_like "url rewriter"
12 12
13 13
    describe "transforming DOM trees" do
14 -
      def dom_document(html); Nokogiri::HTML.parse html; end
14 +
      def dom_document(html)
15 +
        Nokogiri::HTML.parse html
16 +
      end
15 17
16 18
      it "rewrites all a[href]" do
17 19
        expect(generator).to receive(:generate_url).with("some/path").and_return "http://foo.com/"
@@ -89,7 +91,7 @@
Loading
89 91
90 92
      it "correctly identifies URLs with parenthesis inside them" do
91 93
        expect(generator).to receive(:generate_url).with("images/map_(large_(extra)).png").and_return "x"
92 -
        rewriter.transform_css 'url(images/map_(large_(extra)).png)'
94 +
        rewriter.transform_css "url(images/map_(large_(extra)).png)"
93 95
      end
94 96
    end
95 97
  end

@@ -9,13 +9,13 @@
Loading
9 9
        ["a", "1"],
10 10
        ["b", "2"],
11 11
        ["a", "3"],
12 -
        ["a", "1"],
12 +
        ["a", "1"]
13 13
      ]
14 14
15 15
      expect(Deduplicator.apply(input)).to eq [
16 16
        ["b", "2"],
17 17
        ["a", "3"],
18 -
        ["a", "1"],
18 +
        ["a", "1"]
19 19
      ]
20 20
    end
21 21
@@ -23,7 +23,7 @@
Loading
23 23
      input = [
24 24
        ["a", "1"],
25 25
        ["a", "3"],
26 -
        ["a", "2"],
26 +
        ["a", "2"]
27 27
      ]
28 28
29 29
      expect(Deduplicator.apply(input)).to eq input

@@ -1,21 +1,28 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'set'
4 -
require 'nokogiri'
5 -
require 'uri'
6 -
require 'css_parser'
3 +
require "set"
4 +
require "nokogiri"
5 +
require "uri"
6 +
require "css_parser"
7 7
8 8
module Roadie
9 9
  # @api private
10 10
  # The Inliner inlines stylesheets to the elements of the DOM.
11 11
  #
12 12
  # Inlining means that {StyleBlock}s and a DOM tree are combined:
13 -
  #   a { color: red; } # StyleBlock
14 -
  #   <a href="/"></a>  # DOM
13 +
  #
14 +
  # ```css
15 +
  # a { color: red; } # StyleBlock
16 +
  # ```
17 +
  # ```html
18 +
  # <a href="/"></a>  # DOM
19 +
  # ```
15 20
  #
16 21
  # becomes
17 22
  #
18 -
  #   <a href="/" style="color:red"></a>
23 +
  # ```html
24 +
  # <a href="/" style="color:red"></a>
25 +
  # ```
19 26
  class Inliner
20 27
    # @param [Array<Stylesheet>] stylesheets the stylesheets to use in the inlining
21 28
    # @param [Nokogiri::HTML::Document] dom
@@ -47,9 +54,11 @@
Loading
47 54
    end
48 55
49 56
    protected
57 +
50 58
    attr_reader :stylesheets, :dom
51 59
52 60
    private
61 +
53 62
    def consume_stylesheets
54 63
      style_map = StyleMap.new
55 64
      extra_blocks = []
@@ -91,12 +100,18 @@
Loading
91 100
    # with having to rescue errors.
92 101
    # Pseudo selectors that are known to be bad are skipped automatically but
93 102
    # this will catch the rest.
94 -
    rescue Nokogiri::XML::XPath::SyntaxError, Nokogiri::CSS::SyntaxError => error
95 -
      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 +
      )
96 108
      nil
97 109
    rescue => error
98 -
      Utils.warn "Got error when looking for #{selector.inspect} (from \"#{stylesheet.name}\" stylesheet): #{error}"
99 -
      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")
100 115
      nil
101 116
    end
102 117
@@ -122,12 +137,12 @@
Loading
122 137
    end
123 138
124 139
    def find_head
125 -
      dom.at_xpath('html/head')
140 +
      dom.at_xpath("html/head")
126 141
    end
127 142
128 143
    def create_style_element(style_blocks, parent, merge_media_queries)
129 144
      return unless parent
130 -
      element = Nokogiri::XML::Node.new('style', parent.document)
145 +
      element = Nokogiri::XML::Node.new("style", parent.document)
131 146
132 147
      element.content =
133 148
        if merge_media_queries
@@ -141,17 +156,23 @@
Loading
141 156
    # For performance reasons, we should group styles with the same media types within
142 157
    # one media query instead of creating thousands of media queries.
143 158
    # https://github.com/artifex404/media-queries-benchmark
144 -
    # 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 +
    #
145 166
    # @param {Array<StyleBlock>} style_blocks  Style blocks that could not be inlined
146 167
    # @return {Array<String>}
147 168
    def styles_in_shared_media_queries(style_blocks)
148 169
      style_blocks.group_by(&:media).map do |media_types, blocks|
149 170
        css_rules = blocks.map(&:to_s).join("\n")
150 171
151 -
        if media_types == ['all']
172 +
        if media_types == ["all"]
152 173
          css_rules
153 174
        else
154 -
          "@media #{media_types.join(', ')} {\n#{css_rules}\n}"
175 +
          "@media #{media_types.join(", ")} {\n#{css_rules}\n}"
155 176
        end
156 177
      end
157 178
    end
@@ -159,27 +180,36 @@
Loading
159 180
    # Some users might prefer to not group rules within media queries because
160 181
    # it will result in rules getting reordered.
161 182
    # e.g.
183 +
    #
184 +
    # ```css
162 185
    # @media(max-width: 600px) { .col-6 { display: block; } }
163 186
    # @media(max-width: 400px) { .col-12 { display: inline-block; } }
164 187
    # @media(max-width: 600px) { .col-12 { display: block; } }
188 +
    # ````
189 +
    #
165 190
    # will become
191 +
    #
192 +
    # ```css
166 193
    # @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
167 194
    # @media(max-width: 400px) { .col-12 { display: inline-block; } }
195 +
    # ```
196 +
    #
197 +
    #
168 198
    # which would change the styling on the page
169 199
    # (before it would've yielded display: block; for .col-12 at max-width: 600px
170 200
    # and now it yields inline-block;)
171 201
    #
172 202
    # If merge_media_queries is set to false,
173 -
    # we will generate #{style_blocks.size} media queries, potentially
203 +
    # we will generate `style_blocks.size` media queries, potentially
174 204
    # causing performance issues.
175 205
    # @param {Array<StyleBlock>} style_blocks  All style blocks
176 206
    # @return {Array<String>}
177 207
    def styles_in_individual_media_queries(style_blocks)
178 208
      style_blocks.map do |css_rule|
179 -
        if css_rule.media == ['all']
209 +
        if css_rule.media == ["all"]
180 210
          css_rule
181 211
        else
182 -
          "@media #{css_rule.media.join(', ')} {\n#{css_rule}\n}"
212 +
          "@media #{css_rule.media.join(", ")} {\n#{css_rule}\n}"
183 213
        end
184 214
      end
185 215
    end

@@ -8,7 +8,7 @@
Loading
8 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.
9 9
  # @attr_reader [Array<StyleBlock>] blocks
10 10
  class Stylesheet
11 -
    BOM = (+"\xEF\xBB\xBF").force_encoding('UTF-8').freeze
11 +
    BOM = (+"\xEF\xBB\xBF").force_encoding("UTF-8").freeze
12 12
13 13
    attr_reader :name, :blocks
14 14
@@ -26,6 +26,7 @@
Loading
26 26
    end
27 27
28 28
    private
29 +
29 30
    def inlinable_blocks
30 31
      blocks.select(&:inlinable?)
31 32
    end

@@ -5,7 +5,7 @@
Loading
5 5
6 6
  chain(:at_selector) { |selector| @selector = selector }
7 7
  match { |document|
8 -
    @selector ||= 'body > *:first'
8 +
    @selector ||= "body > *:first"
9 9
    normalized_rules == styles_at_selector(document)
10 10
  }
11 11
@@ -23,7 +23,7 @@
Loading
23 23
24 24
  def styles_at_selector(document)
25 25
    expect(document).to have_selector(@selector)
26 -
    StylingExpectation.new document.at_css(@selector)['style']
26 +
    StylingExpectation.new document.at_css(@selector)["style"]
27 27
  end
28 28
end
29 29
@@ -42,23 +42,22 @@
Loading
42 42
    rules == other.rules
43 43
  end
44 44
45 -
  def to_s() rules.to_s end
45 +
  def to_s
46 +
    rules.to_s
47 +
  end
46 48
47 49
  protected
50 +
48 51
  attr_reader :rules
49 52
50 53
  private
54 +
51 55
  def parse_rules(css)
52 -
    css.split(';').map { |property| parse_property(property) }
56 +
    css.split(";").map { |property| parse_property(property) }
53 57
  end
54 58
55 59
  def parse_property(property)
56 -
    rule, value = property.split(':', 2).map(&:strip)
57 -
    [rule, normalize_quotes(value)]
58 -
  end
59 -
60 -
  # JRuby's Nokogiri encodes quotes
61 -
  def normalize_quotes(string)
62 -
    string.gsub '%22', '"'
60 +
    rule, value = property.split(":", 2).map(&:strip)
61 +
    [rule, value]
63 62
  end
64 63
end

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe MarkupImprover do
@@ -10,22 +10,14 @@
Loading
10 10
      dom
11 11
    end
12 12
13 -
    # JRuby up to at least 1.6.0 has a bug where the doctype of a document cannot be changed.
14 -
    # See https://github.com/sparklemotion/nokogiri/issues/984
15 -
    def pending_for_buggy_jruby
16 -
      # No reason to check for version yet since no existing version has a fix.
17 -
      skip "Pending until Nokogiri issue #984 is fixed and released" if defined?(JRuby)
18 -
    end
19 -
20 13
    describe "automatic doctype" do
21 14
      it "inserts a HTML5 doctype if no doctype is present" do
22 -
        pending_for_buggy_jruby
23 15
        expect(improve("<html></html>").internal_subset.to_xml).to eq("<!DOCTYPE html>")
24 16
      end
25 17
26 18
      it "does not insert duplicate doctypes" do
27 -
        html = improve('<!DOCTYPE html><html><body></body></html>').to_html
28 -
        expect(html.scan('DOCTYPE').size).to eq(1)
19 +
        html = improve("<!DOCTYPE html><html><body></body></html>").to_html
20 +
        expect(html.scan("DOCTYPE").size).to eq(1)
29 21
      end
30 22
31 23
      it "leaves other doctypes alone" do
@@ -39,35 +31,35 @@
Loading
39 31
      it "inserts a <html> element as the root" do
40 32
        expect(improve("")).to have_selector("html")
41 33
        expect(improve("<h1>Hey!</h1>")).to have_selector("html h1")
42 -
        expect(improve("<html></html>").css('html').size).to eq(1)
34 +
        expect(improve("<html></html>").css("html").size).to eq(1)
43 35
      end
44 36
45 37
      it "inserts <head> if not present" do
46 -
        expect(improve('<html><body></body></html>')).to have_selector('html > head + body')
47 -
        expect(improve('<html></html>')).to have_selector('html > head')
48 -
        expect(improve('Foo')).to have_selector('html > head')
49 -
        expect(improve('<html><head></head></html>').css('head').size).to eq(1)
38 +
        expect(improve("<html><body></body></html>")).to have_selector("html > head + body")
39 +
        expect(improve("<html></html>")).to have_selector("html > head")
40 +
        expect(improve("Foo")).to have_selector("html > head")
41 +
        expect(improve("<html><head></head></html>").css("head").size).to eq(1)
50 42
      end
51 43
52 44
      it "inserts <body> if not present" do
53 -
        expect(improve('<h1>Hey!</h1>')).to have_selector('html > body > h1')
54 -
        expect(improve('<html><h1>Hey!</h1></html>')).to have_selector('html > body > h1')
55 -
        expect(improve('<html><body><h1>Hey!</h1></body></html>').css('body').size).to eq(1)
45 +
        expect(improve("<h1>Hey!</h1>")).to have_selector("html > body > h1")
46 +
        expect(improve("<html><h1>Hey!</h1></html>")).to have_selector("html > body > h1")
47 +
        expect(improve("<html><body><h1>Hey!</h1></body></html>").css("body").size).to eq(1)
56 48
      end
57 49
    end
58 50
59 51
    describe "charset declaration" do
60 52
      it "is inserted if missing" do
61 -
        dom = improve('<html><head></head><body></body></html>')
53 +
        dom = improve("<html><head></head><body></body></html>")
62 54
63 -
        expect(dom).to have_selector('head meta')
64 -
        meta = dom.at_css('head meta')
65 -
        expect(meta['http-equiv']).to eq('Content-Type')
66 -
        expect(meta['content']).to eq('text/html; charset=UTF-8')
55 +
        expect(dom).to have_selector("head meta")
56 +
        meta = dom.at_css("head meta")
57 +
        expect(meta["http-equiv"]).to eq("Content-Type")
58 +
        expect(meta["content"]).to eq("text/html; charset=UTF-8")
67 59
      end
68 60
69 61
      it "is left alone when predefined" do
70 -
        expect(improve(<<-HTML).xpath('//meta')).to have(1).item
62 +
        expect(improve(<<-HTML).xpath("//meta")).to have(1).item
71 63
        <html>
72 64
          <head>
73 65
            <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

@@ -1,8 +1,8 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
4 -
require 'roadie/rspec'
5 -
require 'shared_examples/asset_provider'
3 +
require "spec_helper"
4 +
require "roadie/rspec"
5 +
require "shared_examples/asset_provider"
6 6
7 7
module Roadie
8 8
  describe FilesystemProvider do
@@ -63,13 +63,11 @@
Loading
63 63
      end
64 64
65 65
      it "shows that the query string is ignored inside raised errors" do
66 -
        begin
67 -
          provider.find_stylesheet!("/foo.css?query-string")
68 -
          fail "No error was raised"
69 -
        rescue CssNotFound => error
70 -
          expect(error.css_name).to eq("foo.css")
71 -
          expect(error.to_s).to include("/foo.css?query-string")
72 -
        end
66 +
        provider.find_stylesheet!("/foo.css?query-string")
67 +
        fail "No error was raised"
68 +
      rescue CssNotFound => error
69 +
        expect(error.css_name).to eq("foo.css")
70 +
        expect(error.to_s).to include("/foo.css?query-string")
73 71
      end
74 72
    end
75 73
  end

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe AssetScanner do
@@ -8,8 +8,13 @@
Loading
8 8
    let(:external_provider) { ProviderList.empty }
9 9
    let(:dom) { dom_document "<html></html>" }
10 10
11 -
    def dom_fragment(html); Nokogiri::HTML.fragment html; end
12 -
    def dom_document(html); Nokogiri::HTML.parse html; end
11 +
    def dom_fragment(html)
12 +
      Nokogiri::HTML.fragment html
13 +
    end
14 +
15 +
    def dom_document(html)
16 +
      Nokogiri::HTML.parse html
17 +
    end
13 18
14 19
    it "is initialized with a DOM tree, a normal asset provider set, and an external asset provider set" do
15 20
      scanner = AssetScanner.new dom, normal_provider, external_provider
@@ -111,7 +116,7 @@
Loading
111 116
        expect(scanner.find_css).to eq([])
112 117
      end
113 118
114 -
      it 'ignores HTML comments and CDATA sections' do
119 +
      it "ignores HTML comments and CDATA sections" do
115 120
        # TinyMCE posts invalid CSS. We support that just to be pragmatic.
116 121
        dom = dom_fragment %(<style><![CDATA[
117 122
          <!--

@@ -1,6 +1,6 @@
Loading
1 1
# frozen_string_literal: true
2 2
3 -
require 'spec_helper'
3 +
require "spec_helper"
4 4
5 5
module Roadie
6 6
  describe Selector do
@@ -31,15 +31,15 @@
Loading
31 31
        expect(Selector.new(bad_selector)).not_to be_inlinable
32 32
      end
33 33
34 -
      expect(Selector.new('p.active')).to be_inlinable
34 +
      expect(Selector.new("p.active")).to be_inlinable
35 35
    end
36 36
37 37
    it "cannot be inlined when containing pseudo elements" do
38 -
      expect(Selector.new('p::some-element')).not_to be_inlinable
38 +
      expect(Selector.new("p::some-element")).not_to be_inlinable
39 39
    end
40 40
41 41
    it "cannot be inlined when selector is an at-rule" do
42 -
      expect(Selector.new('@keyframes progress-bar-stripes')).not_to be_inlinable
42 +
      expect(Selector.new("@keyframes progress-bar-stripes")).not_to be_inlinable
43 43
    end
44 44
45 45
    it "has a calculated specificity" do

@@ -10,7 +10,7 @@
Loading
10 10
      #
11 11
      # URLs that start with double slashes (//css/app.css) are also absolute
12 12
      # in modern browsers, but most email clients do not understand them.
13 -
      return true if path =~ %r{^(\w+:|//)}
13 +
      return true if %r{^(\w+:|//)}.match?(path)
14 14
15 15
      begin
16 16
        !URI.parse(path).relative?
Files Coverage
lib 98.76%
spec 97.52%
Project Totals (57 files) 97.98%
1786054333
1786054333
1786054333
1786054333

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading