alexdunae-w3c_validators 1.0.0

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