Contracts in Ruby are part of the new style

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

Much more than PHP or Python, the Ruby community is constantly pulling in new ideas from other programming language, and we see the emergence of new Ruby styles:


# The standard “record” that contains information about a file on disk.
SourceFile = Struct.new :relative_path, :full_path,
:directory, :types

# Find a file given a type and path.
#
# @param [Symbol] type The file “type”.
# @param [String] path The file path.
# @param [Boolean] glob If the path contains wildcard or glob.
# @return [Middleman::SourceFile, nil]
Contract Symbol, String, Maybe[Bool] => Maybe[SourceFile]
def find(type, path, glob=false)
watchers
.lazy
.select { |d| d.type == type }
.map { |d| d.find(path, glob) }
.reject(&:nil?)
.first
end

Thomas Reynolds comments on his use of contracts:

The Ruby contracts gem adds the ability to decorate methods with code that checks that the inputs and the output match what the contract specifies. This is a simple, opt-in way of adding some type checks without going down the rabbit hole of Static Typing everything. At some point, contracts may be able to directly read the YARD doc strings (like Google’s Closure and Facebook’s Flow do), but for now we have to duplicate this information:

# @param [Symbol] type The file “type”.
# @param [String] path The file path.
# @param [Boolean] glob If the path contains wildcard or glob.
# @return [Middleman::SourceFile, nil]
Contract Symbol, String, Maybe[Bool] => Maybe[SourceFile]
def find(type, path, glob=false)

Basically, I’m saying that the find method takes 3 parameters, the last of which might be nil (also known as Maybe). The return value will either be a Record of the SourceFile type of nil, which is typed as Maybe[Sourcefile].

When I started adding Contracts to the code base, I immediately found dozens of tiny bugs and plenty of places where the docs were out of date with the code. I can’t see myself ever working on another Ruby project without this type safety net in place. Like testing, I believe you should add just enough contracts/test to cover your ass and not worry about things like 100% coverage.

Thomas Reynolds also writes of what he wants to see in the future:

Going forwards, I’d love to see some features from other languages make their way into Ruby. I agree with most everything Erik Michaels-Ober mentions in his talk: Towards a Higher-Level Language. Replace nil with Maybe in the language. Kill Symbol. Fix the standard numbers (this goes for almost every language using IEEE floats).

I also agree with the goals of Rubinius X. I want Immutable Data in Ruby. We NEED a real dependency system. If not as robust as Clojure’s, let’s atleast reach parity with Python. Even Javascript is beating Ruby now :(

I’d like to see optional typing of inputs/outputs.

And finally, pie in the sky, can we solve packaging apps up into distributable binaries, please? Rust and Go are making us look bad.

Source