eyeliner 0.0.1

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