Saturday, January 31, 2009

More Shoes Structure

When I first started using Shoes, it took me a while to get the various pieces set in my head. There's a couple of different levels to understand. There are a number of tutorials about layout, the most fundamental being Stacks and Flows. This is critical to understanding to design your GUI, but it wasn't enough for me to really understand what was going on.

After hacking around, reading through the source code, and writing some addons I think I'm starting to get my head around it, so here's an attempt to explain some more of the structure of Shoes.

The most basic piece is Shoes.app. This is the method you use to open a window for a new Shoes application; hello world in shoes is something like.

Shoes.app do
para "Hello World"
end

What this does is twofold... it instantiates a new Shoes::App object, and sets self inside the block to point to that object. The Shoes::App object provides all of the helper methods for creating different components, such as para, button, stack, flow, etc, and is responsible for actually rendering them. The objects themselves don't render, they just define a structure that the Shoes::App object will then render. This is why, when trying to do something in a module or class outside of the block, you need to pass in the app object, or access it through the app method on some already rendered object (all shoes objects have an app method to get back to the app they are rendered in).

How does the structure that Shoes::App builds up look? It is a tree format, that actually looks remarkably similar to the DOM in the web world.

At the root of the tree is the slot associated with the original Shoes::App object. This slot behaves like a flow, and can be accessed via the slot method on the Shoes::App object; within the Shoes.app block that would be self.slot. (This is important; after reading that the app object was a flow, I originally thought I'd be able to use all of the flow methods immediately on it, but you actually need to call them on self.slot.)

Every node in the tree has an accessor called parent and one called children. Lets examine what these look like in the hello world example above, by adding some debug output:

app = Shoes.app do
para "Hello World"
end
Shoes.debug "Parent is #{app.slot.parent.inspect}"
Shoes.debug "Children are #{app.slot.children.inspect}"

The console now shows:



which is pretty much what we'd expect. The root should have no parent, and the paragraph is pretty much the only element, so it should be the first child. What does that paragraph look like? Lets try

Shoes.app do
p = para "Hello World"
Shoes.debug "Para Parent is #{p.parent.inspect}"
Shoes.debug "Para Children are #{p.children.inspect}"
end

Now we see:



The parent is pointing back to the app.slot (which we now see is not actually a flow, but an instance of the Shoes class, which flows inherit from.) And the children of a Para object actually contain the text of the paragraph.

Understanding this tree structure was one of the biggest breakthroughs for me, because it means that many of the things I know from manipulating the DOM with javascript in the web world are suddenly applicable to Shoes. I'm no javascript genius, but I have already climbed some of the learning curve there, and being able to apply that to Shoes was eye opening.

One of the things the DOM does really well (and the Shoes model should as well) is allow you to navigate, find, and manipulate things that have been generated someplace else. This is where I got the idea for ShoeQuery, and will prove extremely useful in my efforts to build a Shoes debugger.

I think this similarity could make Shoes the toolkit of choice for web developers coming to the desktop.

Thursday, January 29, 2009

Event Handler chains in Shoes

One of the beautiful things about Shoes is how simple and easy it is to set up event handlers on objects. As I talked about in a previous post creating a handler on a button is as simple as

b = button "Click Me"
b.click { alert "You clicked the button" }

This is great for simple things, but I hadn't been hacking on Shoes for very long before I wanted to do more than this. In particular, since one of my projects is creating an application to preview Shoes applications, I wanted to be able to add handlers that call back into my main application without worrying about their effect on the code being previewed.

To do this, you need to be able to have multiple handlers on an element at once, so that you can add new event handlers without disturbing the existing ones. I spent a while trying to understand the c-based implementation of event handlers, and figuring out all of the things I'd have to do to change it to a chain based implementation, but then realized that given the ruby nature of Shoes, this was a prime opportunity for monkeypatching.

Monkeypatching may be a little less performant, but this is for a debugger-style thing anyway (I'm thinking I want to get to something a lot like Firebug is for web development...), so who cares if its slow?

So in I dove. I'm calling the module ShoeShine, because its cleaning up my Shoes without changing the inside at all, and it turned out to be pretty simple to implement. First, I define a few methods to add, remove, and call handlers:


def add_handler(type, &block)
@_handlers ||= {}
@_handlers[type] ||= []
@_handlers[type].push block
# set up callbacks from old handlers invocation into
# new handler chain
self.send "#{type}_without_chains".to_sym do |*args|
self.call_handlers(type, *args)
end
end

def clear_handlers(type)
if @_handlers
if @_handlers.delete(type)
_handler_deleted(type)
end
end
end

def call_handlers(type, *args)
return unless @_handlers[type
@_handlers[type].each do |block|
block.call(*args)
end
end


Then I do some metaprogramming and monkeypatching to plug this in between handler registration and handler callback:


HANDLERS.each do |handler|
eval %(
def #{handler}_with_chains(&block)
# need to clear handlers to maintain old semantics
clear_handlers(:#{handler})
add_handler(:#{handler}, &block)
end
)
end

def self.included(klass)
klass.instance_eval do
ShoeShine::HANDLERS.each do |handler|
if klass.instance_methods.include? handler.to_s
# Replace old handlers with new handlers
alias_method "#{handler}_without_chains".to_sym, handler
alias_method handler, "#{handler}_with_chains".to_sym
end
end
end
end


Finally, I include this module into all interesting Shoes classes:


Shoes.constants.each do |c|
k = Shoes.const_get(c)
if k.is_a? Class
k.send :include, ShoeShine
end
end


Voila! Suddenly, as well as having the traditional Shoes interface to handlers, you can also add additional handlers onto existing objects without disturbing the originals. This will open the door to all sorts of interesting things. I've already mentioned my intent to use this for debugging, but I'm also exploring using this as a way to get around the current Shoes limitations on click, hover, leave, etc handlers of only working on slots, allowing them to trickle down to paragraphs, widgets, etc.

I've got some early versions of this working, but its definitely not ready for prime time yet. For any who are interested, you can find both the ShoeShine code and my early trickle down work at github in the shoes-preview tree.

Sunday, January 25, 2009

Can I just say how much I love method_missing?

I wanted to follow up on my previous explorations with ShoeQuery to add some helper methods to access pieces of shoes functionality... thinking I'd have to add pieces one by one. However, it turns out that due to the magic of method_missing, I was able to add access to basically all of them with a single 22-line method. It looks like:


def method_missing(method, *args, &block)
if args.empty? && !block_given?
# if you have no arguments and no block, think of it as a query
# and return the answer for the first element.
if first.respond_to? method
return first.send(method)
else
return elem.style(method)
end
elsif block_given?
each {|elem| elem.send(method, *args, &block)}
else
# Otherwise, think of it as a setter
setter = "#{method}=".to_sym
if first.respond_to? setter
each {|elem| elem.send(setter, *args, &block)}
else
each {|elem| elem.style(method => args[0], &block)}
end
end
self
end


And now, thanks to this I can write lines in shoes as follows:


# find all paragraphs, change their text to 'all ps', and color
# them red
shoe_query('para').text("all ps").stroke(red)



# replace the click handlers on all buttons
shoe_query('button').click do
para "All your button are belong to us now
end

Introducing ShoeQuery

ShoeQuery (better name needed) was born out of a desire to be able to find and manipulate elements in Shoes without having stashed away their locations ahead of time. It was inspired by jQuery's mechanisms for finding and manipulating DOM objects in Javascript.

The fundamental object (a ShoeQuery object) is pretty much an array of Shoes Elements, augmented with some extra functions. ShoeQuery objects are created via a helper (unsurprisingly named shoe_query) that lives in the Shoes::App object, and so should be accessible anywhere you want it. You can pass into that helper a selector, and it will return a ShoeQuery object containing the elements that match. You can also pass in an array of elements you already have handy, or an existing element, and it will also return a ShoeQuery object containing those elements. This form should be familiar for those who've used jQuery.

Right now, the things it lets you do are pretty limited, though a lot of the functionality jQuery specially provides already exists in Ruby. The one big feature is the ability to find elements by type, including css-like hierarchy. You can do this either by invoking shoe_query directly, or calling find on an existing shoe_query object (to search within its children). For example, given the demo app:


load 'shoe_query.rb'
Shoes.app do
app = Shoes.app do
para "foo"
f = flow do
stack do
para "bar"
para 'blah'
end
end
b = button "click me to change all paragraphs"
b.click do
shoe_query('para').each do |p|
p.text = "all ps"
end
end
b2 = button "click me to just change the paragraphs inside the flow"
b2.click do
shoe_query('flow').find('para').each do |p|
p.text = "flow ps"
end
end
b3 = button "click me to change the button inside the stack"
b3.click do
shoe_query('stack para').each do |p|
p.text = "stack p"
end
end

end


In this case, the first button modifies all three paragraph elements, while the latter two use two different mechanisms to scope their changes to within the flow and within the stack respectively

As I play with this more, I'll be extending it to include more functionality. Let me know if there's anything you want!

You can get ShoeQuery at github at http://github.com/kball/shoequery/tree/master

Friday, January 23, 2009

Shoes Class Hierarchy Redux: Introspection

After writing up the Shoes class hierarchy, someone pointed out that this is already included in the Shoes manual (and available online here. I took a look, and found some disagreements between that class hierarchy and the one I had come to. In particular, large numbers of classes are listed a being subclasses of Shoes::Basic, including some like EditBox and EditLine that are very definitely subclasses of Shoes::Native.

My first thought was that the manual must be just out of date, but upon looking into the source for the manual (located in the shoes source at lib/shoes/help.rb, as well as static/manual.txt), I discovered that the class hierarchy was actually being generated dynamically by introspecting the Shoes classes in the following method:


def class_tree
tree = {}
Shoes.constants.each do |c|
k = Shoes.const_get(c)
next unless k.respond_to? :superclass

c = "Shoes::#{c}"
if k.superclass == Object
tree[c] ||= []
else
k.ancestors[1..-1].each do |sk|
break if [Object, Kernel].include? sk
(tree[sk.name] ||= []) << c
c = sk.name
end
end
end
tree
end


This code takes the constants defined in Shoes, looks for those that have superclasses, and pulls out their ancestors up until Object. Why, then, if the manual is being generated dynamically, does it miss the fact that Shoes::EditLine, Shoes::EditBox, and a host of others inherit from Shoes::Native?

To debug this, I took a look at the ancestors tree of Shoes::EditBox using the shoes preview app I wrote about here, entering


Shoes.debug Shoes::EditBox.ancestors.inspect


and clicking 'Run Without App'. In the error message text box, the class hierarchy of Shoes::EditBox appeared:


[Shoes::EditBox, Shoes::Basic, Shoes::Native, Object, FileUtils, FileUtils::StreamUtils_, Kernel]


Shoes::Basic is definitely the first ancestor... but in the declaration of the EditBox class, Shoes::Native was clearly the ancestor:

(From shoes/ruby.c line 4965)

cEditBox = rb_define_class_under(cShoes, "EditBox", cNative)


What's going on? The moment of inspiration came when I looked at the definition of Shoes::Basic in lib/shoes.rb. Basic is defined as a module within the Shoes class, and then included on a large list of classes. What I'd forgotten was the way that Modules exist in the Ruby inheritance chain. When a module is included, it creates a pseudo-class known as an Iclass that sits directly above the including class in the inheritance chain, and points to the module's methods. Thus by including a module, you are changing around the ancestors of your class. A good reference can be found here, and a quick quiz to test your knowledge here.

Including modules in the display of the hierarchy might be desirable, but I'm not sure at all how to do it. By doing so, instead of having a nice tree form, suddenly we have a DAG,
which is a much more complex structure to display. Both the introspection code and display code currently expect a tree, so this is the source of the errors/lack of completeness in the current manual.

Its not clear how useful having the modules displayed in the hierarchy is, either. The Shoes::Basic module doesn't do very much, its much more useful to know which classes are descended from the Shoes::Native class.

So the simple fix, to change the manual to showing what you might expect, is to add a single line to the loop over ancestors, skipping modules.


k.ancestors[1..-1].each do |sk|
break if [Object, Kernel].include? sk
+ next unless sk.is_a? Class #don't show mixins
(tree[sk.name] ||= []) << c
c = sk.name
end


Now the introspected class hierarcy looks exactly like the hierarchy I constructed by hand. I've pushed the change to my fork of shoes on Github. Dunno when/if they'll get merged.

If someone wants to do the more complex fix of changing the structure and display to be a DAG, go for it!

P.S.

If anyone knows a way to get syntax highlighting for ruby code snippets on blogger, please let me know! Thanks!

Tuesday, January 20, 2009

Leaning Into Distractibility

Some days, I'm able to focus for hours without distraction, getting my head completely into the problem I'm working on, and nothing short of the building collapsing will pull me out of it.

Other days, the slightest passing thought or noise distracts me, and I'm constantly checking my email, opening news sites or blogs in new tabs, and getting up to get snacks or drinks.

Today was one of those distractible days. After watching the inauguration in the morning, my mind was abuzz with thoughts about politics, the economy, the future... pretty much anything but work.

I've tried a few mechanisms for dealing with days like this, before finally landing on one that seems to work and results in me still getting things done. I've tried to power through it, and work on exactly what I otherwise would have worked on, but distractions pop me out of my mental constructions, and I have difficulty solving big problems. I've tried leaving work for some time to allow myself to be distracted, but this almost never results in a quick return to productivity.

The final approach, which I used today, is to take advantage of the distractibility to deal with all of the small niggling tasks that have been building up over time. Tiny and annoying tasks lend themselves to distraction regardless of mood. There is a natural breath after the completion of any task, so even when feeling focused, a series of small tasks lends itself to more interruption and wasted time than a single larger task. When I'm in a distractible mood, I'm going to be wasting that time anyway, so its an ideal time to get rid of these annoyances without detracting from what I could be getting done.

So instead of making progress on my larger tasks, today I spent my time on a myriad of small tasks. I investigated a number of reports from our support team, fixed a few bugs I found with that, refactored some controller logic for our Birthday Cause feature to make it easier to reorder pages in various flows, merged in a lingering branch of cleanup from our last fixit day, and made a number of other small tweaks, fixes, etc.

None of these was very big, none of them very interesting, but all needed to get done at some point. By leaning into my distractibility instead of fighting with it, instead of a wasted day I'm going home with a list of things I no longer need to worry about.

Cross-posted from my company's engineering blog: code.causes.com

Saturday, January 17, 2009

Exploring the Shoes class hierarchy

I've spent a lot of time this week attempting to get to know the Shoes ruby GUI kit better. Shoes is an open source project, and one that is pretty early in its evolution.

This has a couple of implications:

  1. Its very raw. It doesn't take too much tinkering to find something thats broken.

  2. It is incomplete. Shoes has a few fundamental abstractions that make basic layout straightforward, and generally makes simple things simple. However, if you try to do something that _why hasn't tried to do yet, it probably won't work.

  3. You can open it up, learn how it works, and fix things!



I've spent most of my train/commute time (3 hours a day) this week digging into the source, fixing minor bugs, and trying to understand how it all works. While Shoes is a ruby toolkit, most of it is written in C. From what I've been able to determine, there are essentially three layers.

The uppermost layer is the set of Ruby classes and their methods, most defined in C and then exposed to Ruby. These live in lib/shoes.rb, the various files in lib/shoes, shoes/ruby.[ch], and shoes/canvas.[ch].

Below that there is a set of abstract windowing code. This defines the way that Shoes layouts occur, how the different objects relate to each other within the visible canvas, etc. This is located primarily in shoes/app.[ch] and shoes/world.[ch]. Also living in this middle layer are things like image handling, http handling, and special effects.

Finally, the bottom layer is the interface to the native graphics libraries... a gtk interface, a windows interface, and an interface to Cocoa for OS X. These are located in shoes/native.h and the shoes/native directory. These are typically called into from the middle layer, and issue event-related callbacks back up into the middle layer.

As I learn more about Shoes, I hope to understand and write about all of these pieces, but for now I'm focusing most on learning about the interface Shoes exposes to ruby. This allows me to better make sense of what works and what doesn't, and gain an intuition for how things should work in Shoes programs. Since a lot of the code is written in C, I've spent some time figuring out just the Ruby class hierarchy.

Here's the basic hierarchy... I haven't included anything about what methods are defined on what classes here, but I've put my notes at http://drop.io/shoesclasshierarchy if you want to look at them. I'll probably update them as I do more learning.


class Window; end
class Mouse; end
class Canvas; end
class Shoes < Canvas
# Canvas-like things
class App < ::Shoes; end
class Flow < ::Shoes; end
class Stack < ::Shoes; end
class Mask < ::Shoes; end
class Widget < ::Shoes; end

# Standalones with no children
class Shape; end
class Effect; end
class Video; end

# Patterns
class Pattern; end
class Background < Pattern; end
class Border < Pattern; end

# TextBlocks
class TextBlock; end
class Para < TextBlock; end
class Banner < TextBlock; end
class Title < TextBlock; end
class Subtitle < TextBlock; end
class Tagline < TextBlock; end
class Caption < TextBlock; end
class Inscription< TextBlock; end

# Text
class Text; end
class Code < Text; end
class Del < Text; end
class Em < Text; end
class Ins < Text; end
class Span < Text; end
class Strong < Text; end
class Sup < Text; end
class Sub < Text; end
class Link < Text; end
class LinkHover < Text; end

# Natives
class Native; end
class Button < Native; end
class EditLine < Native; end
class EditBox < Native; end
class ListBox < Native; end
class Progress < Native; end
class Check < Native; end
class Radio < Native; end

# Timing related stuff
class TimerBase; end
class Animation < TimerBase; end
class Every < TimerBase; end
class Timer < TimerBase; end

class Color; end

class Download
class Response; end
end

# Errors
class InvalidModeError < StandardError; end
class NotImplementedError < StandardError; end
class VideoError < StandardError; end
end


So at least now I know that if I've figured out something that works pretty well flows, it should work for stacks or the entire app as well. Similarly if I'm comfortable working with para, its likely similar techniques will work for banners, titles, subtitles, captions etc.

Its a work in progress; let me know if I got anything wrong, or if you want to know more about the methods available for each class.

Sunday, January 11, 2009

Running with shoes

I've been playing off and on with Shoes for the last couple of weeks. Shoes is a simple ruby GUI toolkit designed for beginners. It seems like a really cool way to do the GUI aspects of simple desktop applications, designed to reduce the barriers to entry.

Instead of the intimidating scope of something like learning the GTK API, with Shoes you only need to learn a few core abstractions, and you're off and running with simple and beautiful code.

Want to add a button? Its as simple as


button "My Button"


To add a handler on that button?


b = button "My Button"
b.click do
alert "You clicked my button!"
end



I'm pretty excited about playing with this. Unfortunately, however, the framework is very young and still pretty buggy. Documentation is reasonably good, but definitely incomplete. I'm trying to get a development environment together so I can debug some of the problems in the framework that I've run into, but so far have been unsuccessful at building a working version of Shoes; I get a mostly functioning version, but the text is showing up as boxes. I think I'm getting something wrong in the dependencies... I dunno. I've got a question in to the mailing list about this, so we'll see what happens.

In the meantime, I've built a little tool to make my turnaround time for testing how shoes code will look a bit faster. Shoes Preview lets you enter code & see what it will look like all without restarting Shoes. Its still pretty clunky, but already speeding me up from the modify/save/reopen cycle that I had been using. If you try it out, feel free to send me patches or suggestions! Happy hacking!

Sunday, January 4, 2009

Camping

I started playing with Camping yesterday. Camping is ruby web microframework with the explicit goal of taking less than 4k of space. This implies a sparse, simple interface, and for those (like me) who are fitting their web apps into a 256M slice at slicehost, makes for much less memory usage than a rails app, or even a merb app. The idea is that for a simple application, rails is overkill. I'm thinking of it as a way to build json-accessible REST microapps.

I really like the simplicity of routes being defined with a regular expression right at the controller definition.


module Hello::Controllers
class Index < R '/', '/snips'
def get
@snippets = Snippet.find :all
render :index
end
end
end


That said, it took me more code than I would have liked to get a CRUD interface for a simple model. Not even looking at the views, here is the controller code I ended up with:


module Hello::Controllers
class Index < R '/', '/snips'
def get
@snippets = Snippet.find :all
render :index
end
end
class New < R '/snips/new'
def get
@snippet = Snippet.new
render :new
end
def post
snip = Snippet.create(:title => input.title,
:body => input.body)
redirect Show, snip.id
end
end
class Show < R '/snips/(\d+)'
def get(id)
@snippet = Snippet.find(id)
render :show
end
end
class Edit < R '/snips/edit/(\d+)'
def get(id)
@snippet = Snippet.find(id)
render :edit
end
def post(id)
Snippet.find(id).update_attributes(:title => input.title,
:body => input.body)
redirect Show, id
end
end
end




I'd like to make this a little tighter, and make it a little more purely RESTful (especially for my idea of using these as REST-based microapps), but I'm not sure the right way to do that yet. Camping doesn't inherently have anything like the rails _method hack for the missing put/delete http verbs, and the only thing googling has been able to turn up is a plugin that hasn't been touched in over a year called Sleeping Bag. I'll take a look at that and see how it goes.