Ruby Modules, Mixins, Concerns, and Regular Expressions — Ruby Deep Dive [08]
Let’s talk about Ruby Modules, Mixins, Concerns and RegEx in this article.
1. Modules
Modules in Ruby serve as a way to package together methods, constants, and other module-level variables. They allow for namespace organization and provide a mechanism for multiple inheritance through mixins. Modules cannot be instantiated directly but are included in classes to extend their functionality.
module Greetable
def greet
"Hello, #{name}!"
end
end
class Person
include Greetable
attr_reader :name
def initialize(name)
@name = name
end
end
person = Person.new("Alice")
puts person.greet # Output: Hello, Alice!
2. Mixins
Mixins are a way to add behavior to classes in Ruby without using traditional inheritance. Modules are included within classes using the include
keyword, allowing classes to inherit methods defined in the module. This promotes code reuse and keeps class hierarchies flat.
module Loggable
def log(message)
puts "[#{self.class}] #{message}"
end
end
class User
include Loggable
def initialize(name)
@name = name
log("User created: #{@name}")
end
end
User.new("Bob") # Output: [User] User created: Bob
3. Concerns (Rails-specific)
Concerns in Rails are used to encapsulate shared pieces of functionality across models or other parts of an application. They are typically placed in the app/models/concerns
directory and can include methods, scopes, validations, and other shared behaviors. Concerns help maintain clean and modular code by separating concerns logically.
# app/models/concerns/searchable.rb
module Searchable
extend ActiveSupport::Concern
included do
scope :search, ->(query) { where("name LIKE ?", "%#{query}%") }
end
def highlight_matches(query)
name.gsub(/(#{query})/i, '<strong>\1</strong>')
end
end
# app/models/product.rb
class Product < ApplicationRecord
include Searchable
end
# Usage
Product.search("ruby").each do |product|
puts product.highlight_matches("ruby")
end
4. Regular Expressions
Regular expressions (regex) are patterns used to match character combinations in strings. They provide a powerful way to search, manipulate, and validate strings based on specific patterns. Ruby supports regular expressions through the =~
operator and various methods like match
, gsub
, and scan
.
The snippet below covers:
- Basic matching and case-insensitivity
- Start and end of string/line anchors
- Character sets, ranges, and shorthand classes
- Alternation and quantifiers
- Using dot and asterisk for flexible matching
- A more comprehensive email validation regex
- String manipulation with
gsub
- Multiline matching for complete fairy tale content
- Using capture groups to extract parts of a match
These examples demonstrate the versatility and power of regular expressions in Ruby for various text processing tasks.
# Basic matching
puts "Found it" if /Once upon a time/ =~ "Once upon a time, there was a princess..."
# Case-insensitive matching
puts "It matches!" if /AM/i =~ 'am'
# Start and end of string/line
puts "Fairy tale beginning" if /\AOnce upon a time/ =~ "Once upon a time..."
puts "Classic ending" if /happily ever after\z/ =~ "...and they lived happily ever after"
# Matching within lines
content = "Title\nOnce upon a time...\nThe End"
puts "Found fairy tale" if content =~ /^Once upon a time/
# Character sets and ranges
hex_digit = /[0-9a-fA-F]/
word_char = /[0-9a-zA-Z_]/
# Shorthand character classes
digits = /\d\d/ # Matches two digits
word = /\w+/ # Matches one or more word characters
whitespace = /\s*/ # Matches zero or more whitespace characters
# Alternation
time_format = /A\.M\.|AM|P\.M\.|PM/
# Quantifiers
puts "Ruby-ish" if /Ru*by/ =~ "Ruuuuby"
# Combining dot and asterisk
puts "Contains George" if /.*George.*/ =~ "King George III"
# Email validation (more comprehensive)
email_regex = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
# Usage
email = "user@example.com"
if email =~ email_regex
puts "Valid email"
else
puts "Invalid email"
end
# String manipulation with gsub
text = "The quick brown fox"
new_text = text.gsub(/\w+/) { |word| word.capitalize }
puts new_text # Output: The Quick Brown Fox
# Matching multiline fairy tale content
fairy_tale_regex = /^Once upon a time.*happily ever after\.\s*$/m
content = "Once upon a time...\n...happily ever after.\n"
puts "Complete fairy tale" if content =~ fairy_tale_regex
# Using capture groups
phone_regex = /(\d{3})-(\d{3})-(\d{4})/
phone = "123-456-7890"
if match = phone.match(phone_regex)
puts "Area code: #{match[1]}"
puts "Exchange: #{match[2]}"
puts "Number: #{match[3]}"
end
Conclusion
These snippets illustrate practical applications of Ruby modules, mixins, concerns (specific to Rails), and regular expressions. Modules and mixins enhance code reusability and maintainability by encapsulating behavior. Concerns in Rails streamline shared functionality across models, promoting modular and clean architecture. Regular expressions empower developers with robust tools for string manipulation and validation based on specified patterns.