RubyGuides
Share this post!

Category Archives for Programming

ruby sinatra internals

A Quick Analysis of How Sinatra Works

What happens when you require sinatra into your project?

How does route matching work?

How are requests & responses processed?

So many questions, but so little time…

No problem!

I did the hard work for you & put together this article where I answer these questions & more!

Sinatra Initialization

It all starts with one file: sinatra.rb.

All this file does is to require main.rb, not very exciting right?

But here is where it gets more interesting.

Inside main.rb we will find a require for base.rb & we will also find the code for option parsing (port, environment, quiet mode, etc.).

Sinatra uses optparse, from Ruby’s standard library.

Another important thing happening here is the at_exit block:

This is a bit of code that will execute when the program ends.

What happens is that all your code will be read by Ruby & since you don’t have any loops, sleeps or anything like that your program will end naturally, but just before it ends the at_exit block will trigger.

When that happens Sinatra will take over & start a web server so it can handle requests:

Oh and another important thing happens here:

This defines the Sinatra DSL methods like get, post & set.

That’s why you can do this:

Request & Response Processing

Ok, so at this point we have a running server ready to accept new connections.

But what happens when a new connection is received?

Well Sinatra, just like Rails & other Ruby web frameworks, uses the Rack gem to handle all the lower level stuff.

Rack expects a call method to be available on your application. That’s just an object that you give to Rack when you initialize it.

In the case of Sinatra this object is the Sinatra::Base class.

Here’s the method:

It seems like we need to investigate the dispatch! method next to show how a request is handled.

Here’s that method:

The request in broken into 4 steps:

  1. Static files are checked first. These are files like css, js & images. This setting is enabled by default if a directory named “public” exists
  2. The before filter is run
  3. Route matching
  4. The after filter is run

Now we can dig into each step to see what happens in more detail.

Serving Static Files

The static! method is pretty simple:

This code checks if the requested file exists, then it sets the “Cache Control” HTTP header.

On the last line it calls send_file & it does just what the name says 🙂

Before Filter

A before filter allows you to run code before trying to find a matching route.

This is how a filter is added:

As you can see filters is just a hash with two keys, one for each filter type.

But what is compile!?

This method returns an array with 3 elements: a pattern, an array of conditions & a wrapper.

The same method is used for generating routes (when you use a get or post block):

From this we can learn that Sinatra filters behave & work the same way as routes.

Route Matching

The next step in the request processing cycle is route matching:

This code goes over every single route that matches the request method (get, post, etc).

Route matching happens inside the process_route method:

Where pattern is a regular expression.

If a route matches both the path & the conditions then route_eval will be called, which evaluates the block (the body of your get / post route) & ends the route matching process.

This uses the unusual catch / throw mechanism for flow control.

I would recommend against it because it can be very confusing to follow the flow of code, but it’s interesting to see a real-world example of this feature in use.

Response Building

The last step of the request cycle is to prepare the response.

So where does the response go?

The invoke method gathers the response like this:

This result is assigned to the response body using the body method:

Now if we look back where we started, the call method, we will find this line of code:

This calls the finish method on @response, which is a Rack::Response object.

In other words, this will actually trigger the response to be sent to the client.

Bonus: How The Set Method Works

The set method is part of Sinatra’s DSL (Domain-Specific Language) & it lets you set configuration options anywhere in your Sinatra application.

Example:

Every time you use set Sinatra creates 3 methods (via metaprogramming):

The 3 methods are (with public_folder as example):

  • public_folder
  • public_folder=
  • public_folder?

This method will also call the setter method (public_folder=) if it already exists:

Remember that metaprogramming is not free, so I would just stick with an options hash. You don’t need those fancy methods.

Summary

You learned how Sinatra gets initialized, how it handles a request & the different steps it takes until a response can be produced.

Don’t forget to share this post with other Ruby developers so they can learn from it too 🙂

ruby linked list

Practical Linked List in Ruby

This is the 3rd entry in the “Practical Computer Science in Ruby” series! Today we are going to talk about linked list.

So what’s a linked list?

