blather 0.2.1 → 0.2.2

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 (84) hide show
  1. data/LICENSE +2 -0
  2. data/README.rdoc +54 -29
  3. data/Rakefile +94 -13
  4. data/VERSION.yml +4 -0
  5. data/examples/drb_client.rb +2 -4
  6. data/examples/echo.rb +13 -8
  7. data/examples/pubsub/cli.rb +64 -0
  8. data/examples/pubsub/ping_pong.rb +18 -0
  9. data/examples/pubsub/pubsub_dsl.rb +52 -0
  10. data/examples/pubsub_client.rb +39 -0
  11. data/examples/rosterprint.rb +14 -0
  12. data/examples/xmpp4r/echo.rb +35 -0
  13. data/ext/extconf.rb +65 -0
  14. data/lib/blather.rb +18 -121
  15. data/lib/blather/client.rb +13 -0
  16. data/lib/blather/client/client.rb +165 -0
  17. data/lib/blather/client/dsl.rb +99 -0
  18. data/lib/blather/client/pubsub.rb +53 -0
  19. data/lib/blather/client/pubsub/node.rb +27 -0
  20. data/lib/blather/core_ext/active_support.rb +1 -0
  21. data/lib/blather/core_ext/libxml.rb +7 -1
  22. data/lib/blather/errors.rb +39 -18
  23. data/lib/blather/errors/sasl_error.rb +87 -0
  24. data/lib/blather/errors/stanza_error.rb +262 -0
  25. data/lib/blather/errors/stream_error.rb +253 -0
  26. data/lib/blather/jid.rb +9 -16
  27. data/lib/blather/roster.rb +9 -0
  28. data/lib/blather/roster_item.rb +7 -4
  29. data/lib/blather/stanza.rb +19 -25
  30. data/lib/blather/stanza/disco.rb +9 -0
  31. data/lib/blather/stanza/disco/disco_info.rb +84 -0
  32. data/lib/blather/stanza/disco/disco_items.rb +59 -0
  33. data/lib/blather/stanza/iq.rb +16 -4
  34. data/lib/blather/stanza/iq/query.rb +6 -4
  35. data/lib/blather/stanza/iq/roster.rb +38 -38
  36. data/lib/blather/stanza/pubsub.rb +33 -0
  37. data/lib/blather/stanza/pubsub/affiliations.rb +52 -0
  38. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  39. data/lib/blather/stanza/pubsub/event.rb +21 -0
  40. data/lib/blather/stanza/pubsub/items.rb +59 -0
  41. data/lib/blather/stanza/pubsub/owner.rb +9 -0
  42. data/lib/blather/stanza/pubsub/subscriptions.rb +57 -0
  43. data/lib/blather/stream.rb +125 -57
  44. data/lib/blather/stream/client.rb +26 -0
  45. data/lib/blather/stream/component.rb +34 -0
  46. data/lib/blather/stream/parser.rb +17 -27
  47. data/lib/blather/stream/resource.rb +21 -24
  48. data/lib/blather/stream/sasl.rb +60 -37
  49. data/lib/blather/stream/session.rb +12 -19
  50. data/lib/blather/stream/stream_handler.rb +39 -0
  51. data/lib/blather/stream/tls.rb +22 -18
  52. data/lib/blather/xmpp_node.rb +91 -17
  53. data/spec/blather/core_ext/libxml_spec.rb +58 -0
  54. data/spec/blather/errors/sasl_error_spec.rb +56 -0
  55. data/spec/blather/errors/stanza_error_spec.rb +148 -0
  56. data/spec/blather/errors/stream_error_spec.rb +114 -0
  57. data/spec/blather/errors_spec.rb +40 -0
  58. data/spec/blather/jid_spec.rb +0 -7
  59. data/spec/blather/roster_item_spec.rb +5 -0
  60. data/spec/blather/roster_spec.rb +6 -6
  61. data/spec/blather/stanza/discos/disco_info_spec.rb +207 -0
  62. data/spec/blather/stanza/discos/disco_items_spec.rb +136 -0
  63. data/spec/blather/stanza/iq/query_spec.rb +9 -2
  64. data/spec/blather/stanza/iq/roster_spec.rb +117 -1
  65. data/spec/blather/stanza/iq_spec.rb +29 -0
  66. data/spec/blather/stanza/presence/subscription_spec.rb +12 -1
  67. data/spec/blather/stanza/presence_spec.rb +29 -0
  68. data/spec/blather/stanza/pubsub/affiliations_spec.rb +46 -0
  69. data/spec/blather/stanza/pubsub/items_spec.rb +59 -0
  70. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +63 -0
  71. data/spec/blather/stanza/pubsub_spec.rb +26 -0
  72. data/spec/blather/stanza_spec.rb +13 -1
  73. data/spec/blather/stream/client_spec.rb +787 -0
  74. data/spec/blather/stream/component_spec.rb +86 -0
  75. data/spec/blather/xmpp_node_spec.rb +75 -22
  76. data/spec/fixtures/pubsub.rb +157 -0
  77. data/spec/spec_helper.rb +6 -14
  78. metadata +86 -74
  79. data/CHANGELOG +0 -5
  80. data/Manifest +0 -47
  81. data/blather.gemspec +0 -41
  82. data/lib/blather/stanza/error.rb +0 -31
  83. data/spec/blather/stream_spec.rb +0 -462
  84. data/spec/build_safe.rb +0 -20
