Eloquent Ruby in 10 Minutes
Tags: ruby, rails, webdev, programming
Published: 2023-07-07 01:13:00

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 an `if`, just the `if`, the condition, the block, and the end
- Ruby lets us use `unless` to mean `if 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

```ruby
words = ['left', 'right', 'yellow']
```

Or in a fancy faster way like this

```ruby
words = %w{left right yellow}
```

You can create a hash the traditional way like this

```ruby
frequency = {"left" => 1, "right" => 17, "yellow"  => 99}
```
or in a fancy faster way like this only if your keys are symbols

```ruby
frequency = { left: 1, right: 17, yellow: 99 }
```

If you want to make a parameter optional to provide, you can specify a default

```ruby
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

```ruby
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

```ruby
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.