Ilya Bylich

Read this first

lib-ruby-parser

Contents

  1. Intro
  2. Implementation
  3. Future improvements
  4. C bindings
  5. Cpp bindings
  6. Node bindings
  7. WASM
  8. Final thoughts

Intro

So, I’m ready to announce that I’ve finished working on a new Ruby parser. It’s called lib-ruby-parser.

Key features:

  1. It’s fast. It’s written in Rust and it’s slightly faster than Ripper. The difference is about 1-2% on my machine.
  2. It has a beautiful interface. Every single node has its own type that is documented. For example, take a look at CSend node that represents “conditional send” like foo&.bar. Here’s a list of all defined nodes. Both Ripper and RubyVM::AST have no documentation of their AST format. whitequark/parser has a great documentation, but its AST is not “static”.
  3. What’s “static AST”? By saying that I mean that if documentation says that “N is not-nullable” then it’s true no matter what. whitequark/parser does a great job, but the nature of dynamic...

Continue reading →


Evaluating Ruby in Ruby

Evaluating Ruby in Ruby

TLDR

This article is about instruction sequences and evaluating them using pure Ruby.

The repo is available here.

Is it a Ruby implementation?

No. It’s just a runner of instructions. It is similar to MRI’s virtual machine, but it lacks many features and it’s 100x slower.

Can I use it in my applications?

Of course, no. Well, if you want.

Does it work at all?

Yes, and it even passes most language specs from RubySpec test suite.

How Ruby evaluates your code.

Well, I think I should start with explaining basics. There is a plenty of articles about it, so I’ll be short:

  1. First, Ruby parses your code into AST (parse.y)
  2. Then, it compiles it into instruction sequence (compile.c)
  3. And every time when you let’s say call a method it evaluates these instructions. (insn.def, vm_eval.c, vm_insnhelper.c)

Long time ago there was no YARV and Ruby used to evaluate AST.

...

Continue reading →


My favorite parts of Ruby

Disclaimer 1 first of all I’d like to say that I really like Ruby. I write a ton of Ruby code every single day and I prefer it over other languages. Please, do not take it seriously, Ruby is nice, and this post is mostly a joke.

Disclaimer 2 I’m not going to cover popular things like flip-flops (thanks God they are deprecated in 2.6.0).

I was thinking for a while which item should go first, but finally I had to give up. I think all items are funny.

Regexp ‘o’ flag

I don’t even know if there’s anyone in the world using it. o flag is a very, very magical thing that “freezes” a regexp after parsing:

pry> 1.upto(5) { |i| puts /{i}/o.source }
1
1
1
1
1
pry> 3.times.map { |i| /{i}/o.object_id }
=> [70135960411140, 70135960411140, 70135960411140]

That’s a hacky way to define an inline regexp as a constant. It is a constant because its value is constant (object_id returns the same value)...

Continue reading →


Ruby Marshalling from A to Z

Marshalling is a serialization process when you convert an object to a binary string.
Ruby has a standard class Marshal that does all the job for serialization and deserialization.
To serialize an object, use Marshal.dump, to deserialize - Marshal.load or Marshal.restore.

marshalled = Marshal.dump([1, 2, 'string', Object.new])
 => "\x04\b[\ti\x06i\aI\"\vstring\x06:\x06ETo:\vObject\x00"

Marshal.load(marshalled)
 => [1, 2, "string", <Object:0x00000002643000>]

This article explains the format of marshalling and shows how to write a pure Ruby marshalling library
compatible with the standard Ruby implementation.

The gem

Let’s try to make a pure Ruby gem that is compatible with standard Marshal class.

$ bundle gem pure_ruby_marshal
$ tree pure_ruby_marshal
pure_ruby_marshal
├── bin
│   ├── console
│   └── setup
├── CODE_OF_CONDUCT.md
├── Gemfile
├── lib
│   ├── pure_ruby_marshal
│   │
...

Continue reading →


HandlerSocket + Ruby

What is HandlerSocket (HS)

  • a plugin for MySQL
  • which allows you to read/write to MySQL
  • and gives you a separate connection to MySQL
  • and doesn’t allow you to run SQL queries
  • but allows to run simple CRUD queries only using indexes

HandlerSocket query language is very simple (I’d even say it’s primitive), but it’s much faster than MySQL’s one. Though, of course, there are some limitations. Interested?

Installation

You already have it if you are using Percona Server or MariaDB. If not, install it from the source.

To activate the plugin, run:

