roadie 1.0.0.pre2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -1
- data/.yardopts +1 -0
- data/Gemfile.lock +43 -34
- data/README.textile +4 -0
- data/lib/roadie.rb +22 -13
- data/lib/roadie/action_mailer_extensions.rb +16 -9
- data/lib/roadie/css_file_not_found.rb +12 -0
- data/lib/roadie/inliner.rb +65 -32
- data/lib/roadie/style_declaration.rb +34 -0
- data/lib/roadie/version.rb +1 -1
- data/spec/fixtures/views/integration_mailer/marketing.html.erb +2 -0
- data/spec/integration_spec.rb +16 -0
- data/spec/lib/roadie/action_mailer_extensions_spec.rb +11 -17
- data/spec/lib/roadie/css_file_not_found_spec.rb +13 -0
- data/spec/lib/roadie/inliner_spec.rb +46 -27
- data/spec/lib/roadie/style_declaration_spec.rb +45 -0
- data/spec/lib/roadie_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -68
- data/spec/support/have_attribute_matcher.rb +28 -0
- data/spec/support/have_selector_matcher.rb +6 -0
- data/spec/support/have_styling_matcher.rb +36 -0
- metadata +23 -13
- data/.rspec +0 -2
- data/VERSION +0 -1
data/.gitignore
CHANGED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
data/Gemfile.lock
CHANGED
@@ -10,57 +10,66 @@ GEM
|
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
12
|
abstract (1.0.0)
|
13
|
-
actionmailer (3.0.
|
14
|
-
actionpack (= 3.0.
|
15
|
-
mail (~> 2.2.
|
16
|
-
actionpack (3.0.
|
17
|
-
activemodel (= 3.0.
|
18
|
-
activesupport (= 3.0.
|
13
|
+
actionmailer (3.0.3)
|
14
|
+
actionpack (= 3.0.3)
|
15
|
+
mail (~> 2.2.9)
|
16
|
+
actionpack (3.0.3)
|
17
|
+
activemodel (= 3.0.3)
|
18
|
+
activesupport (= 3.0.3)
|
19
19
|
builder (~> 2.1.2)
|
20
20
|
erubis (~> 2.6.6)
|
21
|
-
i18n (~> 0.4
|
21
|
+
i18n (~> 0.4)
|
22
22
|
rack (~> 1.2.1)
|
23
|
-
rack-mount (~> 0.6.
|
24
|
-
rack-test (~> 0.5.
|
23
|
+
rack-mount (~> 0.6.13)
|
24
|
+
rack-test (~> 0.5.6)
|
25
25
|
tzinfo (~> 0.3.23)
|
26
|
-
activemodel (3.0.
|
27
|
-
activesupport (= 3.0.
|
26
|
+
activemodel (3.0.3)
|
27
|
+
activesupport (= 3.0.3)
|
28
28
|
builder (~> 2.1.2)
|
29
|
-
i18n (~> 0.4
|
30
|
-
activesupport (3.0.
|
29
|
+
i18n (~> 0.4)
|
30
|
+
activesupport (3.0.3)
|
31
31
|
builder (2.1.2)
|
32
|
-
css_parser (1.
|
32
|
+
css_parser (1.1.5)
|
33
33
|
diff-lcs (1.1.2)
|
34
34
|
erubis (2.6.6)
|
35
35
|
abstract (>= 1.0.0)
|
36
|
-
i18n (0.
|
37
|
-
mail (2.2.
|
36
|
+
i18n (0.5.0)
|
37
|
+
mail (2.2.15)
|
38
38
|
activesupport (>= 2.3.6)
|
39
|
-
|
40
|
-
|
39
|
+
i18n (>= 0.4.0)
|
40
|
+
mime-types (~> 1.16)
|
41
|
+
treetop (~> 1.4.8)
|
41
42
|
mime-types (1.16)
|
42
|
-
nokogiri (1.4.
|
43
|
+
nokogiri (1.4.4)
|
43
44
|
polyglot (0.3.1)
|
44
45
|
rack (1.2.1)
|
45
46
|
rack-mount (0.6.13)
|
46
47
|
rack (>= 1.0.0)
|
47
|
-
rack-test (0.5.
|
48
|
+
rack-test (0.5.7)
|
48
49
|
rack (>= 1.0)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
rspec-
|
58
|
-
rspec-
|
59
|
-
rspec-
|
60
|
-
|
61
|
-
|
50
|
+
railties (3.0.3)
|
51
|
+
actionpack (= 3.0.3)
|
52
|
+
activesupport (= 3.0.3)
|
53
|
+
rake (>= 0.8.7)
|
54
|
+
thor (~> 0.14.4)
|
55
|
+
rake (0.8.7)
|
56
|
+
rspec (2.5.0)
|
57
|
+
rspec-core (~> 2.5.0)
|
58
|
+
rspec-expectations (~> 2.5.0)
|
59
|
+
rspec-mocks (~> 2.5.0)
|
60
|
+
rspec-core (2.5.1)
|
61
|
+
rspec-expectations (2.5.0)
|
62
|
+
diff-lcs (~> 1.1.2)
|
63
|
+
rspec-mocks (2.5.0)
|
64
|
+
rspec-rails (2.5.0)
|
65
|
+
actionpack (~> 3.0)
|
66
|
+
activesupport (~> 3.0)
|
67
|
+
railties (~> 3.0)
|
68
|
+
rspec (~> 2.5.0)
|
69
|
+
thor (0.14.6)
|
70
|
+
treetop (1.4.9)
|
62
71
|
polyglot (>= 0.3.1)
|
63
|
-
tzinfo (0.3.
|
72
|
+
tzinfo (0.3.24)
|
64
73
|
|
65
74
|
PLATFORMS
|
66
75
|
ruby
|
data/README.textile
CHANGED
@@ -73,6 +73,10 @@ You can set a special <code>data-immutable="true"</code> attribute on @style@ ta
|
|
73
73
|
|
74
74
|
Style elements with <code>media="print"</code> are always ignored.
|
75
75
|
|
76
|
+
h2. Documentation
|
77
|
+
|
78
|
+
* "Online documentation for master":http://rubydoc.info/github/Mange/roadie/master/frames
|
79
|
+
|
76
80
|
h2. Bugs / TODO
|
77
81
|
|
78
82
|
* Improve overall performance
|
data/lib/roadie.rb
CHANGED
@@ -1,26 +1,35 @@
|
|
1
1
|
module Roadie
|
2
|
-
|
3
|
-
|
4
|
-
def self.inline_css(*args)
|
2
|
+
# Shortcut for inlining CSS using {Inliner}
|
3
|
+
# @see Inliner
|
4
|
+
def self.inline_css(*args)
|
5
5
|
Roadie::Inliner.new(*args).execute
|
6
6
|
end
|
7
7
|
|
8
|
+
# Tries to load the CSS "names" specified in the +targets+ parameter inside the +root+ path.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# Roadie.load_css(Rails.root, %w[application newsletter])
|
12
|
+
#
|
13
|
+
# @param [Pathname] root The root path of your stylesheets
|
14
|
+
# @param [Array<String, Symbol>] targets Stylesheet names - <b>without extensions</b>
|
15
|
+
# @return [String] The combined contents of the CSS files
|
16
|
+
# @raise [CSSFileNotFound] When a target cannot be found under +[root]/[target].css+
|
8
17
|
def self.load_css(root, targets)
|
9
|
-
|
10
|
-
|
18
|
+
css_files_from_targets(root, targets).map do |file|
|
19
|
+
raise CSSFileNotFound, file unless file.exist?
|
20
|
+
file.read
|
21
|
+
end.join("\n")
|
22
|
+
end
|
11
23
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
else
|
16
|
-
raise CSSFileNotFound, "Could not find #{target_file}"
|
17
|
-
end
|
24
|
+
private
|
25
|
+
def self.css_files_from_targets(root, targets)
|
26
|
+
targets.map { |target| root.join("#{target}.css") }
|
18
27
|
end
|
19
|
-
loaded_css.join("\n")
|
20
|
-
end
|
21
28
|
end
|
22
29
|
|
23
30
|
require 'roadie/version'
|
31
|
+
require 'roadie/css_file_not_found'
|
32
|
+
require 'roadie/style_declaration'
|
24
33
|
require 'roadie/inliner'
|
25
34
|
|
26
35
|
require 'action_mailer'
|
@@ -3,6 +3,9 @@ require 'nokogiri'
|
|
3
3
|
require 'css_parser'
|
4
4
|
|
5
5
|
module Roadie
|
6
|
+
# This module adds the Roadie functionality to ActionMailer 3 when included in ActionMailer::Base.
|
7
|
+
#
|
8
|
+
# If you want to add Roadie to any other mail framework, take a look at how this module is implemented.
|
6
9
|
module ActionMailerExtensions
|
7
10
|
def self.included(base)
|
8
11
|
base.class_eval do
|
@@ -14,24 +17,28 @@ module Roadie
|
|
14
17
|
protected
|
15
18
|
def mail_with_inline_styles(headers = {}, &block)
|
16
19
|
@inline_style_css_targets = headers[:css]
|
17
|
-
mail_without_inline_styles(headers
|
18
|
-
email
|
20
|
+
mail_without_inline_styles(headers, &block).tap do |email|
|
21
|
+
email.header.fields.delete_if { |field| field.name == 'css' }
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
25
|
def collect_responses_and_parts_order_with_inline_styles(headers, &block)
|
23
26
|
responses, order = collect_responses_and_parts_order_without_inline_styles(headers, &block)
|
24
|
-
|
25
|
-
responses.each do |response|
|
26
|
-
new_responses << inline_style_response(response)
|
27
|
-
end
|
28
|
-
[new_responses, order]
|
27
|
+
[responses.map { |response| inline_style_response(response) }, order]
|
29
28
|
end
|
30
29
|
|
31
30
|
private
|
31
|
+
def url_options
|
32
|
+
Rails.application.config.action_mailer.default_url_options
|
33
|
+
end
|
34
|
+
|
35
|
+
def stylesheet_root
|
36
|
+
Rails.root.join('public', 'stylesheets')
|
37
|
+
end
|
38
|
+
|
32
39
|
def inline_style_response(response)
|
33
40
|
if response[:content_type] == 'text/html'
|
34
|
-
response.merge :body => Roadie.inline_css(css_rules, response[:body],
|
41
|
+
response.merge :body => Roadie.inline_css(css_rules, response[:body], url_options)
|
35
42
|
else
|
36
43
|
response
|
37
44
|
end
|
@@ -43,7 +50,7 @@ module Roadie
|
|
43
50
|
end
|
44
51
|
|
45
52
|
def css_rules
|
46
|
-
@css_rules ||= Roadie.load_css(
|
53
|
+
@css_rules ||= Roadie.load_css(stylesheet_root, css_targets) if css_targets.present?
|
47
54
|
end
|
48
55
|
end
|
49
56
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Roadie
|
2
|
+
# Raised when a stylesheet specified for inlining is not present.
|
3
|
+
# You can access the target filename via #filename.
|
4
|
+
class CSSFileNotFound < StandardError
|
5
|
+
attr_reader :filename
|
6
|
+
|
7
|
+
def initialize(filename)
|
8
|
+
@filename = filename
|
9
|
+
super("Could not find #{filename}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/roadie/inliner.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module Roadie
|
4
|
+
# This class is the core of Roadie as it does all the actual work. You just give it
|
5
|
+
# the CSS rules, the HTML and the url_options for rewriting URLs and let it go on
|
6
|
+
# doing all the heavy lifting and building.
|
2
7
|
class Inliner
|
8
|
+
# Regexp matching all the url() declarations in CSS
|
9
|
+
#
|
10
|
+
# It matches without any quotes and with both single and double quotes
|
11
|
+
# inside the parenthesis. There's much room for improvement, of course.
|
3
12
|
CSS_URL_REGEXP = %r{
|
4
13
|
url\(
|
5
14
|
(["']?)
|
@@ -8,12 +17,15 @@ module Roadie
|
|
8
17
|
(?:\([^)]*\))* # Texts containing parens pairs
|
9
18
|
[^(]+ # Texts without parens - required
|
10
19
|
)
|
11
|
-
\1
|
20
|
+
\1 # Closing quote
|
12
21
|
\)
|
13
22
|
}x
|
14
23
|
|
15
|
-
|
16
|
-
|
24
|
+
# Initialize a new Inliner with the given CSS, HTML and url_options.
|
25
|
+
#
|
26
|
+
# @param [String] css
|
27
|
+
# @param [String] html
|
28
|
+
# @param [Hash] url_options Supported keys: +:host+, +:port+ and +:protocol+
|
17
29
|
def initialize(css, html, url_options)
|
18
30
|
@css = css
|
19
31
|
@inline_css = []
|
@@ -21,17 +33,23 @@ module Roadie
|
|
21
33
|
@url_options = url_options
|
22
34
|
end
|
23
35
|
|
36
|
+
# Start the inlining and return the final HTML output
|
37
|
+
# @return [String]
|
24
38
|
def execute
|
25
39
|
adjust_html do |document|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
@document = document
|
41
|
+
add_missing_structure
|
42
|
+
extract_inline_style_elements
|
43
|
+
inline_css_rules
|
44
|
+
make_image_urls_absolute
|
45
|
+
make_style_urls_absolute
|
46
|
+
@document = nil
|
31
47
|
end
|
32
48
|
end
|
33
49
|
|
34
50
|
private
|
51
|
+
attr_reader :css, :html, :url_options, :document
|
52
|
+
|
35
53
|
def inline_css
|
36
54
|
@inline_css.join("\n")
|
37
55
|
end
|
@@ -49,7 +67,7 @@ module Roadie
|
|
49
67
|
end.to_html
|
50
68
|
end
|
51
69
|
|
52
|
-
def add_missing_structure
|
70
|
+
def add_missing_structure
|
53
71
|
html_node = document.at_css('html')
|
54
72
|
html_node['xmlns'] ||= 'http://www.w3.org/1999/xhtml'
|
55
73
|
|
@@ -68,7 +86,7 @@ module Roadie
|
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
71
|
-
def extract_inline_style_elements
|
89
|
+
def extract_inline_style_elements
|
72
90
|
document.css("style").each do |style|
|
73
91
|
next if style['media'] == 'print' or style['data-immutable']
|
74
92
|
@inline_css << style.content
|
@@ -76,45 +94,60 @@ module Roadie
|
|
76
94
|
end
|
77
95
|
end
|
78
96
|
|
79
|
-
def inline_css_rules
|
80
|
-
|
81
|
-
|
97
|
+
def inline_css_rules
|
98
|
+
elements_with_declarations.each do |element, declarations|
|
99
|
+
ordered_declarations = []
|
100
|
+
seen_properties = Set.new
|
101
|
+
declarations.sort.reverse_each do |declaration|
|
102
|
+
next if seen_properties.include?(declaration.property)
|
103
|
+
ordered_declarations.unshift(declaration)
|
104
|
+
seen_properties << declaration.property
|
105
|
+
end
|
82
106
|
|
83
|
-
|
84
|
-
|
85
|
-
element['style'] = [rules_string, element['style']].compact.join('; ')
|
107
|
+
rules_string = ordered_declarations.map { |declaration| declaration.to_s }.join(';')
|
108
|
+
element['style'] = [rules_string, element['style']].compact.join(';')
|
86
109
|
end
|
87
110
|
end
|
88
111
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
112
|
+
def elements_with_declarations
|
113
|
+
Hash.new { |hash, key| hash[key] = [] }.tap do |element_declarations|
|
114
|
+
parsed_css.each_rule_set do |rule_set|
|
115
|
+
each_selector_without_psuedo(rule_set) do |selector, specificity|
|
116
|
+
each_element_in_selector(selector) do |element|
|
117
|
+
style_declarations_in_rule_set(specificity, rule_set) do |declaration|
|
118
|
+
element_declarations[element] << declaration
|
119
|
+
end
|
120
|
+
end
|
94
121
|
end
|
95
122
|
end
|
96
123
|
end
|
97
124
|
end
|
98
125
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
126
|
+
def each_selector_without_psuedo(rules)
|
127
|
+
rules.selectors.reject { |selector| selector.include?(':') }.each do |selector|
|
128
|
+
yield selector, CssParser.calculate_specificity(selector)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def each_element_in_selector(selector)
|
133
|
+
document.css(selector.strip).each do |element|
|
134
|
+
yield element
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def style_declarations_in_rule_set(specificity, rule_set)
|
139
|
+
rule_set.each_declaration do |property, value, important|
|
140
|
+
yield StyleDeclaration.new(property, value, important, specificity)
|
108
141
|
end
|
109
142
|
end
|
110
143
|
|
111
|
-
def make_image_urls_absolute
|
144
|
+
def make_image_urls_absolute
|
112
145
|
document.css('img').each do |img|
|
113
146
|
img['src'] = ensure_absolute_url(img['src']) if img['src']
|
114
147
|
end
|
115
148
|
end
|
116
149
|
|
117
|
-
def make_style_urls_absolute
|
150
|
+
def make_style_urls_absolute
|
118
151
|
document.css('*[style]').each do |element|
|
119
152
|
styling = element['style']
|
120
153
|
element['style'] = styling.gsub(CSS_URL_REGEXP) { "url(#{$1}#{ensure_absolute_url($2, '/stylesheets')}#{$1})" }
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Roadie
|
2
|
+
class StyleDeclaration
|
3
|
+
include Comparable
|
4
|
+
attr_reader :property, :value, :important, :specificity
|
5
|
+
|
6
|
+
def initialize(property, value, important, specificity)
|
7
|
+
@property = property
|
8
|
+
@value = value
|
9
|
+
@important = important
|
10
|
+
@specificity = specificity
|
11
|
+
end
|
12
|
+
|
13
|
+
def important?
|
14
|
+
@important
|
15
|
+
end
|
16
|
+
|
17
|
+
def <=>(other)
|
18
|
+
if important == other.important
|
19
|
+
specificity <=> other.specificity
|
20
|
+
else
|
21
|
+
important ? 1 : -1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
[property, value].join(':')
|
27
|
+
end
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
extra = [important ? '!important' : nil, specificity].compact
|
31
|
+
"#{to_s} (#{extra.join(' , ')})"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/roadie/version.rb
CHANGED
data/spec/integration_spec.rb
CHANGED
@@ -15,6 +15,11 @@ describe "roadie integration" do
|
|
15
15
|
@reason = reason
|
16
16
|
mail(:subject => 'Notification for you', :to => to) { |format| format.html; format.text }
|
17
17
|
end
|
18
|
+
|
19
|
+
def marketing(to)
|
20
|
+
headers('X-Spam' => 'No way! Trust us!')
|
21
|
+
mail(:subject => 'Buy cheap v1agra', :to => to)
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
before(:each) do
|
@@ -41,6 +46,17 @@ describe "roadie integration" do
|
|
41
46
|
plain_part.body.decoded.should_not match(/<.*>/)
|
42
47
|
end
|
43
48
|
|
49
|
+
# If we deliver mails we can catch weird problems with headers being invalid
|
44
50
|
email.deliver
|
45
51
|
end
|
52
|
+
|
53
|
+
it "should not add headers for the roadie options" do
|
54
|
+
email = IntegrationMailer.notification('doe@example.com', 'no berries left in chest')
|
55
|
+
email.header.fields.map(&:name).should_not include('css')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should keep custom headers in place" do
|
59
|
+
email = IntegrationMailer.marketing('everyone@inter.net')
|
60
|
+
email.header['X-Spam'].should be_present
|
61
|
+
end
|
46
62
|
end
|
@@ -12,17 +12,6 @@ describe Roadie::ActionMailerExtensions, "inlining styles" do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
# Not sure how to implement this one.
|
16
|
-
# TODO: Either remove or implement
|
17
|
-
def nested_multipart_mixed(css_file = nil)
|
18
|
-
raise "Nested multipart mixed is not implemented"
|
19
|
-
content_type "multipart/mixed"
|
20
|
-
part :content_type => "multipart/alternative", :content_disposition => "inline" do |p|
|
21
|
-
p.part :content_type => 'text/html', :body => 'Hello HTML'
|
22
|
-
p.part :content_type => 'text/plain', :body => 'Hello Text'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
15
|
def singlepart_html
|
27
16
|
mail(:subject => "HTML email") do |format|
|
28
17
|
format.html { render :text => 'Hello HTML' }
|
@@ -38,7 +27,7 @@ describe Roadie::ActionMailerExtensions, "inlining styles" do
|
|
38
27
|
|
39
28
|
before(:each) do
|
40
29
|
Roadie.stub!(:load_css => 'loaded css')
|
41
|
-
Roadie.stub!(:inline_css => 'unexpected value
|
30
|
+
Roadie.stub!(:inline_css => 'unexpected value passed to inline_css')
|
42
31
|
end
|
43
32
|
|
44
33
|
describe "for singlepart text/plain" do
|
@@ -63,8 +52,8 @@ describe Roadie::ActionMailerExtensions, "inlining styles" do
|
|
63
52
|
it "should inline css to the email's html part" do
|
64
53
|
Roadie.should_receive(:inline_css).with(anything, 'Hello HTML', anything).and_return('html')
|
65
54
|
email = InliningMailer.multipart
|
66
|
-
email.
|
67
|
-
email.
|
55
|
+
email.html_part.body.decoded.should == 'html'
|
56
|
+
email.text_part.body.decoded.should == 'Hello Text'
|
68
57
|
end
|
69
58
|
end
|
70
59
|
end
|
@@ -90,13 +79,18 @@ describe Roadie::ActionMailerExtensions, "loading css files" do
|
|
90
79
|
Roadie.stub!(:inline_css => 'html')
|
91
80
|
end
|
92
81
|
|
82
|
+
it "should load css from Rails' stylesheet root" do
|
83
|
+
Roadie.should_receive(:load_css).with(Rails.root.join('public', 'stylesheets'), anything).and_return('')
|
84
|
+
CssLoadingMailer.use_default
|
85
|
+
end
|
86
|
+
|
93
87
|
it "should load the css specified in the default mailer settings" do
|
94
|
-
Roadie.should_receive(:load_css).with(
|
88
|
+
Roadie.should_receive(:load_css).with(anything, ['default_value']).and_return('')
|
95
89
|
CssLoadingMailer.use_default
|
96
90
|
end
|
97
91
|
|
98
92
|
it "should load the css specified in the specific mailer action instead of the default choice" do
|
99
|
-
Roadie.should_receive(:load_css).with(
|
93
|
+
Roadie.should_receive(:load_css).with(anything, ['specific']).and_return('')
|
100
94
|
CssLoadingMailer.override(:specific)
|
101
95
|
end
|
102
96
|
|
@@ -106,7 +100,7 @@ describe Roadie::ActionMailerExtensions, "loading css files" do
|
|
106
100
|
end
|
107
101
|
|
108
102
|
it "should load multiple css files when given an array" do
|
109
|
-
Roadie.should_receive(:load_css).with(
|
103
|
+
Roadie.should_receive(:load_css).with(anything, ['specific', 'other']).and_return('')
|
110
104
|
CssLoadingMailer.override([:specific, :other])
|
111
105
|
end
|
112
106
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Roadie
|
4
|
+
describe CSSFileNotFound do
|
5
|
+
it "is initialized with a filename" do
|
6
|
+
CSSFileNotFound.new('file.css').filename.should == 'file.css'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "has a message" do
|
10
|
+
CSSFileNotFound.new('style.css').message.should == 'Could not find style.css'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -15,19 +15,38 @@ describe Roadie::Inliner do
|
|
15
15
|
|
16
16
|
it "should inline simple attributes" do
|
17
17
|
use_css 'p { color: green }'
|
18
|
-
rendering('<p></p>').should have_styling('color' => 'green')
|
18
|
+
rendering('<p></p>').should have_styling('color' => 'green')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should keep the order of the styles that was inlined" do
|
22
|
+
use_css 'h1 { padding: 2px; margin: 5px; }'
|
23
|
+
rendering('<h1></h1>').should have_styling([['padding', '2px'], ['margin', '5px']])
|
19
24
|
end
|
20
25
|
|
21
26
|
it "should combine multiple selectors into one" do
|
22
|
-
use_css
|
23
|
-
.tip { float: right; }
|
24
|
-
rendering('<p class="tip"></p>').should have_styling('color' => 'green', 'float' => 'right')
|
27
|
+
use_css 'p { color: green; }
|
28
|
+
.tip { float: right; }'
|
29
|
+
rendering('<p class="tip"></p>').should have_styling('color' => 'green', 'float' => 'right')
|
25
30
|
end
|
26
31
|
|
27
32
|
it "should use the ones attributes with the highest specificality when conflicts arises" do
|
28
33
|
use_css "p { color: red; }
|
29
|
-
.safe { color: green;
|
30
|
-
rendering('<p class="safe"></p>').should have_styling('color' => 'green'
|
34
|
+
.safe { color: green; }"
|
35
|
+
rendering('<p class="safe"></p>').should have_styling('color' => 'green')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should sort styles by specificity order" do
|
39
|
+
use_css 'p { margin: 2px; }
|
40
|
+
#big { margin: 10px; }
|
41
|
+
.down { margin-bottom: 5px; }'
|
42
|
+
|
43
|
+
rendering('<p class="down"></p>').should have_styling([
|
44
|
+
['margin', '2px'], ['margin-bottom', '5px']
|
45
|
+
])
|
46
|
+
|
47
|
+
rendering('<p class="down" id="big"></p>').should have_styling([
|
48
|
+
['margin-bottom', '5px'], ['margin', '10px']
|
49
|
+
])
|
31
50
|
end
|
32
51
|
|
33
52
|
it "should support multiple selectors for the same rules" do
|
@@ -41,27 +60,27 @@ describe Roadie::Inliner do
|
|
41
60
|
it "should respect !important properties" do
|
42
61
|
use_css "a { text-decoration: underline !important; }
|
43
62
|
a.hard-to-spot { text-decoration: none; }"
|
44
|
-
rendering('<a class="hard-to-spot"></a>').should have_styling('text-decoration' => 'underline')
|
63
|
+
rendering('<a class="hard-to-spot"></a>').should have_styling('text-decoration' => 'underline')
|
45
64
|
end
|
46
65
|
|
47
66
|
it "should combine with already present inline styles" do
|
48
67
|
use_css "p { color: green }"
|
49
|
-
rendering('<p style="font-size: 1.1em"></p>').should have_styling('color'
|
68
|
+
rendering('<p style="font-size: 1.1em"></p>').should have_styling([['color', 'green'], ['font-size', '1.1em']])
|
50
69
|
end
|
51
70
|
|
52
|
-
it "should not
|
71
|
+
it "should not touch already present inline styles" do
|
53
72
|
use_css "p { color: red }"
|
54
|
-
rendering('<p style="color: green"></p>').should have_styling('color'
|
73
|
+
rendering('<p style="color: green"></p>').should have_styling([['color', 'red'], ['color', 'green']])
|
55
74
|
end
|
56
75
|
|
57
76
|
it "should ignore selectors with :psuedo-classes" do
|
58
77
|
use_css 'p:hover { color: red }'
|
59
|
-
rendering('<p></p>').should_not have_styling('color' => 'red')
|
78
|
+
rendering('<p></p>').should_not have_styling('color' => 'red')
|
60
79
|
end
|
61
80
|
|
62
81
|
describe "inline <style> elements" do
|
63
82
|
it "should be used for inlined styles" do
|
64
|
-
rendering(<<-HTML).should have_styling('color'
|
83
|
+
rendering(<<-HTML).should have_styling([['color', 'green'], ['font-size', '1.1em']])
|
65
84
|
<html>
|
66
85
|
<head>
|
67
86
|
<style type="text/css">p { color: green; }</style>
|
@@ -93,7 +112,7 @@ describe Roadie::Inliner do
|
|
93
112
|
<p></p>
|
94
113
|
HTML
|
95
114
|
document.should have_selector('style[data-immutable=true]')
|
96
|
-
document.should_not have_styling('color' => 'red')
|
115
|
+
document.should_not have_styling('color' => 'red')
|
97
116
|
end
|
98
117
|
|
99
118
|
it "should not be touched when media=print" do
|
@@ -117,41 +136,41 @@ describe Roadie::Inliner do
|
|
117
136
|
|
118
137
|
describe "making urls absolute" do
|
119
138
|
it "should work on image sources" do
|
120
|
-
rendering('<img src="/images/foo.jpg" />').should have_attribute('src' => 'http://example.com/images/foo.jpg')
|
121
|
-
rendering('<img src="../images/foo.jpg" />').should have_attribute('src' => 'http://example.com/images/foo.jpg')
|
122
|
-
rendering('<img src="foo.jpg" />').should have_attribute('src' => 'http://example.com/foo.jpg')
|
139
|
+
rendering('<img src="/images/foo.jpg" />').should have_attribute('src' => 'http://example.com/images/foo.jpg')
|
140
|
+
rendering('<img src="../images/foo.jpg" />').should have_attribute('src' => 'http://example.com/images/foo.jpg')
|
141
|
+
rendering('<img src="foo.jpg" />').should have_attribute('src' => 'http://example.com/foo.jpg')
|
123
142
|
end
|
124
143
|
|
125
144
|
it "should not touch image sources that are already absolute" do
|
126
|
-
rendering('<img src="http://other.example.org/images/foo.jpg" />').should have_attribute('src' => 'http://other.example.org/images/foo.jpg')
|
145
|
+
rendering('<img src="http://other.example.org/images/foo.jpg" />').should have_attribute('src' => 'http://other.example.org/images/foo.jpg')
|
127
146
|
end
|
128
147
|
|
129
148
|
it "should work on inlined style attributes" do
|
130
|
-
rendering('<p style="background: url(/paper.png)"></p>').should have_styling('background' => 'url(http://example.com/paper.png)')
|
131
|
-
rendering('<p style="background: url("/paper.png")"></p>').should have_styling('background' => 'url("http://example.com/paper.png")')
|
149
|
+
rendering('<p style="background: url(/paper.png)"></p>').should have_styling('background' => 'url(http://example.com/paper.png)')
|
150
|
+
rendering('<p style="background: url("/paper.png")"></p>').should have_styling('background' => 'url("http://example.com/paper.png")')
|
132
151
|
end
|
133
152
|
|
134
153
|
it "should work on external style declarations" do
|
135
154
|
use_css "p { background-image: url(/paper.png); }
|
136
155
|
table { background-image: url('/paper.png'); }
|
137
156
|
div { background-image: url(\"/paper.png\"); }"
|
138
|
-
rendering('<p></p>').should have_styling('background-image' => 'url(http://example.com/paper.png)')
|
139
|
-
rendering('<table></table>').should have_styling('background-image' => "url('http://example.com/paper.png')")
|
140
|
-
rendering('<div></div>').should have_styling('background-image' => 'url("http://example.com/paper.png")')
|
157
|
+
rendering('<p></p>').should have_styling('background-image' => 'url(http://example.com/paper.png)')
|
158
|
+
rendering('<table></table>').should have_styling('background-image' => "url('http://example.com/paper.png')")
|
159
|
+
rendering('<div></div>').should have_styling('background-image' => 'url("http://example.com/paper.png")')
|
141
160
|
end
|
142
161
|
|
143
162
|
it "should not touch style urls that are already absolute" do
|
144
163
|
external_url = 'url(http://other.example.org/paper.png)'
|
145
164
|
use_css "p { background-image: #{external_url}; }"
|
146
|
-
rendering('<p></p>').should have_styling('background-image' => external_url)
|
147
|
-
rendering(%(<div style="background-image: #{external_url}"></div>)).should have_styling('background-image' => external_url)
|
165
|
+
rendering('<p></p>').should have_styling('background-image' => external_url)
|
166
|
+
rendering(%(<div style="background-image: #{external_url}"></div>)).should have_styling('background-image' => external_url)
|
148
167
|
end
|
149
168
|
|
150
169
|
it "should not touch the urls when no url options are defined" do
|
151
170
|
use_css "img { background: url(/a.jpg); }"
|
152
171
|
rendering('<img src="/b.jpg" />', :url_options => nil).tap do |document|
|
153
172
|
document.should have_attribute('src' => '/b.jpg').at_selector('img')
|
154
|
-
document.should have_styling('background' => 'url(/a.jpg)')
|
173
|
+
document.should have_styling('background' => 'url(/a.jpg)')
|
155
174
|
end
|
156
175
|
end
|
157
176
|
|
@@ -159,13 +178,13 @@ describe Roadie::Inliner do
|
|
159
178
|
use_css "img { background: url(/a.jpg); }"
|
160
179
|
rendering('<img src="/b.jpg" />', :url_options => {:host => 'example.com', :protocol => 'https', :port => '8080'}).tap do |document|
|
161
180
|
document.should have_attribute('src' => 'https://example.com:8080/b.jpg').at_selector('img')
|
162
|
-
document.should have_styling('background' => 'url(https://example.com:8080/a.jpg)')
|
181
|
+
document.should have_styling('background' => 'url(https://example.com:8080/a.jpg)')
|
163
182
|
end
|
164
183
|
end
|
165
184
|
|
166
185
|
it "should not touch data: URIs" do
|
167
186
|
use_css "div { background: url(data:abcdef); }"
|
168
|
-
rendering('<div></div>').should have_styling('background' => 'url(data:abcdef)')
|
187
|
+
rendering('<div></div>').should have_styling('background' => 'url(data:abcdef)')
|
169
188
|
end
|
170
189
|
end
|
171
190
|
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Roadie
|
4
|
+
describe StyleDeclaration do
|
5
|
+
it "should be initialized with a property, value, if it is marked as important, and the specificity" do
|
6
|
+
StyleDeclaration.new('color', 'green', true, 45).tap do |declaration|
|
7
|
+
declaration.property.should == 'color'
|
8
|
+
declaration.value.should == 'green'
|
9
|
+
declaration.should be_important
|
10
|
+
declaration.specificity.should == 45
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "string representation" do
|
15
|
+
it "should be the property and the value joined with a colon" do
|
16
|
+
StyleDeclaration.new('color', 'green', false, 1).to_s.should == 'color:green'
|
17
|
+
StyleDeclaration.new('font-size', '1.1em', false, 1).to_s.should == 'font-size:1.1em'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "comparing" do
|
22
|
+
def declaration(specificity, important = false)
|
23
|
+
StyleDeclaration.new('color', 'green', important, specificity)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should compare on specificity" do
|
27
|
+
declaration(5).should be == declaration(5)
|
28
|
+
declaration(4).should be < declaration(5)
|
29
|
+
declaration(6).should be > declaration(5)
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with an important declaration" do
|
33
|
+
it "should be less than the important declaration regardless of the specificity" do
|
34
|
+
declaration(99, false).should be < declaration(1, true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should compare like normal when both declarations are important" do
|
38
|
+
declaration(5, true).should be == declaration(5, true)
|
39
|
+
declaration(4, true).should be < declaration(5, true)
|
40
|
+
declaration(6, true).should be > declaration(5, true)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/lib/roadie_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe Roadie do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe ".load_css(root, targets)" do
|
12
|
-
let(:fixtures_root) { Pathname.new(__FILE__).dirname.join('..', 'fixtures') }
|
12
|
+
let(:fixtures_root) { Pathname.new(__FILE__).dirname.join('..', 'fixtures', 'public', 'stylesheets') }
|
13
13
|
|
14
14
|
it "should load files matching the target names under root/public/stylesheets" do
|
15
15
|
Roadie.load_css(fixtures_root, ['foo']).should == 'contents of foo'
|
data/spec/spec_helper.rb
CHANGED
@@ -13,6 +13,9 @@ rescue Bundler::BundlerError => e
|
|
13
13
|
end
|
14
14
|
|
15
15
|
require 'rspec'
|
16
|
+
|
17
|
+
Dir['./spec/support/**/*'].each { |file| require file }
|
18
|
+
|
16
19
|
require 'action_mailer'
|
17
20
|
require 'roadie'
|
18
21
|
|
@@ -31,71 +34,3 @@ else
|
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
|
-
RSpec::Matchers.define :have_styling do |rules|
|
35
|
-
chain :at_selector do |selector|
|
36
|
-
@selector = selector
|
37
|
-
end
|
38
|
-
|
39
|
-
match do |document|
|
40
|
-
styles = parsed_styles(document)
|
41
|
-
if rules.nil?
|
42
|
-
styles.blank?
|
43
|
-
else
|
44
|
-
rules.stringify_keys.should == parsed_styles(document)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe { "have styles #{rules.inspect} at selector #{@selector.inspect}" }
|
49
|
-
failure_message_for_should { |document| "expected styles at #{@selector.inspect} to be #{rules.inspect} but was #{parsed_styles(document).inspect}" }
|
50
|
-
failure_message_for_should_not { "expected styles at #{@selector.inspect} to not be #{rules.inspect}" }
|
51
|
-
|
52
|
-
def element_styles(document)
|
53
|
-
node = document.css(@selector).first
|
54
|
-
node && node['style']
|
55
|
-
end
|
56
|
-
|
57
|
-
def parsed_styles(document)
|
58
|
-
return @parsed_styles if defined?(@parsed_styles)
|
59
|
-
if (styles = element_styles(document)).present?
|
60
|
-
@parsed_styles = styles.split(';').inject({}) do |styles, item|
|
61
|
-
attribute, value = item.split(':', 2)
|
62
|
-
styles.merge!(attribute.strip => value.strip)
|
63
|
-
end
|
64
|
-
else
|
65
|
-
@parsed_styles = nil
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
RSpec::Matchers.define :have_attribute do |attribute|
|
71
|
-
chain :at_selector do |selector|
|
72
|
-
@selector = selector
|
73
|
-
end
|
74
|
-
|
75
|
-
match do |document|
|
76
|
-
name, expected = attribute.first
|
77
|
-
expected == attribute(document, name)
|
78
|
-
end
|
79
|
-
|
80
|
-
describe { "have attribute #{attribute.inspect} at selector #{@selector.inspect}" }
|
81
|
-
failure_message_for_should do |document|
|
82
|
-
name, expected = attribute.first
|
83
|
-
"expected #{name} attribute at #{@selector.inspect} to be #{expected.inspect} but was #{attribute(document, name).inspect}"
|
84
|
-
end
|
85
|
-
failure_message_for_should_not do |document|
|
86
|
-
name, expected = attribute.first
|
87
|
-
"expected #{name} attribute at #{@selector.inspect} to not be #{expected.inspect}"
|
88
|
-
end
|
89
|
-
|
90
|
-
def attribute(document, attribute_name)
|
91
|
-
node = document.css(@selector).first
|
92
|
-
node && node[attribute_name]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
RSpec::Matchers.define :have_selector do |selector|
|
97
|
-
match { |document| document.css(selector).present? }
|
98
|
-
failure_message_for_should { "expected document to #{name_to_sentence}#{expected_to_sentence}"}
|
99
|
-
failure_message_for_should_not { "expected document to not #{name_to_sentence}#{expected_to_sentence}"}
|
100
|
-
end
|
101
|
-
|
@@ -0,0 +1,28 @@
|
|
1
|
+
RSpec::Matchers.define :have_attribute do |attribute|
|
2
|
+
@selector = 'body > *:first'
|
3
|
+
|
4
|
+
chain :at_selector do |selector|
|
5
|
+
@selector = selector
|
6
|
+
end
|
7
|
+
|
8
|
+
match do |document|
|
9
|
+
name, expected = attribute.first
|
10
|
+
expected == attribute(document, name)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe { "have attribute #{attribute.inspect} at selector #{@selector.inspect}" }
|
14
|
+
failure_message_for_should do |document|
|
15
|
+
name, expected = attribute.first
|
16
|
+
"expected #{name} attribute at #{@selector.inspect} to be #{expected.inspect} but was #{attribute(document, name).inspect}"
|
17
|
+
end
|
18
|
+
failure_message_for_should_not do |document|
|
19
|
+
name, expected = attribute.first
|
20
|
+
"expected #{name} attribute at #{@selector.inspect} to not be #{expected.inspect}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def attribute(document, attribute_name)
|
24
|
+
node = document.css(@selector).first
|
25
|
+
node && node[attribute_name]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
RSpec::Matchers.define :have_selector do |selector|
|
2
|
+
match { |document| document.css(selector).present? }
|
3
|
+
failure_message_for_should { "expected document to #{name_to_sentence}#{expected_to_sentence}"}
|
4
|
+
failure_message_for_should_not { "expected document to not #{name_to_sentence}#{expected_to_sentence}"}
|
5
|
+
end
|
6
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
RSpec::Matchers.define :have_styling do |rules|
|
2
|
+
@selector = 'body > *:first'
|
3
|
+
|
4
|
+
chain :at_selector do |selector|
|
5
|
+
@selector = selector
|
6
|
+
end
|
7
|
+
|
8
|
+
match do |document|
|
9
|
+
if rules.nil?
|
10
|
+
parsed_styles(document).blank?
|
11
|
+
else
|
12
|
+
rules.to_a.should == parsed_styles(document)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe { "have styles #{rules.inspect} at selector #{@selector.inspect}" }
|
17
|
+
failure_message_for_should { |document| "expected styles at #{@selector.inspect} to be #{rules.inspect} but was #{parsed_styles(document).inspect}" }
|
18
|
+
failure_message_for_should_not { "expected styles at #{@selector.inspect} to not be #{rules.inspect}" }
|
19
|
+
|
20
|
+
def parsed_styles(document)
|
21
|
+
parse_styles(element_style(document))
|
22
|
+
end
|
23
|
+
|
24
|
+
def element_style(document)
|
25
|
+
node = document.css(@selector).first
|
26
|
+
node && node['style']
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_styles(styles)
|
30
|
+
return [] if styles.blank?
|
31
|
+
styles.split(';').inject([]) do |array, item|
|
32
|
+
array << item.split(':', 2).map(&:strip)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roadie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
|
11
|
-
version: 1.0.0.pre2
|
10
|
+
version: 1.0.0
|
12
11
|
platform: ruby
|
13
12
|
authors:
|
14
13
|
- Magnus Bergmark
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2011-
|
18
|
+
date: 2011-03-09 00:00:00 +01:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -91,29 +90,36 @@ extra_rdoc_files:
|
|
91
90
|
files:
|
92
91
|
- .autotest
|
93
92
|
- .gitignore
|
94
|
-
- .
|
93
|
+
- .yardopts
|
95
94
|
- Gemfile
|
96
95
|
- Gemfile.lock
|
97
96
|
- MIT-LICENSE
|
98
97
|
- README.textile
|
99
98
|
- Rakefile
|
100
|
-
- VERSION
|
101
99
|
- autotest/discover.rb
|
102
100
|
- lib/roadie.rb
|
103
101
|
- lib/roadie/action_mailer_extensions.rb
|
102
|
+
- lib/roadie/css_file_not_found.rb
|
104
103
|
- lib/roadie/inliner.rb
|
104
|
+
- lib/roadie/style_declaration.rb
|
105
105
|
- lib/roadie/version.rb
|
106
106
|
- roadie.gemspec
|
107
107
|
- spec/fixtures/public/stylesheets/bar.css
|
108
108
|
- spec/fixtures/public/stylesheets/foo.css
|
109
109
|
- spec/fixtures/public/stylesheets/integration.css
|
110
|
+
- spec/fixtures/views/integration_mailer/marketing.html.erb
|
110
111
|
- spec/fixtures/views/integration_mailer/notification.html.erb
|
111
112
|
- spec/fixtures/views/integration_mailer/notification.text.erb
|
112
113
|
- spec/integration_spec.rb
|
113
114
|
- spec/lib/roadie/action_mailer_extensions_spec.rb
|
115
|
+
- spec/lib/roadie/css_file_not_found_spec.rb
|
114
116
|
- spec/lib/roadie/inliner_spec.rb
|
117
|
+
- spec/lib/roadie/style_declaration_spec.rb
|
115
118
|
- spec/lib/roadie_spec.rb
|
116
119
|
- spec/spec_helper.rb
|
120
|
+
- spec/support/have_attribute_matcher.rb
|
121
|
+
- spec/support/have_selector_matcher.rb
|
122
|
+
- spec/support/have_styling_matcher.rb
|
117
123
|
has_rdoc: true
|
118
124
|
homepage: http://github.com/Mange/roadie
|
119
125
|
licenses: []
|
@@ -135,14 +141,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
141
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
142
|
none: false
|
137
143
|
requirements:
|
138
|
-
- - "
|
144
|
+
- - ">="
|
139
145
|
- !ruby/object:Gem::Version
|
140
|
-
hash:
|
146
|
+
hash: 3
|
141
147
|
segments:
|
142
|
-
-
|
143
|
-
|
144
|
-
- 1
|
145
|
-
version: 1.3.1
|
148
|
+
- 0
|
149
|
+
version: "0"
|
146
150
|
requirements: []
|
147
151
|
|
148
152
|
rubyforge_project:
|
@@ -154,10 +158,16 @@ test_files:
|
|
154
158
|
- spec/fixtures/public/stylesheets/bar.css
|
155
159
|
- spec/fixtures/public/stylesheets/foo.css
|
156
160
|
- spec/fixtures/public/stylesheets/integration.css
|
161
|
+
- spec/fixtures/views/integration_mailer/marketing.html.erb
|
157
162
|
- spec/fixtures/views/integration_mailer/notification.html.erb
|
158
163
|
- spec/fixtures/views/integration_mailer/notification.text.erb
|
159
164
|
- spec/integration_spec.rb
|
160
165
|
- spec/lib/roadie/action_mailer_extensions_spec.rb
|
166
|
+
- spec/lib/roadie/css_file_not_found_spec.rb
|
161
167
|
- spec/lib/roadie/inliner_spec.rb
|
168
|
+
- spec/lib/roadie/style_declaration_spec.rb
|
162
169
|
- spec/lib/roadie_spec.rb
|
163
170
|
- spec/spec_helper.rb
|
171
|
+
- spec/support/have_attribute_matcher.rb
|
172
|
+
- spec/support/have_selector_matcher.rb
|
173
|
+
- spec/support/have_styling_matcher.rb
|
data/.rspec
DELETED
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.0.pre1
|