roadie 2.4.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +10 -14
  4. data/.yardopts +1 -1
  5. data/Changelog.md +38 -5
  6. data/Gemfile +3 -4
  7. data/Guardfile +12 -1
  8. data/README.md +168 -164
  9. data/Rakefile +2 -19
  10. data/lib/roadie.rb +15 -68
  11. data/lib/roadie/asset_provider.rb +7 -58
  12. data/lib/roadie/asset_scanner.rb +92 -0
  13. data/lib/roadie/document.rb +103 -0
  14. data/lib/roadie/errors.rb +57 -0
  15. data/lib/roadie/filesystem_provider.rb +30 -60
  16. data/lib/roadie/inliner.rb +72 -217
  17. data/lib/roadie/markup_improver.rb +88 -0
  18. data/lib/roadie/null_provider.rb +13 -0
  19. data/lib/roadie/null_url_rewriter.rb +12 -0
  20. data/lib/roadie/provider_list.rb +71 -0
  21. data/lib/roadie/rspec.rb +1 -0
  22. data/lib/roadie/rspec/asset_provider.rb +49 -0
  23. data/lib/roadie/selector.rb +43 -18
  24. data/lib/roadie/style_attribute_builder.rb +25 -0
  25. data/lib/roadie/style_block.rb +32 -0
  26. data/lib/roadie/style_property.rb +93 -0
  27. data/lib/roadie/stylesheet.rb +65 -0
  28. data/lib/roadie/upgrade_guide.rb +36 -0
  29. data/lib/roadie/url_generator.rb +126 -0
  30. data/lib/roadie/url_rewriter.rb +84 -0
  31. data/lib/roadie/version.rb +1 -1
  32. data/roadie.gemspec +8 -11
  33. data/spec/fixtures/big_em.css +1 -0
  34. data/spec/fixtures/stylesheets/green.css +1 -0
  35. data/spec/integration_spec.rb +125 -95
  36. data/spec/lib/roadie/asset_scanner_spec.rb +153 -0
  37. data/spec/lib/roadie/css_not_found_spec.rb +17 -0
  38. data/spec/lib/roadie/document_spec.rb +123 -0
  39. data/spec/lib/roadie/filesystem_provider_spec.rb +44 -68
  40. data/spec/lib/roadie/inliner_spec.rb +105 -537
  41. data/spec/lib/roadie/markup_improver_spec.rb +78 -0
  42. data/spec/lib/roadie/null_provider_spec.rb +21 -0
  43. data/spec/lib/roadie/null_url_rewriter_spec.rb +19 -0
  44. data/spec/lib/roadie/provider_list_spec.rb +89 -0
  45. data/spec/lib/roadie/selector_spec.rb +15 -10
  46. data/spec/lib/roadie/style_attribute_builder_spec.rb +29 -0
  47. data/spec/lib/roadie/style_block_spec.rb +35 -0
  48. data/spec/lib/roadie/style_property_spec.rb +82 -0
  49. data/spec/lib/roadie/stylesheet_spec.rb +41 -0
  50. data/spec/lib/roadie/test_provider_spec.rb +29 -0
  51. data/spec/lib/roadie/url_generator_spec.rb +121 -0
  52. data/spec/lib/roadie/url_rewriter_spec.rb +79 -0
  53. data/spec/shared_examples/asset_provider.rb +11 -0
  54. data/spec/shared_examples/url_rewriter.rb +23 -0
  55. data/spec/spec_helper.rb +6 -60
  56. data/spec/support/have_attribute_matcher.rb +2 -2
  57. data/spec/support/have_node_matcher.rb +4 -4
  58. data/spec/support/have_selector_matcher.rb +3 -3
  59. data/spec/support/have_styling_matcher.rb +51 -15
  60. data/spec/support/test_provider.rb +13 -0
  61. metadata +86 -175
  62. data/Appraisals +0 -15
  63. data/gemfiles/rails_3.0.gemfile +0 -7
  64. data/gemfiles/rails_3.0.gemfile.lock +0 -123
  65. data/gemfiles/rails_3.1.gemfile +0 -7
  66. data/gemfiles/rails_3.1.gemfile.lock +0 -126
  67. data/gemfiles/rails_3.2.gemfile +0 -7
  68. data/gemfiles/rails_3.2.gemfile.lock +0 -124
  69. data/gemfiles/rails_4.0.gemfile +0 -7
  70. data/gemfiles/rails_4.0.gemfile.lock +0 -119
  71. data/lib/roadie/action_mailer_extensions.rb +0 -95
  72. data/lib/roadie/asset_pipeline_provider.rb +0 -28
  73. data/lib/roadie/css_file_not_found.rb +0 -22
  74. data/lib/roadie/railtie.rb +0 -39
  75. data/lib/roadie/style_declaration.rb +0 -42
  76. data/spec/fixtures/app/assets/stylesheets/integration.css +0 -10
  77. data/spec/fixtures/public/stylesheets/integration.css +0 -10
  78. data/spec/fixtures/views/integration_mailer/marketing.html.erb +0 -2
  79. data/spec/fixtures/views/integration_mailer/notification.html.erb +0 -8
  80. data/spec/fixtures/views/integration_mailer/notification.text.erb +0 -6
  81. data/spec/lib/roadie/action_mailer_extensions_spec.rb +0 -227
  82. data/spec/lib/roadie/asset_pipeline_provider_spec.rb +0 -65
  83. data/spec/lib/roadie/css_file_not_found_spec.rb +0 -29
  84. data/spec/lib/roadie/style_declaration_spec.rb +0 -49
  85. data/spec/lib/roadie_spec.rb +0 -101
  86. data/spec/shared_examples/asset_provider_examples.rb +0 -11
  87. data/spec/support/anonymous_mailer.rb +0 -21
  88. data/spec/support/change_url_options.rb +0 -5
  89. data/spec/support/parse_styling.rb +0 -25
