roadie 2.0.0 → 2.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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