tamtam 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/lib/tamtam.rb +99 -0
- metadata +54 -0
data/lib/tamtam.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "hpricot"
|
3
|
+
|
4
|
+
# Takes CSS + HTML and converts it to inline styles.
|
5
|
+
# css <= '#foo { font-color: blue; }'
|
6
|
+
# html <= '<div id="foo">woot</div>'
|
7
|
+
# output => '<div id="foo" style="font-color: blue;">woot</div>'
|
8
|
+
#
|
9
|
+
# The class uses regular expressions to parse the CSS.
|
10
|
+
# The regular expressions are based on CPAN's CSS::Parse::Lite.
|
11
|
+
#
|
12
|
+
# Author: Dave Hoover of Obtiva Corp.
|
13
|
+
# Sponsor: Gary Levitt of MadMimi.com
|
14
|
+
class TamTam
|
15
|
+
UNSUPPORTED = /(::first-letter|:link|:visited|:hover|:active)$/
|
16
|
+
|
17
|
+
class << self
|
18
|
+
def inline(args)
|
19
|
+
css, doc = process(args)
|
20
|
+
raw_styles(css).each do |raw_style|
|
21
|
+
style, contents = parse(raw_style)
|
22
|
+
next if style.match(UNSUPPORTED)
|
23
|
+
(doc/style).each do |element|
|
24
|
+
apply_to(element, style, contents)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
doc.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def process(args)
|
33
|
+
if args[:document]
|
34
|
+
doc = Hpricot(args[:document])
|
35
|
+
style = (doc/"style").first
|
36
|
+
[(style && style.inner_html), doc]
|
37
|
+
else
|
38
|
+
[args[:css], Hpricot(args[:body])]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def raw_styles(css)
|
43
|
+
return [] if css.nil?
|
44
|
+
css = css.gsub(/[\r\n]/, " ")
|
45
|
+
validate(css)
|
46
|
+
# jamming brackets back on, wishing for look-behinds
|
47
|
+
styles = css.strip.split("}").map { |style| style + "}" }
|
48
|
+
# running backward to allow for "last one wins"
|
49
|
+
styles.reverse
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate(css)
|
53
|
+
lefts = bracket_count(css, "{")
|
54
|
+
rights = bracket_count(css, "}")
|
55
|
+
if lefts != rights
|
56
|
+
raise InvalidStyleException, "Found #{lefts} left brackets and #{rights} right brackets in:\n #{css}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def bracket_count(css, bracket)
|
61
|
+
css.scan(Regexp.new(Regexp.escape(bracket))).size
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(raw_style)
|
65
|
+
# Regex from CSS::Parse::Lite
|
66
|
+
data = raw_style.match(/^\s*([^{]+?)\s*\{(.*)\}\s*$/)
|
67
|
+
raise "Invalid style: #{style}" if data.nil?
|
68
|
+
data.captures.map { |s| s.strip }
|
69
|
+
end
|
70
|
+
|
71
|
+
def apply_to(element, style, contents)
|
72
|
+
return unless element.respond_to?(:get_attribute)
|
73
|
+
current_style = to_hash(element.get_attribute(:style))
|
74
|
+
new_styles = to_hash(contents).merge(current_style)
|
75
|
+
element.set_attribute(:style, prepare(new_styles))
|
76
|
+
rescue Exception => e
|
77
|
+
raise Exception.new(e), "Trouble on style #{style} on element #{element}: #{e}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_hash(style)
|
81
|
+
return {} if style.nil?
|
82
|
+
hash = {}
|
83
|
+
pieces = style.strip.split(";").map { |s| s.strip.split(":").map { |kv| kv.strip } }
|
84
|
+
pieces.each do |key, value|
|
85
|
+
hash[key] = value
|
86
|
+
end
|
87
|
+
hash
|
88
|
+
end
|
89
|
+
|
90
|
+
def prepare(style_hash)
|
91
|
+
sorted_styles = style_hash.keys.sort.map { |key| key + ": " + style_hash[key] }
|
92
|
+
sorted_styles.join("; ").strip + ";"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class InvalidStyleException < Exception
|
98
|
+
end
|
99
|
+
# "Man Chocolate" (don't ask)
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: tamtam
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-10-05 00:00:00 -05:00
|
8
|
+
summary: Inline a CSS stylesheet into an HTML document.
|
9
|
+
require_paths:
|
10
|
+
- .
|
11
|
+
email: dave@obtiva.com
|
12
|
+
homepage: http://tamtam.rubyforge.org/
|
13
|
+
rubyforge_project: tamtam
|
14
|
+
description: Email services like GMail and Hotmail don't like stylesheets. The only way around it is to use inline tags. Replacing stylesheet references with inline tags is a pain in the arse. Use this tool to do the dirty work for you.
|
15
|
+
autorequire: tamtam
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Dave Hoover
|
31
|
+
files:
|
32
|
+
- lib/tamtam.rb
|
33
|
+
test_files: []
|
34
|
+
|
35
|
+
rdoc_options: []
|
36
|
+
|
37
|
+
extra_rdoc_files: []
|
38
|
+
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
requirements: []
|
44
|
+
|
45
|
+
dependencies:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: hpricot
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.0.0
|
54
|
+
version:
|