tamtam 0.0.2 → 0.0.3
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 +90 -79
- metadata +48 -41
data/lib/tamtam.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "hpricot"
|
3
|
-
|
4
3
|
# Takes CSS + HTML and converts it to inline styles.
|
5
4
|
# css <= '#foo { font-color: blue; }'
|
6
5
|
# html <= '<div id="foo">woot</div>'
|
@@ -9,91 +8,103 @@ require "hpricot"
|
|
9
8
|
# The class uses regular expressions to parse the CSS.
|
10
9
|
# The regular expressions are based on CPAN's CSS::Parse::Lite.
|
11
10
|
#
|
12
|
-
# Author: Dave Hoover of Obtiva Corp.
|
11
|
+
# Author: Dave Hoover and Brian Tatnall of Obtiva Corp.
|
13
12
|
# Sponsor: Gary Levitt of MadMimi.com
|
14
|
-
|
15
|
-
|
13
|
+
module TamTam
|
14
|
+
extend self
|
15
|
+
|
16
|
+
UNSUPPORTED = /(:first-letter|:link|:visited|:hover|:active)(\s|$)/
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
(
|
24
|
-
apply_to(element, style, contents)
|
25
|
-
end
|
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)
|
26
25
|
end
|
27
|
-
doc.to_s
|
28
26
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
27
|
+
doc.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
41
31
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
32
|
+
def process(args)
|
33
|
+
return_value =
|
34
|
+
if args[:document]
|
35
|
+
doc = Hpricot(args[:document])
|
36
|
+
style = (doc/"style").first
|
37
|
+
[(style && style.inner_html), doc]
|
38
|
+
else
|
39
|
+
[args[:css], Hpricot(args[:body])]
|
40
|
+
end
|
41
|
+
if args[:prune_classes]
|
42
|
+
(doc/"*").each { |e| e.remove_attribute(:class) if e.respond_to?(:remove_attribute) }
|
43
|
+
end
|
44
|
+
return_value
|
45
|
+
end
|
46
|
+
|
47
|
+
def raw_styles(css)
|
48
|
+
return [] if css.nil?
|
49
|
+
css.gsub!(/[\r\n]/, " ") # remove newlines
|
50
|
+
css.gsub!(/\/\*.*?\*\//, "") # strip /* comments */
|
51
|
+
validate(css)
|
52
|
+
# splitting on brackets and jamming them back on, wishing for look-behinds
|
53
|
+
styles = css.strip.split("}").map { |style| style + "}" }
|
54
|
+
# running backward to allow for "last one wins"
|
55
|
+
styles.reverse
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate(css)
|
59
|
+
lefts = bracket_count(css, "{")
|
60
|
+
rights = bracket_count(css, "}")
|
61
|
+
if lefts != rights
|
62
|
+
raise InvalidStyleException, "Found #{lefts} left brackets and #{rights} right brackets in:\n #{css}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def bracket_count(css, bracket)
|
67
|
+
css.scan(Regexp.new(Regexp.escape(bracket))).size
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse(raw_style)
|
71
|
+
# Regex from CPAN's CSS::Parse::Lite
|
72
|
+
data = raw_style.match(/^\s*([^{]+?)\s*\{(.*)\}\s*$/)
|
73
|
+
raise InvalidStyleException, "Trouble on style: #{raw_style}" if data.nil?
|
74
|
+
data.captures.map { |s| s.strip }
|
75
|
+
end
|
76
|
+
|
77
|
+
def apply_to(element, style, contents)
|
78
|
+
return unless element.respond_to?(:get_attribute)
|
79
|
+
current_style = to_hash(element.get_attribute(:style))
|
80
|
+
new_styles = to_hash(contents).merge(current_style)
|
81
|
+
element.set_attribute(:style, prepare(new_styles))
|
82
|
+
rescue Exception => e
|
83
|
+
raise InvalidStyleException, "Trouble on style #{style} on element #{element}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_hash(style)
|
87
|
+
return {} if style.nil?
|
88
|
+
hash = {}
|
89
|
+
# Split up the different styles,
|
90
|
+
# can't just split on semicolons because they could be in url(foo;bar.png)
|
91
|
+
styles = style.strip.scan(/((?:\(.*\)|[^;])+)/).flatten
|
92
|
+
# Grab just the style name (color) and style body (blue),
|
93
|
+
# making sure not to split on the colon in url(http://...), then
|
94
|
+
# turn any double-quotes into single-quotes because Hpricot wants to escape double-quotes
|
95
|
+
pieces = styles.map { |s| s.strip.split(":", 2).map { |kv| kv.strip.gsub('"', "'") } }
|
96
|
+
pieces.each do |key, value|
|
97
|
+
hash[key] = value
|
98
|
+
end
|
99
|
+
hash
|
100
|
+
end
|
101
|
+
|
102
|
+
def prepare(style_hash)
|
103
|
+
sorted_styles = style_hash.keys.sort.map { |key| key + ": " + style_hash[key] }
|
104
|
+
sorted_styles.join("; ").strip + ";"
|
94
105
|
end
|
95
106
|
end
|
96
107
|
|
97
108
|
class InvalidStyleException < Exception
|
98
109
|
end
|
99
|
-
# "Man Chocolate" (don't ask)
|
110
|
+
# "Man Chocolate" (don't ask)
|
metadata
CHANGED
@@ -1,55 +1,62 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.2
|
3
|
-
specification_version: 1
|
4
2
|
name: tamtam
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
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
|
-
- lib
|
12
|
-
email: dave@obtiva.com
|
13
|
-
homepage: http://tamtam.rubyforge.org/
|
14
|
-
rubyforge_project: tamtam
|
15
|
-
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.
|
16
|
-
autorequire: tamtam
|
17
|
-
default_executable:
|
18
|
-
bindir: bin
|
19
|
-
has_rdoc: false
|
20
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
21
|
-
requirements:
|
22
|
-
- - ">"
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: 0.0.0
|
25
|
-
version:
|
4
|
+
version: 0.0.3
|
26
5
|
platform: ruby
|
27
|
-
signing_key:
|
28
|
-
cert_chain:
|
29
|
-
post_install_message:
|
30
6
|
authors:
|
31
7
|
- Dave Hoover
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
rdoc_options: []
|
37
|
-
|
38
|
-
extra_rdoc_files: []
|
39
|
-
|
40
|
-
executables: []
|
41
|
-
|
42
|
-
extensions: []
|
43
|
-
|
44
|
-
requirements: []
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
45
11
|
|
12
|
+
date: 2007-10-05 00:00:00 -05:00
|
13
|
+
default_executable:
|
46
14
|
dependencies:
|
47
15
|
- !ruby/object:Gem::Dependency
|
48
16
|
name: hpricot
|
49
17
|
version_requirement:
|
50
|
-
version_requirements: !ruby/object:Gem::
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
19
|
requirements:
|
52
|
-
- - "
|
20
|
+
- - ">="
|
53
21
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0
|
22
|
+
version: "0"
|
55
23
|
version:
|
24
|
+
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.
|
25
|
+
email: dave@obtiva.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files: []
|
31
|
+
|
32
|
+
files:
|
33
|
+
- lib/tamtam.rb
|
34
|
+
has_rdoc: false
|
35
|
+
homepage: http://tamtam.rubyforge.org/
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- .
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project: tamtam
|
57
|
+
rubygems_version: 1.1.1
|
58
|
+
signing_key:
|
59
|
+
specification_version: 2
|
60
|
+
summary: Inline a CSS stylesheet into an HTML document.
|
61
|
+
test_files: []
|
62
|
+
|