Salut 0.3.1 → 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.
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