Crystal compiler does a lot of work in order to allow the programmer be more expressive, productive, and …lazy.
Since 0.7.7 the compiler comes with some initials tools that will help the programmer know what the compiler is understanding from the code and to navigate through in a more interesting way.
Go to implementations tool
When compiling a method call, the compiler knows exactly which method definition will be called. But, when the programmer is viewing the source code, there was no way (other than string search) to reach the method definition.
Bigger the project, harder to find the definition.
So if you have program.cr with the following code:
def add(a, b)
a + b
end
add(1, 2)
$ crystal tool implementations --cursor program.cr:5:1 program.cr 1 implementation found /path/to/program.cr:1:1
You can pass --format json
to make a computer friendly output and build something to integrate it to you favorite text editor. This is used in then crystal-tools atom package and it just looks awesome. Every location is just clickable.
If you use Atom download them and just press ⌘⌥i
/ ctrl-alt-i
while your cursor is over the add
in line 5.
Multiple implementations
This tools does not only will be allow you avoid def foo
vs def self.foo
string matching hell, but will point which are the real candidates of a method call.
class A
def foo
end
end
class B
def foo
end
end
def use_foo(o)
o.foo # put the cursor in this #foo call
end
use_foo(A.new)
use_foo(B.new) # if removed, line 7 won't be an implementation of line 12
Down a macro hole
A snippet is worth a thousand words.
class Person
property name
end
p = Person.new
p.name = "John" # put the cursor in over #name= call
$ crystal tool implementations --cursor program.cr:6:6 program.cr 1 implementation found /path/to/program.cr:2:3 ~> macro property: /path/to/crystal-src/object.cr:365:5 ~> macro setter: /path/to/crystal-src/object.cr:324:9
And you know how object.cr looks like?
class Object
# ...
macro setter(*names)
{% for name in names %}
{% if name.is_a?(DeclareVar) %}
def {{name.var.id}}=(@{{name.var.id}} : {{name.type}}) # line 324
end
{% else %}
def {{name.id}}=(@{{name.id}})
end
{% end %}
{% end %}
end
# ...
macro property(*names)
getter {{*names}}
setter {{*names}} # line 365
end
# ...
end
I love this!
Reveal context tool
Another neat tool that will help you avoid all thouse run with pp var
or pp typeof(var)
is the context tool. Just position your cursor somewhere ⌘⌥c
/ ctrl-alt-c
and you will all variables type information.
Like in the previous tool, the program itself is never executed. All the information shown cames from the same build process that generates the binary.
The tool is available in command line manner.
a = "a string"
b = 1
$ crystal tool context --cursor program.cr:3:1 program.cr 1 possible context found | Expr | Type | ----------------- | a | String | | b | Int32 |
It’s interesting thou to see all the overload a def
holds.
Final notes
Work in progress
It’s work in progress :-). We want more tools, and to make them robust enough for everyone. We think they are ready enough for you to enjoy them, and help us making them better.
Next steps
The crystal-tools atom package will probably get crystal spec
support so it will be easier to run single file/single spec from the editor.
Another desired tool is to get all caller for a given method. Kind of dual tool of implementations that will answere the question, who is using this code?
Green compile status is a requirement
Since this tools were built on top of crystal compiler, with all it’s type inference and compiler phases, if the code does not compile you won’t be able to run any tool.
Main program
All samples presented here were programs in a single file but the tools do work in larger project. For this to happen the tools need to know the main file to compile. This was the last argument of the commands. The --cursor
argument specifies where the text cursor is located in the editor.
For single file programs the main program is just it. For larger programs is not that easy. You as a developer will know which file to compile.
The crystal-tools atom package will use all the specs as main program. If this is not what you need to can change from the settings page which file to compile among other things.
… towards an event better crystal programming experience. ❤