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 CHANGED
@@ -8,3 +8,4 @@ pkg
8
8
  .rvmrc
9
9
 
10
10
  gemfiles/*.lock
11
+ doc
@@ -1,9 +1,20 @@
1
1
  ### dev
2
2
 
3
- [full changelog](https://github.com/Mange/roadie/compare/v2.0.0...master)
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)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- roadie (2.0.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.1)
14
- actionpack (= 3.1.1)
13
+ actionmailer (3.1.3)
14
+ actionpack (= 3.1.3)
15
15
  mail (~> 2.3.0)
16
- actionpack (3.1.1)
17
- activemodel (= 3.1.1)
18
- activesupport (= 3.1.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.2)
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.2)
27
- activemodel (3.1.1)
28
- activesupport (= 3.1.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
- activesupport (3.1.1)
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.16)
55
+ mime-types (1.17.2)
47
56
  multi_json (1.0.3)
48
57
  nokogiri (1.5.0)
49
- polyglot (0.3.2)
50
- rack (1.3.4)
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
- railties (3.1.1)
60
- actionpack (= 3.1.1)
61
- activesupport (= 3.1.1)
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.10)
83
+ rake (0.9.2.2)
84
+ rdoc (3.11)
68
85
  json (~> 1.4)
69
- rspec (2.6.0)
70
- rspec-core (~> 2.6.0)
71
- rspec-expectations (~> 2.6.0)
72
- rspec-mocks (~> 2.6.0)
73
- rspec-core (2.6.4)
74
- rspec-expectations (2.6.0)
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.6.0)
77
- rspec-rails (2.6.1)
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.6.0)
82
- sprockets (2.0.2)
98
+ rspec (~> 2.7.0)
99
+ sprockets (2.0.3)
83
100
  hike (~> 1.2)
84
101
  rack (~> 1.0)
85
- tilt (~> 1.1, != 1.3.0)
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 "by accident" 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.
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
- Simply specify the `:css` option to mailer:
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
 
@@ -1,37 +1,56 @@
1
1
  module Roadie
2
- # Shortcut for inlining CSS using {Inliner}
3
- # @see Inliner
4
- def self.inline_css(*args)
5
- Roadie::Inliner.new(*args).execute
6
- end
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
- # Shortcut to Rails.application.assets
9
- def self.assets
10
- Rails.application.assets
11
- end
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
- # Tries to load the CSS "names" specified in the +targets+ parameter using the Rails asset pipeline.
14
- #
15
- # @example
16
- # Roadie.load_css(%w[application newsletter])
17
- #
18
- # @param [Array<String|Symbol>] targets Stylesheet names
19
- # @return [String] The combined contents of the CSS files
20
- # @raise [CSSFileNotFound] When a target cannot be found from Rails assets
21
- def self.load_css(targets)
22
- targets.map do |file|
23
- raise CSSFileNotFound, file unless assets[file]
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 'action_mailer'
35
- require 'roadie/action_mailer_extensions'
50
+ require 'roadie/asset_provider'
51
+ require 'roadie/asset_pipeline_provider'
52
+ require 'roadie/filesystem_provider'
53
+
54
+ require 'roadie/inliner'
36
55
 
37
- ActionMailer::Base.send :include, Roadie::ActionMailerExtensions
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
- @inline_style_css_targets = headers[:css]
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(css_rules, response[:body], url_options)
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 nil if @inline_style_css_targets == false
45
- Array(@inline_style_css_targets || self.class.default[:css] || []).map { |target| target.to_s }
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