roadie 3.0.5 → 3.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -7
  3. data/.travis.yml +1 -5
  4. data/Changelog.md +20 -1
  5. data/Guardfile +2 -1
  6. data/README.md +193 -53
  7. data/lib/roadie.rb +3 -2
  8. data/lib/roadie/asset_scanner.rb +30 -10
  9. data/lib/roadie/cached_provider.rb +77 -0
  10. data/lib/roadie/document.rb +29 -10
  11. data/lib/roadie/errors.rb +43 -1
  12. data/lib/roadie/filesystem_provider.rb +3 -1
  13. data/lib/roadie/inliner.rb +57 -27
  14. data/lib/roadie/markup_improver.rb +2 -1
  15. data/lib/roadie/net_http_provider.rb +70 -0
  16. data/lib/roadie/null_provider.rb +3 -0
  17. data/lib/roadie/path_rewriter_provider.rb +64 -0
  18. data/lib/roadie/provider_list.rb +19 -1
  19. data/lib/roadie/rspec.rb +1 -0
  20. data/lib/roadie/rspec/cache_store.rb +25 -0
  21. data/lib/roadie/stylesheet.rb +1 -0
  22. data/lib/roadie/url_generator.rb +2 -1
  23. data/lib/roadie/utils.rb +9 -0
  24. data/lib/roadie/version.rb +1 -1
  25. data/roadie.gemspec +2 -1
  26. data/spec/hash_as_cache_store_spec.rb +7 -0
  27. data/spec/integration_spec.rb +91 -0
  28. data/spec/lib/roadie/asset_scanner_spec.rb +79 -25
  29. data/spec/lib/roadie/cached_provider_spec.rb +52 -0
  30. data/spec/lib/roadie/document_spec.rb +43 -7
  31. data/spec/lib/roadie/filesystem_provider_spec.rb +5 -0
  32. data/spec/lib/roadie/inliner_spec.rb +72 -15
  33. data/spec/lib/roadie/net_http_provider_spec.rb +89 -0
  34. data/spec/lib/roadie/path_rewriter_provider_spec.rb +39 -0
  35. data/spec/lib/roadie/provider_list_spec.rb +31 -8
  36. data/spec/lib/roadie/stylesheet_spec.rb +14 -8
  37. data/spec/lib/roadie/utils_spec.rb +7 -0
  38. data/spec/spec_helper.rb +1 -0
  39. data/spec/support/have_styling_matcher.rb +1 -0
  40. metadata +40 -9
  41. data/lib/roadie/upgrade_guide.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 149e5b897cfd1808633c9b03e3e4b35fc08f23d4
4
- data.tar.gz: 1bc5e6e5526f128be884f85a06923f2fbf50ce30
3
+ metadata.gz: 8a3f338440d0c7a3c9dbe8c3c333cb0c15bf37d7
4
+ data.tar.gz: 4d4b97f7ffee5eea3d8d0a0f6d700ed0b84d9799
5
5
  SHA512:
6
- metadata.gz: e3f0f67f6b32561f32b021f09d374b07bb75a7d1e644b0d04e551ba89a135725019c4347b3a2fcf32941a5a15b2b8941dd11dde706d636da567727cab8b69683
7
- data.tar.gz: ff65e28f825d90b61959eab22e916046835efe6305b37af0d19a7526dfd760ec59a767d28517dda26883f5572866e67e431f2f3fe35f0cb9db9c67add5da9b0a
6
+ metadata.gz: 4674757cf96c11bb3e4c8f6a5b4d18f9b6ccb9396ef8c281ef1b04d32ea3435c3349ac64fc46b1885f572d588e821d02ff336be5b463ca0df89f3f4974a22fe9
7
+ data.tar.gz: d280f0f055a9a7baa033c3fcb7389621319bd09ec4255c3ec4fa95b129699e6d30421c9369497b1ed2ff6ef58bd98d39f3cc8bab19af4c0428bd012a4f4fc8e0
data/.gitignore CHANGED
@@ -1,15 +1,10 @@
1
1
  .DS_Store
2
- pkg
3
- .*~
4
2
  .yardoc
5
3
 
6
4
  .rspec
