sprsquish-blather 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +41 -12
  3. data/examples/echo.rb +1 -1
  4. data/examples/execute.rb +0 -5
  5. data/examples/pubsub/cli.rb +64 -0
  6. data/examples/pubsub/ping_pong.rb +18 -0
  7. data/examples/rosterprint.rb +14 -0
  8. data/examples/xmpp4r/echo.rb +35 -0
  9. data/lib/blather/client/client.rb +19 -13
  10. data/lib/blather/client/dsl/pubsub.rb +133 -0
  11. data/lib/blather/client/dsl.rb +16 -0
  12. data/lib/blather/client.rb +1 -1
  13. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
  14. data/lib/blather/core_ext/active_support.rb +1 -117
  15. data/lib/blather/core_ext/nokogiri.rb +35 -0
  16. data/lib/blather/errors/sasl_error.rb +3 -1
  17. data/lib/blather/errors/stanza_error.rb +10 -17
  18. data/lib/blather/errors/stream_error.rb +11 -14
  19. data/lib/blather/errors.rb +3 -20
  20. data/lib/blather/jid.rb +1 -0
  21. data/lib/blather/roster.rb +9 -0
  22. data/lib/blather/roster_item.rb +6 -1
  23. data/lib/blather/stanza/disco/disco_info.rb +45 -33
  24. data/lib/blather/stanza/disco/disco_items.rb +32 -21
  25. data/lib/blather/stanza/disco.rb +7 -1
  26. data/lib/blather/stanza/iq/query.rb +16 -8
  27. data/lib/blather/stanza/iq/roster.rb +33 -22
  28. data/lib/blather/stanza/iq.rb +13 -8
  29. data/lib/blather/stanza/message.rb +20 -31
  30. data/lib/blather/stanza/presence/status.rb +13 -21
  31. data/lib/blather/stanza/presence/subscription.rb +11 -16
  32. data/lib/blather/stanza/presence.rb +3 -5
  33. data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
  34. data/lib/blather/stanza/pubsub/create.rb +43 -0
  35. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  36. data/lib/blather/stanza/pubsub/event.rb +77 -0
  37. data/lib/blather/stanza/pubsub/items.rb +63 -0
  38. data/lib/blather/stanza/pubsub/publish.rb +58 -0
  39. data/lib/blather/stanza/pubsub/retract.rb +53 -0
  40. data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
  41. data/lib/blather/stanza/pubsub/subscription.rb +66 -0
  42. data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
  43. data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
  44. data/lib/blather/stanza/pubsub.rb +63 -0
  45. data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
  46. data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
  47. data/lib/blather/stanza/pubsub_owner.rb +41 -0
  48. data/lib/blather/stanza.rb +35 -18
  49. data/lib/blather/stream/client.rb +1 -2
  50. data/lib/blather/stream/component.rb +9 -5
  51. data/lib/blather/stream/features/resource.rb +63 -0
  52. data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
  53. data/lib/blather/stream/features/session.rb +44 -0
  54. data/lib/blather/stream/features/tls.rb +28 -0
  55. data/lib/blather/stream/features.rb +53 -0
  56. data/lib/blather/stream/parser.rb +70 -46
  57. data/lib/blather/stream.rb +76 -168
  58. data/lib/blather/xmpp_node.rb +113 -52
  59. data/lib/blather.rb +35 -12
  60. data/spec/blather/client/client_spec.rb +44 -58
  61. data/spec/blather/client/dsl/pubsub_spec.rb +465 -0
  62. data/spec/blather/client/dsl_spec.rb +19 -6
  63. data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
  64. data/spec/blather/errors/sasl_error_spec.rb +8 -8
  65. data/spec/blather/errors/stanza_error_spec.rb +25 -33
  66. data/spec/blather/errors/stream_error_spec.rb +21 -16
  67. data/spec/blather/errors_spec.rb +4 -11
  68. data/spec/blather/jid_spec.rb +31 -30
  69. data/spec/blather/roster_item_spec.rb +34 -23
  70. data/spec/blather/roster_spec.rb +27 -12
  71. data/spec/blather/stanza/discos/disco_info_spec.rb +61 -42
  72. data/spec/blather/stanza/discos/disco_items_spec.rb +47 -35
  73. data/spec/blather/stanza/iq/query_spec.rb +34 -11
  74. data/spec/blather/stanza/iq/roster_spec.rb +47 -30
  75. data/spec/blather/stanza/iq_spec.rb +19 -14
  76. data/spec/blather/stanza/message_spec.rb +30 -17
  77. data/spec/blather/stanza/presence/status_spec.rb +43 -20
  78. data/spec/blather/stanza/presence/subscription_spec.rb +41 -21
  79. data/spec/blather/stanza/presence_spec.rb +34 -21
  80. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  81. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  82. data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
  83. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  84. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  85. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  86. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  87. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  88. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  89. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
  90. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  91. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  92. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  93. data/spec/blather/stanza/pubsub_spec.rb +62 -0
  94. data/spec/blather/stanza_spec.rb +53 -38
  95. data/spec/blather/stream/client_spec.rb +231 -88
  96. data/spec/blather/stream/component_spec.rb +14 -5
  97. data/spec/blather/stream/parser_spec.rb +145 -0
  98. data/spec/blather/xmpp_node_spec.rb +192 -96
  99. data/spec/fixtures/pubsub.rb +311 -0
  100. data/spec/spec_helper.rb +5 -4
  101. metadata +53 -17
  102. data/Rakefile +0 -139
  103. data/ext/extconf.rb +0 -65
  104. data/ext/push_parser.c +0 -209
  105. data/lib/blather/core_ext/libxml.rb +0 -28
  106. data/lib/blather/stream/resource.rb +0 -48
  107. data/lib/blather/stream/session.rb +0 -36
  108. data/lib/blather/stream/stream_handler.rb +0 -39
  109. data/lib/blather/stream/tls.rb +0 -33
  110. data/spec/blather/core_ext/libxml_spec.rb +0 -58
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  Blather
2
2
 
