Ruby Classes
Class Basics
Class definition and initialization
class Host
attr_reader :hostname # getter only
attr_writer :status # setter only
attr_accessor :ip, :port # both getter and setter
@@instance_count = 0
def initialize(hostname, ip, port = 22)
@hostname = hostname
@ip = ip
@port = port
@@instance_count += 1
end
def to_s
"#{@hostname} (#{@ip}:#{@port})"
end
def self.count
@@instance_count
end
end
vault = Host.new("vault-01", "10.50.1.40", 8200)
puts vault # => "vault-01 (10.50.1.40:8200)"
puts vault.hostname # => "vault-01"
puts Host.count # => 1
Inheritance
Single inheritance with super
class NetworkDevice
attr_accessor :hostname, :ip
def initialize(hostname, ip)
@hostname = hostname
@ip = ip
end
def to_s
"#{self.class.name}: #{@hostname} (#{@ip})"
end
end
class Switch < NetworkDevice
attr_accessor :vlans
def initialize(hostname, ip, vlans = [])
super(hostname, ip)
@vlans = vlans
end
def trunk_ports
@vlans.length > 1 ? "trunk" : "access"
end
end
sw = Switch.new("sw-core-01", "10.50.1.2", [10, 20, 30])
puts sw # => "Switch: sw-core-01 (10.50.1.2)"
puts sw.is_a?(NetworkDevice) # => true
Access Control
Visibility modifiers
class SecureDevice < NetworkDevice
def connect
authenticate
open_session
end
private
def authenticate
puts "Authenticating to #{@hostname}"
end
protected
def open_session
puts "Session to #{@ip}"
end
end
Comparable and Struct
Operator overloading
class Subnet
include Comparable
attr_reader :network, :prefix
def initialize(cidr)
@network, prefix_str = cidr.split("/")
@prefix = prefix_str.to_i
end
def <=>(other)
prefix <=> other.prefix
end
def to_s
"#{@network}/#{@prefix}"
end
end
subnets = [Subnet.new("10.50.1.0/24"), Subnet.new("10.50.0.0/16")]
puts subnets.sort # /16, /24
Struct and Data
# Struct -- auto-generates initialize, accessors, ==
Host = Struct.new(:name, :ip, :port, keyword_init: true)
h = Host.new(name: "vault", ip: "10.50.1.40", port: 8200)
# Data (Ruby 3.2+) -- immutable value object
Endpoint = Data.define(:host, :port)
ep = Endpoint.new(host: "10.50.1.20", port: 443)