blather 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/README.md +162 -0
  2. data/examples/{print_heirarchy.rb → print_hierarchy.rb} +5 -5
  3. data/examples/stream_only.rb +27 -0
  4. data/lib/blather.rb +4 -0
  5. data/lib/blather/client/client.rb +91 -73
  6. data/lib/blather/client/dsl.rb +156 -32
  7. data/lib/blather/client/dsl/pubsub.rb +86 -54
  8. data/lib/blather/core_ext/active_support.rb +9 -9
  9. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +2 -2
  10. data/lib/blather/core_ext/nokogiri.rb +12 -7
  11. data/lib/blather/errors.rb +25 -14
  12. data/lib/blather/errors/sasl_error.rb +21 -3
  13. data/lib/blather/errors/stanza_error.rb +37 -21
  14. data/lib/blather/errors/stream_error.rb +27 -17
  15. data/lib/blather/jid.rb +79 -24
  16. data/lib/blather/roster.rb +39 -21
  17. data/lib/blather/roster_item.rb +43 -21
  18. data/lib/blather/stanza.rb +88 -40
  19. data/lib/blather/stanza/disco.rb +12 -2
  20. data/lib/blather/stanza/disco/disco_info.rb +112 -20
  21. data/lib/blather/stanza/disco/disco_items.rb +81 -12
  22. data/lib/blather/stanza/iq.rb +94 -38
  23. data/lib/blather/stanza/iq/query.rb +16 -22
  24. data/lib/blather/stanza/iq/roster.rb +98 -20
  25. data/lib/blather/stanza/message.rb +266 -111
  26. data/lib/blather/stanza/presence.rb +118 -42
  27. data/lib/blather/stanza/presence/status.rb +140 -60
  28. data/lib/blather/stanza/presence/subscription.rb +44 -10
  29. data/lib/blather/stanza/pubsub.rb +70 -15
  30. data/lib/blather/stanza/pubsub/affiliations.rb +36 -7
  31. data/lib/blather/stanza/pubsub/create.rb +26 -4
  32. data/lib/blather/stanza/pubsub/errors.rb +13 -4
  33. data/lib/blather/stanza/pubsub/event.rb +56 -10
  34. data/lib/blather/stanza/pubsub/items.rb +46 -6
  35. data/lib/blather/stanza/pubsub/publish.rb +52 -7
  36. data/lib/blather/stanza/pubsub/retract.rb +45 -6
  37. data/lib/blather/stanza/pubsub/subscribe.rb +30 -4
  38. data/lib/blather/stanza/pubsub/subscription.rb +74 -6
  39. data/lib/blather/stanza/pubsub/subscriptions.rb +35 -9
  40. data/lib/blather/stanza/pubsub/unsubscribe.rb +30 -4
  41. data/lib/blather/stanza/pubsub_owner.rb +17 -7
  42. data/lib/blather/stanza/pubsub_owner/delete.rb +23 -5
  43. data/lib/blather/stanza/pubsub_owner/purge.rb +23 -5
  44. data/lib/blather/stream.rb +96 -29
  45. data/lib/blather/stream/parser.rb +6 -9
  46. data/lib/blather/xmpp_node.rb +101 -153
  47. data/spec/blather/client/client_spec.rb +1 -1
  48. data/spec/blather/errors_spec.rb +5 -5
  49. data/spec/blather/stanza/message_spec.rb +56 -0
  50. data/spec/blather/stanza/presence/status_spec.rb +1 -1
  51. data/spec/blather/stanza_spec.rb +3 -3
  52. data/spec/blather/xmpp_node_spec.rb +19 -74
  53. metadata +6 -10
  54. data/README.rdoc +0 -185
  55. data/examples/drb_client.rb +0 -5
  56. data/examples/ping.rb +0 -11
  57. data/examples/pong.rb +0 -6
  58. data/examples/pubsub/cli.rb +0 -64
  59. data/examples/pubsub/ping_pong.rb +0 -18
@@ -2,9 +2,22 @@ module Blather
2
2
  class Stanza
3
3
  class Presence
4
4
 
5
+ # # Subscription Stanza
6
+ #
7
+ # [RFC 3921 Section 8 - Integration of Roster Items and Presence Subscriptions](http://xmpp.org/rfcs/rfc3921.html#rfc.section.8)
8
+ #
9
+ # Blather handles subscription request/response through this class. It
10
+ # provides a set of helper methods to quickly transform the stanza into a
11
+ # response.
12
+ #
13
+ # @handler :subscription
5
14
  class Subscription < Presence
6
15
  register :subscription, :subscription
7
16
 
