alexdunae-w3c_validators 1.0.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,110 @@
1
+ module W3CValidators
2
+ class FeedValidator < Validator
3
+ FEED_VALIDATOR_URI = 'http://validator.w3.org/feed/check.cgi'
4
+
5
+ # Create a new instance of the FeedValidator.
6
+ #
7
+ # ==== Options
8
+ # You can pass in your own validator's URI (i.e.
9
+ # <tt>FeedValidator.new(:validator_uri => 'http://localhost/check')</tt>).
10
+ def initialize(options = {})
11
+ if options[:validator_uri]
12
+ @validator_uri = URI.parse(options[:validator_uri])
13
+ options.delete(options[:validator_uri])
14
+ else
15
+ @validator_uri = URI.parse(FEED_VALIDATOR_URI)
16
+ end
17
+ super(options)
18
+ end
19
+
20
+ # Validate a feed URI using a +SOAP+ request.
21
+ #
22
+ # Returns W3CValidators::Results.
23
+ def validate_uri(url)
24
+ return validate({:url => url})
25
+ end
26
+
27
+ # Validate a feed from a string.
28
+ #
29
+ # Returns W3CValidators::Results.
30
+ def validate_text(text)
31
+ return validate({:rawdata => text})
32
+ end
33
+
34
+ # Validate a local feed file.
35
+ #
36
+ # +file_path+ may be either the fully-expanded path to the file or
37
+ # an IO object (like File).
38
+ #
39
+ # Returns W3CValidators::Results.
40
+ def validate_file(file_path)
41
+ if file_path.respond_to? :read
42
+ src = file_path.read
43
+ else
44
+ src = read_local_file(file_path)
45
+ end
46
+ return validate_text(src)
47
+ end
48
+
49
+ protected
50
+ def validate(options) # :nodoc:
51
+ options = get_request_options(options)
52
+ response = send_request(options, :get)
53
+ @results = parse_soap_response(response.body)
54
+ @results
55
+ end
56
+
57
+ # Perform sanity checks on request params
58
+ def get_request_options(options) # :nodoc:
59
+ options = @options.merge(options)
60
+
61
+ options[:output] = SOAP_OUTPUT_PARAM
62
+
63
+ unless options[:url] or options[:rawdata]
64
+ raise ArgumentError, "an url or rawdata is required."
65
+ end
66
+
67
+ # URL should be a string. If it is a URL object, .to_s will
68
+ # be seamless; if it is not an exception will be raised.
69
+ if options[:url] and not options[:url].kind_of?(String)
70
+ options[:url] = options[:url].to_s
71
+ end
72
+
73
+ options
74
+ end
75
+
76
+ # Parse the SOAP XML response.
77
+ #
78
+ # +response+ must be a Net::HTTPResponse.
79
+ #
80
+ # Returns W3CValidators::Results.
81
+ def parse_soap_response(response) # :nodoc:
82
+ doc = REXML::Document.new(response)
83
+
84
+ result_params = {}
85
+
86
+ {:uri => 'uri', :checked_by => 'checkedby', :validity => 'validity'}.each do |local_key, remote_key|
87
+ if val = doc.elements["//*[local-name()='feedvalidationresponse']/*[local-name()='#{remote_key.to_s}']"]
88
+ result_params[local_key] = val.text
89
+ end
90
+ end
91
+
92
+ results = Results.new(result_params)
93
+
94
+ [:warning, :error].each do |msg_type|
95
+ doc.elements.each("//*[local-name()='#{msg_type.to_s}']") do |message|
96
+ message_params = {}
97
+ message.each_element_with_text do |el|
98
+ message_params[el.name.to_sym] = el.text
99
+ end
100
+ results.add_message(msg_type, message_params)
101
+ end
102
+ end
103
+
104
+ return results
105
+
106
+ rescue Exception => e
107
+ handle_exception e
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,227 @@
1
+ module W3CValidators
2
+ class MarkupValidator < Validator
3
+ MARKUP_VALIDATOR_URI = 'http://validator.w3.org/check'
4
+
5
+ # Create a new instance of the MarkupValidator.
6
+ #
7
+ # ==== Options
8
+ # The +options+ hash allows you to set request parameters (see
9
+ # http://validator.w3.org/docs/api.html#requestformat) quickly. Request
10
+ # parameters can also be set using set_charset!, set_debug! and set_doctype!.
11
+ #
12
+ # You can pass in your own validator's URI (i.e.
13
+ # <tt>MarkupValidator.new(:validator_uri => 'http://localhost/check')</tt>).
14
+ def initialize(options = {})
15
+ if options[:validator_uri]
16
+ @validator_uri = URI.parse(options[:validator_uri])
17
+ options.delete(options[:validator_uri])
18
+ else
19
+ @validator_uri = URI.parse(MARKUP_VALIDATOR_URI)
20
+ end
21
+ super(options)
22
+ end
23
+
24
+ # Specify the character encoding to use when parsing the document.
25
+ #
26
+ # When +only_as_fallback+ is +true+, the given encoding will only be
27
+ # used as a fallback value, in case the +charset+ is absent or unrecognized.
28
+ #
29
+ # +charset+ can be a string (e.g. <tt>set_charset!('utf-8')</tt>) or
30
+ # a symbol (e.g. <tt>set_charset!(:utf_8)</tt>) from the
31
+ # W3CValidators::CHARSETS hash.
32
+ #
33
+ # Has no effect when using validate_uri_quickly.
34
+ def set_charset!(charset, only_as_fallback = false)
35
+ if charset.kind_of?(Symbol)
36
+ if CHARSETS.has_key?(charset)
37
+ charset = CHARSETS[charset]
38
+ else
39
+ return
40
+ end
41
+ end
42
+ @options[:charset] = charset
43
+ @options[:fbc] = only_as_fallback
44
+ end
45
+
46
+ # Specify the Document Type (+DOCTYPE+) to use when parsing the document.
47
+ #
48
+ # When +only_as_fallback+ is +true+, the given document type will only be
49
+ # used as a fallback value, in case the document's +DOCTYPE+ declaration
50
+ # is missing or unrecognized.
51
+ #
52
+ # +doctype+ can be a string (e.g. <tt>set_doctype!('HTML 3.2')</tt>) or
53
+ # a symbol (e.g. <tt>set_doctype!(:html32)</tt>) from the
54
+ # W3CValidators::DOCTYPES hash.
55
+ #
56
+ # Has no effect when using validate_uri_quickly.
57
+ def set_doctype!(doctype, only_as_fallback = false)
58
+ if doctype.kind_of?(Symbol)
59
+ if DOCTYPES.has_key?(doctype)
60
+ doctype = DOCTYPES[doctype]
61
+ else
62
+ return
63
+ end
64
+ end
65
+ @options[:doctype] = doctype
66
+ @options[:fbd] = only_as_fallback
67
+ end
68
+
69
+ # When set the validator will output some extra debugging information on
70
+ # the validated resource (such as HTTP headers) and validation process
71
+ # (such as parser used, parse mode, etc.).
72
+ #
73
+ # Debugging information is stored in the Results +debug_messages+ hash.
74
+ # Custom debugging messages can be set with Results#add_debug_message.
75
+ #
76
+ # Has no effect when using validate_uri_quickly.
77
+ def set_debug!(debug = true)
78
+ @options[:debug] = debug
79
+ end
80
+
81
+ # Validate the markup of an URI using a +SOAP+ request.
82
+ #
83
+ # Returns W3CValidators::Results.
84
+ def validate_uri(uri)
85
+ return validate({:uri => uri}, false)
86
+ end
87
+
88
+ # Validate the markup of an URI using a +HEAD+ request.
89
+ #
90
+ # Returns W3CValidators::Results with an error count, not full error messages.
91
+ def validate_uri_quickly(uri)
92
+ return validate({:uri => uri}, true)
93
+ end
94
+
95
+ # Validate the markup of a string.
96
+ #
97
+ # Returns W3CValidators::Results.
98
+ def validate_text(text)
99
+ return validate({:fragment => text}, false)
100
+ end
101
+
102
+ # Validate the markup of a local file.
103
+ #
104
+ # +file_path+ may be either the fully-expanded path to the file or
105
+ # an IO object (like File).
106
+ #
107
+ # Returns W3CValidators::Results.
108
+ def validate_file(file_path)
109
+ if file_path.respond_to? :read
110
+ src = file_path.read
111
+ else
112
+ src = read_local_file(file_path)
113
+ end
114
+
115
+ return validate({:uploaded_file => src, :file_path => file_path}, false)
116
+ end
117
+
118
+ protected
119
+ def validate(options, quick = false) # :nodoc:
120
+ options = get_request_options(options)
121
+
122
+ if quick
123
+ response = send_request(options, :head)
124
+ @results = parse_head_response(response, options[:uri])
125
+ else
126
+ if options.has_key?(:uri) or options.has_key?(:fragment)
127
+ response = send_request(options, :get)
128
+ else
129
+ response = send_request(options, :post)
130
+ end
131
+
132
+ @results = parse_soap_response(response.body)
133
+ end
134
+ @results
135
+ end
136
+
137
+ # Perform sanity checks on request params
138
+ def get_request_options(options) # :nodoc:
139
+ options = @options.merge(options)
140
+
141
+ options[:output] = SOAP_OUTPUT_PARAM
142
+
143
+ unless options[:uri] or options[:uploaded_file] or options[:fragment]
144
+ raise ArgumentError, "an uri, uploaded file or fragment is required."
145
+ end
146
+
147
+ # URI should be a string. If it is a URI object, .to_s will
148
+ # be seamless; if it is not an exception will be raised.
149
+ if options[:uri] and not options[:uri].kind_of?(String)
150
+ options[:uri] = options[:uri].to_s
151
+ end
152
+
153
+ # Convert booleans to integers
154
+ [:fbc, :fbd, :verbose, :debug, :ss, :outline].each do |k|
155
+ if options.has_key?(k) and not options[k].kind_of?(Fixnum)
156
+ options[k] = options[k] ? 1 : 0
157
+ end
158
+ end
159
+
160
+ options
161
+ end
162
+
163
+
164
+ # Parse the SOAP XML response.
165
+ #
166
+ # +response+ must be a Net::HTTPResponse.
167
+ #
168
+ # Returns W3CValidators::Results.
169
+ def parse_soap_response(response) # :nodoc:
170
+ doc = REXML::Document.new(response)
171
+
172
+ result_params = {}
173
+
174
+ {:doctype => 'm:doctype', :uri => 'm:uri', :charset => 'm:charset',
175
+ :checked_by => 'm:checkedby', :validity => 'm:validity'}.each do |local_key, remote_key|
176
+ if val = doc.elements["env:Envelope/env:Body/m:markupvalidationresponse/#{remote_key}"]
177
+ result_params[local_key] = val.text
178
+ end
179
+ end
180
+
181
+ results = Results.new(result_params)
182
+
183
+ {:warning => 'm:warnings/m:warninglist/m:warning', :error => 'm:errors/m:errorlist/m:error'}.each do |local_type, remote_type|
184
+ doc.elements.each("env:Envelope/env:Body/m:markupvalidationresponse/#{remote_type}") do |message|
185
+ message_params = {}
186
+ message.each_element_with_text do |el|
187
+ message_params[el.name.to_sym] = el.text
188
+ end
189
+ results.add_message(local_type, message_params)
190
+ end
191
+ end
192
+
193
+ doc.elements.each("env:Envelope/env:Body/env:Fault/env:Reason") do |message|
194
+ message.elements.each("env:Text") do |m|
195
+ results.add_message(:error, {:mesage => m.text})
196
+ end
197
+ end
198
+
199
+ doc.elements.each("env:Envelope/env:Body/m:markupvalidationresponse/m:debug") do |debug|
200
+ results.add_debug_message(debug.attribute('name').value, debug.text)
201
+ end
202
+ return results
203
+
204
+ rescue Exception => e
205
+ handle_exception e
206
+ end
207
+
208
+ # Parse the HEAD response into HTMLValidator::Results.
209
+ #
210
+ # +response+ must be a Net::HTTPResponse.
211
+ #
212
+ # Returns Results.
213
+ def parse_head_response(response, validated_uri = nil) # :nodoc:
214
+ validity = (response[HEAD_STATUS_HEADER].downcase == 'valid')
215
+
216
+ results = Results.new(:uri => validated_uri, :validity => validity)
217
+
218
+ # Fill the results with empty error messages so we can count them
219
+ errors = response[HEAD_ERROR_COUNT_HEADER].to_i
220
+ errors.times { results.add_error }
221
+
222
+ results
223
+ end
224
+
225
+
226
+ end
227
+ end
@@ -0,0 +1,82 @@
1
+ module W3CValidators
2
+ class Message
3
+ attr_accessor :type, :line, :col, :source, :explanation, :message, :message_id
4
+ attr_accessor :message_count, :element, :parent, :value
5
+
6
+ MESSAGE_TYPES = [:warning, :error]
7
+
8
+ # Due to the responses received from the W3C's validators, different data
9
+ # are available for different validation types.
10
+ #
11
+ # ==== Feed validation
12
+ # * +line+
13
+ # * +col+
14
+ # * +message+ (originally +text+)
15
+ # * +message_count+
16
+ # * +element+
17
+ # * +parent+
18
+ # * +value+
19
+ # See http://validator.w3.org/feed/docs/soap.html#soap12message for full explanations.
20
+ #
21
+ # ==== Markup validation
22
+ # * +line+
23
+ # * +col+
24
+ # * +message+
25
+ # * +message_id+
26
+ # * +explanation+
27
+ # * +source+
28
+ # See http://validator.w3.org/docs/api.html#soap12message for full explanations.
29
+ #
30
+ # ==== CSS validation (http://jigsaw.w3.org/css-validator/api.html#soap12message)
31
+ # * +level+
32
+ # * +line+
33
+ # * +message+
34
+ # See http://jigsaw.w3.org/css-validator/api.html#soap12message for full explanations.
35
+ def initialize(uri, message_type, options = {})
36
+ @type = message_type
37
+ @uri = uri
38
+
39
+ # All validators
40
+ @line = options[:line]
41
+ @col = options[:col]
42
+
43
+ # MarkupValidator
44
+ @source = options[:source]
45
+ @explanation = options[:explanation]
46
+ @message = options[:message]
47
+ @message_id = options[:messageid]
48
+
49
+ # FeedValidator
50
+ @message = options[:text] unless @message
51
+ @message_count = options[:message_count]
52
+ @element = options[:element]
53
+ @parent = options[:parent]
54
+ @value = options[:value]
55
+
56
+ # CSSValidator
57
+ @level = options[:level]
58
+ end
59
+
60
+ def is_warning?
61
+ @type == :warning
62
+ end
63
+
64
+ def is_error?
65
+ @type == :error
66
+ end
67
+
68
+ # Return the message as a string.
69
+ def to_s
70
+ str = @type.to_s.upcase
71
+ if @uri and not @uri.empty?
72
+ str << "; URI: #{@uri}"
73
+ end
74
+ str << "; line #{@line}"
75
+ if @message and not @message.empty?
76
+ str << ": #{@message}"
77
+ end
78
+ return str
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,144 @@
1
+ require 'json'
2
+
3
+ module W3CValidators
4
+ class NuValidator < Validator
5
+ MARKUP_VALIDATOR_URI = 'http://validator.nu/'
6
+
7
+ # Create a new instance of the NuValidator.
8
+ #
9
+ # ==== Options
10
+ # The +options+ hash allows you to set request parameters (see
11
+ # http://wiki.whatwg.org/wiki/Validator.nu_Common_Input_Parameters) quickly. Request
12
+ # parameters can also be set using set_charset! and set_doctype!.
13
+ #
14
+ # You can pass in your own validator's URI (i.e.
15
+ # <tt>NuValidator.new(:validator_uri => 'http://localhost/check')</tt>).
16
+ def initialize(options = {})
17
+ if options[:validator_uri]
18
+ @validator_uri = URI.parse(options[:validator_uri])
19
+ options.delete(options[:validator_uri])
20
+ else
21
+ @validator_uri = URI.parse(MARKUP_VALIDATOR_URI)
22
+ end
23
+ super(options)
24
+ end
25
+
26
+
27
+ # Validate the markup of an URI.
28
+ #
29
+ # Returns W3CValidators::Results.
30
+ def validate_uri(uri)
31
+ return validate({:doc => uri})
32
+ end
33
+
34
+
35
+ # Validate the markup of a string.
36
+ #
37
+ # Returns W3CValidators::Results.
38
+ def validate_text(text)
39
+ return validate({:content => text})
40
+ end
41
+
42
+ # Validate the markup of a local file.
43
+ #
44
+ # +file_path+ may be either the fully-expanded path to the file or
45
+ # an IO object (like File).
46
+ #
47
+ # Returns W3CValidators::Results.
48
+ def validate_file(file)
49
+ if file.respond_to? :read
50
+ src = file.read
51
+ file_path = file.path ||= nil
52
+ else
53
+ src = read_local_file(file)
54
+ file_path = file
55
+ end
56
+
57
+ return validate({:file => src, :file_path => file_path})
58
+ end
59
+
60
+ protected
61
+ def validate(options) # :nodoc:
62
+ options = get_request_options(options)
63
+
64
+ if options.has_key?(:doc)
65
+ response = send_request(options, :get)
66
+ else
67
+ response = send_request(options, :post)
68
+ end
69
+
70
+ @results = parse_json_response(response.body)
71
+ @results
72
+ end
73
+
74
+ # Perform sanity checks on request params
75
+ def get_request_options(options) # :nodoc:
76
+ options = @options.merge(options)
77
+
78
+ options[:out] = 'json'
79
+
80
+ # only option that is currently supported
81
+ options[:showsource] = 'yes'
82
+
83
+ unless options[:doc] or options[:file] or options[:content]
84
+ raise ArgumentError, "an uri, file or block of text is required."
85
+ end
86
+
87
+ # URI should be a string. If it is a URI object, .to_s will
88
+ # be seamless; if it is not an exception will be raised.
89
+ if options[:doc] and not options[:doc].kind_of?(String)
90
+ options[:doc] = options[:doc].to_s
91
+ end
92
+ options
93
+ end
94
+
95
+
96
+ # Parse the JSON response.
97
+ #
98
+ # +response+ must be a Net::HTTPResponse.
99
+ #
100
+ # Returns W3CValidators::Results.
101
+ def parse_json_response(response) # :nodoc:
102
+ doc = JSON.parse(response)
103
+
104
+ result_params = {
105
+ :doctype => :html5,
106
+ :checked_by => MARKUP_VALIDATOR_URI
107
+ }
108
+
109
+ result_params[:uri] = doc['url'] ||= nil
110
+ if doc['source']
111
+ result_params[:charset] = doc['source']['encoding'] ||= nil
112
+ end
113
+
114
+ result_params[:validity] = !doc['messages'].any? { |msg| msg['type'] =~ /^error$/i }
115
+
116
+ results = Results.new(result_params)
117
+
118
+ doc['messages'].each do |msg|
119
+ if msg['type'] =~ /^error$/i
120
+ msg_type = :error
121
+ elsif msg['subType'] =~ /^warning$/
122
+ msg_type = :warning
123
+ else
124
+ next
125
+ # TODO: should throw exceptions here
126
+ end
127
+
128
+ message_params = {
129
+ :line => msg['firstLine'],
130
+ :col => msg['firstColumn'],
131
+ :message => msg['message'],
132
+ :source => msg['extract']
133
+ }
134
+
135
+ results.add_message(msg_type, message_params)
136
+ end
137
+
138
+ return results
139
+
140
+ rescue Exception => e
141
+ handle_exception e
142
+ end
143
+ end
144
+ end