development

Networked Drawing Canvas in DRb

In honor of Why The Lucky Stiff’s contributions to the fun side of the Ruby community, whyday.org includes a challenge to “see how far you can push some weird corner of Ruby”. I can think of few corners of Ruby that are weirder (or more fun) than DRb.

Distributed RuBy (DRb) is, in my opinion, the most underrated portion of the Ruby standard library. It lets you take a Ruby class and network-enable it with almost no additional code (and without modifying the original class). Back in 2006 when I was considering whether to learn Ruby or not, I took one look at DRb and realized that a language that made such things possible was probably a language worth knowing.

I made this screencast to show off how powerful DRb is, and how easy it is to get started. We create a simple drawing canvas in Tk, then use DRb to network-enable it and draw to it from a 4-line client. We finish with a Ruby client that runs on Android via the Ruboto environment. And along the way, we cover a little basic security to help keep you safe (this is a network app, after all).

Here’s the complete code for the server:

require 'tk'
require 'drb'

$SAFE = 1

canvas = TkCanvas.new(:width => 800, :height => 600)
canvas.pack

class RemoteCanvas
  def initialize(canvas)
    @canvas = canvas
  end
  def circle(x, y)
    TkcOval.new(@canvas, x, y, x + 40, y + 40)
  end
end

DRb.start_service("druby://192.168.0.100:9000", RemoteCanvas.new(canvas))

canvas.mainloop

Here’s our (tiny) sample client:

require 'drb'
DRb.start_service
canvas = DRbObject.new(nil, "druby://192.168.0.100:9000")
canvas.circle(300, 400)

And here’s the complete touchscreen client for Ruboto:

require "ruboto.rb"
confirm_ruboto_version(4, false)
java_import "org.ruboto.embedded.RubotoView"

require 'drb'
DRb.start_service

$activity.start_ruboto_activity "$druby" do

  setup_content do
    @service = DRbObject.new(nil, "druby://192.168.0.100:9000")
    RubotoView.new($druby)
  end

  handle_touch_event do |event|
    @service.circle(event.get_x, event.get_y)
  end

end

Enjoy, and of course feel free to post questions and comments below. And if you’re looking for your own way to celebrate WhyDay, why not pick your favorite library and network-enable it?

android
development
ruby

Permalink

Making You Happy

“Do Ophelia!”

“Please do Tigerlily!”

…came the encore requests from rapt audience members at the Natalie Merchant concert. And with the kind but commanding tone of someone who knows how to work a crowd, Natalie responded:

“To those of you asking for particular songs, don’t worry, we have something planned. But that makes us feel bad, because we might not know how to do the songs you ask for.” [I assume she meant the ensemble of 8-odd strings, woodwinds, etc. onstage, because I doubt she herself had forgotten the lyrics to “Ophelia”.]

“But this is our promise to you - we’ll make you happy.”

I think that’s a good model for every request, whether you’re asking someone to paint you a painting, code you an application, or sing you a song: Tell them the bare minimum to make you happy. Let them figure out the details, in a way that utilizes their strengths (which they know better than you). Instead of getting a clumsy interpretation of what you were imagining, you may find you’ve commissioned a work of art.

development

Permalink

Ruboto On Acid - Multitouch

Ruboto 0.3 added TouchListener to its event handlers. Here’s my experiment with adding multitouch input to the Ruby On Acid demo…

When it starts up (or the factory resets), all attributes are controlled by an ExampleFactory, meaning they’ll randomly be assigned to LoopFactories, SineFactories, RandomWalkFactories, etc. Touch the screen, though, and control of the drawing x/y position will be given to the touchscreen. Touch in a second place, and control of random attributes will go to your second finger: r/g/b channel, opacity, width, or height.

Continue Reading »

android
development
ruby

Permalink

Pat Maddox - I Love Ruby

From Pat’s MountainWest RubyConf talk. I’m giving a presentation on Rails at work (a JEE shop), and I figured this would help convince my audience. But it also says what many in the Ruby community already feel, so I figured I’d share it.

Like the original, this is released under the Creative Commons Attribution-ShareAlike license.

Pat Maddox - I Love Ruby