data/LICENSE CHANGED
@@ -1,3 +1,5 @@
1
+ Blather
2
+
1
3
  Copyright (c) 2008 Jeff Smick
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
@@ -14,8 +14,6 @@ GitHub:: https://github.com/sprsquish/blather
14
14
 
15
15
  RubyForge:: http://rubyforge.org/projects/squishtech/
16
16
 
17
- Lighthouse:: http://squishtech.lighthouseapp.com/projects/20652-blather
18
-
19
17
  == Author
20
18
 
21
19
  Jeff Smick <sprsquish@gmail.com>
@@ -32,47 +30,74 @@ See the /examples directory for more advanced examples.
32
30
 
33
31
  This will auto-accept any subscription requests and echo back any chat messages.
34
32
 
35
- %w[rubygems blather].each { |r| require r }
33
+ require 'rubygems'
34
+ require 'blather/client'
36
35
 
37
36
  setup 'echo@jabber.local', 'echo'
38
37
 
39
38
  # Auto approve subscription requests
40
- handle :subscription do |s|
41
- write(s.approve!) if s.request?
39
+ subscription :request? do |s|
40
+ write s.approve!
42
41
  end
43
42
 
44
43
  # Echo back what was said
45
- handle :message do |m|
46
- write(m.reply) if m.chat? && m.body
44
+ message :chat?, :body do |m|
45
+ write m.reply
47
46
  end
48
-
47
+
48
+ == Handlers
49
+
50
+ Setup handlers by calling their names as methods.
51
+
52
+ # Will only be called for messages where #chat? responds positively
53
+ # and #body == 'exit'
54
+ message :chat?, :body => 'exit'
55
+
56
+ === Handler Guards
57
+
58
+ Guards act like AND statements. Each condition must be met if the handler is to be used.
59
+
60
+ # Equivalent to saying (stanza.chat? && stanza.body)
61
+ message :chat?, :body
62
+
63
+ There are 5 different types of guards:
64
+
65
+ # Symbol
66
+ # Checks for a non-false reply to calling the symbol on the stanza
67
+ # Equivalent to stanza.chat?
68
+ message :chat?
69
+
70
+ # Hash with any value (:body => 'exit')
71
+ # Calls the key on the stanza and checks for equality
72
+ # Equivalent to stanza.body == 'exit'
73
+ message :body => 'exit'
74
+
75
+ # Hash with regular expression (:body => /exit/)
76
+ # Calls the key on the stanza and checks for a match
77
+ # Equivalent to stanza.body.match /exit/
78
+ message :body => /exit/
79
+
80
+ # Proc
81
+ # Calls the proc passing in the stanza
82
+ # Checks that the ID is modulo 3
83
+ message proc { |m| m.id % 3 == 0 }
84
+
85
+ # Array
86
+ # Use arrays with the previous types effectively turns the guard into
87
+ # an OR statement.
88
+ # Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
89
+ message [{:body => 'foo'}, {:body => 'baz'}]
90
+
49
91
  = TODO
50
92
 
51
93
  * Cleanup API
94
+ * Add lambda callback ability to Iq stanzas
52
95
  * Better Documentation