3
- Copyright (c) 2008 Jeff Smick
3
+ Copyright (c) 2009 Jeff Smick
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -1,11 +1,11 @@
1
1
  = Blather
2
2
 
3
- An evented XMPP library
3
+ XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
4
4
 
5
5
  == Features
6
6
 
7
7
  * evented architecture
8
- * uses libxml
8
+ * uses Nokogiri
9
9
  * simplified starting point
10
10
 
11
11
  == Project Pages
@@ -18,11 +18,7 @@ GitHub Docs:: http://docs.github.com/sprsquish/blather
18
18
 
19
19
  RubyForge:: http://rubyforge.org/projects/squishtech
20
20
 
21
- RDocs:: http://squishtech.rubyforge.org/blather/
22
-
23
- == Author
24
-
25
- Jeff Smick <sprsquish@gmail.com>
21
+ RDocs:: http://squishtech.rubyforge.org/blather
26
22
 
27
23
  = Usage
28
24
 
@@ -32,7 +28,7 @@ Jeff Smick <sprsquish@gmail.com>
32
28
 
33
29
  == Example
34
30
 
35
- See the /examples directory for more advanced examples.
31
+ See the examples directory for more advanced examples.
36
32
 
37
33
  This will auto-accept any subscription requests and echo back any chat messages.
38
34
 
@@ -73,7 +69,7 @@ The different types of guards are:
73
69
  # Equivalent to stanza.chat?
74
70
  message :chat?
75
71
 
76
- # Hash with value (:body => 'exit')
72
+ # Hash with any value (:body => 'exit')
77
73
  # Calls the key on the stanza and checks for equality
78
74
  # Equivalent to stanza.body == 'exit'
