roadie 2.0.0 → 2.1.0.pre1
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 +1 -0
- data/Changelog.md +12 -1
- data/Gemfile.lock +49 -30
- data/README.md +39 -9
- data/lib/roadie.rb +45 -26
- data/lib/roadie/action_mailer_extensions.rb +13 -8
- data/lib/roadie/asset_pipeline_provider.rb +28 -0
- data/lib/roadie/asset_provider.rb +62 -0
- data/lib/roadie/filesystem_provider.rb +74 -0
- data/lib/roadie/inliner.rb +16 -16
- data/lib/roadie/railtie.rb +22 -0
- data/lib/roadie/version.rb +1 -1
- data/roadie.gemspec +1 -0
- data/spec/fixtures/public/stylesheets/integration.css +10 -0
- data/spec/integration_spec.rb +62 -47
- data/spec/lib/roadie/action_mailer_extensions_spec.rb +91 -75
- data/spec/lib/roadie/asset_pipeline_provider_spec.rb +65 -0
- data/spec/lib/roadie/filesystem_provider_spec.rb +94 -0
- data/spec/lib/roadie/inliner_spec.rb +30 -5
- data/spec/lib/roadie_spec.rb +31 -16
- data/spec/shared_examples/asset_provider_examples.rb +11 -0
- data/spec/spec_helper.rb +11 -7
- metadata +30 -19
- data/spec/fixtures/app/assets/stylesheets/bar.css +0 -1
- data/spec/fixtures/app/assets/stylesheets/foo.css +0 -1
- data/spec/fixtures/app/assets/stylesheets/green_paragraphs.css +0 -1
- data/spec/fixtures/app/assets/stylesheets/large_purple_paragraphs.css +0 -1
- data/spec/fixtures/app/assets/stylesheets/subdirectory/findme.css +0 -1
- data/spec/fixtures/app/assets/stylesheets/subdirectory/red_paragraphs.css +0 -1
data/.gitignore
CHANGED
data/Changelog.md
CHANGED
@@ -1,9 +1,20 @@
|
|
1
1
|
### dev
|
2
2
|
|
3
|
-
[full changelog](https://github.com/Mange/roadie/compare/v2.0.
|
3
|
+
[full changelog](https://github.com/Mange/roadie/compare/v2.1.0.pre1...master)
|
4
4
|
|
5
5
|
* Nothing yet
|
6
6
|
|
7
|
+
### 2.1.0.pre1
|
8
|
+
|
9
|
+
[full changelog](https://github.com/Mange/roadie/compare/v2.0.0...v2.1.0.pre1)
|
10
|
+
|
11
|
+
* Enhancements:
|
12
|
+
* Support normal filesystem instead of only Asset pipeline
|
13
|
+
* Enable users to create their own way of fetching CSS
|
14
|
+
* Improve test coverage a bit
|
15
|
+
* Use a railtie to hook into Rails
|
16
|
+
* Use real Rails for testing integration
|
17
|
+
|
7
18
|
### 2.0.0
|
8
19
|
|
9
20
|
[full changelog](https://github.com/Mange/roadie/compare/v1.1.3...v2.0.0)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
roadie (2.0.
|
4
|
+
roadie (2.1.0.pre1)
|
5
5
|
actionmailer (~> 3.1.0)
|
6
6
|
css_parser
|
7
7
|
nokogiri (>= 1.4.4)
|
@@ -10,27 +10,36 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: http://rubygems.org/
|
12
12
|
specs:
|
13
|
-
actionmailer (3.1.
|
14
|
-
actionpack (= 3.1.
|
13
|
+
actionmailer (3.1.3)
|
14
|
+
actionpack (= 3.1.3)
|
15
15
|
mail (~> 2.3.0)
|
16
|
-
actionpack (3.1.
|
17
|
-
activemodel (= 3.1.
|
18
|
-
activesupport (= 3.1.
|
16
|
+
actionpack (3.1.3)
|
17
|
+
activemodel (= 3.1.3)
|
18
|
+
activesupport (= 3.1.3)
|
19
19
|
builder (~> 3.0.0)
|
20
20
|
erubis (~> 2.7.0)
|
21
21
|
i18n (~> 0.6)
|
22
|
-
rack (~> 1.3.
|
22
|
+
rack (~> 1.3.5)
|
23
23
|
rack-cache (~> 1.1)
|
24
24
|
rack-mount (~> 0.8.2)
|
25
25
|
rack-test (~> 0.6.1)
|
26
|
-
sprockets (~> 2.0.
|
27
|
-
activemodel (3.1.
|
28
|
-
activesupport (= 3.1.
|
26
|
+
sprockets (~> 2.0.3)
|
27
|
+
activemodel (3.1.3)
|
28
|
+
activesupport (= 3.1.3)
|
29
29
|
builder (~> 3.0.0)
|
30
30
|
i18n (~> 0.6)
|
31
|
-
|
31
|
+
activerecord (3.1.3)
|
32
|
+
activemodel (= 3.1.3)
|
33
|
+
activesupport (= 3.1.3)
|
34
|
+
arel (~> 2.2.1)
|
35
|
+
tzinfo (~> 0.3.29)
|
36
|
+
activeresource (3.1.3)
|
37
|
+
activemodel (= 3.1.3)
|
38
|
+
activesupport (= 3.1.3)
|
39
|
+
activesupport (3.1.3)
|
32
40
|
multi_json (~> 1.0)
|
33
41
|
addressable (2.2.6)
|
42
|
+
arel (2.2.1)
|
34
43
|
builder (3.0.0)
|
35
44
|
css_parser (1.2.5)
|
36
45
|
addressable
|
@@ -43,11 +52,11 @@ GEM
|
|
43
52
|
i18n (>= 0.4.0)
|
44
53
|
mime-types (~> 1.16)
|
45
54
|
treetop (~> 1.4.8)
|
46
|
-
mime-types (1.
|
55
|
+
mime-types (1.17.2)
|
47
56
|
multi_json (1.0.3)
|
48
57
|
nokogiri (1.5.0)
|
49
|
-
polyglot (0.3.
|
50
|
-
rack (1.3.
|
58
|
+
polyglot (0.3.3)
|
59
|
+
rack (1.3.5)
|
51
60
|
rack-cache (1.1)
|
52
61
|
rack (>= 0.4)
|
53
62
|
rack-mount (0.8.3)
|
@@ -56,42 +65,52 @@ GEM
|
|
56
65
|
rack
|
57
66
|
rack-test (0.6.1)
|
58
67
|
rack (>= 1.0)
|
59
|
-
|
60
|
-
|
61
|
-
|
68
|
+
rails (3.1.3)
|
69
|
+
actionmailer (= 3.1.3)
|
70
|
+
actionpack (= 3.1.3)
|
71
|
+
activerecord (= 3.1.3)
|
72
|
+
activeresource (= 3.1.3)
|
73
|
+
activesupport (= 3.1.3)
|
74
|
+
bundler (~> 1.0)
|
75
|
+
railties (= 3.1.3)
|
76
|
+
railties (3.1.3)
|
77
|
+
actionpack (= 3.1.3)
|
78
|
+
activesupport (= 3.1.3)
|
62
79
|
rack-ssl (~> 1.3.2)
|
63
80
|
rake (>= 0.8.7)
|
64
81
|
rdoc (~> 3.4)
|
65
82
|
thor (~> 0.14.6)
|
66
|
-
rake (0.9.2)
|
67
|
-
rdoc (3.
|
83
|
+
rake (0.9.2.2)
|
84
|
+
rdoc (3.11)
|
68
85
|
json (~> 1.4)
|
69
|
-
rspec (2.
|
70
|
-
rspec-core (~> 2.
|
71
|
-
rspec-expectations (~> 2.
|
72
|
-
rspec-mocks (~> 2.
|
73
|
-
rspec-core (2.
|
74
|
-
rspec-expectations (2.
|
86
|
+
rspec (2.7.0)
|
87
|
+
rspec-core (~> 2.7.0)
|
88
|
+
rspec-expectations (~> 2.7.0)
|
89
|
+
rspec-mocks (~> 2.7.0)
|
90
|
+
rspec-core (2.7.1)
|
91
|
+
rspec-expectations (2.7.0)
|
75
92
|
diff-lcs (~> 1.1.2)
|
76
|
-
rspec-mocks (2.
|
77
|
-
rspec-rails (2.
|
93
|
+
rspec-mocks (2.7.0)
|
94
|
+
rspec-rails (2.7.0)
|
78
95
|
actionpack (~> 3.0)
|
79
96
|
activesupport (~> 3.0)
|
80
97
|
railties (~> 3.0)
|
81
|
-
rspec (~> 2.
|
82
|
-
sprockets (2.0.
|
98
|
+
rspec (~> 2.7.0)
|
99
|
+
sprockets (2.0.3)
|
83
100
|
hike (~> 1.2)
|
84
101
|
rack (~> 1.0)
|
85
|
-
tilt (
|
102
|
+
tilt (!= 1.3.0, ~> 1.1)
|
86
103
|
thor (0.14.6)
|
87
104
|
tilt (1.3.3)
|
88
105
|
treetop (1.4.10)
|
89
106
|
polyglot
|
90
107
|
polyglot (>= 0.3.1)
|
108
|
+
tzinfo (0.3.31)
|
91
109
|
|
92
110
|
PLATFORMS
|
93
111
|
ruby
|
94
112
|
|
95
113
|
DEPENDENCIES
|
114
|
+
rails
|
96
115
|
roadie!
|
97
116
|
rspec-rails (>= 2.0.0)
|
data/README.md
CHANGED
@@ -36,15 +36,11 @@ Let me know if you want any other combination supported officially
|
|
36
36
|
|
37
37
|
This project follows [Semtantic Versioning](http://semver.org/) and has been since version 1.0.0.
|
38
38
|
|
39
|
-
Two branches are currently in place:
|
40
|
-
* 2.x - Rails 3.1
|
41
|
-
* 1.x - Rails 3.0
|
42
|
-
|
43
|
-
The 1.x branch will continue to be supported until it is deemed unnecessary by the author, but properly made pull requests will be accepted indefinitely.
|
44
|
-
|
45
39
|
Features
|
46
40
|
--------
|
47
41
|
|
42
|
+
* Supports Rails' Asset Pipeline and simple filesystem access out of the box
|
43
|
+
* You can add support for CSS from any place inside your apps
|
48
44
|
* Writes CSS styles inline
|
49
45
|
* Respects `!important` styles
|
50
46
|
* Does not overwrite styles already present in the `style` attribute of tags
|
@@ -58,7 +54,7 @@ Features
|
|
58
54
|
|
59
55
|
### What about Sass / Less? ###
|
60
56
|
|
61
|
-
Sass is supported
|
57
|
+
Sass is supported as long as the stylesheets are generated and stored in the asset directories. You are recommended to add a deploy task that generates the stylesheets to make sure that they are present at all times on the machine generating the emails.
|
62
58
|
|
63
59
|
Install
|
64
60
|
-------
|
@@ -69,10 +65,21 @@ Add the gem to Rails' Gemfile
|
|
69
65
|
gem 'roadie'
|
70
66
|
```
|
71
67
|
|
68
|
+
Configuring
|
69
|
+
-----------
|
70
|
+
|
71
|
+
Roadie listens to the following options (set in `Application.rb` or in your environment's configuration files:
|
72
|
+
|
73
|
+
* `config.action_mailer.default_url_options` - Used for making URLs absolute
|
74
|
+
* `config.assets.enabled` - If the asset pipeline is turned off, Roadie will default to searching for assets in `public/stylesheets`
|
75
|
+
* `config.roadie.provider` - Set the provider manually, ignoring all other options. Use for advanced cases, or when you have non-default paths or other options.
|
76
|
+
|
72
77
|
Usage
|
73
78
|
-----
|
74
79
|
|
75
|
-
|
80
|
+
Just add a `<link rel="stylesheet" />` or `<style type="text/css"></style>` element inside your email layout and it will be inlined automatically.
|
81
|
+
|
82
|
+
You can also specify the `:css` option to mailer to have it inlined automatically without you having to make a layout:
|
76
83
|
|
77
84
|
```ruby
|
78
85
|
class Notifier < ActionMailer::Base
|
@@ -127,6 +134,29 @@ If the `link` tag uses an absolute URL to the stylesheet, it will not be inlined
|
|
127
134
|
</head>
|
128
135
|
```
|
129
136
|
|
137
|
+
Writing your own provider
|
138
|
+
-------------------------
|
139
|
+
|
140
|
+
A provider handles searching CSS files for you. Cou can easily create your own provider for your specific app by subclassing `Roadie::AssetProvider`. See the API documentation for information about how to build them.
|
141
|
+
|
142
|
+
Example Subclassing the `AssetPipelineProvider`:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
# application.rb
|
146
|
+
config.roadie.provider = UserAssetsProvider.new
|
147
|
+
|
148
|
+
# lib/user_assets_provider.rb
|
149
|
+
class UserAssetsProvider < Roadie::AssetPipelineProvider
|
150
|
+
def find(name)
|
151
|
+
super
|
152
|
+
rescue CSSFileNotFound
|
153
|
+
user = User.find_by_name(name)
|
154
|
+
raise unless user
|
155
|
+
user.custom_css
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
130
160
|
Bugs / TODO
|
131
161
|
-----------
|
132
162
|
|
@@ -154,7 +184,7 @@ History and contributors
|
|
154
184
|
|
155
185
|
Major contributors to Roadie:
|
156
186
|
|
157
|
-
* [Arttu Tervo (arttu)](https://github.com/arttu) - Asset pipeline support
|
187
|
+
* [Arttu Tervo (arttu)](https://github.com/arttu) - Original Asset pipeline support
|
158
188
|
|
159
189
|
You can [see all contributors](https://github.com/Mange/roadie/contributors) on GitHub.
|
160
190
|
|
data/lib/roadie.rb
CHANGED
@@ -1,37 +1,56 @@
|
|
1
1
|
module Roadie
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
class << self
|
3
|
+
# Shortcut for inlining CSS using {Inliner}
|
4
|
+
# @see Inliner
|
5
|
+
def inline_css(*args)
|
6
|
+
Roadie::Inliner.new(*args).execute
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# Shortcut to Rails.application
|
10
|
+
def app
|
11
|
+
Rails.application
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns all available providers
|
15
|
+
def providers
|
16
|
+
[AssetPipelineProvider, FilesystemProvider]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the active provider
|
20
|
+
#
|
21
|
+
# If no provider has been configured a new provider will be instantiated
|
22
|
+
# depending on if the asset pipeline is enabled or not.
|
23
|
+
#
|
24
|
+
# If +config.assets.enabled+ is +true+, the {AssetPipelineProvider} will be used
|
25
|
+
# while {FilesystemProvider} will be used if it is set to +false+.
|
26
|
+
#
|
27
|
+
# @see AssetPipelineProvider
|
28
|
+
# @see FilesystemProvider
|
29
|
+
def current_provider
|
30
|
+
return config.roadie.provider if config.roadie.provider
|
12
31
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
assets[file].to_s.strip
|
25
|
-
end.join("\n")
|
32
|
+
if config.assets.enabled
|
33
|
+
AssetPipelineProvider.new
|
34
|
+
else
|
35
|
+
FilesystemProvider.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def config
|
41
|
+
Roadie.app.config
|
42
|
+
end
|
26
43
|
end
|
27
44
|
end
|
28
45
|
|
29
46
|
require 'roadie/version'
|
30
47
|
require 'roadie/css_file_not_found'
|
31
48
|
require 'roadie/style_declaration'
|
32
|
-
require 'roadie/inliner'
|
33
49
|
|
34
|
-
require '
|
35
|
-
require 'roadie/
|
50
|
+
require 'roadie/asset_provider'
|
51
|
+
require 'roadie/asset_pipeline_provider'
|
52
|
+
require 'roadie/filesystem_provider'
|
53
|
+
|
54
|
+
require 'roadie/inliner'
|
36
55
|
|
37
|
-
|
56
|
+
require 'roadie/railtie' if defined?(Rails)
|
@@ -16,7 +16,12 @@ module Roadie
|
|
16
16
|
|
17
17
|
protected
|
18
18
|
def mail_with_inline_styles(headers = {}, &block)
|
19
|
-
|
19
|
+
if headers.has_key?(:css)
|
20
|
+
@targets = headers[:css]
|
21
|
+
else
|
22
|
+
@targets = default_css_targets
|
23
|
+
end
|
24
|
+
|
20
25
|
mail_without_inline_styles(headers, &block).tap do |email|
|
21
26
|
email.header.fields.delete_if { |field| field.name == 'css' }
|
22
27
|
end
|
@@ -28,25 +33,25 @@ module Roadie
|
|
28
33
|
end
|
29
34
|
|
30
35
|
private
|
36
|
+
def default_css_targets
|
37
|
+
self.class.default[:css]
|
38
|
+
end
|
39
|
+
|
31
40
|
def url_options
|
32
41
|
Rails.application.config.action_mailer.default_url_options
|
33
42
|
end
|
34
43
|
|
35
44
|
def inline_style_response(response)
|
36
45
|
if response[:content_type] == 'text/html'
|
37
|
-
response.merge :body => Roadie.inline_css(
|
46
|
+
response.merge :body => Roadie.inline_css(Roadie.current_provider, css_targets, response[:body], url_options)
|
38
47
|
else
|
39
48
|
response
|
40
49
|
end
|
41
50
|
end
|
42
51
|
|
43
52
|
def css_targets
|
44
|
-
return
|
45
|
-
Array(@
|
46
|
-
end
|
47
|
-
|
48
|
-
def css_rules
|
49
|
-
@css_rules ||= Roadie.load_css(css_targets) if css_targets.present?
|
53
|
+
return [] unless @targets
|
54
|
+
Array.wrap(@targets || []).map { |target| target.to_s }
|
50
55
|
end
|
51
56
|
end
|
52
57
|
end
|
@@ -0,0 +1,28 @@
|
|
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
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Roadie
|
2
|
+
# @abstract Subclass to create your own providers
|
3
|
+
class AssetProvider
|
4
|
+
# The prefix is whatever is prepended to your stylesheets when referenced inside markup.
|
5
|
+
#
|
6
|
+
# The prefix is stripped away from any URLs before they are looked up in {#find}:
|
7
|
+
# find("/assets/posts/comment.css")
|
8
|
+
# # Same as: (if prefix == "/assets"
|
9
|
+
# find("posts/comment.css")
|
10
|
+
attr_reader :prefix
|
11
|
+
|
12
|
+
# @param [String] prefix Prefix of assets as seen from the browser
|
13
|
+
# @see #prefix
|
14
|
+
def initialize(prefix = "/assets")
|
15
|
+
@prefix = prefix
|
16
|
+
@quoted_prefix = prepare_prefix(prefix)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Iterates all the passed elements and calls {#find} on them, joining the results with a newline.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# MyProvider.all("first", "second.css", :third)
|
23
|
+
#
|
24
|
+
# @param [Array] files The target files to be loaded together
|
25
|
+
# @raise [CSSFileNotFound] In case any of the elements is not found
|
26
|
+
# @see #find
|
27
|
+
def all(files)
|
28
|
+
files.map { |file| find(file) }.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
# @abstract Implement in your own subclass
|
32
|
+
#
|
33
|
+
# Return the CSS contents of the file specified. A provider should not care about
|
34
|
+
# the +.css+ extension; it can, however, behave differently if it's passed or not.
|
35
|
+
#
|
36
|
+
# If the asset cannot be found, the method should raise {CSSFileNotFound}.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# MyProvider.find("mystyle")
|
40
|
+
# MyProvider.find("mystyle.css")
|
41
|
+
# MyProvider.find(:mystyle)
|
42
|
+
#
|
43
|
+
# @param [String, Symbol] name Name of the file requested
|
44
|
+
# @raise [CSSFileNotFound] In case any of the elements is not found
|
45
|
+
def find(name)
|
46
|
+
raise "Not implemented"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def prepare_prefix(prefix)
|
51
|
+
if prefix =~ /^\//
|
52
|
+
"/?#{Regexp.quote(prefix[1, prefix.size])}"
|
53
|
+
else
|
54
|
+
Regexp.quote(prefix)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_prefix(name)
|
59
|
+
name.sub(/^#{@quoted_prefix}\/?/, '').sub(%r{^/}, '').gsub(%r{//+}, '/')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|