00:00:29.599
Uh, this is Zachary Scott. Has anyone read about Zach or anything like that on the internet? He is formerly known as Zangief from the USSR. Anyone familiar with his work in video game acting? He was a bear wrestler in the 90s, and his video game acting career kind of went downhill towards the end of the decade. They made too many sequels, and as a result, Zangief took up coding and moved out of the USSR. He slimmed down a little bit and now writes code, primarily in Ruby. He is going to talk to us about mruby, which is fascinating and something that he works on quite a lot.
00:00:37.760
So if you have questions about mruby or Ruby in general, this is one of the people who writes Ruby and mruby. You should come and talk to him. His real name is Zach, but you can call him Zangief if you want.
00:01:20.560
Okay, all right, let's do this! Good morning, everyone!
00:01:32.960
I have 35 minutes and 264 slides, so bear with me.
00:01:40.320
I'm not kidding; we will get through it, I promise. As Joan mentioned, I am Zach, or Zizak on the internet. I live in San Francisco, which is number one in first world problems.
00:01:53.439
I work at a company called Shutterfly, and I am their senior archaeologist, where I am paid to work on legacy code. They also pay me to work on open source projects. I am a Ruby core member, contributor to Ruby, and Sinatra maintainer, and I even contribute to Rails. Someone once said that this is the trifecta, but I like to think of it as a triforce.
00:02:06.479
I can't be here without thanking the organizers for getting me here and Josh for having me. It's really great to be at my first Ruby on Ales conference. I know some of you are repeat attendees, and that's awesome! They invited me for a reason.
00:02:25.440
I don't know who this guy is, but he's Irish, so I trust him. I flew down here from San Francisco to Redmond Airport, which has the initials RDM.
00:02:36.640
I couldn't help but wonder, maybe I'm the only person wondering where all the Red Mages are. No? Just me?
00:03:00.560
So what are we going to talk about today? I was looking on the site, and I noticed I don’t really have a title; I’m not good at coming up with titles. So TBA actually means 'To Be Announced.' I have a huge announcement I'd like to share with you guys.
00:03:12.720
Oh my god, Sinatra too! Just kidding, we’re not going to do that.
00:03:28.319
You could also say TBA means 'To Be Awesome.' Step one: lab coats. I’m not kidding.
00:03:41.040
I'm going to show you how to be awesome; step one, you need a lab coat. Josh actually asked me to bring this.
00:03:56.319
It even has my name on it, which is great! The next thing is, go first.
00:04:10.319
I’m just warning you, it's all downhill from here, folks. I’m mostly just trolling. But the third step is to blow people’s minds. Now I'm still just trolling; I want to talk about Ruby everywhere today, and mostly using mruby to do that, or as I like to call it, Ruby.
00:04:40.800
We’re going to talk about packaging Ruby. We will look at the landscape for packaging and what's available. We will examine how mruby works and go through the process of building it, and I’ll show you something I built in mruby to help you better understand it. We will also look at some of the caveats involved or possibilities with mruby.
00:05:19.440
Coming up with a title is actually really hard. I noticed Ryan’s title is 'Standing on the Shoulders of Giants,' which is kind of funny because last year in Australia, I used that same title, not knowing that the year before, Corey Haines had the same exact title.
00:05:47.840
Anyways, I was thinking I couldn't come up with a title, and the first thing I thought of was Wolf Pack. I don’t know why. Then I was reminded of the World Wrestling Federation. I thought of Dances with Wolves and Kevin Costner. I was actually going to use it as a title, but I think it would just blow over people's heads.
00:06:10.240
So let's look at the landscape, what's available out there today. In order to get into that, I want to briefly touch on what subject matter packaging is.
00:06:28.800
If we talk about shipping code, I like to think of it as the ship. We already know Ruby, Gems, Bundler, and Heroku; these are just facilities to move code and load it for us. Packaging is a way to do this for us. What we usually need is our code, an environment, an interpreter to run our code, and some kind of interface, which is typically in Ruby.
00:06:59.040
The main reason I want to focus on this is that I really just want to write Ruby. I don’t want to write JavaScript or Go or anything that people are using these days for packaging. I just want to focus on writing Ruby because I really love the language. Typically, we work on Linux, OSX, or OS X—depends on the interface and what we're going for. I will briefly talk about Windows support, but that's another 260 slide deck that I did not create.
00:07:39.119
When we talk about the interface, what we are asking is what is our target and who consumes it. In most cases, the two cases I’m going to focus on here are the command-line interface and embedding.
00:08:10.880
When we talk about command-line interface, we want to target an end user's computer. In some cases, we don’t have an interpreter available, so we have to choose between mruby or JRuby. If you’re going to use JRuby for a command-line interface, you will have to worry about the startup time, and I really don’t want to throw anyone to the wolves.
00:08:56.239
Shoes.rb actually solves this problem really well; it’s the first one I ever ran into. It does some really cool things with a great idea: you can create installer packages for Linux, OSX, and Windows. It achieves this by compiling Shoes and Ruby into libraries that you can link dynamically, and it can also include dynamic libraries for SQLite and link against them when it creates the archive.
00:09:31.679
It uses a pure Ruby implementation of tar to archive the whole package and then uses bininject to create an EXE or dmg for OSX, or for Linux it creates a shell script. I think there are people working on DEB and other formats. This just basically serves as the installer, and it will go ahead and build Ruby with Shoes and everything.
00:10:05.120
You know, this has some downsides, primarily because anything built by Y is a wolf in sheep's clothing. There are some libraries we can use to do this as well; if you look on the Ruby toolbox, you'll see only four listed. The top one is building Windows executables, so that doesn’t really help if you want to build executables for other environments.
00:10:42.239
The problem with these is that they typically build the interpreter, like Shoes does, and this often breaks during upgrades. You could get locked into a version because configuration definitely varies a lot, especially when we're talking about Windows support, which is minimal at best.
00:11:16.639
But I think it’s getting better. There’s a project called Traveling Ruby that works for Windows, Linux, and OSX. It kind of functions similarly to how Shoes handles it. Except, it uses pre-built binaries and includes the interpreter for you along with some common libraries.
00:11:47.040
Then you just have to write your Ruby code, and it packages it with the binary. I say good luck with other dependencies because if you have an C extension or something, it’s up to you to figure out how to compile that for your target.
00:12:29.919
If it’s Windows or something, you will have to worry about that. For Windows, they just added a spike that basically uses the Ruby installer in binary and embeds that. I really wanted to try Traveling Ruby; it looks really cool, but I didn’t get very far.
00:12:58.560
I don’t want to be the one to cry wolf, but it was a pretty cool project you should definitely check out. When we talk about CLI, we also discuss embedding, which usually means targeting the end user’s phone.
00:13:31.360
One such example you can do this with is RubyMotion, which allows you to write cross-platform native apps in Ruby. This has some great features; it’s statically compiled ahead of time, so it compiles your code into native machine code, making it much more efficient that way.
00:13:59.839
RubyMotion is cross-platform. However, there are some issues, mainly because there are separate interpreters for Android and OSX, and the implementation isn’t open. If you’re not familiar with the project, it’s a commercial project, and there’s a fee you have to pay monthly or yearly to use it.
00:14:25.440
They do handle app store submissions for you, which is a benefit compared to having to do it on your own. When I talked to Loren about this at a recent conference in Belgium, he mentioned that the number one complaint is that people don’t know why they have to pay.
00:14:58.799
My answer to that is: Ruby is dead; it doesn't matter; don't buy dead things. So how does mruby solve this? How is it different? If you’re not familiar with mruby, it's a subset of the Ruby language that’s designed to be embedded. Mats wrote it and still maintains it today, with the last stable release being in November.
00:15:32.279
When we look at building mruby, we have an existing version of Ruby, and I'm using trunk to clone the repo from Git. It takes a few seconds, and then we change directories and compile it. You'll see how fast it is to compile the language. If you've ever compiled Ruby or JRuby, you'll know it takes quite a while. This literally takes only 10-15 seconds, and it’s done.
00:15:59.440
Just to reiterate, we have an existing Ruby, we cloned it, and then we were in rake—that's all you need to do to build the interpreter. The summary of that gives us all the included Gems that come with mruby. Now they’re not part of the core, but it’s essentially a standard library.
00:16:39.440
Two of the main ones we can use right off the bat are mirb and the mruby binary itself. I’ll show you a quick demo of that using the build that compiles to the host target as one of the targets, and we can see the version there.
00:17:06.959
If we use mirb, we get an interactive Ruby interpreter, so within 30 seconds, you can have that set up with all the core features of Ruby compiled statically.
00:17:39.600
To better understand this, let's look at the build process and what it does. Essentially, it compiles all the sources that mruby links to and then performs some code generation because it compiles the bytecode and packages it for us. You saw in the binary where this is just a package.
00:18:09.920
This binary gets output as all of your code compiled statically. I’ll get into more detail in a second, but if we look at the rake file, this is how mruby does this. There are two tasks; I’ll talk about this one in a second, but the build one links to all the depth files.
00:18:44.480
These are just file tasks. Basically, what it does is go through all the binaries for your target and link them so that they can be used later as the install path for dependencies through rake.
00:19:19.159
Then it goes through each target of each gem you depend on in each binary, links them to libmruby, and then creates a dependency on libmruby itself so it can compile all of them into that file.
00:19:56.639
When we run our tests, I was going to show a demo, but it actually takes about 0.17 seconds to run the test, so there's no point in using a video; it’s very fast.
00:20:33.839
The two hosts I was discussing are Host Debug and Test Host. This is just the default build configuration setup of mruby; you can specify any number of targets.
00:21:10.320
I'll show you that later. The test process is convoluted; it concatenates all the tests you specify and compiles them into bytecode. Then, it compiles the bytecode for running the test, including all the licenses that you depend on, and executes this test binary for each of your targets.
00:21:54.960
We can understand this better if we look at the rake file in mruby's test, where we depend on all these depth files. It also does some more work here, creating all of our targets and goes through and grabs all the test files, linking them to this mruby test dependency.
00:22:30.960
The mruby test is just an executable. We will look into that in a moment, but for each target, it sets up the gems so they are configured and the flags are passed through while linking to this gem init file, which is generated for a second pile time.
00:23:04.239
This process creates a cert library, which is essentially a Ruby library, a very minimal, trimmed-down library like a mini test unit. My favorite method in here is assert, which is similar to Power Assert if any of you have heard of that gem. You just use assert with a block to evaluate code and determine if it passes or fails.
00:23:49.679
It has support for ISO standard specifications built into mruby. I don’t personally use that, but it's important for some. In this process, it takes that Ruby file and compiles it to bytecode, linking it to this function call. Our read of the init file happens when creating this file task to create the test executable.
00:24:29.440
We read in the init file that we generated, and it ends up looking like this, where we take the assert—this is the internal representation of the bytecode for the assert library—and then load it. This information turns into about 630 lines of bytecode. Next, we load the actual tests, which turn into approximately 13,000 lines of bytecode on mruby itself, including all the libraries.
00:25:13.120
Additionally, if you have gems enabled and you're linking to gems, it'll run all of their tests, generating a new function for each gem when it creates a new function that gets embedded.
00:25:57.440
If we look at the output from the compiler, it helps us a lot to understand here. We can see where it compiles these mruby bytecode calls for all the test files that mruby links to, and it starts from here, going through the mruby test compiled executable. Then we can see where it compiles and links the gem test.
00:26:30.080
These gem test files are linked, executing in about 0.18 seconds. This is literally just an executable binary for us that we could take and run at any point, and it has all of our code linked statically, including all the tests.
00:27:12.560
This is something that mruby can do, and I think it's brilliant. We have this ability in Ruby now that we haven't had before. How many of you are still with me? Good, good!
00:27:51.680
To better understand, I think it’ll help if we build something. I want to introduce my little library that I built, called mruby static, inspired by Jekyll. I just wanted a way to write markdown and preview it on a page, so I used mruby to do this.
00:28:29.520
I thought it was pertinent when someone tweeted that Jekyll had too many dependencies, one of them being Nokogiri, and it takes forever to compile. If any of you have ever compiled a huge Jekyll site like rubylang.org, it takes about 13 to 15 minutes. I don't understand why.
00:29:06.240
So I gave up and built this. I have some to-dos if you're interested; come talk to me. I’ll walk you through the code right now. But if I demo it, I can show you basically that I have a site that just has the site.rb file, a source directory with static CSS, and I have the binary static that I generated.
00:29:42.720
I'll show you how I created the binary. We can create a new post, passing in a string as a title, which just creates a file for us. If I open that file, we see my written content is there.
00:30:17.760
So this is just a starting point for anything like you would do with Jekyll, right? But there's no metadata because why do I need metadata, I don't know. If we want to preview this page, we can run preview, copy this URL, and open it in our browser.
00:30:54.560
I thought I had typed the name, but it gives me a 404. All right, your content is here okay, all right. I proceeded to take the README from the file because it's just a markdown file, as you saw on the GitHub page, and just moved that content over.
00:31:26.799
Next, I run the preview again, remember to restart the server because things are cached. Then we can see this is the README rendered using my markdown engine.
00:32:03.679
It’s very straightforward and makes it super easy if I just wanted to get up and running with something to show you guys.
00:32:38.399
It also has the ability to output all these files to a folder, creating a deployable site. In this case, I did generate the site and you can see the HTML file. This isn’t just rendering the markdown live; it’s actually the compiled version.
00:33:15.039
All of this is made possible by this library I wrote, which starts off at the entry point where we configure the static site generator and then just call start. It’s like any other typical CLI interface we would write. The configuration probably looks familiar if you're writing Rails or Ruby.
00:33:52.000
It’s just a class, and we yield to instance eval to pass in anything that overwrites these options. There are some defaults that I don’t want to reproduce. When we call start, it parses the command.
00:34:30.480
Then it takes the arguments from the command line, runs a simple regex on them to turn that into a class, and sends the action. If you do happen to get an argument error, I catch it and call the help method.
00:35:07.680
This help method is just a basic help system, like every CLI app should include. We can intern this into a class, and call the action, which is just another class, like, for example, post new.
00:35:39.520
Thank you for listening.