hallon 0.11.0 → 0.12.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/.yardopts +1 -0
- data/{CHANGELOG → CHANGELOG.md} +82 -27
- data/Gemfile +1 -0
- data/README.markdown +1 -1
- data/Rakefile +8 -6
- data/examples/adding_tracks_to_playlist.rb +3 -0
- data/examples/logging_in.rb +3 -0
- data/examples/playing_audio.rb +130 -0
- data/examples/printing_link_information.rb +3 -0
- data/examples/show_published_playlists_of_user.rb +5 -13
- data/hallon.gemspec +2 -2
- data/lib/hallon.rb +15 -0
- data/lib/hallon/album.rb +1 -1
- data/lib/hallon/album_browse.rb +4 -3
- data/lib/hallon/artist.rb +1 -1
- data/lib/hallon/artist_browse.rb +5 -4
- data/lib/hallon/base.rb +7 -2
- data/lib/hallon/error.rb +1 -1
- data/lib/hallon/ext/spotify.rb +26 -42
- data/lib/hallon/image.rb +7 -8
- data/lib/hallon/observable.rb +134 -62
- data/lib/hallon/observable/album_browse.rb +30 -0
- data/lib/hallon/observable/artist_browse.rb +31 -0
- data/lib/hallon/observable/image.rb +31 -0
- data/lib/hallon/observable/player.rb +13 -0
- data/lib/hallon/observable/playlist.rb +194 -0
- data/lib/hallon/observable/playlist_container.rb +74 -0
- data/lib/hallon/observable/post.rb +30 -0
- data/lib/hallon/observable/search.rb +29 -0
- data/lib/hallon/observable/session.rb +236 -0
- data/lib/hallon/observable/toplist.rb +30 -0
- data/lib/hallon/player.rb +8 -17
- data/lib/hallon/playlist.rb +11 -7
- data/lib/hallon/playlist_container.rb +11 -4
- data/lib/hallon/queue.rb +71 -0
- data/lib/hallon/search.rb +10 -7
- data/lib/hallon/session.rb +18 -21
- data/lib/hallon/toplist.rb +4 -3
- data/lib/hallon/user.rb +5 -5
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +4 -0
- data/spec/hallon/artist_browse_spec.rb +4 -0
- data/spec/hallon/base_spec.rb +26 -9
- data/spec/hallon/hallon_spec.rb +0 -18
- data/spec/hallon/image_spec.rb +0 -1
- data/spec/hallon/link_spec.rb +14 -0
- data/spec/hallon/observable/album_browse_spec.rb +7 -0
- data/spec/hallon/observable/artist_browse_spec.rb +7 -0
- data/spec/hallon/observable/image_spec.rb +8 -0
- data/spec/hallon/observable/playlist_container_spec.rb +21 -0
- data/spec/hallon/observable/playlist_spec.rb +85 -0
- data/spec/hallon/observable/post_spec.rb +8 -0
- data/spec/hallon/observable/search_spec.rb +7 -0
- data/spec/hallon/observable/session_spec.rb +143 -0
- data/spec/hallon/observable/toplist_spec.rb +7 -0
- data/spec/hallon/observable_spec.rb +134 -65
- data/spec/hallon/playlist_container_spec.rb +24 -18
- data/spec/hallon/playlist_spec.rb +2 -0
- data/spec/hallon/queue_spec.rb +35 -0
- data/spec/hallon/session_spec.rb +4 -4
- data/spec/hallon/spotify_spec.rb +35 -9
- data/spec/mockspotify.rb +2 -3
- data/spec/spec_helper.rb +0 -1
- data/spec/support/common_objects.rb +27 -15
- data/spec/support/enumerable_comparison.rb +9 -0
- data/spec/support/shared_for_callbacks.rb +60 -0
- data/spec/support/shared_for_linkable_objects.rb +1 -1
- metadata +56 -20
data/hallon.gemspec
CHANGED
@@ -21,8 +21,8 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.platform = Gem::Platform::RUBY
|
22
22
|
gem.required_ruby_version = '~> 1.8'
|
23
23
|
|
24
|
-
gem.add_dependency '
|
25
|
-
gem.
|
24
|
+
gem.add_dependency 'ref', '~> 1.0'
|
25
|
+
gem.add_dependency 'spotify', '~> 10.3.0'
|
26
26
|
gem.add_development_dependency 'rake', '~> 0.8'
|
27
27
|
gem.add_development_dependency 'rspec', '~> 2'
|
28
28
|
gem.add_development_dependency 'yard'
|
data/lib/hallon.rb
CHANGED
@@ -9,8 +9,20 @@ require 'hallon/linkable'
|
|
9
9
|
require 'hallon/version'
|
10
10
|
require 'hallon/error'
|
11
11
|
require 'hallon/base'
|
12
|
+
require 'hallon/queue'
|
12
13
|
require 'hallon/enumerator'
|
13
14
|
|
15
|
+
require 'hallon/observable/album_browse'
|
16
|
+
require 'hallon/observable/artist_browse'
|
17
|
+
require 'hallon/observable/image'
|
18
|
+
require 'hallon/observable/playlist_container'
|
19
|
+
require 'hallon/observable/playlist'
|
20
|
+
require 'hallon/observable/post'
|
21
|
+
require 'hallon/observable/session'
|
22
|
+
require 'hallon/observable/search'
|
23
|
+
require 'hallon/observable/toplist'
|
24
|
+
require 'hallon/observable/player'
|
25
|
+
|
14
26
|
require 'hallon/session'
|
15
27
|
require 'hallon/link'
|
16
28
|
require 'hallon/user'
|
@@ -26,6 +38,9 @@ require 'hallon/artist_browse'
|
|
26
38
|
require 'hallon/player'
|
27
39
|
require 'hallon/search'
|
28
40
|
|
41
|
+
# Why is this not the default in Ruby?
|
42
|
+
Thread.abort_on_exception = true
|
43
|
+
|
29
44
|
# The Hallon module wraps around all Hallon objects to avoid polluting
|
30
45
|
# the global namespace. To start using Hallon, you most likely want to
|
31
46
|
# be looking for the documentation on {Hallon::Session}.
|
data/lib/hallon/album.rb
CHANGED
data/lib/hallon/album_browse.rb
CHANGED
@@ -7,7 +7,7 @@ module Hallon
|
|
7
7
|
# @see Album
|
8
8
|
# @see http://developer.spotify.com/en/libspotify/docs/group__albumbrowse.html
|
9
9
|
class AlbumBrowse < Base
|
10
|
-
|
10
|
+
extend Observable::AlbumBrowse
|
11
11
|
|
12
12
|
# Creates an AlbumBrowse instance from an Album or an Album pointer.
|
13
13
|
#
|
@@ -22,8 +22,9 @@ module Hallon
|
|
22
22
|
raise TypeError, "expected album pointer, was given #{given}"
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
subscribe_for_callbacks do |callback|
|
26
|
+
@pointer = Spotify.albumbrowse_create!(session.pointer, pointer, callback, nil)
|
27
|
+
end
|
27
28
|
|
28
29
|
raise FFI::NullPointerError, "album browsing failed" if @pointer.null?
|
29
30
|
end
|
data/lib/hallon/artist.rb
CHANGED
@@ -49,7 +49,7 @@ module Hallon
|
|
49
49
|
def portrait(as_image = true)
|
50
50
|
if as_image
|
51
51
|
portrait = Spotify.artist_portrait(pointer)
|
52
|
-
Image.
|
52
|
+
Image.from(portrait)
|
53
53
|
else
|
54
54
|
portrait = Spotify.link_create_from_artist_portrait!(pointer)
|
55
55
|
Link.from(portrait)
|
data/lib/hallon/artist_browse.rb
CHANGED
@@ -5,7 +5,7 @@ module Hallon
|
|
5
5
|
# @see Artist
|
6
6
|
# @see http://developer.spotify.com/en/libspotify/docs/group__artistbrowse.html
|
7
7
|
class ArtistBrowse < Base
|
8
|
-
|
8
|
+
extend Observable::ArtistBrowse
|
9
9
|
|
10
10
|
# @return [Array<Symbol>] artist browsing types for use in {#initialize}
|
11
11
|
def self.types
|
@@ -26,8 +26,9 @@ module Hallon
|
|
26
26
|
raise TypeError, "expected artist pointer, was given #{given}"
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
29
|
+
subscribe_for_callbacks do |callback|
|
30
|
+
@pointer = Spotify.artistbrowse_create!(session.pointer, pointer, type, callback, nil)
|
31
|
+
end
|
31
32
|
|
32
33
|
raise FFI::NullPointerError, "artist browsing failed" if @pointer.null?
|
33
34
|
end
|
@@ -70,7 +71,7 @@ module Hallon
|
|
70
71
|
size = Spotify.artistbrowse_num_portraits(pointer)
|
71
72
|
Enumerator.new(size) do |i|
|
72
73
|
if as_image
|
73
|
-
id = Spotify.artistbrowse_portrait(pointer, i)
|
74
|
+
id = Spotify.artistbrowse_portrait(pointer, i)
|
74
75
|
Image.new(id)
|
75
76
|
else
|
76
77
|
link = Spotify.link_create_from_artistbrowse_portrait!(pointer, i)
|
data/lib/hallon/base.rb
CHANGED
@@ -3,10 +3,15 @@ module Hallon
|
|
3
3
|
# All objects in Hallon are mere representations of Spotify objects.
|
4
4
|
# Hallon::Base covers basic functionality shared by all of these.
|
5
5
|
class Base
|
6
|
-
# @param [#null?] pointer
|
6
|
+
# @param [#nil?, #null?] pointer
|
7
7
|
# @return [self, nil] a new instance of self, unless given pointer is #null?
|
8
8
|
def self.from(pointer, *args, &block)
|
9
|
-
|
9
|
+
is_nil = pointer.nil?
|
10
|
+
is_null = pointer.null? if pointer.respond_to?(:null?)
|
11
|
+
|
12
|
+
unless is_nil or is_null
|
13
|
+
new(pointer, *args, &block)
|
14
|
+
end
|
10
15
|
end
|
11
16
|
|
12
17
|
# Underlying FFI pointer.
|
data/lib/hallon/error.rb
CHANGED
@@ -49,7 +49,7 @@ module Hallon
|
|
49
49
|
# @param [Fixnum, Symbol] error
|
50
50
|
# @return [nil]
|
51
51
|
def maybe_raise(x)
|
52
|
-
return nil if [nil, :timeout].include?(x)
|
52
|
+
return nil if [nil, :timeout, :is_loading].include?(x)
|
53
53
|
|
54
54
|
error, symbol = disambiguate(x)
|
55
55
|
return symbol if symbol == :ok
|
data/lib/hallon/ext/spotify.rb
CHANGED
@@ -122,7 +122,7 @@ module Spotify
|
|
122
122
|
|
123
123
|
# @return [String] representation of the spotify pointer
|
124
124
|
def to_s
|
125
|
-
"<#{self.class} address
|
125
|
+
"<#{self.class} address=0x#{address.to_s(16)} type=#{type}>"
|
126
126
|
end
|
127
127
|
|
128
128
|
# Create a proc that will accept a pointer of a given type and
|
@@ -142,14 +142,8 @@ module Spotify
|
|
142
142
|
# @param [Object] pointer
|
143
143
|
# @param [Symbol] type (optional, no type checking is done if not given)
|
144
144
|
# @return [Boolean] true if object is a spotify pointer and of correct type
|
145
|
-
def self.typechecks?(object, type
|
146
|
-
if
|
147
|
-
false
|
148
|
-
elsif type
|
149
|
-
object.type == type.to_s
|
150
|
-
else
|
151
|
-
true
|
152
|
-
end
|
145
|
+
def self.typechecks?(object, type)
|
146
|
+
!! (object.type == type.to_s) if object.is_a?(Spotify::Pointer)
|
153
147
|
end
|
154
148
|
end
|
155
149
|
|
@@ -200,51 +194,41 @@ module Spotify
|
|
200
194
|
end
|
201
195
|
|
202
196
|
# Makes it easier binding callbacks safely to callback structs.
|
203
|
-
#
|
197
|
+
#
|
198
|
+
# @see add
|
199
|
+
# @see remove
|
204
200
|
module CallbackStruct
|
205
|
-
#
|
206
|
-
#
|
207
|
-
# storage does not get garbage collected as long as these callbacks
|
208
|
-
# are needed!**
|
201
|
+
# Before assigning [member]=(callback), inspect the arity of
|
202
|
+
# said callback and raise an ArgumentError if they don‘t match.
|
209
203
|
#
|
210
|
-
# @
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
end
|
204
|
+
# @raise ArgumentError if the arity of the given callback does not match the member
|
205
|
+
def []=(member, callback)
|
206
|
+
unless callback.arity < 0 or callback.arity == arity_of(member)
|
207
|
+
raise ArgumentError, "#{member} callback takes #{arity_of(member)} arguments, was #{callback.arity}"
|
208
|
+
else
|
209
|
+
super
|
217
210
|
end
|
218
211
|
end
|
219
|
-
end
|
220
212
|
|
221
|
-
|
222
|
-
include CallbackStruct
|
213
|
+
protected
|
223
214
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
215
|
+
# @param [Symbol] member
|
216
|
+
# @return [Integer] arity of the given callback member
|
217
|
+
def arity_of(member)
|
218
|
+
fn = layout[member].type
|
219
|
+
fn.param_types.size
|
220
|
+
end
|
229
221
|
end
|
230
222
|
|
231
|
-
|
223
|
+
SessionCallbacks.instance_eval do
|
232
224
|
include CallbackStruct
|
233
|
-
|
234
|
-
private
|
235
|
-
# @see CallbackStruct
|
236
|
-
def proc_for(target, member)
|
237
|
-
lambda { |pointer, *args, userdata| target.trigger(member, *args) }
|
238
|
-
end
|
239
225
|
end
|
240
226
|
|
241
|
-
|
227
|
+
PlaylistCallbacks.instance_eval do
|
242
228
|
include CallbackStruct
|
229
|
+
end
|
243
230
|
|
244
|
-
|
245
|
-
|
246
|
-
def proc_for(target, member)
|
247
|
-
lambda { |pointer, *args, userdata| target.trigger(member, *args) }
|
248
|
-
end
|
231
|
+
PlaylistContainerCallbacks.instance_eval do
|
232
|
+
include CallbackStruct
|
249
233
|
end
|
250
234
|
end
|
data/lib/hallon/image.rb
CHANGED
@@ -12,8 +12,7 @@ module Hallon
|
|
12
12
|
|
13
13
|
to_link :from_image
|
14
14
|
|
15
|
-
|
16
|
-
include Observable
|
15
|
+
extend Observable::Image
|
17
16
|
|
18
17
|
# Create a new instance of an Image.
|
19
18
|
#
|
@@ -30,13 +29,13 @@ module Hallon
|
|
30
29
|
end
|
31
30
|
|
32
31
|
@pointer = to_pointer(link, :image) do
|
33
|
-
|
34
|
-
ptr.write_bytes(link)
|
35
|
-
Spotify.image_create!(session.pointer, ptr)
|
32
|
+
Spotify.image_create!(session.pointer, link)
|
36
33
|
end
|
37
34
|
|
38
|
-
|
39
|
-
|
35
|
+
subscribe_for_callbacks do |callbacks|
|
36
|
+
Spotify.image_remove_load_callback(pointer, callbacks, nil)
|
37
|
+
Spotify.image_add_load_callback(pointer, callbacks, nil)
|
38
|
+
end
|
40
39
|
end
|
41
40
|
|
42
41
|
# @return [Boolean] true if the image is loaded.
|
@@ -58,7 +57,7 @@ module Hallon
|
|
58
57
|
# @param [Boolean] raw true if you want the image id as a hexadecimal string
|
59
58
|
# @return [String] image ID as a string.
|
60
59
|
def id(raw = false)
|
61
|
-
id = Spotify.image_image_id(pointer)
|
60
|
+
id = Spotify.image_image_id(pointer)
|
62
61
|
raw ? id : to_hex(id)
|
63
62
|
end
|
64
63
|
|
data/lib/hallon/observable.rb
CHANGED
@@ -1,87 +1,159 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
require 'ref'
|
3
|
+
|
2
4
|
module Hallon
|
3
5
|
# A module providing event capabilities to Hallon objects.
|
4
6
|
#
|
5
7
|
# @private
|
6
8
|
module Observable
|
9
|
+
# This module is responsible for creating methods for registering
|
10
|
+
# callbacks. It expects a certain protocol to already available.
|
11
|
+
module ClassMethods
|
12
|
+
# When extended it’ll call #initialize_observable to set-up `other`.
|
13
|
+
def self.extended(other)
|
14
|
+
other.send(:initialize_observable)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Method, Struct] callbacks to attach to this object
|
18
|
+
attr_reader :callbacks
|
19
|
+
|
20
|
+
# Subscribe to callbacks for a given pointer.
|
21
|
+
#
|
22
|
+
# @param [Object] object
|
23
|
+
# @param [FFI::Pointer] pointer
|
24
|
+
def subscribe(object, pointer)
|
25
|
+
key = pointer.address
|
26
|
+
ref = Ref::WeakReference.new(object)
|
27
|
+
|
28
|
+
@lock.synchronize do
|
29
|
+
if @subscribers_rev[ref.referenced_object_id]
|
30
|
+
raise ArgumentError, "already subscribed to callbacks"
|
31
|
+
end
|
32
|
+
|
33
|
+
@subscribers[key] ||= {} # use a hash for fast reverse lookups
|
34
|
+
@subscribers[key][ref.referenced_object_id] = ref
|
35
|
+
@subscribers_rev[ref.referenced_object_id] = key
|
36
|
+
end
|
37
|
+
|
38
|
+
ObjectSpace.define_finalizer(object, @unsubscriber)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Retrieve all subscribers for a given pointer.
|
42
|
+
#
|
43
|
+
# @param [FFI::Pointer] pointer
|
44
|
+
def subscribers_for(pointer)
|
45
|
+
key = pointer.address
|
46
|
+
|
47
|
+
@lock.synchronize do
|
48
|
+
@subscribers.fetch(key, {}).values.map(&:object).compact
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Run when ClassMethods are extended.
|
55
|
+
#
|
56
|
+
# It sets up the callbacks and all book-keeping required to keep
|
57
|
+
# track of all subscribers properly.
|
58
|
+
def initialize_observable
|
59
|
+
@callbacks = initialize_callbacks
|
60
|
+
|
61
|
+
@lock = Ref::SafeMonitor.new
|
62
|
+
@subscribers = {}
|
63
|
+
@subscribers_rev = {}
|
64
|
+
@unsubscriber = proc do |object_id|
|
65
|
+
@lock.synchronize do
|
66
|
+
if key = @subscribers_rev.delete(object_id)
|
67
|
+
@subscribers[key].delete(object_id)
|
68
|
+
@subscribers.delete(key) if @subscribers[key].empty?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param [#to_s] name
|
75
|
+
# @return [Method]
|
76
|
+
def callback_for(name)
|
77
|
+
method("#{name}_callback")
|
78
|
+
end
|
79
|
+
|
80
|
+
# Scans through the list of subscribers, trying to find any
|
81
|
+
# subscriber attached to this pointer. For each subscriber,
|
82
|
+
# trigger the appropriate event.
|
83
|
+
#
|
84
|
+
# @param [FFI::Pointer] pointer
|
85
|
+
# @param [Symbol] event
|
86
|
+
# @param […] arguments
|
87
|
+
# @return whatever the (last) handler returned
|
88
|
+
def trigger(pointer, event, *arguments)
|
89
|
+
subscribers_for(pointer).inject(nil) do |_, subscriber|
|
90
|
+
# trigger is protected, inconvenient but symbolic
|
91
|
+
subscriber.send(:trigger, event, *arguments)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Will extend `other` with {ClassMethods}.
|
97
|
+
def self.included(other)
|
98
|
+
other.extend(ClassMethods)
|
99
|
+
end
|
100
|
+
|
7
101
|
# Defines a handler for the given event.
|
8
102
|
#
|
9
|
-
# @
|
10
|
-
#
|
11
|
-
# puts message
|
12
|
-
# end
|
13
|
-
#
|
14
|
-
# trigger(:callback, "Moo!") # => prints "Moo!"
|
15
|
-
#
|
16
|
-
# @example multiple events with one handler
|
17
|
-
# on(:a, :b, :c) do |name, *args|
|
18
|
-
# puts "#{name} called with: #{args.inspect}"
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# trigger(:a) # => prints ":a called with: []"
|
22
|
-
# trigger(:b, :c) # => prints ":b called with: [:c]"
|
23
|
-
#
|
24
|
-
# @note when defining a handler for multiple events, the
|
25
|
-
# first argument passed to the handler is the name
|
26
|
-
# of the event that called it
|
27
|
-
# @param [#to_sym] event name of event to handle
|
103
|
+
# @param [#to_s] event name of event to handle
|
104
|
+
# @return [Proc] the given block
|
28
105
|
# @yield (*args) event handler block
|
29
|
-
def on(
|
106
|
+
def on(event, &block)
|
30
107
|
raise ArgumentError, "no block given" unless block
|
31
|
-
|
32
|
-
|
33
|
-
block = proc { |*args| yield(event, *args) } if wrap
|
34
|
-
__handlers[event] = [] unless __handlers.has_key?(event)
|
35
|
-
__handlers[event] << block
|
36
|
-
end
|
108
|
+
raise NameError, "no such callback: #{event}" unless has_callback?(event)
|
109
|
+
handlers[event.to_s] = block
|
37
110
|
end
|
38
111
|
|
39
|
-
#
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
def trigger(event, *params, &block)
|
44
|
-
catch :return do
|
45
|
-
return_value = nil
|
46
|
-
__handlers[event.to_sym].each do |handler|
|
47
|
-
return_value = handler.call(*params, &block)
|
48
|
-
end
|
49
|
-
return_value
|
50
|
-
end
|
112
|
+
# @param [#to_s] name
|
113
|
+
# @return [Boolean] true if a callback with `name` exists.
|
114
|
+
def has_callback?(name)
|
115
|
+
self.class.respond_to?("#{name}_callback", true)
|
51
116
|
end
|
52
117
|
|
53
|
-
# Run
|
54
|
-
#
|
55
|
-
# @example
|
56
|
-
# o = Object.new
|
57
|
-
# o.instance_eval { include Hallon::Base }
|
58
|
-
# o.on(:method) { "outside" }
|
118
|
+
# Run a given block, and once it exits restore all handlers
|
119
|
+
# to the way they were before running the block.
|
59
120
|
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
# o.on(:method) { "inside" }
|
63
|
-
# puts o.on_method # => "inside"
|
64
|
-
# end
|
65
|
-
# puts o.on_method # => "outside"
|
121
|
+
# This allows you to temporarily use different handlers for
|
122
|
+
# some events.
|
66
123
|
#
|
67
124
|
# @yield
|
68
|
-
# @return whatever the given block returns
|
69
125
|
def protecting_handlers
|
70
|
-
|
71
|
-
__handlers.each do |k, v|
|
72
|
-
deep_copy[k] = v.dup
|
73
|
-
end
|
126
|
+
old_handlers = handlers.dup
|
74
127
|
yield
|
75
128
|
ensure
|
76
|
-
|
129
|
+
handlers.replace(old_handlers)
|
77
130
|
end
|
78
131
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
132
|
+
protected
|
133
|
+
|
134
|
+
# Register this object as interested in callbacks.
|
135
|
+
#
|
136
|
+
# @yield [callback]
|
137
|
+
# @yieldparam [Method, Struct] callback (always the same object)
|
138
|
+
# @return whatever the block returns
|
139
|
+
def subscribe_for_callbacks
|
140
|
+
yield(self.class.callbacks).tap do
|
141
|
+
self.class.subscribe(self, pointer)
|
85
142
|
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# @param [#to_s] name
|
146
|
+
# @param [...] arguments
|
147
|
+
# @return whatever the handler returns
|
148
|
+
def trigger(name, *arguments, &block)
|
149
|
+
if handler = handlers[name.to_s]
|
150
|
+
handler.call(*arguments, self, &block)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [Hash<String, Proc>]
|
155
|
+
def handlers
|
156
|
+
@__handlers ||= Hash.new(proc {})
|
157
|
+
end
|
86
158
|
end
|
87
159
|
end
|