79
75
  message :body => 'exit'
@@ -99,6 +95,12 @@ The different types of guards are:
99
95
  # Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
100
96
  message [{:body => 'foo'}, {:body => 'baz'}]
101
97
 
98
+ # XPath
99
+ # Runs the xpath query on the stanza and checks for results
100
+ # This guard type cannot be combined with other guards
101
+ # Equivalent to !stanza.find('/iq/ns:pubsub', :ns => 'pubsub:namespace').empty?
102
+ iq '/iq/ns:pubsub', :ns => 'pubsub:namespace'
103
+
102
104
  == On the Command Line:
103
105
 
104
106
  Default usage is:
@@ -117,11 +119,38 @@ Command line options:
117
119
 
118
120
  = TODO
119
121
 
120
- * Add XPath guard that passes the result to the handler
121
122
  * Add Disco the the DSL
122
- * PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
123
123
  * More examples (Re-write XMPP4R examples into Blather)
124
124
 
125
+ = Author
126
+
127
+ Jeff Smick <sprsquish@gmail.com>
128
+
129
+ = Contributors
130
+
131
+ Nolan Darilek <nolan@thewordnerd.info>
132
+
125
133
  = License
126
134
 
127
- Please see LICENSE
135
+ Blather
136
+
137
+ Copyright (c) 2009 Jeff Smick
138
+
139
+ Permission is hereby granted, free of charge, to any person obtaining
140
+ a copy of this software and associated documentation files (the
141
+ "Software"), to deal in the Software without restriction, including
142
+ without limitation the rights to use, copy, modify, merge, publish,
143
+ distribute, sublicense, and/or sell copies of the Software, and to
144
+ permit persons to whom the Software is furnished to do so, subject to
145
+ the following conditions:
146
+
147
+ The above copyright notice and this permission notice shall be
148
+ included in all copies or substantial portions of the Software.
149
+
150
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
151
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
152
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
153
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
154
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
155
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
156
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/examples/echo.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'blather/client'
4
-
4
+ Blather.logger.level = Logger::DEBUG
5
5
  when_ready { puts "Connected ! send messages to #{jid.stripped}." }
6
6
 
7
7
  subscription :request? do |s|
data/examples/execute.rb CHANGED
@@ -1,11 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'blather/client'
4
- require 'blather/client/pubsub'
5
-
6
- setup 'echo@jabber.local', 'echo'
7
-
8
- Blather::LOG.level = Logger::DEBUG
9
4
 
10
5
  message :chat?, :body => 'exit' do |m|