development
ruby

Permalink

A challenge!

30 minutes ago, I got this comment on my Ruboto on Acid post:

LSD makes letters on a computer screen look as if they’re dancing around and have a mind of their own. It’s also entirely impossible to think logically enough to code while on it. I recommend you buy some acid and see how it’s nothing like this at all. ;)

And here is my answer. :)

#!/usr/bin/env ruby

require 'rubyonacid/factories/example'
require 'tk'

#This factory will be in charge of all drawing coordinates, colors, etc.
f = RubyOnAcid::ExampleFactory.new

#A skip factory, in charge of randomly resetting the meta factory.
resetter = RubyOnAcid::SkipFactory.new(:odds => 0.99)

#The window to draw to.
canvas = TkCanvas.new(:width => 400, :height => 400)
canvas.pack

#The line objects we create will be stored here.
shapes = []

letters = "woah, trippy, dude!".split(//)

#Create a thread to update the window while it's displayed.
Thread.abort_on_exception = true
Thread.new do
  loop do

    #Get red, green, and blue values for a color from the factory.
    #Format is #RRGGBB in hexadecimal (like HTML).
    color = sprintf("#%02x%02x%02x",
      f.get(:red, :max => 254).to_i,
      f.get(:green, :max => 254).to_i,
      f.get(:blue, :max => 254).to_i
    )

    #Create and store a line of the chosen color.
    #Get width and locations of the endpoints from the factory.
    shapes << TkcText.new(
      canvas,
      f.get(:x1, :max => 400),
      f.get(:y1, :max => 400),
      :text => f.choose(:text, letters),
      :font => TkFont.new(
        :size => f.get(:size, :min => 1, :max => 72).to_i,
      ),
      :fill => color
    )

    #If the resetter returns true, tell the ExampleFactory to reassign
    #its source factories to different keys.
    f.reset_assignments if resetter.boolean(:reset)

    #Delete the oldest line if we have accumulated too many.
    shapes.shift.delete if shapes.length > letters.length

  end
end

#Display the window.
canvas.mainloop

screen-shot-2010-06-12-at-94231-pm.pngscreen-shot-2010-06-12-at-94109-pm.png
screen-shot-2010-06-12-at-93947-pm.pngscreen-shot-2010-06-12-at-93537-pm.png

video

development
ruby

Permalink

MP3 conversions of Ruby conference videos…

I’ve got a sizable commute, so I’ve taken to downloading conference videos and converting to MP3 to play in the car. Most work reasonably well as speech-only, I’m finding. In hopes of helping others, I’m posting them here.

Many thanks to Confreaks, the conference organizers, and to the generous speakers, who released their speeches under a Creative Commons license. In accordance with the license of the original videos, these MP3s are also released under a Creative Commons Attribution-ShareAlike license.

Download MP3 conversions of Confreaks conference videos here.

You can automatically download the lot with wget if you have it installed:

wget --recursive --no-parent --accept mp3,ogg,MP3,OGG http://jay.mcgavren.com/files/conference_mp3s

Conversions were done with ffmpeg. Here’s the script I used:

#!/bin/sh
for filename; do
    ffmpeg -i "${filename}" -acodec libmp3lame -ab 96k -ac 2 -ar 44100 "${filename}.mp3"
done

My chief complaint was wild variation in volume levels; I haven’t blown a speaker yet but loud noises have made me jump sometimes. I’ve processed all these with “mp3gain” (which I thought was only available as a Windows GUI app but have since learned has a Linux command-line version) in an effort to correct this, but I make no guarantees there won’t be sudden jumps or drops in volume.

Many tweaks are still possible, and I will look into them if there’s demand:

  • Remove the periods of silence on each track (where Confreaks originally showed sponsor logos).
  • Convert remaining videos (these were hand-picked).
  • Lower-bitrate versions for the space-conscious.
  • See if The Levelator produces better results than mp3gain.
  • ID3 tags with speakers, titles, and other metadata.
  • An actual podcast feed.

Enjoy, and leave a comment with the improvements you’d like to see!

development
ruby

Permalink

Ruboto On Acid…

After dissecting the demos that come with Ruboto 0.2 and figuring out how to upload a library and runner script to an Android emulator (hint: “$ adb push . /sdcard/jruby/subdirname”), it only took an hour or so to create a working Ruby On Acid demo. And what worked on the emulator immediately worked when uploaded to the phone.

Ruby On Acid in Ruboto IRB
Continue Reading »

android
development
ruby

Permalink

RubyOnAcid version in progress…

Ditched the idea of “tuples” because they complicated the API, and I realized I could do what I want without ‘em. Behold, a LissajousFactory filtered through a RoundingFactory, and feeding into a ProximityFactory:

screen-shot-2010-05-20-at-81348-pm.png

development
ruby

Permalink

Phoenix IGDA Game Jam - Lava Game

Our in-progress game for Android phones, where you move a character around and dig trenches for lava to flow through. Surprisingly easy work once you have the SDK installed and configured. Works great on both an emulator and the hardware.

We have the character movement and grid of dirt squares going. Artwork is, um, a placeholder. :)