17
+ # Create a new Subscription stanza
18
+ #
19
+ # @param [Blather::JID, #to_s] to the JID to subscribe to
20
+ # @param [Symbol, nil] type the subscription type
8
21
  def self.new(to = nil, type = nil)
9
22
  node = super()
10
23
  node.to = to
@@ -12,50 +25,71 @@ class Presence
12
25
  node
13
26
  end
14
27
 
28
+ # @private
15
29
  def inherit(node)
16
30
  inherit_attrs node.attributes
17
31
  self
18
32
  end
19
33
 
34
+ # Set the to value on the stanza
35
+ #
36
+ # @param [Blather::JID, #to_s] to a JID to subscribe to
20
37
  def to=(to)
21
38
  super JID.new(to).stripped
22
39
  end
23
40
 
24
- ##
25
- # Create an approve stanza
41
+ # Transform the stanza into an approve stanza
42
+ # makes approving requests simple
43
+ #
44
+ # @example approve an incoming request
45
+ # subscription(:request?) { |s| write_to_stream s.approve! }
46
+ # @return [self]
26
47
  def approve!
27
48
  self.type = :subscribed
28
49
  reply_if_needed!
29
50
  end
30
51
 
31
- ##
32
- # Create a refuse stanza
52
+ # Transform the stanza into a refuse stanza
53
+ # makes refusing requests simple
54
+ #
55
+ # @example refuse an incoming request
56
+ # subscription(:request?) { |s| write_to_stream s.refuse! }
57
+ # @return [self]
33
58
  def refuse!
34
59
  self.type = :unsubscribed
35
60
  reply_if_needed!
36
61
  end
37
62
 
38
- ##
39
- # Create an unsubscribe stanza
63
+ # Transform the stanza into an unsubscribe stanza
64
+ # makes unsubscribing simple
65
+ #
66
+ # @return [self]
40
67
  def unsubscribe!
41
68
  self.type = :unsubscribe
42
69
  reply_if_needed!
43
70
  end
44
71
 
45
- ##
46
- # Create a cancel stanza
72
+ # Transform the stanza into a cancel stanza
73
+ # makes canceling simple
74
+ #
75
+ # @return [self]
47
76
  def cancel!
48
77
  self.type = :unsubscribed
49
78
  reply_if_needed!
50
79
  end
51
80
 
52
- ##
53
- # Create a request stanza
81
+ # Transform the stanza into a request stanza
82
+ # makes requests simple
83
+ #
84
+ # @return [self]
54
85
  def request!
55
86
  self.type = :subscribe
56
87
  reply_if_needed!
57
88
  end
58
89
 
90
+ # Check if the stanza is a request
91
+ #
92
+ # @return [true, false]
59
93
  def request?
60
94
  self.type == :subscribe
61
95
  end
@@ -1,19 +1,34 @@
1
1
  module Blather
2
2
  class Stanza
3
3
 
4
+ # # Pubsub Stanza
5
+ #
6
+ # [XEP-0060 - Publish-Subscribe](http://xmpp.org/extensions/xep-0060.html)
7
+ #
8
+ # The base class for all PubSub nodes. This provides helper methods common to
9
+ # all PubSub nodes.
10
+ #
11
+ # @handler :pubsub_node
4
12
  class PubSub < Iq
5
13
  register :pubsub_node, :pubsub, 'http://jabber.org/protocol/pubsub'
6
14
 
15
+ # @private
7
16
  def self.import(node)
8
17
  klass = nil
9
18
  if pubsub = node.document.find_first('//ns:pubsub', :ns => self.registered_ns)
10
- pubsub.children.each { |e| break if klass = class_from_registration(e.element_name, (e.namespace.href if e.namespace)) }
19
+ pubsub.children.detect do |e|
20
+ ns = e.namespace ? e.namespace.href : nil
21
+ klass = class_from_registration(e.element_name, ns)
22
+ end
11
23
  end
12
24
  (klass || self).new(node[:type]).inherit(node)
13
25
  end
14
26
 
15
- ##
16
- # Ensure the namespace is set to the query node
27
+ # Overwrites the parent constructor to ensure a pubsub node is present.
28
+ # Also allows the addition of a host attribute
29
+ #
30
+ # @param [<Blather::Stanza::Iq::VALID_TYPES>] type the IQ type
31
+ # @param [String, nil] host the host the node should be sent to
17
32
  def self.new(type = nil, host = nil)
18
33
  new_node = super type
19
34
  new_node.to = host
@@ -21,13 +36,18 @@ class Stanza
21
36
  new_node
22
37
  end
23
38
 
