Digging ruby from Roda, a rack based web framework.

Recently, I have been looking for a good ruby project to contribute to. Its rather a personal journey to this world of programming fantasies. My quest was futile, not because there aren’t good ruby project out there, but because I was doing it the wrong way. A better way to do something, is to have a reason why, I had a solution looking for a problem. It had to be a problem looking for a solution.

It came to me that, I was not that good in ruby , and that  I was wasting my time on “cargo cult stuffs”. I thought its about time, that someone has to ask why, and also figuring out how things really work. I’m talking this from my point of view, because I’m writing this in a place where people are afraid of themselves, I once spent a good chunk of time just trying to find a gem that can safely open and read files, at least I didn’t trust the ruby standard library, not because its inefficient, but because I lacked the knowledge to understand why, and how things really worked.

Rails is famous, and so is Sinatra in the ruby world. All have one thing in common, they are based on Rack, an abstraction layer to the web servers. This is not a rack tutorial, and its not like a tutorial at all. Its my journey, to dissect another Rack based web framework in called Roda . Its a new framework, once a fork of cuba(yet another framework).

I’m going deep, inside the source code,to discover the way ruby is used. Along the way, I hope to learn as much in ruby as in rack infrastructure from roda’s perspective. As I have said earlier, its a depth first dig, its more like a code review effort, in pursuit of understanding ruby and not roda.

The Code organization.

directory hierarchy

I am going to focus first on the lib folder(where the real code is), the rest will be explained later in future posts. The lib folder is organised as follows,

-lib
  -roda
    -plugins
      -all_verbs.rb
      -default_headers.rb
      -error_handler.rb
      -flash.rb
      -h.rb
      -halt.rb
      -header_matchers.rb
      -hooks.rb
      -indifferent_params.rb
      -middleware.rb
      -multi_route.rb
      -not_found.rb
      -pass.rb
      -render.rb
      -streaming.rb
    -version.rb
  -roda.rb

Roda is a pluggable framework, meaning that it works mostly using plugins, the default plugin class being Roda::RodaPlugins::Base . What's interesting with Roda is that, instead of using modules at the top level for namespacing, the framework exposes the Roda class at the top of the hierarchy.

The directory structure is clean, the base logic is inside roda.rb and plugins are in the plugins diretory. Meanwhile, we start with the file roda.rb and the fact that it starts by definingclass Roda makes me ask myself why and can’t wait to find out.

The Roda class

Now its time to go line by line and see what really happens inside. I will be moving from top to bottom, trying to figure out what relly happens and why.

At the top of the file we have the following code

require "rack"
require "thread"
require "roda/version"

Roda is rack based, and hence we need the rack library, the thread library is for threading but I’m not quiet sure where it is used maybe Its somewhere inside but we will find out. roda\version holds the string which has the version number, we will know much when we reach that file later.

class Roda
  class RodaError < StandardError; end

The file starts with defining the Roda class, and that was a bit a surprise to me. I have been using module to organize my code but why class instead of a module ?

A quick research took me to the concept of Metaprogramming, I won’t go deep into metaprogramming,  I am just interested in ruby metaprogramming and the notion of modules and classes seems to look like a file system where there are directories and files hence the other concept of namespacing.

Digging on namespacing

We have to visit the ruby object model to find our answers, metaprogramming has been a hot topic in the ruby world especially the extensive use of metaprogamming in the rails framework, which has brought the powers of ruby on the limelight.

The following is my understanding of the ruby object model.

The ruby Object model is like a file system, organized in directories(class and modules) and Files(the code). It comprises of two components of interest. class and module. Just as the directory with nested sub directories,the object model is in a hierarchy where top level can have many other sub levels.

That is where the concept of inheritance kicks in. Inheritance,in ruby is like any other programming languages(In definition),but it is slightly implemented differently. the keyword class is used to define a class, and module is used to define a module.

Class is a sublass of Module, so its more like an enhanced module, to be specific, a Class defines three extra instance methods new(), allocate() and superclass().

  • new(): helps to create objects
  • allocate(): just as new()
  • superclass(): returns the superclass

So, we can visualize the object model up to Class as follows

