Search code examples
rubysyntaxcelluloid

Shorthand in Ruby, Artoo.io


I am looking for an explanation for what's going on at the top of artoo.io robots. There is a declaration at the top of this example using the keyboard driver:

require 'artoo'

connection :keyboard, adaptor: :keyboard
device :keyboard, driver: :keyboard, connection: :keyboard

It seems that some shorthand/alternative syntax is displayed, and I'd love an explanation of that shorthand. I understand the alternative hash syntax: :adapter => :keyboard.

What is going on in those last two lines of code above? What is connection? Is it a class inside artoo that is being initialized? Why is there no new? Where does :keyboard come from? If there is an alternative syntax that represents the relationships more explicitly, could you show that as well?


Solution

  • This is a great question. It might be a duplicate but I couldn't find one and this is the sort of thing that is tricky for smart programmers who are new to Ruby.

    First, to your question: What is connection?

    It is a method call. In some cases it can be hard to tell what is a method and what is a variable, because it just depends on how they were defined. But in this case it is clear because connection has parameters after it. In ruby, a method can be called like this:

    foo
    

    In that case it is a method that takes no parameters. Or it can look like this:

    foo 1, 2, 3
    

    That is a method with three parameters. Or it can look like this:

    foo(1, 2, 3)
    

    That is the same method, but with a slightly different syntax (which is more familiar to people experiences in c-mimicing languages like c, C++, Java, Javascript, C#, etc...)

    So when you see parameters listed after a bare word, with no operators between, it is a sure sign it's a method call.

    Now to break down your code entirely.

    require 'artoo'
    

    This is technically a method call. You're calling the require method and passing a single parameter of the literal string 'artoo'. As you probably know, require loads an external ruby file into the current file.

    connection :keyboard, adaptor: :keyboard
    

    This is a method call with some syntactic sugar:

    You know right away that connection is a method call because it has parameters after it (i.e. no operator between connection and what comes after). But what parameters?

    :keyboard: is a Symbol, which is ruby's equivalent of an intern'd string.

    adaptor: :keyboard is a Hash.

    Ruby has two primary hash syntaxes:

    {key => value}
    

    Where key and value are any objects, or:

    {key: value}
    

    Where key is a bare literal Symbol and value is any object. Also, to keep code clean, when you pass a Hash as the last parameter to a method, you can leave off the { and } because it is unambiguous. It ends up giving you a clean "named parameter" style method call:

    do_something_to my_person, kindness: 10, aggressiveness: 2
    

    In your code:

    connection :keyboard, adaptor: :keyboard
    

    You have the alternate hash syntax (symbol keys) with the { and } left off. The whole line is 100% equivalent to:

    connection(:keyboard, {:adaptor => :keyboard})
    

    Your last line:

    device :keyboard, driver: :keyboard, connection: :keyboard
    

    Is the same thing. Equivalent to:

    device(:keyboard, {:driver => :keyboard, :connection => :keyboard})
    

    It just looks nicer (once you get used to it).