Ruby has two basic concepts for organizing methods: classes and modules. We cover each in turn.
Here’s a Ruby class definition:
1: | class Order < ApplicationRecord |
- | has_many :line_items |
- | def self.find_all_unpaid |
- | self.where('paid = 0') |
5: | end |
- | def total |
- | sum = 0 |
- | line_items.each {|li| sum += li.total} |
- | sum |
10: | end |
- | end |
Class definitions start with the class keyword, followed by the class name (which must start with an uppercase letter). This Order class is defined to be a subclass of the ApplicationRecord class.
Rails makes heavy use of class-level declarations. Here, has_many is a method that’s defined by Active Record. It’s called as the Order class is being defined. Normally these kinds of methods make assertions about the class, so in this book we call them declarations.
Within a class body, you can define class methods and instance methods. Prefixing a method name with self. (as we do on line 3) makes it a class method; it can be called on the class generally. In this case, we can make the following call anywhere in our application:
| to_collect = Order.find_all_unpaid |
Objects of a class hold their state in instance variables. These variables, whose names all start with @, are available to all the instance methods of a class. Each object gets its own set of instance variables.
Instance variables aren’t directly accessible outside the class. To make them available, write methods that return their values:
| class Greeter |
| def initialize(name) |
| @name = name |
| end |
| |
| def name |
| @name |
| end |
| |
| def name=(new_name) |
| @name = new_name |
| end |
| end |
| |
| g = Greeter.new("Barney") |
| g.name # => Barney |
| g.name = "Betty" |
| g.name # => Betty |
Ruby provides convenience methods that write these accessor methods for you (which is great news for folks tired of writing all those getters and setters):
| class Greeter |
| attr_accessor :name # create reader and writer methods |
| attr_reader :greeting # create reader only |
| attr_writer :age # create writer only |
| end |
A class’s instance methods are public by default; anyone can call them. You’ll probably want to override this for methods that are intended to be used only by other instance methods:
| class MyClass |
| def m1 # this method is public |
| end |
| protected |
| def m2 # this method is protected |
| end |
| private |
| def m3 # this method is private |
| end |
| end |
The private directive is the strictest; private methods can be called only from within the same instance. Protected methods can be called both in the same instance and by other instances of the same class and its subclasses.
Classes aren’t the only organizing structure in Ruby. The other organizing structure is a module.
Modules are similar to classes in that they hold a collection of methods, constants, and other module and class definitions. Unlike with classes, you can’t create objects based on modules.
Modules serve two purposes. First, they act as a namespace, letting you define methods whose names won’t clash with those defined elsewhere. Second, they allow you to share functionality among classes. If a class mixes in a module, that module’s methods become available as if they had been defined in the class. Multiple classes can mix in the same module, sharing the module’s functionality without using inheritance. You can also mix multiple modules into a single class.
Helper methods are an example of where Rails uses modules. Rails automatically mixes these helper modules into the appropriate view templates. For example, if you wanted to write a helper method that’s callable from views invoked by the store controller, you could define the following module in the store_helper.rb file in the app/helpers directory:
| module StoreHelper |
| def capitalize_words(string) |
| string.split(' ').map {|word| word.capitalize}.join(' ') |
| end |
| end |
One module that’s part of the standard library of Ruby deserves special mention, given its usage in Rails: YAML.
YAML[31] is a recursive acronym that stands for YAML Ain’t Markup Language. In the context of Rails, YAML is used as a convenient way to define the configuration of things such as databases, test data, and translations. Here’s an example:
| development: |
| adapter: sqlite3 |
| database: db/development.sqlite3 |
| pool: 5 |
| timeout: 5000 |
In YAML, indentation is important, so this defines development as having a set of four key-value pairs, separated by colons. While YAML is one way to represent data, particularly when interacting with humans, Ruby provides a more general way for representing data for use by applications.
3.137.178.133