11
6
  say m.from, 'Exiting ...'
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'blather/client'
4
+
5
+ #ls
6
+ #cd
7
+ #cat
8
+ #Blather::LOG.level = Logger::DEBUG
9
+ module CliHandler
10
+ include EM::Protocols::LineText2
11
+
12
+ def ls(node)
13
+ pubsub.node(parse_dir(node)) do |result|
14
+ cur = node.split('/')
15
+ puts
16
+ puts result.items.map { |i| (i.node.split('/') - cur).join('/') }.join("\n")
17
+ start_line
18
+ end
19
+ end
20
+
21
+ def cd(node)
22
+ @node = parse_dir(node)
23
+ start_line
24
+ end
25
+
26
+ def cat(item)
27
+ end
28
+
29
+ def connect(who)
30
+ @who = who
31
+ puts "connected to '#{who}'"
32
+ end
33
+
34
+ def exit(_)
35
+ EM.stop
36
+ end
37
+
38
+ def initialize
39
+ $stdout.sync = true
40
+ @node = ''
41
+ @who = ''
42
+ start_line
43
+ end
44
+
45
+ def start_line
46
+ puts "\n/#{@node}> "
47
+ end
48
+
49
+ def receive_line(line)
50
+ return unless line =~ /(connect|exit|ls|cd|cat)\s?(.*)/i
51
+ __send__ $1, $2
52
+ end
53
+
54
+ def parse_dir(list)
55
+ return '' if list == '/'
56
+ cur = @node.split('/')
57
+ list.split('/').each { |dir| dir == '..' ? cur.pop : (cur << dir) }
58
+ cur * '/'
59
+ end
60
+ end
61
+
62
+ setup 'echo@jabber.local', 'echo'
63
+ pubsub_host 'pubsub.jabber.local'
64
+ when_ready { EM.open_keyboard CliHandler }
@@ -0,0 +1,18 @@
1
+ setup 'ping-pong@jabber.local', 'ping-pong'
2
+
3
+ pubsub.host = 'pubsub.jabber.local'
4
+
5
+ pubsub_event :node => 'ping' do |node|
6
+ pubsub.publish 'pong', node.payload
7
+ end
8
+
9
+ pubsub_event :node => 'pong' do |node|
10
+ x = node.payload.to_i
11
+ if x > 0
12
+ pubsub.publish 'ping', (x - 1)
13
+ else
14
+ shutdown
15
+ end
16
+ end
17
+
18
+ when_ready { pubsub.publish 'ping', 3 }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Prints out each roster entry
4
+
5
+ require 'blather/client'
6
+
7
+ when_ready do
8
+ roster.grouped.each do |group, items|
9
+ puts "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}"
10
+ items.each { |item| puts "- #{item.name} (#{item.jid})" }
11
+ puts
12
+ end
13
+ shutdown
14
+ end
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This bot will reply to every message it receives. To end the game, send 'exit'
4
+
5
+ require 'xmpp4r/client'
6
+ include Jabber
7
+
8
+ # settings
9
+ if ARGV.length != 2
10
+ puts "Run with ./echo_thread.rb user@server/resource password"
11
+ exit 1
12
+ end
13
+ myJID = JID.new(ARGV[0])
14
+ myPassword = ARGV[1]
15
+ cl = Client.new(myJID)
16
+ cl.connect
17
+ cl.auth(myPassword)
18
+ cl.send(Presence.new)
19
+ puts "Connected ! send messages to #{myJID.strip.to_s}."
20
+ mainthread = Thread.current
21
+ cl.add_message_callback do |m|
22
+ if m.type != :error
23
+ m2 = Message.new(m.from, "You sent: #{m.body}")
24
+ m2.type = m.type
25
+ cl.send(m2)
26
+ if m.body == 'exit'
27
+ m2 = Message.new(m.from, "Exiting ...")
28
+ m2.type = m.type
29
+ cl.send(m2)
30
+ mainthread.wakeup
31
+ end
32
+ end
33
+ end
34
+ Thread.stop
35
+ cl.close
@@ -40,7 +40,8 @@ module Blather #:nodoc:
40
40
  end
41
41
 
42
42
  def setup(jid, password, host = nil, port = nil)
43
- @setup = [JID.new(jid), password]
43
+ @jid = JID.new(jid)
44
+ @setup = [@jid, password]
44
45
  @setup << host if host
45
46
  @setup << port if port
46
47
  self
@@ -63,7 +64,6 @@ module Blather #:nodoc:
63
64
  end
64
65
 
65
66
  def write(stanza)
66
- stanza.from ||= jid if stanza.respond_to?(:from)
67
67
  @stream.send(stanza) if @stream
68
68
  end
69
69
 
@@ -73,11 +73,7 @@ module Blather #:nodoc:
73
73
  end
74
74
 
75
75
  def post_init
76
- case @stream
77
- when Stream::Component then ready!
78
- when Stream::Client then client_post_init
79
- else raise "Don't know #{@stream.class} stream type. How the hell did this happen!?"
80
- end
76
+ self.jid.node ? client_post_init : ready!
81
77
  end
82
78
 
83
79
  def close
@@ -93,7 +89,7 @@ module Blather #:nodoc:
93
89
  handler.call stanza
