We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Evaluate Ruby Without Ruby

00:00

Formal Metadata

Title
Evaluate Ruby Without Ruby
Title of Series
Number of Parts
67
Author
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language
Producer
Production PlaceCincinnati

Content Metadata

Subject Area
Genre
Abstract
Have you ever wanted to implement a tool that can be configured by Ruby code? You may think such tools require MRI, JRuby or Rubinius to evaluate the configuration. But that's not true! Let's see how we can build a tool that evaluates Ruby without dependency on Ruby interpreter using mruby.
14
Thumbnail
44:49
34
Thumbnail
46:50
58
Computer animationEngineering drawing
Software developerLocal GroupCommon Language InfrastructurePortable communications deviceIntegrated development environmentCommon Language InfrastructureSoftware developerGroup actionCartesian coordinate systemService (economics)Product (business)Gastropod shellECosVery-high-bit-rate digital subscriber lineWaveTrailComputer animation
Portable communications deviceBuildingCommon Language InfrastructureTime domainFormal languageLatent heatTerm (mathematics)Server (computing)Group actionFormal languageTerm (mathematics)Cartesian coordinate systemInstallation artProblemorientierte ProgrammierspracheDomain nameSheaf (mathematics)XMLComputer animation
Sanitary sewerGroup actionAbstractionTime domainLatent heatConfiguration spaceServer (computing)Process (computing)Service (economics)Sheaf (mathematics)Very-high-bit-rate digital subscriber lineDistribution (mathematics)MassInjektivitätComputer animation
ImplementationComplex (psychology)Group actionProblemorientierte ProgrammierspracheResultantImplementationInstance (computer science)Interactive televisionSocial classData storage deviceDressing (medical)CASE <Informatik>Computer animation
Common Language InfrastructurePortable communications deviceBuildingPerformance appraisalInstance (computer science)CASE <Informatik>Computer animation
Integrated development environmentOperations researchSoftware maintenanceDistribution (mathematics)Server (computing)Web applicationSoftware maintenanceBootstrap aggregatingDistribution (mathematics)Integrated development environmentOperator (mathematics)CASE <Informatik>Server (computing)MultiplicationScripting languageSoftware developerScaling (geometry)Service (economics)Computer animation
Integrated development environmentSoftwareIntegrated development environmentCuboidDistribution (mathematics)Bootstrap aggregatingComputer programmingSoftware developerMultiplication signBootingVery-high-bit-rate digital subscriber lineRadiusPoint (geometry)User interfaceComputer animation
BuildingLangevin-GleichungImplementationComputer hardwareSoftwareScripting languageLink (knot theory)System callCloningFormal languageSoftwarePerformance appraisalComputer hardwareScripting languageFormal languageImplementationRepository (publishing)BuildingEinbettung <Mathematik>Limit (category theory)Compilation albumDirectory serviceSemiconductor memoryBitVery-high-bit-rate digital subscriber lineSystem callPairwise comparisonView (database)XMLComputer animation
String (computer science)ResultantScripting languageFormal languagePerformance appraisalSoftwareLattice (order)WordMoving average
SoftwareIntegrated development environmentBinary fileSoftwareIntegrated development environmentCASE <Informatik>Binary codeLibrary (computing)Content (media)BootingComputer animation
Common Language InfrastructurePortable communications deviceBuildingImplementationFormal languageConfiguration spaceData managementSingle-precision floating-point formatBinary fileScripting languageCloningBuildingContent (media)Portable communications deviceVery-high-bit-rate digital subscriber lineMereologyScripting languageConfiguration managementDirectory serviceRange (statistics)Binary codeFormal languageSingle-precision floating-point formatIntegrated development environmentSystem callCommon Language InfrastructureCompilation albumComputer animation
Scripting languageConvex hullFormal languageString (computer science)Scripting languageRing (mathematics)Gauge theoryStructural loadComputer hardwareComputer animation
Operations researchImplementationFormal languagePerformance appraisalResultantPerformance appraisalPointer (computer programming)Formal languageImplementationFunctional (mathematics)Operator (mathematics)VideoconferencingVery-high-bit-rate digital subscriber lineData structureComputer animation
ImplementationResultantCASE <Informatik>Right anglePerformance appraisalComputer animation
ImplementationResultantBlock (periodic table)Group actionParameter (computer programming)Attribute grammarInstance (computer science)Structural loadSocial classVideoconferencingPerformance appraisalDressing (medical)
Bridging (networking)Integrated development environmentError messageImplementationBridging (networking)WordError messageConnected spaceChainReal numberCASE <Informatik>View (database)Computer animation
Bridging (networking)Integrated development environmentError messageFormal languageBinary fileImplementationOperations researchComputing platformCommon Language InfrastructureBuildingVideoconferencingBoilerplate (text)Default (computer science)Computer programmingGastropod shellKernel (computing)Motion captureShared memoryException handlingKernel (computing)Standard deviationWritingFormal languageLibrary (computing)Operator (mathematics)Data conversionMotion captureBinary codeServer (computing)Multiplication signDefault (computer science)ImplementationFerry CorstenBoilerplate (text)Computing platformInstance (computer science)BuildingSinc functionCodeDirectory serviceMathematicsFlow separationStandard errorCartesian coordinate systemIntegrated development environmentSoftware maintenanceWeb pageMereologyHash functionWordBootstrap aggregatingScripting languageRankingGauge theoryFocus (optics)Revision controlComputer programmingPhysical systemRight angleCorrespondence (mathematics)Semiconductor memoryVideoconferencingExtension (kinesiology)Electric generatorTheoryCompilerSphereCASE <Informatik>Computer animation
ImplementationOpen setMotion captureImplementationStandard errorBuildingCASE <Informatik>Functional (mathematics)Computer configurationError messageMotion captureString (computer science)Message passingFormal languageLimit (category theory)Bayesian network
Electronic meeting systemCommon Language InfrastructureIntegrated development environmentBinary codeUser interfaceMobile appComputer fileIntegrated development environmentCartesian coordinate systemOperator (mathematics)Modal logicComputer animation
Core dumpIntelCommon Language InfrastructurePhysical systemRevision controlTotal S.A.Multiplication signSinc functionRevision controlImplementation2 (number)Computer animation
Common Language InfrastructureCodeImplementationConfiguration spaceIntegrated development environmentBinary fileFormal languageData managementHill differential equationMereologyIntegrated development environmentConfiguration managementFormal languageCodeBinary codeBootstrap aggregatingBayesian networkRight angleVery-high-bit-rate digital subscriber lineMeta elementComputer animation
ImplementationMotion captureOpen setLibrary (computing)
Row (database)Coma BerenicesJSONXML
Transcript: English(auto-generated)
talking about evaluating Ruby without Ruby.
Let me introduce myself. My name is Takashi Kokubun, working at Cookpad, which is a company in Japan that hosts recipe sharing service, cooking recipes. I'm working as a developer productivity group
at Cookpad Inc. The recipe sharing service is Rails application, and we provide zero-parent environment for Rails applications. Today's topic is Ruby DSL. I implemented the tool with mRuby,
and I'll show you why I did that. Introduction to mRuby and two ways to build portable CLI apps configured by Ruby DSL. So first, talking about Ruby DSL.
DSL is domain-specific language, which is a language specialized to a particular application domain. Ruby DSL is a DSL defined in the terms of Ruby language. For example, this is Ruby DSL I am talking about today.
This is, first package is installs nginx, and this can work in both CentOS and Ubuntu. Next section is service nginx, and this enables nginx start up on a server
and start nginx process. As you can see, installing nginx and starting nginx is abstracted away for some distributions, and we can configure it with Ruby.
It's boring if we write this in JSON, because you are Ruby, you are happy to write this configuration. So how is Ruby DSL implemented? Have you ever implemented Ruby DSL?
Thank you. For example, if you want to evaluate this package nginx, and returns package and nginx array, the simple implementation is like this. Defines DSL cross that has package method,
and when package method is called, it stores the package name to result. We can get results from the DSL's result method.
The more complex case, if package has nested DSL, like action, we specify action install, specifying install interaction to nginx package.
To implement this, you have to create package class, and you can evaluate the nested action API in package class, and you can do that by instance exec method.
So how is Ruby DSL implemented? Usually, Ruby DSL is implemented with MRI, using instance eval or instance exec, et cetera. But we wanted to evaluate Ruby DSL without MRI. Why?
Let's have a look. The second topic is our motivation to evaluate Ruby DSL without MRI. Ruby DSL use case at Cookpad. We developed development environment bootstrap script
for Mac OS and Linux. We use not only Mac OS, but also Linux distributions to develop web applications. We wanted to use Ruby DSL to simply describe operations for multiple OS distributions, like I showed you before.
For maintenance costs, we use the same Ruby DSL as a server provisioning tool we developed and use, which is called Itamae. Itamae means chef of sushi. So the DSL is inspired by chef,
the server provisioning tool. For example, this is DSL of Itamae, and first, this describes installing memcache-d and PostgreSQL. If you write this DSL, you can install memcache-d
and PostgreSQL by Itamae to Mac OS, and also, you can install this to Ubuntu by the same DSL. But there is a problem. Our problem to bootstrap development environment
using MRI is there are difficulties to use MRI on initial environment. For example, Mac OS, it ships Ruby 2.0.0. It is not maintained now, and it is shipped with latest Mac OS,
so we can't use maintained Ruby. For Linux, most Linux distribution doesn't ship MRI out of the box. So we don't want to manually install MRI prior to bootstrap, because it is a first step
of bootstrapping development environment. If you use MRI for user's environment, you have to care about how a gem is set up every time you run Ruby DSL to bootstrap development environment. Our Ruby on MRIs already installed
is a gem installed to MRI currently selected by RBM. And packaging Ruby or gem commands to run just one gem is little overkill. It's cost to maintain. And how can we then, how can we live in dependency of MRI?
For the reasons I talked all about, told to you, we want to develop dependency of MRI. All these programs are resolved if it doesn't depend on MRI. And can we embed Ruby VM into our software?
So let's talking about MRB. This is, I'll talk about MRB. MRB is a lightweight implementation of Ruby, and which is embeddable in hardware and software.
If you embed MRB to hardware, you can compile Ruby scripts to very small binary, and you can run it on limited resource hardware. If you embed software, you can learn Ruby scripts from your software.
It is not written in Ruby. So today's topic is software embedding of MRB. And if you embed MRB, you can evaluate Ruby scripts from any software, even if it is not written in Ruby.
And it allows us to build a software evaluating Ruby DSL and independent to MRI. As I showed you before, normal tool that runs with DSL is implemented with MRI,
but if you use MRB, you can make it independent to MRI. So how to use it? How to embed and use MRB? Firstly, you have to get from MRB repository and just run make command.
And by executing make command, leave mruby.a is generated in that directory, build host directory, and it should be linked to your software to use MRB.
And then call mruby-capi, or use its binding for a language you use. If you use non-C language, you have to write a binding to call the C API. This is example to embed MRB to software
and calling the C API. Firstly, you have to initialize mruby-vm by mruby-open, and after the initialization, you can evaluate Ruby scripts like this
by calling mruby-rollstring API of mruby. You can run this hard-word join script and you can get the result of Ruby scripts as a C string array of characters. And you can print the hard-word string in C language.
So now we can embed mruby into our software. Is it enough? No. Our use case is development environment bootstrap, and we should also care about dependencies
other than MRI. So we want to build it as a single binary, which does not depend on other dynamic libraries, and there are some good ways to do that. I tried two ways to do that, so let's compare them. The main contents of today,
building portable CLI apps configured by Ruby DSL. I introduced two ways to build portable CLI apps configured by Ruby DSL. The first way to do that is go mruby. Using mruby only for evaluating Ruby DSL
and implements other parts in Go language. The next is mruby's CLI, which is introduced today by Eric, and this way I implemented both Ruby DSL and others using mruby.
So I experimentally implemented the two I introduced before, which is configuration management tool, Itamae. So let's compare them. The first way to do that is go mruby.
Using Go, you can compile Go script into single binary, so embedding mruby to Go language, you can build single binary, and you can run Ruby scripts from the single binary.
So this example is using go mruby, and which is called Itamae Go. You can see that a real example at my GitHub, kokubens, like itamae-go. How to run Ruby scripts from Go? First, again, you get grown mruby and make mruby.
And if you want to use Ruby mruby from Go mruby, you have to copy the mruby to Go mruby's directory, and importing the directory and call mruby APIs
by Go language. This is example of using mruby from Go language. First, you have to initialize mruby VM like the C language, and mruby load string is in Go, which is a load string in Go language.
You can do the same thing in C language, a hardware join script, and you can evaluate that and get the Go string from the load string value API.
So how to implement Ruby DSA in Go? If you use Ruby for all implementation, you don't care about converting the data structures, but to implement I operations in Go, it is necessary to get data for Go
from an evaluation result of Ruby DSL. I implemented the method for Ruby DSL in Go language. First, define method. It is necessary to call define method, and first define function named package.
It is empty for now, and that returns nil. And then, for simple case of the DSL, we want to get the result of Ruby DSL evaluation, and the result is the right package resource struct.
We can get package resource struct and its name from this API. And the complex case, then if block is given to the package DSL,
the arguments is increased to two. By checking the number of arguments, initializing a package class, and call the block by instance eval,
and calling the methods attributes and actions or any other attributes, you can get the result of Ruby DSL evaluation. The package is implemented in Ruby.
You can define any class in Ruby by mrb load string, so this package that's new was defined in Ruby. But as you can see, it was a little hard to maintain. Writing bridge to connect Ruby and Go words is really boring,
and checking errors for all Ruby method calls is boring. All method calls in this example returns underscore, but in real use case, you may check the all errors from all method chains.
It's very boring. And you've got to use three languages, because to define package class, you have to write Ruby, and the conversion is Go language, and mrb gem is,
the base of mrb gem is C, so you have to use three languages for maintaining this library. And you need to prepare environments for cross-compiling by yourself. The next example has a very useful environment for cross-compiling,
but if you use Go mruby, there are so few examples using this, so this is how to cross-compile and linking the library to the Go script and cross-compiling it. But why do we need Go language?
Why I choose Go language was, the purpose of that was to make it as a single binary and to implement IO operations for developing environment bootstrap. In this case, other parts of ML, sorry,
Ruby DSL is, all other parts are implemented in Go language, so it is very easy to implement IO operations, because there are many package, sorry, standard libraries to implement IO operations in Go language,
and so can we achieve them without Go language? If we write, if we implement, if we can implement IO operations in C, you can do that in mruby, too. So try mruby-cli. The next example is using mruby-cli,
so I implemented the next example called mItamai, which is alternative implementation of the server provisioning to Itamai and the former Itamai Go, which is actually maintained by me for now.
And it is single binary and built with mruby-cli, and written in pure Ruby, because it uses mruby-cli, and all of the parts are implemented in Ruby language. You can see that code in my GitHub.
Then, what is mruby-cli? mruby-cli is a cross-compiled platform to build CLI apps using mruby. You can see that on Terrence Reese's mruby-cli repository, and Eric gave a talk building maintainable
command line tools with mruby this morning. If you missed it, watch the video reader. So how to use mruby-cli? It is very simple. Downloading mruby-cli command from the mruby-cli releases page and generates boilerplate to implement the tool
by mruby-cli-haves application name, and change directory to that, and run docker-compose run-compile. You can get binaries in that directory. So just executing these commands,
by just executing these commands, you can build a single binary. That is not dependent on MRI, and implement it with Ruby. How to implement Ruby DSL with mruby-cli?
It is almost the same way as MRI, but something is different in mruby-cli. You've got to add some mruby gems to call methods which is not provided by default. In mruby, since mruby is very small implementation,
some default features in cub are omitted. mruby, I used mruby-eval for instance evil, and mruby-object-extension for instance exec.
So what is mruby-gem? It is like Ruby gem for MRI, but unlike mruby-gem, it's compiled together when building mruby. So the docker-compose run-compile, when you execute it,
mruby-gem is compiled into the same binary. So you can use it without adding dependency to the binary. Some of the features in MRI are separated to mruby-gem, so if you miss some of the features in mruby, you can search it from mruby-gem.
To implement the server provisioning tool, since it was implemented originally in Ruby, I wanted to port existing standard libraries or Ruby gems to mruby-gem.
It's very easy when they are written in Ruby, because most features required by Ruby programming, except keyword arguments, are available at existing mruby-gems. And I created some mruby-gems to implement M8MI, which is share words and hash gem.
Then, but if the methods are not implemented in Ruby, it is a little hard to use that. If the method is written in C, you have to write C to implement the mruby-gem.
Some of IO operations in mruby already existed, but I wanted to use capture standard out and the standard error, the exit status separately. There are no Open3 library and kernel spawn methods,
so it is very hard to achieve the capturing standard out and standard error and exit status at the same time. It is necessary to write C rank is to implement kernel spawn command, spawn method. This is the implementation of spawn method
in my mruby-gems, mruby Open3. Firstly, this method, this function calls fork, and it redirects standard out and standard error. So, as you can see, this implementation is very limited, use case of spawn command, spawn method.
Original spawn method has very, very, very various options, and it is hard to implement all of the features so I implemented original spawn for this mruby Open3.
Writing the methods in C language, writing the methods in C language, we could build Open3 Capture3 methods using the API. As you can see, it calls out and error option
in string, but it is only, the spawn method has only these methods, these options. So it was a little easier, but the spawn method is incomplete. So, you may, if you may not familiar with C language,
you think it's hard to implement apps with mruby-cli. I think, yes, it's hard a little when the necessary mruby-gems are absent, but there are great merits to build apps using mruby-cli.
The first merit is you can distribute applications easily. That single binary are not depending on user's environment like gem command or ruby command, and which can be cross-comparable easily by the docker file provided by mruby-cli. The next merit to using, to use mruby-cli
is the start-up of the command is very fast. If you use MRI to implement the original command, it takes 700 milliseconds to execute very simple version command, but if you implement it in mruby,
since it's already compiled, it executes very fast. It takes only 23 milliseconds. It is 33 times faster than original MRI implementation. And the very important part is that it's very maintainable.
No bridging code like Go and Ruby words, or I'm very happy to write all indentation in Ruby if you are Rubyist, and this is conclusion.
To simplify development environment bootstrap, I made a configuration management tool configured by Ruby DSL as a single binary using mruby, which is m-irimae on that GitHub, and there are two ways to build a tool configured by Ruby DSL as a single binary.
If there is no reason to use Go language, if there's a reason, use Go mruby, and otherwise mruby-cli is recommended for that purpose. That's all, thank you.
Any questions?
The question was, sorry, I'm quoting, can you port, can I port the part I write in C language to mruby-jam? I exported it as mruby-jam mruby-open3.
Since it is, the spawn method is in, is used only by mruby-open3 library. I made it in the mruby-open3 mruby-jam. So it is already ported to mruby-jam.
No other questions? Okay, that's all, thank you.