eyeliner 0.0.1

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 ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "rake", "~> 0.9.2"
7
+ gem "rspec", "~> 2.6.0"
8
+ end
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require "rspec/core/rake_task"
6
+
7
+ task "default" => "spec"
8
+
9
+ RSpec::Core::RakeTask.new do |t|
10
+ t.pattern = 'spec/**/*_spec.rb'
11
+ t.rspec_opts = ["--colour", "--format", "nested"]
12
+ end
data/eyeliner.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "eyeliner/version"
4
+
5
+ Gem::Specification.new do |s|
6
+
7
+ s.name = "eyeliner"
8
+ s.version = Eyeliner::VERSION
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Mike Williams", "Rob Mitchell"]
11
+ s.email = ["mike@cogentconsulting.com.au", "rob@cogentconsulting.com.au"]
12
+ s.homepage = "http://github.com/cogent/eyeliner"
13
+ s.summary = %q{Eyeliner puts CSS makeup on your HTML emails.}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_runtime_dependency("nokogiri", ">= 1.4.4")
20
+ s.add_runtime_dependency("css_parser", ">= 1.1.9")
21
+
22
+ end
@@ -0,0 +1,3 @@
1
+ module Eyeliner
2
+ VERSION = "0.0.1"
3
+ end
data/lib/eyeliner.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'nokogiri'
2
+ require 'css_parser'
3
+
4
+ module Eyeliner
5
+
6
+ class Inliner
7
+
8
+ attr_accessor :css
9
+
10
+ def initialize
11
+ @css = ""
12
+ end
13
+
14
+ StyleRule = Struct.new(:declarations, :specificity) do
15
+
16
+ def <=>(other)
17
+ specificity <=> other.specificity
18
+ end
19
+
20
+ def to_s
21
+ declarations
22
+ end
23
+
24
+ end
25
+
26
+ def inline(input)
27
+ fragment = Nokogiri::HTML.fragment(input)
28
+ css_parser = CssParser::Parser.new
29
+ css_parser.add_block!(css)
30
+ styles_by_element = Hash.new do |h,k|
31
+ h[k] = []
32
+ end
33
+ css_parser.each_selector do |selector, declarations, specificity|
34
+ fragment.css(selector).each do |element|
35
+ styles_by_element[element] << StyleRule.new(declarations, specificity)
36
+ end
37
+ end
38
+ styles_by_element.each do |element, rules|
39
+ element["style"] = rules.sort.join(" ")
40
+ end
41
+ fragment.to_html
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe Eyeliner::Inliner do
4
+
5
+ let(:eyeliner) { Eyeliner::Inliner.new }
6
+
7
+ def should_not_modify(input)
8
+ eyeliner.inline(input).should == input
9
+ end
10
+
11
+ def should_modify(input, options)
12
+ eyeliner.inline(input).should == options[:to]
13
+ end
14
+
15
+ context "with no CSS" do
16
+
17
+ describe "#inline" do
18
+
19
+ context "with empty input" do
20
+
21
+ it "returns empty output" do
22
+ should_not_modify("")
23
+ end
24
+
25
+ end
26
+
27
+ context "with an HTML fragment" do
28
+
29
+ it "returns the same output" do
30
+ should_not_modify("<div>abc</div>")
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ context "with some explicit CSS" do
40
+
41
+ before do
42
+ eyeliner.css << %{
43
+ .box { border: 1px solid green; }
44
+ .small { font-size: 8px; }
45
+ }
46
+ end
47
+
48
+ describe "#inline" do
49
+
50
+ it "leaves non-matching elements alone" do
51
+ should_not_modify("<p>xyz</p>")
52
+ end
53
+
54
+ it "adds style attributes to matching elements" do
55
+ should_modify %(<p class="box">xyz</p>),
56
+ :to => %(<p class="box" style="border: 1px solid green;">xyz</p>)
57
+ end
58
+
59
+ it "iterates into nested elements" do
60
+ should_modify %(<p><span class="small">xyz</span></p>),
61
+ :to => %(<p><span class="small" style="font-size: 8px;">xyz</span></p>)
62
+ end
63
+
64
+ it "combines all matching rules" do
65
+ should_modify %(<p class="small box">xyz</p>),
66
+ :to => %(<p class="small box" style="border: 1px solid green; font-size: 8px;">xyz</p>)
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ context "where CSS rules conflict" do
74
+
75
+ before do
76
+ eyeliner.css << %{
77
+ p { color: red; }
78
+ p.small { text-decoration: underline; }
79
+ .small { font-size: 8px; }
80
+ }
81
+ end
82
+
83
+ describe "#inline" do
84
+
85
+ it "applies styles in order of specificity" do
86
+ should_modify %(<p class="small">xyz</p>),
87
+ :to => %(<p class="small" style="color: red; font-size: 8px; text-decoration: underline;">xyz</p>)
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,3 @@
1
+ require 'rspec'
2
+
3
+ require 'eyeliner'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eyeliner
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Mike Williams
9
+ - Rob Mitchell
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-07-13 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: nokogiri
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.4.4
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: css_parser
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 1.1.9
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ description:
39
+ email:
40
+ - mike@cogentconsulting.com.au
41
+ - rob@cogentconsulting.com.au
42
+ executables: []
43
+
44
+ extensions: []
45
+
46
+ extra_rdoc_files: []
47
+
48
+ files:
49
+ - .gitignore
50
+ - Gemfile
51
+ - Rakefile
52
+ - eyeliner.gemspec
53
+ - lib/eyeliner.rb
54
+ - lib/eyeliner/version.rb
55
+ - spec/eyeliner_spec.rb
56
+ - spec/spec_helper.rb
57
+ homepage: http://github.com/cogent/eyeliner
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3190977879137818689
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3190977879137818689
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.7.2
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Eyeliner puts CSS makeup on your HTML emails.
90
+ test_files:
91
+ - spec/eyeliner_spec.rb
92
+ - spec/spec_helper.rb