superfeedr-blather 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'blather', "~> 0.4.14"
4
+
5
+ # group :development do
6
+ # gem 'blather', :require => 'blather/client'
7
+ # end
8
+
9
+ group :development do
10
+ gem "jeweler", "~> 1.5.2"
11
+ gem "yard", "~> 0.6.0"
12
+ end
13
+
14
+ group :test do
15
+ gem 'rspec'
16
+ gem 'autotest'
17
+ gem 'autotest-notification', :require => 'autotest_notification'
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ZenTest (4.4.2)
5
+ autotest (4.4.6)
6
+ ZenTest (>= 4.4.1)
7
+ autotest-notification (2.3.1)
8
+ autotest (~> 4.3)
9
+ blather (0.4.14)
10
+ eventmachine (>= 0.12.6)
11
+ nokogiri (>= 1.4.0)
12
+ diff-lcs (1.1.2)
13
+ eventmachine (0.12.10)
14
+ git (1.2.5)
15
+ jeweler (1.5.2)
16
+ bundler (~> 1.0.0)
17
+ git (>= 1.2.5)
18
+ rake
19
+ nokogiri (1.4.4)
20
+ rake (0.8.7)
21
+ rspec (2.3.0)
22
+ rspec-core (~> 2.3.0)
23
+ rspec-expectations (~> 2.3.0)
24
+ rspec-mocks (~> 2.3.0)
25
+ rspec-core (2.3.1)
26
+ rspec-expectations (2.3.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.3.0)
29
+ yard (0.6.4)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ autotest
36
+ autotest-notification
37
+ blather (~> 0.4.14)
38
+ jeweler (~> 1.5.2)
39
+ rspec
40
+ yard (~> 0.6.0)
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 David Nolan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,67 @@
1
+ = superfeedr-blather
2
+
3
+ superfeedr-blather implements a Superfeedr[http://superfeedr.com] PubSub XMPP client in Ruby using the Blather gem.
4
+
5
+ Starting up a connection and echoing new notifications is as easy as this:
6
+
7
+ setup YOUR_SUPERFEEDR_USERNAME, YOUR_SUPERFEEDR_PASSWORD
8
+
9
+ pubsub_event do |e|
10
+ e.items.each do |i|
11
+ puts "New post from #{i.entry.title}:"
12
+ puts i.entry.content
13
+ end
14
+ end
15
+
16
+ == About
17
+
18
+ You get some patches for Blather and some classes that wrap the stuff
19
+ you want from Superfeedr (entries, authors etc.).
20
+
21
+ Under-the-hood, Blather uses EventMachine and Nokogiri so it's fast
22
+ and convenient. If you want to daemonize your client, daemon-kit[https://github.com/kennethkalmer/daemon-kit/] comes
23
+ ready with a {blather template}[https://github.com/kennethkalmer/daemon-kit/blob/master/lib/daemon_kit/xmpp.rb].
24
+
25
+ You might want to compare Superfeedr's own
26
+ superfeedr-ruby[https://github.com/superfeedr/superfeedr-ruby] which
27
+ is based on a different XMPP lib, Skates.
28
+
29
+ == Tips
30
+
31
+ Take a look in <tt>/examples</tt> for examples of handling notifications,
32
+ (un)subscribing, and fetching the list of subscriptions.
33
+
34
+ When you're playing around, subscribe to Superfeedr's <tt>dummy.xml</tt> feed and use the button on
35
+ http://www.superfeedr.com/users/kapoq/feeds/xmpp_console to generate a
36
+ new notification on demand ("show console" displays the button).
37
+
38
+ == Install
39
+
40
+ git clone git://github.com/kapoq/superfeedr-blather.git
41
+
42
+ == Source and latest version
43
+
44
+ superfeedr-blather lives at
45
+ https://github.com/kapoq/superfeedr-blather.
46
+
47
+ Stop by and say hi some time (contribs welcome).
48
+
49
+ == Author
50
+
51
+ Dave Nolan / Kapoq Ltd / kapoq.com[http://kapoq.com]
52
+
53
+ == TODO
54
+
55
+ * apply patches upstream to blather
56
+ * loading filename conflicts using bundler
57
+ * multiple namespaces
58
+
59
+ * improve type-casting
60
+
61
+ * implement superfeedr-specific handlers
62
+
63
+ * swap out default client so there's no attempt to load roster on connect
64
+
65
+ * implement Superfeedr notifications extensions:
66
+ * stripped
67
+ * chunks (No mention in the Superfeedr schema docs but is used elsewhere)
data/README.rdoc ADDED
@@ -0,0 +1,64 @@
1
+ = superfeedr-blather
2
+
3
+ superfeedr-blather implements a Superfeedr[http://superfeedr.com] PubSub XMPP client in Ruby using the Blather gem.
4
+
5
+ Starting up a connection and echoing new notifications is as easy as this:
6
+
7
+ setup YOUR_SUPERFEEDR_USERNAME, YOUR_SUPERFEEDR_PASSWORD
8
+
9
+ pubsub_event do |e|
10
+ e.items.each do |i|
11
+ puts "New post from #{i.entry.title}:"
12
+ puts i.entry.content
13
+ end
14
+ end
15
+
16
+ == About
17
+
18
+ You get some patches for Blather and some classes that wrap the stuff
19
+ you want from Superfeedr (entries, authors etc.).
20
+
21
+ Under-the-hood, Blather uses EventMachine and Nokogiri so it's fast
22
+ and convenient. If you want to daemonize your client, daemon-kit[https://github.com/kennethkalmer/daemon-kit/] comes
23
+ ready with a {blather template}[https://github.com/kennethkalmer/daemon-kit/blob/master/lib/daemon_kit/xmpp.rb].
24
+
25
+ You might want to compare Superfeedr's own
26
+ superfeedr-ruby[https://github.com/superfeedr/superfeedr-ruby] which
27
+ is based on a different XMPP lib, Skates.
28
+
29
+ == Tips
30
+
31
+ Take a look in <tt>/examples</tt> for examples of handling notifications,
32
+ (un)subscribing, and fetching the list of subscriptions.
33
+
34
+ When you're playing around, subscribe to Superfeedr's <tt>dummy.xml</tt> feed and use the button on
35
+ http://www.superfeedr.com/users/kapoq/feeds/xmpp_console to generate a
36
+ new notification on demand ("show console" displays the button).
37
+
38
+ == Install
39
+
40
+ git clone git://github.com/kapoq/superfeedr-blather.git
41
+
42
+ == Source and latest version
43
+
44
+ superfeedr-blather lives at
45
+ https://github.com/kapoq/superfeedr-blather.
46
+
47
+ Stop by and say hi some time (contribs welcome).
48
+
49
+ == Author
50
+
51
+ Dave Nolan / Kapoq Ltd / kapoq.com[http://kapoq.com]
52
+
53
+ == TODO
54
+
55
+ * apply patches upstream to blather
56
+ * loading filename conflicts using bundler
57
+ * multiple namespaces
58
+
59
+ * improve type-casting
60
+
61
+ * implement Superfeedr notifications extensions:
62
+ * stripped
63
+ * chunks (No mention in the Superfeedr schema docs but is used elsewhere)
64
+
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "superfeedr-blather"
17
+ gem.homepage = "http://github.com/kapoq/superfeedr-blather"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{superfeedr-blather implements a Superfeedr PubSub XMPP client in Ruby using the Blather gem.}
20
+ gem.description = %Q{You get some patches for Blather and some classes that wrap the stuff you want from Superfeedr (entries, authors etc.). Under-the-hood, Blather uses EventMachine and Nokogiri so it’s fast and convenient. If you want to daemonize your client, daemon-kit comes ready with a blather template.}
21
+ gem.email = "dave@kapoq.com"
22
+ gem.authors = ["dave@kapoq.com"]
23
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
24
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
25
+ gem.add_runtime_dependency 'blather', '~> 0.4.14'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ task :default => :spec
36
+
37
+ require 'yard'
38
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/examples/echo.rb ADDED
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/superfeedr-blather'
2
+ require 'blather/client'
3
+
4
+ setup YOUR_SUPERFEEDR_USERNAME, YOUR_SUPERFEEDR_PASSWORD
5
+
6
+ when_ready do
7
+ Blather.logger.info "Connected..."
8
+ end
9
+
10
+ pubsub_event do |e|
11
+ puts "\n<!--Incoming!-->\n\n"
12
+
13
+ e.items.each do |i|
14
+ entry = i.entry
15
+ puts "Entry:"
16
+ puts " #{entry.id}"
17
+ puts " #{entry.link.href}"
18
+ puts " #{entry.title}"
19
+ puts " #{entry.content}"
20
+ end
21
+
22
+ puts "\n<--eof message-->"
23
+ end
24
+
@@ -0,0 +1,41 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/superfeedr-blather'
2
+ require 'blather/client'
3
+
4
+ setup YOUR_SUPERFEEDR_USERNAME, YOUR_SUPERFEEDR_PASSWORD
5
+
6
+ when_ready do
7
+ Blather.logger.info "Connected..."
8
+
9
+ # TODO: use callbacks instead of timed sequence
10
+
11
+ EM.add_timer(1) {
12
+ write_to_stream Blather::Stanza::PubSub::Subscriptions.new(:get, :id => "subman1", :from => jid, :to => "firehoser.superfeedr.com")
13
+ }
14
+
15
+ EM.add_timer(4) {
16
+ Blather.logger.info "unsubscribing from dummy"
17
+ write_to_stream Blather::Stanza::PubSub::Unsubscribe.new :set, "firehoser.superfeedr.com", "http://superfeedr.com/dummy.xml", jid
18
+ }
19
+
20
+ EM.add_timer(7) {
21
+ write_to_stream Blather::Stanza::PubSub::Subscriptions.new(:get, :id => "subman1", :from => jid, :to => "firehoser.superfeedr.com")
22
+ }
23
+
24
+ EM.add_timer(10) {
25
+ Blather.logger.info "re-subscribing to dummy"
26
+ write_to_stream Blather::Stanza::PubSub::Subscribe.new :set, "firehoser.superfeedr.com", "http://superfeedr.com/dummy.xml", jid
27
+ }
28
+
29
+ EM.add_timer(13) {
30
+ write_to_stream Blather::Stanza::PubSub::Subscriptions.new(:get, :id => "subman1", :from => jid, :to => "firehoser.superfeedr.com")
31
+ }
32
+ end
33
+
34
+ pubsub_subscriptions do |subs|
35
+ if subs.list.detect { |sub| sub.node_url =~ /dummy\.xml/ }
36
+ Blather.logger.info "subscribed to dummy.xml"
37
+ else
38
+ Blather.logger.info "not subscribed to dummy.xml"
39
+ end
40
+ end
41
+
data/examples/timer.rb ADDED
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + '/../lib/superfeedr-blather'
2
+ require 'blather/client'
3
+
4
+ setup YOUR_SUPERFEEDR_USERNAME, YOUR_SUPERFEEDR_PASSWORD
5
+
6
+ when_ready do
7
+ Blather.logger.info"Connected..."
8
+
9
+ EM.add_periodic_timer(3) {
10
+ Blather.logger.info "fetching subs"
11
+ write_to_stream Blather::Stanza::PubSub::Subscriptions.new(:get, :id => "subman1", :from => jid, :to => "firehoser.superfeedr.com")
12
+ }
13
+ end
14
+
15
+ pubsub_subscriptions do |subs|
16
+ puts "\n<!--Incoming!-->\n\n"
17
+ subs.list.each { |sub| puts "#{sub.node_url} is #{sub.subscription_state}" }
18
+ puts "\n<--eof message-->"
19
+ end
@@ -0,0 +1,20 @@
1
+ # Monkey-patch to add status and fix items lookup
2
+
3
+ module Blather
4
+ class Stanza
5
+ class PubSub
6
+ class Event < Message
7
+ def items
8
+ items_node.find('.//ps:item', :ps => PS).map do |i|
9
+ PubSubItem.new(nil,nil,self.document).inherit i
10
+ end
11
+ end
12
+
13
+ def status
14
+ n = find("ps_event:event/sf:status", :ps_event => PS_EVENT, :sf => SF)
15
+ Superfeedr::Status.new(n) if n
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ ATOM = "http://www.w3.org/2005/Atom"
2
+ GEO = "http://www.georss.org/georss"
3
+ PS = "http://jabber.org/protocol/pubsub"
4
+ PS_EVENT = "http://jabber.org/protocol/pubsub#event"
5
+ SF = "http://superfeedr.com/xmpp-pubsub-ext"
@@ -0,0 +1,12 @@
1
+ # Adds superfeedr entry to PubSubItem
2
+
3
+ module Blather
4
+ class Stanza
5
+ class PubSubItem < XMPPNode
6
+ def entry
7
+ n = find("atom:entry", :atom => ATOM)
8
+ Superfeedr::Entry.new(n) unless n.nil?
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ # Monkey-patch to add superfeedr namespace and jid/page attributes
2
+
3
+ module Blather
4
+ class Stanza
5
+ class PubSub
6
+ class Subscriptions
7
+ def self.new(type, opts = {})
8
+ new_node = super type, nil
9
+ new_node.to = opts.delete(:to) || opts.delete(:host)
10
+ new_node.from = opts.delete(:from)
11
+ new_node.id = opts.delete(:id)
12
+ new_node.pubsub.add_namespace_definition("sf", SF)
13
+ new_node.subscriptions(opts.delete(:page) || 1)
14
+ new_node
15
+ end
16
+
17
+ def subscriptions(page = 1)
18
+ aff = pubsub.find_first('subscriptions', self.class.registered_ns)
19
+ unless aff
20
+ aff = XMPPNode.new('subscriptions', self.document)
21
+ aff["sf:page"] = page.to_s
22
+ aff["jid"] = self.from
23
+ self.pubsub << aff
24
+ end
25
+ aff
26
+ end
27
+
28
+ def list
29
+ subscriptions.find('//ns:subscription', :ns => self.class.registered_ns).map do |child|
30
+ Superfeedr::Subscription.new(child)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,210 @@
1
+ module Superfeedr
2
+ class Node
3
+ def initialize(node)
4
+ @node = node
5
+ end
6
+
7
+ private
8
+
9
+ def content_from(name, ns = nil)
10
+ child = xpath(name, ns).first
11
+ child.content if child
12
+ end
13
+
14
+ def datetime_from(name, ns = nil)
15
+ datetime = content_from(name, ns)
16
+ DateTime.parse(datetime) if datetime
17
+ end
18
+
19
+ def integer_from(name, ns = nil)
20
+ int = content_from(name, ns)
21
+ int.to_i if int
22
+ end
23
+
24
+ def xpath(name, ns = nil)
25
+ ns ||= {:atom => ATOM, :geo => GEO, :sf => SF}
26
+ @node.xpath(name, ns)
27
+ end
28
+ end
29
+
30
+
31
+ class Entry < Node
32
+ # entry[@id] : the Unique ID of the entry. If the original entry doesn't have an ID.
33
+ def id
34
+ content_from("atom:id")
35
+ end
36
+
37
+ # entry[@title] : The title of the entry.
38
+ def title
39
+ content_from("atom:title")
40
+ end
41
+
42
+ # entry[@published] : The publication date (iso8601) of the entry.
43
+ def published_at
44
+ datetime_from("atom:published")
45
+ end
46
+
47
+ # entry[@updated] : The last updated date (iso8601) of the entry.
48
+ def updated_at
49
+ datetime_from("atom:updated")
50
+ end
51
+
52
+ # entry[@content] : The content of the entry. Check the type attribute to determine the mime-type.
53
+ def content
54
+ content_from("atom:content")
55
+ end
56
+
57
+ def mime_type
58
+ content_from("atom:content/@type")
59
+ end
60
+
61
+ # entry[@summary] (optional, unique) : The summary of the entry. Check the type attribute to determine the mime-type
62
+ def summary
63
+ content_from("atom:summary")
64
+ end
65
+
66
+ # entry[@xml:lang] : The language of the entry. It's either extracted or computed from the content (the longer t# he content, the more relevant).
67
+ def lang
68
+ content_from("@lang")
69
+ end
70
+
71
+ def link
72
+ child = xpath("atom:link")
73
+ Link.new(child) if child
74
+ end
75
+
76
+ def categories
77
+ xpath(".//atom:category/@term").map { |c| c.text }
78
+ end
79
+
80
+ def authors
81
+ xpath(".//atom:author").map { |child| Author.new(child) }
82
+ end
83
+
84
+ def points
85
+ xpath(".//geo:point").map { |child| Point.new(child) }
86
+ end
87
+ end
88
+
89
+ class Status < Node
90
+ # title (provided only upon notification) : the feed title.
91
+ def title
92
+ content_from("sf:title")
93
+ end
94
+
95
+ # http[@code] : last HTTP status code, please see Status Code Definitions.
96
+ def http_code
97
+ content_from("sf:http/@code")
98
+ end
99
+
100
+ # http : the content of that tag is a more explicit log message for your information.
101
+ def http
102
+ content_from("sf:http")
103
+ end
104
+
105
+ # status[@feed] : contains the URL of the feed
106
+ def feed
107
+ content_from("@feed")
108
+ end
109
+
110
+ # status[@digest] : if sets to true; it indicates that the
111
+ # notification is a digest.
112
+ def digest?
113
+ !!content_from("@digest")
114
+ end
115
+
116
+ # period : the polling frequency in seconds for this feed.
117
+ def period
118
+ integer_from("sf:period")
119
+ end
120
+
121
+ # next_fetch : the feed will be fetched at most before this time.
122
+ def next_fetch
123
+ datetime_from("sf:next_fetch")
124
+ end
125
+
126
+ # last_fetch : the last time at which we fetched the feed.
127
+ def last_fetch
128
+ datetime_from("sf:last_fetch")
129
+ end
130
+
131
+ # last_parse : the last time at which we parsed the feed. It happens that we fetch a feed and do not parse it as its content hasn't been modified.
132
+ def last_parse
133
+ datetime_from("sf:last_parse")
134
+ end
135
+
136
+ # last_maintenance_at : Each feed inside Node has a
137
+ # maintenance cycle that we use to detect stale feeds, or related
138
+ # feeds. We normally run maintenance at most every 24hour for each
139
+ # feed.
140
+
141
+ def last_maintenance_at
142
+ datetime_from("sf:last_maintenance_at")
143
+ end
144
+
145
+ # entries_count_since_last_maintenance (provided only upon notification) : The number of new entries in the feed since we last ran the maintenance script. This is a very good indicator of the verboseness of a feed. You may want to remove feeds that are too verbose.
146
+ def entries_count_since_last_maintenance
147
+ integer_from("sf:entries_count_since_last_maintenance")
148
+ end
149
+ end
150
+
151
+ class Author < Node
152
+ def name
153
+ content_from("atom:name")
154
+ end
155
+
156
+ def uri
157
+ content_from("atom:uri")
158
+ end
159
+
160
+ def email
161
+ content_from("atom:email")
162
+ end
163
+ end
164
+
165
+ class Link < Node
166
+ def type
167
+ content_from("@type")
168
+ end
169
+
170
+ def title
171
+ content_from("@title")
172
+ end
173
+
174
+ def rel
175
+ content_from("@rel")
176
+ end
177
+
178
+ def href
179
+ content_from("@href")
180
+ end
181
+ end
182
+
183
+ class Point < Node
184
+ def raw
185
+ content_from(".")
186
+ end
187
+
188
+ def longtitude
189
+ point.first
190
+ end
191
+
192
+ def latitude
193
+ point.last
194
+ end
195
+
196
+ def point
197
+ @point ||= (raw || []) && raw.split(",")
198
+ end
199
+ end
200
+
201
+ class Subscription < Node
202
+ def subscription_state
203
+ content_from("@subscription")
204
+ end
205
+
206
+ def node_url
207
+ content_from("@node")
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ Bundler.require(:default)
5
+
6
+ %w(namespaces pubsub event subscriptions).each { |f| require File.join(File.expand_path(File.dirname(__FILE__)), "blather", f) }
7
+ %w(superfeedr).each { |f| require File.join(File.expand_path(File.dirname(__FILE__)), "superfeedr", f) }
@@ -0,0 +1,51 @@
1
+ <message type="chat" from="firehoser.superfeedr.com" to="test@superfeedr.com"><active xmlns="http://jabber.org/protocol/chatstates"/>
2
+ <event xmlns="http://jabber.org/protocol/pubsub#event">
3
+ <status xmlns="http://superfeedr.com/xmpp-pubsub-ext" feed="http://superfeedr.com/dummy.xml">
4
+ <http code="200">7462B in 2.441718s, 2/10 new entries</http>
5
+ <next_fetch>2010-12-10T16:06:41Z</next_fetch>
6
+ <title>The Dummy Time Feed</title>
7
+ <entries_count_since_last_maintenance>19</entries_count_since_last_maintenance>
8
+ <period>450</period>
9
+ <last_fetch>2010-12-10T15:59:11Z</last_fetch>
10
+ <last_parse>2010-12-10T15:59:11Z</last_parse>
11
+ <last_maintenance_at>2010-12-10T06:25:29+00:00</last_maintenance_at>
12
+ </status>
13
+ <items node="http://superfeedr.com/dummy.xml">
14
+ <item xmlns="http://jabber.org/protocol/pubsub">
15
+ <entry xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.georss.org/georss" xmlns:as="http://activitystrea.ms/spec/1.0/" xmlns:sf="http://superfeedr.com/xmpp-pubsub-ext" lang="en-US">
16
+ <id>tag:superfeedr.com,2005:String/1291996755</id>
17
+ <published>2010-12-10T15:59:15+00:00</published>
18
+ <updated>2010-12-10T15:59:15+00:00</updated>
19
+ <title>15:59:15</title>
20
+ <content type="text">Friday December 10 15:59:15 UTC 2010 Somebody wanted to know what time it was.</content>
21
+ <summary>A short message from our sponsors</summary>
22
+ <geo:point>37.773721,-122.414957</geo:point>
23
+ <link type="text/html" title="15:59:15" rel="alternate" href="http://superfeedr.com/?1291996755"/>
24
+ <category term="tests"/>
25
+ <author>
26
+ <name>Superfeedr</name>
27
+ <uri>http://superfeedr.com/</uri>
28
+ <email>julien@superfeedr.com</email>
29
+ </author>
30
+ </entry>
31
+ </item>
32
+ <item xmlns="http://jabber.org/protocol/pubsub">
33
+ <entry xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.georss.org/georss" xmlns:as="http://activitystrea.ms/spec/1.0/" xmlns:sf="http://superfeedr.com/xmpp-pubsub-ext" lang="en-US">
34
+ <id>tag:superfeedr.com,2005:String/1291996758</id>
35
+ <published>2010-12-10T15:59:18+00:00</published>
36
+ <updated>2010-12-10T15:59:18+00:00</updated>
37
+ <title>15:59:18</title>
38
+ <content type="text">Friday December 10 15:59:18 UTC 2010 Somebody wanted to know what time it was.</content>
39
+ <geo:point>37.773721,-122.414957</geo:point>
40
+ <link type="text/html" title="15:59:18" rel="alternate" href="http://superfeedr.com/?1291996758"/>
41
+ <category term="tests"/>
42
+ <author>
43
+ <name>Superfeedr</name>
44
+ <uri>http://superfeedr.com/</uri>
45
+ <email>julien@superfeedr.com</email>
46
+ </author>
47
+ </entry>
48
+ </item>
49
+ </items>
50
+ </event>
51
+ </message>
@@ -0,0 +1,26 @@
1
+ <iq from="firehoser.superfeedr.com" to="test@superfeedr.com/client" type="result" id="subman1">
2
+ <pubsub xmlns:superfeedr="http://superfeedr.com/xmpp-pubsub-ext" xmlns="http://jabber.org/protocol/pubsub">
3
+ <subscriptions page="1">
4
+ <subscription node="http://superfeedr.com/dummy.xml" format="atom" jid="test@superfeedr.com" subscription="subscribed" digest="false">
5
+ <superfeedr:status>
6
+ <superfeedr:http code="304">Content not modified</superfeedr:http>
7
+ <superfeedr:next_fetch>2010-12-29T19:59:27+00:00</superfeedr:next_fetch>
8
+ <superfeedr:period>14400</superfeedr:period>
9
+ <superfeedr:last_fetch>2010-12-29T15:59:27+00:00</superfeedr:last_fetch>
10
+ <superfeedr:last_parse>2010-12-29T11:19:47+00:00</superfeedr:last_parse>
11
+ <superfeedr:last_maintenance_at>2010-12-29T07:21:29+00:00</superfeedr:last_maintenance_at>
12
+ </superfeedr:status>
13
+ </subscription>
14
+ <subscription node="http://superfeedr.com/fake.xml" format="atom" jid="test@superfeedr.com" subscription="subscribed" digest="false">
15
+ <superfeedr:status>
16
+ <superfeedr:http code="2">Content not modified</superfeedr:http>
17
+ <superfeedr:next_fetch>2010-12-29T19:59:27+00:00</superfeedr:next_fetch>
18
+ <superfeedr:period>14400</superfeedr:period>
19
+ <superfeedr:last_fetch>2010-12-29T15:59:27+00:00</superfeedr:last_fetch>
20
+ <superfeedr:last_parse>2010-12-29T11:19:47+00:00</superfeedr:last_parse>
21
+ <superfeedr:last_maintenance_at>2010-12-29T07:21:29+00:00</superfeedr:last_maintenance_at>
22
+ </superfeedr:status>
23
+ </subscription>
24
+ </subscriptions>
25
+ </pubsub>
26
+ </iq>
@@ -0,0 +1,5 @@
1
+ <iq type="get" id="subman1" to="firehoser.superfeedr.com" from="test@superfeedr.com/client">
2
+ <pubsub xmlns="http://jabber.org/protocol/pubsub" xmlns:superfeedr="http://superfeedr.com/xmpp-pubsub-ext">
3
+ <subscriptions superfeedr:page="1" jid="test@superfeedr.com/client"/>
4
+ </pubsub>
5
+ </iq>
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__)) + "/../lib/superfeedr-blather"
2
+
3
+ Bundler.require(:test)
4
+
5
+ RSpec.configure do |config|
6
+ # config.include SpecHelper
7
+ end
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ describe "notifications" do
4
+ let(:message) { @message ||= open(File.expand_path(File.dirname(__FILE__) + '/../fixtures/notification.xml')) }
5
+ let(:node) { @node ||= Blather::XMPPNode.import(Nokogiri::XML.parse(message).root) }
6
+
7
+ describe Blather::Stanza::PubSub::Event do
8
+ it "finds items" do
9
+ node.should have(2).items
10
+ end
11
+
12
+ it "finds status" do
13
+ node.status.should be_present
14
+ end
15
+ end
16
+
17
+ describe Blather::Stanza::PubSubItem do
18
+ it "finds entries" do
19
+ node.items.map(&:entry).compact.should have(2).entries
20
+ end
21
+ end
22
+
23
+ describe Superfeedr::Entry do
24
+ let(:entry) { node.items.first.entry }
25
+
26
+ it "finds the id" do
27
+ entry.id.should == "tag:superfeedr.com,2005:String/1291996755"
28
+ end
29
+
30
+ it "finds the title" do
31
+ entry.title.should == "15:59:15"
32
+ end
33
+
34
+ it "finds the date published" do
35
+ entry.published_at.should == DateTime.parse("2010-12-10T15:59:15+00:00")
36
+ end
37
+
38
+ it "finds the date updated" do
39
+ entry.updated_at.should == DateTime.parse("2010-12-10T15:59:15+00:00")
40
+ end
41
+
42
+ it "finds the mime-type of the content" do
43
+ entry.mime_type.should == "text"
44
+ end
45
+
46
+ it "finds the content" do
47
+ entry.content.should == "Friday December 10 15:59:15 UTC 2010 Somebody wanted to know what time it was."
48
+ end
49
+
50
+ it "finds the summary" do
51
+ entry.summary.should == "A short message from our sponsors"
52
+ end
53
+
54
+ it "finds the lanugage" do
55
+ entry.lang.should == "en-US"
56
+ end
57
+
58
+ it "finds the link" do
59
+ entry.link.should be_instance_of(Superfeedr::Link)
60
+ end
61
+
62
+ it "finds points" do
63
+ entry.points.should have(1).item
64
+ end
65
+
66
+ it "finds the categories" do
67
+ entry.categories.should =~ %w(tests)
68
+ end
69
+
70
+ it "finds the authors" do
71
+ entry.authors.should have(1).item
72
+ end
73
+ end
74
+
75
+ describe Superfeedr::Status do
76
+ let(:status) { node.status }
77
+
78
+ it "finds the title" do
79
+ status.title.should == "The Dummy Time Feed"
80
+ end
81
+
82
+ it "finds the http status" do
83
+ status.http_code.should == "200"
84
+ end
85
+
86
+ it "finds the http response stats" do
87
+ status.http.should == "7462B in 2.441718s, 2/10 new entries"
88
+ end
89
+
90
+ it "finds the entries_count_since_last_maintenance" do
91
+ status.entries_count_since_last_maintenance.should == 19
92
+ end
93
+
94
+ it "finds the period" do
95
+ status.period.should == 450
96
+ end
97
+
98
+ it "finds the next fetch datetime" do
99
+ status.next_fetch.should == DateTime.parse("2010-12-10T16:06:41Z")
100
+ end
101
+ end
102
+
103
+ describe Superfeedr::Link do
104
+ let(:link) { node.items.first.entry.link }
105
+
106
+ it "finds type" do
107
+ link.type.should == "text/html"
108
+ end
109
+
110
+ it "finds title" do
111
+ link.title.should == "15:59:15"
112
+ end
113
+
114
+ it "finds rel" do
115
+ link.rel.should == "alternate"
116
+ end
117
+
118
+ it "finds href" do
119
+ link.href.should == "http://superfeedr.com/?1291996755"
120
+ end
121
+ end
122
+
123
+ describe Superfeedr::Author do
124
+ let(:author) { node.items.first.entry.authors.first }
125
+
126
+ it "finds name" do
127
+ author.name.should == "Superfeedr"
128
+ end
129
+
130
+ it "finds uri" do
131
+ author.uri.should == "http://superfeedr.com/"
132
+ end
133
+
134
+ it "finds email" do
135
+ author.email.should == "julien@superfeedr.com"
136
+ end
137
+ end
138
+
139
+ describe Superfeedr::Point do
140
+ let(:point) { node.items.first.entry.points.first }
141
+
142
+ it "finds long/lat" do
143
+ point.longtitude.should == "37.773721"
144
+ point.latitude.should == "-122.414957"
145
+ end
146
+
147
+ it "finds raw data" do
148
+ point.raw.should == "37.773721,-122.414957"
149
+ end
150
+ end
151
+
152
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe "list of resources/subscriptions" do
4
+ let(:stanza) { @stanza ||= open(File.expand_path(File.dirname(__FILE__) + '/../fixtures/resource_list.xml')) }
5
+ let(:node) { @node ||= Blather::XMPPNode.import(Nokogiri::XML.parse(stanza).root) }
6
+
7
+ describe Blather::Stanza::PubSub::Subscriptions do
8
+ it "finds subscriptions" do
9
+ node.list.should have(2).items
10
+ end
11
+ end
12
+
13
+ describe Superfeedr::Subscription do
14
+ let(:sub) { node.list.first }
15
+
16
+ it "finds subscription state" do
17
+ sub.subscription_state.should == "subscribed"
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "requesting list of resources/subscriptions" do
23
+ describe Blather::Stanza::PubSub::Subscriptions do
24
+ let(:node) { @node ||= Blather::Stanza::PubSub::Subscriptions.new(:get, :id => "subman1", :from => "test@superfeedr.com", :to => "firehoser.superfeedr.com") }
25
+
26
+ it "includes correct to, from, and id attributes in the <iq> node" do
27
+ node["from"].should == "test@superfeedr.com"
28
+ node["to"].should == "firehoser.superfeedr.com"
29
+ node["id"].should == "subman1"
30
+ end
31
+
32
+ it "includes superfeedr namespace in the <pubsub> node" do
33
+ pubsub_node = node.find_first(".//ns:subscriptions", :ns => Blather::Stanza::PubSub.registered_ns)
34
+ pubsub_node.namespaces["xmlns:sf"].should == "http://superfeedr.com/xmpp-pubsub-ext"
35
+ end
36
+
37
+ it "includes page and jid in the <subscriptions> node" do
38
+ subscriptions_node = node.find_first(".//ns:subscriptions", :ns => Blather::Stanza::PubSub.registered_ns)
39
+ subscriptions_node["jid"].should == "test@superfeedr.com"
40
+ subscriptions_node["sf:page"].should == "1"
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{superfeedr-blather}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["dave@kapoq.com"]
12
+ s.date = %q{2011-01-03}
13
+ s.description = %q{You get some patches for Blather and some classes that wrap the stuff you want from Superfeedr (entries, authors etc.). Under-the-hood, Blather uses EventMachine and Nokogiri so it’s fast and convenient. If you want to daemonize your client, daemon-kit comes ready with a blather template.}
14
+ s.email = %q{dave@kapoq.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE",
24
+ "README",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "autotest/discover.rb",
29
+ "examples/echo.rb",
30
+ "examples/sub_unsub.rb",
31
+ "examples/timer.rb",
32
+ "lib/blather/event.rb",
33
+ "lib/blather/namespaces.rb",
34
+ "lib/blather/pubsub.rb",
35
+ "lib/blather/subscriptions.rb",
36
+ "lib/superfeedr-blather.rb",
37
+ "lib/superfeedr/superfeedr.rb",
38
+ "spec/fixtures/notification.xml",
39
+ "spec/fixtures/resource_list.xml",
40
+ "spec/fixtures/resources_list_request.xml",
41
+ "spec/spec_helper.rb",
42
+ "spec/stanza/notification_spec.rb",
43
+ "spec/stanza/subscriptions_spec.rb",
44
+ "superfeedr-blather.gemspec"
45
+ ]
46
+ s.homepage = %q{http://github.com/kapoq/superfeedr-blather}
47
+ s.licenses = ["MIT"]
48
+ s.require_paths = ["lib"]
49
+ s.rubygems_version = %q{1.3.7}
50
+ s.summary = %q{superfeedr-blather implements a Superfeedr PubSub XMPP client in Ruby using the Blather gem.}
51
+ s.test_files = [
52
+ "examples/echo.rb",
53
+ "examples/sub_unsub.rb",
54
+ "examples/timer.rb",
55
+ "spec/spec_helper.rb",
56
+ "spec/stanza/notification_spec.rb",
57
+ "spec/stanza/subscriptions_spec.rb"
58
+ ]
59
+
60
+ if s.respond_to? :specification_version then
61
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
62
+ s.specification_version = 3
63
+
64
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
+ s.add_runtime_dependency(%q<blather>, ["~> 0.4.14"])
66
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
67
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
68
+ s.add_runtime_dependency(%q<blather>, ["~> 0.4.14"])
69
+ else
70
+ s.add_dependency(%q<blather>, ["~> 0.4.14"])
71
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
72
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
73
+ s.add_dependency(%q<blather>, ["~> 0.4.14"])
74
+ end
75
+ else
76
+ s.add_dependency(%q<blather>, ["~> 0.4.14"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
78
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
79
+ s.add_dependency(%q<blather>, ["~> 0.4.14"])
80
+ end
81
+ end
82
+
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: superfeedr-blather
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - dave@kapoq.com
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-03 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: blather
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 4
30
+ - 14
31
+ version: 0.4.14
32
+ type: :runtime
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: jeweler
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 5
45
+ - 2
46
+ version: 1.5.2
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: yard
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ - 6
60
+ - 0
61
+ version: 0.6.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: blather
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ - 4
75
+ - 14
76
+ version: 0.4.14
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *id004
80
+ description: "You get some patches for Blather and some classes that wrap the stuff you want from Superfeedr (entries, authors etc.). Under-the-hood, Blather uses EventMachine and Nokogiri so it\xE2\x80\x99s fast and convenient. If you want to daemonize your client, daemon-kit comes ready with a blather template."
81
+ email: dave@kapoq.com
82
+ executables: []
83
+
84
+ extensions: []
85
+
86
+ extra_rdoc_files:
87
+ - LICENSE
88
+ - README
89
+ - README.rdoc
90
+ files:
91
+ - Gemfile
92
+ - Gemfile.lock
93
+ - LICENSE
94
+ - README
95
+ - README.rdoc
96
+ - Rakefile
97
+ - VERSION
98
+ - autotest/discover.rb
99
+ - examples/echo.rb
100
+ - examples/sub_unsub.rb
101
+ - examples/timer.rb
102
+ - lib/blather/event.rb
103
+ - lib/blather/namespaces.rb
104
+ - lib/blather/pubsub.rb
105
+ - lib/blather/subscriptions.rb
106
+ - lib/superfeedr-blather.rb
107
+ - lib/superfeedr/superfeedr.rb
108
+ - spec/fixtures/notification.xml
109
+ - spec/fixtures/resource_list.xml
110
+ - spec/fixtures/resources_list_request.xml
111
+ - spec/spec_helper.rb
112
+ - spec/stanza/notification_spec.rb
113
+ - spec/stanza/subscriptions_spec.rb
114
+ - superfeedr-blather.gemspec
115
+ has_rdoc: true
116
+ homepage: http://github.com/kapoq/superfeedr-blather
117
+ licenses:
118
+ - MIT
119
+ post_install_message:
120
+ rdoc_options: []
121
+
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3239166693757579629
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ requirements: []
142
+
143
+ rubyforge_project:
144
+ rubygems_version: 1.3.7
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: superfeedr-blather implements a Superfeedr PubSub XMPP client in Ruby using the Blather gem.
148
+ test_files:
149
+ - examples/echo.rb
150
+ - examples/sub_unsub.rb
151
+ - examples/timer.rb
152
+ - spec/spec_helper.rb
153
+ - spec/stanza/notification_spec.rb
154
+ - spec/stanza/subscriptions_spec.rb