Module: Hallon::Observable

Defined in:
lib/hallon/observable.rb,
lib/hallon/observable/post.rb,
lib/hallon/observable/image.rb,
lib/hallon/observable/search.rb,
lib/hallon/observable/player.rb,
lib/hallon/observable/session.rb,
lib/hallon/observable/toplist.rb,
lib/hallon/observable/playlist.rb,
lib/hallon/observable/album_browse.rb,
lib/hallon/observable/artist_browse.rb,
lib/hallon/observable/playlist_container.rb

Overview

A module providing event capabilities to Hallon objects.

Defined Under Namespace

Modules: AlbumBrowse, ArtistBrowse, ClassMethods, Image, Player, Playlist, PlaylistContainer, Post, Search, Session, Toplist

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(other) ⇒ Object

Will extend other with ClassMethods.


61
62
63
# File 'lib/hallon/observable.rb', line 61

def self.included(other)
  other.extend(ClassMethods)
end

Instance Method Details

#handlersHash<String, Proc> (protected)

Returns:

  • (Hash<String, Proc>)

167
168
169
# File 'lib/hallon/observable.rb', line 167

def handlers
  @__handlers ||= Hash.new(proc {})
end

#has_callback?(name) ⇒ Boolean

Returns true if a callback with name exists.

Parameters:

  • name (#to_s)

Returns:

  • (Boolean)

    true if a callback with name exists.


126
127
128
# File 'lib/hallon/observable.rb', line 126

def has_callback?(name)
  self.class.respond_to?("#{name}_callback", true)
end

#on(event) {|*args| ... } ⇒ Proc

Defines a handler for the given event.

Parameters:

  • event (#to_s)

    name of event to handle

Yields:

  • (*args)

    event handler block

Returns:

  • (Proc)

    the previous handler

Raises:

  • (ArgumentError)

70
71
72
73
74
75
# File 'lib/hallon/observable.rb', line 70

def on(event, &block)
  event &&= event.to_s
  raise ArgumentError, "no block given" unless block
  raise NameError, "no such callback: #{event}" unless has_callback?(event)
  handlers[event].tap { handlers[event] = block }
end

#protecting_handlers { ... } ⇒ Object

Run a given block, and once it exits restore all handlers to the way they were before running the block.

This allows you to temporarily use different handlers for some events.

Yields:


137
138
139
140
141
142
# File 'lib/hallon/observable.rb', line 137

def protecting_handlers
  old_handlers = handlers.dup
  yield
ensure
  handlers.replace(old_handlers)
end

#subscribe_for_callbacks {|callback| ... } ⇒ Object (protected)

Register this object as interested in callbacks.

Yields:

  • (callback)

Yield Parameters:

  • callback (Method, Struct)

    (always the same object)

Returns:

  • whatever the block returns


160
161
162
163
164
# File 'lib/hallon/observable.rb', line 160

def subscribe_for_callbacks
  yield(self.class.callbacks).tap do
    self.class.subscribe(self, pointer) unless pointer.null?
  end
end

#trigger(name, *arguments, &block) ⇒ Object

Returns whatever the handler returns.

Parameters:

  • name (#to_s)
  • arguments (...)

Returns:

  • whatever the handler returns


147
148
149
150
151
# File 'lib/hallon/observable.rb', line 147

def trigger(name, *arguments, &block)
  if handler = handlers[name.to_s]
    handler.call(*arguments, &block)
  end
end

#wait_for(*events) {|Symbol, *args| ... } ⇒ Object

Note:

Given block will be called once instantly without parameters.

Note:

If no events happen for 0.25 seconds, the block will be called without parameters.

Wait for the given callbacks to fire until the block returns true

Parameters:

  • events (Symbol, ...)

    list of events to wait for

Yields:

  • (Symbol, *args)

    name of the event that fired, and its’ arguments

Returns:

  • whatever the block returns


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/hallon/observable.rb', line 84

def wait_for(*events)
  channel = SizedQueue.new(10) # sized just to be safe

  old_handlers = events.each_with_object({}) do |event, hash|
    hash[event] = on(event) do |*args|
      channel << [event, *args]
      hash[event].call(*args)
    end
  end

  old_notify = session.on(:notify_main_thread) do
    channel << :notify
  end

  if result = yield
    return result
  end

  loop do
    begin
      timeout = [session.process_events.fdiv(1000), 2].min # scope to two seconds
      timeout = timeout + 0.010 # minimum of ten miliseconds timeout
      params = Timeout::timeout(timeout) { channel.pop }
      redo if params == :notify
    rescue Timeout::Error
      params = nil
    end

    if result = yield(*params)
      return result
    end
  end
ensure
  old_handlers.each_pair do |event, handler|
    on(event, &handler)
  end unless old_handlers.nil?
  session.on(:notify_main_thread, &old_notify) unless old_notify.nil?
end