INSTALL PLUGIN handlersocket SONAME 'handlersocket.so';

Configuration

My configuration is the following:

 [mysqld] section
 the port number to bind to for read requests
loose_handlersocket_port = 9998
 the port number to bind to for write requests
loose_handlersocket_port_wr = 9999
 the number of worker threads for read requests
...

Continue reading →


Saving execution context for later debugging

Consider the following situation: you’ve got an exception in production. Of course, all of us are good developers, but you know, sometimes *it just happens. What do you usually do to get some information about the error? You just grab the request parameters to test it locally, right? Then I might have a better solution for you: dump your memory once an error happens and restore the dump later to debug it.

Binding

In Ruby the best candidate for doing this is Binding class. If you have a binding, your can easily do some debug using well-known pry gem. But the binding itself cannot be dumped (at least not, using default Ruby tools).

How to get a local binding? Just use binding. How to get a binding from an object? Just add a method to you class:

class MyClass
  def local_binding
    binding
  end
end

MyClass.new.local_binding
 => <Binding>

Binding encapsulates the execution context...

Continue reading →


Wrapping JavaScript library with Opal

Introduction

The task that is solved here is not real, but it’s still a good example of (probably?) real work with Opal. I could choose some complex enough JavaScript library and write a simple wrapper using Opal, but there’s no fun. Instead, let’s write a wrapper for existing rich client-side application (it may show you how to wrap your existing application logic). Well, wrapper for something like a client-side scheduler may sound boring, so I’ve chosen a JS-based browser game called BrowserQuest written by Mozilla, and I’ll show you how to write a bot for it using Opal.

Opal

There are so many posts about Opal, so I’m just going to say “it’s a Ruby to JavaScript” compiler, that’s enough.

Environment

First of all, we need something that runs the game and injects a bot into the page. I, personally, while writing integration tests (this is the place, where we usually face to web...

Continue reading →


Capybara and asynchronous stuff

In this entry I will try to cover the following aspects:

  1. Running asynchronous code in a web driver
  2. Making the call synchronous
  3. Wrapping it into some common solution
  4. Advanced example - working with IndexedDB from Capybara

What is Capybara, Poltergeist and PhantomJS?

PhantomJS

First of all, we need to know what is PhantomJS. I would say it’s a ‘tool that acts like a browser but can be controlled from outside using simple command interface’. In more common words, it’s a web driver. It’s a full-featured WebKit (an engine of Chrome/Safari/few last versions of Opera and other browsers), but in console. You can use it for scripting, automating or testing.

Poltergeist

Poltergeist is a Ruby wrapper for PhantomJS. Usually you write the code for PhantomJS on JavaScript, with Poltergeist you can run it on Ruby.

Capybara

Well, I’m pretty sure you know what it is. It’s a test framework. And...

Continue reading →


Apipie - amazing tool for documenting your Rails API

This article is about for Apipie gem (https://github.com/Apipie/apipie-rails) which provides a DSL for documenting your API. I will try to cover features that I personally use on my project.

Comparing to other tools for generating API documentation (yardoc, sdoc) I would say that the main thing that you gain with Apipie is that your documentation is a real ruby code, so you can write computations, concerns etc.

Here is a simple example of how it looks in code:

class UsersController < ApplicationController

  resource_description do
    formats [:json]
    api_versions 'public'
  end

  api :POST, '/users' 'Create user'
  description 'Create user with specifed user params'
  param :user, Hash, desc: 'User information' do
    param :full_name, String, desc: 'Full name of the user'
    param :age, Fixnum, desc: 'Age of the user'
  end
  def create
     Some application code
  end
end

...

Continue reading →


What is Ruby DSL

As you already know, DSL means domain-specific language. It’s like a language in a language. Here are some examples that we use every day:

class User
  attr_reader :name
end

class Profile < ActiveRecord::Base
  has_many :posts
end

class ApiController < ActionController::Base
  before_action :authenticate
end

But all these examples use rails-provided DSL, how about your own? First of all, you should know that all these methods (attr_reader, has_many and before_action) are actually class-methods of Module, ActiveRecord::Base and ActionController::Base. So you can write something like:

class TestClass
  def self.my_dsl_method(dsl_method_arg)
    puts "dsl method called with {dsl_method_arg}"
  end
  my_dsl_method :some_argument
end

And the body of my_dsl_method can be more dynamic then just printing a string. It can define methods, execute some calculations, etc. Less words, more...

Continue reading →