 There's more, more enterprisey looking output that is completely meaningless. We do see an error buried here, if you look very closely. Fortunately, if you use Maven more than once, you'll know that this error always happens and it doesn't matter, and you can just sort of ignore it. Finally, we get to the results of what we're trying to do, which is this quasi-human readable format. And you can always tell a command line user interface failure by these arbitrary lines of dashes. Because clearly, the developer couldn't read what he was outputting, so he had to put these dashes in here to figure out what's going on. In this case, the test failed. So we see build failure right there. OK, this is not very good. Unfortunately, we exit with zero, which on Unix means success. So build failure means success. This makes this program very difficult to script and to do anything with, and to incorporate into a larger system. The complete opposite of that is subversion. Subversion's not my favorite version control system, but it's a pretty awesome command line application. Here is some output where I've got some conflicts, some files. And there's only two here, but you can imagine having, like, say, 20 of them, and you've got to go sort this out. One way too lazy to copy and paste all that stuff. And since subversion plays well with others, I can gradually add Unix commands so that I can list out what's in conflicts. Give it a bit of a stupid seize. Send the entire list of files to BI where I can go fix everything. And then when I'm done, I can say I've resolved all the conflicts subversion where good to go. The creators of subversion didn't sit down. They didn't have a meeting about how can we get a list of conflicted files to go to BI and then get back and resolve them on command. Like, they didn't do that. What they did is they made their application play well with others so they could be used in ways that were not intended without having to jump through a lot of groups. So this is all kind of boiling down to the Unix way of interacting. Facts.org has this awesome quote that I'll read. Expect the output of every program to become the input of another, as yet unknown, program. Don't clutter output with extreme information. But with strangely common or binary input formats. And don't insist on interactive input. I think we can see that many of the programs you've looked at are viling a lot of these rules. So what this means more specifically is that your input and output of your program should be machine, parsable, and human readable. So you think of like delimited, common delimited, tab delimited, something like that. That Maven log file has info in square brackets which not only are special characters to the shell, but there's two of them. So it just makes it hard to deal with it. You want to make things line oriented. Wherever the thing your application does, should output other things, and those things should be one thing per line because it's very easy using Unix to a little more a small amount of Ruby code to kind of parse that out and deal with it. And of course exit codes as I mentioned before. Everything look great, UX with zero. If anything look wrong, it's with non-super. Just exit negative one, or if you have 20 different possible error conditions, you can exit with 20 different error codes. It doesn't really matter, but negative one is certainly fine. And then if you need to message the user about errors that happened or debug information or things like that, you use standard error because you can redirect that wherever you want, DevNol, some log file or whatever, and the output, whatever it is your application does, would go to standard out. This might seem obvious, but there's so many command line applications that just don't do things this way. So here's a little bit of Ruby code. It's the world's most inflexible graph. We're only looking for things with foo in the line. We print it out if we find one. Keep in account of it. We have our debugging here. Hopefully we went to standard error so we can know what we want to. And then in our case, not finding foo is an error, so we exit with negative one, and we exit with zero, everything's good. So you can see that what this thing does is there's only about three extra lines of code we had to add here to make it easily interoperable with other programs. So what we're planning on with others is the Unix way what I just described and the highway, right? There's no other way to do it. Well, that may have been true a while ago, but I don't think that's really true now. I think there's what I call the Cucumber way, which Cucumber meaning the testing tool of behavior-driven design, developing whatever you want to call it. Cucumber is the first app that I recall having a real user experience that didn't irritate me. There's a lot of heavily bearded Unix Fishing Autos who would be horrified to see such colors and bold on their command prompt, but I think Cucumber did a really good job here. You see all this red, which is kind of hard to make out here, of things that you haven't done yet and things that are broken and yellow or things you haven't done yet. When you make everything right, you see this nice, lovely little bit of green and it made me so happy the first time I did that. And I said, hey, it's possible to have a real actual user experience on the command line. So I think that's totally fine if this situation calls for it. And so basically what that means, you know, we're still having our exit codes. We don't want to mess around with that. And we still want to have a Unix C option. You know, we might say, hey, I need to actually put this in Cron and Cron doesn't care about bold. So we just have some sort of normal Unix output. That's fine. But the regular output would be colors, bold, italic. And here's a couple of Ruby gems that make it really easy. They basically add methods to string that make it incredibly simple to create all of these fancy colors and bold on the command line. But I think that you have to really embrace this and take it all the way or not do it. You don't want to just throw a couple of bolds in there just because you can or make something red just because you can. You really need to make it a full user experience if that makes sense and if it doesn't, then don't do it. Because really the Unix way is always fine. If you're not sure what to do, the Unix way is fine. But if you think your application is complicated enough and sophisticated enough to have a real user experience, then like I said, Ruby gives you some very easy tools to do. So everything I've said so far, you could probably make some great command line applications or Python or whatever if you had to. So why do we care about Ruby? Well there's really easy ways to interact with the system as we've seen already. You've probably known this. System just executes whatever. Active executes whatever gives you the output of that as a string. Dollars like question mark gives you access to the results so you can say if dollar sign, question mark dot success, then everything's cool. And then of course file utils, if you've done any rake stuff, file utils gives you a bunch of methods that look and behave like Unix command line tools, which lets you make system automation strips that are almost as succinct as batch, but they won't work on any platform. So if you find yourself having to run on Windows, then you totally can. You don't have to worry about SIG win, whether or not it's gonna work and what it's gonna do with your pass. Now beyond just the ability to run system commands, obviously Ruby is a great language in general. It has all these high level abstractions on this automated programming. So presumably you're working on an application like a web app or a desktop app or a mobile app and it's all using some object-oriented language. Ruby hopefully, possibly C sharp or Java. And all of the lessons that you know from object-oriented programming there, you can apply to your Ruby command line scripts. If you're writing them in bash, you can. And if you're writing them in Perl, everything's sort of hacked on at the end. So that's, so you can apply everything there. Packaging distribution gem is very easy. If you need to do something more sophisticated you can just check out our version control. Gem is really easy to use. And it's fast, it's just as fast as bash to start up and run a script. There's no crazy VM that you have to start up. If I go back to that maven output, you can see running one test took like a minute. So you don't have that issue with Ruby. And finally the community really was built on the command line. Every Ruby gem that you get has command line tools with it usually. Everything kind of starts on the command line. So it's really part of the kind of ethos of Ruby. And what that means to you is that there's a ton of gems that you can find them that can do all kinds of cool stuff on the command line. And of course the Ruby culture is to make little gems that do one thing. So you can glue them up together as you need to. Which is great. So how do we actually do this? Once we've sort of bought into this. So for a simple application, option parser, maybe some of you use that. It's included with Ruby. It's available everywhere. It's very easy. The RDoC pretty much gives you a great example of how to use it. So here's how we would start it up. We would say option parser.new and we'd give it a block that takes some objects and on that object we'll call some methods that will describe what our command line interface looks like. So we do something like this. We're gonna take a switch called dash dash no auto. And it means no auto regenerate. And then the block that's given will be executed when the user specifies this switch on the command line. So you can do whatever you want in that block. Typically people just set up some hash that has a list of the options but you can really do anything you want there. And then this little string here will get used to create a nice help interface that you don't have to worry about formally. If you need to take an argument, you can use the square bracket syntax and option parser will parse that command line and give it to you as an argument to your block. Then you can do whatever you want. You can barf. If you don't like it, you can set up more things, default, whatever makes sense. So option parser is very easy to use. The code that it results in is very easy to understand and pretty clear. And you can even do some type conversions so you don't have to call two I on everything. And best of all, it allocates a nice option summary. So you don't have to format anything. You don't have to go into printf or worry about spacing. It takes care of all that for you, which is really nice. Making a command suite style application is a little bit difficult. You can do it, but you have to go through some hoops and it's not exactly straightforward. So trollop is another option to option parser if you find three lines to set an option too much. You can do it in one line per option here. It's just a lot more succinct and brief. You don't have a gem to install. So it's pretty easy to distribute just some file you can include or you can just paste into your script if you need to. It's a little bit easier to do the command suite style applications, but it is still a little bit verbose because it was sort of added later and not kind of built in. So if we're doing command suite style applications where we're gonna take the sub-command and have lots of different options. We've got a hand jam like this. This is an old version of show off which is the program we're running right now. And you can see pretty much how this works. So we're just grabbing the command out of our V and we just paste it in. Of course, this is not super extensible. So if your application needs to grow, we come more sophisticated. This hand jamming is just gonna start becoming the best or worse, you're just not gonna extend your application because it's just too difficult. And the help message is you've got hand jamming those two. If you add a command, you've gotta go find the string that lists all commands and add that there too. This is surprisingly prolific though. I needed to make a command suite application way back when and I looked around and found a lot of this code and I didn't like that because I'm lazy and I don't have to write all that. And I wanted it to be nice. I wanted it to be a really awesome app. So I created a genome of my own called GLI which stands for like interface if that's what makes sense to me. And so it's designed to make command suite style applications like very, very simple. I wanted the application to be super polished, have a really nice help interface without me having to do a lot of work. Like I said, I'm really lazy but I want it to be nice. So I basically made a little scaffolding that sets up some boilerplate for us and so we're gonna create a command called my command. It's gonna take three sub commands called ls, rm and init and then when we run what was generated we can see we've got a nice little help. I mean, obviously the content is just boilerplate but all this formatting of making the dot dash line up in the spacing everything I don't want to have to deal with it. It's totally done for me. Just pretty nice. When we get help on a particular command it does, it does this. Beautiful, that's exactly what I don't want to have to spend time doing. I want to spend time implementing my application. So here's a little bit of the syntax. It's kind of like rake and that you have, provide some description and then you say I've got a switch and a switch is a yes or no type of thing. We can also have a flag which is a switch that takes an argument and so we can say there's a default value that we want to have if the user doesn't specify it. We can describe the name with the argument like means and a description and all this goes into that help so that when we get help we can see exactly what we need and it can take us very much code to do it. This array lets us say dash f or dash dash file equals so you can get some flexibility with how you want to set up your interface. And then here's how we actually define command. Similar that we say there's a description of what our command serve does and this is taken from the current version of showoff which is using GLI. So again we get this pass to our commands block and we have all the same methods that we have for the global commands command specific flags and options and switches. And then finally we have an action block and so this is the block of code that gets called when the user executes your command on the command line. And this block is given the global options that the user specified including any defaults if they didn't specify things. The command specific options that the user specified again including defaults. And then the list of unparked arguments anything that was left over after parsing was done. And then in here you can do whatever it is you need to do if something is going wrong you can just sort of barf and instead of getting a stack trace you can get a nice error message. And then you can basically just do whatever it is you need to do. Now you can sort of certainly override the error message so there's some hooks into the whole kind of life cycle here. If you don't like just one error message you want to do something a little more sophisticated you can catch all the unhandled exceptions and do whatever it is you want to do. If you now with a command suite application typically you're doing something a little more grandiose than just processing some data. So here is the pre and post hooks from a command line app I wrote to interact with track which is a wiki bug tracking type of system. And so every sub command needed access to track in general. So this pre gets executed before the command happens so you can set up whatever it is you need to set up in your application and everybody has access to it. You can debate that I shouldn't be using global variables but that's the code that I got this from. And we're setting up our thing to track and then going on our merry way so every command has access to that. You can do the same thing with a post hook, you can tear down database connections or whatever it is that makes sense. A few other features you can use all of this to generate RDoC documentation so you can include that in your gem and it's available in the system RDoC which is nice and you don't have to write any of that. You can also have a configuration file that's user or site specific. So if the user doesn't like the default values you've assigned or if he wants to specify default values for options, he can put it in config file and we'll just get read on that. Now, if my Google food had been better a year ago when I wrote this and the commanders authors Google food was better, I probably would have found commander which does almost the same thing. The syntax is very similar. It looks like I completely ripped it off or something. Unfortunately found out about it a little too late. Other than the general syntax, it takes a little bit different approach. I guess it's more of like a Rails approach right where it glues together a lot of different gems that you might need on a command line. They're all available as dependencies you can just access them. So anything from Highline which lets you interact with the user getting input and output, ASCII tables which draws like nice tables or even Braille on the Mac. Like if there's a whole bunch of different gems that are just kind of there when you make a commander application which may be what you wanted and you may not want those dependencies you know what kind of depends. It doesn't have the hooks or config file support but it has been around for quite a while and it's a pretty mature thing. Last little bit is this thing called Thor which is not really about building a command line app but it's about running code from the command line if that makes sense. You basically define tasks in Ruby files and then you tell Thor to install them into a central repository and then anywhere else in the system you can run these tasks using the names that you use to install your code which is not exactly making a command line app but it is a very expedient way to make functionality available throughout the system and it seems pretty cool. So anyway, in summary, the whole point of this is that you should approach your command line applications and you should want to make them awesome. You should approach them with the same kind of rigor and professionalism that you would do regular applications because it's not that hard. Ruby provides a lot of ways to make it really easy so it doesn't take that much effort to kind of bring your app up to the next level. And really it's all about being selfish, right? It's all about being nice to future you because future you's gonna have to deal with this and future you would much rather have a nice application that's helpful and plays well with others in X-verse class than not. So that's basically everything. Here's a link to all of the gems that I talked about to check out and that's it, thanks. We have a few time for questions if anybody's got anything. You mentioned option parser and follow. How does that compare to like get up long? Or is it pretty much the same thing? Get out is like the old school like C and Pearl one. And it's just a lot more for both and option parser just, I'm sure it uses that under the covers. I just thought option parser is a lot easier to use in get out. But of course, get out is gonna be familiar to anyone who's coming from Pearl or C. Do you have like, does it have support for flags that have support for a flag where a user just can optionally not pass an argument? I know those are rare. Right, so the question is you might have a flag it's like dash F or dash F who? And no, I decided it would be simpler to separate things completely. There might be something I had later. I just never really knew that. So I noticed in your slide on GOI you had two F flags. So that's like three of those two flags probably conflicted, right? Yeah, that was actually a mistake in my code that I noticed as I was giving the talk right now. What would happen is that the last thing that used it would win essentially. So in that example, I think there would have been a dash dash force flag. That would still be available, but dash F would be expecting an argument. So if you did dash F, it would give you an error. Colorization, I deal with this with like rails, log files. Did you use to decide when for color output to be on and off or do you only use a switch to turn it on and off? I mostly just use a switch, although I think I want to say it actually knows if it's output is going to a file and it doesn't do all that stuff. I'm not exactly sure how to do that. I'm sure there's some Unix TTY stuff, but I haven't actually looked into that. Well, I think, I mean, the good question is that having the cross platform, ComaLine app changed my fan using Ruby. Certainly if I knew ahead of time, it absolutely has to work on Windows. I think I would jump to Ruby a lot sooner. Right now what happens is I need to script something and I kind of know it's not gonna be on Windows. So I blot up SA, so I'm like, eh, this is not gonna work out. So I have to kind of catch myself sometimes. But yeah, I mean, that's why I like to get in the habit of trying to do it always in Ruby, so that I don't have to do it for it. Do you have any current way for a testing fan line application for a view? Yeah, actually, I cut that out for time, but the guy that makes Cucumber, he, I can't remember what it is, but he makes a, a, a Luba. Yeah, yeah, yeah. So you can use that to do like behavior-driven command line tests. The tests I wrote for GLI, it was really challenging because I had to sort of simulate RV and all that stuff. And if I had done about a rubo, what I made things a little bit easier. I think it's pretty stable. I've been using it for a lot of things and I haven't really done a lot of updates recently. There's certainly a lot of features I can add, but right now I'm most of the primary user of it. It's being used in show off and a few other people have worked it, but nothing too crazy. So I'm just sort of in a holding pattern until someone has some opinion about what it should be about. So Jim installed GLI, it's almost as easy as grabbing, just to make sure we get those? Yeah, I keep it up to date and it's not too far, I don't think it helps ahead of it at all, so. Okay, thank you. I think if I had found Commander before, I probably would not have written GLI because it took a lot of work to make it right and everything. And that was on the problem I had to solve with that exact time, but I really wanted to solve it. And Commander is pretty nice. I mean, I think in retrospect, Commander has a pretty heavy dependency tree and so where I work now, I set up an application, the application that motivated my whole story about someone getting hired to do their job. This actually happened, someone was hired and they started running my application and they didn't realize it. So I updated it to be a little bit nicer and then the assistive men were like, dude, what is this Ruby gem thing I've got to install? So that was kind of a problem. And I didn't have a lot of dependencies so they ended up doing some crazy thing where you can wrap a gem for a CentOS install package or something. And I was like, wow, if I had like 20 dependencies, this would have been kind of a pain. So I think it's nice to have the option of not having something like this. Yeah, I think that's what this thing, this thing our system was trying to do. It would basically figure out the gems and put them all together into one thing and it used Yom and I'm not super familiar with it, but mostly I've just used gem because I've had control of the system. Cool, anybody have anything else? Very great, well, thanks a lot.