feedvalidator 0.1.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,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