Wednesday, October 05, 2016
RubyConf 2015 - Building CLI Apps for Everyone by Terence Lee
Awesome. Mic's working.
Hi, hello everyone, I'm here to talk about...
I'm here to talk about building CLI apps for everyone,
so if you were looking at the board
and you saw something about managing a community
for Ruby association, this is not that talk.
Unfortunately, he couldn't make it.
So, yeah, I'm Terence Lee.
I go buy hone02 on Twitter,
I come from Austin, Texas,
which is only an hour and a half north of here.
We have some awesome tacos.
If you're ever in town, I'm more than happy to take you
out for some tacos.
I know some people have collected on that.
There's also a Torchy's Tacos, I think, in San Antonio,
halfway between here and the airport.
Is what I've heard.
They have awesome tacos.
With a few fellows here,
and Davy, who is not here at RubyConf,
we run this weird conference called Keep Ruby Weird,
which is in Austin, Texas.
Just happened last month.
Stay tuned for year three next year.
You can probably hassle Ernie about how
great or terrible the conference was.
He was there.
I'm also a big proponent of Ruby karaoke.
If you did not go to Ruby karaoke at RubyConf,
you missed out on a really awesome, magical experience.
This was us singing Bohemian Rhapsody,
which is a classic, of course.
And it really started, I was inspired by Charlie Nutter,
back in last year, during RubyConf Taiwan,
he karaoke'd for a marathon seven hours.
I only managed to do, like, five,
but it was a really great experience,
and this is him singing a duet
with Plexus, which is always a good time.
I have to give a shout-out to P.J. Haggerty,
who could not make it here,
but he has been a huge proponent of Ruby karaoke,
and has helped organize a ton of them.
So much that I've actually organized none of them this year,
but there's been one at every single Ruby Conference
I've been to, which has been pretty great.
So I work at Heroku, I do Ruby things there
with Richard Schneeman, who's sitting over there.
He had that picture on the first slide,
drinking that medium sized margarita.
Everything's larger in Texas, apparently.
So onto the actual talk.
I'm here to talk to you about packaging in Ruby,
and why we should be building things in Ruby.
In order to get a sense of how this works,
I'm gonna talk about the Heroku toolbelt,
and the story behind it,
and where we started, and where it's going today.
And so when we first started, we were just a Ruby gem,
so in order to get started, you just ran gem install heroku.
I think even some people today are still using the
Heroku gem, even though you're not supposed to.
It's been deprecated.
And at the time, it was a great decision because
Heroku was just targeting Ruby customers.
That was the only thing we supported on the platform,
and so plugging into the Ruby gem's ecosystem
made it really easy and convenient to get up and running.
We didn't have to deal with package management,
we didn't have to figure out how to
deal with all this stuff, because
Ruby gems already had a specification,
and if you're a Ruby developer,
you already had the Ruby gems installed to
ready build your rails and other applications.
So that was great win for us, because it allowed us to
move quickly and not have to deal with many other things.
But the downside, over time, that we learned
was that it required people to actually have
Ruby installed on their system,
which, as we moved to being a more polyglot platform,
that became an issue.
I've talked to some other people who have...
Like there's the Sass Project, which requires you,
when it first got started, to have Ruby installed
to do, like, Sass stuff,
which was a huge barrier to entry for front end developers
who may not be familiar with getting Ruby up and running.
If you've ever helped out at a Rails Girls or Rails Bridge,
I'm sure you're very familiar with
how painful this process can be.
And the other thing, even if you were a Ruby developer,
we couldn't guarantee the version of Ruby you're running
was the same one,
so we had to essentially support many versions of Ruby.
On OSX, it was famous that they Ruby 1.8.7
as the default version of Ruby for a long time,
and even after Ruby 1.8.7 was deprecated,
and no security updates or anything were being added to it,
we still had to make sure our gem was backwards compatible,
so we couldn't take advantage of any of the new features
and syntaxes, just because we had
to make sure it would work.
Which made debugging and maintaining it
a pain in the butt.
So then we moved on to a, essentially,
a packaged up installer,
where we would package up the Ruby runtime
into this thing called the toolbelt,
and we would take the gem and basically
have the gem and the runtime with it.
And so we would have to build that
for every single platform that we wanted to run.
I don't know if any of you have tried to package up Ruby
for Windows, but it is not very fun.
We had a special box that would do that,
and even for OSX, we had a Mac mini,
when we first started this, under someone's desk
at the office that was just there
for packaged up OSX Rubies.
And we've automated a lot of that stuff since then,
but it is still a lot more work
than just pushing up a new gem, right?
If you're just updating a gem, you can just run
rake release or some other task,
and it's very simple to get versions and stuff out.
Now it's a much more involved process,
and with the new OSX signing stuff,
we have to have certificates and other things in place.
So then there was this HK project that was started
internally by an employee,
and it was basically rewriting the entire CLI
inside of Go.
And one of the big motivating factors
for doing this was that speed is a feature.
Like, fast is a feature.
And so at the time, when this was benchmarked,
running Heroku version on the Ruby gem
or the toolbelt took almost two seconds,
and the Go equivalent was 16 milliseconds,
and so you're talking about
orders of magnitude of difference here.
Admittedly, the Go version did a lot less
than the toolbelt version, but I think
it does show some baseline on performance difference there.
I think a lot of this can be attributed to the fact that
having to load a bunch of these things
inside of Ruby at runtime can be a slow process.
If you hadn't heard of this before,
require is pretty slow.
There is a performance impact for doing that.
So especially for a command line application,
you want to split up your application
as it gets bigger, because you don't want to have
the monolithic Perl 23,000 lines of Perl code
that you're trying to parse through
for a single command.
So you end up splitting it,
but then you have to do all these hacks
which we've done in the toolbelt
to only load the files that we need to
at the time that they're needed
all throughout the code base,
as the default version of Ruby
for a modular and actually maintainable.
The second thing that was really appealing about Go
for us when we were doing this was that
you could statically link each binary,
which meant that we could build a single file
that we could distribute to every single
operating system that we cared to support.
Which meant for Windows and OSX and Linux,
it was one file, we could just package that up
and then give it to someone,
and they could install it on their system
and it wasn't this folder of files and things
plus some runtime, and path environment variables
to make sure that all that stuff is set up.
And if you had an existing Ruby install,
we had to make sure we weren't
monging and overriding stuff
while you're running the toolbelt,
that it would pick up other things
that you already had set.
So I don't think the Heroku toolbelt story is unique.
I know Hashicorp has had a similar story.
Their Vagrant project, a lot of their CLIs
were originally written in Ruby.
Vagrant is still written in Ruby,
but they went from being a Ruby gem
to not being a Ruby gem anymore last year,
to just packaging up itself,
and then all their newer CLI stuff is written in Go,
for a lot of these same reasons.
If you do want to package stuff up in Ruby, though,
there's project called Travelling Ruby by the Fusion guys.
Probably most well known for Mod Ruby and Fusion Passenger.
The nice thing here is you don't actually have to rewrite
your entire application, you can still use Ruby,
and it kind of handles the toolbelt part of
packaging up a runtime and
having extensions that you're gonna use,
if you have native extensions like Nokogiri, for instance.
But the downside is you're actually restricted to
all the runtimes and extensions that they have precompiled,
and the exact versions that they have compiled.
So if you want to use something else,
you're kind of out there on your own to try to
make all that work, if you want to support
Windows and Linux and OSX all at the same time.
When I was in Portugal,
I actually ended up talking to sferik,
and he was telling me about this Crystal project,
so besides Go, there's also Crystal,
which is a statically typed, compiled
Ruby-like language that allows you to build things.
After kind of seeing this over the last few years,
and we have a ton of Ruby CLIs
and ecosystem for it,
with, like, option parsers and GLI and Thor
and things like that, and there is a lot of CLIs
that originated in the Ruby ecosystem.
It's a little sad to see them all go away,
and I think a big part of that is because
our packaging story isn't great for packaging up MRI, right?
Like to deploy a Rails application,
we have this chef scripts that
go and clone your repo, run bundler, and then
do all the setup stuff to hopefully make it all work.
Instead of using other languages,
I wanted to continue to build things in Ruby,
which was kind of the inspiration behind all this stuff.
And I gave a version of this talk at Rocky Mountain Ruby,
and Steve gave a kind of really poignant Tweet in response
that I think applies heavily here.
There's nothing wrong with using other languages.
Like, Go and Crystal are both great languages
in their own right, and if you're happy using that stuff,
you should continue to go ahead and do so.
This isn't a language bashing talk.
But I want to continue to build things in Ruby,
and I wanted to find a way we can shore up the weaknesses
for continuing to do stuff in Ruby
where people want to choose to do so.
I think picking Ruby shouldn't be a technical limitation
of why you're working on your project,
that you have to migrate everything off of it.
So how to we make packaging possible
if you want to continue using Ruby?
So Zachary Scott and I started a project called mruby-cli
back this early summer.
We spent a bunch of time trying to solve this problem.
And we had a few design goals in mind,
so if we're going to write a thing for Rubyists
you should be writing most of your code in Ruby.
I think that's a pretty important point.
And so inside of mruby-cli, you have an mrblib directory,
and then you can essentially just have a bunch of RB files,
while are Ruby files.
And you can have sub-folders in them,
like you would in a Rubygem,
you can put anything, you can put all these RB files
in any kind of organizational structure that you want,
as long as it resides in this folder.
The next thing is that performance is a feature,
and I learned that through the HK story,
as I saw that develop.
And what I really mean by that
is actually startup performance.
So generally, when people do these benchmarks,
you take it with a grain of salt.
But for command line applications,
it's actually really pertinent.
How fast can you boot up the Ruby runtime
and get something out on the screen?
Because most command line applications
are, hopefully, gonna be this quick thing
where you're interacting with it relatively quickly,
and you want to be able to get that fast feedback loop.
So inside of MRI, I'm sure most of you
have written this application before,
where you really just print hello world to the screen.
So on Ruby 2.2.2, which is what I tested this on,
it took 40 milliseconds to boot up,
which is not super slow,
and that's totally tolerable and it's pretty respectable
to deal with.
I wouldn't mind writing command line applications in this,
but as you start to add require and other things,
this will definitely slow down.
And so when I did this in mruby-cli
as we started to build out this project,
the simple hello world application was three milliseconds.
So it's an order of magnitude faster,
and to me that gives you a lot of headroom
to do a lot more interesting things inside of the project
and still get that really fast iterative kind of workflow
that you would want out of a CLI.
Like if you're building a CLI
as a product for your company,
and people are running a bunch of commands,
you definitely want it to have that kind of
loop and feedback system.
So, like I was saying earlier,
there's no require inside of mruby,
which means that as you continue to add files into it,
you're not gonna get that kind of runtime slowdown
that you would in MRI itself.
So as the CLI apps get bigger,
it's only the performance differential for the startup time
is only gonna get bigger.
And the third design goal that we had in mind was that,
like the Go thing that made that so attractive is that
the product and artifact that we have to produce
is this single binary that people can ship,
because that's a very attractive system,
and not having to figure out some way
to package all this stuff up, and set up
all these environment variables and things,
if you can just have a single binary
that has all the runtime and things included,
you can just ship that to the customer
and they can get that up running relatively quickly.
So inside of mruby-cli,
we have a bunch of different platforms,
and you essentially, when you run the build,
you see the build name and then it produces a single binary.
So for the hello world thing,
this is the build summary that you would get.
And we have one for OSX as well as Windows,
so you can cross compile
for all Linux, OSX, and Windows,
which is a really great experience.
And, to give you a sense of how big these files are
that include this mruby runtime,
the OSX binary is only 421 kilobytes.
So not the smallest thing, but not terribly large either.
And the final thing was, in order to actually
get any traction on this,
the setup has to be really simple to get up and running.
In order to do all this cross building stuff like Go does,
you have to set up all these tools,
and we wanted to make that as simple as possible,
because we knew that mruby-cli
would be a real underdog compared to
all the other solutions out there.
So we're leveraging Docker, we built a container,
and if you're not familiar with Docker,
it's basically a Linux containerization thing
that allows us to provide a simple setup for
people who are interested in trying this out.
So we have a tag pushed up onto Docker Hub
that has, basically, all the tools and things you need,
so in order to get started all you need
is Docker and the mruby-cli binary.
You don't have to have Ruby installed,
you don't have to have GCC or any C compiler,
none of the cross compiling tools for OSX,
and nothing for Windows either.
This allowed us as well to only target
one platform to then cross build for everything
and not have to handle that three by three matrix
of how you compile from one thing to the next thing.
So the simplest hello world example of
what this all looks like is
when you have mruby-cli on the path,
you pass this dash dash setup
and you name the thing, like in rails new,
of what you want to call it.
So hello, and then once you CD into that directory,
you have a bunch of files,
and you run this compile task through Docker compose.
And you can go and grab some coffee, wait for it to compile,
and then you can run a shell,
or just execute the actual target build that is specific
to the platform you're actually building this on,
and when you run hello, you see hello world.
So that's kind of the workflow of
how you would get something up and running from nothing.
And so when we actually run the setup,
like in Rails, we produce a bunch of files
so you don't have to write them yourself,
and this allows you to get up and running
Basically for the rest of the talk we're gonna go through
what is generated, and how all this stuff works
and fits together.
And mruby-cli itself is actually just this idea
and really just that Rails template generator,
and that's all it is, and it pieces all this stuff together.
Most of the leg work is actually being done by mruby itself,
and the entire build system and everything inbuilt with it,
so in order to really to understand how any of this works,
we have to take a step back and just
talk about mruby.
So what is mruby?
Mruby is this embeddable Ruby that is meant to lightweight,
because it is being embedded in multiple different
architectures and types and whatnot,
so it's meant to have quick bootup times
and light weight in memory.
People ask me all the time, "Okay,
"this is a really cool project,
"where's it actually being used?"
And I was talking to Matts yesterday at our boff
and asked him about it,
and they use mruby in Japan,
there's a company that produces routers,
and they use it to basically extend the firmware.
So you can write mruby code to extend the firmware stuff
that you're using, and not have to, say,
drop down to C or assembly or whatever
the firmware's being written in.
Which is really cool, and it makes it
really powerful and flexible.
And here's some of the contributors
that have been working on mruby.
So what are the big differences
between mruby and MRI?
Most of you are probably not super familiar with mruby,
and it's maybe your first time looking into it seriously.
So, since mruby's being built and targeted for
different architectures, besides just x86,
like it can compile to Android and iOS
as well as it's often used for IOT type of things as well.
And Raspberry Pi, Arduino, stuff like that.
That means that we can't guarantee that
there is actually a file system there
or any of the OS level things that we're used to having
inside of MRI itself, so that means no file,
no socket, no input output kind of thing.
It's not threadsafe, because threads are
an operating system level feature,
so that also means there's no threading or forking as well.
And the syntax itself is a subset of Ruby 1.9,
with maybe some stuff from Ruby 2,
like string freeze, which got added recently.
But on the flip side, it is an actual Ruby language,
so that means stuff like procs and blocks
that we're used to having,
DHH freedom patching that he talked about a few years ago,
and meta programming and literals.
Things that we're used to having inside of Ruby
are there and they work
like you would expect inside of Ruby.
So in order to understand how all this comes together,
we have to look at how you actually run mruby code.
Like, I write a Ruby file, how do I get it
to actually print something to the screen,
or do what our command line application does?
So the simplest way, like inside of MRI,
you can actually, when you build mruby,
you can get an mruby binary,
which is just the interpreter.
So you can patch dash E, you can print stuff out,
you can also take your Ruby file
and then pass it as an argument to the mruby binary
and it just goes through and interprets the code.
And we also provide MIRB binary as well,
so you can get all that ripple goodness
that was really exciting when I first got started in Ruby.
You can do that as well in mruby.
But where it starts to get really exciting
is that there's an mruby bytecode compiler,
so you can take any mruby script that you're writing,
and if you use the mruby bytecode compiler,
it actually takes the code that you've written
and puts it into mruby bytecode.
And you get this dot MRB file that you have.
And once you have that, you can use the mruby interpreter,
pass the dash B flag to specify
that this is a bytecode representation,
and run the code.
So it means at runtime you do not actually have to
go and that compilation process.
And if you take this a step further,
you can actually take that and embed it inside of a C file
and get the mruby bytecode compiler
to actually produce C code with
an array of all this stuff that you need,
and then you can go and write a main function
that invokes all this stuff,
and then you can go ahead and basically compile down
into static files.
So if we take this to its natural conclusion,
you can actually produce a single binary
with all this stuff.
And so with mruby-cli, since we wanted to focus
on people producing Ruby code, and not writing a bunch of C,
I assume many Rubyists are not familiar
with writing a bunch of C,
C is not my best language,
we produce, basically, a C wrapper script for you
that takes all the arguments that you need
from the C code and passes it down to mruby.
So inside of your Ruby code, you have access
to all the arguments, and you can just write
all of your stuff inside of Ruby
and not have to write any of the C bits.
So the only contract we actually have is that
we call out to this underscore underscore main
underscore underscore method,
and the argv is a Ruby representation
of the arg array that is being passed inside of the C code.
So like I was saying before, we have an mrblib folder
that has all the Ruby code,
and, again, it's really important that we're
letting people write stuff in Ruby.
And one of the awesome things about mruby
is that all the stuff in it, the whole entire build system
is built on top of Ruby itself,
so the entire build system uses rake,
there's much rake tasks and stuff,
so in order to compile and test and do things,
you can just run a rake test, and that's the same
We also just leverage the rake system.
So since this stuff has been built,
one of the unique things about it is
there's this build config dot RB file
that basically helps you configure what you're building.
So you can essentially create a new build
for the targets that you want to build for.
In our case, we generate one for OSX,
and this is an example of what it would look like
to do a new cross build.
You don't actually have to write any of this stuff out,
we generate all this stuff by default.
We generate that build config, and we populate
with all these things, so
in general you don't really have to be touching this file
unless you want to be overriding stuff,
if you have some super requirements or whatnot,
or you don't care about compiling to some operating system.
You can just delete this or comment it out.
And so when we run compile,
we see that we get all that stuff built,
and there's also this system called mrbgems,
which is probably the closest equivalent to
what MRI has for Rubygems.
Inside of this mrbgem rake, it's similar to
the Rubygem specification.
If you've ever written a Rubygem,
probably a lot of this stuff looks familiar to you.
You specify all the metadata.
And where it starts to get really interesting
is this add dependency.
Like, this looks different than actually
inside of MRI itself.
So it takes two arguments.
There's the name and, basically, where this gem comes from.
Since there's not exactly a central repository
like rubygems.org that's really standardized
as a service, where you can push up new releases and stuff,
you have to actually tell mruby
where to get this stuff from.
So there's three different kinds of locations
that it supports out of the box.
There's core, so inside of the mrb directory itself
there's an mrb gems folder.
Inside of it, there's a bunch of mrbgems that you can use.
And the reason that it's split out is because
you're trying to, again, have a small footprint,
which is great for CLI development,
so we only want to be pulling in the things
that we want to be using.
So there's many extensions that we're
probably familiar with having inside of Ruby
for array and enumerators and things like that,
and if we want to actually leverage that,
you would essentially pull that in as a dependency.
So we can really limit what we're actually pulling in
and not have the entire kitchen sink.
So that's all bundled in and maintained by
the mruby team.
There's mgems, which is the closest equivalent
to rubygems.org, but it's not quite the same thing.
Essentially it's a repository on GitHub,
and when you want to add something to it,
you send a pool request that adds your mrbgem
into the system, and it basically clones it and then...
They're essentially just other GitHub repos,
for the most part, but it's a system that allows you
not having to know where all this stuff lives,
and you can just specify the mgem list.
Of course, you can also just use GitHub itself,
which means if you want to start testing a thing
that you didn't feel should be on mgem yet
because it's not solid, but you need to test and build it,
or if you want to fork a gem, right?
And you want to do that,
there's an easy way to add that there.
And so one of the things inside of build config,
like I was saying, overriding stuff,
one of the things you can do is actually
override any dependencies that you
have conflicts for.
So if a mrb gem has another dependency,
but you need to fix some bug there,
in MRI, like in bundler, you probably would fork that thing
on GitHub, you'd have to fork the parent thing
to have the gem spec point to your other thing,
and then make sure all that stuff's included.
Inside of mruby, we can actually just
specify this bottom line here, the conf dot gem,
and it will use that over anything else
that is specified inside of it.
Mrb gem rake, and all the other mrb gem rakes
that you're pulling in for the other mrbgems.
Since we're Rubyists, we need to test stuff,
so there is unit testing through mtest,
and that is gem that can get pulled in,
and then you can essentially have a folder of test files
that are all unit tested.
One thing to note is that, since these are unit tests,
they're running inside of mruby,
so you're limited to the mruby syntax and code
and the dependencies that you're actually pulling in,
so you can't pull in extra stuff if you don't add it in.
But it does allow you write really fast unit tests.
So this is an example of what that looks like.
It looks, probably, pretty familiar
to most people who've run any other unit tests.
The next thing is that we actually also support bintest,
and this is built into
mruby, and this actually uses MRI,
so you see those require files,
which should give you that hand,
and it just leverages open3, and it's a framework for
kind of wrapping all that stuff around it.
Basically, you just want to invoke the binary
that you're producing, and just test
and put outputs there.
But since you have the entire MRI system to your disposal,
you can do a lot more fancier things
inside your integration tests for setup and whatnot.
So this is an example of what an integration test
would look like inside of mruby,
So this all sounds great,
but what are the gotchas that you're gonna be facing
when you want to build something like this?
So the first thing is that MRI has
a rich standard library out there.
I mean, in Aja's keynote, you saw, like
Rinda and tuple space and stuff like that.
None of that stuff is really available inside of mruby,
and even the stuff that is is fairly trimmed down,
by design to keep it lightweight and small.
So if you wanted to port something over
to mruby, it's not as easy, because there's many...
Even if it had no dependencies inside of MRI,
it probably leverages a ton of the standard library,
which may or may not by working 100% inside of mruby.
And that also means you can't leverage Rubygems, right?
That entire ecosystem of Rubygems that is out there,
I think I was told it's, like, 7000 gems,
none of that can be directly just, like,
pull this thing in from Rubygems and expect it to work.
So that's a huge bummer.
And in order to support this cross compiling stuff,
the mrbgems that have native extensions in C and whatnot
need to support cross compiling in order to get it
to work across multiple operating systems.
So as zee-zach and I have gone through
and gotten stuff to work for mruby-cli,
and the mruby-cli projects that we've been building,
we've gone and started adding support for cross compilation.
So like libyaml and the XML parsons stuff with...
Or no, the regex stuff with oni-you-rama,
we've gotten all that stuff to cross compile and work
on Linux, OSX, and Windows fine.
So this is definitely a huge uphill battle,
because I think a lot of the gems
are essentially built for the use case of the author,
and so they don't need to support all these other platforms.
But there is, I did want to talk about one
success story that we've had with mruby-cli.
So there's this project called jruby-launcher,
inside the jruby ecosystem,
and normally when you download jruby
you get either a bash file
that boots it up on a Unix system,
or you get a bat file on Windows.
And they essentially had to maintain both of these things,
which can be kind of a huge pain in the butt.
So they have this gem that you can gem install
that is this C++ code that can be used to basically
launch your thing, and they could have
a unified code base for all the operating systems
they wanted to support.
Inside of this jruby-launcher code,
you have a bunch of C++ and header files.
And just to pull one of these files,
there was this copyright from Sun Microsystems
at the top of the main jruby CPP file,
and its last copyright was 2010.
It's kinda old,
and Sun Microsystems doesn't even exist anymore
as a company, so there's that.
And if we look at some of these commits,
some of these files, like that CPP file
hasn't been touched in six years.
So you can imagine how fun it must be
to maintain this thing.
So a coworker of mine, Joe Kutner,
started this project called njruby,
and essentially it's the entire jruby-launcher rewritten
onto the top of mruby-cli.
So inside of it, he essentially rebuilt all this stuff
using a mix of Ruby and C code,
and he built some lib JBM bindings inside of mruby
to actually interact with the JBM itself,
but all the option parsing and stuff is written in Ruby.
Which is definitely much nicer for a Rubyist to do
than to do all that string manipulation in C++.
And one of the also great things about it is
he has unit tests, so this a a test folder
of all unit tests to test all the option parsing.
I don't believe the jruby-launcher code has any unit tests,
they're all integration tests.
But in mruby-cli we can have both.
So it's really great to see projects like that come up,
especially for a project like jruby,
I'm sure a lot more people will be willing to get involved
in njruby that in jruby-launcher,
to actually contribute back and be able to understand
and see what's going on.
So what can you do with mruby-cli?
How do you fit into this ecosystem
of stuff that we're building?
So one of the things is, like I said,
we started it early this summer, which means
the community's really young.
Mruby itself is only, like, five or so years old, I think,
since its inception, publically.
But that also means that,
although it doesn't have
a ton of commits that are flowing through all the time,
the mruby GitHub...
Mruby's on GitHub, and we support pool requests and things
on the MRI project, which is still on its version,
so for a lot of Rubyists,
this is a lot more familiar to work with.
And as you can see, Matts does read the pool requests
and comments on stuff, which is great
to be able to interact with Matts and other people
on this project.
It's fairly active project, but it's not
so trafficked that you can't follow through.
There's only a few commits that usually get into master
a day, if that, and people who are
active on the project are fairly active.
Mruby 1.2.0 just got released this morning by Matts,
and I prepped a release this morning as well
for mruby-cli, so before we used to depend
on master, on mruby,
which was not the greatest thing,
because if something in master came out,
it could potentially break your build,
which was not ideal for me.
So we depend on a lot of new features,
but now that 1.2.0 is out, we can now
lock it down to the release of 1.2.0,
which means future versions will be a lot more stable.
So you can go to the mruby-cli project,
and if you go to the releases page,
there's binary for every single...
Or for at least OSX, Linux, and Windows,
32 and 64 bit binaries that you can download,
and use, and you just need to put it on your path,
and it will be a self-contained thing that works.
So now that you've seen all this stuff,
how do we actually go and build a binary?
Like I was talking about downloading,
go download the mruby-cli binary.
If you don't have any of the Docker stuff set up,
you need to install the Docker toolbox to get
Docker and Docker Compose.
And then mruby-cli setup will go through
and generate a new application,
and then go ahead and modify it.
One of the things that I got,
I think, one of the first C++ intro CS classes I took,
the assignment was, like, make a calculator.
Like, make addition and all that stuff work,
or maybe build the HP calculator
that Aaron was talking about in his talk.
Do all that string manipulation in C...
And then you just run this docker-compose
compile command, and it should go and fetch
the containers for you from Docker Hub,
if you don't have it, so you don't need
a separate thing for that.
And then you basically just rinse and repeat this cycle
of modification, recompilation.
And you'll see that once you have it
actually compiled the first time.
Subsequent compiles are actually relatively quick and fast.
And I'd love to actually hear about
anything that people built.
We have a few projects that people have been working on,
but no matter how small, or if it's large,
that you're building, I would love to engage and talk
and see what works or what doesn't work for you
on this project.
This is a huge passion project of mine,
and I really enjoy working on it,
so I'd definitely love to engage there.
And I appreciate the fact
that our community as a whole is really awesome,
so we have stuff like Friday hugs,
things like Ruby karaoke.
The fact that our community enjoys doing all this stuff,
I want to continue to build things in Ruby,
and I hope you do,
and I hope we can help remove technical limitations
of not choosing Ruby as the technology for doing stuff.
So let's go out there and build things in Ruby.
How much time do I have?
So the question was is the bytecode spec published anywhere?
I don't believe it is, but Matts
would definitely know better.
I don't know if he's here.
I don't think he is.
You should ask him during the Q and A
at the keynote, the closing keynote, since he's not here.
So the question was, the stuff you penned on in the test,
if you're able to separate that from the final binary.
The test build is a specific, separate build
that's specialized inside of mruby,
so the tests that you write are not actually
in the final build that you produce.
And then there's an add test dependency
that got added recently, in 1.2.
So that allows you to add dependencies inside
of your mruby project, in general,
that won't get produced in the final build.
That feature's relatively new,
so I ran into some issues with it,
but supposedly it's fixed now.
So you should be able to have a test specific thing
that runs, that isn't included.
And often times, the first build you have
is usually a host build.
That's the thing that you run on your local machine.
And in that build, I have debug and other option sets,
so you can see sack trace and back trace of stuff.
So then, even if the target build was the same as my host,
I would have a separate target build
that didn't include all that stuff.
So the question was is the Heroku toolbelt gonna use this?
The answer's no.
I'm not involved with the Heroku toolbelt heavily anymore,
and that ship kind of has sailed already
with the Go stuff.
If you're already happy using some other language,
there probably isn't a huge reason to
then port your entire project back over.
Like, a reason might be maybe you are in
a company that has a bunch of people that are Rubyists,
and it would be easier for other people to get involved.
But we have someone here who's in charge of the CLI,
and they do both Ruby and Go,
so they're comfortable just continuing
to work on the Go stuff.
So the question was when you package up in mrubygem,
it looks very similar to a Rubygem,
and is there any compatibility between the two?
I mean, I think even the file names aren't the same
between the gem spec, like it's bla bla dot gem spec,
and then in Rubygems it's mrb gem dot rake.
And it's the same name for all the mrbgems.
I mean, I imagine you could probably produce
a package that had both of those things,
but I would imagine you would run into a lot of issues
for most people that there's many more libraries
that you need inside of an mruby project.
But I'm sure you could conceive some thing
that mruby gem dot rake pulled stuff in
that was missing, that wasn't in your gem spec.
But I haven't seen anyone actually use that,
but I don't think it's out of the realm of possibility.
Cool. Thanks everyone.