packrat 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Mike Hansen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = packrat
2
+
3
+ Packrat is a gem for merging all css rules to inline for html emails and files.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Mike Hansen. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "packrat"
8
+ gem.summary = "Packrat is a gem for merging all css rules to inline for html emails and files."
9
+ gem.description = "Packrat is a gem for merging all css rules to inline for html emails and files."
10
+ gem.email = "indyjones805@gmail.com"
11
+ gem.homepage = "http://github.com/mikehansen/packrat"
12
+ gem.authors = ["Mike Hansen"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "packrat #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/packrat.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'yaml'
2
+ require 'open-uri'
3
+ require 'hpricot'
4
+ require 'css_parser'
5
+ require 'active_support'
6
+
7
+ require File.dirname(__FILE__) + "/premailer/html_to_plain_text"
8
+ require File.dirname(__FILE__) + "/premailer/premailer"
9
+
10
+ module Packrat
11
+
12
+ class << self
13
+ def enable
14
+ enable_actionpack
15
+ end
16
+
17
+ def enable_actionpack
18
+ return if ActionView::Base.method_defined? :packrat_css
19
+ require 'packrat/view_helpers'
20
+ ActionView::Base.send :include, ViewHelpers
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ if defined? Rails
27
+ Packrat.enable_actionpack if defined? ActionController
28
+ end
@@ -0,0 +1,20 @@
1
+ module Packrat
2
+ module ViewHelpers
3
+
4
+ def packrat_css(&block)
5
+ c = capture(&block)
6
+ premailer = Premailer.new(StringIO.new(c), :local_file => false)
7
+ inlined = premailer.to_inline_css
8
+
9
+ if Rails::VERSION::MAJOR == 2
10
+ concat(inlined, proc.binding)
11
+ elsif Rails::VERSION::MAJOR == 3
12
+ inlined.html_safe
13
+ else
14
+ puts "Sorry, Packrat only works with Rails 2.x and Rails 3.x"
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ require 'text/reform'
2
+ require 'htmlentities'
3
+
4
+ # Support functions for Premailer
5
+ module HtmlToPlainText
6
+
7
+ # Returns the text in UTF-8 format with all HTML tags removed
8
+ #
9
+ # TODO:
10
+ # - add support for DL, OL
11
+ def convert_to_text(html, line_length = 65, from_charset = 'UTF-8')
12
+ r = Text::Reform.new(:trim => true,
13
+ :squeeze => false,
14
+ :break => Text::Reform.break_wrap)
15
+
16
+ txt = html
17
+
18
+ # decode HTML entities
19
+ he = HTMLEntities.new
20
+ txt = he.decode(txt)
21
+
22
+ # handle headings (H1-H6)
23
+ txt.gsub!(/[ \t]*<h([0-9]+)[^>]*>(.*)<\/h[0-9]+>/i) do |s|
24
+ hlevel = $1.to_i
25
+ # cleanup text inside of headings
26
+ htext = $2.gsub(/<\/?[^>]*>/i, '').strip
27
+ hlength = (htext.length > line_length ?
28
+ line_length :
29
+ htext.length)
30
+
31
+ case hlevel
32
+ when 1 # H1, asterisks above and below
33
+ ('*' * hlength) + "\n" + htext + "\n" + ('*' * hlength) + "\n"
34
+ when 2 # H1, dashes above and below
35
+ ('-' * hlength) + "\n" + htext + "\n" + ('-' * hlength) + "\n"
36
+ else # H3-H6, dashes below
37
+ htext + "\n" + ('-' * htext.length) + "\n"
38
+ end
39
+ end
40
+
41
+ # links
42
+ txt.gsub!(/<a.*href=\"([^\"]*)\"[^>]*>(.*)<\/a>/i) do |s|
43
+ $2.strip + ' ( ' + $1.strip + ' )'
44
+ end
45
+
46
+ # lists -- TODO: should handle ordered lists
47
+ txt.gsub!(/[\s]*(<li[^>]*>)[\s]*/i, '* ')
48
+ # list not followed by a newline
49
+ txt.gsub!(/<\/li>[\s]*(?![\n])/i, "\n")
50
+
51
+ # paragraphs and line breaks
52
+ txt.gsub!(/<\/p>/i, "\n\n")
53
+ txt.gsub!(/<br[\/ ]*>/i, "\n")
54
+
55
+ # strip remaining tags
56
+ txt.gsub!(/<\/?[^>]*>/, '')
57
+
58
+ # wrap text
59
+ txt = r.format(('[' * line_length), txt)
60
+
61
+ # remove linefeeds (\r\n and \r -> \n)
62
+ txt.gsub!(/\r\n?/, "\n")
63
+
64
+ # strip extra spaces
65
+ txt.gsub!(/\302\240+/, " ") # non-breaking spaces -> spaces
66
+ txt.gsub!(/\n[ \t]+/, "\n") # space at start of lines
67
+ txt.gsub!(/[ \t]+\n/, "\n") # space at end of lines
68
+
69
+ # no more than two consecutive newlines
70
+ txt.gsub!(/[\n]{3,}/, "\n\n")
71
+
72
+ txt.strip
73
+ end
74
+ end
@@ -0,0 +1,409 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Premailer by Alex Dunae (dunae.ca, e-mail 'code' at the same domain), 2008-09
4
+ #
5
+ # Premailer processes HTML and CSS to improve e-mail deliverability.
6
+ #
7
+ # Premailer's main function is to render all CSS as inline <tt>style</tt>
8
+ # attributes. It also converts relative links to absolute links and checks
9
+ # the 'safety' of CSS properties against a CSS support chart.
10
+ #
11
+ # = Example
12
+ # premailer = Premailer.new('http://example.com/myfile.html', :warn_level => Premailer::Warnings::SAFE)
13
+ #
14
+ # # Write the HTML output
15
+ # fout = File.open("output.html", "w")
16
+ # fout.puts premailer.to_inline_css
17
+ # fout.close
18
+ #
19
+ # # Write the plain-text output
20
+ # fout = File.open("ouput.txt", "w")
21
+ # fout.puts premailer.to_plain_text
22
+ # fout.close
23
+ #
24
+ # # List any CSS warnings
25
+ # puts premailer.warnings.length.to_s + ' warnings found'
26
+ # premailer.warnings.each do |w|
27
+ # puts "#{w[:message]} (#{w[:level]}) may not render properly in #{w[:clients]}"
28
+ # end
29
+ #
30
+ # premailer = Premailer.new(html_file, :warn_level => Premailer::Warnings::SAFE)
31
+ # puts premailer.to_inline_css
32
+ class Premailer
33
+ include HtmlToPlainText
34
+ include CssParser
35
+
36
+ VERSION = '1.5.4'
37
+
38
+ CLIENT_SUPPORT_FILE = File.dirname(__FILE__) + '/../../misc/client_support.yaml'
39
+
40
+ RE_UNMERGABLE_SELECTORS = /(\:(visited|active|hover|focus|after|before|selection|target|first\-(line|letter))|^\@)/i
41
+
42
+ # should also exclude :first-letter, etc...
43
+
44
+ # URI of the HTML file used
45
+ attr_reader :html_file
46
+
47
+ # processed HTML document (Hpricot)
48
+ attr_reader :processed_doc
49
+
50
+ # source HTML document (Hpricot)
51
+ attr_reader :doc
52
+
53
+ module Warnings
54
+ NONE = 0
55
+ SAFE = 1
56
+ POOR = 2
57
+ RISKY = 3
58
+ end
59
+ include Warnings
60
+
61
+ WARN_LABEL = %w(NONE SAFE POOR RISKY)
62
+
63
+ # Create a new Premailer object.
64
+ #
65
+ # +path+ is the path to the HTML file to process. Can be either the URL of a
66
+ # remote file or a local path.
67
+ #
68
+ # ==== Options
69
+ # [+line_length+] Line length used by to_plain_text. Boolean, default is 65.
70
+ # [+warn_level+] What level of CSS compatibility warnings to show (see Warnings).
71
+ # [+link_query_string+] A string to append to every <a href=""> link. Do not include the initial +?+.
72
+ # [+base_url+] Used to calculate absolute URLs for local files.
73
+ def initialize(path, options = {})
74
+ @options = {:warn_level => Warnings::SAFE,
75
+ :line_length => 65,
76
+ :link_query_string => nil,
77
+ :base_url => nil,
78
+ :local_file => true,
79
+ :remove_classes => false}.merge(options)
80
+ @html_file = path
81
+
82
+ if options[:local_file] == false
83
+ @is_local_file = false
84
+ elsif path =~ /^(http|https|ftp)\:\/\//i
85
+ @is_local_file = false
86
+ else
87
+ @is_local_file = true
88
+ end
89
+
90
+ @css_warnings = []
91
+
92
+ @css_parser = CssParser::Parser.new({:absolute_paths => true,
93
+ :import => true,
94
+ :io_exceptions => false
95
+ })
96
+
97
+ @doc, @html_charset = load_html(@html_file)
98
+ @processed_doc = @doc
99
+
100
+ if @is_local_file and @options[:base_url]
101
+ @processed_doc = convert_inline_links(@processed_doc, @options[:base_url])
102
+ elsif not @is_local_file
103
+ @processed_doc = convert_inline_links(@processed_doc, @html_file)
104
+ end
105
+ load_css_from_html!
106
+ end
107
+
108
+ # Array containing a hash of CSS warnings.
109
+ def warnings
110
+ return [] if @options[:warn_level] == Warnings::NONE
111
+ @css_warnings = check_client_support if @css_warnings.empty?
112
+ @css_warnings
113
+ end
114
+
115
+ # Returns the original HTML as a string.
116
+ def to_s
117
+ @doc.to_html
118
+ end
119
+
120
+ # Converts the HTML document to a format suitable for plain-text e-mail.
121
+ #
122
+ # Returns a string.
123
+ def to_plain_text
124
+ html_src = ''
125
+ begin
126
+ html_src = @doc.search("body").innerHTML
127
+ rescue
128
+ html_src = @doc.to_html
129
+ end
130
+ convert_to_text(html_src, @options[:line_length], @html_charset)
131
+ end
132
+
133
+ # Merge CSS into the HTML document.
134
+ #
135
+ # Returns a string.
136
+ def to_inline_css
137
+ doc = @processed_doc
138
+ unmergable_rules = CssParser::Parser.new
139
+
140
+ # Give all styles already in style attributes a specificity of 1000
141
+ # per http://www.w3.org/TR/CSS21/cascade.html#specificity
142
+ doc.search("*[@style]").each do |el|
143
+ el['style'] = '[SPEC=1000[' + el.attributes['style'] + ']]'
144
+ end
145
+
146
+ # Iterate through the rules and merge them into the HTML
147
+ @css_parser.each_selector(:all) do |selector, declaration, specificity|
148
+ # Save un-mergable rules separately
149
+ selector.gsub!(/:link([\s]|$)+/i, '')
150
+
151
+ # Convert element names to lower case
152
+ selector.gsub!(/([\s]|^)([\w]+)/) {|m| $1.to_s + $2.to_s.downcase }
153
+
154
+ if selector =~ RE_UNMERGABLE_SELECTORS
155
+ unmergable_rules.add_rule_set!(RuleSet.new(selector, declaration))
156
+ else
157
+
158
+ doc.search(selector) do |el|
159
+ if el.elem?
160
+ # Add a style attribute or append to the existing one
161
+ block = "[SPEC=#{specificity}[#{declaration}]]"
162
+ el['style'] = (el.attributes['style'] ||= '') + ' ' + block
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ # Read <style> attributes and perform folding
169
+ doc.search("*[@style]").each do |el|
170
+ style = el.attributes['style'].to_s
171
+
172
+ declarations = []
173
+
174
+ style.scan(/\[SPEC\=([\d]+)\[(.[^\]\]]*)\]\]/).each do |declaration|
175
+ rs = RuleSet.new(nil, declaration[1].to_s, declaration[0].to_i)
176
+ declarations << rs
177
+ end
178
+
179
+ # Perform style folding and save
180
+ merged = CssParser.merge(declarations)
181
+
182
+ el['style'] = Premailer.escape_string(merged.declarations_to_s)
183
+ end
184
+
185
+ doc = write_unmergable_css_rules(doc, unmergable_rules)
186
+
187
+ doc.search('*').remove_class if @options[:remove_classes]
188
+
189
+ @processed_doc = doc
190
+
191
+ doc.to_html
192
+ end
193
+
194
+
195
+ protected
196
+ # Load the HTML file and convert it into an Hpricot document.
197
+ #
198
+ # Returns an Hpricot document and a string with the HTML file's character set.
199
+ def load_html(path) # :nodoc:
200
+ if path.is_a?(IO) || path.is_a?(StringIO)
201
+ @html_file = "http://foo.bar"
202
+ Hpricot(path.read)
203
+ elsif @is_local_file
204
+ Hpricot(File.open(path, "r") {|f| f.read })
205
+ else
206
+ Hpricot(open(path))
207
+ end
208
+ end
209
+
210
+ # Load CSS included in <tt>style</tt> and <tt>link</tt> tags from an HTML document.
211
+ def load_css_from_html! # :nodoc:
212
+ if tags = @doc.search("link[@rel='stylesheet'], style")
213
+ tags.each do |tag|
214
+
215
+ if tag.to_s.strip =~ /^\<link/i and tag.attributes['href'] and media_type_ok?(tag.attributes['media'])
216
+
217
+ link_uri = Premailer.resolve_link(tag.attributes['href'].to_s, @html_file)
218
+ if @is_local_file
219
+ css_block = ''
220
+ begin
221
+ File.open(link_uri, "r") do |file|
222
+ while line = file.gets
223
+ css_block << line
224
+ end
225
+ end
226
+ @css_parser.add_block!(css_block, {:base_uri => @html_file})
227
+ rescue; end
228
+ else
229
+ @css_parser.load_uri!(link_uri)
230
+ end
231
+
232
+ elsif tag.to_s.strip =~ /^\<style/i
233
+ @css_parser.add_block!(tag.innerHTML, :base_uri => URI.parse(@html_file))
234
+ end
235
+ end
236
+ tags.remove
237
+ end
238
+ end
239
+
240
+ def media_type_ok?(media_types) # :nodoc:
241
+ return true if media_types.nil? or media_types.empty?
242
+ return media_types.split(/[\s]+|,/).any? { |media_type| media_type.strip =~ /screen|handheld|all/i }
243
+ rescue
244
+ return true
245
+ end
246
+
247
+ # Create a <tt>style</tt> element with un-mergable rules (e.g. <tt>:hover</tt>)
248
+ # and write it into the <tt>body</tt>.
249
+ #
250
+ # <tt>doc</tt> is an Hpricot document and <tt>unmergable_css_rules</tt> is a Css::RuleSet.
251
+ #
252
+ # Returns an Hpricot document.
253
+ def write_unmergable_css_rules(doc, unmergable_rules) # :nodoc:
254
+ styles = ''
255
+ unmergable_rules.each_selector(:all, :force_important => true) do |selector, declarations, specificity|
256
+ styles += "#{selector} { #{declarations} }\n"
257
+ end
258
+
259
+ unless styles.empty?
260
+ style_tag = "\n<style type=\"text/css\">\n#{styles}</style>\n"
261
+ doc.search("head").append(style_tag)
262
+ end
263
+ doc
264
+ end
265
+
266
+ # Convert relative links to absolute links.
267
+ #
268
+ # Processes <tt>href</tt> <tt>src</tt> and <tt>background</tt> attributes
269
+ # as well as CSS <tt>url()</tt> declarations found in inline <tt>style</tt> attributes.
270
+ #
271
+ # <tt>doc</tt> is an Hpricot document and <tt>base_uri</tt> is either a string or a URI.
272
+ #
273
+ # Returns an Hpricot document.
274
+ def convert_inline_links(doc, base_uri) # :nodoc:
275
+ base_uri = URI.parse(base_uri) unless base_uri.kind_of?(URI)
276
+
277
+ append_qs = @options[:link_query_string] ||= ''
278
+
279
+ ['href', 'src', 'background'].each do |attribute|
280
+ tags = doc.search("*[@#{attribute}]")
281
+
282
+ next if tags.empty?
283
+
284
+ tags.each do |tag|
285
+ # skip links that look like they have merge tags
286
+ # and mailto, ftp, etc...
287
+ if tag.attributes[attribute] =~ /^(\{|\[|<|\#|mailto:|ftp:|gopher:)/i
288
+ next
289
+ end
290
+
291
+ if tag.attributes[attribute] =~ /^http/i
292
+ begin
293
+ merged = URI.parse(tag.attributes[attribute])
294
+ rescue; next; end
295
+ else
296
+ begin
297
+ merged = Premailer.resolve_link(tag.attributes[attribute].to_s, base_uri)
298
+ rescue
299
+ begin
300
+ merged = Premailer.resolve_link(URI.escape(tag.attributes[attribute].to_s), base_uri)
301
+ rescue; end
302
+ end
303
+ end
304
+
305
+ # make sure 'merged' is a URI
306
+ merged = URI.parse(merged.to_s) unless merged.kind_of?(URI)
307
+
308
+ # only append a querystring to <a> tags
309
+ if tag.name =~ /^a$/i and not append_qs.empty?
310
+ if merged.query
311
+ merged.query = merged.query + '&' + append_qs
312
+ else
313
+ merged.query = append_qs
314
+ end
315
+ end
316
+ tag[attribute] = merged.to_s
317
+
318
+ end # end of each tag
319
+ end # end of each attrs
320
+
321
+ doc.search("*[@style]").each do |el|
322
+ el['style'] = CssParser.convert_uris(el.attributes['style'].to_s, base_uri)
323
+ end
324
+ doc
325
+ end
326
+
327
+ def self.escape_string(str) # :nodoc:
328
+ str.gsub(/"/, "'")
329
+ end
330
+
331
+ def self.resolve_link(path, base_path) # :nodoc:
332
+ resolved = nil
333
+ if base_path.kind_of?(URI)
334
+ resolved = base_path.merge(path)
335
+ return Premailer.canonicalize(resolved)
336
+ elsif base_path.kind_of?(String) and base_path =~ /^(http[s]?|ftp):\/\//i
337
+ resolved = URI.parse(base_path)
338
+ resolved = resolved.merge(path)
339
+ return Premailer.canonicalize(resolved)
340
+ else
341
+
342
+ return File.expand_path(path, File.dirname(base_path))
343
+ end
344
+ end
345
+
346
+ # from http://www.ruby-forum.com/topic/140101
347
+ def self.canonicalize(uri) # :nodoc:
348
+ u = uri.kind_of?(URI) ? uri : URI.parse(uri.to_s)
349
+ u.normalize!
350
+ newpath = u.path
351
+ while newpath.gsub!(%r{([^/]+)/\.\./?}) { |match|
352
+ $1 == '..' ? match : ''
353
+ } do end
354
+ newpath = newpath.gsub(%r{/\./}, '/').sub(%r{/\.\z}, '/')
355
+ u.path = newpath
356
+ u.to_s
357
+ end
358
+
359
+ # Check <tt>CLIENT_SUPPORT_FILE</tt> for any CSS warnings
360
+ def check_client_support # :nodoc:
361
+ @client_support = @client_support ||= YAML::load(File.open(CLIENT_SUPPORT_FILE))
362
+
363
+ warnings = []
364
+ properties = []
365
+
366
+ # Get a list off CSS properties
367
+ @processed_doc.search("*[@style]").each do |el|
368
+ style_url = el.attributes['style'].gsub(/([\w\-]+)[\s]*\:/i) do |s|
369
+ properties.push($1)
370
+ end
371
+ end
372
+
373
+ properties.uniq!
374
+
375
+ property_support = @client_support['css_properties']
376
+ properties.each do |prop|
377
+ if property_support.include?(prop) and
378
+ property_support[prop].include?('support') and
379
+ property_support[prop]['support'] >= @options[:warn_level]
380
+ warnings.push({:message => "#{prop} CSS property",
381
+ :level => WARN_LABEL[property_support[prop]['support']],
382
+ :clients => property_support[prop]['unsupported_in'].join(', ')})
383
+ end
384
+ end
385
+
386
+ @client_support['attributes'].each do |attribute, data|
387
+ next unless data['support'] >= @options[:warn_level]
388
+ if @doc.search("*[@#{attribute}]").length > 0
389
+ warnings.push({:message => "#{attribute} HTML attribute",
390
+ :level => WARN_LABEL[property_support[prop]['support']],
391
+ :clients => property_support[prop]['unsupported_in'].join(', ')})
392
+ end
393
+ end
394
+
395
+ @client_support['elements'].each do |element, data|
396
+ next unless data['support'] >= @options[:warn_level]
397
+ if @doc.search("element").length > 0
398
+ warnings.push({:message => "#{element} HTML element",
399
+ :level => WARN_LABEL[property_support[prop]['support']],
400
+ :clients => property_support[prop]['unsupported_in'].join(', ')})
401
+ end
402
+ end
403
+
404
+ return warnings
405
+ end
406
+ end
407
+
408
+
409
+
data/packrat.gemspec ADDED
@@ -0,0 +1,57 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{packrat}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Mike Hansen"]
12
+ s.date = %q{2010-10-18}
13
+ s.description = %q{Packrat is a gem for merging all css rules to inline for html emails and files.}
14
+ s.email = %q{indyjones805@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/packrat.rb",
27
+ "lib/packrat/view_helpers.rb",
28
+ "lib/premailer/html_to_plain_text.rb",
29
+ "lib/premailer/premailer.rb",
30
+ "packrat.gemspec",
31
+ "test/helper.rb",
32
+ "test/test_packrat.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/mikehansen/packrat}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.6}
38
+ s.summary = %q{Packrat is a gem for merging all css rules to inline for html emails and files.}
39
+ s.test_files = [
40
+ "test/helper.rb",
41
+ "test/test_packrat.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
55
+ end
56
+ end
57
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'packrat'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestPackrat < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: packrat
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Mike Hansen
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-10-18 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: thoughtbot-shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: Packrat is a gem for merging all css rules to inline for html emails and files.
33
+ email: indyjones805@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - LICENSE
40
+ - README.rdoc
41
+ files:
42
+ - .document
43
+ - .gitignore
44
+ - LICENSE
45
+ - README.rdoc
46
+ - Rakefile
47
+ - VERSION
48
+ - lib/packrat.rb
49
+ - lib/packrat/view_helpers.rb
50
+ - lib/premailer/html_to_plain_text.rb
51
+ - lib/premailer/premailer.rb
52
+ - packrat.gemspec
53
+ - test/helper.rb
54
+ - test/test_packrat.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/mikehansen/packrat
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.6
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Packrat is a gem for merging all css rules to inline for html emails and files.
85
+ test_files:
86
+ - test/helper.rb
87
+ - test/test_packrat.rb