inline-style 0.4.2 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in inline-style.gemspec
4
+ gemspec
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ inline-style (0.4.6)
5
+ css_parser
6
+ maca-fork-csspool
7
+ nokogiri
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (3.0.4)
13
+ css_parser (1.1.5)
14
+ diff-lcs (1.1.2)
15
+ ffi (1.0.6)
16
+ rake (>= 0.8.7)
17
+ i18n (0.5.0)
18
+ maca-fork-csspool (2.0.2)
19
+ ffi
20
+ mail (2.2.15)
21
+ activesupport (>= 2.3.6)
22
+ i18n (>= 0.4.0)
23
+ mime-types (~> 1.16)
24
+ treetop (~> 1.4.8)
25
+ mime-types (1.16)
26
+ nokogiri (1.4.4)
27
+ polyglot (0.3.1)
28
+ rack (1.2.1)
29
+ rake (0.8.7)
30
+ rspec (2.4.0)
31
+ rspec-core (~> 2.4.0)
32
+ rspec-expectations (~> 2.4.0)
33
+ rspec-mocks (~> 2.4.0)
34
+ rspec-core (2.4.0)
35
+ rspec-expectations (2.4.0)
36
+ diff-lcs (~> 1.1.2)
37
+ rspec-mocks (2.4.0)
38
+ treetop (1.4.9)
39
+ polyglot (>= 0.3.1)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ css_parser
46
+ inline-style!
47
+ maca-fork-csspool
48
+ mail
49
+ nokogiri
50
+ rack
51
+ rspec
52
+ rspec-core
@@ -1,12 +1,19 @@
1
1
  History.txt
2
2
  Manifest.txt
3
- README.rdoc
3
+ README.txt
4
4
  Rakefile
5
5
  example.rb
6
+ inline-style.gemspec
6
7
  lib/inline-style.rb
8
+ lib/inline-style/css_parsers.rb
9
+ lib/inline-style/css_parsers/css_parser.rb
10
+ lib/inline-style/css_parsers/csspool.rb
11
+ lib/inline-style/mail/interceptor.rb
7
12
  lib/inline-style/rack/middleware.rb
8
13
  spec/as_middleware_spec.rb
9
14
  spec/css_inlining_spec.rb
15
+ spec/css_parsers_spec.rb
16
+ spec/factory_spec.rb
10
17
  spec/fixtures/all.css
11
18
  spec/fixtures/boletin.html
12
19
  spec/fixtures/box-model.html
@@ -15,4 +22,5 @@ spec/fixtures/none.css
15
22
  spec/fixtures/print.css
16
23
  spec/fixtures/selectors.html
17
24
  spec/fixtures/style.css
25
+ spec/interceptor_spec.rb
18
26
  spec/spec_helper.rb
@@ -10,6 +10,8 @@ each refered element taking selector specificity and declarator order.
10
10
  Useful for html email: some clients (gmail, et all) won't render non inline styles.
11
11
 
12
12
  * Includes a Rack middleware for using with Rails, Sinatra, etc...
13
+ * Includes a interceptor for the mail gem which allows automatic
14
+ inline processing for both mail as well as ActionMailer.
13
15
  * It takes into account selector specificity.
14
16
 
15
17
  == USAGE
@@ -92,12 +94,23 @@ Will become:
92
94
 
93
95
  # Restrict processing to some routes:
94
96
  use InlineStyle::Rack::Middleware, :paths => [%r(/mails/.*), "/somepath"]
97
+
98
+ == MAIL INTERCEPTOR
99
+
100
+ If using the mail library the following code will work:
101
+
102
+ Mail.register_interceptor \
103
+ InlineStyle::Mail::Interceptor.new(:stylesheets_path => 'public')
104
+
105
+ If using ActionMailer (which wraps mail):
106
+
107
+ ActionMailer::Base.register_interceptor \
108
+ InlineStyle::Mail::Interceptor.new(:stylesheets_path => 'public')
95
109
 
96
110
  == ISSUES:
97
111
 
