Summarized using AI

Pure Ruby GUI

Robert C. Martin and Micah Martin • September 29, 2011 • New Orleans, Louisiana • Talk

The video titled "Pure Ruby GUI" features a talk by Bob and Micah Martin at RubyConf 2011, where they discuss their creation of a pure Ruby GUI tool that monitors their website cleancoders.com. The presentation begins with Micah explaining the context of the talk, noting that while his father Bob (known as Uncle Bob) is in Norway, he is still an integral part of the discussion through pre-recorded clips. The key focus of their talk is to detail the development of a desktop application that visualizes data from their website about usage and profits from video sales.

Key Points Discussed:

  • Project Background: Micah describes how they initially launched cleancoders.com to share Bob's programming insights via videos. The website began to grow in traffic and profits, prompting the need for better analytics on viewership and sales.
  • Challenge of Data Representation: They faced difficulties in interpreting the available data from PayPal, Google App Engine, and their content management system. Micah expressed the need for a graphical tool for analytics rather than simple data queries.
  • Use of Frameworks: After some discussion, Micah debates whether to build a Rails app or a more lightweight solution. He mentions that Rails is complex and heavy for their needs and concludes it's better to approach the design without being bound to a specific framework.
  • Adopting Limelight: They ultimately decided to use Limelight, a Ruby GUI framework, to avoid the complexities of HTML, CSS, and JavaScript. Limelight allows developers to create applications purely in Ruby, which suited their requirements better.
  • User Interface Design: Micah explains the architecture of their application, which includes scenes, props, styles, and actors (players), connecting these elements back to their underlying business logic.
  • Results: The final application allows them to quickly generate and view usage graphs, significantly improving their analytical capabilities. The discussion emphasizes the idea that thinking about applications independently from frameworks leads to more flexibility and ease of development.

Conclusions and Takeaways:

  • The talk underscores the value of separating business logic from specific technologies or frameworks, allowing developers to adapt their tools as needed without being 'shackled' to a particular solution.
  • Limelight offered a clean way to create a GUI for their application while keeping the code base simple and manageable. The flexibility in design allows potential future extensions, such as transitioning to web applications, without overhauling existing logic.

As a result, the presentation effectively showcases the combination of creativity and technical acumen required to build efficient tools for business needs while maintaining a humorous and engaging approach throughout the talk.

Pure Ruby GUI
Robert C. Martin and Micah Martin • New Orleans, Louisiana • Talk

Date: September 29, 2011
Published: December 12, 2011
Announced: unknown

Father-son-team Bob and Micah Martin open the hood on a pure ruby GUI tool they built to monitor their website, cleancoders.com. During this whimsical tour Bob and Micah will reveal how they made use of Limelight, along with a simple web service layer, to build a desktop GUI that provides vivid realtime information on usage of their site.

RubyConf 2011

