blather 0.4.7 → 0.4.8

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.
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
@@ -1,20 +1,27 @@
1
1
  module Blather
2
2
 
3
- ##
4
- # Local Roster
3
+ # Local Roster
5
4
  # Takes care of adding/removing JIDs through the stream
6
5
  class Roster
7
6
  include Enumerable
8
7
 
8
+ # Create a new roster
9
+ #
10
+ # @param [Blather::Stream] stream the stream the roster should use to
11
+ # update roster entries
12
+ # @param [Blather::Stanza::Roster] stanza a roster stanza used to preload
13
+ # the roster
14
+ # @return [Blather::Roster]
9
15
  def initialize(stream, stanza = nil)
10
16
  @stream = stream
11
17
  @items = {}
12
18
  stanza.items.each { |i| push i, false } if stanza
13
19
  end
14
20
 
15
- ##
16
- # Process any incoming stanzas adn either add or remove the
21
+ # Process any incoming stanzas and either adds or removes the
17
22
  # corresponding RosterItem
23
+ #
24
+ # @param [Blather::Stanza::Roster] stanza a roster stanza
18
25
  def process(stanza)
19
26
  stanza.items.each do |i|
20
27
  case i.subscription
@@ -24,18 +31,21 @@ module Blather
24
31
  end
25
32
  end
26
33
 
27
- ##
28
34
  # Pushes a JID into the roster
29
- # then returns self to allow for chaining
35
+ #
36
+ # @param [String, Blather::JID, #jid] elem a JID to add to the roster
37
+ # @return [self]
38
+ # @see #push
30
39
  def <<(elem)
31
40
  push elem
32
41
  self
33
42
  end
34
43
 
35
- ##
36
- # Push a JID into the roster
37
- # Will send the new item to the server
38
- # unless overridden by calling #push(elem, false)
44
+ # Push a JID into the roster and update the server
45
+ #
46
+ # @param [String, Blather::JID, #jid] elem a jid to add to the roster
47
+ # @param [true, false] send send the update over the wire
48
+ # @see Blather::JID
39
49
  def push(elem, send = true)
40
50
  jid = elem.respond_to?(:jid) ? elem.jid : JID.new(elem)
41
51
  @items[key(jid)] = node = RosterItem.new(elem)
@@ -44,35 +54,41 @@ module Blather
44
54
  end
45
55
  alias_method :add, :push
46
56
 
47
- ##
48
- # Remove a JID from the roster
49
- # Sends a remove query stanza to the server
57
+ # Remove a JID from the roster and update the server
58
+ #
59
+ # @param [String, Blather::JID] jid the JID to remove from the roster
50
60
  def delete(jid)
51
61
  @items.delete key(jid)
52
- @stream.write Stanza::Iq::Roster.new(:set, Stanza::Iq::Roster::RosterItem.new(jid, nil, :remove))
62
+ item = Stanza::Iq::Roster::RosterItem.new(jid, nil, :remove)
63
+ @stream.write Stanza::Iq::Roster.new(:set, item)
53
64
  end
54
65
  alias_method :remove, :delete
55
66
 
56
- ##
57
67
  # Get a RosterItem by JID
68
+ #
69
+ # @param [String, Blather::JID] jid the jid of the item to return
70
+ # @return [Blather::RosterItem, nil] the associated RosterItem
58
71
  def [](jid)
59
72
  items[key(jid)]
60
73
  end
61
74
 
62
- ##
63
75
  # Iterate over all RosterItems
76
+ #
77
+ # @yield [Blather::RosterItem] yields each RosterItem
64
78
  def each(&block)
65
79
  items.each &block
66
80
  end
67
81
 
68
- ##
69
- # Returns a duplicate of all RosterItems
82
+ # Get a duplicate of all RosterItems
83
+ #
84
+ # @return [Array<Blather::RosterItem>] a duplicate of all RosterItems
70
85
  def items
71
86
  @items.dup
72
87
  end
73
88
 
74
- ##
75
89
  # A hash of items keyed by group
90
+ #
91
+ # @return [Hash<group => Array<RosterItem>>]
76
92
  def grouped
77
93
  self.inject(Hash.new{|h,k|h[k]=[]}) do |hash, item|
