packrat 0.1.0

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/.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