collecta-rb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +44 -0
- data/examples/collecta.rb +24 -0
- data/lib/collecta-rb.rb +84 -0
- data/lib/collecta/archive.rb +12 -0
- data/lib/collecta/pubsub.rb +54 -0
- data/lib/collecta/result.rb +23 -0
- data/lib/collecta/subscribe.rb +12 -0
- data/spec/collecta/archive_spec.rb +10 -0
- data/spec/collecta/result_spec.rb +60 -0
- data/spec/collecta/subscribe_spec.rb +11 -0
- data/spec/collecta_spec.rb +3 -0
- data/spec/spec_helper.rb +43 -0
- metadata +96 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jeff Smick
|
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.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
Collecta.rb
|
2
|
+
===========
|
3
|
+
|
4
|
+
A ruby library based on Blather for working with the Collecta XMPP api.
|
5
|
+
|
6
|
+
Install
|
7
|
+
-------
|
8
|
+
Gem is hosted on [Gemcutter](http://gemcutter.org/)
|
9
|
+
|
10
|
+
sudo gem install collecta-rb
|
11
|
+
|
12
|
+
Example
|
13
|
+
-------
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'collecta-rb'
|
17
|
+
require 'pp'
|
18
|
+
|
19
|
+
client = Collecta::Client.setup '[api-key]'
|
20
|
+
|
21
|
+
client.subscribe('earthquake') do |result|
|
22
|
+
pp({
|
23
|
+
:query => result.query,
|
24
|
+
:title => result.title,
|
25
|
+
:category => result.category,
|
26
|
+
:abstract => result.abstract,
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
client.notifications('earthquake') do |notification|
|
31
|
+
pp notification
|
32
|
+
end
|
33
|
+
|
34
|
+
client.archive('earthquake') do |result|
|
35
|
+
pp result
|
36
|
+
end
|
37
|
+
|
38
|
+
EM.run { client.connect }
|
39
|
+
|
40
|
+
|
41
|
+
Copyright
|
42
|
+
---------
|
43
|
+
|
44
|
+
Copyright (c) 2009 Jeff Smick. See LICENSE for details.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'collecta-rb'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
client = Collecta::Client.setup 'f67a267c6d5c86ed36ae676e70698bdd'
|
6
|
+
|
7
|
+
client.subscribe('earthquake') do |result|
|
8
|
+
pp({
|
9
|
+
:query => result.query,
|
10
|
+
:title => result.title,
|
11
|
+
:category => result.category,
|
12
|
+
:abstract => result.abstract,
|
13
|
+
})
|
14
|
+
end
|
15
|
+
|
16
|
+
client.notifications('earthquake') do |notification|
|
17
|
+
pp notification
|
18
|
+
end
|
19
|
+
|
20
|
+
client.archive('earthquake') do |result|
|
21
|
+
pp result
|
22
|
+
end
|
23
|
+
|
24
|
+
EM.run { client.connect }
|
data/lib/collecta-rb.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
%w[
|
2
|
+
blather
|
3
|
+
blather/client/client
|
4
|
+
|
5
|
+
collecta/pubsub
|
6
|
+
collecta/archive
|
7
|
+
collecta/result
|
8
|
+
collecta/subscribe
|
9
|
+
].each { |r| require r }
|
10
|
+
|
11
|
+
module Collecta
|
12
|
+
COLLECTA_JID = 'search.collecta.com'.freeze
|
13
|
+
HOST = 'guest.collecta.com'.freeze
|
14
|
+
NODE = 'search'.freeze
|
15
|
+
|
16
|
+
class Client < Blather::Client
|
17
|
+
attr_accessor :api_key # :nodoc:
|
18
|
+
|
19
|
+
# Setup the connection with an API key
|
20
|
+
def self.setup(apikey)
|
21
|
+
new_client = super "@#{HOST}", nil
|
22
|
+
new_client.api_key = apikey
|
23
|
+
new_client
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize # :nodoc:
|
27
|
+
super
|
28
|
+
@deferred = []
|
29
|
+
end
|
30
|
+
|
31
|
+
# Subscribe to a query
|
32
|
+
def subscribe(search, &block)
|
33
|
+
return if defer(:subscribe, search, &block)
|
34
|
+
self.write Subscribe.new self.api_key, search
|
35
|
+
self.register_handler(:pubsub_event, "//ns:headers/ns:header[@name='x-collecta#query' and .='#{search}']", :ns => 'http://jabber.org/protocol/shim') do |evt, _|
|
36
|
+
block.call Result.new.inherit(evt)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Subscribe to query notifications
|
41
|
+
def notifications(search, &block)
|
42
|
+
return if defer(:notifications, search, &block)
|
43
|
+
self.write Subscribe.new self.api_key, nil, search
|
44
|
+
self.register_handler(:pubsub_event, "//ns:item[@id='#{search}']", :ns => 'http://jabber.org/protocol/pubsub#event') do |evt, item|
|
45
|
+
block.call item.first.find('//ns:count', :ns => 'http://api.collecta.com/ns/search-0#notify').first.content.to_i
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieve the last set of entries for <tt>search</tt>
|
50
|
+
def archive(search, &block)
|
51
|
+
return if defer(:archive, search, &block)
|
52
|
+
self.write_with_handler Archive.new(self.api_key, search), &block
|
53
|
+
end
|
54
|
+
|
55
|
+
# Collecta doesn't seem to like stanzas with whitespace so clear it out
|
56
|
+
def write(stanza) # :nodoc:
|
57
|
+
super stanza.to_xml(:indent => 0).gsub(/\n|\r/,'')
|
58
|
+
end
|
59
|
+
|
60
|
+
# Allow users to setup callbacks before the connection is setup
|
61
|
+
def defer(*args, &block) # :nodoc:
|
62
|
+
if @stream
|
63
|
+
false
|
64
|
+
else
|
65
|
+
@deferred << [args, block]
|
66
|
+
true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Run all deferred commands after the connection is established
|
71
|
+
def post_init(stream, jid = nil) # :nodoc:
|
72
|
+
super
|
73
|
+
until @deferred.empty?
|
74
|
+
args = @deferred.pop
|
75
|
+
self.__send__ *(args[0]), &args[1]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def client_post_init # :nodoc:
|
80
|
+
# overwrite the default actions to take after a client is setup
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Collecta
|
2
|
+
class Archive < Blather::Stanza::PubSub::Items
|
3
|
+
include Collecta::Pubsub
|
4
|
+
def self.new(apikey, search)
|
5
|
+
new_node = super :get, COLLECTA_JID
|
6
|
+
new_node.node = NODE
|
7
|
+
new_node.apikey = apikey
|
8
|
+
new_node.query = search
|
9
|
+
new_node
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Collecta
|
2
|
+
module Pubsub
|
3
|
+
DATA_NS = 'jabber:x:data'.freeze
|
4
|
+
|
5
|
+
def apikey
|
6
|
+
self.options.content_from '//ns:field[@var="x-collecta#apikey"]/ns:value', :ns => DATA_NS
|
7
|
+
end
|
8
|
+
|
9
|
+
def apikey=(key)
|
10
|
+
self.add_field 'x-collecta#apikey', key
|
11
|
+
end
|
12
|
+
|
13
|
+
def query
|
14
|
+
self.options.find('//ns:field[@var="x-collecta#query"]/ns:value', :ns => DATA_NS).map { |n| n.content }
|
15
|
+
end
|
16
|
+
|
17
|
+
def query=(values)
|
18
|
+
self.add_field 'x-collecta#query', values
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify
|
22
|
+
self.options.find('//ns:field[@var="x-collecta#notify"]/ns:value', :ns => DATA_NS).map { |n| n.content }
|
23
|
+
end
|
24
|
+
|
25
|
+
def notify=(values)
|
26
|
+
self.add_field 'x-collecta#notify', values
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
def options
|
31
|
+
x = self.pubsub.find_first('//pubsub_ns:options/ns:x', :pubsub_ns => self.registered_ns, :ns => DATA_NS)
|
32
|
+
unless x
|
33
|
+
self.pubsub << (o = Blather::XMPPNode.new('options', self.document))
|
34
|
+
o << (x = Blather::XMPPNode.new('x', self.document))
|
35
|
+
x.namespace = 'jabber:x:data'
|
36
|
+
x[:type] = 'submit'
|
37
|
+
|
38
|
+
field = self.add_field('FORM_TYPE', 'http://jabber.org/protocol/pubsub#subscribe_options')
|
39
|
+
field[:type] = 'hidden'
|
40
|
+
end
|
41
|
+
x
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_field(var, values)
|
45
|
+
self.options << (field = Blather::XMPPNode.new('field', self.document))
|
46
|
+
field[:var] = var
|
47
|
+
[values].flatten.each do |value|
|
48
|
+
field << (val = Blather::XMPPNode.new('value', self.document))
|
49
|
+
val.content = value
|
50
|
+
end
|
51
|
+
field
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Collecta
|
2
|
+
class Result < Blather::Stanza::PubSub::Event
|
3
|
+
def query
|
4
|
+
content_from('//ns:headers/ns:header[@name="x-collecta#query"]', :ns => 'http://jabber.org/protocol/shim').strip
|
5
|
+
end
|
6
|
+
|
7
|
+
def title
|
8
|
+
self.entry.content_from '//ns:title', :ns => 'http://www.w3.org/2005/Atom'
|
9
|
+
end
|
10
|
+
|
11
|
+
def category
|
12
|
+
self.entry.content_from '//ns:category', :ns => 'http://api.collecta.com/ns/search-0#results'
|
13
|
+
end
|
14
|
+
|
15
|
+
def abstract
|
16
|
+
self.entry.find('//ns:abstract', :ns => 'http://api.collecta.com/ns/search-0#results').first.inner_html.strip
|
17
|
+
end
|
18
|
+
|
19
|
+
def entry
|
20
|
+
Blather::XMPPNode.new('event').inherit self.items.first.find_first('//ns:entry', :ns => 'http://www.w3.org/2005/Atom')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Collecta
|
2
|
+
class Subscribe < Blather::Stanza::PubSub::Subscribe
|
3
|
+
include Collecta::Pubsub
|
4
|
+
def self.new(apikey, query = nil, notify = nil)
|
5
|
+
new_node = super :set, COLLECTA_JID, NODE
|
6
|
+
new_node.apikey = apikey
|
7
|
+
new_node.query = query
|
8
|
+
new_node.notify = notify if notify
|
9
|
+
new_node
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Collecta::Archive do
|
4
|
+
it 'can be created with an apikey and a search term' do
|
5
|
+
archive = Collecta::Archive.new 'apikey-value', 'search-term'
|
6
|
+
archive.must_be_kind_of Blather::Stanza::PubSub::Items
|
7
|
+
archive.must_have_apikey 'apikey-value'
|
8
|
+
archive.must_have_query 'search-term'
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Collecta::Result do
|
4
|
+
before do
|
5
|
+
@result = Collecta::Result.new.inherit(Blather::XMPPNode.import(Nokogiri::XML.parse(<<-XML).root))
|
6
|
+
<message from='search.collecta.com'
|
7
|
+
to='tofu@collecta.com/search'>
|
8
|
+
<event xmlns='http://jabber.org/protocol/pubsub#event'>
|
9
|
+
<items node='search'>
|
10
|
+
<item id='1cb57d9c-1c46-11dd-838c-001143d5d5db'>
|
11
|
+
<entry xmlns="http://www.w3.org/2005/Atom">
|
12
|
+
<source>
|
13
|
+
<title>metajack</title>
|
14
|
+
<icon>http://identi.ca/avatar/4685-96-20090213165024.jpeg</icon>
|
15
|
+
<author>
|
16
|
+
<name>metajack</name>
|
17
|
+
</author>
|
18
|
+
<link href="http://identi.ca/metajack"/>
|
19
|
+
<link href="http://identi.ca/metajack" type="application/atom+xml" rel="self"/>
|
20
|
+
<link href="http://creativecommons.org/licenses/by/3.0/" rel="license"/>
|
21
|
+
</source>
|
22
|
+
<link href="http://identi.ca/metajack"/>
|
23
|
+
<title>metajack</title>
|
24
|
+
<published>2009-04-25T04:03:38+00:00</published>
|
25
|
+
<id>http://identi.ca/notice/3694388</id>
|
26
|
+
<updated>1970-01-01T00:00:00+00:00</updated>
|
27
|
+
<category xmlns="http://api.collecta.com/ns/search-0#results">update</category>
|
28
|
+
<abstract xmlns="http://api.collecta.com/ns/search-0#results">
|
29
|
+
<p>metajack Great. My first day back in SF and there's an earthquake.</p>
|
30
|
+
</abstract>
|
31
|
+
<link rel='collecta-abstract-image' href='http://identi.ca/avatar/4685-96-20090213165024.jpeg'/>
|
32
|
+
</entry>
|
33
|
+
</item>
|
34
|
+
</items>
|
35
|
+
</event>
|
36
|
+
<headers xmlns='http://jabber.org/protocol/shim'>
|
37
|
+
<header name='x-collecta#query'>
|
38
|
+
earthquake
|
39
|
+
</header>
|
40
|
+
</headers>
|
41
|
+
</message>
|
42
|
+
XML
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'has a query' do
|
46
|
+
@result.query.must_equal 'earthquake'
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'has a title' do
|
50
|
+
@result.title.must_equal 'metajack'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'has a category' do
|
54
|
+
@result.category.must_equal 'update'
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'has an abstract' do
|
58
|
+
@result.abstract.must_equal "<p>metajack Great. My first day back in SF and there's an earthquake.</p>"
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Collecta::Subscribe do
|
4
|
+
it 'can be created with an apikey, a search term and a notify term' do
|
5
|
+
subscription = Collecta::Subscribe.new 'apikey-value', 'search-term', 'notify-term'
|
6
|
+
subscription.must_be_kind_of Blather::Stanza::PubSub::Subscribe
|
7
|
+
subscription.must_have_apikey 'apikey-value'
|
8
|
+
subscription.must_have_query 'search-term'
|
9
|
+
subscription.must_have_notify 'notify-term'
|
10
|
+
end
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/spec'
|
3
|
+
|
4
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
5
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), *%w[.. lib]))
|
6
|
+
require 'collecta-rb'
|
7
|
+
|
8
|
+
MiniTest::Unit.autorun
|
9
|
+
|
10
|
+
module MiniTest
|
11
|
+
require 'pathname' if MINI_DIR =~ %r{^./}
|
12
|
+
|
13
|
+
module Assertions
|
14
|
+
def assert_has_apikey(key, node, msg = nil)
|
15
|
+
msg = message(msg) { "Expected #{mu_pp(node)} to have API key #{mu_pp(key)}" }
|
16
|
+
assert(node.apikey == key, msg)
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_has_query(query, node, msg = nil)
|
20
|
+
msg = message(msg) { "Expected #{mu_pp(node)} to have query #{mu_pp(query)}" }
|
21
|
+
assert(node.query.include?(query), msg)
|
22
|
+
end
|
23
|
+
|
24
|
+
def assert_has_notify(notify, node, msg = nil)
|
25
|
+
msg = message(msg) { "Expected #{mu_pp(node)} to have query #{mu_pp(notify)}" }
|
26
|
+
assert(node.notify.include?(notify), msg)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Object
|
32
|
+
def must_have_apikey *args
|
33
|
+
return MiniTest::Spec.current.assert_has_apikey(args.first, self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def must_have_query *args
|
37
|
+
return MiniTest::Spec.current.assert_has_query(args.first, self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def must_have_notify *args
|
41
|
+
return MiniTest::Spec.current.assert_has_notify(args.first, self)
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: collecta-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Smick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-02 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: blather
|
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: minitest
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: yard
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
description: A ruby library based on Blather for working with the Collecta XMPP api.
|
46
|
+
email: sprsquish@gmail.com
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- LICENSE
|
53
|
+
- README.md
|
54
|
+
files:
|
55
|
+
- examples/collecta.rb
|
56
|
+
- lib/collecta-rb.rb
|
57
|
+
- lib/collecta/archive.rb
|
58
|
+
- lib/collecta/pubsub.rb
|
59
|
+
- lib/collecta/result.rb
|
60
|
+
- lib/collecta/subscribe.rb
|
61
|
+
- LICENSE
|
62
|
+
- README.md
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://github.com/sprsquish/collecta-rb
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options:
|
69
|
+
- --charset=UTF-8
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
version:
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.5
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: A ruby library based on Blather for working with the Collecta XMPP api.
|
91
|
+
test_files:
|
92
|
+
- spec/collecta/archive_spec.rb
|
93
|
+
- spec/collecta/result_spec.rb
|
94
|
+
- spec/collecta/subscribe_spec.rb
|
95
|
+
- spec/collecta_spec.rb
|
96
|
+
- spec/spec_helper.rb
|