78
94
  item[1].groups.each { |group| hash[group] << item[1] }
@@ -81,13 +97,15 @@ module Blather
81
97
  end
82
98
 
83
99
  private
100
+ # Creates a stripped jid
84
101
  def self.key(jid)
85
102
  JID.new(jid).stripped.to_s
86
103
  end
87
104
 
105
+ # Instance method to wrap around the class method
88
106
  def key(jid)
89
107
  self.class.key(jid)
90
108
  end
91
- end #Roster
109
+ end # Roster
92
110
 
93
- end
111
+ end # Blather
@@ -1,10 +1,9 @@
1
1
  module Blather
2
2
 
3
- ##
4
3
  # RosterItems hold internal representations of the user's roster
5
4
  # including each JID's status.
6
5
  class RosterItem
7
- VALID_SUBSCRIPTION_TYPES = [:both, :from, :none, :remove, :to]
6
+ VALID_SUBSCRIPTION_TYPES = [:both, :from, :none, :remove, :to].freeze
8
7
 
9
8
  attr_reader :jid,
10
9
  :ask,
@@ -18,8 +17,19 @@ module Blather
18
17
  super
19
18
  end
20
19
 
21
- ##
22
- # item:: can be a JID, String (a@b) or a Stanza
20
+ # Create a new RosterItem
21
+ #
22
+ # @overload initialize(jid)
23
+ # Create a new RosterItem based on a JID
24
+ # @param [Blather::JID] jid the JID object
25
+ # @overload initialize(jid)
26
+ # Create a new RosterItem based on a JID string
27
+ # @param [String] jid a JID string
28
+ # @overload initialize(node)
29
+ # Create a new RosterItem based on a stanza
30
+ # @param [Blather::Stanza::Iq::Roster::RosterItem] node a RosterItem
31
+ # stanza
32
+ # @return [Blather::RosterItem] the new RosterItem
23
33
  def initialize(item)
24
34
  @statuses = []
25
35
  @groups = []
@@ -40,54 +50,66 @@ module Blather
40
50
  @groups = [nil] if @groups.empty?
41
51
  end
42
52
 
43
- ##
44
53
  # Set the jid
54
+ #
55
+ # @param [String, Blather::JID] jid the new jid
56
+ # @see Blather::JID
45
57
  def jid=(jid)
46
58
  @jid = JID.new(jid).stripped
47
59
  end
48
60
 
49
- ##
50
61
  # Set the subscription
51
62
  # Ensures it is one of VALID_SUBSCRIPTION_TYPES
63
+ #
64
+ # @param [#to_sym] sub the new subscription
52
65
  def subscription=(sub)
53
- raise ArgumentError, "Invalid Type (#{sub}), use: #{VALID_SUBSCRIPTION_TYPES*' '}" if
54
- sub && !VALID_SUBSCRIPTION_TYPES.include?(sub = sub.to_sym)
66
+ if sub && !VALID_SUBSCRIPTION_TYPES.include?(sub = sub.to_sym)
67
+ raise ArgumentError, "Invalid Type (#{sub}), use: #{VALID_SUBSCRIPTION_TYPES*' '}"
68
+ end
55
69
  @subscription = sub ? sub : :none
56
70
  end
57
71
 
58
- ##
59
72
  # Get the current subscription
60
- # returns:: :both, :from, :none, :remove, :to or :none
73
+ #
74
+ # @return [:both, :from, :none, :remove, :to]
61
75
  def subscription
62
76
  @subscription || :none
63
77
  end
64
78
 
65
- ##
66
79
  # Set the ask value
67
- # ask:: must only be nil or :subscribe
80
+ #
81
+ # @param [nil, :subscribe] ask the new ask
68
82
  def ask=(ask)
69
- raise ArgumentError, "Invalid Type (#{ask}), can only be :subscribe" if ask && (ask = ask.to_sym) != :subscribe
83
+ if ask && (ask = ask.to_sym) != :subscribe
84
+ raise ArgumentError, "Invalid Type (#{ask}), can only be :subscribe"
85
+ end
70
86
  @ask = ask ? ask : nil
71
87
  end
72
88
 