lava_in_progress.png

development
java

Permalink

Ruby tweets!

A while back I stumbled across a page of JAPHs, or Just Another Perl Hacker scripts. This was an ongoing competition Perl users had years ago to print the phrase “Just Another Perl Hacker” in the most convoluted way possible, utilizing little-known tricks of the language. They usually stuffed these mini-scripts into their Usenet signatures. I had always admired JAPHs, and decided to try my hand at a Ruby version. But I needed a forum, and I hadn’t been on Usenet in years.

So what’s the modern version? Why, Twitter, of course! The 140-character limit would provide an extra level of challenge, enough so that I didn’t feel a need restrict myself to printing “Just Another Ruby Hacker”.

I started simple, printing a wave to STDOUT.

ruby -e "i=0;loop{puts ' '*(29*(Math.sin(i)/2+1))+'|'*(29*(Math.cos(i)/2+1)); i+=0.1}" #ruby

Copy-paste that to a terminal, and hit Enter. (If you copy from Twitter, there’s no need to worry about line breaks or the Favorite star; the browser strips them.) You get something like this:

               |||||||||||||||||||||||||||||||||||||||||||
                   ||||||||||||||||||||||||||||||||||||||||||
                       ||||||||||||||||||||||||||||||||||||||||
                          ||||||||||||||||||||||||||||||||||||||
                            ||||||||||||||||||||||||||||||||||
                             ||||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||
                           |||||||||||||||||||||
                        ||||||||||||||||||
                     |||||||||||||||
                 ||||||||||||||
            ||||||||||||||
        |||||||||||||||
     ||||||||||||||||||
  |||||||||||||||||||||
|||||||||||||||||||||||||
||||||||||||||||||||||||||||||
 ||||||||||||||||||||||||||||||||||
   ||||||||||||||||||||||||||||||||||||||
       |||||||||||||||||||||||||||||||||||||||||
          ||||||||||||||||||||||||||||||||||||||||||
               |||||||||||||||||||||||||||||||||||||||||||
                   ||||||||||||||||||||||||||||||||||||||||||
                       ||||||||||||||||||||||||||||||||||||||||
                          |||||||||||||||||||||||||||||||||||||
                            ||||||||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||||||
                             |||||||||||||||||||||||||
                           |||||||||||||||||||||
...

Here’s a more-readable version:

            #Have to initialize i before incrementing.
            i=0;

            #loop{} is a few characters less than 1000.times{}.
            #People know where Ctrl-C is on their keyboards. :)
            #Brackets cost less characters than do/end.
            loop {

              #sin() and cos() range -1 to 1.
              #We change result to range 0 to 1.
              left_width = Math.sin(i) / 2 + 1
              wave_width = Math.cos(i) / 2 + 1

              #Indentation of wave's left side.
              print ' ' * (29*left_width)
              #Wave's width, which decides placement of right side.
              print '|' * (29*wave_width)

              print "\n"

              #Increasing input for sin()/cos() makes wave undulate.
              i += 0.1

            }

That’s still among my favorites. But anybody can use puts(). The next was more ambitious…

Continue Reading »

development
ruby

Permalink