librelist archives

« back to archive

connect Shoes.app to signals from external class

connect Shoes.app to signals from external class

From:
J. Kaiden
Date:
2011-06-02 @ 11:18
hi folks,

  i've got a question about making a Shoes.app aware of signals from an
external class.  below is a dumb example for simplicity's sake, but what i'm
really trying to do is connect to gstreamer's EOS (end of song) signal
emitted by an external player class instantiated in my Shoes.app, in order
to update the Shoes GUI as the songs change.
  gstreamer watches a bus for signals, and emits them when they are found -
which i've tried to emulate here using the #.times method, though i'm not
sure it's a very good reproduction of what really happens, and maybe that's
where the trouble lies.  i initially wrote this example using a
GLib::Timeout, but that might well only work on my build (!) so i figured
i'd try this:

#######
class DumbExample
attr_reader :signal, :shot

def initialize
@hits = [1, 3, 5, 7, 9]
end
 def shoot
50.times{|time|
@signal = "nada"
@shot = rand(10)
if @hits.include?(@shot)
self.gotOne(@shot, time)
end
p "##{time} :: signal = #{@signal}"
}
end
 def gotOne(shot, time)
p "##{time} :: #{shot}"
@signal = "got one"
end
end


Shoes.app do

dumb = DumbExample.new
dumb.shoot
 case dumb.signal
when "got one"
para dumb.shot
end
end
##########

  i run this in scite, so i can watch the output from DumbExample - and what
i notice is that the Shoes.app only responds to dumb.signal the last "time"
(#49).  if i've "got one" the 49th time, i'll see it (and only it) in my
Shoes.app - otherwise i get nothing (and not "nada" ;) )
  is there a way to make the Shoes.app aware of and respond to signals as
they are emitted in an external class?  maybe throw a "yield" into
DumbExample#shoot, and put the case statement within dumb.shoot's block?  or
am i (as is quite likely) missing something obvious?

  thanks,

  - j

Re: [shoes] connect Shoes.app to signals from external class

From:
ashbb
Date:
2011-06-02 @ 12:48
Hi Jake,

> maybe throw a "yield" into DumbExample#shoot, and put the case statement
within
> dumb.shoot's block?
Yeah, try out the following. :)

##############
class DumbExample < Shoes::Widget
  attr_reader :signal, :shot

  def initialize
    @hits = [1, 3, 5, 7, 9]
  end

  def shoot
    50.times{|time|
      @signal = "nada"
      @shot = rand(10)
      if @hits.include?(@shot)
        self.gotOne(@shot, time)
        yield
      end
      para "##{time} :: signal = #{@signal}\n"
    }
  end

  def gotOne(shot, time)
    para "##{time} :: #{shot}\n"
    @signal = "got one"
  end
end

Shoes.app do
  de = dumb_example
  de.shoot do
    case de.signal
    when "got one"
      para de.shot, "\n", stroke: red
    end
  end
end
##############

ashbb

Re: [shoes] connect Shoes.app to signals from external class

From:
ashbb
Date:
2011-06-02 @ 12:55
Hi again,

If you don't have to use `para` within DumbExample class. You don't have to
use Shoes::Widget like this:

class DumbExample
  attr_reader :signal, :shot

  def initialize
    @hits = [1, 3, 5, 7, 9]
  end

  def shoot
    50.times{|time|
      @signal = "nada"
      @shot = rand(10)
      if @hits.include?(@shot)
        self.gotOne(@shot, time)
        yield
      end
      #para "##{time} :: signal = #{@signal}\n"
    }
  end

  def gotOne(shot, time)
    #para "##{time} :: #{shot}\n"
    @signal = "got one"
  end
end

Shoes.app do
  de = DumbExample.new
  de.shoot do
    case de.signal
    when "got one"
      para de.shot, "\n", stroke: red
    end
  end
end

--------
ashbb

Re: [shoes] connect Shoes.app to signals from external class

From:
J. Kaiden
Date:
2011-06-02 @ 21:36
you guys rule...

  steve - thanks for the link - looks very interesting, checking it out
now...  this could be the perfect solution.  i'll let you know if i can
shoesify it...

  ashbb - works like a charm...  i had fooled around some with the
Shoes::Widget, and it seemed like a way to go - but as you noted, i don't
need to call #shoot within DumbExample.  your second suggestion gives me
just what i was looking for.

  thanks again for the ideas, rock on...

 - j

Re: [shoes] connect Shoes.app to signals from external class

From:
J. Kaiden
Date:
2011-06-03 @ 00:01
hey folks,

  fooled around with the observer pattern for a bit, and came up with this,
which seems like a nice way of handling signals too:

###
require "observer"

class Publisher
include Observable

def initialize
@hits = [1, 3, 5, 7, 9]
end
 def shoot
50.times{|t|
@shot = rand(10)
if @hits.include?(@shot)
changed
notify_observers(t, @shot)
end
}
end
end

Shoes.app do

def update(t, shot)
para "##{t} => #{shot}: "
end
 pub = Publisher.new
pub.add_observer(self)
pub.shoot
end
###

  - thanks again,

  - j

Re: [shoes] connect Shoes.app to signals from external class

From:
ashbb
Date:
2011-06-03 @ 11:15
Cool!

ashbb

Re: [shoes] connect Shoes.app to signals from external class

From:
Steve Klabnik
Date:
2011-06-03 @ 13:02
That's awesome, I'm glad that works.

I think that Observers will end up being an important part of writing medium
to large Shoes apps.

Re: [shoes] connect Shoes.app to signals from external class

From:
Steve Klabnik
Date:
2011-06-02 @ 12:18
Well, yes. You're not 'sending' anything, you're calling a method, then 
doing the para after. 

What you want is the Observer pattern: 
http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html

I don't know of anyone that's used this with Shoes yet, though, so it 
could be interesting!