assert_valid_html 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.
@@ -0,0 +1,8 @@
1
+ require "assert_valid_html"
2
+ require "assert_valid_html/test"
3
+ require "rails"
4
+
5
+ module AssertValidHtml
6
+ class Railtie < Rails::Railtie
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ class ActionController::TestCase
2
+ def assert_valid_html
3
+ return unless @response.headers['Content-Type'].match(/html/)
4
+
5
+ validator = AssertValidHtml::Validator.new(@response.body)
6
+ assert_block(validator.message){ validator.valid? }
7
+ end
8
+
9
+ alias_method :assert_valid_markup, :assert_valid_html
10
+ end
@@ -0,0 +1,93 @@
1
+ require "open3"
2
+
3
+ module AssertValidHtml
4
+ class Validator
5
+ ValidationError = Struct.new(:message, :line, :context)
6
+
7
+ ALLOWED_ATTRIBUTES = %w[
8
+ media hreflang rel target value charset autofocus placeholder form
9
+ required disabled autocomplete min max multiple pattern step list
10
+ novalidate formaction formenctype formmethod formnovalidate formtarget
11
+ type label contextmenu scoped async manifest sizes reversed sandbox
12
+ seamless srcdoc contenteditable draggable hidden role data-\\S* aria-\\S*
13
+ spellcheck
14
+ ]
15
+
16
+ ALLOWED_ELEMENTS = %w[
17
+ section article aside hgroup header footer nav figure figcaption video
18
+ audio source embed progress meter time ruby rt rp wbr canvas command
19
+ details datalist keygen output
20
+ ]
21
+
22
+ IGNORED = [
23
+ /Warning: trimming empty/,
24
+ /lacks "summary" attribute/,
25
+ /<meta> lacks "content" attribute/, # HTML5
26
+ /proprietary attribute "xmlns:fb"/, # Facebook
27
+ /<\/?fb:/ # //
28
+ ]
29
+
30
+ def self.ignore(regexp)
31
+ ignored << regexp
32
+ end
33
+
34
+ def self.ignored
35
+ @ignored ||= IGNORED.dup
36
+ end
37
+
38
+ def self.ignored_regexp
39
+ Regexp.new((ignored + [
40
+ %r{proprietary attribute "(?:#{ALLOWED_ATTRIBUTES.join("|")})"},
41
+ %r{discarding unexpected </?(?:#{ALLOWED_ELEMENTS.join("|")})>}
42
+ ]).join("|"))
43
+ end
44
+
45
+ def initialize(html)
46
+ @html = html
47
+ @lines = html.split(/\n/)
48
+ end
49
+
50
+ def valid?
51
+ errors.empty?
52
+ end
53
+
54
+ def errors
55
+ @errors ||= (
56
+ ignored = self.class.ignored_regexp
57
+ tidy(@html).split(/\n/).select {|w| w =~ /Warning/ && w !~ ignored }
58
+ ).inject([]){ |array, error|
59
+ line, message = parse_tidy_message(error)
60
+ array << ValidationError.new(message, line, context(line))
61
+ }
62
+ end
63
+
64
+ def context(line)
65
+ top = [0, line - 6].max
66
+ bottom = [[@lines.length - 1, 0].max, line + 4].min
67
+ (top..bottom).to_a.zip(@lines[top..bottom]).map{ |number, text|
68
+ "%s %3d | %s" % [number + 1 == line ? "*" : " ", number + 1, text]
69
+ }.join("\n")
70
+ end
71
+
72
+ def message
73
+ if valid?
74
+ "HTML is valid"
75
+ else
76
+ (["HTML is invalid"] + errors.map{ |e| e.message + "\n" + e.context }).join("\n\n")
77
+ end
78
+ end
79
+
80
+ private
81
+ def parse_tidy_message(error)
82
+ m = error.match(/^line (\d+) column (\d+) - (.*)/)
83
+ return m[1].to_i, "#{m[3]} at line #{m[1]} column #{m[2]}"
84
+ end
85
+
86
+ def tidy(html)
87
+ stdin, stdout, stderr = Open3.popen3("tidy -q -e -utf8")
88
+ stdin << html
89
+ stdin.close
90
+ stderr.read
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,9 @@
1
+ module AssertValidHtml
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ require 'assert_valid_html/railtie' if defined?(Rails)
2
+ require "assert_valid_html/validator"
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: assert_valid_html
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Paul Battley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-17 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description:
23
+ email: pbattley@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/assert_valid_html.rb
32
+ - lib/assert_valid_html/validator.rb
33
+ - lib/assert_valid_html/test.rb
34
+ - lib/assert_valid_html/version.rb
35
+ - lib/assert_valid_html/railtie.rb
36
+ has_rdoc: true
37
+ homepage:
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 3
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.3.7
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Check HTML validity without using an external web service
70
+ test_files: []
71
+