headhunter 0.1.4 → 0.1.5
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +5 -0
- data/lib/headhunter/css_hunter.rb +36 -64
- data/lib/headhunter/css_validator.rb +88 -139
- data/lib/headhunter/html_validator.rb +26 -33
- data/lib/headhunter/rack/capturing_middleware.rb +1 -1
- data/lib/headhunter/runner.rb +9 -9
- data/lib/headhunter/version.rb +1 -1
- data/lib/tidy/tidy +0 -0
- metadata +3 -3
- data/lib/headhunter/local_response.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14ca57c35b2c4f399b3f3d3a475489f9ae3b50fc
|
4
|
+
data.tar.gz: 8d3fe32d258b3952fe649ff35d375635ad162afc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3478cf3aac060a39857d989640622f6b0eeaea7ead4fb1add028c4513336ce38e972a4a6ce757864b2b6ae7a7c9c91a821c61a468fea6917cbb7a5d825dc384e
|
7
|
+
data.tar.gz: f9861651aeed1cc736d042ab0f86d567b6c5b0ea3c8522fb05825e641c8907c34972b9fde3c82845cf311614468c400a79c7aa4e9e8958b7de62398980b9ede6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -6,6 +6,8 @@
|
|
6
6
|
[](https://codeclimate.com/github/jmuheim/headhunter)
|
7
7
|
[](https://travis-ci.org/jmuheim/headhunter)
|
8
8
|
[](https://bitdeli.com/free "Bitdeli Badge")
|
9
|
+
[](https://gemnasium.com/jmuheim/headhunter)
|
10
|
+
[](https://coveralls.io/r/jmuheim/headhunter)
|
9
11
|
|
10
12
|
Headhunter is an HTML and CSS validation tool that injects itself into your Rails feature tests and auto<strong>magic</strong>ally checks all your generated HTML and CSS for validity.
|
11
13
|
|
@@ -59,8 +61,11 @@ You need a **Java Runtime Environment** to run CSS validation. This should norma
|
|
59
61
|
- In feature tests, the same views are getting rendered again and again. These same sources shouldn't be validated over and over again!
|
60
62
|
- More configuration options needed! CSS1, CSS2, CSS2.1, CSS3! XHTML, HTML5, etc.
|
61
63
|
- Better output needed! With context lines, etc.
|
64
|
+
- HTML output: info about GET/POST/PUT/DELETE!
|
62
65
|
- Look out for multiple used IDs on the same page and raise error!
|
63
66
|
- Look out for invalid tags and raise error (tidy doesn't seem to do this?!)!
|
67
|
+
- Cache HTML validations: use MD5 to prevent validating the same source again and again! (Maybe even keep the cache between running specs!)
|
68
|
+
- Add option to CssHunter that ignores "bare" rules like applet, blockquote, etc. (which usually stem from libraries like Compass reset or Normalize)
|
64
69
|
|
65
70
|
## Disclaimer
|
66
71
|
|
@@ -1,104 +1,76 @@
|
|
1
1
|
require 'css_parser'
|
2
2
|
require 'nokogiri'
|
3
|
-
require 'open-uri'
|
4
3
|
|
5
4
|
module Headhunter
|
6
5
|
class CssHunter
|
7
|
-
|
6
|
+
attr_reader :unused_selectors, :used_selectors, :error_selectors
|
7
|
+
|
8
|
+
def initialize(stylesheets = [])
|
8
9
|
@stylesheets = stylesheets
|
9
|
-
@parsed_rules = {}
|
10
10
|
@unused_selectors = []
|
11
11
|
@used_selectors = []
|
12
12
|
@error_selectors = []
|
13
13
|
|
14
|
-
|
14
|
+
@stylesheets.each do |stylesheet|
|
15
|
+
add_css_selectors_from(IO.read(stylesheet))
|
16
|
+
end
|
15
17
|
end
|
16
18
|
|
17
|
-
def process
|
18
|
-
|
19
|
+
def process(html)
|
20
|
+
detect_used_selectors_in(html).each do |selector|
|
21
|
+
@used_selectors << selector
|
19
22
|
@unused_selectors.delete(selector)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
|
-
def
|
24
|
-
|
25
|
-
puts "#{@used_selectors.size} selectors are in use.".green if @used_selectors.size > 0
|
26
|
-
puts "#{@unused_selectors.size} selectors are not in use: #{@unused_selectors.sort.join(', ').red}".red if @unused_selectors.size > 0
|
27
|
-
puts "#{@error_selectors.size} selectors could not be parsed: #{@error_selectors.sort.join(', ').red}".red if @unused_selectors.size > 0
|
28
|
-
puts
|
29
|
-
end
|
26
|
+
def statistics
|
27
|
+
lines = []
|
30
28
|
|
31
|
-
|
29
|
+
lines << "Found #{used_selectors.size + unused_selectors.size + error_selectors.size} CSS selectors.".yellow
|
30
|
+
lines << 'All selectors are in use.'.green if unused_selectors.size + error_selectors.size == 0
|
31
|
+
lines << "#{unused_selectors.size} selectors are not in use: #{unused_selectors.sort.join(', ').red}".red if unused_selectors.size > 0
|
32
|
+
lines << "#{error_selectors.size} selectors could not be parsed: #{error_selectors.sort.join(', ').red}".red if error_selectors.size > 0
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
lines.join("\n")
|
35
|
+
end
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
# but we report on the selector with its pseudo classes.
|
39
|
-
stripped_selector = strip(selector)
|
37
|
+
def detect_used_selectors_in(html)
|
38
|
+
document = Nokogiri::HTML(html)
|
40
39
|
|
41
|
-
|
40
|
+
@unused_selectors.collect do |selector, declarations|
|
41
|
+
bare_selector = bare_selector_from(selector)
|
42
42
|
|
43
43
|
begin
|
44
|
-
if
|
45
|
-
@used_selectors << selector
|
46
|
-
selector
|
47
|
-
end
|
44
|
+
selector if document.search(bare_selector).any?
|
48
45
|
rescue Nokogiri::CSS::SyntaxError => e
|
49
46
|
@error_selectors << selector
|
47
|
+
@unused_selectors.delete(selector)
|
50
48
|
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def load_css!
|
55
|
-
@stylesheets.each do |stylesheet|
|
56
|
-
new_selector_count = add_css!(fetch(stylesheet))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def fetch(path)
|
61
|
-
loc = path
|
62
|
-
|
63
|
-
begin
|
64
|
-
open(loc).read
|
65
|
-
rescue Errno::ENOENT
|
66
|
-
raise FetchError.new("#{loc} was not found")
|
67
|
-
rescue OpenURI::HTTPError => e
|
68
|
-
raise FetchError.new("retrieving #{loc} raised an HTTP error: #{e.message}")
|
69
|
-
end
|
49
|
+
end.compact # FIXME: Why is compact needed?
|
70
50
|
end
|
71
51
|
|
72
|
-
def
|
52
|
+
def add_css_selectors_from(css)
|
73
53
|
parser = CssParser::Parser.new
|
74
54
|
parser.add_block!(css)
|
75
55
|
|
76
|
-
selector_count = 0
|
77
|
-
|
78
56
|
parser.each_selector do |selector, declarations, specificity|
|
79
|
-
next if @unused_selectors.include?(selector)
|
80
|
-
next if selector
|
81
|
-
next if has_pseudo_classes(selector) and @unused_selectors.include?(strip(selector))
|
82
|
-
|
57
|
+
# next if @unused_selectors.include?(selector)
|
58
|
+
# next if has_pseudo_classes?(selector) and @unused_selectors.include?(bare_selector_from(selector))
|
83
59
|
@unused_selectors << selector
|
84
|
-
@parsed_rules[selector] = declarations
|
85
|
-
|
86
|
-
selector_count += 1
|
87
60
|
end
|
88
|
-
|
89
|
-
selector_count
|
90
61
|
end
|
91
62
|
|
92
|
-
def has_pseudo_classes(selector)
|
93
|
-
|
63
|
+
# def has_pseudo_classes?(selector)
|
64
|
+
# selector =~ /::?[\w\-]+/
|
65
|
+
# end
|
66
|
+
|
67
|
+
def bare_selector_from(selector)
|
68
|
+
# Add more clean up stuff here, e.g. stuff like @keyframe (Deadweight implemented this)?
|
69
|
+
remove_pseudo_classes_from(selector)
|
94
70
|
end
|
95
71
|
|
96
|
-
def
|
97
|
-
selector
|
98
|
-
selector = selector.gsub(/:.*/, '') # input#x:nth-child(2):not(#z.o[type='file'])
|
99
|
-
selector
|
72
|
+
def remove_pseudo_classes_from(selector)
|
73
|
+
selector.gsub(/:.*/, '') # input#x:nth-child(2):not(#z.o[type='file'])
|
100
74
|
end
|
101
75
|
end
|
102
|
-
|
103
|
-
class FetchError < StandardError; end
|
104
76
|
end
|
@@ -1,73 +1,65 @@
|
|
1
1
|
require 'net/http'
|
2
|
-
require '
|
2
|
+
require 'nokogiri/xml'
|
3
3
|
|
4
4
|
module Headhunter
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(body)
|
9
|
-
@body = body
|
10
|
-
@headers = {'x-w3c-validator-status' => valid?(body)}
|
11
|
-
end
|
5
|
+
class CssValidator
|
6
|
+
VALIDATOR_PATH = Gem.loaded_specs['headhunter'].full_gem_path + '/lib/css-validator/'
|
12
7
|
|
13
|
-
|
14
|
-
@headers[key]
|
15
|
-
end
|
8
|
+
attr_reader :stylesheets, :responses
|
16
9
|
|
17
|
-
|
10
|
+
def initialize(stylesheets = [], profile = 'css3', vextwarning = true)
|
11
|
+
@stylesheets = stylesheets
|
12
|
+
@profile = profile # TODO!
|
13
|
+
@vextwarning = vextwarning # TODO!
|
18
14
|
|
19
|
-
|
20
|
-
|
15
|
+
@responses = @stylesheets.map do |stylesheet|
|
16
|
+
validate(stylesheet)
|
17
|
+
end
|
21
18
|
end
|
22
|
-
end
|
23
19
|
|
24
|
-
|
25
|
-
|
20
|
+
def validate(uri)
|
21
|
+
# See http://stackoverflow.com/questions/1137884/is-there-an-open-source-css-validator-that-can-be-run-locally
|
22
|
+
# More config options see http://jigsaw.w3.org/css-validator/manual.html
|
23
|
+
results = if File.exists?(uri)
|
24
|
+
Dir.chdir(VALIDATOR_PATH) { `java -jar css-validator.jar --output=soap12 file:#{uri}` }
|
25
|
+
else
|
26
|
+
raise "Couldn't locate uri #{uri}"
|
27
|
+
end
|
26
28
|
|
27
|
-
|
28
|
-
@profile = 'css3' # TODO: Option for profile css1 and css21
|
29
|
-
@stylesheets = stylesheets
|
30
|
-
@messages_per_stylesheet = {}
|
29
|
+
Response.new(results)
|
31
30
|
end
|
32
31
|
|
33
|
-
def
|
34
|
-
@
|
32
|
+
def valid_responses
|
33
|
+
@responses.select(&:valid?)
|
35
34
|
end
|
36
35
|
|
37
|
-
def
|
38
|
-
@
|
39
|
-
css = fetch(stylesheet)
|
40
|
-
css = ' ' if css.empty? # The validator returns a 500 error if it receives an empty string
|
41
|
-
|
42
|
-
response = get_validation_response({text: css, profile: @profile, vextwarning: 'true'})
|
43
|
-
unless response_indicates_valid?(response)
|
44
|
-
process_errors(stylesheet, css, response)
|
45
|
-
end
|
46
|
-
end
|
36
|
+
def invalid_responses
|
37
|
+
@responses.reject(&:valid?)
|
47
38
|
end
|
48
39
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
40
|
+
def statistics
|
41
|
+
lines = []
|
42
|
+
|
43
|
+
lines << "Validated #{responses.size} stylesheets.".yellow
|
44
|
+
lines << "All stylesheets are valid.".green if invalid_responses.size == 0
|
45
|
+
lines << "#{x_stylesheets_be(invalid_responses.size)} invalid.".red if invalid_responses.size > 0
|
53
46
|
|
54
|
-
|
55
|
-
|
47
|
+
invalid_responses.each do |response|
|
48
|
+
lines << " #{extract_filename(response.uri)}:".red
|
56
49
|
|
57
|
-
|
50
|
+
response.errors.each do |error|
|
51
|
+
lines << " - #{error.to_s}".red
|
52
|
+
end
|
58
53
|
end
|
59
54
|
|
60
|
-
|
55
|
+
lines.join("\n")
|
61
56
|
end
|
62
57
|
|
63
|
-
private
|
64
|
-
|
65
|
-
# Converts a path like public/assets/application-d205d6f344d8623ca0323cb6f6bd7ca1.css to application.css
|
66
58
|
def extract_filename(path)
|
67
|
-
if matches = path.match(
|
68
|
-
matches[1] + matches[3]
|
59
|
+
if matches = path.match(/public\/assets\/([a-z\-_]*)-([a-z0-9]{32})(\.css)$/)
|
60
|
+
matches[1] + matches[3] # application-d205d6f344d8623ca0323cb6f6bd7ca1.css becomes application.css
|
69
61
|
else
|
70
|
-
|
62
|
+
File.basename(path)
|
71
63
|
end
|
72
64
|
end
|
73
65
|
|
@@ -79,115 +71,72 @@ module Headhunter
|
|
79
71
|
end
|
80
72
|
end
|
81
73
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
REXML::Document.new(response.body).root.each_element('//m:error') do |e|
|
86
|
-
@messages_per_stylesheet[file] << "Line #{extract_line_from_error(e)}: #{extract_message_from_error(e)}"
|
74
|
+
class Response
|
75
|
+
def initialize(response = nil)
|
76
|
+
@document = Nokogiri::XML(convert_soap_to_xml(response)) if response
|
87
77
|
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def extract_line_from_error(e)
|
91
|
-
e.elements['m:line'].text
|
92
|
-
end
|
93
78
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
def fetch(path) # TODO: Move to Headhunter!
|
99
|
-
loc = path
|
100
|
-
|
101
|
-
begin
|
102
|
-
open(loc).read
|
103
|
-
rescue Errno::ENOENT
|
104
|
-
raise FetchError.new("#{loc} was not found")
|
105
|
-
rescue OpenURI::HTTPError => e
|
106
|
-
raise FetchError.new("retrieving #{loc} raised an HTTP error: #{e.message}")
|
79
|
+
def [](key)
|
80
|
+
@headers[key]
|
107
81
|
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def get_validation_response(query_params)
|
111
|
-
query_params.merge!({:output => 'soap12'})
|
112
82
|
|
113
|
-
|
114
|
-
|
115
|
-
else
|
116
|
-
call_remote_validator(query_params)
|
83
|
+
def valid?
|
84
|
+
@document.css('validity').text == 'true'
|
117
85
|
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def response_indicates_valid?(response)
|
121
|
-
response['x-w3c-validator-status'] == 'Valid'
|
122
|
-
end
|
123
|
-
|
124
|
-
def call_remote_validator(query_params = {})
|
125
|
-
boundary = Digest::MD5.hexdigest(Time.now.to_s)
|
126
|
-
data = encode_multipart_params(boundary, query_params)
|
127
|
-
response = http_start(validator_host).post2(validator_path,
|
128
|
-
data,
|
129
|
-
'Content-type' => "multipart/form-data; boundary=#{boundary}")
|
130
86
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
Dir.chdir(path) do
|
142
|
-
File.open(css_file, 'a') { |f| f.write query_params[:text] }
|
143
|
-
|
144
|
-
# See http://stackoverflow.com/questions/1137884/is-there-an-open-source-css-validator-that-can-be-run-locally
|
145
|
-
if system "java -jar css-validator.jar --output=soap12 file:#{css_file} > #{results_file}"
|
146
|
-
results = IO.read results_file
|
147
|
-
else
|
148
|
-
raise 'Could not execute local validation!'
|
87
|
+
def errors
|
88
|
+
@document.css('errors error').map do |error|
|
89
|
+
Error.new( error.css('line').text.strip.to_i,
|
90
|
+
error.css('message').text.strip[0..-3],
|
91
|
+
errortype: error.css('errortype').text.strip,
|
92
|
+
context: error.css('context').text.strip,
|
93
|
+
errorsubtype: error.css('errorsubtype').text.strip,
|
94
|
+
skippedstring: error.css('skippedstring').text.strip
|
95
|
+
)
|
149
96
|
end
|
97
|
+
end
|
150
98
|
|
151
|
-
|
152
|
-
|
99
|
+
def uri
|
100
|
+
@document.css('cssvalidationresponse > uri').text
|
153
101
|
end
|
154
102
|
|
155
|
-
|
156
|
-
end
|
103
|
+
private
|
157
104
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
ret << "\r\n--#{boundary}\r\n"
|
163
|
-
ret << "Content-Disposition: form-data; name=\"#{k.to_s}\"\r\n\r\n"
|
164
|
-
ret << v
|
165
|
-
end
|
105
|
+
def convert_soap_to_xml(soap)
|
106
|
+
sanitize_prefixed_tags_from(
|
107
|
+
remove_first_line_from(soap)
|
108
|
+
)
|
166
109
|
end
|
167
|
-
ret << "\r\n--#{boundary}--\r\n"
|
168
|
-
ret
|
169
|
-
end
|
170
110
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
111
|
+
# The first line of the validator's response contains parameter options like this:
|
112
|
+
#
|
113
|
+
# {vextwarning=false, output=soap, lang=en, warning=2, medium=all, profile=css3}
|
114
|
+
#
|
115
|
+
# We remove this so Nokogiri can parse the document as XML.
|
116
|
+
def remove_first_line_from(soap)
|
117
|
+
soap.split("\n")[1..-1].join("\n")
|
178
118
|
end
|
179
|
-
end
|
180
119
|
|
181
|
-
|
182
|
-
|
183
|
-
|
120
|
+
# The validator's response contains strange SOAP tags like `m:error` or `env:body` which need to be sanitized for Nokogiri.
|
121
|
+
#
|
122
|
+
# We simply remove the `m:` and `env:` prefixes from the source, so e.g. `<env:body>` becomes `<body>`.
|
123
|
+
def sanitize_prefixed_tags_from(soap)
|
124
|
+
soap.gsub /(m|env):/, ''
|
125
|
+
end
|
184
126
|
|
185
|
-
|
186
|
-
|
187
|
-
|
127
|
+
class Error
|
128
|
+
attr_reader :line, :message, :details
|
129
|
+
|
130
|
+
def initialize(line, message, details = {})
|
131
|
+
@line = line
|
132
|
+
@message = message
|
133
|
+
@details = details
|
134
|
+
end
|
188
135
|
|
189
|
-
|
190
|
-
|
136
|
+
def to_s
|
137
|
+
"Line #{@line}: #{@message}."
|
138
|
+
end
|
139
|
+
end
|
191
140
|
end
|
192
141
|
end
|
193
142
|
end
|
@@ -2,46 +2,43 @@ require 'html_validation'
|
|
2
2
|
|
3
3
|
module Headhunter
|
4
4
|
class HtmlValidator
|
5
|
+
attr_reader :responses
|
6
|
+
|
5
7
|
def initialize
|
6
|
-
@
|
7
|
-
@invalid_results = []
|
8
|
+
@responses = []
|
8
9
|
end
|
9
10
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
11
|
+
def validate(url, html)
|
12
|
+
# Docs for Tidy: http://tidy.sourceforge.net/docs/quickref.html
|
13
|
+
@responses << PageValidations::HTMLValidation.new.validation(html, url)
|
14
|
+
@responses.last
|
13
15
|
end
|
14
16
|
|
15
|
-
def
|
16
|
-
|
17
|
-
html.gsub! '{{VALID_RESULTS}}', prepare_results_for(@valid_results)
|
18
|
-
html.gsub! '{{INVALID_RESULTS}}', prepare_results_for(@invalid_results)
|
19
|
-
File.open('.validation/results.html', 'w') { |file| file.write(html) }
|
17
|
+
def valid_responses
|
18
|
+
@responses.select(&:valid?)
|
20
19
|
end
|
21
20
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
21
|
+
def invalid_responses
|
22
|
+
@responses.reject(&:valid?)
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
full_result_html.gsub! '{{EXCEPTIONS}}', exceptions_html
|
29
|
-
full_result_html.gsub! '{{HTML_CONTEXT}}', 'context'
|
30
|
-
full_result_html.gsub! '{{LINK}}', "#{result.resource}.html.txt"
|
25
|
+
def statistics
|
26
|
+
lines = []
|
31
27
|
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
lines << "Validated #{responses.size} pages.".yellow
|
29
|
+
lines << "All pages are valid.".green if invalid_responses.size == 0
|
30
|
+
lines << "#{x_pages_be(invalid_responses.size)} invalid.".red if invalid_responses.size > 0
|
35
31
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
invalid_responses.each do |response|
|
33
|
+
lines << " #{response.resource}:".red
|
34
|
+
|
35
|
+
([response.exceptions].flatten).each do |exception|
|
36
|
+
lines << " - #{exception.strip}".red
|
37
|
+
end
|
38
|
+
end
|
43
39
|
|
44
|
-
|
40
|
+
lines.join("\n")
|
41
|
+
end
|
45
42
|
|
46
43
|
def x_pages_be(size)
|
47
44
|
if size <= 1
|
@@ -50,9 +47,5 @@ module Headhunter
|
|
50
47
|
"#{size} pages are"
|
51
48
|
end
|
52
49
|
end
|
53
|
-
|
54
|
-
def random_name
|
55
|
-
(0...8).map { (65 + rand(26)).chr }.join
|
56
|
-
end
|
57
50
|
end
|
58
51
|
end
|
data/lib/headhunter/runner.rb
CHANGED
@@ -16,12 +16,11 @@ module Headhunter
|
|
16
16
|
@css_hunter = CssHunter.new(stylesheets)
|
17
17
|
|
18
18
|
@css_validator = CssValidator.new(stylesheets)
|
19
|
-
@css_validator.process!
|
20
19
|
end
|
21
20
|
|
22
|
-
def process
|
23
|
-
@html_validator.
|
24
|
-
@css_hunter.process
|
21
|
+
def process(url, html)
|
22
|
+
@html_validator.validate(url, html)
|
23
|
+
@css_hunter.process(url, html)
|
25
24
|
end
|
26
25
|
|
27
26
|
def clean_up!
|
@@ -31,11 +30,12 @@ module Headhunter
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def report
|
34
|
-
@html_validator.
|
33
|
+
puts [ @html_validator.statistics,
|
34
|
+
@css_validator.statistics,
|
35
|
+
@css_hunter.statistics
|
36
|
+
].join "\n\n"
|
35
37
|
|
36
|
-
|
37
|
-
@css_validator.report
|
38
|
-
@css_hunter.report
|
38
|
+
puts
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
@@ -58,7 +58,7 @@ module Headhunter
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def stylesheets
|
61
|
-
Dir["#{ASSETS_PATH}/*.css"]
|
61
|
+
Dir["#{::Rails.root}/#{ASSETS_PATH}/*.css"]
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
data/lib/headhunter/version.rb
CHANGED
data/lib/tidy/tidy
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: headhunter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Muheim
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -195,7 +195,6 @@ files:
|
|
195
195
|
- lib/headhunter/css_hunter.rb
|
196
196
|
- lib/headhunter/css_validator.rb
|
197
197
|
- lib/headhunter/html_validator.rb
|
198
|
-
- lib/headhunter/local_response.rb
|
199
198
|
- lib/headhunter/rack/capturing_middleware.rb
|
200
199
|
- lib/headhunter/rails.rb
|
201
200
|
- lib/headhunter/runner.rb
|
@@ -203,6 +202,7 @@ files:
|
|
203
202
|
- lib/headhunter/templates/results.html
|
204
203
|
- lib/headhunter/version.rb
|
205
204
|
- lib/headhunter.rb
|
205
|
+
- lib/tidy/tidy
|
206
206
|
- Gemfile
|
207
207
|
- Gemfile.lock
|
208
208
|
- Rakefile
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'rexml/document'
|
2
|
-
|
3
|
-
module Headhunter
|
4
|
-
class LocalResponse
|
5
|
-
attr_reader :body
|
6
|
-
|
7
|
-
def initialize(body)
|
8
|
-
@body = body
|
9
|
-
@headers = {'x-w3c-validator-status' => valid?}
|
10
|
-
end
|
11
|
-
|
12
|
-
def [](key)
|
13
|
-
@headers[key]
|
14
|
-
end
|
15
|
-
|
16
|
-
def valid?
|
17
|
-
REXML::Document.new(@body).root.each_element('//m:validity') { |e| return e.text == 'true' }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|