7
- .idea/*
8
- .rvmrc
5
+ .ruby-version
9
6
 
10
7
  Gemfile.lock
11
8
  doc
12
9
  tmp
13
-
14
- spec/railsapps/*/log
15
- spec/railsapps/*/tmp
10
+ pkg
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
- - 2.0.0
4
+ - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
7
  - jruby
@@ -13,7 +13,3 @@ script: "rake"
13
13
  env:
14
14
  # Setup Coveralls
15
15
  secure: "D1Uvi+a7W89k91zXVVwuuvv8O8qbDdyJ4g9i+3bGaSYySHxD8YuuG1QiQ4G/S2KLp/r3VPRpa8Wb1mSwb81tEBzXpzoZC7zSvgntPxRPhMg4zpodZ0O0AkK8/t1yZSkIe0V5sejFOQ1a5LJa3OorKBBjrqM5kPDOygTXtO3bQ6E="
16
-
17
- matrix:
18
- allow_failures:
19
- - rvm: rbx
@@ -1,9 +1,28 @@
1
1
  ### dev
2
2
 
3
- [full changelog](https://github.com/Mange/roadie/compare/v3.0.5...master)
3
+ [full changelog](https://github.com/Mange/roadie/compare/v3.1.0.rc1...master)
4
4
 
5
5
  * Nothing yet.
6
6
 
7
+ ### 3.1.0.rc1
8
+
9
+ [full changelog](https://github.com/Mange/roadie/compare/v3.0.5...v3.1.0.rc1)
10
+
11
+ * Enhancements:
12
+ * Allow user to specify asset providers for referenced assets with full URLs and inline them (#107)
13
+ * Pass `Document` instance to transformation callbacks (#86)
14
+ * Made `nokogiri` dependency more forgiving.
15
+ * Supports `1.5.0`...`1.7.0` now instead of `1.6.0`...`1.7.0`. Some people out there are stuck on this older version of Nokogiri, and I don't want to leave them out.
16
+ * Output better errors when no assets can be found.
17
+ * The error will now show which providers were tried and in which order, along with the error message from the specific providers.
18
+ * `Roadie::FilesystemProvider` shows the given path when inspected.
19
+ * `data-roadie-ignore` attributes will now be removed from markup; hiding "development markers" in the final email.
20
+ * Add a `Roadie::CachedProvider` asset provider that wraps other providers and cache them.
21
+ * Add a `Roadie::PathRewriterProvider` asset provider that rewrites asset names for other providers.
22
+ * This saves you from having to create custom providers if you require small tweaks to the lookup in order to use an official provider.
23
+ * **Deprecations:**
24
+ * `Roadie::Stylesheet#each_inlinable_block` is now deprecated. You can iterate and filter the `blocks` at your own discresion.
25
+
7
26
  ### 3.0.5
8
27
 
9
28
  [full changelog](https://github.com/Mange/roadie/compare/v3.0.4...v3.0.5)
data/Guardfile CHANGED
@@ -9,7 +9,8 @@ rspec_options = {
9
9
  guard 'rspec', rspec_options do
10
10
  watch(%r{^spec/.+_spec\.rb$})
11
11
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
- watch('lib/roadie.rb') { "spec" }
12
+ watch('lib/roadie.rb') { "spec" }
13
+ watch('lib/roadie/errors.rb') { "spec" }
13
14
 
14
15
  watch(%r{lib/roadie/rspec/.*\.rb}) { "spec" }
15
16
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Roadie
2
2
  ======
3
3
 
4
- [![Build history and status](https://secure.travis-ci.org/Mange/roadie.png)](http://travis-ci.org/#!/Mange/roadie)
4
+ [![Build history and status](https://travis-ci.org/Mange/roadie.svg?branch=master)](http://travis-ci.org/#!/Mange/roadie)
5
5
  [![Code Climate](https://codeclimate.com/github/Mange/roadie.png)](https://codeclimate.com/github/Mange/roadie)
6
6
  [![Coverage Status](https://coveralls.io/repos/Mange/roadie/badge.png?branch=master)](https://coveralls.io/r/Mange/roadie?branch=master)
7
7
  [![Gem Version](https://badge.fury.io/rb/roadie.png)](http://badge.fury.io/rb/roadie)
@@ -17,28 +17,27 @@ Roadie tries to make sending HTML emails a little less painful by inlining style
17
17
  How does it work?
18
18
  -----------------
19
19
 
20
- Email clients have bad support for stylesheets, and some of them blocks stylesheets from downloading. The easiest way to handle this is to work with all styles inline, but that is error prone and hard to work with as you cannot use classes and/or reuse styling.
20
+ Email clients have bad support for stylesheets, and some of them blocks stylesheets from downloading. The easiest way to handle this is to work with inline styles (`style="..."`), but that is error prone and hard to work with as you cannot use classes and/or reuse styling over your HTML.
21
21
 
22
- This gem helps making this easier by automatically inlining stylesheet rules into the document before sending it. You just give it a list of stylesheets and it will go though all of the selectors assigning the styles to the maching elements. Careful attention has been put into rules being applied in the correct order, so it should behave just like in the browser¹.
22
+ This gem makes this easier by automatically inlining stylesheets into the document. You give Roadie your CSS, or let it find it by itself from the `<link>` and `<style>` tags in the markup, and it will go though all of the selectors assigning the styles to the maching elements. Careful attention has been put into selectors being applied in the correct order, so it should behave just like in the browser.
23
23
 
24
- Roadie also rewrites all relative URLs in the email to a absolute counterpart, making images you insert and those referenced in your stylesheets work. No more headaches about how to write the stylesheets while still having them work with emails from your acceptance environments.
24
+ "Dynamic" selectors (`:hover`, `:visited`, `:focus`, etc.), or selectors not understood by Nokogiri will be inlined into a single `<style>` element for those email clients that support it. This changes specificity a great deal for these rules, so it might not work 100% out of the box. (See more about this below)
25
25
 
26
- ¹: Of course, rules like `:hover` will not work by definition. Only static styles can be added.
26
+ Roadie also rewrites all relative URLs in the email to an absolute counterpart, making images you insert and those referenced in your stylesheets work. No more headaches about how to write the stylesheets while still having them work with emails from your acceptance environments.
27
27
 
28
28
  Features
29
29
  --------
30
30
 
31
- * Writes CSS styles inline
32
- * Respects `!important` styles
33
- * Does not overwrite styles already present in the `style` attribute of tags
34
- * Supports the same CSS selectors as [Nokogiri](http://nokogiri.org/) (use CSS3 selectors in your emails!)
35
- * Makes image urls absolute
36
- * Hostname and port configurable on a per-environment basis
37
- * Makes link `href`s and `img` `src`s absolute
38
- * Automatically adds proper html skeleton when missing (you don't have to create a layout for emails)²
39
- * Allows you to inject stylesheets in a number of ways, at runtime
40
-
41
- ²: This might be removed in a future version, though. You really ought to create a good layout and not let Roadie guess how you want to have it structured.
31
+ * Writes CSS styles inline.
32
+ * Respects `!important` styles.
33
+ * Does not overwrite styles already present in the `style` attribute of tags.
34
+ * Supports the same CSS selectors as [Nokogiri](http://nokogiri.org/); use CSS3 selectors in your emails!
35
+ * Keeps `:hover` and friends around in a separate `<style>` element.
36
+ * Makes image urls absolute.
37
+ * Hostname and port configurable on a per-environment basis.
38
+ * Makes link `href`s and `img` `src`s absolute.
39
+ * Automatically adds proper HTML skeleton when missing; you don't have to create a layout for emails.
40
+ * Allows you to inject stylesheets in a number of ways, at runtime.
42
41
 
43
42
  Install & Usage
44
43
  ---------------
@@ -46,10 +45,10 @@ Install & Usage
46
45
  [Add this gem to your Gemfile as recommended by Rubygems](http://rubygems.org/gems/roadie) and run `bundle install`.
47
46
 
48
47
  ```ruby
49
- gem 'roadie', '~> x.y.0'
48
+ gem 'roadie', '~> 3.1.0'
50
49
  ```
51
50
 
52
- You may then create a new instance of a Roadie document:
51
+ You can then create a new instance of a Roadie document:
53
52
 
54
53
  ```ruby
55
54
  document = Roadie::Document.new "<html><body></body></html>"
@@ -58,12 +57,14 @@ document.transform
58
57
  # => "<html><body style=\"color:green;\"></body></html>"
59
58
  ```
60
59
 
61
- Your document instance can be configured several options:
60
+ Your document instance can be configured with several options:
62
61
 
63
62
  * `url_options` - Dictates how absolute URLs should be built.
64
- * `asset_providers` - A single (or list of) asset providers that are invoked when external CSS is referenced. See below.
65
- * `before_transformation` - A callback run before inlining starts.
66
- * `after_transformation` - A callback run after inlining is completed.
63
+ * `keep_uninlinable_css` - Set to false to skip CSS that cannot be inlined.
64
+ * `asset_providers` - A list of asset providers that are invoked when CSS files are referenced. See below.
65
+ * `external_asset_providers` - A list of asset providers that are invoked when absolute CSS URLs are referenced. See below.
66
+ * `before_transformation` - A callback run before transformation starts.
67
+ * `after_transformation` - A callback run after transformation is completed.
67
68
 
68
69
  ### Making URLs absolute ###
69
70
 
@@ -92,8 +93,8 @@ Style and link elements with `media="print"` are also ignored.
92
93
 
93
94
  ```html
94
95
  <head>
95
- <link rel="stylesheet" type="text/css" href="/assets/emails/rock.css"> <!-- Will be inlined -->
96
- <link rel="stylesheet" type="text/css" href="http://www.metal.org/metal.css"> <!-- Will NOT be inlined; absolute URL -->
96
+ <link rel="stylesheet" type="text/css" href="/assets/emails/rock.css"> <!-- Will be inlined with normal providers -->
97
+ <link rel="stylesheet" type="text/css" href="http://www.metal.org/metal.css"> <!-- Will be inlined with external providers, *IF* specified; otherwise ignored. -->
97
98
  <link rel="stylesheet" type="text/css" href="/assets/jazz.css" media="print"> <!-- Will NOT be inlined; print style -->
98
99
  <link rel="stylesheet" type="text/css" href="/ambient.css" data-roadie-ignore> <!-- Will NOT be inlined; ignored -->
99
100
  <style></style> <!-- Will be inlined -->
@@ -134,14 +135,19 @@ If a referenced stylesheet cannot be found, the `#transform` method will raise a
134
135
 
135
136
  ### Configuring providers ###
136
137
 
137
- You can write your own providers if you need very specific behavior for your app, or you can use the built-in providers.
138
+ You can write your own providers if you need very specific behavior for your app, or you can use the built-in providers. Providers come in two groups: normal and external. Normal providers handle paths without host information (`/style/foo.css`) while external providers handle URLs with host information (`//example.com/foo.css`, `localhost:3001/bar.css`, and so on).
139
+
140
+ The default configuration is to not have any external providers configured, which will cause those referenced stylesheets to be ignored. Adding one or more providers for external assets causes all of them to be searched and inlined, so if you only want this to happen to specific stylesheets you need to add ignore markers to every other styleshheet (see above).
138
141
 
139
142
  Included providers:
140
- * `FilesystemProvider` - Looks for files on the filesystem, relative to the given directory unless otherwise specified.
143
+ * `FilesystemProvider` Looks for files on the filesystem, relative to the given directory unless otherwise specified.
141
144
  * `ProviderList` – Wraps a list of other providers and searches them in order. The `asset_providers` setting is an instance of this. It behaves a lot like an array, so you can push, pop, shift and unshift to it.
142
- * `NullProvider` - Does not actually provide anything, it always finds empty stylesheets. Use this in tests or if you want to ignore stylesheets that cannot be found by your other providers.
145
+ * `NullProvider` Does not actually provide anything, it always finds empty stylesheets. Use this in tests or if you want to ignore stylesheets that cannot be found by your other providers (or if you want to force the other providers to never run).
146
+ * `NetHttpProvider` – Downloads stylesheets using `Net::HTTP`. Can be given a whitelist of hosts to download from.
147
+ * `CachedProvider` – Wraps another provider (or `ProviderList`) and caches responses inside the provided cache store.
148
+ * `PathRewriterProvider` – Rewrites the passed path and then passes it on to another provider (or `ProviderList`).
143
149
 
144
- If you want to search several locations on the filesystem, just declare that:
150
+ If you want to search several locations on the filesystem, you can declare that:
145
151
 
146
152
  ```ruby
147
153
  document.asset_providers = [
@@ -150,16 +156,127 @@ document.asset_providers = [
150
156
  ]
151
157
  ```
152
158
 
159
+ #### `NullProvider` ####
160
+
153
161
  If you want to ignore stylesheets that cannot be found instead of crashing, push the `NullProvider` to the end:
154
162
 
155
163
  ```ruby
164
+ # Don't crash on missing assets
156
165
  document.asset_providers << Roadie::NullProvider.new
166
+
167
+ # Don't download assets in tests
168
+ document.external_asset_providers.unshift Roadie::NullProvider.new
169
+ ```
170
+
171
+ **Note:** This will cause the referenced stylesheet to be removed from the source code, so email client will never see it either.
172
+
173
+ #### `NetHttpProvider` ####
174
+
175
+ The `NetHttpProvider` will download the URLs that is is given using Ruby's standard `Net::HTTP` library.
176
+
177
+ You can give it a whitelist of hosts that downloads are allowed from:
178
+
179
+ ```ruby
180
+ document.external_asset_providers << Roadie::NetHttpProvider.new(whitelist: ["myapp.com", "assets.myapp.com", "cdn.cdnnetwork.co.jp"])
181
+ document.external_asset_providers << Roadie::NetHttpProvider.new # Allows every host
182
+ ```
183
+
184
+ #### `CachedProvider` ####
185
+
186
+ You might want to cache providers from working several times. If you are sending several emails quickly from the same process, this might also save a lot of time on parsing the stylesheets if you use in-memory storage such as a hash.
187
+
188
+ You can wrap any other kind of providers with it, even a `ProviderList`:
189
+
190
+ ```ruby
191
+ document.external_asset_providers = Roadie::CachedProvider.new(document.external_asset_providers, my_cache)
192
+ ```
193
+
194
+ If you don't pass a cache backend, it will use a normal `Hash`. The cache store must follow this protocol:
195
+
196
+ ```ruby
197
+ my_cache["key"] = some_stylesheet_instance # => #<Roadie::Stylesheet instance>
198
+ my_cache["key"] # => #<Roadie::Stylesheet instance>
199
+ my_cache["missing"] # => nil
200
+ ```
201
+
202
+ **Warning:** The default `Hash` store will never be cleared, so make sure you don't allow the number of unique asset paths to grow too large in a single run. This is especially important if you run Roadie in a daemon that accepts arbritary documents, and/or if you use hash digests in your filenames. Making a new instance of `CachedProvider` will use a new `Hash` instance.
203
+
204
+ You can implement your own custom cache store by implementing the `[]` and `[]=` methods.
205
+
206
+ ```ruby
207
+ class MyRoadieMemcacheStore
208
+ def initialize(memcache)
209
+ @memcache = memcache
210
+ end
211
+
212
+ def [](path)
213
+ css = memcache.read("assets/#{path}/css")
214
+ if css
215
+ name = memcache.read("assets/#{path}/name") || "cached #{path}"
216
+ Roadie::Stylesheet.new(name, css)
217
+ end
218
+ end
219
+
220
+ def []=(path, stylesheet)
221
+ memcache.write("assets/#{path}/css", stylesheet.to_s)
222
+ memcache.write("assets/#{path}/name", stylesheet.name)
223
+ stylesheet # You need to return the set Stylesheet
224
+ end
225
+ end
226
+
227
+ document.external_asset_providers = Roadie::CachedProvider.new(
228
+ document.external_asset_providers,
229
+ MyRoadieMemcacheStore.new(MemcacheClient.instance)
230
+ )
231
+ ```
232
+
233
+ If you are using Rspec, you can test your implementation by using the shared examples for the "roadie cache store" role:
234
+
235
+ ```ruby
236
+ require "roadie/rspec"
237
+
238
+ describe MyRoadieMemcacheStore do
239
+ let(:memcache_client) { MemcacheClient.instance }
240
+ subject { MyRoadieMemcacheStore.new(memcache_client) }
241
+
242
+ it_behaves_like "roadie cache store" do
243
+ before { memcache_client.clear }
244
+ end
245
+ end
246
+ ```
247
+
248
+ #### `PathRewriterProvider` ####
249
+
250
+ With this provider, you can rewrite the paths that are searched in order to more easily support another provider. Examples could include rewriting absolute URLs into something that can be found on the filesystem, or to access internal hosts instead of external ones.
251
+
252
+ ```ruby
253
+ filesystem = Roadie::FilesystemProvider.new("assets")
254
+ document.asset_providers << Roadie::PathRewriterProvider.new(filesystem) do |path|
255
+ path.sub('stylesheets', 'css').downcase
256
+ end
257
+
258
+ document.external_asset_providers = Roadie::PathRewriterProvider.new(filesystem) do |url|
259
+ if url =~ /myapp\.com/
260
+ URI.parse(url).path.sub(%r{^/assets}, '')
261
+ else
262
+ url
263
+ end
264
+ end
265
+ ```
266
+
267
+ You can also wrap a list, for example to implement `external_asset_providers` by composing the normal `asset_providers`:
268
+
269
+ ```ruby
270
+ document.external_asset_providers =
271
+ Roadie::PathRewriterProvider.new(document.asset_providers) do |url|
272
+ URI.parse(url).path
273
+ end
157
274
  ```
158
275
 
159
276
  ### Writing your own provider ###
160
277
 
161
- Writing your own provider is also easy. You just need to provide:
162
- * `#find_stylesheet(name)`, returning either a `Roadie::Stylesheet` or nil.
278
+ Writing your own provider is also easy. You need to provide:
279
+ * `#find_stylesheet(name)`, returning either a `Roadie::Stylesheet` or `nil`.
163
280
  * `#find_stylesheet!(name)`, returning either a `Roadie::Stylesheet` or raising `Roadie::CssNotFound`.
164
281
 
165
282
  ```ruby
@@ -180,7 +297,11 @@ class UserAssetsProvider
180
297
  end
181
298
 
182
299
  # Instead of implementing #find_stylesheet!, you could also:
183
- # include Roadie::AssetProvider
300
+ # include Roadie::AssetProvider
301
+ # That will give you a default implementation without any error message. If
302
+ # you have multiple error cases, it's recommended that you implement
303
+ # #find_stylesheet! without #find_stylesheet and raise with an explanatory
304
+ # error message.
184
305
  end
185
306
 
186
307
  # Try to look for a user stylesheet first, then fall back to normal filesystem lookup.
@@ -203,19 +324,48 @@ describe MyOwnProvider do
203
324
  # Extra setup just for these tests:
204
325
  it_behaves_like "roadie asset provider", valid_name: "found.css", invalid_name: "does_not_exist.css" do
205
326
  subject { MyOwnProvider.new(...) }
206
- before { Whatever.stub ... }
327
+ before { stub_dependencies }
207
328
  end
208
329
  end
209
330
  ```
210
331
 
332
+ ### Keeping CSS that is impossible to inline
333
+
334
+ Some CSS is impossible to inline properly. `:hover` and `::after` comes to mind. Roadie tries its best to keep these around by injecting them inside a new `<style>` element in the `<head>`.
335
+
336
+ The problem here is that Roadie cannot possible adjust the specificity for you, so they will not apply the same way as they did before the styles were inlined.
337
+
338
+ Another caveat is that a lot of email clients does not support this (which is the entire point of inlining in the first place), so don't put anything important in here. Always handle the case of these selectors not being part of the email.
339
+
340
+ #### Specificity problems ####
341
+
342
+ Inlined styles will have much higher specificity than styles in a `<style>`. Here's an example:
343
+
344
+ ```html
345
+ <style>p:hover { color: blue; }</style>
346
+ <p style="color: green;">Hello world</p>
347
+ ```
348
+
349
+ When hovering over this `<p>`, the color will not change as the `color: green` rule takes precedence. You can get it to work by adding `!important` to the `:hover` rule.
350
+
351
+ It would be foolish to try to automatically inject `!important` on every rule automatically, so this is a manual process.
352
+
353
+ #### Turning it off ####
354
+
355
+ If you'd rather skip this and have the styles not possible to inline disappear, you can turn off this feature by setting the `keep_uninlinable_css` option to false.
356
+
357
+ ```ruby
358
+ document.keep_uninlinable_css = false
359
+ ```
360
+
211
361
  ### Callbacks ###
212
362
 
213
- Callbacks allow you to do custom work on documents before they are inlined. The Nokogiri document tree is passed to the callable:
363
+ Callbacks allow you to do custom work on documents before they are transformed. The Nokogiri document tree is passed to the callable along with the `Roadie::Document` instance:
214
364
 
215
365
  ```ruby
216
366
  class TrackNewsletterLinks
217
- def call(document)
218
- document.css("a").each { |link| fix_link(link) }
367
+ def call(dom, document)
368
+ dom.css("a").each { |link| fix_link(link) }
219
369
  end
220
370
 
221
371
  def fix_link(link)
@@ -224,7 +374,7 @@ class TrackNewsletterLinks
224
374
  end
225
375
  end
226
376
 
227
- document.before_transformation = { |document| logger.debug "Inlining document with title #{document.at_css('head > title').try(:text)}" }
377
+ document.before_transformation = proc { |dom, document| logger.debug "Inlining document with title #{dom.at_css('head > title').try(:text)}" }
228
378
  document.after_transformation = TrackNewsletterLinks.new
229
379
  ```
230
380
 
@@ -234,18 +384,16 @@ Build Status
234
384
  Tested with [Travis CI](http://travis-ci.org) using:
235
385
 
236
386
  * MRI 1.9.3
237
- * MRI 2.0.0
238
- * MRI 2.1.3
239
- * MRI 2.2.0
387
+ * MRI 2.0
388
+ * MRI 2.1
389
+ * MRI 2.2
240
390
  * JRuby (latest)
241
- * Rubinius >= 2.1 (experimental)
391
+ * Rubinius >= 2.1
242
392
 
243
393
  [(Build status)](http://travis-ci.org/#!/Mange/roadie)
244
394
 
245
395
  Let me know if you want any other VM supported officially.
246
396
 
247
- Rubinius support is experimental since it is currently hindered by a Rubinius bug that will probably be fixed shortly.
248
-
249
397
  ### Versioning ###
250
398
 
251
399
  This project follows [Semantic Versioning](http://semver.org/) and has been since version 1.0.0.
@@ -266,24 +414,15 @@ Another example is Nokogiri's lack of HTML5 support, so certain new element migh
266
414
  Roadie uses Nokogiri to parse the HTML of your email, so any C-like problems like segfaults are likely in that end. The best way to fix this is to first upgrade libxml2 on your system and then reinstall Nokogiri.
267
415
  Instructions on how to do this on most platforms, see [Nokogiri's official install guide](http://nokogiri.org/tutorials/installing_nokogiri.html).
268
416
 
269
- ### My `:hover` selectors don't work. How can I fix them? ###
270
-
271
- Put any styles using `:hover` in a separate stylesheet and make sure it is ignored. (See `data-roadie-ignore` under [Referenced Stylesheets](https://github.com/Mange/roadie/blob/master/README.md#referenced-stylesheets) above)
272
-
273
- ### My `@media` queries don't work. How can I fix them? ###
274
-
275
- Put any styles using them in a separate stylesheet and make sure it is ignored. (See `data-roadie-ignore` under [Referenced Stylesheets](https://github.com/Mange/roadie/blob/master/README.md#referenced-stylesheets) above)
276
-
277
- ### My vendor-specific styles don't work. How can I fix them? ###
417
+ ### What happened to my `@keyframes`?
278
418
 
279
- Put any styles using them in a separate stylesheet and make sure it is ignored. (See `data-roadie-ignore` under [Referenced Stylesheets](https://github.com/Mange/roadie/blob/master/README.md#referenced-stylesheets) above)
419
+ The CSS Parser used in Roadie does not handle keyframes. I don't think any email clients do either, but if you want to keep on trying you can add them manually to a `<style>` element (or a separate referenced stylesheet) and [tell Roadie not to touch them](#referenced-stylesheets).
280
420
 
281
421
  Documentation
282
422
  -------------
283
423
 
284
424
  * [Online documentation for gem](https://www.omniref.com/ruby/gems/roadie)
285
425
  * [Online documentation for master](https://www.omniref.com/github/Mange/roadie)
286
- * [Online documentation for Roadie 2.4.3](https://www.omniref.com/ruby/gems/roadie/2.4.3)
287
426
  * [Changelog](https://github.com/Mange/roadie/blob/master/Changelog.md)
288
427
 
289
428
  Running specs
@@ -303,6 +442,7 @@ Major contributors to Roadie:
303
442
 
304
443
  * [Arttu Tervo (arttu)](https://github.com/arttu) - Original Asset pipeline support
305
444
  * [Ryunosuke SATO (tricknotes)](https://github.com/tricknotes) - Initial Rails 4 support
445
+ * [Leung Ho Kuen (PikachuEXE)](https://github.com/PikachuEXE) - A lot of bug reporting and triaging.
306
446
 
307
447
  You can [see all contributors](https://github.com/Mange/roadie/contributors) on GitHub.
308
448