73
- ##
74
89
  # Set the status then sorts them according to priority
75
- # presence:: Status
90
+ #
91
+ # @param [Blather::Stanza::Status] the new status
76
92
  def status=(presence)
77
93
  @statuses.delete_if { |s| s.from == presence.from }
78
94
  @statuses << presence
79
95
  @statuses.sort!
80
96
  end
81
97
 
82
- ##
83
- # Return the status with the highest priority
84
- # if resource is set find the status of that specific resource
98
+ # The status with the highest priority
99
+ #
100
+ # @param [String, nil] resource the resource to get the status of
85
101
  def status(resource = nil)
86
- top = resource ? @statuses.detect { |s| s.from.resource == resource } : @statuses.first
102
+ top = if resource
103
+ @statuses.detect { |s| s.from.resource == resource }
104
+ else
105
+ @statuses.first
106
+ end
87
107
  end
88
108
 
89
- ##
90
- # Translate the RosterItem into a proper stanza that can be sent over the stream
109
+ # Translate the RosterItem into a proper stanza that can be sent over the
110
+ # stream
111
+ #
112
+ # @return [Blather::Stanza::Iq::Roster]
91
113
  def to_stanza(type = nil)
92
114
  r = Stanza::Iq::Roster.new type
93
115
  n = Stanza::Iq::Roster::RosterItem.new jid, name, subscription, ask
@@ -1,95 +1,143 @@
1
1
  module Blather
2
- ##
3
- # Base XMPP Stanza
2
+
3
+ # # Base XMPP Stanza
4
+ #
5
+ # All stanzas inherit this class. It provides a set of methods and helpers
6
+ # common to all XMPP Stanzas
7
+ #
8
+ # @handler :stanza
4
9
  class Stanza < XMPPNode
10
+ # @private
5
11
  @@last_id = 0
12
+ # @private
6
13
  @@handler_list = []
7
14
 
8
- class_inheritable_array :handler_heirarchy
15
+ class_inheritable_array :handler_hierarchy
9
16
 
10
- ##
11
- # Registers a callback onto the callback heirarchy stack
17
+ # Registers a callback onto the callback stack
12
18
  #
13
- # Thanks to help from ActiveSupport every class
14
- # that inherits Stanza can register a callback for itself
15
- # which is added to a list and iterated over when looking for
16
- # a callback to use
19
+ # @param [Symbol] handler the name of the handler
20
+ # @param [Symbol, String, nil] name the name of the first element in the
21
+ # stanza. If nil the inherited name will be used. If that's nil the
22
+ # handler name will be used.
23
+ # @param [String, nil] ns the namespace of the stanza
17
24
  def self.register(handler, name = nil, ns = nil)
18
25
  @@handler_list << handler
19
- self.handler_heirarchy ||= []
20
- self.handler_heirarchy.unshift handler
26
+ self.handler_hierarchy ||= [:stanza]
27
+ self.handler_hierarchy.unshift handler
21
28
 
22
29
  name = name || self.registered_name || handler
23
30
  super name, ns
24
31
  end
25
32
 
33
+ # The handler stack for the current stanza class
34
+ #
35
+ # @return [Array<Symbol>]
26
36
  def self.handler_list
27
37
  @@handler_list
28
38
  end
29
39
 
30
- ##
31
40
  # Helper method that creates a unique ID for stanzas
41
+ #
42
+ # @return [String] a new unique ID
32
43
  def self.next_id
33
44
  @@last_id += 1
34
45
  'blather%04x' % @@last_id
35
46
  end
36
47
 
37
- ##
38
- # Helper method to generate stanza guard methods
39
- #
40
- # attribute_helpers_for(:type, [:subscribe, :unsubscribe])
48
+ # Check if the stanza is an error stanza
41
49
  #
42
- # This generates "subscribe?" and "unsubscribe?" methods that return
43
- # true if self.type == :subscribe or :unsubscribe, respectively.
44
- def self.attribute_helpers_for(attr, values)
45
- [values].flatten.each do |v|
46
- define_method("#{v}?") { __send__(attr) == v }
47
- end
50
+ # @return [true, false]
51
+ def error?
52
+ self.type == :error
48
53
  end
