 Good morning. I hope you guys had a great, yesterday, what was yesterday? I'll do the same thing. My name is Brian Sambolden. I'm from Phoenix, Arizona. I'm actually from Scottsdale. And I'm here to talk about Trellis, which is the product of conference-driven development. Basically, every conference I go, I write a little bit of it, and I release a new version. In Trellis, it's a component-driven web development framework. It's all Ruby. Right now, it runs on Ruby 187, because that's what was running on my Mac when I started doing this. 186 doesn't work just because of how I deal with blocks. In 19, it's still broken in some areas, so I'm fixing that pretty soon. So components on the web. There's three things that I actually was looking for when I wanted to build a framework that was radically different from Rails. And don't get me wrong, I love Rails. I make, basically, a living with Rails. But in the Java world, yeah, that's right. I was a Java developer. I am still a Java developer in the skies. And if they give me enough money for it, I'll still do it. I'm that dirty. So one of the things I wanted is reusable components. And it's one of those things that when I'm doing a Rails application, dealing with partials and the exponential explosion of partials, you strike me crazy. Everything looks great. Fat models, skinny controllers, and then this grace of a view layer. And it always takes me a great deal of refactoring to actually clean the views. So I wanted a way to basically encapsulate view logic and also encapsulate some of the logic that manipulates that view logic. And that is the definition of a component. I also wanted to be able to build components out of components and do the kind of recursive type of development. I wanted events and event handlers. I didn't want to call anything directly. I want things to say, hey, this is what I publish. This is the kind of things that come out of me. And whoever wants to listen to them, go ahead and subscribe to them. Transparent state management. I hate dealing with HTTP. Dealing with HTTP in the Java world, it's always been one of those things that was always in your face, basically with the Java server API. And then I discover Rack on Ruby. And Rack basically makes dealing with HTTP so simple that for me to create an abstraction on top of that, it became cake. So what is Trailers? It's magic like Rails. So there's a lot of DSLs. And I kind of went DSL crazy with this because I was getting into writing DSLs. And I was writing DSLs for pretty much any Java library. I wrote a DSL and JRuby for it just because I could. In metaprogramming, it's kind of like a drug, you know? You get the first hit and then you're hooked and from that point on, I was like, okay, I don't need a DSL for this. Stop now. It is a micro framework or at least it started as a micro framework. In 300 lines of code, I did about 60% of what a Java framework written by a good friend of mine did called Tapestry. And that was kind of one of my main inspirations for this. But the moment I saw that 300 lines of Ruby code could do what, you know, thousands of lines of Java code did, I was like, that's it, I just can't go back now. Unless you give me enough money, we already talked about that. So it's more like camping in Sinatra. It's very Sinatra-like when you look at the code. And actually one of my plans is to get rid of all the plumbing that is unnecessary and write on top of Sinatra pretty soon. Because those guys, I mean, they have a pretty large development team now. And it's, you know, I might as well concentrate on the component features of the framework and not on the underlying plumbing. So just like any rack applications designed for small mounts in, that sounds wrong, in small apps, components. So of course, that's the main goal of the whole thing. It's supposed to be easy to be built. They got to encapsulate the complexity of the application. So when there's something too complex, you move it to a component. Components could be core components from the framework or custom components for your application. And it's NVC all the way. NVC at the application level and NVC at the component level. So here's a quick overview of how things work. You have an application, which is a trellis application, just like a Sinatra application. That has a bunch of pages. The pages have components in them. The components are declared on the template of the page or if there are invisible components in the actual page code. The components emit events. The components consume events. The pages consume events and also dispatches events to the components. The inspiration, pretty much tapestry and web objects were the two big ones to begin with. Then when it came time to implement, I started looking at seaside. Of course, continuations in Ruby still suck, so I couldn't do continuations. So I had to basically do HTTP magic behind the scenes with state management to basically deal with things like that. How to freeze the state of a component, put it in the session or put a token in the session, store the component in the database or in memcache or whatever rack could actually give me to do session management, and then bring it back. Of course, Sinatra, the moment I saw Sinatra, I'm like, wow, I got to do something like that. Camping just because of the size and how easy it was to just get started. Of course, there's some lesser-known frameworks like Iowa and We, which have some really cool features, but again, they're not that well-known. Of course, the big 800-pound gorilla rails, which all the magic of rails, just the first time you saw Active Record, if you came from the Java world, you're like, oh my God, I've been doing hibernate for all these years. I'm going to kill myself. I actually teach a hibernate class, which at the end of the class now I have a slide where I say, well, all those three days of hibernate you can replace with this one slide of Active Record. And they hate me for that. So of course, it's built on rack. I was going to do some nice rack jokes, but I'm going to move on. And let's look at some code. So hello world. Everybody needs to see hello world of any framework. The hello world in our trailers can have a simple RB file, in this case called simplest, in one HTML template. And this is what I have in there. So I have the RB class. And you can see that it has an application. It has a star page. And it has a command at the bottom basically to launch the application standalone. You can deploy them to anything that rack supports. So I deploy them to Heroku. You can use anything that supports rack up to launch an application. You can use to launch the application. This template, it's just an HTML template. Very simple. You can see that there's components in there. The components are those tags that start with trailers. And here's a bigger view of the same application, but all in one file. So I also have inline templates. And I kind of like that when I'm doing developer oriented web applications. But I don't want to be doing anything with an HTML editor. I know what I want. I know the structural semantic markup. I throw it in there and I worry about the CSS and all that stuff later. So in here I have a markup template. And it's a little small, the font, but there's embedded components. And here I have a component called value that returns the value of a property of the page, or an instance variable. And I have a page link which generates an href to basically go to a specific page. So up there I have the application. It has one entry point, the home page. I have one page class that has an instance variable for the current time. So you guys pretty much can figure out what I'm doing with this very simple demo. And I have one page template embedded in the page class. And there's two components that I use right now. So one is the value in the page link. And I can get access to that current time instance variable from within my value component. And there's many ways to get to things. An instance variable is raw just like you do in ERB. And do loops in the templates if you want and all that stuff. But I cannot prefer not to do a lot of scripting in the views. And that's one of the reasons to have components, to basically hide all that nastiness from the views. So let me show you this. To run them, they're just Ruby scripts. So there's a start method there on that last command that I put in the file. And you can just run them. So let me go ahead and show you that application. Oh, and I broke it. Yay. All right, let me move on to the next one. It's always happens. It's beautiful. So how do you navigate from page to page? To navigate from page to page, you basically, when you handle an event, the return value of that event becomes the value of the page you're going to. Each page has to know in advance which pages it can navigate to. So you have to declare them in your page. You can say page home goes to page X and Y. And then from the event handler methods, you can say return, you know, you can return an X or a Y instance that's already available to that page, and that will create the navigation link. And of course, this doesn't make much sense without a example. So here's an example. This is the Hilo application, a very simple game, where you're guessing, basically, the number guessing game. And I'm going to have a page. It's called a star page, a guest page, and a game over page. And most trailers applications are like this, they're little state machines where the nodes are just pages. And the transitions happen via event handling. So I have three HTML pages, and I have the Hilo RB code. The application has the home page, and you can optionally define the pages you're going to navigate to. So here I'm saying that I have the guest page and the game over page as pages available to my application. You can have multiple applications with the pages across different apps. The star page has an onSelect. That onSelect, the convention that I put in there is that everything that starts with on, it's an event handler. So there's going to be a select event created by a component on the page, and the onSelect is going to answer that call. I put the return, I know it's just to make it more clear in terms of explaining what's going on. So I'm going to set a value on the guest page, which is the target of the number to be guest, and then I'm going to navigate to the guest page. Very simple. On the star page, I have the start guesting link. That's what it's going to generate the select event that onSelect is responding to. The default routing URL scheme, it's like this. You have a page.event underscore the source, so where it came from. Then you have optional values, as many query parameters as a URL can handle. Then inside of that, when I go to the guest page, I'm actually running a loop component. So it's another trail is built-in component that basically loops over any set of values. Of course, a loop is something very simple to pull off with just Ruby code, so you could do that too. The loop component is one of the first components that I wrote to see how to handle basically HTML tags produced in Ruby code under the scenes. It creates that link of numbers. When you click on one of those numbers, look at the URL looks like guest.select underscore link, so it's coming from the link component. The event it's select, it's coming from the guest page, and it's passing the value one. Of course, you've got different values for all the 10 digits that you have in there. Then you can make a guest. You can see that the loop generates all the guest links, and you're going to end up with something like this. Let me go ahead and launch this guy. So there's the high-low browser. It's on the wrong side of the moon. If I click on start guessing, you can see that there's a typical number guessing game. I can't really see what I'm doing here because it's too low. Sad things to be proud of. So basically, here's a state machine with the nodes replaced with the actual pages. You can see really what's going on. But again, it's a very simple... If you have something that you have a very well-defined flow, this is a really easy way to basically get that flow ahead of time and then flesh out the nodes. In a Rails application, we kind of go more with the controller. The controller has multiple views, and that sometimes can get out of hand in terms of understanding what the application is doing. Of course, this only scales to a certain size. So that's why I like small applications that are little state machines to be built with this. I want to go and build a CMS using this, which I did, though. But I proved my own point that I started basically getting confused about how the flow of events happened. Not as fast as you would in a Rails application, because if you have a very large Rails app, you have to really start basically whiteboarding what goes where. In this case, this is actually pretty helpful with that type of application. I have also a Hangman application. I'll show you that when running. I'm going to skip the code just so you guys can see what goes on. Similar state machine type of app. Instead of having numbers, I have letters, and I suck at this game since I can only see part of the screen. But you can see that you have a list of words. This is about probably 100 lines of Ruby code. Very simple. And I'll show you the Ruby code for that. So here's the Hangman application. And it has a main application. Notice that I have static resources, and RAC basically gives me all the magic to basically have static resources, have, you know, read, for example, things like a JavaScript file and cache it. There's all kinds of RAC middleware. Yesterday you learned a little bit about RAC. And the number of middlewares available enables you to build a web framework like this. I mean, I built the first version of it on one conference. So it is really amazing a framework to build things like this. Here's the start page where I basically create the list of words from a text file. Then I have an unselect to start the game. I set the target word. On the guest page I have some persistent fields now because you have to remember the guesses that the user has made. This is where the state management comes into play. A page can have persistent fields. A component can have persistent fields. You can also tell the page this persistent field is going to go to the session. This one is going to go to cookies. This one is going to go to the database. This one is going to go to memcache. Decide what to put where. So in most cases you will put something simple like a token, a encrypted token on a cookie and use that to find the chunk of information that might be in memcache or in the database. Other than that, this is just some traditional Ruby code. I'm noticing here that I basically have an array of underscores to show basically the things that haven't been the letters that have not been picked from the word. The game over page of course just has the target which is the target word that we were guessing so I can print them in there and say, hey, you failed to guess this word or yay, you found the word X. And the number of guesses that they had left. So I can tell them, hey, you found the word and you only had two guesses left. All right, let's talk about templates. Templates, I can do XHTML templates or HTML templates or HTML5 templates. And I have a removed component that is nice that came from Tapestry for a designer so they can have a preview of the page aesthetically and that gets removed at runtime. So it's a very simple component but I thought it was a really cool feature that Howard created in that framework. Hamel, so if you like Hamel and SAS, you can use that in line or in templates. And let's talk about components though which is the main feature of Trail is that it should basically drive you towards using components. Components in Rails. There's the sales for stateless components project and there's also Apotomo which is for stateful components. So if you like the concept of basically reusing view logic and some controller logic instead of copying and pasting or doing some weird hierarchy of controllers you can use something like sales or Apotomo. And I don't know why I'm selling the competition here. So here's that loop component that I show you and this is basically the 10-15 lines of Ruby code and you can see in here that basically it's just looping over some values that are available to the context of the page. So I use something called radius to basically do all the templating and all the tags. So that tag, that render do tag it's something that comes out of that radius gem. And other than that basically just each one of these components contributes a little bit of markup to the page. So that's a stateless component. Here's another one, a custom one. In this case I created a component that basically goes to Flickr, uses the interestingness API and grabs a bunch of random pictures. Which when I show you the demo something inappropriate might show up I apologize in advance or not. And you can see when I put one of these components in there I can tell it I want two pictures from the API or I want three pictures from the API. And let me show you that code. So there's the FlickrRB project and in here I have my custom component. It's the Flickr interestingness. It's a trellis component. This is basically just the rendering of the tag. And in here of course I'm not caching anything. I mean I'm doing this brute force. I'm hitting the service which is an XML RPC service using the XML RPC client. And I'm calling that method the Flickr interestingness getList then I'm using Nokogiri to parse all that stuff. And then I create I do some expat to basically grab what I need the URLs for the pictures. And then I dump those using builder onto the markup of the component. So inside of the application now I have one embedded template in here and I can now use my components like this. So I have there one component and then I can have another component some other place with some parameters. So this is the beauty of this. You can have every time that you see a pattern in your views that repeats with some changes in, you know, cardinality or something like that a component might be an appropriate abstraction for that. So let me go ahead and launch this guy. I believe I have the little hyperlink there. And let me go and make sure that it's running. How long do you hate when you lose your window? Okay. So I'm going to quickly okay now it's running on 306. Let's go back to the browser 306. And of course assuming that the web is working for me I should be able to now see the component. And you can see the moment I refresh the page of course it's going to go and make that call again. Now I could do some magic behind the scenes. I can say, hey, cache some of these URLs in the background the component itself could cache them that's a class level type of caching. So the component could say, oh, start caching some of these URLs and then I can do randomizing from those URLs that I cached rather than do the call again. So you have those choices. That's some of the things that I built into the framework. So that is a stateless component, but really a stateful component it's where you're going to get your money's worth. And here's an example of a counter component. This is my contribution to the bounty. So I have a component called a counter and that counter has a state. It's just a count. In a page I'm going to put a bunch of those named counter 1, counter 2 and counter 3 and when I call the events on that component the page will intercept the event and then pass it to the component instance. And, of course, refresh the page. Right now, of course, I'm doing everything on a page refresh. I'm doing non-AJAX events. I also have AJAX events that can do some pretty cool stuff. And I started with UE and I kind of get disappointed with the framework so I'm rewriting everything with jQuery now so it's kind of in a state of flux. And I also have each component has a reset method that basically sets the count back to zero. And I have a reset event handler on the page that then will call the instances of reset on all the components. I have two ways to communicate. I have the indirect event-based communication so when an event happens on the component the page graphs it and then gives it to the right component instance and then I have a reset link that has an event handler on the page itself that actually then manipulates the component instances directly. So for each component that I place on the page I have an instance variable available to the page. I can show you what that looks like and it's better if I just show you the actual code running first. And I believe I have this one running. Let's see. Okay. So here's my component and you can see that I can increment I have three instances of them I can increment them all they're all keeping state for this particular demo I'm keeping the state in a cookie. This is just my choice for this demo. And this is a page event so when I click on that reset counters I'm resetting all the counters by manipulating the instances directly. So let me show you the code now and I think we can then go into questions. So I have stateful counters it's the code for that and here is the code for the component it's called counter it's a stateful component I was playing with my DSL-ish language in here I think this is a goofy way I was doing an acts as stateful type of approach but I think I'm just going to have a component that's a stateful one and just inherit from that. I went too crazy with this syntactic sugar right here. There's a tag name for that so there's going to be a counter tag that you put on the page I have a field call value which is persistent and again you can see here that I'm playing with my DSL still everything is still in flux in terms of the final you know lingo for the framework. I initialized I call a reset method to set the value back to zero and here's what I'm actually rendering the component and I'm rendering an href for adding and subtracting and then again I'm using builder to basically put an h1 with the value and two hrefs for adding and subtracting that's it. I have an on add so this component generates events that the component itself responds to. So when I click one of those links it's going to generate an on add event that on add is going to respond to and increment the internal value. So this is through OO construct encapsulation. The page doesn't really have access to that value. Well in Ruby we have access to anything but I'm not exposing that value directly to the page. There's an subtract and there's a reset. On the counters application I have in my page three instances when they click on reset here's what I'm manipulating the components directly. I'm calling reset on all three of them. Of course I could loop and do some nicer stuff in here and I'm returning the page itself. So when you return self in a trellis application you're basically saying refresh the page or navigate back to this page. There's of course redirects routing all that funky stuff in there. But that's it. That's basically the application. In the template all I have it's a three tags for the components. So very simple but you can see the power of this. This is where the real power of this lies. The stateful components being able to have state localized to a view and a little bit of a controller all wrapped together that you can reuse in other places. You can put parameters in there to change the behavior slightly and avoid having an explosion of basically controller snippets or if-then-else's or case statements in a controller which I seem my fair share of them. You can do pretty complex things. I wrote a grid component that basically takes a model object in this case just a data mapper model object and basically does all the table sorting editing all those things. So you can create components that are CROT components then you can place them on pages. You can put those pages in a gem and basically have CROT applications out of the box with just pages and components. Routing. I have basically routes just like in Sinatra. I basically stole most of the Sinatra code for routing but then I actually started experimenting with new things. So the routing, if you know Sinatra routing you can do the routing in trellis the same way. For example, I have a day of the year month and day same type of route substitution of parameters. I also did something cool that I think actually I'm not a genius but I thought it was pretty clever. Rather than having to put your routes in the right order, I sort them by reachability. So I automatically sort all the routes by reachability and that way you don't have to basically, like in rails we have to have our routes in routes RB in order. You don't have to do that with trellis. Trellis will basically figure out that the catch hole route should be the last thing to try because I evaluate them and I give them a weight. And those with the highest weight goes first and the ones with the lowest weight go last. So of course the catch hole has the lowest value possible. And that's of course just an aspect test for that. I also have filters. I have before, around, and after filters. And this is when I broke 186 and 19 because I used the 187 block parameters style so I have to rewrite this to basically work in 19. And this being a small project I actually I think I have two people using it somewhere in Japan that send me emails and I'm like, oh crap. So now I own it. But my goal is not for people to adopt this massively. If it works for you it's something small, great. But the idea of components I think is something that now there's a big momentum behind pushing those into rails in a clean way. Probably as a plug-in. Apatoma I think is doing a great job for that. So again take a look at that. So I can do filters to do for example things like authorization and the like. For testing I use rack test. So basically I TDD all my Trellis applications. And I can basically use RSpec to do a rack test. So basically very traditional Ruby development TDD. And now what's next? Of course sessions. I'm actually working on some more session magic which I think that's where the value of the framework comes into place. I'm going to do some crott pages so I can do the ten minute or the five minute blog demo and that type of stuff. And wow some newbies. Ajax again I ripped out all the Yahoo stuff because I was pretty surprised. I'm falling in love back with JavaScript because of jQuery. Actually I hated JavaScript before. It's not falling in love back again. This is a bad dating service. Persistence. I use for some of my demos I use Datamapper. It just works pretty well. And deployment it's rack so I deploy my apps to Heroku. You know one push there all you have to do is to rack up file. And again the more conferences I go the better it gets. There's some links in there and I already gave the PDF for the presentation so you guys should have it pretty soon. There's a website where I basically blog about all the things I'm discovering so this is very experimental. You will see one blog post where I say hey this is the really cool thing, the coolest thing that I've ever seen and then the next blog post I'm saying like that was a stupid decision. I ripped it out of the framework. It's a production level right now. They asked me to pitch Sony Conf in Arizona. Which is again another Ruby conference in the desert. Notice how beautiful of a setting it's here and of course we're going to have Joe watching you so but if you're with me you don't need your papers so we should be good. And that's my company. We do Ruby, Rails and actually Groovy and Grails too. Thank you. Any questions? Yes. That's what Apotomo has done and they've done a great job at that and actually I'm copying a lot of things that I'm seeing them doing but there's some things in there that they haven't seen because they haven't worked with a component framework. They didn't come from .NET or from Java to see components fail miserably and sometimes succeed pretty well. I saw for example JSF and I was like oh my god what a monstrosity and then I saw Tapestry and it worked well. Even makes Java palatable. So you have to be have gone through those successes and failures with components to know how they work well and of course back in the day I used to do Delphi and all the Windows base drag and drop type of things and of course I saw all the horrible things that happened with those two. You guys remember somebody putting a button double clicking on the button and putting a whole cobalt program here the framework to basically create small applications with very simple handlers with three or four lines of code at most and take a lot of the complexity into the components. Yes. I played with it for about a week and a half then I tried to get really familiar with Ruby Continuations then to realize that it was going to be a worthless effort for me to go the continuation route. So then I figured well I'm going to have to do something the HTTP session to deal with that type of approach. So I wrote a lot of plumbing code that basically deals with trying to fake Continuations in a traditional way. Yeah, it's small talk. Yeah, somebody is talking about small talk in seaside pretty soon. In small talk I mean it's a wonderful language. It just didn't get enough momentum at that point in time. In history of computer science languages it just had to be at the right time. Things like Java succeeded. Despite of the language. Of course the Java VM is a wonderful piece of machinery. But the language now we all know I mean I went from C to C++ to Java and I thought are we going backwards? What's going on in here? Any other questions? Well I used to actually have my own library of Delphi components back in the day. So I used to write hundreds of components fairly complex things. So I had that knowledge behind the scenes of basically how to build components that work well. How not to do how to let people customize the components but not too much. And basically avoid people basically creating components for everything. Not everything has to be a component. You can do things in a traditional way and only use components for the stuff that requires state and required to be reusable and slightly parameterizable. So if Sinatra runs on rails, so then Trellis will run on Sinatra or run on rails. So I'm piggybacking on the successful ones. All right, excellent. Thank you.