roadie 2.4.3 → 3.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.
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