24
- ##
25
- # Kill the pubsub node before running inherit
39
+ # Overrides the parent to ensure the current pubsub node is destroyed before
40
+ # inheritting the new content
41
+ #
42
+ # @private
26
43
  def inherit(node)
27
44
  remove_children :pubsub
28
45
  super
29
46
  end
30
47
 
48
+ # Get or create the pubsub node on the stanza
49
+ #
50
+ # @return [Blather::XMPPNode]
31
51
  def pubsub
32
52
  p = find_first('ns:pubsub', :ns => self.class.registered_ns) ||
33
53
  find_first('pubsub', :ns => self.class.registered_ns)
@@ -38,9 +58,21 @@ class Stanza
38
58
  end
39
59
  p
40
60
  end
41
- end
61
+ end # PubSub
42
62
 
63
+ # # PubSubItem Fragment
64
+ #
65
+ # This fragment is found in many places throughout the pubsub spec
66
+ # This is a convenience class to attach methods to the node
43
67
  class PubSubItem < XMPPNode
68
+ ATOM_NS = 'http://www.w3.org/2005/Atom'.freeze
69
+
70
+ # Create a new PubSubItem
71
+ #
72
+ # @param [String, nil] id the id of the stanza
73
+ # @param [#to_s, nil] payload the payload to attach to this item.
74
+ # @param [XML::Document, nil] document the document the node should be
75
+ # attached to. This should be the document of the parent PubSub node.
44
76
  def self.new(id = nil, payload = nil, document = nil)
45
77
  new_node = super 'item', document
46
78
  new_node.id = id
@@ -48,27 +80,50 @@ class Stanza
48
80
  new_node
49
81
  end
50
82
 
51
- attribute_accessor :id
83
+ # Get the item's ID
84
+ #
85
+ # @return [String, nil]
86
+ def id
87
+ read_attr :id
88
+ end
52
89
 
53
- def payload=(payload = nil)
54
- self.entry.content = payload
90
+ # Set the item's ID
91
+ #
92
+ # @param [#to_s] id the new ID
93
+ def id=(id)
94
+ write_attr :id, id
55
95
  end
56
96
 
97
+ # Get the item's payload
98
+ #
99
+ # To get the XML representation use #entry
100
+ #
101
+ # @return [String, nil]
57
102
  def payload
58
103
  self.entry.content.empty? ? nil : content
59
104
  end
60
105
 
106
+ # Set the item's payload
107
+ #
108
+ # @param [String, nil] payload the payload
109
+ def payload=(payload)
110
+ self.entry.content = payload
111
+ end
112
+
113
+ # Get or create the entry node
114
+ #
115
+ # @return [Blather::XMPPNode]
61
116
  def entry
62
- e = find_first('ns:entry', :ns => 'http://www.w3.org/2005/Atom') ||
63
- find_first('entry', :ns => 'http://www.w3.org/2005/Atom')
117
+ e = find_first('ns:entry', :ns => ATOM_NS) ||
118
+ find_first('entry', :ns => ATOM_NS)
64
119
 
65
120
  unless e
66
121
  self << (e = XMPPNode.new('entry', self.document))
67
- e.namespace = 'http://www.w3.org/2005/Atom'
122
+ e.namespace = ATOM_NS
68
123
  end
69
124
  e
70
125
  end
71
- end
126
+ end # PubSubItem
72
127
 
73
- end #Stanza
74
- end #Blather
128
+ end # Stanza
129
+ end # Blather
@@ -2,39 +2,68 @@ module Blather
2
2
  class Stanza
3
3
  class PubSub
4
4
 
5
+ # # PubSub Affiliations Stanza
6
+ #
7
+ # [XEP-0060 Section 8.9 - Manage Affiliations](http://xmpp.org/extensions/xep-0060.html#owner-affiliations)
8
+ #
9
+ # @handler :pubsub_affiliations
5
10
  class Affiliations < PubSub
6
11
  register :pubsub_affiliations, :affiliations, self.registered_ns
7
12
 
8
13
  include Enumerable
9
14
  alias_method :find, :xpath
10
15
 
16
+ # Overrides the parent to ensure an affiliation node is created
17
+ # @private
11
18
  def self.new(type = nil, host = nil)
12
19
  new_node = super
13
20
  new_node.affiliations
14
21
  new_node
15
22
  end
16
23
 
17
- ##
18
24
  # Kill the affiliations node before running inherit
25
+ # @private
19
26
  def inherit(node)
20
27
  affiliations.remove
21
28
  super
22
29
  end
23
30
 
31
+ # Get or create the affiliations node
32
+ #
33
+ # @return [Blather::XMPPNode]
24
34
  def affiliations
