zsff 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.
- data/History.txt +4 -0
- data/Manifest.txt +6 -0
- data/README.txt +52 -0
- data/Rakefile +18 -0
- data/lib/zsff.rb +112 -0
- data/test/test_zsff.rb +113 -0
- metadata +69 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
zsff
|
2
|
+
by Erik Peterson
|
3
|
+
http://subwindow.com/zsff
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
A parser/validator for ZSFF feeds.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
Right now, only one function: parse. This does the validation and parsing all in one step. This is intended to be used by any reader (who would take care of what links have been read, etc).
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
results = Zsff.parse(url)
|
16
|
+
results[:errors] #Any errors encountered while parsing
|
17
|
+
results[:warnings] #Any warnings encountered while parsing
|
18
|
+
results[:attrs] #A hash for the author, title, etc information from the feed
|
19
|
+
results[:links] #List of links in the feed
|
20
|
+
|
21
|
+
== REQUIREMENTS:
|
22
|
+
|
23
|
+
None
|
24
|
+
|
25
|
+
== INSTALL:
|
26
|
+
|
27
|
+
sudo gem install, anything else
|
28
|
+
|
29
|
+
== LICENSE:
|
30
|
+
|
31
|
+
(The MIT License)
|
32
|
+
|
33
|
+
Copyright (c) 2008 Erik Peterson
|
34
|
+
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
36
|
+
a copy of this software and associated documentation files (the
|
37
|
+
'Software'), to deal in the Software without restriction, including
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
41
|
+
the following conditions:
|
42
|
+
|
43
|
+
The above copyright notice and this permission notice shall be
|
44
|
+
included in all copies or substantial portions of the Software.
|
45
|
+
|
46
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
47
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
48
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
49
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
50
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
51
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
52
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/zsff.rb'
|
6
|
+
|
7
|
+
Hoe.new('zsff', Zsff::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'zsff'
|
9
|
+
p.author = 'Erik Peterson'
|
10
|
+
p.email = 'erik@subwindow.com'
|
11
|
+
p.summary = 'A parser/validator for ZSFF feeds'
|
12
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
13
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
14
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
15
|
+
p.remote_rdoc_dir = ''
|
16
|
+
end
|
17
|
+
|
18
|
+
# vim: syntax=Ruby
|
data/lib/zsff.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Author:: Erik Peterson (mailto:erik@subwindow.com)
|
2
|
+
# Copyright:: Copyright (c) 2008 Erik Peterson
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
# This class parses and validates a Zsff feed by URL or a raw feed string
|
6
|
+
|
7
|
+
require 'net/http'
|
8
|
+
require 'open-uri'
|
9
|
+
class Zsff
|
10
|
+
VERSION = '1.0.0'
|
11
|
+
attr_accessor :url
|
12
|
+
attr_accessor :contents
|
13
|
+
attr_accessor :errors
|
14
|
+
attr_accessor :warnings
|
15
|
+
attr_accessor :version
|
16
|
+
attr_accessor :author
|
17
|
+
attr_accessor :title
|
18
|
+
attr_accessor :site
|
19
|
+
attr_accessor :subtitle
|
20
|
+
attr_accessor :copyright
|
21
|
+
attr_accessor :content_type
|
22
|
+
attr_accessor :links
|
23
|
+
|
24
|
+
def initialize(attributes = nil)
|
25
|
+
self.attributes = attributes unless attributes.nil?
|
26
|
+
@errors = []
|
27
|
+
@warnings = []
|
28
|
+
@links = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parse_url(url)
|
32
|
+
parser = self.new(:url => url)
|
33
|
+
parser.parse
|
34
|
+
return parser
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_contents(contents)
|
38
|
+
parser = self.new(:contents => contents)
|
39
|
+
parser.parse
|
40
|
+
return parser
|
41
|
+
end
|
42
|
+
|
43
|
+
def attributes=(attributes)
|
44
|
+
attributes.each do |k, v|
|
45
|
+
send(k.to_s + "=", v)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse
|
50
|
+
if self.url
|
51
|
+
begin
|
52
|
+
uri = URI.parse(url)
|
53
|
+
@contents = Net::HTTP.get(uri)
|
54
|
+
rescue
|
55
|
+
@errors.push("Invalid URL")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
parse_contents
|
61
|
+
|
62
|
+
return @errors.size == 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_contents
|
66
|
+
begin
|
67
|
+
raw = @contents.split(/\n\n/)
|
68
|
+
@errors.push("Must have two line breaks between Attributes section and Links section") and return if raw.size < 2
|
69
|
+
|
70
|
+
@version = raw.first.split(/\n/).first
|
71
|
+
raw.first.split(/\n/)[1..-1].each do |attribute|
|
72
|
+
parts = attribute.split(":")
|
73
|
+
next if parts.size < 2
|
74
|
+
self.send(parts.first.downcase.gsub(/-/, "_") + "=", parts[1..-1].join(":").strip)
|
75
|
+
end
|
76
|
+
|
77
|
+
error_if :version, @version.nil? || @version.match(/ZSFF 1\.[0-9]/).nil?
|
78
|
+
error_if :author, @author.nil? || @author == ""
|
79
|
+
error_if :title, @title.nil? || @title == ""
|
80
|
+
error_if :site, @site.nil? || @site == ""
|
81
|
+
warn_if :site, @site.nil? || !is_valid_url?(@site)
|
82
|
+
warn_if :subtitle, @subtitle.nil? || @subtitle == ""
|
83
|
+
warn_if :copyright, @copyright.nil? || @copyright == ""
|
84
|
+
error_if :content_type, @content_type.nil? || @content_type.match(/.*\/.*/).nil?
|
85
|
+
|
86
|
+
items = raw.last.split(/\n/)
|
87
|
+
items.each do |item|
|
88
|
+
warnings.push("Item '#{item}' does not appear to be a valid URL") and next unless is_valid_url?(item)
|
89
|
+
unless item.match(/\.page$/)
|
90
|
+
content = items.select{|i|item.gsub(/\.(php|php3|asp|aspx|htm|cfm|html)$/, "") + ".page" == i}.first
|
91
|
+
@links.push({:link => item, :content => content})
|
92
|
+
end
|
93
|
+
end
|
94
|
+
#rescue
|
95
|
+
# @errors.push("Cannot parse ZSFF file")
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def error_if(attribute, condition)
|
102
|
+
@errors.push("Invalid #{attribute.to_s.capitalize} declaration.") if condition
|
103
|
+
end
|
104
|
+
|
105
|
+
def warn_if(attribute, condition)
|
106
|
+
@warnings.push("#{attribute.to_s.capitalize} may be invalid.") if condition
|
107
|
+
end
|
108
|
+
|
109
|
+
def is_valid_url?(url)
|
110
|
+
!url.match(/(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)/ix).nil?
|
111
|
+
end
|
112
|
+
end
|
data/test/test_zsff.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/zsff'
|
3
|
+
class ZsffTest < Test::Unit::TestCase
|
4
|
+
# Replace this with your real tests.
|
5
|
+
def test_parse_url
|
6
|
+
parser = Zsff.new(:url => "http://subwindow.com/articles.zsff")
|
7
|
+
|
8
|
+
assert_equal true, parser.parse
|
9
|
+
assert_equal [], parser.errors
|
10
|
+
assert_equal [], parser.warnings
|
11
|
+
assert_equal "ZSFF 1.0", parser.version
|
12
|
+
assert_equal "Erik Peterson", parser.author
|
13
|
+
assert_equal "subWindow Blog", parser.title
|
14
|
+
assert_equal "http://www.subwindow.com/", parser.site
|
15
|
+
assert_equal "Just another crappy programmer's blog", parser.subtitle
|
16
|
+
assert_equal "2008", parser.copyright
|
17
|
+
assert_equal "text/plain", parser.content_type
|
18
|
+
assert parser.links.size > 2
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_static_parse_url
|
22
|
+
parser = Zsff::parse_url("http://subwindow.com/articles.zsff")
|
23
|
+
|
24
|
+
assert_equal [], parser.errors
|
25
|
+
assert_equal [], parser.warnings
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_static_parse_contents
|
29
|
+
zsff = <<ZSFFSTR
|
30
|
+
ZSFF 1.0
|
31
|
+
Author: Erik Peterson
|
32
|
+
Title: subWindow Blog
|
33
|
+
Site: http://www.subwindow.com/
|
34
|
+
Subtitle: Just another crappy programmer's blog
|
35
|
+
Copyright: 2008
|
36
|
+
Content-type: text/plain
|
37
|
+
|
38
|
+
http://subwindow.com/articles/3.page
|
39
|
+
http://subwindow.com/articles/3.html
|
40
|
+
http://subwindow.com/articles/2
|
41
|
+
http://subwindow.com/articles/2.page
|
42
|
+
http://subwindow.com/articles/1
|
43
|
+
ZSFFSTR
|
44
|
+
|
45
|
+
parser = Zsff::parse_contents(zsff)
|
46
|
+
|
47
|
+
assert_equal [], parser.errors
|
48
|
+
assert_equal [], parser.warnings
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_parse_string
|
52
|
+
zsff = <<ZSFFSTR
|
53
|
+
ZSFF 1.0
|
54
|
+
Author: Erik Peterson
|
55
|
+
Title: subWindow Blog
|
56
|
+
Site: http://www.subwindow.com/
|
57
|
+
Subtitle: Just another crappy programmer's blog
|
58
|
+
Copyright: 2008
|
59
|
+
Content-type: text/plain
|
60
|
+
|
61
|
+
http://subwindow.com/articles/3.page
|
62
|
+
http://subwindow.com/articles/3.html
|
63
|
+
http://subwindow.com/articles/2
|
64
|
+
http://subwindow.com/articles/2.page
|
65
|
+
http://subwindow.com/articles/1
|
66
|
+
ZSFFSTR
|
67
|
+
|
68
|
+
parser = Zsff.new(:contents => zsff)
|
69
|
+
assert_equal true, parser.parse
|
70
|
+
assert_equal [], parser.errors
|
71
|
+
assert_equal [], parser.warnings
|
72
|
+
assert_equal "ZSFF 1.0", parser.version
|
73
|
+
assert_equal "Erik Peterson", parser.author
|
74
|
+
assert_equal "subWindow Blog", parser.title
|
75
|
+
assert_equal "http://www.subwindow.com/", parser.site
|
76
|
+
assert_equal "Just another crappy programmer's blog", parser.subtitle
|
77
|
+
assert_equal "2008", parser.copyright
|
78
|
+
assert_equal "text/plain", parser.content_type
|
79
|
+
assert_equal 3, parser.links.size
|
80
|
+
assert_equal "http://subwindow.com/articles/3.html", parser.links[0][:link]
|
81
|
+
assert_equal "http://subwindow.com/articles/3.page", parser.links[0][:content]
|
82
|
+
assert_equal "http://subwindow.com/articles/2", parser.links[1][:link]
|
83
|
+
assert_equal "http://subwindow.com/articles/2.page", parser.links[1][:content]
|
84
|
+
assert_equal "http://subwindow.com/articles/1", parser.links[2][:link]
|
85
|
+
assert_equal nil, parser.links[2][:content]
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_fail_parse
|
89
|
+
zsff = "THIS IS NOT A VALID ZSFF FEED"
|
90
|
+
|
91
|
+
parser = Zsff.new(:url => zsff)
|
92
|
+
assert_equal false, parser.parse
|
93
|
+
assert parser.errors.include?("Invalid URL")
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_fail_links
|
97
|
+
zsff = <<ZSFFSTR
|
98
|
+
ZSFF 1.0
|
99
|
+
Author: Erik Peterson
|
100
|
+
Title: subWindow Blog
|
101
|
+
Site: http://www.subwindow.com/
|
102
|
+
Subtitle: Just another crappy programmer's blog
|
103
|
+
Copyright: 2008
|
104
|
+
Content-type: text/plain
|
105
|
+
http://subwindow.com/articles/3
|
106
|
+
http://subwindow.com/articles/2
|
107
|
+
ZSFFSTR
|
108
|
+
|
109
|
+
parser = Zsff.new(:contents => zsff)
|
110
|
+
assert_equal false, parser.parse
|
111
|
+
assert parser.errors.include?("Must have two line breaks between Attributes section and Links section")
|
112
|
+
end
|
113
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zsff
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erik Peterson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-01-17 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.4.0
|
23
|
+
version:
|
24
|
+
description: "== FEATURES/PROBLEMS: Right now, only one function: parse. This does the validation and parsing all in one step. This is intended to be used by any reader (who would take care of what links have been read, etc). == SYNOPSIS: results = Zsff.parse(url) results[:errors] #Any errors encountered while parsing results[:warnings] #Any warnings encountered while parsing results[:attrs] #A hash for the author, title, etc information from the feed results[:links] #List of links in the feed == REQUIREMENTS:"
|
25
|
+
email: erik@subwindow.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- History.txt
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
files:
|
35
|
+
- History.txt
|
36
|
+
- Manifest.txt
|
37
|
+
- README.txt
|
38
|
+
- Rakefile
|
39
|
+
- lib/zsff.rb
|
40
|
+
- test/test_zsff.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: " by Erik Peterson"
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options:
|
45
|
+
- --main
|
46
|
+
- README.txt
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
requirements: []
|
62
|
+
|
63
|
+
rubyforge_project: zsff
|
64
|
+
rubygems_version: 1.0.1
|
65
|
+
signing_key:
|
66
|
+
specification_version: 2
|
67
|
+
summary: A parser/validator for ZSFF feeds
|
68
|
+
test_files:
|
69
|
+
- test/test_zsff.rb
|