feedvalidator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ == FeedValidator 0.1.0
2
+ * Added the basic features to validate feeds, and new assertions to test cases
data/README ADDED
@@ -0,0 +1,71 @@
1
+ = FeedValidator
2
+
3
+ FeedValidator is an interface to the {W3C Feed Validation online service}[http://validator.w3.org/feed/],
4
+ based on its SOAP 1.2 support.
5
+
6
+ It helps to find errors in RSS or ATOM feeds.
7
+
8
+ FeedValidator add a new assertion (<code>assert_valid_feed</code>) which you can use in Rails applications.
9
+ This assertion implements a cache to improve the performance of the tests and to not abuse of the
10
+ {W3C Feed Validation online service}[http://validator.w3.org/feed/]
11
+
12
+
13
+ == Examples
14
+
15
+ * For use FeedValidator just do this:
16
+
17
+ require 'feed_validator'
18
+
19
+ v = W3C::FeedValidator.new()
20
+ v.validate_url('http://www.w3.org/QA/news.rss')
21
+ puts v.to_s unless v.valid?
22
+
23
+ * In Rails you can use it in your functional tests, just modify your /test/test_helper.rb adding this line:
24
+
25
+ require 'feed_validator/assertions'
26
+
27
+ And now you can use in your functional test, in this way:
28
+
29
+ def test_bar_valid_feed
30
+ get :bar
31
+ assert_valid_feed
32
+ end
33
+
34
+ Or use the class-level method to quickly create validation tests for a bunch of actions at once:
35
+
36
+ assert_valid_feed :bar, :foo
37
+
38
+
39
+ == Download
40
+
41
+ The latest version of FeedValidator can be found at
42
+
43
+ * http://rubyforge.org/frs/?group_id=1533
44
+
45
+ Documentation can be found at
46
+
47
+ * http://feedvalidator.rubyforge.org
48
+
49
+
50
+ == Installation
51
+
52
+ You can install FeedValidator as a gem:
53
+ gem install feedvalidator
54
+
55
+ Or you can install it from the tarball or zip packages on the download page
56
+ and then extract it to your lib directory as you would with any other
57
+ Ruby library.
58
+
59
+
60
+ == License
61
+
62
+ FeedValidator is released under the MIT license.
63
+
64
+
65
+ == Support
66
+
67
+ You can find the Feed Validator RubyForge page at http://rubyforge.org/projects/feedvalidator.
68
+
69
+ Feel free to submit commits or feature requests.
70
+
71
+ For other information, feel free to contact mailto:edgar@lacaraoscura.com.
@@ -0,0 +1,30 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ require 'ftools'
4
+
5
+ include Config
6
+
7
+ # this was adapted from rdoc's install.rb by ways of Log4r
8
+
9
+ $sitedir = CONFIG["sitelibdir"]
10
+ unless $sitedir
11
+ version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
12
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
13
+ $sitedir = $:.find {|x| x =~ /site_ruby/ }
14
+ if !$sitedir
15
+ $sitedir = File.join($libdir, "site_ruby")
16
+ elsif $sitedir !~ Regexp.quote(version)
17
+ $sitedir = File.join($sitedir, version)
18
+ end
19
+ end
20
+
21
+ # the acual gruntwork
22
+ Dir.chdir("lib")
23
+
24
+ Find.find("feed_validator", "feed_validator.rb") { |f|
25
+ if f[-3..-1] == ".rb"
26
+ File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
27
+ else
28
+ File::makedirs(File.join($sitedir, *f.split(/\//)))
29
+ end
30
+ }
@@ -0,0 +1,164 @@
1
+ #--
2
+ # Copyright (c) 2006 Edgar Gonzalez <edgar@lacaraoscura.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+ #
24
+ # Provide an interface to the {W3C Feed Validation online service}[http://validator.w3.org/feed/],
25
+ # based on its SOAP 1.2 support.
26
+ #
27
+ require 'net/http'
28
+ require 'cgi'
29
+ require 'rexml/document'
30
+
31
+ module W3C
32
+
33
+ # Implements an interface to the {W3C Feed Validation online service}[http://validator.w3.org/feed/],
34
+ # based on its SOAP 1.2 support.
35
+ #
36
+ # It helps to find errors in RSS or Atom feeds.
37
+ # ---
38
+ # Please remember that the {W3C Feed Validation service}[http://validator.w3.org/feed/] is a shared resource,
39
+ # so do not abuse it: you should make your scripts sleep between requests.
40
+ #
41
+ class FeedValidator
42
+ VERSION = "0.1.0"
43
+
44
+ # True if the w3c feed validation service not found errors in the feed.
45
+ #
46
+ attr_reader :valid
47
+
48
+ # The complete response (as Net::HTTPResponse object) sent it by the w3c feed validation service.
49
+ #
50
+ attr_reader :response
51
+
52
+ # Collection of _errors_ founded by the w3c feed validation service.
53
+ # Every error is a hash containing: <tt>:type</tt>, <tt>:line</tt>,
54
+ # <tt>:column</tt>, <tt>:text</tt>, <tt>:element</tt>
55
+ #
56
+ attr_reader :errors
57
+
58
+ # Collection of _warnings_ founded by the w3c feed validation service.
59
+ # Every error is a hash containing: <tt>:type</tt>, <tt>:line</tt>,
60
+ # <tt>:column</tt>, <tt>:text</tt>, <tt>:element</tt>
61
+ #
62
+ attr_reader :warnings
63
+
64
+ # Collection of _informations_ founded by the w3c feed validation service.
65
+ # Every error is a hash containing: <tt>:type</tt>, <tt>:line</tt>,
66
+ # <tt>:column</tt>, <tt>:text</tt>, <tt>:element</tt>
67
+ #
68
+ attr_reader :informations
69
+
70
+ # Initialize the feed validator object
71
+ #
72
+ def initialize
73
+ clear
74
+ end
75
+
76
+ # Validate the data provided.
77
+ # Returns a true value if the validation succeeded (regardless of whether the feed contains errors).
78
+ #
79
+ def validate_data(rawdata)
80
+ clear
81
+ params = "rawdata=#{CGI.escape(rawdata)}&manual=1&output=soap12"
82
+ begin
83
+ @response = Net::HTTP.start('validator.w3.org',80).post('/feed/check.cgi',params)
84
+ parse_response(@response.body)
85
+ return true
86
+ rescue
87
+ return false
88
+ end
89
+ end
90
+
91
+ # Validate the url provided.
92
+ # Returns a true value if the validation succeeded (regardless of whether the feed contains errors).
93
+ #
94
+ def validate_url(url)
95
+ clear
96
+ params = "url=#{CGI.escape(url)}&output=soap12"
97
+ begin
98
+ @response = Net::HTTP.get_response('validator.w3.org',"/feed/check.cgi?#{params}",80)
99
+ parse_response(@response.body)
100
+ return true
101
+ rescue
102
+ return false
103
+ end
104
+ end
105
+
106
+ alias :valid? :valid
107
+
108
+ def to_s
109
+ msg = "Vailidity: #{@valid}\n"
110
+ msg << "Errors count: #{@errors.size}\n"
111
+ @errors.each_with_index{ |item, i| msg << "(#{i+1}) type: #{item[:type]} | line: #{item[:line]} | column: #{item[:column]} | text: #{item[:text]},\n"}
112
+ msg << "Warnings count: #{@warnings.size}\n"
113
+ @warnings.each_with_index{ |item, i| msg << "(#{i+1}) type: #{item[:type]} | line: #{item[:line]} | column: #{item[:column]} | text: #{item[:text]},\n"}
114
+ msg << "Informations count: #{@informations.size}\n"
115
+ @informations.each_with_index{ |item, i| msg << "(#{i+1}) type: #{item[:type]} | line: #{item[:line]} | column: #{item[:column]} | text: #{item[:text]},\n"}
116
+ msg
117
+ end
118
+
119
+ private
120
+
121
+ def parse_response(response) #nodoc
122
+ xml = REXML::Document.new(response)
123
+ @valid = (/true/.match(xml.root.elements["env:Body/m:feedvalidationresponse/m:validity"].get_text.value))? true : false
124
+ unless @valid
125
+ xml.elements.each("env:Envelope/env:Body/m:feedvalidationresponse/m:errors/m:errorlist/error") do |error|
126
+ @errors << {
127
+ :type => error.elements["type"].get_text.value,
128
+ :line => error.elements["line"].get_text.value,
129
+ :column => error.elements["column"].get_text.value,
130
+ :text => error.elements["text"].get_text.value,
131
+ :element => error.elements["element"].get_text.value
132
+ }
133
+ end
134
+ end
135
+ xml.elements.each("env:Envelope/env:Body/m:feedvalidationresponse/m:warnings/m:warninglist/warning") do |warning|
136
+ @warnings << {
137
+ :type => warning.elements["type"].get_text.value,
138
+ :line => warning.elements["line"].get_text.value,
139
+ :column => warning.elements["column"].get_text.value,
140
+ :text => warning.elements["text"].get_text.value,
141
+ :element => warning.elements["element"].get_text.value
142
+ }
143
+ end
144
+ xml.elements.each("env:Envelope/env:Body/m:feedvalidationresponse/m:informations/m:infolist/information") do |info|
145
+ @informations << {
146
+ :type => info.elements["type"].get_text.value,
147
+ :line => info.elements["line"].get_text.value,
148
+ :column => info.elements["column"].get_text.value,
149
+ :text => info.elements["text"].get_text.value,
150
+ :element => info.elements["element"].get_text.value
151
+ }
152
+ end
153
+ end
154
+
155
+ def clear #nodoc
156
+ @response = nil
157
+ @valid = false
158
+ @errors = []
159
+ @warnings = []
160
+ @informations = []
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,91 @@
1
+ #--
2
+ # Copyright (c) 2006 Edgar Gonzalez <edgar@lacaraoscura.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'feed_validator'
25
+ require 'test/unit'
26
+ require 'tmpdir'
27
+ require 'md5'
28
+
29
+ module W3C
30
+ class FeedValidator
31
+ # Parse a response from the w3c feed validation service.
32
+ # Used by assert_valid_feed
33
+ def parse(response)
34
+ clear
35
+ if response.respond_to?(:body)
36
+ parse_response(response.body)
37
+ else
38
+ parse_response(response)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ class Test::Unit::TestCase
45
+
46
+ # Assert that feed is valid according the {W3C Feed Validation online service}[http://validator.w3.org/feed/].
47
+ # By default, it validates the contents of @response.body, which is set after calling
48
+ # one of the get/post/etc helper methods in rails. You can also pass it a string to be validated.
49
+ # Validation errors, warnings and informations, if any, will be included in the output. The response from the validator
50
+ # service will be cached in the system temp directory to minimize duplicate calls.
51
+ #
52
+ # For example in Rails, if you have a FooController with an action Bar, put this in foo_controller_test.rb:
53
+ #
54
+ # def test_bar_valid_feed
55
+ # get :bar
56
+ # assert_valid_feed
57
+ # end
58
+ #
59
+ def assert_valid_feed(fragment=@response.body)
60
+ v = W3C::FeedValidator.new()
61
+ filename = File.join Dir::tmpdir, 'feed.' + MD5.md5(fragment).to_s
62
+ begin
63
+ response = File.open filename do |f| Marshal.load(f) end
64
+ v.parse(response)
65
+ rescue
66
+ unless v.validate_data(fragment)
67
+ warn("Sorry! could not validate the feed.")
68
+ return assert(true,'')
69
+ end
70
+ File.open filename, 'w+' do |f| Marshal.dump v.response, f end
71
+ end
72
+ assert(v.valid?, v.valid? ? '' : v.to_s)
73
+ end
74
+
75
+ # Class-level method to quickly create validation tests for a bunch of actions at once in Rails.
76
+ # For example, if you have a FooController with three actions, just add one line to foo_controller_test.rb:
77
+ #
78
+ # assert_valid_feed :bar, :baz, :qux
79
+ #
80
+ def self.assert_valid_feed(*actions)
81
+ actions.each do |action|
82
+ class_eval <<-EOF
83
+ def test_#{action}_valid_feed
84
+ get :#{action}
85
+ assert_valid_feed
86
+ end
87
+ EOF
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,109 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ PKG_NAME = 'feedvalidator'
10
+ PKG_VERSION = '0.1.0'
11
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
12
+
13
+ RELEASE_NAME = "REL #{PKG_VERSION}"
14
+
15
+ RUBY_FORGE_PROJECT = "feedvalidator"
16
+ RUBY_FORGE_USER = "edgar"
17
+
18
+ PKG_FILES = FileList[
19
+ "lib/**/*", "test/**/*", "examples/**/*", "doc/**/*", "[A-Z]*", "install.rb", "rakefile"
20
+ ].exclude(/\b.svn\b|~$/)
21
+
22
+ desc "Default Task"
23
+ task :default => [ :test_all ]
24
+
25
+ # Run the unit tests
26
+
27
+ Rake::TestTask.new("test_all") { |t|
28
+ t.libs << "test"
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = true
31
+ }
32
+
33
+ # Generate the RDoc documentation
34
+
35
+ Rake::RDocTask.new { |rdoc|
36
+ rdoc.rdoc_dir = 'doc'
37
+ rdoc.title = "FeedValidator"
38
+ rdoc.options << '--line-numbers' << '--inline-source'
39
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
40
+ rdoc.rdoc_files.include('README', 'CHANGELOG')
41
+ rdoc.rdoc_files.include('lib/**/*.rb')
42
+ }
43
+
44
+ # Create compressed packages
45
+
46
+ dist_dirs = [ "lib", "test" ]
47
+
48
+ spec = Gem::Specification.new do |s|
49
+ s.name = PKG_NAME
50
+ s.version = PKG_VERSION
51
+ s.summary = "An interface to the W3C Feed Validation online service"
52
+ s.description = "Implements a simple system for generating UUIDs."
53
+
54
+ s.files = [ "rakefile", "install.rb", "README", "CHANGELOG" ]
55
+ dist_dirs.each do |dir|
56
+ s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if do |item|
57
+ item.include?( "\.svn" )
58
+ end
59
+ end
60
+
61
+ s.require_path = 'lib'
62
+ s.autorequire = 'feed_validator'
63
+
64
+ s.has_rdoc = true
65
+ s.extra_rdoc_files = %w( README )
66
+ s.rdoc_options.concat ['--main', 'README']
67
+
68
+ s.author = "Edgar Gonzalez"
69
+ s.email = "edgar@lacaraoscura.com"
70
+ s.homepage = "http://feedvalidator.rubyforge.org"
71
+ s.rubyforge_project = "feedvalidator"
72
+ end
73
+
74
+ Rake::GemPackageTask.new(spec) do |p|
75
+ p.gem_spec = spec
76
+ p.need_tar = true
77
+ p.need_zip = true
78
+ end
79
+
80
+ task :lines do
81
+ lines, codelines, total_lines, total_codelines = 0, 0, 0, 0
82
+
83
+ for file_name in FileList["lib/**/*.rb"]
84
+ f = File.open(file_name)
85
+
86
+ while line = f.gets
87
+ lines += 1
88
+ next if line =~ /^\s*$/
89
+ next if line =~ /^\s*#/
90
+ codelines += 1
91
+ end
92
+ puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
93
+
94
+ total_lines += lines
95
+ total_codelines += codelines
96
+
97
+ lines, codelines = 0, 0
98
+ end
99
+
100
+ puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
101
+ end
102
+
103
+
104
+ # Publishing ------------------------------------------------------
105
+
106
+ desc "Publish the API documentation"
107
+ task :pdoc => [:rdoc] do
108
+ Rake::SshDirPublisher.new("edgar@rubyforge.org", "/var/www/gforge-projects/feedvalidator/", "doc").upload
109
+ end