require 'json' module W3CValidators class NuValidator < Validator MARKUP_VALIDATOR_URI = 'http://validator.nu/' # Create a new instance of the NuValidator. # # ==== Options # The +options+ hash allows you to set request parameters (see # http://wiki.whatwg.org/wiki/Validator.nu_Common_Input_Parameters) quickly. Request # parameters can also be set using set_charset! and set_doctype!. # # You can pass in your own validator's URI (i.e. # NuValidator.new(:validator_uri => 'http://localhost/check')). # # See Validator#new for proxy server options. def initialize(options = {}) if options[:validator_uri] @validator_uri = URI.parse(options[:validator_uri]) options.delete(options[:validator_uri]) else @validator_uri = URI.parse(MARKUP_VALIDATOR_URI) end super(options) end # Validate the markup of an URI. # # Returns W3CValidators::Results. def validate_uri(uri) return validate({:doc => uri}) end # Validate the markup of a string. # # Returns W3CValidators::Results. def validate_text(text) return validate({:content => text}) end # Validate the markup of a local file. # # +file_path+ may be either the fully-expanded path to the file or # an IO object (like File). # # Returns W3CValidators::Results. def validate_file(file) if file.respond_to? :read src = file.read file_path = file.path ||= nil else src = read_local_file(file) file_path = file end return validate({:file => src, :file_path => file_path}) end protected def validate(options) # :nodoc: options = get_request_options(options) if options.has_key?(:doc) response = send_request(options, :get) else response = send_request(options, :post) end @results = parse_json_response(response.body) @results end # Perform sanity checks on request params def get_request_options(options) # :nodoc: options = @options.merge(options) options[:out] = 'json' # only option that is currently supported options[:showsource] = 'yes' unless options[:doc] or options[:file] or options[:content] raise ArgumentError, "an uri, file or block of text is required." end # URI should be a string. If it is a URI object, .to_s will # be seamless; if it is not an exception will be raised. if options[:doc] and not options[:doc].kind_of?(String) options[:doc] = options[:doc].to_s end options end # Parse the JSON response. # # +response+ must be a Net::HTTPResponse. # # Returns W3CValidators::Results. def parse_json_response(response) # :nodoc: doc = JSON.parse(response) result_params = { :doctype => :html5, :checked_by => MARKUP_VALIDATOR_URI } result_params[:uri] = doc['url'] ||= nil if doc['source'] result_params[:charset] = doc['source']['encoding'] ||= nil end result_params[:validity] = !doc['messages'].any? { |msg| msg['type'] =~ /^error$/i } results = Results.new(result_params) doc['messages'].each do |msg| if msg['type'] =~ /^error$/i msg_type = :error elsif msg['subType'] =~ /^warning$/ msg_type = :warning else next # TODO: should throw exceptions here end message_params = { :line => msg['firstLine'], :col => msg['firstColumn'], :message => msg['message'], :source => msg['extract'] } results.add_message(msg_type, message_params) end return results rescue Exception => e handle_exception e end end end