Like the name says, a linked list is a way to store data in a list format (thanks, Captain Obvious!).

The “linked” part comes from the fact that data is stored in a node & these nodes are linked to each other in a sequential manner.

linked list

How is this different from an array?

Linked List vs Array

A linked list has different performance characteristics than an array. That’s one reason why you may want to pick one over the other.

This means that a linked list can be more efficient for certain tasks than an array.

In a linked list there is no indexing, no random access, meaning that you can’t just reach out for an item in the middle of the list.

You have to start at the “head” of the list & follow the links until you find the node you want or until the end of the list.

On the other hand, removing (or adding) an item from the middle of a linked list is a lot faster.

All you have to do is change the “next” pointer for one node.

But if you want to delete an element from the middle of an array you will leave a gap & to close that gap you have to move all the elements on the right of the deleted element.

array delete

Not very efficient if you have to do this often!

If we want to insert in the middle of an array we have to move all the array elements to create an empty space.

Let’s see a code example:

Note: There is also a built-in Array#insert method, but I wanted to show you how this method works.

If you are wondering about the actual performance impact of inserting an item in the middle of a list here’s a benchmark:

Big difference here, but it also depends a lot on the size of the LinkedList since we have to search for the node.

Another way to compare two data structures is to look at a time complexity table (this assumes you don’t have to search a node for insertion & deletion):

Data Structure Access Search Insertion Deletion
Array O(1) O(n) O(n) O(n)
Linked List O(n) O(n) O(1) O(1)

Looking for real-world applications?

Here’s a pull request by Aaron Patterson where he speeds up Ruby Gems by using a linked list:

https://github.com/rubygems/rubygems/pull/1188

Linked List Implementation

Ruby doesn’t include a LinkedList class so we need to create our own.

We want the following operations to be available:

  • append (to the end of the list)
  • append_after
  • delete
  • find

Here’s one possible implementation:

Notice that this particular implementation doesn’t keep track of the tail & instead it finds the tail when appending a new item. This makes the append operation linear time (O(n)). In the video below I show you another implementation where I append the elements at the front.

And here is our node class:

We can use it like this:

This is a basic “Singly-Linked List” implementation.

You also have other types of linked list:

  • Doubly-Linked List
  • Circular Linked List

In the doubly-linked list every node has two pointers: one to the next node & another to the previous node.

This allows for more flexibility when searching the list, but also requires extra work when making changes to the list.

A circular linked list is the same than a doubly-linked list, but the last node is connected to the head node.

Video

Summary

You have learned about linked list, a data structure which you could consider if you are doing a lot of adding & removing of elements in the middle of an array.

It could also come up in a coding interview, so it’s worth learning even if it’s just for that.

Don’t forget to share this post using the buttons below so more people can benefit from this knowledge 🙂

ruby sort

The Ultimate Guide to Ruby Sorting

How many ways are there to sort an array in Ruby?

More than you think…

…even though Array only has two sorting methods (sort & sort_by) these methods can take a block, which allows you to sort in several different ways.

I want to share with you a few examples in this post.

You will also learn how to implement your own sorting method using the quick-sort algorithm.

Basic Sorting

The most basic form of sorting is provided by the Ruby sort method, which is defined in the Enumerable module.

Let’s see an example:

Notice that sort will return a new array with the results.

It’s also possible to sort “in-place” using the sort! method. This method modifies the current array instead of creating a new one.

Customized Sorting

Now let’s see more advanced sorting, like being able to sort by string length & things like that.

To do that we can use the sort_by method.

For example:

It is also possible to do this using the regular sort method with a block.

But in general & prefer the sort_by method because the intention is more clear, it’s easier to read & it is also a bit faster.

Note: This <=> symbol is called “the spaceship operator” & it’s a method you can implement in your class. It should return 1 (greater than), 0 (equal) or -1 (less than).

Reverse Sort

What about sorting in reverse?

You could use the reverse method after sorting, or you can use a block & put a minus sign in front of the thing you are sorting.

Let me show you an example:

Alphanumeric Sorting

