Writing a Ruby Library in Crystal

The Crystal Programming Language is one of the bleeding edge programming languages around the block. Its main attractive features are the following:

I was sold because it has Ruby style syntax and you can compile it to a single binary to run anywhere similar to Go. Imagine you don’t need to install rvm, chruby or Gems, you simply compile the binary for your architecture and stick it on a server (or Docker container) and it just works. This was my main motivation for writing an Elasticsearch library in Crystal.

After spending 4 months rewriting the Elasticsearch Ruby (https://github.com/elastic/elasticsearch-ruby) into Crystal I want to summarise some key differences in both and how to work around them for a more seamless development flow transition between Ruby and Crystal.

Crystal is Typed

Yes it is one of its key features and that needs to be applied and considered, especially when writing code. If you are used to statically typed languages then this will be much easier to implement. Lets look at an example Class definition.

# Defining a class in Crystal
class Response
getter :status, :body, :headers
def initialize(@status : Int32, @body : String, @headers : HTTP::Headers)
end
end

The equivalent Ruby code is

# Defining a class in Ruby
class Response
attr_reader :status, :body, :headers
def initialize(status, body, headers)
@status = status
@body = body
@headers = headers
end
end

This gets a little tricky especially when defining hashes, arrays and common patterns in Ruby.

# Ruby
a = []
b = {}
# Crystal
a = [] of String
b = {} of String => String
# Ruby
def sample(a, b, options={})
end
# Crystal 
def sample(a, b, options={} of String => String)
end

Personally it took me getting used to typing my arrays and hashes having written mostly in Python and Ruby for the last 5 years.

Crystal has less libraries

At the time I am writing this, Crystal has many libraries that cover most use cases but don’t expect the diversity, functionality and community of Ruby libraries. Also some libraries might simply have a different name, for example the CGI library (https://ruby-doc.org/stdlib-2.2.3/libdoc/cgi/rdoc/CGI/Util.html) closest counter part in Crystal is the HTML Standard Library (https://crystal-lang.org/api/0.19.4/HTML.html). Sometimes you might run into bugs or problems where you will be left on your own. In these cases I would highly suggest to reach out to the contributors of Crystal on Github.

Macros are awesome

Macros in Crystal are a great way of writing DRY code, its almost like using a templating language to write your code. I think the best way to understand is to simply show some code. Here is a macro from the Cossack (Crystal’s equivalent of Faraday):

https://github.com/crystal-community/cossack/blob/master/src/cossack.cr

@@default_client = Client.new   
{% for method in %w(get post put patch delete head options) %}  
  def self.{{method.id}}(*args, **nargs)      
@@default_client.{{method.id}}(*args, **nargs)
end
  def self.{{method.id}}(*args, **nargs, &block : Request -> _)
@@default_client.{{method.id}}(*args, **nargs, &block)
end
{% end %}

More about macros here: https://crystal-lang.org/docs/syntax_and_semantics/macros.html

Crystal is unstable

As with many projects at this early stage, there might be times where you will run into bugs in the compiler or a standard library method will be renamed in the next version which will cause your code to break. This is to be expected, I normally keep an eye on the recent commits to the master branch to make the necessary changes and fix up for the next release of Crystal.

Differences between Crystal and Ruby

For a more detailed break down of the exact differences, here is a great Github wiki entry: https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists.

I would highly suggest a read of the above before even thinking about writing something in Crystal if you are from a Ruby background.

Conclusion

The past 4 months were educational and I learnt a great deal about Crystal and Ruby. Above are some of the challenges I faced and I am hoping by sharing my experience I can help to attract more Rubyists to the Crystal Community or vice versa.

Checkout Elasticsearch Crystal: 
https://github.com/paktek123/elasticsearch-crystal