25
- aff = pubsub.find_first('pubsub_ns:affiliations', :pubsub_ns => self.class.registered_ns)
26
- self.pubsub << (aff = XMPPNode.new('affiliations', self.document)) unless aff
35
+ aff = pubsub.find_first('ns:affiliations', :ns => self.class.registered_ns)
36
+ unless aff
37
+ self.pubsub << (aff = XMPPNode.new('affiliations', self.document))
38
+ end
27
39
  aff
28
40
  end
29
41
 
42
+ # Convenience method for iterating over the list
43
+ #
44
+ # @see #list for the format of the yielded input
30
45
  def each(&block)
31
46
  list.each &block
32
47
  end
33
48
 
49
+ # Get the number of affiliations
50
+ #
51
+ # @return [Fixnum]
34
52
  def size
35
53
  list.size
36
54
  end
37
55
 
56
+ # Get the hash of affilations as affiliation-type => [nodes]
57
+ #
58
+ # @example
59
+ #
60
+ # { :owner => ['node1', 'node2'],
61
+ # :publisher => ['node3'],
62
+ # :outcast => ['node4'],
63
+ # :member => ['node5'],
64
+ # :none => ['node6'] }
65
+ #
66
+ # @return [Hash<String => Array<String>>]
38
67
  def list
39
68
  items = affiliations.find('//ns:affiliation', :ns => self.class.registered_ns)
40
69
  items.inject({}) do |hash, item|
@@ -43,8 +72,8 @@ class PubSub
43
72
  hash
44
73
  end
45
74
  end
46
- end #Affiliations
75
+ end # Affiliations
47
76
 
48
- end #PubSub
49
- end #Stanza
50
- end #Blather
77
+ end # PubSub
78
+ end # Stanza
79
+ end # Blather
@@ -2,9 +2,19 @@ module Blather
2
2
  class Stanza
3
3
  class PubSub
4
4
 
5
+ # # PubSub Create Stanza
6
+ #
7
+ # [XEP-0060 Section 8.1 - Create a Node](http://xmpp.org/extensions/xep-0060.html#owner-create)
8
+ #
9
+ # @handler :pubsub_create
5
10
  class Create < PubSub
6
11
  register :pubsub_create, :create, self.registered_ns
7
12
 
13
+ # Create a new Create Stanza
14
+ #
15
+ # @param [<Blather::Stanza::Iq::VALID_TYPES>] type the node type
16
+ # @param [String, nil] host the host to send the request to
17
+ # @param [String, nil] node the name of the node to create
8
18
  def self.new(type = :set, host = nil, node = nil)
9
19
  new_node = super(type, host)
10
20
  new_node.create_node
@@ -13,14 +23,23 @@ class PubSub
13
23
  new_node
14
24
  end
15
25
 
26
+ # Get the name of the node to create
27
+ #
28
+ # @return [String, nil]
16
29
  def node
17
30
  create_node[:node]
18
31
  end
19
32
 
33
+ # Set the name of the node to create
34
+ #
35
+ # @param [String, nil] node
20
36
  def node=(node)
21
37
  create_node[:node] = node
22
38
  end
23
39
 
40
+ # Get or create the actual create node on the stanza
41
+ #
42
+ # @return [Balther::XMPPNode]
24
43
  def create_node
25
44
  unless create_node = pubsub.find_first('ns:create', :ns => self.class.registered_ns)
26
45
  self.pubsub << (create_node = XMPPNode.new('create', self.document))
@@ -29,6 +48,9 @@ class PubSub
29
48
  create_node
30
49
  end
31
50
 
51
+ # Get or create the actual configure node on the stanza
52
+ #
53
+ # @return [Blather::XMPPNode]
32
54
  def configure_node
33
55
  unless configure_node = pubsub.find_first('ns:configure', :ns => self.class.registered_ns)
34
56
  self.pubsub << (configure_node = XMPPNode.new('configure', self.document))
@@ -36,8 +58,8 @@ class PubSub
36
58
  end
37
59
  configure_node
38
60
  end
39
- end #Retract
61
+ end # Create
40
62
 
41
- end #PubSub
42
- end #Stanza
43
- end #Blather
63
+ end # PubSub
64
+ end # Stanza
65
+ end # Blather
@@ -1,9 +1,18 @@
1
1
  module Blather
2
2
  class Stanza
3
3
 
4
+ # # PusSub Error Stanza
5
+ #
6
+ # @private
4
7
  class PubSubErrors < PubSub
5
- attribute_accessor :node, :to_sym => false
6
- end
8
+ def node
9
+ read_attr :node
10
+ end
7
11
 
