superfeedr-blather 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.
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