Let’s say you want to sort a list of strings that contain numbers.

Like this:

By default you will not get this list sorted like you want:

But you can fix this using sort_by:

I used a regular expression (\d+) to match the numbers, then get the first number (first) & convert it to an integer object (to_i).

Sorting Hashes

You are not limited to sorting arrays, you can also sort a hash.

Example:

This will sort by value, but notice something interesting here, what you get back is not a hash.

You get a multi-dimensional array when sorting a hash.

To turn this back into a hash you can use the Array#to_h method.

QuickSort Implementation

Just for fun let’s implement our own sorting method. This is going to be slower than the built-in sort methods, but it’s still an interesting exercise if you like computer science.

The idea of quick sort is to pick one number at random then divide the list we are sorting into two groups.

One group is the numbers less than the chosen number & the other group is the numbers bigger than the chosen number.

Then we just repeat this operation until the list is sorted.

Benchmarks

Let’s see how all these sorting methods compare to each other in terms of performance.

Ruby 2.4.0:

As you can see the regular sort method is a lot faster than sort_by, but it’s not as flexible unless you use a block.

Video

Summary

You have learned how to use the sort & the sort_by methods to sort your arrays & hashes in different ways. You have also learned about the performance differences & how to implement the quicksort algorithm.

Don’t forget to share this post so more people can learn 🙂

ruby constant

Everything You Need to Know About Ruby Constants

There is a lot more to Ruby constants that you might think…

For example, you can change the value of a constant, unlike other languages like C or Java.

Since this is such an important topic let’s explore it in detail in this article!

Defining Constants

A constant doesn’t require any special symbol or syntax to declare. You just need to make the first letter an uppercase letter.

The following are valid constants:

Notice that you can’t define constants inside a method.

You will get this cryptic error message:

So just define your constants outside methods, typically we want to have constant definitions at the top of your class so they are clearly visible.

You can then access these constants inside the class methods or outside the class using the following syntax:

We are going to talk a bit more about the scope of constants later in this post, so stay tuned for that!

Uninitialized Constant

One common error that you may get is this:

I want you to mentally translate this error to “constant not found Foo”. One important point to understand this error is that Ruby classes are constants.

They are constants because the first letter is uppercase. This matters because the most likely reason that you are seeing this error is that you forgot to require some file or gem that defines the constant.

Or maybe you just misspelled the name of the constant.

So keep an eye open for that.

Constants Can Change

Like I mentioned in the introduction, Ruby constants can change.

But you will see this warning message:

Your program will still work fine, but you want to avoid this.

There is no way to prevent a constant from changing because variables in Ruby are not containers, they are simply pointers to objects.

The best you can do is to use an immutable object.

Example:

Related article: Ruby mutability & the freeze method.

Notice that in this example you can still change what the AUTHOR constant is pointing to, the only thing freeze protects you from is from changing the object itself.

Constant Methods

There are a few methods dedicated to working with constants:

Method Description
constants Returns an array of symbols that represent the constants defined in a class
const_get Returns value for a constant. Takes a symbol or string as parameter
const_set Sets the value for a constant. Takes two parameters: constant name as a symbol & constant value
const_missing Same as method_missing but for constants
const_defined? Returns true if a given constant (as a symbol) has been defined
remove_const Removes a constant
private_constant Makes a constant private so it can’t be accessed outside the class with Class::ABC syntax

There are a few metaprogramming tricks you can do using these methods.

Example:

Also you can use a string like “Array” & get the actual class:

But be careful with that one since a user could inject code if the string is coming from params or some other form of user input.

In Rails, there is the constantize method which basically does const_get for you, but keep in mind that it doesn’t do any security checks.

Cheatsheet

cheatsheet-constant

Ruby Constant Scope

When you create a constant outside of any class, at the top-level of your code, that constant will be available anywhere.

Constants are also available in child classes.

Constants defined outside a nested module or class are also available inside the nested classes.

Module Mixing

Constants from mixed-in modules are also available:

Notice that this works when including the module, it won’t work if you are extending it.