8
- end #Stanza
9
- end #Blather
12
+ def node=(node)
13
+ write_attr :node, node
14
+ end
15
+ end # PubSubErrors
16
+
17
+ end # Stanza
18
+ end # Blather
@@ -2,48 +2,83 @@ module Blather
2
2
  class Stanza
3
3
  class PubSub
4
4
 
5
+ # # PubSub Event Stanza
6
+ #
7
+ # [XEP-0060](http://xmpp.org/extensions/xep-0060.html)
8
+ #
9
+ # The PubSub Event stanza is used in many places. Please see the XEP for more
10
+ # information.
11
+ #
12
+ # @handler :pubsub_event
5
13
  class Event < Message
14
+ SHIM_NS = 'http://jabber.org/protocol/shim'.freeze
15
+
6
16
  register :pubsub_event, :event, 'http://jabber.org/protocol/pubsub#event'
7
17
 
8
- ##
9
- # Ensure the event_node is created
18
+ # Ensures the event_node is created
19
+ # @private
10
20
  def self.new(type = nil)
11
21
  node = super
12
22
  node.event_node
13
23
  node
14
24
  end
15
25
 
16
- ##
17
26
  # Kill the event_node node before running inherit
27
+ # @private
18
28
  def inherit(node)
19
29
  event_node.remove
20
30
  super
21
31
  end
22
32
 
33
+ # Get the name of the node
34
+ #
35
+ # @return [String, nil]
23
36
  def node
24
37
  !purge? ? items_node[:node] : purge_node[:node]
25
38
  end
26
39
 
40
+ # Get a list of retractions
41
+ #
42
+ # @return [Array<String>]
27
43
  def retractions
28
- items_node.find('//ns:retract', :ns => self.class.registered_ns).map { |i| i[:id] }
44
+ items_node.find('//ns:retract', :ns => self.class.registered_ns).map do |i|
45
+ i[:id]
46
+ end
29
47
  end
30
48
 
49
+ # Check if this is a retractions stanza
50
+ #
51
+ # @return [Boolean]
31
52
  def retractions?
32
53
  !retractions.empty?
33
54
  end
34
55
 
56
+ # Get the list of items attached to this event
57
+ #
58
+ # @return [Array<Blather::Stanza::PubSub::PubSubItem>]
35
59
  def items
36
- items_node.find('//ns:item', :ns => self.class.registered_ns).map { |i| PubSubItem.new(nil,nil,self.document).inherit i }
60
+ items_node.find('//ns:item', :ns => self.class.registered_ns).map do |i|
61
+ PubSubItem.new(nil,nil,self.document).inherit i
62
+ end
37
63
  end
38
64
 
65
+ # Check if this stanza has items
66
+ #
67
+ # @return [Boolean]
39
68
  def items?
40
69
  !items.empty?
41
70
  end
42
71
 
72
+ # Check if this is a purge stanza
73
+ #
74
+ # @return [XML::Node, nil]
43
75
  def purge?
44
76
  purge_node
45
77
  end
46
78
 
79
+ # Get or create the actual event node
80
+ #
81
+ # @return [Blather::XMPPNode]
47
82
  def event_node
48
83
  node = find_first('//ns:event', :ns => self.class.registered_ns)
49
84
  node = find_first('//event', self.class.registered_ns) unless node
@@ -54,6 +89,9 @@ class PubSub
54
89
  node
55
90
  end
56
91
 
92
+ # Get or create the actual items node
93
+ #
94
+ # @return [Blather::XMPPNode]
57
95
  def items_node
58
96
  node = find_first('ns:event/ns:items', :ns => self.class.registered_ns)
59
97
  unless node
@@ -63,15 +101,23 @@ class PubSub
63
101
  node
64
102
  end
65
103
 
104
+ # Get the actual purge node
105
+ #
106
+ # @return [Blather::XMPPNode]
66
107
  def purge_node
67
108
  event_node.find_first('//ns:purge', :ns => self.class.registered_ns)
68
109
  end
69
110
 
111
+ # Get the subscription IDs associated with this event
112
+ #
113
+ # @return [Array<String>]
70
114
  def subscription_ids
71
- find('//ns:header[@name="SubID"]', :ns => 'http://jabber.org/protocol/shim').map { |n| n.content }
115
+ find('//ns:header[@name="SubID"]', :ns => SHIM_NS).map do |n|
116
+ n.content
117
+ end
72
118
  end
73
- end
119
+ end # Event
74
120
 
75
- end #PubSub
76
- end #Stanza
77
- end #Blather
121
+ end # PubSub
122
+ end # Stanza
123
+ end # Blather