Modules
Module in Ruby this is a way to group some classes, functions, constants together. It is quite similiar to the class, but module can not have an instance or the subclasses - it is just a namespace for a group of objects. Module is defined by keywords module ... end
. Below is an example of Network module containing method, class and constant:
module Network # module name PROTOCOLS = [:http, :ftp, :telnet] # module constant def Network.is_a_protocol?(protocol) # module method is defined like the class method PROTOCOLS.include? protocol # module constact is accessible from the module method end class Ip # module class def initialize(p1, p2, p3, p4) @p1 = p1; @p2 = p2; @p3 = p3; @p4 = p4 end def to_s "#{@p1}.#{@p2}.#{@p3}.#{@p4}" end def inspect "IP: #{to_s}" end end end
To access the module method use Module_name.method_name
, Module_name::CONSTANT_NAME
for constants and Module_name::ClassName
for classes.
Network::PROTOCOLS #=> [:http, :ftp, :telnet] Network.is_a_protocol? :ftp #=> true ip = Network::Ip.new 192, 168, 1, 1 #=> IP: 192.168.1.1
But it would be annoying to write a module name many times, especially when you are writing a long script. To avoid this, you may insert all the things from the module using include ModuleName
statement to treat all the stuff like the local objects:
include Network #=> Object PROTOCOLS #=> [:http, :ftp, :telnet] is_a_protocol? :ftp #=> true ip = Ip.new 192, 168, 1, 1 #=> IP: 192.168.1.1
Math Module
There is a build in module Math
contains trigonometric and transcendental function (see documentation ri Math
for complete list of methods). It is good to include Math
if you are planning to do more work with this module.
Math.sin(Math::PI/2) #=> 1.0 include Math #=> Object sin(PI/2) #=> 1.0 sqrt 2 #=> 1.4142135623730951
Etc Module
Another interesting built-in module is called Etc
- a Ruby way to access information stored in /etc/passwd
and /etc/group
.
require 'etc' # you must load the file with Etc module before you can use it #=> true Etc.getlogin # Etc.getlogin returns the current user name #=> "grych" Etc.getpwnam(Etc.getlogin) # Etc.getpwnam returns object containing all the information from passwd #=> #<struct Struct::Passwd name="grych", passwd="********", uid=501, gid=20, gecos="Tomasz Gryszkiewicz", dir="/Users/grych", shell="/bin/zsh", change=0, uclass="", expire=0> Etc.getpwnam('grych').gecos # and this is how you can access this structure #=> "Tomasz Gryszkiewicz"
Mixins
While discussing objects we talked about inheritance: to remind, object can be a subclass of the other object, it inherits all the methods, variables from the other class. But object can have only one superclass, so if you want to use some methods from few different sources, you must use Mixin. Mixin it is a module to be loaded into the class. All the module methods, constants will be included to the class.
To have an example lets create the mixin called Pingable
with method alive?
returns true if ping to the server works.
module Pingable def alive? p = `ping -c 1 -t 10 #{self.full_name}` # like in Shell you can run any command by putting it in `` p.include? '1 packets received' # if output of ping command include this string, returns true end end
self.fullname
in the code above does not refer to the mixin, but to the instance of an object, to which this mixin will be included. This is a kind of a protocol: we assume, that all object which want to include Pingable
must have defined full_name
method.
Let's go and load the mixin to our Server class:
class Server include Pingable # include previously defined mixin def initialize(name, domain) @name = name @domain = domain end def full_name # mixin will call that function @name + @domain end end s = Server.new('www', '.startrek.com') #=> #<Server:0x007fce68aee3e8 @name="www", @domain=".startrek.com"> s.alive? #=> true Server.new('www', '.starwars.com').alive? #=> false