roadie 3.5.1 → 5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +43 -0
- data/.rubocop.yml +5 -0
- data/.solargraph.yml +16 -0
- data/Changelog.md +30 -4
- data/Gemfile +7 -2
- data/README.md +12 -14
- data/Rakefile +4 -3
- data/lib/roadie/asset_provider.rb +5 -1
- data/lib/roadie/asset_scanner.rb +8 -6
- data/lib/roadie/cached_provider.rb +3 -0
- data/lib/roadie/deduplicator.rb +3 -0
- data/lib/roadie/document.rb +10 -11
- data/lib/roadie/errors.rb +22 -16
- data/lib/roadie/filesystem_provider.rb +15 -3
- data/lib/roadie/inliner.rb +51 -19
- data/lib/roadie/markup_improver.rb +24 -31
- data/lib/roadie/net_http_provider.rb +27 -12
- data/lib/roadie/null_provider.rb +20 -5
- data/lib/roadie/null_url_rewriter.rb +11 -3
- data/lib/roadie/path_rewriter_provider.rb +6 -1
- data/lib/roadie/provider_list.rb +17 -11
- data/lib/roadie/rspec/asset_provider.rb +6 -1
- data/lib/roadie/rspec/cache_store.rb +2 -0
- data/lib/roadie/rspec.rb +4 -2
- data/lib/roadie/selector.rb +18 -5
- data/lib/roadie/style_attribute_builder.rb +4 -1
- data/lib/roadie/style_block.rb +5 -3
- data/lib/roadie/style_property.rb +5 -2
- data/lib/roadie/stylesheet.rb +4 -13
- data/lib/roadie/url_generator.rb +26 -8
- data/lib/roadie/url_rewriter.rb +12 -9
- data/lib/roadie/utils.rb +3 -1
- data/lib/roadie/version.rb +1 -1
- data/lib/roadie.rb +25 -23
- data/roadie.gemspec +23 -23
- data/spec/hash_as_cache_store_spec.rb +3 -1
- data/spec/integration_spec.rb +43 -44
- data/spec/lib/roadie/asset_scanner_spec.rb +11 -5
- data/spec/lib/roadie/cached_provider_spec.rb +6 -4
- data/spec/lib/roadie/css_not_found_spec.rb +10 -5
- data/spec/lib/roadie/deduplicator_spec.rb +5 -3
- data/spec/lib/roadie/document_spec.rb +47 -28
- data/spec/lib/roadie/filesystem_provider_spec.rb +10 -11
- data/spec/lib/roadie/inliner_spec.rb +42 -45
- data/spec/lib/roadie/markup_improver_spec.rb +19 -26
- data/spec/lib/roadie/net_http_provider_spec.rb +16 -14
- data/spec/lib/roadie/null_provider_spec.rb +4 -3
- data/spec/lib/roadie/null_url_rewriter_spec.rb +4 -3
- data/spec/lib/roadie/path_rewriter_provider_spec.rb +6 -4
- data/spec/lib/roadie/provider_list_spec.rb +27 -22
- data/spec/lib/roadie/selector_spec.rb +7 -5
- data/spec/lib/roadie/style_attribute_builder_spec.rb +7 -5
- data/spec/lib/roadie/style_block_spec.rb +3 -2
- data/spec/lib/roadie/style_property_spec.rb +10 -8
- data/spec/lib/roadie/stylesheet_spec.rb +4 -21
- data/spec/lib/roadie/test_provider_spec.rb +6 -4
- data/spec/lib/roadie/url_generator_spec.rb +3 -2
- data/spec/lib/roadie/url_rewriter_spec.rb +10 -7
- data/spec/lib/roadie/utils_spec.rb +2 -0
- data/spec/shared_examples/asset_provider.rb +2 -0
- data/spec/shared_examples/url_rewriter.rb +5 -3
- data/spec/spec_helper.rb +10 -8
- data/spec/support/have_attribute_matcher.rb +3 -2
- data/spec/support/have_node_matcher.rb +5 -3
- data/spec/support/have_selector_matcher.rb +4 -3
- data/spec/support/have_styling_matcher.rb +12 -11
- data/spec/support/have_xpath_matcher.rb +4 -3
- data/spec/support/test_provider.rb +2 -0
- metadata +24 -8
- data/.travis.yml +0 -22
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
2
4
|
|
3
5
|
module Roadie
|
4
6
|
describe StyleProperty do
|
5
7
|
it "is initialized with a property, value, if it is marked as important, and the specificity" do
|
6
|
-
StyleProperty.new(
|
7
|
-
expect(declaration.property).to eq(
|
8
|
-
expect(declaration.value).to eq(
|
8
|
+
StyleProperty.new("color", "green", true, 45).tap do |declaration|
|
9
|
+
expect(declaration.property).to eq("color")
|
10
|
+
expect(declaration.value).to eq("green")
|
9
11
|
expect(declaration).to be_important
|
10
12
|
expect(declaration.specificity).to eq(45)
|
11
13
|
end
|
@@ -13,18 +15,18 @@ module Roadie
|
|
13
15
|
|
14
16
|
describe "string representation" do
|
15
17
|
it "is the property and the value joined with a colon" do
|
16
|
-
expect(StyleProperty.new(
|
17
|
-
expect(StyleProperty.new(
|
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
20
|
end
|
19
21
|
|
20
22
|
it "contains the !important flag when set" do
|
21
|
-
expect(StyleProperty.new(
|
23
|
+
expect(StyleProperty.new("color", "green", true, 1).to_s).to eq("color:green !important")
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
27
|
describe "comparing" do
|
26
28
|
def declaration(specificity, important = false)
|
27
|
-
StyleProperty.new(
|
29
|
+
StyleProperty.new("color", "green", important, specificity)
|
28
30
|
end
|
29
31
|
|
30
32
|
it "compares on specificity" do
|
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
3
4
|
|
4
5
|
module Roadie
|
5
6
|
describe Stylesheet do
|
@@ -17,28 +18,10 @@ module Roadie
|
|
17
18
|
expect(stylesheet.blocks.map(&:to_s)).to eq([
|
18
19
|
"body{color:green !important;font-size:200%}",
|
19
20
|
"a{color:red}",
|
20
|
-
"i{color:red}"
|
21
|
+
"i{color:red}"
|
21
22
|
])
|
22
23
|
end
|
23
24
|
|
24
|
-
if VERSION < "4.0"
|
25
|
-
it "can iterate all inlinable blocks" do
|
26
|
-
inlinable = double(inlinable?: true, selector: "good", properties: "props")
|
27
|
-
bad = double(inlinable?: false, selector: "bad", properties: "props")
|
28
|
-
|
29
|
-
stylesheet = Stylesheet.new("example.css", "")
|
30
|
-
allow(stylesheet).to receive_messages blocks: [bad, inlinable, bad]
|
31
|
-
|
32
|
-
expect(stylesheet.each_inlinable_block.to_a).to eq([
|
33
|
-
["good", "props"],
|
34
|
-
])
|
35
|
-
end
|
36
|
-
else
|
37
|
-
it "should no longer have #each_inlinable_block" do
|
38
|
-
fail "Remove #each_inlinable_block"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
25
|
it "has a string representation of the contents" do
|
43
26
|
stylesheet = Stylesheet.new("example.css", "body { color: green;}a{ color: red; font-size: small }")
|
44
27
|
expect(stylesheet.to_s).to eq("body{color:green}\na{color:red;font-size:small}")
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "roadie/rspec"
|
3
5
|
|
4
6
|
describe TestProvider do
|
5
7
|
subject(:provider) { TestProvider.new }
|
@@ -11,7 +13,7 @@ describe TestProvider do
|
|
11
13
|
it "finds styles from a predefined hash" do
|
12
14
|
provider = TestProvider.new({
|
13
15
|
"foo.css" => "a { color: red; }",
|
14
|
-
"bar.css" => "body { color: green; }"
|
16
|
+
"bar.css" => "body { color: green; }"
|
15
17
|
})
|
16
18
|
expect(provider.find_stylesheet("foo.css").to_s).not_to include("body")
|
17
19
|
expect(provider.find_stylesheet("bar.css").to_s).to include("body")
|
@@ -21,7 +23,7 @@ describe TestProvider do
|
|
21
23
|
it "can have a default for missing entries" do
|
22
24
|
provider = TestProvider.new({
|
23
25
|
"foo.css" => "a { color: red; }",
|
24
|
-
:default
|
26
|
+
:default => "body { color: green; }"
|
25
27
|
})
|
26
28
|
expect(provider.find_stylesheet("foo.css").to_s).not_to include("body")
|
27
29
|
expect(provider.find_stylesheet("bar.css").to_s).to include("body")
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
require "shared_examples/url_rewriter"
|
3
5
|
|
4
6
|
module Roadie
|
5
7
|
describe UrlRewriter do
|
@@ -9,7 +11,9 @@ module Roadie
|
|
9
11
|
it_behaves_like "url rewriter"
|
10
12
|
|
11
13
|
describe "transforming DOM trees" do
|
12
|
-
def dom_document(html)
|
14
|
+
def dom_document(html)
|
15
|
+
Nokogiri::HTML.parse html
|
16
|
+
end
|
13
17
|
|
14
18
|
it "rewrites all a[href]" do
|
15
19
|
expect(generator).to receive(:generate_url).with("some/path").and_return "http://foo.com/"
|
@@ -71,9 +75,8 @@ module Roadie
|
|
71
75
|
it "rewrites all url() directives" do
|
72
76
|
expect(generator).to receive(:generate_url).with("some/path.jpg").and_return "http://foo.com/image.jpg"
|
73
77
|
css = "body { background: top url(some/path.jpg) #eee; }"
|
74
|
-
|
75
|
-
|
76
|
-
}.to change { css }.to "body { background: top url(http://foo.com/image.jpg) #eee; }"
|
78
|
+
transformed_css = rewriter.transform_css css
|
79
|
+
expect(transformed_css).to eq "body { background: top url(http://foo.com/image.jpg) #eee; }"
|
77
80
|
end
|
78
81
|
|
79
82
|
it "correctly identifies URLs with single quotes" do
|
@@ -88,7 +91,7 @@ module Roadie
|
|
88
91
|
|
89
92
|
it "correctly identifies URLs with parenthesis inside them" do
|
90
93
|
expect(generator).to receive(:generate_url).with("images/map_(large_(extra)).png").and_return "x"
|
91
|
-
rewriter.transform_css
|
94
|
+
rewriter.transform_css "url(images/map_(large_(extra)).png)"
|
92
95
|
end
|
93
96
|
end
|
94
97
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
shared_examples_for "url rewriter" do
|
2
4
|
it "is constructed with a generator" do
|
3
5
|
generator = double "URL generator"
|
@@ -6,7 +8,7 @@ shared_examples_for "url rewriter" do
|
|
6
8
|
}.to_not raise_error
|
7
9
|
end
|
8
10
|
|
9
|
-
it "has a #transform_dom(dom) method that returns
|
11
|
+
it "has a #transform_dom(dom) method that returns the modified string" do
|
10
12
|
expect(subject).to respond_to(:transform_dom)
|
11
13
|
expect(subject.method(:transform_dom).arity).to eq(1)
|
12
14
|
|
@@ -14,10 +16,10 @@ shared_examples_for "url rewriter" do
|
|
14
16
|
expect(subject.transform_dom(dom)).to be_nil
|
15
17
|
end
|
16
18
|
|
17
|
-
it "has a #transform_css(css) method that returns
|
19
|
+
it "has a #transform_css(css) method that returns the modified string" do
|
18
20
|
expect(subject).to respond_to(:transform_css)
|
19
21
|
expect(subject.method(:transform_css).arity).to eq(1)
|
20
22
|
|
21
|
-
expect(subject.transform_css("")).to
|
23
|
+
expect(subject.transform_css("")).to eq("")
|
22
24
|
end
|
23
25
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
-
|
2
|
-
require 'webmock/rspec'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
require "rspec/collection_matchers"
|
4
|
+
require "webmock/rspec"
|
5
|
+
|
6
|
+
if ENV["CI"]
|
7
|
+
require "simplecov"
|
6
8
|
SimpleCov.start
|
7
9
|
|
8
|
-
require
|
10
|
+
require "codecov"
|
9
11
|
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
10
12
|
end
|
11
13
|
|
12
|
-
$: << File.dirname(__FILE__) +
|
13
|
-
require
|
14
|
+
$: << File.dirname(__FILE__) + "/../lib"
|
15
|
+
require "roadie"
|
14
16
|
|
15
17
|
RSpec.configure do |config|
|
16
18
|
config.run_all_when_everything_filtered = true
|
17
19
|
end
|
18
20
|
|
19
|
-
Dir[
|
21
|
+
Dir["./spec/support/**/*.rb"].sort.each { |file| require file }
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_attribute do |attribute|
|
2
|
-
@selector =
|
4
|
+
@selector = "body > *:first"
|
3
5
|
|
4
6
|
chain :at_selector do |selector|
|
5
7
|
@selector = selector
|
@@ -25,4 +27,3 @@ RSpec::Matchers.define :have_attribute do |attribute|
|
|
25
27
|
node && node[attribute_name]
|
26
28
|
end
|
27
29
|
end
|
28
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_node do |selector|
|
2
4
|
chain(:with_attributes) { |attributes| @attributes = attributes }
|
3
5
|
match do |document|
|
@@ -9,11 +11,11 @@ RSpec::Matchers.define :have_node do |selector|
|
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
|
-
failure_message { "expected document to #{name_to_sentence}#{expected_to_sentence}"}
|
13
|
-
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}" }
|
14
16
|
|
15
17
|
def match_attributes(node_attributes)
|
16
|
-
attributes =
|
18
|
+
attributes = node_attributes.map { |name, attribute| [name, attribute.value] }.to_h
|
17
19
|
@attributes == attributes
|
18
20
|
end
|
19
21
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_selector do |selector|
|
2
4
|
match { |document| !document.css(selector).empty? }
|
3
|
-
failure_message { "expected document to have selector #{selector.inspect}"}
|
4
|
-
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}" }
|
5
7
|
end
|
6
|
-
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_styling do |rules|
|
2
4
|
normalized_rules = StylingExpectation.new(rules)
|
3
5
|
|
4
6
|
chain(:at_selector) { |selector| @selector = selector }
|
5
7
|
match { |document|
|
6
|
-
@selector ||=
|
8
|
+
@selector ||= "body > *:first"
|
7
9
|
normalized_rules == styles_at_selector(document)
|
8
10
|
}
|
9
11
|
|
@@ -21,7 +23,7 @@ RSpec::Matchers.define :have_styling do |rules|
|
|
21
23
|
|
22
24
|
def styles_at_selector(document)
|
23
25
|
expect(document).to have_selector(@selector)
|
24
|
-
StylingExpectation.new document.at_css(@selector)[
|
26
|
+
StylingExpectation.new document.at_css(@selector)["style"]
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
@@ -40,23 +42,22 @@ class StylingExpectation
|
|
40
42
|
rules == other.rules
|
41
43
|
end
|
42
44
|
|
43
|
-
def to_s
|
45
|
+
def to_s
|
46
|
+
rules.to_s
|
47
|
+
end
|
44
48
|
|
45
49
|
protected
|
50
|
+
|
46
51
|
attr_reader :rules
|
47
52
|
|
48
53
|
private
|
54
|
+
|
49
55
|
def parse_rules(css)
|
50
|
-
css.split(
|
56
|
+
css.split(";").map { |property| parse_property(property) }
|
51
57
|
end
|
52
58
|
|
53
59
|
def parse_property(property)
|
54
|
-
rule, value = property.split(
|
55
|
-
[rule,
|
56
|
-
end
|
57
|
-
|
58
|
-
# JRuby's Nokogiri encodes quotes
|
59
|
-
def normalize_quotes(string)
|
60
|
-
string.gsub '%22', '"'
|
60
|
+
rule, value = property.split(":", 2).map(&:strip)
|
61
|
+
[rule, value]
|
61
62
|
end
|
62
63
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec::Matchers.define :have_xpath do |xpath|
|
2
4
|
match { |document| !document.xpath(xpath).empty? }
|
3
|
-
failure_message { "expected document to have xpath #{xpath.inspect}"}
|
4
|
-
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}" }
|
5
7
|
end
|
6
|
-
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roadie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Magnus Bergmark
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,8 +105,10 @@ extra_rdoc_files:
|
|
91
105
|
- Changelog.md
|
92
106
|
files:
|
93
107
|
- ".autotest"
|
108
|
+
- ".github/workflows/main.yml"
|
94
109
|
- ".gitignore"
|
95
|
-
- ".
|
110
|
+
- ".rubocop.yml"
|
111
|
+
- ".solargraph.yml"
|
96
112
|
- ".yardopts"
|
97
113
|
- Changelog.md
|
98
114
|
- Gemfile
|
@@ -166,7 +182,7 @@ homepage: http://github.com/Mange/roadie
|
|
166
182
|
licenses:
|
167
183
|
- MIT
|
168
184
|
metadata: {}
|
169
|
-
post_install_message:
|
185
|
+
post_install_message:
|
170
186
|
rdoc_options: []
|
171
187
|
require_paths:
|
172
188
|
- lib
|
@@ -174,15 +190,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
174
190
|
requirements:
|
175
191
|
- - ">="
|
176
192
|
- !ruby/object:Gem::Version
|
177
|
-
version: '
|
193
|
+
version: '2.6'
|
178
194
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
195
|
requirements:
|
180
196
|
- - ">="
|
181
197
|
- !ruby/object:Gem::Version
|
182
198
|
version: '0'
|
183
199
|
requirements: []
|
184
|
-
rubygems_version: 3.0.
|
185
|
-
signing_key:
|
200
|
+
rubygems_version: 3.0.9
|
201
|
+
signing_key:
|
186
202
|
specification_version: 4
|
187
203
|
summary: Making HTML emails comfortable for the Ruby rockstars
|
188
204
|
test_files:
|
data/.travis.yml
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
rvm:
|
4
|
-
- 2.1
|
5
|
-
- 2.2
|
6
|
-
- 2.3
|
7
|
-
- 2.4
|
8
|
-
- 2.5
|
9
|
-
- jruby
|
10
|
-
- rbx
|
11
|
-
before_install:
|
12
|
-
- gem install bundler -v '1.17.3'
|
13
|
-
matrix:
|
14
|
-
allow_failures:
|
15
|
-
# Rubinius and JRuby have a lot of trouble and no large following, so I'm going to
|
16
|
-
# allow failures on it until it gets more stable on Travis / Real Life(tm).
|
17
|
-
# Let me know if you need it. Patches are welcome!
|
18
|
-
- rvm: jruby
|
19
|
-
- rvm: rbx
|
20
|
-
fast_finish: true
|
21
|
-
cache: bundler
|
22
|
-
script: "rake"
|