94
90
  else
95
91
  stanza.handler_heirarchy.each do |type|
96
- break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
92
+ break if call_handler_for(type, stanza)# && (stanza.is_a?(BlatherError) || stanza.type == :iq)
97
93
  end
98
94
  end
99
95
  end
@@ -132,8 +128,15 @@ module Blather #:nodoc:
132
128
 
133
129
  def call_handler_for(type, stanza)
134
130
  if @handlers[type]
135
- @handlers[type].find { |guards, handler| handler.call(stanza) unless guarded?(guards, stanza) }
136
- true
131
+ @handlers[type].find do |guards, handler|
132
+ if guards.first.is_a?(String)
133
+ unless (result = stanza.find(*guards)).empty?
134
+ handler.call(stanza, result)
135
+ end
136
+ elsif !guarded?(guards, stanza)
137
+ handler.call(stanza)
138
+ end
139
+ end
137
140
  end
138
141
  end
139
142
 
@@ -171,9 +174,12 @@ module Blather #:nodoc:
171
174
  def check_guards(guards)
172
175
  guards.each do |guard|
173
176
  case guard
174
- when Array then guard.each { |g| check_guards([g]) }
175
- when Symbol, Proc, Hash then nil
176
- else raise "Bad guard: #{guard.inspect}"
177
+ when Array
178
+ guard.each { |g| check_guards([g]) }
179
+ when Symbol, Proc, Hash, String
180
+ nil
181
+ else
182
+ raise "Bad guard: #{guard.inspect}"
177
183
  end
178
184
  end
179
185
  end