49
54
 
50
- attribute_helpers_for(:type, :error)
51
-
52
- ##
53
- # Copies itself then swaps from and to
54
- # then returns the new stanza
55
+ # Creates a copy with to and from swapped
56
+ #
57
+ # @return [Blather::Stanza]
55
58
  def reply
56
59
  self.dup.reply!
57
60
  end
58
61
 
59
- ##
60
62
  # Swaps from and to
63
+ #
64
+ # @return [self]
61
65
  def reply!
62
66
  self.to, self.from = self.from, self.to
63
67
  self
64
68
  end
65
69
 
66
- attribute_accessor :id
70
+ # Get the stanza's ID
71
+ #
72
+ # @return [String, nil]
73
+ def id
74
+ read_attr :id
75
+ end
67
76
 
68
- attribute_writer :to, :from
77
+ # Set the stanza's ID
78
+ #
79
+ # @param [#to_s] id the new stanza ID
80
+ def id=(id)
81
+ write_attr :id, id
82
+ end
69
83
 
70
- ##
71
- # returns:: JID created from the "to" value of the stanza
84
+ # Get the stanza's to
85
+ #
86
+ # @return [Blather::JID, nil]
72
87
  def to
73
88
  JID.new(self[:to]) if self[:to]
74
89
  end
75
90
 
76
- ##
77
- # returns:: JID created from the "from" value of the stanza
91
+ # Set the stanza's to field
92
+ #
93
+ # @param [#to_s] to the new JID for the to field
94
+ def to=(to)
95
+ write_attr :to, to
96
+ end
97
+
98
+ # Get the stanza's from
99
+ #
100
+ # @return [Blather::JID, nil]
78
101
  def from
79
102
  JID.new(self[:from]) if self[:from]
80
103
  end
81
104
 
82
- attribute_accessor :type, :call => :to_sym
105
+ # Set the stanza's from field
106
+ #
107
+ # @param [#to_s] from the new JID for the from field
108
+ def from=(from)
109
+ write_attr :from, from
110
+ end
83
111
 
84
- ##
85
- # Transform the stanza into a stanza error
86
- # <tt>err_name_or_class</tt> can be the name of the error or the error class to use
87
- # <tt>type</tt>, <tt>text</tt>, <tt>extras</tt> are the same as for StanzaError#new
112
+ # Get the stanza's type
113
+ #
114
+ # @return [Symbol, nil]
115
+ def type
116
+ read_attr :type, :to_sym
117
+ end
118
+
119
+ # Set the stanza's type
120
+ #
121
+ # @param [#to_s] type the new stanza type
122
+ def type=(type)
123
+ write_attr :type, type
124
+ end
125
+
126
+ # Create an error stanza from the current stanza
127
+ #
128
+ # @param [String] name the error name
129
+ # @param [<Blather::StanzaError::VALID_TYPES>] type the error type
130
+ # @param [String, nil] text the error text
131
+ # @param [Array<XML::Node>] extras an array of extra nodes to attach to
132
+ # the error
133
+ #
134
+ # @return [Blather::StanzaError]
88
135
  def as_error(name, type, text = nil, extras = [])
89
136
  StanzaError.new self, name, type, text, extras
90
137
  end
91
138
 
92
- protected
139
+ protected
140
+ # @private
93
141
  def reply_if_needed!
94
142
  unless @reversed_endpoints
95
143
  reply!
@@ -1,15 +1,25 @@
1
1
  module Blather
2
2
  class Stanza
3
3
 
4
+ # # Disco Base class
5
+ #
6
+ # Use Blather::Stanza::DiscoInfo or Blather::Stanza::DiscoItems
4
7
  class Disco < Iq::Query
8
+
9
+ # Get the name of the node
10
+ #
11
+ # @return [String] the node name
5
12
  def node
6
13
  query[:node]
7
14
  end
8
15
 
16
+ # Set the name of the node
17
+ #
18
+ # @param [#to_s] node the new node name
9
19
  def node=(node)
10
20
  query[:node] = node
11
21
  end
12
22
  end
13
23
 
14
- end #Stanza
15
- end #Blather
24
+ end # Stanza
25
+ end # Blather