53
96
  * Service Discovery (XEP-0030: http://xmpp.org/extensions/xep-0030.html)
54
97
  * PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
55
- * ?? (suggestions)
98
+ * More examples (Re-write XMPP4R examples into Blather)
56
99
 
57
100
  = License
58
101
 
59
- Copyright (c) 2008 Jeff Smick
60
-
61
- Permission is hereby granted, free of charge, to any person obtaining
62
- a copy of this software and associated documentation files (the
63
- "Software"), to deal in the Software without restriction, including
64
- without limitation the rights to use, copy, modify, merge, publish,
65
- distribute, sublicense, and/or sell copies of the Software, and to
66
- permit persons to whom the Software is furnished to do so, subject to
67
- the following conditions:
68
-
69
- The above copyright notice and this permission notice shall be
70
- included in all copies or substantial portions of the Software.
71
-
72
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
73
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
74
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
75
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
76
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
77
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
78
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
102
+ Please see LICENSE
103
+ The LibXML-Ruby license can be found in its directory
data/Rakefile CHANGED
@@ -1,17 +1,98 @@
1
- require 'echoe'
2
- require 'hanna/rdoctask'
1
+ require 'rubygems'
2
+ require 'rake'
3
3
 
4
- Echoe.new('blather') do |p|
5
- p.author = 'Jeff Smick'
6
- p.email = 'sprsquish@gmail.com'
7
- p.url = 'http://github.com/sprsquish/blather/tree/master'
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'blather'
8
+ gem.description = gem.summary = 'An evented XMPP library written on EventMachine and libxml-ruby'
8
9
 
9
- p.project = 'squishtech'
10
- p.summary = 'An evented XMPP library written on EventMachine and libxml-ruby'
10
+ gem.email = 'sprsquish@gmail.com'
11
+ gem.homepage = 'http://github.com/sprsquish/blather'
12
+ gem.authors = ['Jeff Smick']
11
13
 
12
- p.runtime_dependencies = ['eventmachine', 'libxml-ruby >=0.9.7']
13
- p.rdoc_options += %w[-S -T hanna --main README.rdoc --exclude autotest]
14
+ gem.rubyforge_project = 'squishtech'
14
15
 
15
- p.test_pattern = 'spec/**/*_spec.rb'
16
- p.rcov_options = ['--exclude \/Library\/Ruby\/Gems,spec\/', '--xrefs']
17
- end
16
+ gem.extensions = %w[ext/extconf.rb]
17
+
18
+ gem.add_dependency 'eventmachine', '>= 0.12.6'
19
+ gem.add_dependency 'libxml-ruby', '>= 1.1.3'
20
+
21
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
22
+ end
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
+ end
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'spec'
30
+ test.pattern = 'spec/**/*_spec.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'spec'
38
+ test.pattern = 'spec/**/*_spec.rb'
39
+ test.rcov_opts += ['--exclude \/Library\/Ruby\/Gems,spec\/', '--xrefs']
40
+ test.verbose = true
41
+ end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+
49
+ task :default => :test
50
+
51
+ begin
52
+ require 'hanna/rdoctask'
53
+
54
+ Rake::RDocTask.new do |rdoc|
55
+ if File.exist?('VERSION.yml')
56
+ config = YAML.load(File.read('VERSION.yml'))
57
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
58
+ else
59
+ version = ""
60
+ end
61
+
62
+ rdoc.rdoc_dir = 'rdoc'
63
+ rdoc.title = "blather #{version}"
64
+ rdoc.rdoc_files.include('README*')
65
+ rdoc.rdoc_files.include('lib/**/*.rb')
66
+ rdoc.options += %w[-S -T hanna --main README.rdoc --exclude autotest --exclude vendor]
67
+ end
68
+ rescue LoadError
69
+ task :rdoc do
70
+ abort "Hanna is not available. In order to use the Hanna, you must: sudo gem install mislav-hanna"
71
+ end
72
+ end
73
+
74
+ desc 'Build extensions'
75
+ task :build => :extensions
76
+ task :extension => :build
77
+
78
+ ext = Config::CONFIG["DLEXT"]
79
+ task :extensions => ["ext/push_parser.#{ext}"]
80
+ file "ext/push_parser.#{ext}" =>
81
+ ["Makefile"] + FileList["ext/*.{c,h}"].to_a do |t|
82
+ Dir.chdir("ext") { sh "make" }
83
+ end
84
+
85
+ namespace :extensions do
86
+ desc 'Clean extensions'
87
+ task :clean do
88
+ Dir.chdir("ext") do
89
+ sh "rm -f Makefile"
90
+ sh "rm -f *.{o,so,bundle,log}"
91
+ end
92
+ end
93
+ end
94
+
95
+ file "Makefile" => %w[ext/extconf.rb] do
96
+ command = ["ruby"] + $:.map{|dir| "-I#{File.expand_path dir}"} + ["extconf.rb"]
97
+ Dir.chdir("ext") { sh(*command) }
98
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 2
4
+ :patch: 2
@@ -1,7 +1,5 @@
1
- %w[rubygems lib/blather drb/drb].each { |r| require r }
1
+ %w[rubygems lib/blather/client drb/drb].each { |r| require r }
2
2
 
3
3
  setup 'drb_client@jabber.local', 'drb_client'
4
4
 
5
- handle :ready do
6
- DRb.start_service 'druby://localhost:99843', self
7
- end
5
+ when_ready { DRb.start_service 'druby://localhost:99843', self }
@@ -1,13 +1,18 @@
1
- %w[rubygems lib/blather].each { |r| require r }
1
+ #!/usr/bin/env ruby
2
2
 
3
- setup 'echo@jabber.local', 'echo'
3
+ require 'blather/client'
4
4
 
5
- # Auto approve subscription requests
6
- handle :subscription do |s|
7
- write(s.approve!) if s.request?
5
+ when_ready { puts "Connected ! send messages to #{jid.stripped}." }
6
+
7
+ subscription :request? do |s|
8
+ write s.approve!
9
+ end
10
+
11
+ message :chat?, :body => 'exit' do |m|
12
+ say m.from, 'Exiting ...'
13
+ shutdown
8
14
  end
9
15
 
10
- # Echo back what was said
11
- handle :message do |m|
12
- write(m.reply) if m.chat? && m.body
16
+ message :chat?, :body do |m|
17
+ say m.from, "You sent: #{m.body}"
13
18
  end
@@ -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,52 @@
1
+ # Get affiliations
2
+ pubsub.affiliations do |aff|
3
+ aff == {
4
+ :member => [],
5
+ :none => [],
6
+ :outcast => [],
7
+ :owner => [],
8
+ :publisher => []
9
+ }
10
+ end
11
+
12
+ # Get subscriptions
13
+ pubsub.subscriptions do |sub|
14
+ sub == {
15
+ :none => [],
16
+ :pending => [],
17
+ :subscribed => [],
18
+ :unconfigured => []
19
+ }
20
+ end
21
+
22
+ # Get nodes
23
+ pubsub.nodes(path = nil) do |nodes|
24
+ nodes == [
25
+ DiscoItems::Item
26
+ .jid
27
+ .node
28
+ .name
29
+ ]
30
+ end
31
+
32
+ # Get node
33
+ pubsub.node(path = nil) do |node|
34
+ node = Node
35
+ .attributes = {
36
+ [form data fields]
37
+ }
38
+ .type = '(leaf|collection)'
39
+ .feature = ''
40
+ .items(ids = [], :max => nil) { |list_of_items| }
41
+ end
42
+
43
+ # Get node items
44
+ pubsub.items(path = '' | ids = [], max = nil) do |node_items|
45
+ node_items = [
46
+ Item
47
+ .jid
48
+ .id
49
+ .name
50
+ .payload
51
+ ]
52
+ end
@@ -0,0 +1,39 @@
1
+ # For subscribers
2
+ pubsub.nodes [path]
3
+ pubsub.node('path')
4
+ pubsub.node('path').subscribe
5
+ pubsub.node('path').affiliation
6
+ # For owners
7
+ pubsub.node('path').affiliations
8
+ pubsub.node('path').delete!
9
+ pubsub.node('path').purge!
10
+ pubsub.node('path').options
11
+ pubsub.node('path').defaults
12
+ pubsub.node('path').configure {}
13
+
14
+ pubsub.affiliations
15
+
16
+ pubsub.create 'node'
17
+
18
+ pubsub.publish 'node', 'content'
19
+ pubsub.delete 'node', 'item_id'
20
+
21
+ pubsub.subscriptions
22
+ pubsub.subscribe 'node'
23
+ pubsub.unsubscribe 'node'
24
+
25
+ # For subscribers
26
+ pubsub.subscriptions 'node'
27
+ pubsub.subscription 'node', [sub_id]
28
+ pubsub.subscription('node', [sub_id]).unsubscribe!
29
+ pubsub.subscription('node', [sub_id]).options
30
+ pubsub.subscription('node', [sub_id]).configure 'node', {}
31
+ # For owners
32
+ pubsub.subscriptions.pending
33
+ pubsub.subscription('sub_id').delete!
34
+
35
+
36
+ Node::Collection
37
+ nodes
38
+ Node::Leaf
39
+ items