tamtam 0.0.2 → 0.0.3

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