superfeedr-ruby 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +69 -0
- data/Rakefile +80 -0
- data/VERSION.yml +4 -0
- data/lib/config.yaml +2 -0
- data/lib/stanzas/iq_query_stanza.rb +36 -0
- data/lib/stanzas/notification_stanza.rb +75 -0
- data/lib/stanzas/subscribe_query_stanza.rb +26 -0
- data/lib/stanzas/subscriptions_query_stanza.rb +18 -0
- data/lib/stanzas/unsubscribe_query_stanza.rb +27 -0
- data/lib/superfeedr.rb +210 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/stanzas/iq_query_stanza_spec.rb +30 -0
- data/spec/stanzas/notifications_stanza_spec.rb +91 -0
- data/spec/stanzas/subscribe_stanza_spec.rb +15 -0
- data/spec/stanzas/subscriptions_stanza_spec.rb +15 -0
- data/spec/stanzas/unsubscribe_stanza_spec.rb +15 -0
- data/spec/superfeedr_ruby_spec.rb +237 -0
- metadata +99 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 julien
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
= superfeedr-ruby
|
2
|
+
|
3
|
+
Yes, the gem is called superfeedr-ruby, but the library is superfeedr only ;)
|
4
|
+
|
5
|
+
{Superfeedr.com}[http://superfeedr.com] is a Real-time Cloud Feed Parsing service
|
6
|
+
|
7
|
+
* *Realtime* : By combining different technologies we can notify you of new entries in less than 15 minutes (or it's free)
|
8
|
+
* *No* *more* *polling* : Stop wasting your time and resources fetching 'old data', and stop being late when there is new data.
|
9
|
+
* *Simplicity* : give us urls, and we'll do the rest. Check our docs and tutorials.
|
10
|
+
* *Standardization* : No more nightmares with gazillions of formats, we will send you strict ATOM, whatever the original feed format is.
|
11
|
+
* *Multi*-*channel* : receive the notifications by XMPP, on a local JID or your own external JID, or using WebHooks.
|
12
|
+
* *Cost* *saving* : we will match the cost of your existing system.
|
13
|
+
|
14
|
+
== FEATURES:
|
15
|
+
|
16
|
+
* Subscribe to a feed
|
17
|
+
|
18
|
+
Superfeedr.subscribe("http://github.com/superfeedr.atom") do |result|
|
19
|
+
puts "Yay, subscribed to the github Atom feed for Superfeedr" if result
|
20
|
+
end
|
21
|
+
|
22
|
+
* Unsubscribe from a feed
|
23
|
+
|
24
|
+
Superfeedr.unsubscribe("http://github.com/superfeedr.atom") do |result|
|
25
|
+
puts "Sad, you unsubscribed from the github Atom feed for Superfeedr" if result
|
26
|
+
end
|
27
|
+
|
28
|
+
* List subscriptions by page
|
29
|
+
|
30
|
+
Superfeedr.subscriptions(5) do |page, feeds|
|
31
|
+
puts "On page #{page}" :
|
32
|
+
puts feeds.inspect
|
33
|
+
end
|
34
|
+
|
35
|
+
* Receive notifications
|
36
|
+
|
37
|
+
Superfeedr.on_notification do |notification|
|
38
|
+
puts "The feed #{notification.feed_url} has been fetched (#{notification.http_status}: #{notification.message_status}) and will be fetched again in #{(notification.next_fetch - Time.now)/60} minutes."
|
39
|
+
notification.entries.each do |e|
|
40
|
+
puts " - #{e.title} (#{e.link}) was published (#{e.published}) with #{e.unique_id} as unique id : \n #{e.summary} (#{e.chunk}/#{e.chunks})"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
== Install
|
45
|
+
|
46
|
+
Install the gem from Github :
|
47
|
+
|
48
|
+
gem sources -a http://gems.github.com
|
49
|
+
sudo gem install superfeedr-superfeedr-ruby
|
50
|
+
|
51
|
+
Source :
|
52
|
+
|
53
|
+
git clone git@github.com:superfeedr/superfeedr-ruby.git
|
54
|
+
|
55
|
+
|
56
|
+
== Example
|
57
|
+
|
58
|
+
Please see this {Gist}[http://gist.github.com/110247] while I am trying to find a way to integrate it into this document ;)
|
59
|
+
|
60
|
+
|
61
|
+
== REQUIREMENTS:
|
62
|
+
|
63
|
+
{Babylon}[http://github.com/julien51/skates/tree/master] : please note that there are 2 gems named Baylon. The one you want is the one about XMPP, you can get it with :
|
64
|
+
|
65
|
+
sudo gem install skates
|
66
|
+
|
67
|
+
== Copyright
|
68
|
+
|
69
|
+
Copyright (c) 2009 julien. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
config = YAML.load(File.read('VERSION.yml'))
|
8
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
9
|
+
gem.name = "superfeedr-ruby"
|
10
|
+
gem.version = "#{version}"
|
11
|
+
gem.summary = %Q{Ruby Client for the Superfeedr}
|
12
|
+
gem.email = "julien.genestoux@gmail.com"
|
13
|
+
gem.homepage = "http://github.com/julien51/superfeedr-ruby"
|
14
|
+
gem.authors = ["julien Genestoux"]
|
15
|
+
gem.rubyforge_project = "superfeedr-ruby"
|
16
|
+
gem.add_dependency('skates')
|
17
|
+
gem.add_dependency('nokogiri')
|
18
|
+
gem.has_rdoc = true
|
19
|
+
gem.homepage = 'http://github.com/julien51/superfeedr-ruby/'
|
20
|
+
gem.files = FileList["[A-Z]*", "{bin,generators,lib,test,spec}/**/*"]
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
30
|
+
end
|
31
|
+
|
32
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
33
|
+
spec.libs << 'lib' << 'spec'
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rake/rdoctask'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
if File.exist?('VERSION.yml')
|
44
|
+
config = YAML.load(File.read('VERSION.yml'))
|
45
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
46
|
+
else
|
47
|
+
version = ""
|
48
|
+
end
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "superfeedr-ruby #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
require 'rake/contrib/sshpublisher'
|
58
|
+
namespace :rubyforge do
|
59
|
+
|
60
|
+
desc "Release gem and RDoc documentation to RubyForge"
|
61
|
+
task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
|
62
|
+
|
63
|
+
namespace :release do
|
64
|
+
desc "Publish RDoc to RubyForge."
|
65
|
+
task :docs => [:rdoc] do
|
66
|
+
config = YAML.load(
|
67
|
+
File.read(File.expand_path('~/.rubyforge/user-config.yml'))
|
68
|
+
)
|
69
|
+
|
70
|
+
host = "#{config['username']}@rubyforge.org"
|
71
|
+
remote_dir = "/var/www/gforge-projects/superfeedr-ruby/"
|
72
|
+
local_dir = 'rdoc'
|
73
|
+
|
74
|
+
Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
rescue LoadError
|
79
|
+
puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
|
80
|
+
end
|
data/VERSION.yml
ADDED
data/lib/config.yaml
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class IqQueryStanza
|
2
|
+
|
3
|
+
def initialize(params = {})
|
4
|
+
@doc = Nokogiri::XML::Document.new
|
5
|
+
@iq = Nokogiri::XML::Node.new("iq", @doc)
|
6
|
+
@iq["type"] = params[:type].to_s
|
7
|
+
@iq["to"] = Superfeedr.conf[:superfeedr_jid]
|
8
|
+
@iq["id"] = "#{random_iq_id}"
|
9
|
+
@iq["from"] = params[:from] if params[:from]
|
10
|
+
end
|
11
|
+
|
12
|
+
def type
|
13
|
+
@iq["type"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def to
|
17
|
+
@iq["to"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def from
|
21
|
+
@iq["from"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
@iq["id"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def random_iq_id
|
29
|
+
rand(1000)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
@iq.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
##
|
2
|
+
# Repesents the items published by the firehoser (the feed entries).
|
3
|
+
# They have accessors for the following fields :
|
4
|
+
# - title
|
5
|
+
# - summary
|
6
|
+
# - link
|
7
|
+
# - published
|
8
|
+
# - unique_id
|
9
|
+
# - chunks (long entries might be notified in several chunks)
|
10
|
+
# - chunk (current chunk out of chunks)
|
11
|
+
#
|
12
|
+
require "cgi"
|
13
|
+
class Item
|
14
|
+
include SAXMachine
|
15
|
+
element :item, :as => :chunk, :value => :chunk
|
16
|
+
element :item, :as => :chunks, :value => :chunks
|
17
|
+
element :title
|
18
|
+
element :summary
|
19
|
+
element :link, :as => :link, :value => :href
|
20
|
+
element :id, :as => :unique_id
|
21
|
+
element :published
|
22
|
+
|
23
|
+
def link
|
24
|
+
CGI.unescape(@link).gsub("\n", "")
|
25
|
+
end
|
26
|
+
|
27
|
+
def published
|
28
|
+
Time.parse(@published)
|
29
|
+
end
|
30
|
+
|
31
|
+
def chunks
|
32
|
+
@chunks.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def chunk
|
36
|
+
@chunk.to_i
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
##
|
43
|
+
# Notification : sent every time a feed has been fetched. It has the following methods:
|
44
|
+
# - message_status : a simple message that gives information about the last fetch
|
45
|
+
# - http_status : status of the http response
|
46
|
+
# - feed_url : url of the feed
|
47
|
+
# - next_fetch : Time when the feed will be fetched again (this is purely informative and it might change)
|
48
|
+
# - items : array of new items detected (might be empty)
|
49
|
+
class NotificationStanza
|
50
|
+
include SAXMachine
|
51
|
+
|
52
|
+
def initialize(xml)
|
53
|
+
parse(xml.to_s)
|
54
|
+
end
|
55
|
+
|
56
|
+
def next_fetch
|
57
|
+
Time.parse(@next_fetch)
|
58
|
+
end
|
59
|
+
|
60
|
+
def http_status
|
61
|
+
@http_status.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def feed_url
|
65
|
+
CGI.unescape(@feed_url).gsub("\n", "")
|
66
|
+
end
|
67
|
+
|
68
|
+
element :http, :as => :message_status
|
69
|
+
element :http, :as => :http_status, :value => :code
|
70
|
+
element :status, :value => :feed, :as => :feed_url
|
71
|
+
element :next_fetch
|
72
|
+
elements :item, :as => :entries, :class => Item
|
73
|
+
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class SubscribeQueryStanza < IqQueryStanza
|
2
|
+
|
3
|
+
def initialize(params)
|
4
|
+
raise NoFeedToSubscribe if params[:nodes].nil? or params[:nodes].empty?
|
5
|
+
raise TooManyFeeds if params[:nodes].size > 30
|
6
|
+
super(params.merge({:type => :set}))
|
7
|
+
@pubsub = Nokogiri::XML::Node.new("pubsub", @doc)
|
8
|
+
@pubsub["xmlns"] = "http://jabber.org/protocol/pubsub"
|
9
|
+
params[:nodes].each do |node|
|
10
|
+
add_node(node)
|
11
|
+
end
|
12
|
+
@iq.add_child(@pubsub)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_node(node)
|
16
|
+
subscribe = Nokogiri::XML::Node.new("subscribe", @doc)
|
17
|
+
subscribe["node"] = node
|
18
|
+
subscribe["jid"] = from.split("/").first
|
19
|
+
@pubsub.add_child(subscribe)
|
20
|
+
end
|
21
|
+
|
22
|
+
def nodes
|
23
|
+
@pubsub.children.map {|c| c["node"]}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class SubscriptionsQueryStanza < IqQueryStanza
|
2
|
+
|
3
|
+
def initialize(params)
|
4
|
+
super(params.merge({:type => :get}))
|
5
|
+
pubsub = Nokogiri::XML::Node.new("pubsub", @doc)
|
6
|
+
pubsub["xmlns"] = "http://jabber.org/protocol/pubsub"
|
7
|
+
@iq.add_child(pubsub)
|
8
|
+
subscriptions = Nokogiri::XML::Node.new("subscriptions", @doc)
|
9
|
+
subscriptions["page"] = params[:page].to_s
|
10
|
+
subscriptions["jid"] = from.split("/").first
|
11
|
+
pubsub.add_child(subscriptions)
|
12
|
+
end
|
13
|
+
|
14
|
+
def page
|
15
|
+
@iq.search("subscriptions").first["page"]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class UnsubscribeQueryStanza < IqQueryStanza
|
2
|
+
|
3
|
+
def initialize(params)
|
4
|
+
raise NoFeedToSubscribe if params[:nodes].nil? or params[:nodes].empty?
|
5
|
+
raise TooManyFeeds if params[:nodes].size > 30
|
6
|
+
super(params.merge({:type => :set}))
|
7
|
+
|
8
|
+
@pubsub = Nokogiri::XML::Node.new("pubsub", @doc)
|
9
|
+
params[:nodes].each do |node|
|
10
|
+
add_node(node)
|
11
|
+
end
|
12
|
+
@pubsub["xmlns"] = "http://jabber.org/protocol/pubsub"
|
13
|
+
@iq.add_child(@pubsub)
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_node(node)
|
17
|
+
unsubscribe = Nokogiri::XML::Node.new("unsubscribe", @doc)
|
18
|
+
unsubscribe["node"] = node.to_s
|
19
|
+
unsubscribe["jid"] = from.split("/").first
|
20
|
+
@pubsub.add_child(unsubscribe)
|
21
|
+
end
|
22
|
+
|
23
|
+
def nodes
|
24
|
+
@pubsub.children.map {|c| c["node"]}
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/superfeedr.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
require "skates"
|
2
|
+
require "stanzas/iq_query_stanza.rb"
|
3
|
+
require "stanzas/notification_stanza.rb"
|
4
|
+
require "stanzas/subscribe_query_stanza.rb"
|
5
|
+
require "stanzas/unsubscribe_query_stanza.rb"
|
6
|
+
require "stanzas/subscriptions_query_stanza.rb"
|
7
|
+
|
8
|
+
##
|
9
|
+
# By default, the log level is at error. You can change that at anytime in your app
|
10
|
+
Babylon.logger.level = Log4r::ERROR
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
# Based on the API documented there : http://superfeedr.com/documentation
|
15
|
+
module Superfeedr
|
16
|
+
|
17
|
+
class NotConnected < StandardError; end
|
18
|
+
|
19
|
+
@@connection = nil
|
20
|
+
@@callbacks = {}
|
21
|
+
@@connection_callback = nil
|
22
|
+
@@notification_callback = nil
|
23
|
+
|
24
|
+
##
|
25
|
+
# Connects your client to the Superfeedr.com XMPP server. You need to pass the following arguments :
|
26
|
+
# "jid" : login@superfeedr.com
|
27
|
+
# "password" : your superfeedr.com password
|
28
|
+
# ["host" : host for your jid or component : only useful if you use an external jid ]
|
29
|
+
# ["port" : port for your jid or component : only useful if you use an external jid ]
|
30
|
+
# ["app_type" : (client | component) only useful if you use an external jid ]
|
31
|
+
# The optional block will be called upon connection.
|
32
|
+
def self.connect(jid, password, host = nil, port = nil, app_type = "client", &block)
|
33
|
+
|
34
|
+
params = {
|
35
|
+
"jid" => jid,
|
36
|
+
"password" => password,
|
37
|
+
"host" => host,
|
38
|
+
"port" => port
|
39
|
+
}
|
40
|
+
@@connection_callback = block
|
41
|
+
|
42
|
+
run = Proc.new {
|
43
|
+
if app_type == "client"
|
44
|
+
Babylon::ClientConnection.connect(params, self)
|
45
|
+
else
|
46
|
+
Babylon::ComponentConnection.connect(params, self)
|
47
|
+
end
|
48
|
+
}
|
49
|
+
|
50
|
+
if EventMachine.reactor_running?
|
51
|
+
run.call
|
52
|
+
else
|
53
|
+
EventMachine.run {
|
54
|
+
run.call
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Subscribes to the multiple feeds, 30 by 30. Calls the block after each set of 30 feeds.
|
61
|
+
def self.subscribe(*feeds, &block)
|
62
|
+
return if feeds.flatten! == []
|
63
|
+
subset = feeds.slice!(0..29)
|
64
|
+
Superfeedr.add_feeds(subset) do |result|
|
65
|
+
subscribe(feeds, &block)
|
66
|
+
block.call(subset)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Ubsubscribe to multiple feeds, one by one. Calls the block after each set of 30 feeds.
|
72
|
+
def self.unsubscribe(*feeds, &block)
|
73
|
+
return if feeds.flatten! == []
|
74
|
+
subset = feeds.slice!(0..29)
|
75
|
+
Superfeedr.remove_feeds(subset) do |result|
|
76
|
+
unsubscribe(feeds, &block)
|
77
|
+
block.call(subset)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# List all subscriptions, by sending them by blocks (page), starting at page specified in argument
|
83
|
+
def self.subscriptions(start_page = 1, &block)
|
84
|
+
Superfeedr.subscriptions_by_page(start_page) do |page, result|
|
85
|
+
if !result.empty?
|
86
|
+
subscriptions(start_page + 1, &block)
|
87
|
+
end
|
88
|
+
block.call(page, result)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Adds the url to the list of feeds you're monitoring. The block passed in argument will be called upon success.
|
94
|
+
# The block will take one boolen argument : true means everything went right... false means something failed!
|
95
|
+
# (Please set Babylon's log to Log4r::INFO for more info)
|
96
|
+
def self.add_feeds(feeds_url, &block)
|
97
|
+
raise NotConnected unless connection
|
98
|
+
stanza = SubscribeQueryStanza.new({:nodes => feeds_url, :from => connection.jid})
|
99
|
+
@@callbacks[stanza.id] = Hash.new
|
100
|
+
@@callbacks[stanza.id][:method] = method(:on_subscribe)
|
101
|
+
@@callbacks[stanza.id][:param] = block
|
102
|
+
send(stanza)
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# Unsubscribe from a feed. The block passed in argument will be called upon success.
|
107
|
+
# The block will take one boolen argument : true means everything went right... false means something failed!
|
108
|
+
# (Please set Babylon's log to Log4r::INFO for more info)
|
109
|
+
def self.remove_feeds(feeds_url, &block)
|
110
|
+
raise NotConnected unless connection
|
111
|
+
stanza = UnsubscribeQueryStanza.new({:nodes => feeds_url, :from => connection.jid})
|
112
|
+
@@callbacks[stanza.id] = Hash.new
|
113
|
+
@@callbacks[stanza.id][:method] = method(:on_unsubscribe)
|
114
|
+
@@callbacks[stanza.id][:param] = block
|
115
|
+
send(stanza)
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# Lists the subscriptions by page. The block passed in argument will be called with 2 arguments : the page,
|
120
|
+
# and an array of the feed's url in the page you requested.
|
121
|
+
# (Currently the Superfeedr API only supports 30 feeds per page.)
|
122
|
+
def self.subscriptions_by_page(page = 1, &block)
|
123
|
+
raise NotConnected unless connection
|
124
|
+
stanza = SubscriptionsQueryStanza.new({:page => page, :from => connection.jid})
|
125
|
+
@@callbacks[stanza.id] = Hash.new
|
126
|
+
@@callbacks[stanza.id][:method] = method(:on_subscriptions)
|
127
|
+
@@callbacks[stanza.id][:param] = block
|
128
|
+
send(stanza)
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Specifies the block that will be called upon notification.
|
133
|
+
# Your block should take a NotificationStanza instance argument.
|
134
|
+
def self.on_notification(&block)
|
135
|
+
@@notification_callback = block
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Called with a response to a subscriptions listing
|
140
|
+
def self.on_subscriptions(stanza, &block)
|
141
|
+
page = stanza.xpath('//subscriptions').first["page"].to_i
|
142
|
+
feeds = stanza.xpath('//subscription').map { |s| CGI.unescapeHTML(s["node"]) }
|
143
|
+
block.call(page, feeds)
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Called with a response to a subscribe
|
148
|
+
def self.on_subscribe(stanza, &block)
|
149
|
+
block.call(stanza["type"] == "result")
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Called with a response to an unsubscribe.
|
154
|
+
def self.on_unsubscribe(stanza, &block)
|
155
|
+
block.call(stanza["type"] == "result")
|
156
|
+
end
|
157
|
+
|
158
|
+
##
|
159
|
+
# ::nodoc::
|
160
|
+
def self.callbacks
|
161
|
+
@@callbacks
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# ::nodoc::
|
166
|
+
def self.connection
|
167
|
+
@@connection
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# ::nodoc::
|
172
|
+
def self.send(xml)
|
173
|
+
connection.send_xml(xml)
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# ::nodoc::
|
178
|
+
def self.on_connected(connection)
|
179
|
+
@@connection = connection
|
180
|
+
@@connection_callback.call
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# ::nodoc::
|
185
|
+
def self.on_disconnected()
|
186
|
+
@@connection = false
|
187
|
+
end
|
188
|
+
|
189
|
+
##
|
190
|
+
# This shall not be called by your application. It is called upon stanza recetion. If it is a reply to a stanza we sent earlier, then, we just call it's associated callback. If it is a notification stanza, then, we call the notification callback (that you should have given when calling Superfeedr.connect) with a NotificationStanza instance.
|
191
|
+
def self.on_stanza(stanza)
|
192
|
+
if stanza["id"] && @@callbacks[stanza["id"]]
|
193
|
+
@@callbacks[stanza["id"]][:method].call(stanza, &@@callbacks[stanza["id"]][:param])
|
194
|
+
@@callbacks.delete(stanza["id"])
|
195
|
+
else
|
196
|
+
if stanza.name == "message" and stanza.at("event")
|
197
|
+
@@notification_callback.call(NotificationStanza.new(stanza)) if @@notification_callback
|
198
|
+
# Here we need to call the main notification callback!
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Config loaded from config.yaml
|
205
|
+
def self.conf
|
206
|
+
@@conf ||= YAML::load(File.read(File.dirname(__FILE__) + '/config.yaml'))
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "Iq Query Stanzas" do
|
4
|
+
|
5
|
+
it "should have the right type" do
|
6
|
+
IqQueryStanza.new(@params).type.should == @params[:type]
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have the right to" do
|
10
|
+
IqQueryStanza.new(@params).to.should == "firehoser.superfeedr.com"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a random id" do
|
14
|
+
IqQueryStanza.new(@params).id.should match /[0..9]*/
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have the right from" do
|
18
|
+
IqQueryStanza.new(@params).from.should == @params[:from]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe IqQueryStanza do
|
24
|
+
before(:each) do
|
25
|
+
@params = { :type => "set", :from => "me@server.com/resource"}
|
26
|
+
end
|
27
|
+
|
28
|
+
it_should_behave_like "Iq Query Stanzas"
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
describe NotificationStanza do
|
3
|
+
|
4
|
+
before(:each) do
|
5
|
+
xml = <<-EOXML
|
6
|
+
<message from='firehoser.superfeedr.com' to='you@superfeedr.com'>
|
7
|
+
<event xmlns='http://jabber.org/protocol/pubsub#event'>
|
8
|
+
<status feed="http://domain.tld/path/to/feed.xml" xmlns:superfeedr='http://superfeedr.com/xmpp-pubsub-ext'>
|
9
|
+
<http code="200">9718 bytes fetched in 1.462708s : 2 new entries.</http>
|
10
|
+
<next_fetch>2009-05-10T11:19:38-07:00</next_fetch>
|
11
|
+
</status>
|
12
|
+
<items node='http://domain.tld/path/to/feed.xml'>
|
13
|
+
<item chunk="1" chunks="2" >
|
14
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
15
|
+
<title>Soliloquy</title>
|
16
|
+
<summary>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</summary>
|
17
|
+
<link rel='alternate' type='text/html' href='http://superfeedr.com/entries/12345789'/>
|
18
|
+
<id>tag:domain.tld,2009:Soliloquy-32397</id>
|
19
|
+
<published>2010-04-05T11:04:21Z</published>
|
20
|
+
</entry>
|
21
|
+
</item>
|
22
|
+
<item chunk="2" chunks="2" >
|
23
|
+
<entry xmlns='http://www.w3.org/2005/Atom'>
|
24
|
+
<title>Finibus Bonorum et Malorum</title>
|
25
|
+
<summary>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</summary>
|
26
|
+
<link rel='alternate' type='text/html' href='http://superfeedr.com/entries/12345788'/>
|
27
|
+
<id>tag:domain.tld,2009:Finibus-32398</id>
|
28
|
+
<published>2010-04-06T08:54:02Z</published>
|
29
|
+
</entry>
|
30
|
+
</item>
|
31
|
+
</items>
|
32
|
+
</event>
|
33
|
+
</message>
|
34
|
+
EOXML
|
35
|
+
@stanza = NotificationStanza.new(xml)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have the right feed_url" do
|
39
|
+
@stanza.feed_url.should == "http://domain.tld/path/to/feed.xml"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should have the right message_status"
|
43
|
+
|
44
|
+
it "should have the right http_status" do
|
45
|
+
@stanza.http_status.should == 200
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should have the have the right next_fetch" do
|
49
|
+
@stanza.next_fetch.should == Time.parse("2009-05-10T11:19:38-07:00")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have the right number of items" do
|
53
|
+
@stanza.entries.count.should == 2
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "items" do
|
57
|
+
before(:each) do
|
58
|
+
@item = @stanza.entries.first
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should have the right chunk" do
|
62
|
+
@item.chunk.should == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should have the right chunks" do
|
66
|
+
@item.chunks.should == 2
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have the right title" do
|
70
|
+
@item.title.should == "Soliloquy"
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should have the right summary" do
|
74
|
+
@item.summary.should == "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have the right link" do
|
78
|
+
@item.link.should == "http://superfeedr.com/entries/12345789"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should have the right unique_id" do
|
82
|
+
@item.unique_id.should == "tag:domain.tld,2009:Soliloquy-32397"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should have the right published" do
|
86
|
+
@item.published.should == Time.parse("2010-04-05T11:04:21Z")
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/iq_query_stanza_spec'
|
3
|
+
describe SubscribeQueryStanza do
|
4
|
+
|
5
|
+
it_should_behave_like "Iq Query Stanzas"
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@params = { :type => "set", :from => "me@server.com/resource", :nodes => ["http//domain.tld/feed.xml"], :type => "set", :from => "me@server.com/resource"}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the right node value" do
|
12
|
+
SubscribeQueryStanza.new(@params).nodes.should == @params[:nodes]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/iq_query_stanza_spec'
|
3
|
+
describe SubscriptionsQueryStanza do
|
4
|
+
|
5
|
+
it_should_behave_like "Iq Query Stanzas"
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@params = { :type => "set", :from => "me@server.com/resource", :page => 3, :type => "set", :from => "me@server.com/resource"}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the right page value" do
|
12
|
+
SubscriptionsQueryStanza.new(@params).page.should == @params[:page].to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/iq_query_stanza_spec'
|
3
|
+
describe UnsubscribeQueryStanza do
|
4
|
+
|
5
|
+
it_should_behave_like "Iq Query Stanzas"
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@params = { :type => "set", :from => "me@server.com/resource", :nodes => ["http//domain.tld/feed.xml", "http//domain.tld/feed2.xml"], :type => "set", :from => "me@server.com/resource"}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have the right node value" do
|
12
|
+
UnsubscribeQueryStanza.new(@params).nodes.should == @params[:nodes]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Superfeedr do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@mock_connection = mock(Babylon::XmppConnection, {:send_xml => true, :jid => "client@server.tld/resource"})
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "connect" do
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "on_stanza" do
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
describe "subscribe" do
|
17
|
+
it "should call add_feeds with feeds supplied" do
|
18
|
+
feeds = ["a"] * 50
|
19
|
+
Superfeedr.should_receive(:add_feeds).with(["a"] * 30).and_yield(true)
|
20
|
+
Superfeedr.should_receive(:add_feeds).with(["a"] * 20).and_yield(true)
|
21
|
+
Superfeedr.subscribe(feeds) do |result|
|
22
|
+
result.should be_true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "unsubscribe" do
|
28
|
+
it "should call remove_feeds with feeds supplied" do
|
29
|
+
feeds = ["a"] * 40
|
30
|
+
Superfeedr.should_receive(:remove_feeds).with(["a"] * 30).and_yield(true)
|
31
|
+
Superfeedr.should_receive(:remove_feeds).with(["a"] * 10).and_yield(true)
|
32
|
+
Superfeedr.unsubscribe(feeds) do |result|
|
33
|
+
result.should be_true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "subscriptions" do
|
39
|
+
it "should call subscriptions_by_page for each page as long as they're not empty" do
|
40
|
+
def method_called_upon_page
|
41
|
+
end
|
42
|
+
self.should_receive(:method_called_upon_page).exactly(4).times
|
43
|
+
3.times do |t|
|
44
|
+
Superfeedr.should_receive(:subscriptions_by_page).with(t+1).and_yield( t+1 , ["a", "b", "c"])
|
45
|
+
end
|
46
|
+
Superfeedr.should_receive(:subscriptions_by_page).with(4).and_yield(4, [])
|
47
|
+
Superfeedr.subscriptions do |page, result|
|
48
|
+
method_called_upon_page
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
describe "add_feeds" do
|
55
|
+
before(:each) do
|
56
|
+
Superfeedr.stub!(:connection).and_return(@mock_connection)
|
57
|
+
Superfeedr.stub!(:send).and_return(true)
|
58
|
+
@block = Proc.new {
|
59
|
+
|
60
|
+
}
|
61
|
+
@node = "http://domain.com/feed.xml"
|
62
|
+
@mock_stanza = mock(SubscribeQueryStanza, {:id => "123"})
|
63
|
+
SubscribeQueryStanza.stub!(:new).and_return(@mock_stanza)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should raise an error if not connected" do
|
67
|
+
Superfeedr.should_receive(:connection).and_return(nil)
|
68
|
+
lambda {
|
69
|
+
Superfeedr.add_feeds(@node, &@block)
|
70
|
+
}.should raise_error(Superfeedr::NotConnected)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should create a new SubscribeQueryStanza with the right url" do
|
74
|
+
SubscribeQueryStanza.should_receive(:new).with({:nodes => @node, :from => @mock_connection.jid}).and_return(@mock_stanza)
|
75
|
+
Superfeedr.add_feeds(@node, &@block)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should add a Proc that just calls the block in params to the @@callbacks" do
|
79
|
+
Superfeedr.add_feeds(@node, &@block)
|
80
|
+
Superfeedr.callbacks[@mock_stanza.id][:method].should == Superfeedr.method(:on_subscribe)
|
81
|
+
Superfeedr.callbacks[@mock_stanza.id][:param].should == @block
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should send the stanza" do
|
85
|
+
Superfeedr.should_receive(:send).with(@mock_stanza).and_return(true)
|
86
|
+
Superfeedr.add_feeds(@node, &@block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "remove_feeds" do
|
91
|
+
before(:each) do
|
92
|
+
Superfeedr.stub!(:connection).and_return(@mock_connection)
|
93
|
+
Superfeedr.stub!(:send).and_return(true)
|
94
|
+
@block = Proc.new {
|
95
|
+
|
96
|
+
}
|
97
|
+
@nodes = ["http://domain.com/feed.xml"]
|
98
|
+
@mock_stanza = mock(UnsubscribeQueryStanza, {:id => "123"})
|
99
|
+
UnsubscribeQueryStanza.stub!(:new).and_return(@mock_stanza)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should raise an error if not connected" do
|
103
|
+
Superfeedr.should_receive(:connection).and_return(nil)
|
104
|
+
lambda {
|
105
|
+
Superfeedr.remove_feeds(@nodes, &@block)
|
106
|
+
}.should raise_error(Superfeedr::NotConnected)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should create a new SubscribeQueryStanza with the right url" do
|
110
|
+
UnsubscribeQueryStanza.should_receive(:new).with({:nodes => @nodes, :from => @mock_connection.jid}).and_return(@mock_stanza)
|
111
|
+
Superfeedr.remove_feeds(@nodes, &@block)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should add a Proc that just calls the block in params to the @@callbacks" do
|
115
|
+
Superfeedr.remove_feeds(@nodes, &@block)
|
116
|
+
Superfeedr.callbacks[@mock_stanza.id][:method].should == Superfeedr.method(:on_unsubscribe)
|
117
|
+
Superfeedr.callbacks[@mock_stanza.id][:param].should == @block
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should send the stanza" do
|
121
|
+
Superfeedr.should_receive(:send).with(@mock_stanza).and_return(true)
|
122
|
+
Superfeedr.remove_feeds(@nodes, &@block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "subscriptions_by_page" do
|
127
|
+
before(:each) do
|
128
|
+
Superfeedr.stub!(:connection).and_return(@mock_connection)
|
129
|
+
Superfeedr.stub!(:send).and_return(true)
|
130
|
+
@block = Proc.new {
|
131
|
+
|
132
|
+
}
|
133
|
+
@page = 3
|
134
|
+
@mock_stanza = mock(SubscriptionsQueryStanza, {:id => "123"})
|
135
|
+
SubscriptionsQueryStanza.stub!(:new).and_return(@mock_stanza)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should raise an error if not connected" do
|
139
|
+
Superfeedr.should_receive(:connection).and_return(nil)
|
140
|
+
lambda {
|
141
|
+
Superfeedr.subscriptions_by_page(@page, &@block)
|
142
|
+
}.should raise_error(Superfeedr::NotConnected)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should create a new SubscribeQueryStanza with the right url" do
|
146
|
+
SubscriptionsQueryStanza.should_receive(:new).with({:page => @page, :from => @mock_connection.jid}).and_return(@mock_stanza)
|
147
|
+
Superfeedr.subscriptions_by_page(@page, &@block)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should add a Proc that just calls the block in params to the @@callbacks" do
|
151
|
+
Superfeedr.subscriptions_by_page(@page, &@block)
|
152
|
+
Superfeedr.callbacks[@mock_stanza.id][:method].should == Superfeedr.method(:on_subscriptions)
|
153
|
+
Superfeedr.callbacks[@mock_stanza.id][:param].should == @block
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should send the stanza" do
|
158
|
+
Superfeedr.should_receive(:send).with(@mock_stanza).and_return(true)
|
159
|
+
Superfeedr.subscriptions_by_page(@page, &@block)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "on_subscribe" do
|
164
|
+
it "should call the block with true if the stanza type is 'result'" do
|
165
|
+
xml = <<-EOXML
|
166
|
+
<iq type="result" to="you@superfeedr.com/home" from="firehoser.superfeedr.com" id="sub1">
|
167
|
+
<pubsub xmlns="http://jabber.org/protocol/pubsub">
|
168
|
+
<subscription jid="you@superfeedr.com" subscription="subscribed" node="http://domain.tld/path/to/feed.xml"/>
|
169
|
+
</pubsub>
|
170
|
+
</iq>
|
171
|
+
EOXML
|
172
|
+
stanza = Nokogiri::XML(xml)
|
173
|
+
Superfeedr.on_subscribe(stanza.root) do |res|
|
174
|
+
res.should be_true
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should call the block with false if the stanza type is not 'result'" do
|
179
|
+
xml = <<-EOXML
|
180
|
+
<iq type="error" to="you@superfeedr.com/home" from="firehoser.superfeedr.com" id="sub1">
|
181
|
+
<pubsub xmlns="http://jabber.org/protocol/pubsub">
|
182
|
+
<subscription jid="you@superfeedr.com" subscription="subscribed" node="http://domain.tld/path/to/feed.xml"/>
|
183
|
+
</pubsub>
|
184
|
+
</iq>
|
185
|
+
EOXML
|
186
|
+
stanza = Nokogiri::XML(xml)
|
187
|
+
Superfeedr.on_subscribe(stanza.root) do |res|
|
188
|
+
res.should be_false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "on_unsubscribe" do
|
195
|
+
it "should call the block with true if the stanza type is 'result'" do
|
196
|
+
xml = <<-EOXML
|
197
|
+
<iq type='result' from='firehoser.superfeedr.com' to='you@superfeedr.com/home' id='unsub1' />
|
198
|
+
EOXML
|
199
|
+
stanza = Nokogiri::XML(xml)
|
200
|
+
Superfeedr.on_unsubscribe(stanza.root) do |res|
|
201
|
+
res.should be_true
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should call the block with false if the stanza type is not 'result'" do
|
206
|
+
xml = <<-EOXML
|
207
|
+
<iq type='error' from='firehoser.superfeedr.com' to='you@superfeedr.com/home' id='unsub1' />
|
208
|
+
EOXML
|
209
|
+
stanza = Nokogiri::XML(xml)
|
210
|
+
Superfeedr.on_unsubscribe(stanza.root) do |res|
|
211
|
+
res.should be_false
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "on_subscriptions" do
|
217
|
+
it "should call the block with the page number and the list of feeds as an array" do
|
218
|
+
xml = <<-EOXML
|
219
|
+
<iq type="result" to="you@superfeedr.com/home" id="subman1" from="firehoser.superfeedr.com">
|
220
|
+
<pubsub>
|
221
|
+
<subscriptions page="3">
|
222
|
+
<subscription node="http://domain.tld/path/to/a/feed/atom.xml&toto=tutu" subscription="subscribed" jid="you@superfeedr.com" />
|
223
|
+
<subscription node="http://domain2.tld/path/to/feed.rss" subscription="subscribed" jid="you@superfeedr.com" />
|
224
|
+
</subscriptions>
|
225
|
+
</pubsub>
|
226
|
+
</iq>
|
227
|
+
EOXML
|
228
|
+
stanza = Nokogiri::XML(xml)
|
229
|
+
Superfeedr.on_subscriptions(stanza.root) do |page, subscriptions|
|
230
|
+
page.should == 3
|
231
|
+
subscriptions.should == ["http://domain.tld/path/to/a/feed/atom.xml&toto=tutu", "http://domain2.tld/path/to/feed.rss"]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: superfeedr-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- julien Genestoux
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-10 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: skates
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: julien.genestoux@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- LICENSE
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION.yml
|
49
|
+
- lib/config.yaml
|
50
|
+
- lib/stanzas/iq_query_stanza.rb
|
51
|
+
- lib/stanzas/notification_stanza.rb
|
52
|
+
- lib/stanzas/subscribe_query_stanza.rb
|
53
|
+
- lib/stanzas/subscriptions_query_stanza.rb
|
54
|
+
- lib/stanzas/unsubscribe_query_stanza.rb
|
55
|
+
- lib/superfeedr.rb
|
56
|
+
- spec/spec.opts
|
57
|
+
- spec/spec_helper.rb
|
58
|
+
- spec/stanzas/iq_query_stanza_spec.rb
|
59
|
+
- spec/stanzas/notifications_stanza_spec.rb
|
60
|
+
- spec/stanzas/subscribe_stanza_spec.rb
|
61
|
+
- spec/stanzas/subscriptions_stanza_spec.rb
|
62
|
+
- spec/stanzas/unsubscribe_stanza_spec.rb
|
63
|
+
- spec/superfeedr_ruby_spec.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/julien51/superfeedr-ruby/
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --charset=UTF-8
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project: superfeedr-ruby
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Ruby Client for the Superfeedr
|
92
|
+
test_files:
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
- spec/stanzas/iq_query_stanza_spec.rb
|
95
|
+
- spec/stanzas/notifications_stanza_spec.rb
|
96
|
+
- spec/stanzas/subscribe_stanza_spec.rb
|
97
|
+
- spec/stanzas/subscriptions_stanza_spec.rb
|
98
|
+
- spec/stanzas/unsubscribe_stanza_spec.rb
|
99
|
+
- spec/superfeedr_ruby_spec.rb
|