Salut 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Mark Rada
1
+ Copyright (c) 2010-2011 Mark Rada
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.markdown CHANGED
@@ -3,6 +3,12 @@ Salut
3
3
 
4
4
  Salut is just a little bit of example code of using Bonjour with MacRuby.
5
5
 
6
+ If all you want to do is log that callbacks were called back, or just add
7
+ very little to a callback, then this code will work well for you. But Apple
8
+ has already done a very good job of distilling Bonjour to the point that
9
+ even without this gem you would not have to add much code in order to use
10
+ Bonjour.
11
+
6
12
  Of course, this is not a substitute for reading the [Bonjour Overview](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/NetServices/Introduction.html%23//apple_ref/doc/uid/TP40002445-SW1) and related documentation (not even close).
7
13
 
8
14
  Reference Documentation
@@ -22,27 +28,28 @@ Example Usage
22
28
 
23
29
  Advertising a hypothetical service:
24
30
 
25
- service = Salut::Service.new({
26
- service_type:'_http._tcp.',
27
- instance_name:`hostname s`.chomp,
28
- port:3000
29
- })
31
+ service = Salut::Service.new(
32
+ service_type:'_http._tcp.',
33
+ instance_name:'SalutDemo',
34
+ port:3000
35
+ )
30
36
  service.start_advertising
31
37
 
32
38
  Finding the service using the browser:
33
39
 
34
40
  browser = Salut::Browser.new
35
- # look at the delegate methods to find out what variables are given to the proc
36
- browser.delegates[:'netServiceBrowser:didFindService:moreComing:'] = Proc.new {
41
+ # the NSNetServiceBrowserDelegate lists all the possible delegates
42
+ # or look at the 'Delegate methods' group in lib/Salut/Browser.rb
43
+ browser.delegate :"netServiceBrowser:didFindService:moreComing:" do
37
44
  |sender, service, more|
38
- service.resolve # because we want to resolve them all!
45
+ service.resolve # if you want to resolve all services found
39
46
  if more
40
47
  NSLog('Not up to date yet')
41
48
  else
42
49
  NSLog('All caught up')
43
50
  end
44
- }
45
- browser.find_services '_http._tcp.', in_domain:''
51
+ end
52
+ browser.find_services '_http._tcp.'
46
53
 
47
54
  If you want to stop advertising:
48
55
 
@@ -58,12 +65,11 @@ a GUI app, but a command line app will have to force the loop to run.
58
65
  You can only use a Service or Browser for one thing at a time, and the API is designed
59
66
  with that assumption in mind.
60
67
 
61
- TODO
62
- ====
68
+ TODO for 1.0
69
+ ==========
63
70
 
64
71
  - Monitoring and TXT record stuff
65
72
  - publishWithOptions default argument
66
- - Do not pass NSNetService or NSNetServiceBrowser to callbacks
67
73
 
68
74
  Contributing to Salut
69
75
  =====================
@@ -79,6 +85,6 @@ Contributing to Salut
79
85
  Copyright
80
86
  =========
81
87
 
82
- Copyright (c) 2010 Mark Rada. See LICENSE.txt for
88
+ Copyright (c) 2010-2011 Mark Rada. See LICENSE.txt for
83
89
  further details.
84
90
 
data/lib/Salut/Browser.rb CHANGED
@@ -1,4 +1,4 @@
1
- # -*- coding: utf-8 -*-
1
+ require 'Salut/Service'
2
2
 
3
3
  module Salut
4
4
 
@@ -21,9 +21,12 @@ module Salut
21
21
  # @return [Array<String>]
22
22
  attr_reader :domains
23
23
 
24
- # @return [Array<NSNetService>]
24
+ # @return [Array<Salut::Service>]
25
25
  attr_reader :services
26
26
 
27
+ # @return [NSNetServiceBrowser]
28
+ attr_reader :browser
29
+
27
30
  # Ensure that some instance variables are initialized
28
31
  def initialize
29
32
  @browser = NSNetServiceBrowser.alloc.init
@@ -42,26 +45,17 @@ module Salut
42
45
 
43
46
  # @group Adding callback extensions
44
47
 
45
- # @return [Hash{Symbol=>Proc}]
46
- attr_accessor :delegates
47
-
48
- # A shortcut for reading from the delegate methods
49
- # @param [Symbol] key
50
- # @return [Proc]
51
- def [] key
52
- @delegates[key]
53
- end
54
-
55
- # A shortcut for writing to the delegate methods hash
56
- # @param [Symbol] key
57
- # @param [Proc] value
48
+ # A shortcut for reading/writing to the delegate methods hash
49
+ # @param [Symbol] method the name of the callback
58
50
  # @return [Proc]
59
- def []= key, value
60
- @delegates[key] = value
51
+ def delegate method
52
+ if block_given?
53
+ @delegates[method] = Proc.new
54
+ else
55
+ @delegates[method]
56
+ end
61
57
  end
62
58
 
63
- # @endgroup
64
-
65
59
 
66
60
  # @group Finding domains
67
61
 
@@ -72,99 +66,86 @@ module Salut
72
66
 
73
67
  alias_method :stop_finding_domains, :stop_finding
74
68
 
75
- # @endgroup
76
-
77
69
 
78
70
  # @group Finding services
79
71
 
80
72
  # @todo find a way to use default arguments
81
73
  # @param [String] service_name
82
74
  # @param [String] domain_name
83
- def find_services service_type, in_domain:domain_name
75
+ def find_services service_type, domain_name = ''
84
76
  @browser.searchForServicesOfType service_type, inDomain:domain_name
85
77
  end
86
78
 
87
79
  alias_method :stop_finding_services, :stop_finding
88
80
 
89
- # @endgroup
90
-
91
81
 
92
82
  # @group Delegate methods
93
83
 
94
- # @yieldparam [NSNetServiceBrowser] sender
84
+ # @yieldparam [Salut::Browser] sender
95
85
  # @yieldparam [String] domain_name
96
86
  # @yieldparam [Boolean] more
97
- # @return [nil]
98
87
  def netServiceBrowser sender, didFindDomain:domain_name, moreComing:more
99
88
  @domains << domain_name
100
- @delegates[__method__].call sender, domain_name, more if @delegates[__method__]
89
+ @delegates[__method__].call self, domain_name, more if @delegates[__method__]
101
90
  Salut.log.info "Found domain: #{domain_name}"
102
91
  end
103
92
 
104
- # @yieldparam [NSNetServiceBrowser] sender
93
+ # @yieldparam [Salut::Browser] sender
105
94
  # @yieldparam [String] domain_name
106
95
  # @yieldparam [Boolean] more
107
- # @return [nil]
108
96
  def netServiceBrowser sender, didRemoveDomain:domain_name, moreComing:more
109
97
  @domains.delete domain_name
110
- @delegates[__method__].call sender, domain_name, more if @delegates[__method__]
98
+ @delegates[__method__].call self, domain_name, more if @delegates[__method__]
111
99
  Salut.log.info "Removing domain: #{domain_name}"
112
100
  end
113
101
 
114
- # @yieldparam [NSNetServiceBrowser] sender
102
+ # @yieldparam [Salut::Browser] sender
115
103
  # @yieldparam [Salut::Service] service
116
104
  # @yieldparam [Boolean] more
117
- # @return [nil]
118
105
  def netServiceBrowser sender, didFindService:service, moreComing:more
119
- salut_service = Service.new({ service:service })
106
+ salut_service = Service.new service:service
120
107
  @services << salut_service
121
- @delegates[__method__].call sender, salut_service, more if @delegates[__method__]
108
+ @delegates[__method__].call self, salut_service, more if @delegates[__method__]
122
109
  Salut.log.info "Found service (#{service.description})"
123
110
  end
124
111
 
125
- # @yieldparam [NSNetServiceBrowser] sender
112
+ # @yieldparam [Salut::Browser] sender
126
113
  # @yieldparam [Salut::Service] removed_service
127
114
  # @yieldparam [Boolean] more
128
- # @return [nil]
129
115
  def netServiceBrowser sender, didRemoveService:service, moreComing:more
130
- removed_service
116
+ removed_service = nil
131
117
  @services.delete_if { |salut_service|
132
118
  if salut_service.service == service
133
119
  removed_service = salut_service
134
120
  true
135
121
  end
136
122
  }
137
- @delegates[__method__].call sender, removed_service, more if @delegates[__method__]
123
+ @delegates[__method__].call self, removed_service, more if @delegates[__method__]
138
124
  Salut.log.info "Removing service (#{service.description})"
139
125
  end
140
126
 
141
- # @yieldparam [NSNetServiceBrowser] sender
142
- # @return [nil]
127
+ # @yieldparam [Salut::Browser] sender
143
128
  def netServiceBrowserWillSearch sender
144
129
  @searching = true
145
- @delegates[__method__].call sender if @delegates[__method__]
130
+ @delegates[__method__].call self if @delegates[__method__]
146
131
  Salut.log.info "Starting search (#{sender.description})"
147
132
  end
148
133
 
149
- # @yieldparam [NSNetServiceBrowser] sender
134
+ # @yieldparam [Salut::Browser] sender
150
135
  # @yieldparam [Hash] error_dict
151
- # @return [nil]
152
136
  def netServiceBrowser sender, didNotSearch:error_dict
153
137
  @searching = false
154
- @delegates[__method__].call sender, error_dict if @delegates[__method__]
138
+ @delegates[__method__].call self, error_dict if @delegates[__method__]
155
139
  Salut.log.info "Failed to search (#{sender.description})\n\t problem was\n#{error_dict.description}"
156
140
  end
157
141
 
158
- # @yieldparam [NSNetServiceBrowser] sender
159
- # @return [nil]
142
+ # @yieldparam [Salut::Browser] sender
160
143
  def netServiceBrowserDidStopSearch sender
161
144
  @searching = false
162
- @delegates[__method__].call sender if @delegates[__method__]
145
+ @delegates[__method__].call self if @delegates[__method__]
163
146
  Salut.log.info "Done searching (#{sender.description})"
164
147
  end
165
148
 
166
- # @endgroup
167
-
168
149
  end
169
150
 
170
151
  end
data/lib/Salut/Service.rb CHANGED
@@ -1,5 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
-
3
1
  module Salut
4
2
 
5
3
  # Advertises its service on the local network using Bonjour or is
@@ -53,26 +51,17 @@ module Salut
53
51
 
54
52
  # @group Adding callback extensions
55
53
 
56
- # @return [Hash{Symbol=>Proc}]
57
- attr_accessor :delegates
58
-
59
- # A shortcut for reading from the delegate methods
60
- # @param [Symbol] key
61
- # @return [Proc]
62
- def [] key
63
- @delegates[key]
64
- end
65
-
66
- # A shortcut for writing to the delegate methods hash
67
- # @param [Symbol] key
68
- # @param [Proc] value
54
+ # A shortcut for reading/writing from the delegate methods
55
+ # @param [Symbol] method
69
56
  # @return [Proc]
70
- def []= key, value
71
- @delegates[key] = value
57
+ def delegate method
58
+ if block_given?
59
+ @delegates[method] = Proc.new
60
+ else
61
+ @delegates[method]
62
+ end
72
63
  end
73
64
 
74
- # @endgroup
75
-
76
65
 
77
66
  # @group Advertising a service
78
67
 
@@ -102,8 +91,6 @@ module Salut
102
91
  @service = nil
103
92
  end
104
93
 
105
- # @endgroup
106
-
107
94
 
108
95
  # @group Working with discovered services
109
96
 
@@ -114,76 +101,64 @@ module Salut
114
101
  @service.resolveWithTimeout timeout
115
102
  end
116
103
 
117
- # @endgroup
118
-
119
104
 
120
105
  # @group Delegate methods
121
106
 
122
- # @yieldparam [NSNetService] sender
123
- # @return [nil]
107
+ # @yieldparam [Salut::Service] sender a reference to self
124
108
  def netServiceWillPublish sender
125
- @delegates[__method__].call sender if @delegates[__method__]
109
+ @delegates[__method__].call self if @delegates[__method__]
126
110
  Salut.log.info "Starting to advertise service (#{sender.description})"
127
111
  end
128
112
 
129
- # @yieldparam [NSNetService] sender
113
+ # @yieldparam [Salut::Service] sender a reference to self
130
114
  # @yieldparam [Hash] error_dict
131
- # @return [nil]
132
115
  def netService sender, didNotPublish:error_dict
133
116
  @advertising = false
134
- @delegates[__method__].call sender, error_dict if @delegates[__method__]
117
+ @delegates[__method__].call self, error_dict if @delegates[__method__]
135
118
  Salut.log.info "ERROR: could not advertise service (#{sender.description})\n\t the problem was\n#{error_dict.description}"
136
119
  end
137
120
 
138
- # @yieldparam [NSNetService] sender
139
- # @return [nil]
121
+ # @yieldparam [Salut::Service] sender a reference to self
140
122
  def netServiceDidPublish sender
141
123
  @advertising = true
142
- @delegates[__method__].call sender if @delegates[__method__]
124
+ @delegates[__method__].call self if @delegates[__method__]
143
125
  Salut.log.info "Successfully advertising service (#{sender.description})"
144
126
  end
145
127
 
146
- # @yieldparam [NSNetService] sender
147
- # @return [nil]
128
+ # @yieldparam [Salut::Service] sender a reference to self
148
129
  def netServiceWillResolve sender
149
- @delegates[__method__].call sender if @delegates[__method__]
130
+ @delegates[__method__].call self if @delegates[__method__]
150
131
  Salut.log.info "Resolving service (#{sender.description})"
151
132
  end
152
133
 
153
- # @yieldparam [NSNetService] sender
134
+ # @yieldparam [Salut::Service] sender a reference to self
154
135
  # @yieldparam [Hash] error_dict
155
- # @return [nil]
156
136
  def netService sender, didNotResolve:error_dict
157
- @delegates[__method__].call sender if @delegates[__method__]
137
+ @delegates[__method__].call self, error_dict if @delegates[__method__]
158
138
  Salut.log.info "ERROR: could not resolve service (#{sender.description})\n\t the problem was\n#{error_dict.description}"
159
139
  end
160
140
 
161
- # @yieldparam [NSNetService] sender
162
- # @return [nil]
141
+ # @yieldparam [Salut::Service] sender a reference to self
163
142
  def netServiceDidResolveAddress sender
164
- @delegates[__method__].call sender if @delegates[__method__]
143
+ @delegates[__method__].call self if @delegates[__method__]
165
144
  Salut.log.info "Resolved address for service (#{sender.description})"
166
145
  end
167
146
 
168
147
  # @todo should I process the TXT record before giving it to the proc?
169
- # @yieldparam [NSNetService] sender
148
+ # @yieldparam [Salut::Service] sender a reference to self
170
149
  # @yieldparam [NSData] data the new TXT record
171
- # @return [nil]
172
150
  def netService sender, didUpdateTXTRecordData:data
173
- @delegates[__method__].call sender, data if @delegates[__method__]
151
+ @delegates[__method__].call self, data if @delegates[__method__]
174
152
  Salut.log.info "Updated TXT record for service (#{sender.description})"
175
153
  end
176
154
 
177
- # @yieldparam [NSNetService] sender
178
- # @return [nil]
155
+ # @yieldparam [Salut::Service] sender a reference to self
179
156
  def netServiceDidStop sender
180
157
  @advertising = false
181
- @delegates[__method__].call sender if @delegates[__method__]
158
+ @delegates[__method__].call self if @delegates[__method__]
182
159
  Salut.log.info "Stopped advertising/resolving service (#{sender.description})"
183
160
  end
184
161
 
185
- # @endgroup
186
-
187
162
  end
188
163
 
189
164
  end
data/spec/Browser_spec.rb CHANGED
@@ -1,2 +1,136 @@
1
1
  require './spec_helper'
2
2
 
3
+ describe Salut::Browser do
4
+ before do
5
+ Salut.log.level = Logger::WARN
6
+ @browser = Salut::Browser.new
7
+ end
8
+
9
+ describe '#searching?' do
10
+ it 'should be initialized to false' do
11
+ @browser.searching?.should.be.equal false
12
+ end
13
+
14
+ it 'should be false after I stop searching' do
15
+ @browser.find_services '_ssh._tcp.'
16
+ run_run_loop 1
17
+ @browser.searching?.should.be.equal true
18
+
19
+ @browser.stop_finding_services
20
+ run_run_loop 1
21
+ @browser.searching?.should.be.equal false
22
+
23
+ @browser.find_browsable_domains
24
+ run_run_loop 1
25
+ @browser.searching?.should.be.equal true
26
+
27
+ @browser.stop_finding_domains
28
+ run_run_loop 1
29
+ @browser.searching?.should.be.equal false
30
+ end
31
+
32
+ # I don't know how to cause a failure when searching
33
+ # for browsable domains
34
+ it 'should be false if searching fails' do
35
+ @browser.find_services 'badname'
36
+ run_run_loop
37
+ @browser.searching?.should.be.equal false
38
+ end
39
+
40
+ it 'should be true when searching starts' do
41
+ @browser.find_services '_ssh._tcp.'
42
+ @browser.searching?.should.be.equal true
43
+
44
+ @browser.stop_finding_services
45
+ run_run_loop 1
46
+ @browser.searching?.should.be.equal false
47
+
48
+ @browser.find_browsable_domains
49
+ @browser.searching?.should.be.equal true
50
+ end
51
+ end
52
+
53
+
54
+ describe '#domains' do
55
+ it 'should be initialized to an empty array' do
56
+ @browser.domains.class.should.be.equal Array
57
+ @browser.domains.should.be.equal []
58
+ end
59
+
60
+ # here I assume that local. will always be found
61
+ it 'should be populated with domains when I browse for domains' do
62
+ @browser.domains.size.should.be.equal 0
63
+ @browser.find_browsable_domains
64
+ run_run_loop
65
+ @browser.domains.size.should.not.be.equal 0
66
+ end
67
+
68
+ # @todo not sure how to fake this one
69
+ it 'should shrink when domains disappear'
70
+ end
71
+
72
+
73
+ describe '#services' do
74
+ before do
75
+ @service = Salut::Service.new(
76
+ service_type:'_test._tcp.',
77
+ instance_name:'TEST',
78
+ port:9000
79
+ )
80
+ @service.start_advertising
81
+ run_run_loop
82
+ end
83
+
84
+ it 'should be initialized to an empty array' do
85
+ @browser.services.class.should.be.equal Array
86
+ @browser.services.should.be.equal []
87
+ end
88
+
89
+ it 'should populate when I call #find_services' do
90
+ @browser.services.size.should.be.equal 0
91
+ @browser.find_services '_test._tcp.'
92
+ run_run_loop
93
+ @browser.services.size.should.not.be.equal 0
94
+ end
95
+
96
+ it 'should dispopulate if services go away after being discovered by calling #find_services' do
97
+ @browser.services.size.should.be.equal 0
98
+ @browser.find_services '_test._tcp.'
99
+ run_run_loop
100
+ @browser.services.size.should.be.equal 1
101
+ @service.stop_advertising
102
+ run_run_loop
103
+ @browser.services.size.should.be.equal 0
104
+ end
105
+ end
106
+
107
+
108
+ describe '#browser' do
109
+ it 'should be the underlying NSNetServiceBrowser' do
110
+ @browser.browser.class.should.be.equal NSNetServiceBrowser
111
+ end
112
+
113
+ it 'should be set at initialization' do
114
+ @browser.browser.should.not.be.equal nil
115
+ end
116
+ end
117
+
118
+
119
+ describe '#initialize' do
120
+ it 'should initialize browser with an NSNetServiceBrowser' do
121
+ @browser.browser.should.not.be.equal nil
122
+ end
123
+
124
+ it 'should initialize #domains to an empty array' do
125
+ @browser.domains.should.be.equal []
126
+ end
127
+
128
+ it 'should initialize #services to an empty array' do
129
+ @browser.services.should.be.equal []
130
+ end
131
+
132
+ it 'should initialize #searching? to false' do
133
+ @browser.searching?.should.be.equal false
134
+ end
135
+ end
136
+ end