98
112
  * It supports pseudo classes according to W3C specification for style in style attribute: http://www.w3.org/TR/css-style-attr, although browsers
99
113
  doesn't seems to.
100
- * It strips any numeric character (Rails may add) at the end of the stylesheet file name, anyway stylesheets should end with .css extension
101
114
 
102
115
  == REQUIREMENTS:
103
116
 
@@ -130,4 +143,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
130
143
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
131
144
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
132
145
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
133
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
146
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,26 +1,9 @@
1
- require 'rubygems' unless ENV['NO_RUBYGEMS']
2
- %w[rake rake/clean fileutils newgem rubigen].each { |f| require f }
3
- require File.dirname(__FILE__) + '/lib/inline-style'
4
-
5
- $hoe = Hoe.new('inline-style', InlineStyle::VERSION) do |p|
6
- p.developer('Macario Ortega', 'macarui@gmail.com')
7
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
8
- p.rubyforge_name = p.name
9
- p.extra_deps = [
10
- ['nokogiri','>= 1.3.3'],
11
- ['maca-fork-csspool', '>= 2.0.2']
12
- ]
13
- p.extra_dev_deps = [
14
- ['newgem', ">= #{::Newgem::VERSION}"]
15
- ]
16
-
17
- p.clean_globs |= %w[**/.DS_Store tmp *.log]
18
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
19
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
20
- p.rsync_args = '-av --delete --ignore-errors'
21
- end
22
-
23
- require 'newgem/tasks'
24
- Dir['tasks/**/*.rake'].each { |t| load t }
25
-
26
-
1
+ require 'bundler'
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => [:spec]
5
+
6
+ desc "Run specs"
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "inline-style/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "inline-style"
7
+ s.version = Inline::Style::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Macario Ortega", "Eric Anderson"]
10
+ s.email = ["macarui@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Inlines CSS for html email delivery}
13
+ s.description = %q{Inlines CSS for html email delivery}
14
+
15
+ # s.rubyforge_project = "inline-style"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'rack'
24
+ s.add_development_dependency 'rspec-core'
25
+ s.add_development_dependency 'mail'
26
+
27
+ s.add_dependency 'nokogiri'
28
+ s.add_dependency 'css_parser'
29
+ s.add_dependency 'maca-fork-csspool'
30
+ end
@@ -1,14 +1,11 @@
1
1
  require 'nokogiri'
2
2
  require 'open-uri'
3
3
 
4
- gem 'maca-fork-csspool'
5
- require 'csspool'
6
-
4
+ require "#{ File.dirname( __FILE__ ) }/inline-style/css_parsers"
7
5
  require "#{ File.dirname( __FILE__ ) }/inline-style/rack/middleware"
6
+ require "#{ File.dirname( __FILE__ ) }/inline-style/mail/interceptor"
8
7
 
9
8
  module InlineStyle
10
- VERSION = '0.4.2'
11
-
12
9
  # Options:
13
10
  # +:stylesheets_path+
14
11
  # Stylesheets root path, can also be a URL
@@ -27,41 +24,44 @@ module InlineStyle
27
24
  css = extract_css html, stylesheets_path
28
25
  nodes = {}
29
26
 
30
- css.rule_sets.each do |rule_set|
31
- rule_set.selectors.each do |selector|
32
- css_selector = selector.to_s
27
+ css.each_rule_set do |rule_set|
28
+ rule_set.each_selector do |css_selector, declarations, specificity|
29
+ orig_selector = css_selector.dup
33
30
  css_selector = "#{ 'body ' unless /^body/ === css_selector }#{ css_selector.gsub /:.*/, '' }"
34
31
 
35
32
  html.css(css_selector).each do |node|
36
33
  nodes[node] ||= []
37
- nodes[node].push selector
34
+ nodes[node].push [css_selector, declarations, specificity, orig_selector]
38
35
 
39
36
  next unless node['style']
40
37
 
41
38
  path = node.css_path
42
39
  path << "##{ node['id'] }" if node['id']
43
40
  path << ".#{ node['class'].scan(/\S+/).join('.') }" if node['class']
44
-
45
- CSSPool.CSS("#{ path }{#{ node['style'] }}").rule_sets.each{ |rule| nodes[node].push *rule.selectors }
41
+
42
+ InlineStyle::CssParsers.parser.new("#{ path }{#{ node['style'] }}").each_rule_set do |rule|
43
+ rule.each_selector do |css_selector_inner, declarations_inner, specificity_inner|
44
+ nodes[node].push [css_selector_inner, declarations_inner, specificity_inner, css_selector_inner]
45
+ end
46
+ end
46
47
  end
47
48
  end
48
49
  end
49
50
 
50
51
  nodes.each_pair do |node, style|
51
- style = style.sort_by{ |sel| "#{ sel.specificity }%03d" % style.index(sel) }
52
- sets = style.partition{ |sel| not /:\w+/ === sel.to_s }
52
+ style = style.sort_by{ |(sel, dec, spe, orig)| "#{ spe }%03d" % style.index([sel, dec, spe, orig]) }
53
+ sets = style.partition{ |(sel, dec, spe, orig)| not /:\w+/ === orig }
53
54
 
54
55
  sets.pop if not pseudo or sets.last.empty?
55
56
 
56
57
  node['style'] = sets.collect do |selectors|
57
58
  index = sets.index selectors
58
59
 
59
- set = selectors.map do |selector|
60
- declarations = selector.declarations.map{ |d| d.to_css.squeeze(' ') }.join
61
- index == 0 ? declarations : "\n#{ selector.to_s.gsub /\w(?=:)/, '' } {#{ declarations }}"
60
+ set = selectors.map do |(css_selector, declarations, specificity, orig_selector)|
61
+ index == 0 ? declarations : "\n#{ orig_selector.gsub /\w(?=:)/, '' } {#{ declarations }}"
62
62
  end
63
63
 
64
- index == 0 && sets.size > 1 ? "{#{ set }}" : set.join
64
+ index == 0 && sets.size > 1 ? "{#{ set }}" : set.collect(&:strip).join(' ')
65
65
  end.join.strip
66
66
  end
67
67
 
@@ -70,8 +70,8 @@ module InlineStyle
70
70
 
71
71
  # Returns CSSPool::Document
72
72
  def self.extract_css html, stylesheets_path = ''
73
- CSSPool.CSS html.css('style, link').collect { |e|
74
- next unless e['media'].nil? or ['screen', 'all'].include? e['media']
73
+ InlineStyle::CssParsers.parser.new html.css('style, link').collect { |e|
74
+ next unless e['media'].nil? || ['screen', 'all'].include?(e['media'])
75
75
  next(e.remove and e.content) if e.name == 'style'
76
76
  next unless e['rel'] == 'stylesheet'
77
77
  e.remove
@@ -80,4 +80,4 @@ module InlineStyle
80
80
  open(uri).read rescue nil
81
81
  }.join("\n")
82
82
  end
83
- end
83
+ end
@@ -0,0 +1,21 @@
1
+ module InlineStyle
2
+
3
+ # A factory for returning a configured CSS parser. Defaults to
4
+ # :css_parser if not specified. Will also use ENV['CSS_PARSER'].
5
+ module CssParsers
6
+
7
+ # Allows you to specify the CSS parser to use.
8
+ def self.parser=(parser)
9
+ @parser = nil
10
+ @parser_name = parser
11
+ end
12
+
13
+ def self.parser
14
+ return @parser if @parser
15
+ @parser_name = ENV['CSS_PARSER'] || :css_parser unless @parser_name
16
+ require "inline-style/css_parsers/#{@parser_name}"
17
+ @parser = const_get(@parser_name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,56 @@
1
+ require 'css_parser'
2
+
3
+ module InlineStyle::CssParsers
4
+ class CssParser
5
+
6
+ def initialize(css_code)
7
+ @parser = ::CssParser::Parser.new
8
+ @parser.add_block! css_code
9
+ end
10
+
11
+ def each_rule_set(&blk)
12
+ @parser.each_rule_set do |rule_set|
13
+ yield Ruleset.new(rule_set)
14
+ end
15
+ end
16
+
17
+ class Ruleset
18
+
19
+ def initialize(ruleset)
20
+ @ruleset = ruleset
21
+ end
22
+
23
+ def each_selector
24
+ @ruleset.each_selector do |sel, dec, spe|
25
+ normalize_for_test! dec
26
+ yield sel, dec, spe
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ # To make testings work for both parsers we need to conform to
33
+ # csspool normalizing attributes. This means all numbers have a
34
+ # decimal place. It also means that urls do not have quotes.
35
+ #
36
+ # NOTE: This really doesn't have anything to do with the
37
+ # correctness of the parser. It just makes testing easier since
38
+ # each parser can run against the same tests.
39
+ def normalize_for_test!(dec)
40
+
41
+ # Give all numbers a decimal if they do not already have it
42
+ dec.gsub! '0;', '0.0;'
43
+ dec.gsub! ' 0 ', ' 0.0 '
44
+ dec.gsub! /([^\.0-9]\d+)px/, '\1.0px'
45
+ dec.gsub! /([^\.0-9]\d+)%/, '\1.0%'
46
+
47
+ # Remove any quotes in url()
48
+ dec.gsub! "url('", 'url('
49
+ dec.gsub! "')", ')'
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ gem 'maca-fork-csspool'
2
+ require 'csspool'
3
+
4
+ module InlineStyle::CssParsers
5
+ class Csspool
6
+
7
+ def initialize(css_code)
8
+ @parser = CSSPool.CSS css_code
9
+ end
10
+
11
+ def each_rule_set
12
+ @parser.rule_sets.each do |rule_set|
13
+ yield Ruleset.new(rule_set)
14
+ end
15
+ end
16
+
17
+ class Ruleset
18
+
19
+ def initialize(ruleset)
20
+ @ruleset = ruleset
21
+ end
22
+
23
+ def each_selector(&blk)
24
+ @ruleset.selectors.each do |selector|
25
+ yield selector.to_s,
26
+ selector.declarations.map{ |d| d.to_s.squeeze(' ') }.join.strip,
27
+ selector.specificity.inject(0) {|t, s| t+s}
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ # A interceptor for +mail+ (https://github.com/mikel/mail) to
2
+ # automatically inline the styles of outgoing e-mails. To use:
3
+ #
4
+ # Mail.register_interceptor \
5
+ # InlineStyle::Mail::Interceptor.new(:stylesheets_path => 'public')
6
+ #
7
+ # Rails 3's ActionMailer wraps around the +mail+ and also supports
8
+ # interceptors. Example usage:
9
+ #
10
+ # ActionMailer::Base.register_interceptor \
11
+ # InlineStyle::Mail::Interceptor.new(:stylesheets_path => 'public')
12
+ module InlineStyle
13
+ module Mail
14
+ class Interceptor
15
+ # The mime types we should inline. Basically HTML and XHTML.
16
+ # If you have something else you can just push it onto the list
17
+ INLINE_MIME_TYPES = %w(text/html application/xhtml+xml)
18
+
19
+ # Save the options to later pass to InlineStyle.process
20
+ def initialize(options={})
21
+ @options = options
22
+ end
23
+
24
+ # Mail callback where we actually inline the styles
25
+ def delivering_email(part)
26
+ if part.multipart?
27
+ for part in part.parts
28
+ delivering_email part
29
+ end
30
+ elsif INLINE_MIME_TYPES.any? {|m| part.content_type.starts_with? m}
31
+ part.body = InlineStyle.process(part.body.to_s, @options)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -3,8 +3,8 @@ module InlineStyle
3
3
  class Middleware
4
4
  #
5
5
  # Options:
6
- # +document_root+
7
- # File system path for app's public directory where the stylesheets are to be found, defaults to
6
+ # +stylesheets_path+
7
+ # Stylesheets root path or app's public directory where the stylesheets are to be found, defaults to
8
8
  # env['DOCUMENT_ROOT']
9
9
  #
10
10
  # +paths+
@@ -33,7 +33,7 @@ module InlineStyle
33
33
  response = ::Rack::Response.new '', status, headers
34
34
  body = content.respond_to?(:body) ? content.body : content
35
35
 
36
- response.write InlineStyle.process(body, {:document_root => env['DOCUMENT_ROOT']}.merge(@opts))
36
+ response.write InlineStyle.process(body, {:stylesheets_path => env['DOCUMENT_ROOT']}.merge(@opts))
37
37
  response.finish
38
38
  end
39
39
  end
@@ -0,0 +1,5 @@
1
+ module Inline
2
+ module Style
3
+ VERSION = '0.4.6'
4
+ end
5
+ end
@@ -0,0 +1,55 @@
1
+ require "#{ File.dirname __FILE__ }/spec_helper"
2
+ require "#{ DIR }/../lib/inline-style/css_parsers/css_parser"
3
+ require "#{ DIR }/../lib/inline-style/css_parsers/csspool"
4
+
5
+ describe InlineStyle::CssParsers::CssParser do
6
+
7
+ it 'should wrap css_parser' do
8
+ rs_count = 0
9
+ sel_count = 0
10
+ selectors = %w(p b i)
11
+ decs = ['color: black;', 'color: black;', 'color: green; text-decoration: none;']
12
+ spes = [1, 1, 1]
13
+ p = InlineStyle::CssParsers::CssParser.new "p, b {color: black}\ni {color: green; text-decoration: none}"
14
+
15
+ p.each_rule_set do |rs|
16
+ rs_count += 1
17
+ rs.each_selector do |sel, dec, spe|
18
+ sel_count += 1
19
+ sel.should == selectors.shift
20
+ dec.should == decs.shift
21
+ spe.should == spes.shift
22
+ end
23
+ end
24
+
25
+ rs_count.should == 2
26
+ sel_count.should == 3
27
+ end
28
+
29
+ end
30
+
31
+ describe InlineStyle::CssParsers::Csspool do
32
+
33
+ it 'should wrap csspool' do
34
+ rs_count = 0
35
+ sel_count = 0
36
+ selectors = %w(p b i)
37
+ decs = ['color: black;', 'color: black;', 'color: green; text-decoration: none;']
38
+ spes = [1, 1, 1]
39
+ p = InlineStyle::CssParsers::Csspool.new "p, b {color: black}\ni {color: green; text-decoration: none}"
40
+
41
+ p.each_rule_set do |rs|
42
+ rs_count += 1
43
+ rs.each_selector do |sel, dec, spe|
44
+ sel_count += 1
45
+ sel.should == selectors.shift
46
+ dec.should == decs.shift
47
+ spe.should == spes.shift
48
+ end
49
+ end
50
+
51
+ rs_count.should == 2
52
+ sel_count.should == 3
53
+ end
54
+
55
+ end
@@ -0,0 +1,38 @@
1
+ require "#{ File.dirname __FILE__ }/spec_helper"
2
+
3
+ describe InlineStyle::CssParsers do
4
+
5
+ before do
6
+ @orig_env = ENV['CSS_PARSER']
7
+ ENV['CSS_PARSER'] = nil
8
+ InlineStyle::CssParsers.parser = nil # Clear out any cached value
9
+ end
10
+ after do
11
+ ENV['CSS_PARSER'] = @orig_env
12
+ InlineStyle::CssParsers.parser = nil # Clear out any cached value
13
+ end
14
+
15
+ it 'should load css_parser by default' do
16
+ InlineStyle::CssParsers.parser.name.
17
+ should == 'InlineStyle::CssParsers::CssParser'
18
+ end
19
+
20
+ it "should obey ENV['CSS_PARSER']" do
21
+ ENV['CSS_PARSER'] = 'css_parser'
22
+ InlineStyle::CssParsers.parser.name.
23
+ should == 'InlineStyle::CssParsers::CssParser'
24
+ end
25
+
26
+ it 'should be able to load csspool' do
27
+ InlineStyle::CssParsers.parser = :csspool
28
+ InlineStyle::CssParsers.parser.name.
29
+ should == 'InlineStyle::CssParsers::Csspool'
30
+ end
31
+
32
+ it 'should be able to load css_parser' do
33
+ InlineStyle::CssParsers.parser = :css_parser
34
+ InlineStyle::CssParsers.parser.name.
35
+ should == 'InlineStyle::CssParsers::CssParser'
36
+ end
37
+
38
+ end
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
2
  <html xmlns="http://www.w3.org/1999/xhtml">
3
3
  <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
4
+ <meta content="text/html; charset=utf-8" http-equiv="Content-type">
5
5
  <title> Boletín CENART - November
6
6
  </title>
7
7
  <link href="/print.css?1248460539" rel="stylesheet" media="print" type="text/css">
@@ -96,7 +96,7 @@
96
96
  contacto <br style="margin: 0.0; padding: 0.0;"><a href="mailto:mail@host.org" style="margin: 0.0; padding: 0.0; color: #185d6b; font-weight: bold; font-size: 1.2em;">mail@host.org</a>
97
97
  </div>
98
98
  <div id="logos" style="margin: 0.0; padding: 0.0; width: 100.0%; margin-top: 40.0px; background-image: url(/images/boletines/Noviembre/logos_fondo.jpg);">
99
- <img src="A" id="izq" alt="A" style="margin: 0.0; padding: 0.0; float: left;"><img src="B" id="der" alt="B" style="margin: 0.0; padding: 0.0; float: right;"><div class="clearer" style="margin: 0.0; padding: 0.0; clear: both;">
99
+ <img src="A" id="izq" alt="A" style="margin: 0.0; padding: 0.0; float: left; margin: 30.0px; padding: 10.0px; color: red;"><img src="B" id="der" alt="B" style="margin: 0.0; padding: 0.0; float: right;"><div class="clearer" style="margin: 0.0; padding: 0.0; clear: both;">
100
100
  </div>
101
101
  </div>
102
102
 
@@ -0,0 +1,63 @@
1
+ require "#{ File.dirname __FILE__ }/spec_helper"
2
+
3
+ require 'mail'
4
+ Mail.defaults do
5
+ delivery_method :test
6
+ end
7
+ Mail.register_interceptor \
8
+ InlineStyle::Mail::Interceptor.new(:stylesheets_path => FIXTURES)
9
+
10
+ describe InlineStyle::Mail::Interceptor do
11
+
12
+ before do
13
+ Mail::TestMailer.deliveries.clear
14
+ end
15
+
16
+ it 'should inline html e-mail' do
17
+ Mail.deliver do
18
+ to 'joe@example.com'
19
+ from 'joe@example.com'
20
+ subject 'HTML e-mail'
21
+ content_type 'text/html'
22
+ body File.read("#{ FIXTURES }/boletin.html")
23
+ end
24
+
25
+ Mail::TestMailer.deliveries.first.body.to_s.
26
+ should == File.read("#{ FIXTURES }/inline.html")
27
+ end
28
+
29
+ it 'should not inline non-html' do
30
+ Mail.deliver do
31
+ to 'joe@example.com'
32
+ from 'joe@example.com'
33
+ subject 'Plain text e-mail (with HTML looking content)'
34
+ content_type 'text/plain'
35
+ body File.read("#{ FIXTURES }/boletin.html")
36
+ end
37
+
38
+ Mail::TestMailer.deliveries.first.body.to_s.
39
+ should == File.read("#{ FIXTURES }/boletin.html")
40
+ end
41
+
42
+ it 'should inline html part of multipart/alternative' do
43
+ Mail.deliver do
44
+ to 'joe@example.com'
45
+ from 'joe@example.com'
46
+ subject 'Multipart/alternative e-mail'
47
+ text_part do
48
+ body File.read("#{ FIXTURES }/boletin.html")
49
+ end
50
+ html_part do
51
+ content_type 'text/html; charset=UTF-8'
52
+ body File.read("#{ FIXTURES }/boletin.html")
53
+ end
54
+ end
55
+
56
+ Mail::TestMailer.deliveries.first.parts[0].body.to_s.
57
+ should == File.read("#{ FIXTURES }/boletin.html")
58
+
59
+ Mail::TestMailer.deliveries.first.parts[1].body.to_s.
60
+ should == File.read("#{ FIXTURES }/inline.html")
61
+ end
62
+
63
+ end
@@ -19,8 +19,11 @@ describe InlineStyle::Rack::Middleware do
19
19
  get_response('/', @html, :stylesheets_path => FIXTURES).should have_inline_style_for('#A')
20
20
  end
21
21
 
22
+ it "should use external css" do
23
+ get_response('/', Nokogiri.HTML(@html), :stylesheets_path => FIXTURES).css('#izq').first['style'].should =~ /margin: 30.0px/
24
+ end
25
+
22
26
  describe 'Path inclusion' do
23
-
24
27
  it "should inline style for string path" do
25
28
  paths = "/some/path"
26
29
  get_response('/some/path', @html, :stylesheets_path => FIXTURES, :paths => paths).should have_inline_style_for('#A')
@@ -54,4 +57,4 @@ describe InlineStyle::Rack::Middleware do
54
57
  get_response('/other/path', @html, :stylesheets_path => FIXTURES, :paths => paths).should_not have_inline_style_for('#A')
55
58
  end
56
59
  end
57
- end
60
+ end
@@ -1,12 +1,11 @@
1
1
  require 'rubygems'
2
- require 'spec'
2
+ require 'rspec'
3
3
  require "#{ DIR = File.dirname(__FILE__) }/../lib/inline-style"
4
4
  require 'rack'
5
5
  require 'rack/mock'
6
6
 
7
7
  FIXTURES = "#{ DIR }/fixtures"
8
8
 
9
-
10
9
  module HaveInlineStyleMatcher
11
10
  class HaveInlineStyle
12
11
  def initialize selector
@@ -32,4 +31,4 @@ module HaveInlineStyleMatcher
32
31
  end
33
32
  end
34
33
 
35
- Spec::Runner.configure { |config| config.include HaveInlineStyleMatcher }
34
+ RSpec.configure { |config| config.include HaveInlineStyleMatcher }
metadata CHANGED
@@ -1,85 +1,143 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inline-style
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 6
9
+ version: 0.4.6
5
10
  platform: ruby
6
11
  authors:
7
12
  - Macario Ortega
13
+ - Eric Anderson
8
14
  autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-10-29 00:00:00 -06:00
18
+ date: 2011-03-07 00:00:00 -06:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
- name: nokogiri
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
23
- version: 1.3.3
24
- version:
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :development
33
+ version_requirements: *id001
25
34
  - !ruby/object:Gem::Dependency
26
- name: maca-fork-csspool
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
35
+ name: rack
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
30
39
  requirements:
31
40
  - - ">="
32
41
  - !ruby/object:Gem::Version
33
- version: 2.0.2
34
- version:
35
- - !ruby/object:Gem::Dependency
36
- name: newgem
42
+ segments:
43
+ - 0
44
+ version: "0"
37
45
  type: :development
38
- version_requirement:
39
- version_requirements: !ruby/object:Gem::Requirement
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec-core
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
40
52
  requirements:
41
53
  - - ">="
42
54
  - !ruby/object:Gem::Version
43
- version: 1.4.1
44
- version:
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id003
45
60
  - !ruby/object:Gem::Dependency
46
- name: hoe
61
+ name: mail
62
+ prerelease: false
63
+ requirement: &id004 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
47
71
  type: :development
48
- version_requirement:
49
- version_requirements: !ruby/object:Gem::Requirement
72
+ version_requirements: *id004
73
+ - !ruby/object:Gem::Dependency
74
+ name: nokogiri
75
+ prerelease: false
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
50
78
  requirements:
51
79
  - - ">="
52
80
  - !ruby/object:Gem::Version
53
- version: 1.8.0
54
- version:
55
- description: |-
56
- Will take all css in a page (either from linked stylesheet or from style tag) and will embed it in the style attribute for
57
- each refered element taking selector specificity and declarator order.
58
-
59
- Useful for html email: some clients (gmail, et all) won't render non inline styles.
60
-
61
- * Includes a Rack middleware for using with Rails, Sinatra, etc...
62
- * It takes into account selector specificity.
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ type: :runtime
85
+ version_requirements: *id005
86
+ - !ruby/object:Gem::Dependency
87
+ name: css_parser
88
+ prerelease: false
89
+ requirement: &id006 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ type: :runtime
98
+ version_requirements: *id006
99
+ - !ruby/object:Gem::Dependency
100
+ name: maca-fork-csspool
101
+ prerelease: false
102
+ requirement: &id007 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ type: :runtime
111
+ version_requirements: *id007
112
+ description: Inlines CSS for html email delivery
63
113
  email:
64
114
  - macarui@gmail.com
65
115
  executables: []
66
116
 
67
117
  extensions: []
68
118
 
69
- extra_rdoc_files:
70
- - History.txt
71
- - Manifest.txt
72
- - README.rdoc
119
+ extra_rdoc_files: []
120
+
73
121
  files:
122
+ - .gitignore
123
+ - Gemfile
124
+ - Gemfile.lock
74
125
  - History.txt
75
126
  - Manifest.txt
76
- - README.rdoc
127
+ - README.txt
77
128
  - Rakefile
78
129
  - example.rb
130
+ - inline-style.gemspec
79
131
  - lib/inline-style.rb
132
+ - lib/inline-style/css_parsers.rb
133
+ - lib/inline-style/css_parsers/css_parser.rb
134
+ - lib/inline-style/css_parsers/csspool.rb
135
+ - lib/inline-style/mail/interceptor.rb
80
136
  - lib/inline-style/rack/middleware.rb
81
- - spec/as_middleware_spec.rb
137
+ - lib/inline-style/version.rb
82
138
  - spec/css_inlining_spec.rb
139
+ - spec/css_parsers_spec.rb
140
+ - spec/factory_spec.rb
83
141
  - spec/fixtures/all.css
84
142
  - spec/fixtures/boletin.html
85
143
  - spec/fixtures/box-model.html
@@ -88,35 +146,40 @@ files:
88
146
  - spec/fixtures/print.css
89
147
  - spec/fixtures/selectors.html
90
148
  - spec/fixtures/style.css
149
+ - spec/interceptor_spec.rb
150
+ - spec/rack_middleware_spec.rb
91
151
  - spec/spec_helper.rb
92
152
  has_rdoc: true
93
- homepage: http://github.com/maca/inline-style
153
+ homepage: ""
94
154
  licenses: []
95
155
 
96
156
  post_install_message:
97
- rdoc_options:
98
- - --main
99
- - README.rdoc
157
+ rdoc_options: []
158
+
100
159
  require_paths:
101
160
  - lib
102
161
  required_ruby_version: !ruby/object:Gem::Requirement
162
+ none: false
103
163
  requirements:
104
164
  - - ">="
105
165
  - !ruby/object:Gem::Version
166
+ segments:
167
+ - 0
106
168
  version: "0"
107
- version:
108
169
  required_rubygems_version: !ruby/object:Gem::Requirement
170
+ none: false
109
171
  requirements:
110
172
  - - ">="
111
173
  - !ruby/object:Gem::Version
174
+ segments:
175
+ - 0
112
176
  version: "0"
113
- version:
114
177
  requirements: []
115
178
 
116
- rubyforge_project: inline-style
117
- rubygems_version: 1.3.5
179
+ rubyforge_project:
180
+ rubygems_version: 1.3.7
118
181
  signing_key:
119
182
  specification_version: 3
120
- summary: Will take all css in a page (either from linked stylesheet or from style tag) and will embed it in the style attribute for each refered element taking selector specificity and declarator order
183
+ summary: Inlines CSS for html email delivery
121
184
  test_files: []
122
185