@@ -1,28 +0,0 @@
1
- module Roadie
2
- # A provider that hooks into Rail's Asset Pipeline.
3
- #
4
- # Usage:
5
- # config.roadie.provider = AssetPipelineProvider.new('prefix')
6
- #
7
- # @see http://guides.rubyonrails.org/asset_pipeline.html
8
- class AssetPipelineProvider < AssetProvider
9
- # Looks up the file with the given name in the asset pipeline
10
- #
11
- # @return [String] contents of the file
12
- def find(name)
13
- asset_file(name).to_s.strip
14
- end
15
-
16
- private
17
- def assets
18
- Roadie.app.assets
19
- end
20
-
21
- def asset_file(name)
22
- basename = remove_prefix(name)
23
- assets[basename].tap do |file|
24
- raise CSSFileNotFound.new(basename) unless file
25
- end
26
- end
27
- end
28
- end
@@ -1,22 +0,0 @@
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, :guess
6
-
7
- def initialize(filename, guess = nil)
8
- @filename = filename
9
- @guess = guess
10
- super(build_message)
11
- end
12
-
13
- private
14
- def build_message
15
- if guess
16
- "Could not find #{filename} (guessed from #{guess.inspect})"
17
- else
18
- "Could not find #{filename}"
19
- end
20
- end
21
- end
22
- end
@@ -1,39 +0,0 @@
1
- require 'action_mailer'
2
- require 'roadie'
3
- require 'roadie/action_mailer_extensions'
4
-
5
- module Roadie
6
- # {Roadie::Railtie} registers {Roadie} with the current Rails application
7
- # It adds configuration options:
8
- #
9
- # config.roadie.enabled = true
10
- # Set this to false to disable Roadie completely. This could be useful if
11
- # you don't want Roadie in certain environments.
12
- #
13
- # config.roadie.provider = nil
14
- # You can use this to set a provider yourself. See {Roadie::AssetProvider}.
15
- #
16
- # config.roadie.after_inlining = lambda do |doc|
17
- # doc.css('#products p.desc a[href^="/"]').each do |link|
18
- # link['href'] = "http://www.foo.com" + link['href']
19
- # end
20
- # end
21
- # You can use this to set a custom inliner. A custom inliner transforms an outgoing HTML email using application specific rules.
22
- # The custom inliner is invoked after the default inliner.A custom inliner can be created using a `lambda` that accepts one parameter
23
- # or an object that responds to the `call` method with one parameter.
24
- #
25
- # @see Roadie
26
- # @see AssetProvider
27
- class Railtie < Rails::Railtie
28
- config.roadie = ActiveSupport::OrderedOptions.new
29
- config.roadie.enabled = true
30
- config.roadie.provider = nil
31
- config.roadie.after_inlining = nil
32
-
33
- initializer "roadie.extend_action_mailer" do
34
- ActiveSupport.on_load(:action_mailer) do
35
- include Roadie::ActionMailerExtensions
36
- end
37
- end
38
- end
39
- end
@@ -1,42 +0,0 @@
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_with_important].join(':')
27
- end
28
-
29
- def inspect
30
- "#{to_s} (#{specificity})"
31
- end
32
-
33
- private
34
- def value_with_important
35
- if important
36
- "#{value} !important"
37
- else
38
- value
39
- end
40
- end
41
- end
42
- end
@@ -1,10 +0,0 @@
1
- body { background: url(../images/dots.png) repeat-x; }
2
- #message { background-color: #fff; margin: 0 auto; width: 75%; }
3
-
4
- h1 { color: #eee; }
5
- strong {
6
- -moz-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
7
- -webkit-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
8
- -o-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
9
- box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
10
- }
@@ -1,10 +0,0 @@
1
- body { background: url(../images/dots.png) repeat-x; }
2
- #message { background-color: #fff; margin: 0 auto; width: 75%; }
3
-
4
- h1 { color: #eee; }
5
- strong {
6
- -moz-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
7
- -webkit-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
8
- -o-box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
9
- box-shadow: #62b0d7 1px 1px 1px 1px inset, #aaaaaa 1px 1px 3px 0;
10
- }
@@ -1,2 +0,0 @@
1
- Contact us to buy stuff!
2
- <a href="http://www.example.com/cheap-marketing">SPAM MASTERS</a>
@@ -1,8 +0,0 @@
1
- <div id="message">
2
- <h1>Dear person</1>
3
-
4
- <p>I have to inform you that <strong><%= @reason %></strong>.</p>
5
-
6
- <p>Thank you,<br />
7
- The app</p>
8
- </div>
@@ -1,6 +0,0 @@
1
- = Dear person =
2
-
3
- I have to inform you that <%= @reason %>.
4
-
5
- Thank you,
6
- The app
@@ -1,227 +0,0 @@
1
- # coding: utf-8
2
- require 'spec_helper'
3
-
4
- module Roadie
5
- describe ActionMailerExtensions, "CSS selection" do
6
- mailer = Class.new(AnonymousMailer) do
7
- default :css => 'default'
8
-
9
- def default_css
10
- mail(:subject => "Default CSS") do |format|
11
- format.html { render :text => '' }
12
- end
13
- end
14
-
15
- def override_css(css)
16
- mail(:subject => "Default CSS", :css => css) do |format|
17
- format.html { render :text => '' }
18
- end
19
- end
20
- end
21
-
22
- def expect_global_css(files)
23
- Roadie.should_receive(:inline_css).with(provider, files, anything, anything, anything).and_return('')
24
- end
25
-
26
- let(:provider) { double("asset provider", :all => '') }
27
-
28
- before(:each) do
29
- Roadie.stub(:inline_css => 'unexpected value passed to inline_css')
30
- Roadie.stub(:current_provider => provider)
31
- end
32
-
33
- it "uses the default CSS when :css is not specified" do
34
- expect_global_css ['default']
35
- mailer.default_css
36
- end
37
-
38
- it "uses the specified CSS instead of the default" do
39
- expect_global_css ['some', 'other/files']
40
- mailer.override_css([:some, 'other/files'])
41
- end
42
-
43
- it "allows procs defining the CSS files to use" do
44
- proc = lambda { 'from proc' }
45
-
46
- expect_global_css ['from proc']
47
- mailer.override_css([proc])
48
- end
49
-
50
- it "runs procs in the context of the instance" do
51
- new_mailer = Class.new(mailer) do
52
- private
53
- def a_private_method
54
- 'from private method'
55
- end
56
- end
57
- proc = lambda { a_private_method }
58
-
59
- expect_global_css ['from private method']
60
- new_mailer.override_css([proc])
61
- end
62
-
63
- it "uses no global CSS when :css is set to nil" do
64
- expect_global_css []
65
- mailer.override_css(nil)
66
- end
67
-
68
- it "uses no global CSS when :css is set to false" do
69
- expect_global_css []
70
- mailer.override_css(false)
71
- end
72
-
73
- it "uses no global CSS when :css is set to a proc returning nil" do
74
- expect_global_css []
75
- mailer.override_css(lambda { nil })
76
- end
77
- end
78
-
79
- describe ActionMailerExtensions, "after_initialize handler" do
80
- let(:global_after_inlining_handler) { double("global after inlining handler") }
81
- let(:per_mailer_after_inlining_handler) { double("per mailer after inlining handler") }
82
- let(:per_mail_after_inlining_handler) { double("per mail after inlining handler") }
83
- let(:provider) { double("asset provider", :all => '') }
84
-
85
- before(:each) do
86
- Roadie.stub(:current_provider => provider)
87
- Roadie.stub(:after_inlining_handler => global_after_inlining_handler)
88
- end
89
-
90
- def expect_inlining_handler(handler)
91
- Roadie.should_receive(:inline_css).with(provider, anything, anything, anything, handler)
92
- end
93
-
94
- describe "global" do
95
- let(:mailer) do
96
- Class.new(AnonymousMailer) do
97
- def nil_handler
98
- mail(:subject => "Nil handler") do |format|
99
- format.html { render :text => '' }
100
- end
101
- end
102
-
103
- def global_handler
104
- mail(:subject => "Global handler") do |format|
105
- format.html { render :text => '' }
106
- end
107
- end
108
- end
109
- end
110
-
111
- it "is set to the provided global handler when mailer/per mail handler are not specified" do
112
- expect_inlining_handler(global_after_inlining_handler)
113
- mailer.global_handler
114
- end
115
-
116
- it "is not used when not set" do
117
- Roadie.stub(:after_inlining_handler => nil)
118
- expect_inlining_handler(nil)
119
- mailer.nil_handler
120
- end
121
- end
122
-
123
- describe "overridden" do
124
- let(:mailer) do
125
- handler = per_mailer_after_inlining_handler
126
- Class.new(AnonymousMailer) do
127
- default :after_inlining => handler
128
-
129
- def per_mailer_handler
130
- mail(:subject => "Mailer handler") do |format|
131
- format.html { render :text => '' }
132
- end
133
- end
134
-
135
- def per_mail_handler(handler)
136
- mail(:subject => "Per Mail handler", :after_inlining => handler) do |format|
137
- format.html { render :text => '' }
138
- end
139
- end
140
- end
141
- end
142
-
143
- it "is set to the provided mailer handler" do
144
- expect_inlining_handler(per_mailer_after_inlining_handler)
145
- mailer.per_mailer_handler
146
- end
147
-
148
- it "is set to the provided per mail handler" do
149
- expect_inlining_handler(per_mail_after_inlining_handler)
150
- mailer.per_mail_handler(per_mail_after_inlining_handler)
151
- end
152
- end
153
- end
154
-
155
- describe ActionMailerExtensions, "using HTML" do
156
- mailer = Class.new(AnonymousMailer) do
157
- default :css => 'simple'
158
-
159
- def multipart
160
- mail(:subject => "Multipart email") do |format|
161
- format.html { render :text => 'Hello HTML' }
162
- format.text { render :text => 'Hello Text' }
163
- end
164
- end
165
-
166
- def singlepart_html
167
- mail(:subject => "HTML email") do |format|
168
- format.html { render :text => 'Hello HTML' }
169
- end
170
- end
171
-
172
- def singlepart_plain
173
- mail(:subject => "Text email") do |format|
174
- format.text { render :text => 'Hello Text' }
175
- end
176
- end
177
- end
178
-
179
- let(:provider) { double("asset provider", :all => '') }
180
-
181
- before(:each) do
182
- Roadie.stub(:inline_css => 'unexpected value passed to inline_css')
183
- Roadie.stub(:current_provider => provider)
184
- end
185
-
186
- describe "for singlepart text/plain" do
187
- it "does not touch the email body" do
188
- Roadie.should_not_receive(:inline_css)
189
- mailer.singlepart_plain
190
- end
191
- end
192
-
193
- describe "for singlepart text/html" do
194
- it "inlines css to the email body" do
195
- Roadie.should_receive(:inline_css).with(provider, ['simple'], 'Hello HTML', anything, anything).and_return('html')
196
- mailer.singlepart_html.body.decoded.should == 'html'
197
- end
198
-
199
- it "does not inline css when Roadie is disabled" do
200
- Roadie.stub :enabled? => false
201
- Roadie.should_not_receive(:inline_css)
202
- mailer.singlepart_html.body.decoded.should == 'Hello HTML'
203
- end
204
- end
205
-
206
- describe "for multipart" do
207
- it "keeps both parts" do
208
- mailer.multipart.should have(2).parts
209
- end
210
-
211
- it "inlines css to the email's html part" do
212
- Roadie.should_receive(:inline_css).with(provider, ['simple'], 'Hello HTML', anything, anything).and_return('html')
213
- email = mailer.multipart
214
- email.html_part.body.decoded.should == 'html'
215
- email.text_part.body.decoded.should == 'Hello Text'
216
- end
217
-
218
- it "does not inline css when Roadie is disabled" do
219
- Roadie.stub :enabled? => false
220
- Roadie.should_not_receive(:inline_css)
221
- email = mailer.multipart
222
- email.html_part.body.decoded.should == 'Hello HTML'
223
- email.text_part.body.decoded.should == 'Hello Text'
224
- end
225
- end
226
- end
227
- end
@@ -1,65 +0,0 @@
1
- require 'spec_helper'
2
- require 'shared_examples/asset_provider_examples'
3
-
4
- module Roadie
5
- describe AssetPipelineProvider do
6
- let(:provider) { AssetPipelineProvider.new }
7
-
8
- it_behaves_like AssetProvider
9
-
10
- it "has a configurable prefix" do
11
- AssetPipelineProvider.new("/prefix").prefix.should == "/prefix"
12
- end
13
-
14
- it 'has a prefix of "/assets" by default' do
15
- provider.prefix.should == "/assets"
16
- end
17
-
18
- describe "#find(file)" do
19
- let(:pipeline) { double("Rails asset pipeline") }
20
- before(:each) { Roadie.app.stub(:assets => pipeline) }
21
-
22
- def expect_pipeline_access(name, returning = '')
23
- pipeline.should_receive(:[]).with(name).and_return(returning)
24
- end
25
-
26
- it "loads files matching the target names in Rails assets" do
27
- expect_pipeline_access('foo', 'contents of foo')
28
- expect_pipeline_access('foo.css', 'contents of foo.css')
29
-
30
- provider.find('foo').should == 'contents of foo'
31
- provider.find('foo.css').should == 'contents of foo.css'
32
- end
33
-
34
- it "strips the contents" do
35
- expect_pipeline_access('foo', " contents \n ")
36
- provider.find('foo').should == "contents"
37
- end
38
-
39
- it "removes the prefix from the filename" do
40
- expect_pipeline_access('foo')
41
- expect_pipeline_access('path/to/foo')
42
- expect_pipeline_access('bar')
43
-
44
- provider = AssetPipelineProvider.new("/prefix")
45
- provider.find('/prefix/foo')
46
- provider.find('/prefix/path/to/foo')
47
- provider.find('prefix/bar')
48
- end
49
-
50
- it "cleans up double slashes from the path" do
51
- expect_pipeline_access('path/to/foo')
52
-
53
- provider = AssetPipelineProvider.new("/prefix/")
54
- provider.find('/prefix/path/to//foo')
55
- end
56
-
57
- it "raises a Roadie::CSSFileNotFound error when the file could not be found" do
58
- expect_pipeline_access('not_here', nil)
59
- expect {
60
- provider.find('not_here')
61
- }.to raise_error(Roadie::CSSFileNotFound, /not_here/)
62
- end
63
- end
64
- end
65
- end