- BasicOject
- Object
- Module
- Class

We need a living example to see what that means.Time to grab the console and start typing stuffs. I assume if you are a ruby fan, you already know about irb or interactive ruby. there is a very sweet alternative called pry. Just in case you haven’t tried pry yet do thee following in the command line.

Install pry

gem install pry

Run pry

pry

Okay, now inside your pry session #### what is the superclass of Class Class.superclass #=> Module

What is the superclass of Module

Module.superclass #=> Object

What is the superclass of Object

Object.superclass #=> BasicObject

What is the superclass of BasicObject

BasicObject.superclass #=> nil

Then, to be precise, a class can be used with a module interchangeably. But, in good practice, the question will arise, when to use one of them? the answer to the question is, what do you want to do with that piece of code?

  • If you want it to be inherited or subclassed then use a Class
  • If you want a means to store more constants (literally classes and modules are constants), use modules.
  • If you want to write methods that will be included in a class, the use a module.

Up to this point, I think I know why at the top of the hierarchy lies a Roda class. Its because, it will be subclassed with other user defined class to create robust web applications.

This means, you create a roda based app like this, let us say you want to create My Awesome app, you can define your app as

class MyAesomeApp<Roda
# your logic goes here
end

Okay lets keep pn moving, inside the Roda class now, from the above code snipped we see a one liner class definition. And I won't go into details about error handling, but I’m quite sure that is not of interest at the moment.

Ruby, happens to be not indentation sensitive like Python, a chunk of ruby code ends when the end keyword is encountered which means , you can write a good one line app without any execution troubles. Because we can does not mean we should.

I was wondering, what about the expressions inside the chunk of code?, how are they arranged to fit in a one liner? Well, the answer is the ; semi colon symbol, the symbol is used to indicate the end of a ruby expression.

I needed to prove this theory(yeah I was skeptical to believe), thank God there is pry to test it out.We are going to create a class foo with attr_accessor bar and add a custom function that prints the value of bar in a single line of ruby code.

Fire up our pry(If you havent already). And here we go.

class Foo;attr_accessor :bar;def initialize; @bar="bar-fu" end;def foo; p @bar end end #=> nil

foobar=Foo.new  #=> "@bar="bar-fu"

foobar.foo  #=> "bar-fu"

foobar.bar=" one liner, sorry my chinese" #=> "one liner, sorry my chinese"

foobar.foo  #=> "one liner, sorry my chinese"

Okay, up to this point, we have learnt that ruby is so sweet, we can write the whole class of things in a single line

IMHO: One liner, is a bad habit, hard to maintain code may evolve into an alien language. We should use it just in case it isn’t that long. for our case the RodaError class has no logic in it hence its okay to use one liner.

Lets move to the next piece of Roda code

  class RodaRequest < ::Rack::Request;
    @roda_class = ::Roda

    class << self
      def inspect
        "#{roda_class.inspect}::RodaRequest"
      end
    end
  end

comments from the source says:

  # Base class used for Roda responses.  The instance methods for this
  # class are added by Roda::RodaPlugins::Base::ResponseMethods, so this
  # only contains the class methods.

That being said, I was curious to know why in the subclassing they used the ::Rack::Request instead of Rack::Request.

It turns out, in a depply nested tree of modules and classes, Ruby offers another means of referencing the intended module or class by simply ommitting what is before it with a :: symbol.

Take an example you have a Module::AnotherModule::MyClass and you are inside Module and wish to reference MyClass you can just write ::MyClass and you are good to go.

Looking at @roda_class=::Roda, made me wonder, what kind of variable is that? I mean, I have seen variable definitions inside class methods, but not at the top. So, I did some digging and found out there are two kinds of instance variables, class instance variables and object instance variables.

Class Instance Variables and Object Instance Variables

These are variables for the current class, this means, they operate at the level before instantiation of a class. Alright, it might seem confusing, but we can do this by an example.

Open up our pry shell and lets go to work.

Consider we have a following class

class MamaMia
  @who=" Mama mia mbili"
  def self.what
    @who
  end
end

The code above is simple, we defined a class method what( we will know about class methods later) that returns the instance variable who

