assert_valid_html 0.1.0

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