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.
Files changed (2) hide show
  1. data/lib/tamtam.rb +90 -79
  2. metadata +48 -41
@@ -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
- class TamTam
15
- UNSUPPORTED = /(::first-letter|:link|:visited|:hover|:active)$/
13
+ module TamTam
14
+ extend self
15
+
16
+ UNSUPPORTED = /(:first-letter|:link|:visited|:hover|:active)(\s|$)/
16
17
 
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
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
- 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
27
+ doc.to_s
28
+ end
29
+
30
+ private
41
31
 
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
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.2
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
- files:
33
- - lib/tamtam.rb
34
- test_files: []
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::Version::Requirement
18
+ version_requirements: !ruby/object:Gem::Requirement
51
19
  requirements:
52
- - - ">"
20
+ - - ">="
53
21
  - !ruby/object:Gem::Version
54
- version: 0.0.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
+