So, here is how we use class methods

MamaMia.what  #=> "Mama mia mbili"

But, when we create an obgect from the class, we get an error when we call what method since it operates at class level and not object level. But for the sake of curiosity lets add another method, this time a class instance method to which we will give a different value of @who. And we will check if the class variable @who will change.

class MamaMia
  @who=" Mama mia mbili"
  def self.what
    @who
  end

  def some_what
    @who=" A good Day"
  end
end

obj=MamaMia.new

obj.some_what #+> " A good Day"

MamaMia.what #=> "Mama mia mbili"

Another thing that caught my attention is the use of class<<self, why defining another nameless class and even add methods to it? I had to find out. And here is when the concept of the singleton_class aka eigenclass kicks in.

Before we go ahead, I should be clear on this, I am not explaining what roda does, Im rather exploring what ruby does, how ruby is used by digging the source code of roda framework.

Scope of execution

Up to this moment, I have come to realize that, scope is very important when trying to understand how objects and classes work. To me, it seems there are three important scopes, the global scope, the class(or module ) level scope and the object level scope.

Global scope is the ruby execution environment, the class or module scope is just like its name suggest, and the object level scope, is where instances of classes or modules operate( remember that, classes and modules are the same thing).

That being said, we can take a look at eigen class.

Eigenclass

Thiss is a hidden class of an object and its so funny to understand that, the object model has more that what it seems to have. objects have eigenclass, eigenclass is a class, a class has a superclass of Object which has an eigenclass too.

Cutting the complications, the eigenclass is another means of tapping into an object’s scope and do something with it.

Inside a class definition, self is used to refer to the current object in a class.

Eigen class is defined by using the class style. it takes an object and add methods in the given object’s scope.

# working in a eigenclass of an object
class<<(object)
# do something
end

So, in other sense, eigenclass is used to add methods to an object. We know that we define methods in a class, but this defines methods in an oject.

The code snippet says class<<self which means we are adding methods into the object self.

Okay, the concept seems to be confusing, maybe we should try an example. lets say we have a class Azam.

class Azam
end

The class is empty, and if we create an instance of the class, and call a method tamtam we will get an error.

tam=Azam.new
tam.tamtam #=> Udefined method.

Through the eigenclass we can add methods to the object tam withought having to define them in the class Azam, check this out.

tam=Azam.new

tamu=class<<tam
       def tamtam
         puts "sweet like"
       end
     end

#Lets make sure we are still dealing with the same class of Azam
tamu.class #=> Azam

#test our added method
tamu.tamtam #=> "sweet like"

That was awesome, we added the the method on the fly, and it was working as if we have defined it in the class method.

So, up to this point, Im pretty sure I know what exactly is happening inside this class, hence by doing this,

    class << self
      def inspect
        "#{roda_class.inspect}::RodaRequest"
      end
    end

We are adding a method inspect into the class scope, and since we are iside the class scope, we have access to the class variable roda_class thats why we are able to to call roda_class.inspect.

From what we have learnt, it seems the auther wanted to inspect the class RodaRequest by just doing RodaRequest.inspect which will in turn reaturn the exactly roda app class inspection since 

@roda_class=::Roda.

Testing my theory is is right.

require 'roda'

class MyClass<Roda; end

request=MyClass::RodaRequest

request.inspect #=>"MyApp::RodaRequest"

Again

MyApp::RodaRequest.inspect #=>"MyApp::RodaRequest"

We are able to achieve the same result, at class level and at object level, sweet.

But wait, why doing all of that, where is the trick. The answer is, inspect was supposed to return the class name in our case, RodaRequest, so by overriding inspect we are able to have a full namespace reference to the class, ie MyApp::RodaRequest. Why we need this? I don’t know, maybe when we go much deeper we may find the answer.

That is enough for today though, use the comment box below to share your view or ask for more description. Next time, We will be digging this eigenclass concept much deeper, there many interesting stuffs in it.

About Author

Geofrey Ernest is a freelance web developer / programmer based in Mwanza Tanzania, He enjoys writing and experimenting with different programming languages.He is currently open to take new projects. X