@@ -0,0 +1,133 @@
1
+ module Blather
2
+ module DSL
3
+
4
+ class PubSub
5
+ attr_accessor :host
6
+
7
+ def initialize(host)
8
+ @host = host
9
+ end
10
+
11
+ ##
12
+ # Retrieve Affiliations
13
+ # Yields a hash of affiliations in the form:
14
+ # {:aff_type => ['node1', 'node2']}
15
+ def affiliations(host = nil, &callback)
16
+ request Stanza::PubSub::Affiliations.new(:get, send_to(host)), :list, callback
17
+ end
18
+
19
+ ##
20
+ # Retrieve Subscriptions
21
+ # Yields a hash of subscriptions in the form:
22
+ # {:sub_type => [{:node => 'node1', :jid => 'j@d'}]}
23
+ def subscriptions(host = nil, &callback)
24
+ request Stanza::PubSub::Subscriptions.new(:get, send_to(host)), :list, callback
25
+ end
26
+
27
+ ##
28
+ # Discover Nodes
29
+ # Yields a list of DiscoItem::Item objects
30
+ # +path+ is the node's path. Default is '/'
31
+ def nodes(path = nil, host = nil, &callback)
32
+ path ||= '/'
33
+ stanza = Stanza::DiscoItems.new(:get, path)
34
+ stanza.to = send_to(host)
35
+ request stanza, :items, callback
36
+ end
37
+
38
+ ##
39
+ # Discover node information
40
+ # Yields a DiscoInfo node
41
+ # +path+ is the node's path
42
+ def node(path, host = nil, &callback)
43
+ stanza = Stanza::DiscoInfo.new(:get, path)
44
+ stanza.to = send_to(host)
45
+ request stanza, nil, callback
46
+ end
47
+
48
+ ##
49
+ # Retrieve items for a node
50
+ # +path+ is the node's path
51
+ # +list+ can be an array of items to retrieve
52
+ # +max+ can be the maximum number of items to return
53
+ def items(path, list = [], max = nil, host = nil, &callback)
54
+ request Stanza::PubSub::Items.request(send_to(host), path, list, max), :items, callback
55
+ end
56
+
57
+ ##
58
+ # Subscribe to a node
59
+ # Yields the resulting Subscription object
60
+ # +node+ is the node to subscribe to
61
+ # +jid+ is the jid that should be used. Defaults to the stripped current JID
62
+ def subscribe(node, jid = nil, host = nil)
63
+ jid ||= DSL.client.jid.stripped
64
+ request(Stanza::PubSub::Subscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
65
+ end
66
+
67
+ ##
68
+ # Unsubscribe from a node
69
+ # Yields the resulting Unsubscribe object
70
+ # +node+ is the node to subscribe to
71
+ # +jid+ is the jid that should be used. Defaults to the stripped current JID
72
+ def unsubscribe(node, jid = nil, host = nil)
73
+ jid ||= DSL.client.jid.stripped
74
+ request(Stanza::PubSub::Unsubscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
75
+ end
76
+
77
+ ##
78
+ # Publish an item to a node
79
+ # Yields the resulting Publish node
80
+ # +node+ is the node to publish to
81
+ # +payload+ is the payload to send (see Blather::Stanza::PubSub::Publish for details)
82
+ def publish(node, payload, host = nil)
83
+ request(Stanza::PubSub::Publish.new(send_to(host), node, :set, payload)) { |n| yield n if block_given? }
84
+ end
85
+
86
+ ##
87
+ # Delete items from a node
88
+ # Yields the resulting node
89
+ # +node+ is the node to retract items from
90
+ # +ids+ is a list of ids to retract. This can also be a single id
91
+ def retract(node, ids = [], host = nil)
92
+ request(Stanza::PubSub::Retract.new(send_to(host), node, :set, ids)) { |n| yield n if block_given? }
93
+ end
94
+
95
+ ##
96
+ # Create a node
97
+ # Yields the resulting node
98
+ # This does not (yet) handle configuration
99
+ # +node+ is the node to create
100
+ def create(node, host = nil)
101
+ request(Stanza::PubSub::Create.new(:set, send_to(host), node)) { |n| yield n if block_given? }
102
+ end
103
+
104
+ ##
105
+ # Purge all node items
106
+ # Yields the resulting node
107
+ # +node+ is the node to purge
108
+ def purge(node, host = nil)
109
+ request(Stanza::PubSubOwner::Purge.new(:set, send_to(host), node)) { |n| yield n if block_given? }
110
+ end
111
+
112
+ ##
113
+ # Delete a node
114
+ # Yields the resulting node
115
+ # +node+ is the node to delete
116
+ def delete(node, host = nil)
117
+ request(Stanza::PubSubOwner::Delete.new(:set, send_to(host), node)) { |n| yield n if block_given? }
118
+ end
119
+
120
+ private
121
+ def request(node, method = nil, callback = nil, &block)
122
+ block = lambda { |node| callback.call(method ? node.__send__(method) : node) } unless block_given?
123
+ DSL.client.write_with_handler(node, &block)
124
+ end
125
+
126
+ def send_to(host = nil)
127
+ raise 'You must provide a host' unless (host ||= @host)
128
+ host
129
+ end
130
+ end
131
+
132
+ end
133
+ end
@@ -2,11 +2,27 @@ require File.join(File.dirname(__FILE__), 'client')
2
2
 
3
3
  module Blather
4
4
  module DSL
5
+
6
+ autoload :PubSub, File.expand_path(File.join(File.dirname(__FILE__), *%w[dsl pubsub]))
7
+
5
8
  def client
6
9
  @client ||= Client.new
7
10
  end
8
11
  module_function :client
9
12
 
13
+ def pubsub
14
+ @pubsub ||= PubSub.new jid.domain
15
+ end
16
+
17
+ ##
18
+ # Push data to the stream
19
+ # This works such that it can be chained:
20
+ # self << stanza1 << stanza2 << "raw data"
21
+ def <<(stanza)
22
+ write stanza
23
+ self
24
+ end
25
+
10
26
  ##
11
27
  # Prepare server settings
12
28
  # setup [node@domain/resource], [password], [host], [port]
@@ -60,7 +60,7 @@ at_exit do
60
60
  if options[:log]
61
61
  log = File.new(options[:log], 'a')
62
62
  log.sync = options[:debug]
63
- Blather::LOG.level = Logger::DEBUG if options[:debug]
63
+ Blather.logger.level = Logger::DEBUG if options[:debug]
64
64
  $stdout.reopen log
65
65
  $stderr.reopen $stdout
66
66
  end
@@ -0,0 +1,117 @@
1
+ # Thanks to Rails ActiveSupport for everything in this file
2
+
3
+ # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
4
+ # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
5
+ # to, for example, an array without those additions being shared with either their parent, siblings, or
6
+ # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
7
+ class Class # :nodoc:
8
+ def class_inheritable_reader(*syms)
9
+ syms.each do |sym|
10
+ next if sym.is_a?(Hash)
11
+ class_eval <<-EOS
12
+ def self.#{sym}
13
+ read_inheritable_attribute(:#{sym})
14
+ end
15
+
16
+ def #{sym}
17
+ self.class.#{sym}
18
+ end
19
+ EOS
20
+ end
21
+ end
22
+
23
+ def class_inheritable_writer(*syms)
24
+ syms.each do |sym|
25
+ class_eval <<-EOS
26
+ def self.#{sym}=(obj)
27
+ write_inheritable_attribute(:#{sym}, obj)
28
+ end
29
+ EOS
30
+ end
31
+ end
32
+
33
+ def class_inheritable_array_writer(*syms)
34
+ syms.each do |sym|
35
+ class_eval <<-EOS
36
+ def self.#{sym}=(obj)
37
+ write_inheritable_array(:#{sym}, obj)
38
+ end
39
+ EOS
40
+ end
41
+ end
42
+
43
+ def class_inheritable_hash_writer(*syms)
44
+ syms.each do |sym|
45
+ class_eval <<-EOS
46
+ def self.#{sym}=(obj)
47
+ write_inheritable_hash(:#{sym}, obj)
48
+ end
49
+ EOS
50
+ end
51
+ end
52
+
53
+ def class_inheritable_accessor(*syms)
54
+ class_inheritable_reader(*syms)
55
+ class_inheritable_writer(*syms)
56
+ end
57
+
58
+ def class_inheritable_array(*syms)
59
+ class_inheritable_reader(*syms)
60
+ class_inheritable_array_writer(*syms)
61
+ end
62
+
63
+ def class_inheritable_hash(*syms)
64
+ class_inheritable_reader(*syms)
65
+ class_inheritable_hash_writer(*syms)
66
+ end
67
+
68
+ def inheritable_attributes
69
+ @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
70
+ end
71
+
72
+ def write_inheritable_attribute(key, value)
73
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
74
+ @inheritable_attributes = {}
75
+ end
76
+ inheritable_attributes[key] = value
77
+ end
78
+
79
+ def write_inheritable_array(key, elements)
80
+ write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
81
+ write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
82
+ end
83
+
84
+ def write_inheritable_hash(key, hash)
85
+ write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
86
+ write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
87
+ end
88
+
89
+ def read_inheritable_attribute(key)
90
+ inheritable_attributes[key]
91
+ end
92
+
93
+ def reset_inheritable_attributes
94
+ @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
95
+ end
96
+
97
+ private
98
+ # Prevent this constant from being created multiple times
99
+ EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
100
+
101
+ def inherited_with_inheritable_attributes(child)
102
+ inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
103
+
104
+ if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
105
+ new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
106
+ else
107
+ new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
108
+ memo.update(key => value.duplicable? ? value.dup : value)
109
+ end
110
+ end
111
+
112
+ child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
113
+ end
114
+
115
+ alias inherited_without_inheritable_attributes inherited
116
+ alias inherited inherited_with_inheritable_attributes
117
+ end #Class