Example:

Also when you use a method defined in the included method, it will use the constants defined in that module, even if the same constant is defined in the current class.

Module Nesting

I want to show you one more example with nested classes (same for modules).

Notice the A::B notation here, which we tried to use as a shortcut. But the problem is that class C won’t have access to FOO directly.

For that reason you want to stick to this kind of nesting:

In the first example you can still do ::A::FOO to access the constant, but if the class name changes then you will get an error.

This ::A::FOO syntax works because it tells Ruby to look in the top-level scope, where constants like Array & String are defined.

Video

Summary

You learned about Ruby constants, a type of variable which has some interesting behavior. You can change the value of a constant but it will print a warning.

You also learned that class names are constants & that you should avoid const_get with user input.

If you enjoyed this post don’t forget to share it so more people can understand how constants work.

ruby metaprogramming costs

The Hidden Costs of Metaprogramming

Metaprogramming sounds like a very fancy word, but is it any good?

It can be useful, but many people don’t realize that using metaprogramming has some costs.

Just so we are on the same page…

What is metaprogramming exactly?

I define metaprogramming as using any method that:

  • Alters the structure of your code (like define_method)
  • Runs a string as if it was part of your actual Ruby code (like instance_eval)
  • Does something as a reaction to some event (like method_missing)

So what are the costs of metaprogramming? I classify them into 3 groups:

  • Speed
  • Readability
  • Searchability

Note: You could also say that there is a fourth group: Security. The reason for that are the eval methods, which don’t make any kind of security checks on what is being passed in. You have to do that yourself.

Let’s explore each of those in more detail!

Speed

The first cost is speed because most metaprogramming methods are slower than regular methods.

Here is some benchmarking code:

The results (Ruby 2.2.4):

As you can see both metaprogramming methods (define_method & method_missing) are quite a bit slower than the normal method.

Here is something interesting I discovered…

The results above are from Ruby 2.2.4, but if you run these benchmarks on Ruby 2.3 or Ruby 2.4 it looks like these methods are getting slower!

Ruby 2.4 benchmark results:

I ran this benchmark several times to make sure it wasn’t a fluke.

But if you pay attention & look at the iterations per second (i/s) it seems like regular methods got faster since Ruby 2.3. That’s the reason method_missing looks a lot slower 🙂

Readability

Error messages can be less than helpful when using the instance_eval / class_eval methods.

Take a look at the following code:

This will result in the following error:

Notice that we are missing the file name (it says eval instead) & the correct line number. The good news is that there is a fix for this, these eval methods take two extra parameters:

  • a file name
  • a line number

Using the built-in constants __FILE__ & __LINE__ as the parameters for class_eval you will get the correct information in the error message.

Example:

Why isn’t this the default?

I don’t know, but it’s something to keep in mind if you are going to use these methods 🙂

Searchability

Metaprogramming methods make your code less searchable, less accessible (via worse documentation) & harder to debug.

If you are looking for a method definition you won’t be able to do CTRL+F (or whatever shortcut you use) to find a method defined via metaprogramming, especially if the method’s name is built at run-time.

The following example defines 3 methods using metaprogramming:

Tools that generate documentation (like Yard or RDoc) can’t find these methods & list them.

These tools use a technique called “Static Analysis” to find classes & methods. This technique can only find methods that are defined directly (using the def syntax).

Try running yard doc with the last example, you will see that the only method found is create_post_tags.

It looks like this:

yard example

There is a way to tell yard to document extra methods, using the @method tag, but that is not always practical.

Example:

Also if you are going to use a tool like grep, ack, or your editor to search for method definitions, it’s going to be harder to find metaprogramming methods than regular methods.

“I don’t think Sidekiq uses any metaprogramming at all because I find it obscures the code more than it helps 95% of the time.” – Mike Perham, Creator of Sidekiq

Conclusion

Not everything is bad about metaprogramming. It can be useful in the right situations to make your code more flexible.

Just be aware of the extra costs so you can make better decisions.

Don’t forget to share this post if you found it useful 🙂

1 2 3 14