00:00:17.039 so I am uh I'm Michael Martin and this is talk by me and uh my father who you
00:00:22.480 may know as Uncle Bob Martin um yeah he is my dad and and he
00:00:28.160 goes by Uncle Bob and Dr Nick pointed out that that logically makes me cousin
00:00:33.559 Micah uh you may call me cousin Micah but I may not respond when you do
00:00:41.280 that uh and uh I'm up here and so the logical question in your mind right now
00:00:46.640 where is Uncle Bob he's right there no actually he's he's in Norway
00:00:53.960 and I feel really bad that he's not there and he feels really bad that that he's not here I feel bad he's not here
00:00:59.519 he feels that he's not here and so I want to give you some explanation when we originally proposed this talk uh we
00:01:05.040 were both free for for this week here in Rubicon but by the time our talk was accepted we were like Yay but he looked
00:01:12.320 in his calendar and he found out ah I'm going to be in Norway so we uh we talked about it and what we thought well we
00:01:18.960 should probably just cancel or maybe what we could do is is do something a little bit clever and Pitch it to the uh
00:01:25.600 rubikon organizers and so we did and we got no response which which I interpreted as go for
00:01:35.200 it yeah so uh so this is going to be a little bit of an experimental style talk
00:01:40.720 um we'll see how it goes there's some audio here so we've got sound hooked into the computer and Uncle Bob is
00:01:47.079 actually in this talk in a form that you have probably never seen him uh so it
00:01:52.759 should be fun uh I'm going to tell you a little bit of a story um and it starts with a
00:02:00.680 conversation my father and I had about this website about six months ago we we built
00:02:06.640 this website see my dad he's uh if you've ever heard him talk he's got a lot of opinions and uh he wanted to
00:02:13.560 express those opinions to more people and so he he he thought well I'll just record myself giving my opinions and uh
00:02:21.040 people can watch these videos and uh he talked to the peep code peep uh yeah peep code guys and the prag
00:02:28.640 prags and in the end he he realized that he wanted his own delivery mechanism so he talked to me and we decided that we
00:02:35.000 would build a website we called it clean coders and and his videos are up on this website uh available for people to
00:02:41.480 purchase and you can hear his opinions um and so we're having a conversation and and I told them you
00:02:48.519 know things are looking good we're getting a lot of viewers and uh we're making some money and and it's looking
00:02:56.720 good and he had a question by the way
00:03:02.000 um someone had a sticker on the computer of a funny looking cat and I asked him what what is that is it ceiling cat well
00:03:08.560 who the heck is ceiling cat and they I haven't seen that so they pointed
00:03:16.440 me to the to the lcat Bible has anyone seen the lcat Bible not enough of you
00:03:22.280 you should go check it out after this talk uh it's hysterical and uh Insidious
00:03:28.360 and and it the the whole law speak creeped into my daily life and into
00:03:34.000 these slides so well there it is so I was telling him all this and he
00:03:41.080 said great Scott do you know how much money we've
00:03:54.319 identify the movie in the background anyone
00:03:59.920 it is not the wizard of us anyone seen Forbidden
00:04:05.319 Planet yeah classic sci-fi movie who who's the lead actor of Forbidden
00:04:11.439 Planet Leslie neelen yeah and he's not at all funny in this movie which which
00:04:16.799 is awkward anyway I did know how much money we would made because we're using PayPal
00:04:22.560 and I could just go to our PayPal account and see the money that was in there got to cover it up because you you really don't want to
00:04:28.600 know uh so I could tell them how much money we made but I couldn't tell them you know more than that I couldn't tell
00:04:34.840 them how much each episode was doing and uh I have an image to show you I see I
00:04:41.160 Googled for PayPal and uh if you're from PayPal or if you like PayPal I suggest
00:04:47.759 you close your eyes right now okay I found this
00:04:52.880 image and after using PayPal for six months um I don't want to be negative so I
00:04:59.240 don't want to say this expresses my opinion but uh on the positive note I've heard great things about brain so I'm
00:05:09.880 can anyway so we we had a growing list of videos and we wanted to know more
00:05:16.320 about the usage of the website we wanted to know how well each video was doing wanted to know how many each we
00:05:22.919 sold how many users we have how many times they watch videos and what kind of licenses they buy and so my dad oh yeah
00:05:30.759 yeah so we wanted all that information and we had the data U all the data was up there see we we built the app in
00:05:36.680 Google app engines and uh it's it's in written enclosure which is is another
00:05:41.759 talk not for this conference um but we we've recorded all the purchases that people made all the
00:05:46.919 viewers we have all the downloads of the videos uh every time someone views it we record it all the different licenses we
00:05:53.039 have all the information it's there but it's just not in a digestible format and
00:06:00.039 so so I think what we need is some kind of tool some graphical tool that uh
00:06:06.639 tracks the the uh people who buy the episodes something that'll put up graphs
00:06:12.800 that show us uh how many people bought the episodes and how much money we made
00:06:18.039 from the episodes and and all the trends you know interesting Trends stuff like
00:06:25.840 that that doesn't seem real hard does it I mean you could something up real quick in rails couldn't
00:06:36.960 you yeah that's embarrassing
00:06:43.199 um so what was shocking there besides a shower
00:06:48.560 scene what was shocking is he said just whip up a rail app I was like rails
00:06:54.039 really to do this I mean I spent all this time building a closure app and now you want me to build a rails app to to
00:06:59.759 to Crunch all that data and you know rails typically you has this relational database but how
00:07:05.960 does app engine fit in there and HTML CSS JavaScript I mean I'm not a big fan
00:07:11.759 of those Technologies do we really have to go there and do that and in in this rail structure where does the clean
00:07:18.080 coders piece of logic fit in there how I mean how does it how does it interact with all this other
00:07:25.199 stuff and so oh before we go there and so uh yeah so you know I I considered
00:07:32.400 this and I also considered something that my father said at a talk he gave in Ohio
00:07:39.000 recently consider this floor plan it shows you the architecture of a building
00:07:45.159 what kind of building do you think it is welcome I'm glad you made it today
00:07:52.400 I'd like you to notice the spectacular entryway to this wonderful house a grand
00:07:58.400 foyer over here we have a formal living room isn't it beautiful this way we have a
00:08:06.960 formal dining room which comfortably seats 12 16 even sister come on over
00:08:13.759 this way here we have a gourmet kitchen with
00:08:19.319 a center Island who wouldn't love to cook in there we have an attached dinette for
00:08:27.080 your morning book club and coffee with all your girlfriends come on over here
00:08:32.200 this is my favorite room it's so cozy and warm the family
00:08:37.479 room wonderful space for all of your
00:08:43.320 entertaining it's a house I mean these plans scream house the architecture of
00:08:50.160 this building leaves no doubt about what it's intended for it's a
00:08:57.320 house so if I showed you the architecture of a library you'd likely
00:09:02.560 see a grand front entrance a hallway where you could put a checkout Clerk's
00:09:08.200 desk space for many reading tables perhaps little private study rooms and
00:09:14.720 gallery after Gallery capable of holding vast quantities of
00:09:19.760 books a layout like that it would just scream library at
00:09:25.880 you and that's what good architecture should do good architecture should virtually shout out the use cases
00:09:34.120 architecture is all about use cases you shouldn't think of rails as an
00:09:40.720 architecture rails is a suite of tools you shouldn't think of spring and MySQL
00:09:47.560 and hibernate as making up an architecture they're just a bunch of
00:09:53.519 tools so the architecture of a library or a house or a restaurant is is not
00:09:59.800 made up of hammers and saws and 2x4s and nails and the architecture of a web
00:10:07.120 accounting system should not shout out rails or spring hibernate my SQL just
00:10:14.279 because it happens to be delivered on the web the architecture of an accounting
00:10:20.200 system should scream accounting at you systems architectures are about their
00:10:26.440 use cases they're not about the Frameworks that happen to lie underneath the
00:10:33.079 scenes so that's that's the EOB that I know not the guy who said just whip up a rails app uh and so I was considering
00:10:39.600 this and and also what he said about rails and rails doesn't scream Analytics tool and so I thought about how we could
00:10:47.600 build this at the core of the system that I was building was this analytics you know taking a bunch of data uh
00:10:54.160 crunching it and turning it into a format that we can digest uh displaying graphs and so you know this is what I
00:11:00.639 had in mind I wanted to build this thing and the data you know maybe it's a
00:11:05.920 relational database or maybe we just pull it out of Google app engine um we
00:11:11.519 we hadn't figured that out exactly quite yet so you know I have this in a dotted line because it's kind of an abstraction
00:11:17.000 right it doesn't really affect the way that I build this part of the system and the the
00:11:22.360 UI you know it could be rails but it might not have to be rails right so I have that as an abstraction and I can
00:11:28.519 build this entire part of the application without worrying about those other two layers and so I approached my
00:11:34.399 dad about this oh CPE you're not going to get all soft to our craftsmanship he on me are you I mean come on this is
00:11:40.560 just a dumb little rails app we don't need to go through the whole architecture thing here just a nice
00:11:47.000 little rails app I mean rails is perfect for this right it's got to be a web app who knows where I'm going to be in the
00:11:52.399 world I fly everywhere I just want to pull these graphs up on my screen really quick I don't need a whole great big
00:11:59.560 long architecture deal so stop being so dog on religious and just whip up the
00:12:05.920 rails app okay would you want to work for that
00:12:14.399 guy all right so that's that's Bizarro dad again and so at this point I go off
00:12:19.600 and I start working on this not taking him too seriously what he just said there and I looked again at this this
00:12:25.600 design that I had drawn before and I started working on this middle layer because that's where the Core Business
00:12:32.000 logic was and so I thought you know this is just a bunch of Ruby code that is is taking data and crunching it down it
00:12:38.320 really doesn't have any external dependencies yet so why don't I just take it and put it into a gem and so
00:12:44.680 that's what I did I wrote the code I wrote a gem spec push it up on GitHub I have a gem that has all of our Core
00:12:49.800 Business logic Now by itself it wasn't terribly useful because I didn't have any data
00:12:55.959 for it um and I could have made up some data and actually did in order to test
00:13:01.440 this but uh to to demonstrate it to my dad I had to actually do some real data and so I started working on this part of
00:13:07.920 the system here and I considered using a a relational database but that would
00:13:13.800 mean I'd have to take all the data from App engine and somehow get it into a relational database and uh it just
00:13:19.800 seemed easier you know app engine provides an API to get all the data so what I did is I built another gem which
00:13:24.959 just goes off to Google app engine pull out the data and it returns a list of hashes so all my data is just a bunch of
00:13:31.600 hashes so I can do whatever I want with it and uh you know I I stopped here but
00:13:38.120 I thought you know need be what I can do is I can add a rails front end here and then we'll have the full system
00:13:44.800 that my dad was asking for but before I went there I figured there's an easier way to do this I can demonstrate the
00:13:50.120 functionality without building the rails app if I just put uh like a command line
00:13:55.680 interface on top of it uh that's a lot simpler to do so that's what I did and
00:14:01.199 it looked a little bit something like this uh I built a command called clean
00:14:06.800 tracker and you can see the the options here uh it's got some command line
00:14:12.279 options some switches and then a whole list of charts that it will generate and so then uh on the bottom here I'm I'm
00:14:18.959 actually executing the command I have to give it my username because the API for app engine requires some
00:14:25.320 credentials um and then I say uh which chart I want to load and there's A- C switch
00:14:32.519 which what it does is it loads up a previously casted set of data because the internet in this hotel is not very
00:14:38.880 fast and so you can see it's going off it's it's getting the data it's crunching it generates a graph and it
00:14:44.279 pops it up in preview just a little PDF so there we go there's the app full
00:14:50.680 stack fully functional it's got my core business logic it's got that gem that pulls in the data and it's got a text UI
00:14:57.240 so I'm pretty pleased with this so I go go to my dad and say pretty cool
00:15:02.959 eh oh come on you mean couldn't you have done this simpler I mean there's all
00:15:08.000 these commands and command switches and every time I type one of these commands it takes forever to load I mean I
00:15:14.320 thought I thought we were doing a rails app I thought isn't that what I told you
00:15:19.880 to do a rails app why does it have to be so complicated all the time why couldn't this have just been a simple little
00:15:26.120 rails app yeah so I went away from that
00:15:32.519 conversation and uh you know I kind of put my head down and thought all right well I can add rails here to complete
00:15:40.680 the application and give a nice gooey but then it occurred to me does it have to be a rails app I mean we could use
00:15:46.720 Sinatra but does it have to be a web app at all yeah you know I was thinking about
00:15:53.680 that I mean rails is a great framework for web applications that use Rel
00:15:59.440 databases but this application really isn't a web app is it I mean what we really want is just to be able to pull
00:16:06.240 it up on our laptop and look at the graphs every once in a while and that means you know all we need to do is kind
00:16:12.120 of suck the data out of Google app engine we don't need a relational database to store that uh so active
00:16:19.040 record really wouldn't be much help would it I mean really no point in using rails for this is
00:16:24.920 there besides I mean web apps are really complicated Affairs and just think of
00:16:30.440 the number of languages you've got to know to put up a dumb web page you got to know HTML and CSS and JavaScript and
00:16:39.759 haml and yaml and Jason and gravich and krich and Frack knows what else just too
00:16:47.319 much right what we really need here is some simple gooey that you could put
00:16:53.800 together in a nice language like Ruby I could agree more and that sounds
00:16:59.880 much more fun to build if I could just use Ruby and so I went off and I
00:17:04.959 searched for a ruby Rich client gooey framework and I found this tool called Limelight and I looked into a little bit
00:17:11.640 more and uh it's it's got some some interesting aspects to it but what I
00:17:17.199 likeed most is that there's no HTML there's no CSS and there's no JavaScript
00:17:22.799 it's all ruby and that was attractive to me I could just write Ruby code and not worry about all that other stuff
00:17:29.480 and so here's my design that I had instead of putting rails up there what I'm going to do is I'm going to take Limelight and put a limelight layer on
00:17:35.840 top to complete my app and that's exactly what I did and this is what it looks like so Limelight once you build
00:17:42.880 it you can package it all up into this nice little bundle here you double click it it loads Limelight and uh Limelight
00:17:49.679 in turn loads your application which you see here the first scene here is a a login
00:17:55.919 scene so we can get the credentials which actually download the data
00:18:02.280 and then it gives me an option of whether I want to pull down all the data or just use the cached set of data and
00:18:08.080 I'm going to use a cast again because the hotel internet is really slow so it loads all the data and then
00:18:16.000 it starts crunching away to generate the first graph okay so now we see a nice graph
00:18:23.559 here showing the accumulation of viewers we've had over the last six months and this is interesting data we found this
00:18:29.320 really really helpful and on the left here is a list of all the graphs that we
00:18:35.000 can generate it's the same list that was available with the command line interface but here we can just click on
00:18:40.720 those and uh load up each each graph and we don't have to worry about reloading
00:18:46.679 all the data every
00:18:52.640 time so I mean we don't need to go into the details of what all of these uh graphs are showing but it's really
00:18:58.320 useful in information I mean it's stuff that we couldn't have figured out just by looking doing queries on the data I
00:19:03.520 mean this is this is very helpful for what we're going to do in the future for the website and it's much easier to use
00:19:10.080 right just going down the list here and clicking those buttons to generate new graphs is is much easier than the
00:19:15.600 command line interface and uh it's a lot faster as
00:19:21.480 well and I want to talk a little bit about how how we did that uh and in order to do that we have to talk about
00:19:28.280 the limel terminology Limelight uses this metaphor of a
00:19:36.640 theater when you're building a a limelight app you're not it doesn't call
00:19:42.159 it an app it calls it a production like a Broadway production or theater production and that metaphor goes all
00:19:47.720 the way through so all the aspects of your app use terms from this metaphor
00:19:53.679 and at the very bottom we have what are called props right if you if you think of a a theater the curtains open and on
00:20:00.120 stage you have props might be table chair whatever is appropriate for that particular scene uh props are just the
00:20:06.400 building blocks of a scene and a scene is just a prop that contains other
00:20:12.960 props then there are Styles which uh specify the appearance of all the props
00:20:19.440 we have players which uh Define the behavior of all of the props the stage
00:20:25.159 is just a container for a scene and the production is just a collection of
00:20:31.320 scenes that's it these components Define your app and so if we take a look at the
00:20:37.679 first scene that we have the login scene what we can do is break it down into the
00:20:43.720 fundamental components and we can see that we have like a header up here this whole section is a header we have a
00:20:50.039 little divider here uh and then this whole section of the scene is a login pane with a paragraph and login
00:20:57.360 parameters here and buttons and so on and these are all names that I just made up they're totally arbitrary
00:21:04.320 what we can do is we can take that and we can build some code to represent that scene and this is the code that that
00:21:11.120 builds that scene these are the props so you can see we have a header up
00:21:16.760 here and then there's our divider our login pane is this big block here which contains the the welcome message and the
00:21:24.360 login parameters does it look like HTML
00:21:30.120 it does a bit and that's that's its purpose right it's to define the structure of your scene but it's not HTML it's just Ruby
00:21:37.960 code and when we get to the Styles right we can we can talk about uh the login
00:21:43.440 label which is this guy right here right it's uh it's got this gray
00:21:49.279 color it's it's got a f size of 20 Hela etc etc uh and this probably looks a lot
00:21:55.320 like CSS but it's not it's just Ruby code so you can put any other Ruby code you want in this file you can introduce
00:22:01.840 variables or or write some algorithms to generate the Styles whatever you like it's all ruby
00:22:07.440 code and then the interesting stuff how do you interact with the user how do you get the props to actually do cool stuff
00:22:13.039 and that's where players come in players are like the actors of your scene uh kind of uh kind of like JavaScript in a
00:22:20.200 web app now one of the things we want to do is when we click this button we want to actually log in uh so this is called
00:22:28.039 the login button so if I want this button to do something what we do is we create a login button
00:22:33.960 module and that code gets injected into the prop so whenever the mouse is clicked this bit of code is executed and
00:22:42.080 what this does is it finds it finds the prop named username uh pulls out the text stores it
00:22:48.240 into a variable it finds the prop called password field gets the text puts it
00:22:53.320 into a variable and then it tells the director to log in using those parameters
00:23:00.000 um now you should note here that the director is uh is not part of Limelight this is my core business logic layer the
00:23:07.320 director lives in that gem that was sitting in the middle of that design so this is how the UI talks to my core
00:23:14.159 business logic right so that's how we log in now the director has to tell the scene to do
00:23:20.440 stuff like when you click that button and you log in you might not get the right credentials so it has to tell you
00:23:26.480 and so the uh the login scene has a player of its own so all this code gets
00:23:31.880 injected into the scene and we can see that when the scene originally opens it tells the director
00:23:37.400 hey I'm ready you can use me and then uh if if the login fails for some reason what we can do is we can display a text
00:23:43.919 message um in the error message prop and then we'll set the transparency to zero
00:23:49.240 so you can actually see it and uh we'll tell the producer to open the new scene that loads all the
00:23:55.400 data so that is how the director talks to the scene
00:24:01.919 and then there are stages stages are really simple these are just defining what uh what the window looks like on
00:24:08.919 the screen and you can see that the default Scene It loads is the login scene and then the production this is
00:24:14.880 the the encompassing um model that represents your application there's a few administrative
00:24:21.400 things we have to do when we open the production like add the lib folder to the load path we have to uh I'm using
00:24:27.760 bundler here so we tell bundler to load up all of the gems we do some requires and then when
00:24:34.200 the production is fully loaded we create a client to our data and we create a
00:24:39.320 director which is our middle layer passing in the client and now we're ready to go it's all
00:24:45.520 set so I built this Limelight app and I showed it to my dad it's pretty cool
00:24:52.080 eh now that's what I'm talking about I mean I can just start up this
00:24:57.320 application wait 30 seconds while the data loads and then hop from graph to
00:25:02.559 graph to graph this is really cool so if we ever need to turn this
00:25:09.520 into a web app why we could just bolt a rails front end right on this thing right on top of the analysis gem we've
00:25:17.039 got the best of both worlds you see son I mean it pays to
00:25:24.240 listen to your old man every once in a while doesn't it so I think I'll do a whole
00:25:31.039 cleaners.com episode on this I'll call it episode s use cases high level design
00:25:39.399 and architecture shouldn't take me any more than a couple of
00:25:44.559 weeks so Micah this is great but um there's a few more graphs I need I'm sure you can just whip them up for me
00:25:51.000 really quick yeah my my parents have a thing
00:25:56.080 for chihuahua that's that's like the fourth one that they've had cute dog anyway so uh so he likes
00:26:05.159 this this app and uh and the moral of this story the way I see it is that if
00:26:11.080 you if you think about your app in terms of the framework and build your application into the framework then what
00:26:17.159 you've done is you've bound yourself to that framework uh ball and chain you are Shackled to it and removing your
00:26:22.760 application from the framework is going to be very difficult after that point so what you can do
00:26:29.000 if you want to is to think about your application in isolation independent from all the external dependencies and
00:26:35.559 then you have the option to apply any external dependency you want whether it's app engine or postgress or MySQL or
00:26:42.799 rails or Limelight or whatever else you could you could do two implementations
00:26:48.080 like You' have a postgress and a mySQL database or a limelight and a rails interface if you chose to do so and your
00:26:54.919 core business logic would be unaffected by those changes so that concludes the story um thank you
00:27:02.440 very much for for coming and
00:27:12.559 listening if you're interested in looking at the code it's all available on GitHub and E Light is
00:27:21.960 hiring any questions yeah deoy
00:27:38.279 so if if it's a rails
00:27:46.000 app right so for Limelight the deployment is you you take that that bundle like an
00:27:52.480 LLP file and you can you can make it downloadable people just download it and double click it and it opens
00:27:59.640 it does yeah it's ready to go by itself over
00:28:09.200 here no I have not uh Limelight uses uh J Ruby so it's on
00:28:14.880 Java J Ruby is really great for that over
00:28:25.279 there yeah I did look a lot at SHO new at first um it it wasn't working quite
00:28:31.679 right back when I looked at it and I don't know how it's doing today but I heard that there's other people that picked it up and continued work oh
00:28:36.840 someone back there apparently is working on
00:28:42.559 it thank you yes it
00:28:53.320 is absolutely thank you
00:28:59.240 any more questions okay great oh yeah you got
00:29:06.360 one yes yes and if you check out the code you you will see my tests for the GUI code itself you being being just a a
00:29:13.480 ruby layer it's really easy to test compared to a web
Explore all talks recorded at RubyConf 2011
+55