Over the last few month's I've been diving much deeper into Ruby, going through the famous Eloquent Ruby book.
It's been a crazy helpful book, about both RULES and CONVENTIONS
Here's a massive brain dump of of Ruby goodness
Writing Code That Looks Like Ruby
- Variable names start with lowercase letter unless they start with
@
- Knowing the idioms and norms of a language is just as important as the syntax rules
- Good code tells the reader exactly what it is trying to do. Great code shouts its intent
- Good code is clear AND concise
- Ruby convention is 2 spaces for indentation (Sorry Tab People 🤷♂️)
Comments
- Anything following as
#
is a comment - Comments should just explain how to use a chunk of software, not whys or other hows
- Keep background comments separate from instruction
- Don't fall into the trap of explaining lines of code that can/should speak for themselves
Some Ruby Rules and Conventions
- Everything except classes should be snake_case
- Class names should be CamelCase
- Constants should be ALL_CAPS_WITH_UNDERSCORES
- Parentheses around methods aren't technically required but most people do use them
- When it's just a single argument, some people won't put parentheses when calling an argument especially with puts or instance_of
- Control statements (ifs) don't require parentheses, and we generally leave them out
- You can put more than one line on one line by separating with a semicolon, but you shouldn't Ruby has lots of things you CAN do but SHOULDN'T do
- If a code block has only a single statement, put it on a single line with { } otherwise use
do end
syntax - Ruby doesn’t actually enforce constants. you can change them 💩
- methods should end in ? for things that return a binary
- methods should end in ! for things that could be dangerous
- There is no
do
after anif
, just theif
, the condition, the block, and the end - Ruby lets us use
unless
to meanif not
- If the body of a conditional is just one line, we can collapse the whole thing
- Both false and nil are treated as false, EVERYTHING ELSE is true
Some fun Code Samples
You can create an array of strings the traditional way like this
words = ['left', 'right', 'yellow']
Or in a fancy faster way like this
words = %w{left right yellow}
You can create a hash the traditional way like this
frequency = {"left" => 1, "right" => 17, "yellow" => 99}
or in a fancy faster way like this only if your keys are symbols
frequency = { left: 1, right: 17, yellow: 99 }
If you want to make a parameter optional to provide, you can specify a default
def load_font( name, size = 12 )
You can make a method take an arbitrary number of arguments by passing an astrisk before the argument name. Will create an array of values passed
def print_all ( *strings )
To run through a Ruby collection, you should use the .each
method!
words.each {|word| puts word }
The find_index
method for arrays returns the index of a condition being met
words.find_index { |this_word| word == this_word }
Strings vs Symbols in Ruby
- Ruby lets you choose either double or single quotes for strings
- Strings are mutable in Ruby
- You must use double quotes if you’re doing string interpolation or newlines or tabs
- Strings are optimized for processing, symbols are optimized to stand for something
- There can only ever be one instance of a given symbol, unlike a string
- You can turn a symbol into a string with .to_s
- You can turn a string into a symbol with .to_sym
- Dynamic typing means types are checked on the fly as code is executed
- You can change the type of a variable, but you shouldn’t
- Dynamic typing allows more concise code
Duck Typing in Ruby
Ruby assumes if an object has the right kind of methods, then it’s the right kind of object
This is called duck typing
If it walks like a duck, well, you know the saying
- The payoff of dynamic typing is not automatic, eventually you don’t have to write base classes
- Ruby’s dynamic typing means you don’t declare the class of parameters, which lets your code be less coupled — you can change things easier
- This does increase cognitive load a bit as it may not be clear what you need to pass to a method
- Ruby is a language for grown ups that expects you to not shoot yourself in the foot like a child
Tests
- Test early, test often, and test whenever you make a change
- The ruby style of programming insists that no class is finished without tests
- We have a built in Test::Unit we can use for simple one-off tests, but Rspec gives us much more functionality
- Ideal tests exercises exactly one test at a time
- A stub is an object that implements the same interface as a class that is needed for a test, but returns fake answers
- Mocks are like stubs, but fail the test when wrong methods are called or with wrong arguments
- Unit tests should be fast so they actually get run
- Unit tests should be independent of one another
- Unit tests should be capable of actually failing
- Most Ruby programmers favor really short methods that do exactly one thing
- This makes things more testable (yay!)
- The code should be articulate and explain itself to anyone maintaining it
What is the Composed Method in Ruby?
Ruby uses the composed method, where methods have 3 characteristics
- They focus on solving a single aspect of a problem
- They operate at a single conceptual level (don’t mix logic)
- They have a name that reflects their purpose
Overloading
- You can overload operators in Ruby like *, - , +, / - this is different than other languages like C or Java, where they hide them
- Unless it’s overloaded
==
behaves the same way as .equal?
Ruby Classes
- We build classes to represent groups of things, and have instances represent the things themselves
- Every Ruby object is an instance of some class
- Every class (except Object) has a superclass
- If you don’t specify, the superclass is
Object
- They act as containers for methods
- They are factories for making instances
- If doesn’t need an instance, it should just be a module
- Singletons are objects whose behavior is not completely controlled by a class
- A singleton method is a method that is defined for exactly one object instance
- Singleton methods override any regular class-defined methods
- Class methods are singleton methods in disguise
- Class variables start with two @s instead of 1, and they’re associated with the class rather than an instance of the class
- If the current class variable is not defined in the current class, Ruby looks to the parent (and so on)
- This can cause problems with child classes if you change the parent - it’s coupling
- The class instance variable, represented with a single
@
, is attached to a single object, an instance of the given class - Ruby gives
:attr_accessor
methods you can use to have getter methods for a class instance variable - Classes are containers for holding things AND factories that produce objects
Ruby Modules vs Classes
- A Ruby module is the container part of a class without the factory
- You can put things in a module, like methods, constants, classes, and even other modules
- You can’t instantiate a module, there's no factory 🙂
- You can use modules to include methods and then call those methods with
ModuleName.method_name
- Ruby classes are arranged in an inheritance tree, so a key part of constructing a new class is picking a superclass
- You can “mixin” modules into the inheritance tree of a class
- Mixins let you share common code among unrelated classes
Conclusion
There's a LOT more to this book, especially metaprogramming
Honestly, that was a lot less interesting to me than what I've talked about here, so I hope you can find it useful.