Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
Python and Tcl - public course schedule [here]
Private courses on your site - see [here]
Please ask about maintenance training for Perl, PHP, Lua, etc
 
Modules, Mixins and Comparators in Ruby

As your program and range of names grows, you may find that you have code that's going to cause potential name space conflicts - repeated names. That was something that OO elegantly solves for classes of objects, but perhaps you want the equivalent of a class that doesn't instantiate anything?

You're looking for a NAMESPACE that's loaded in - probably with a REQUIRE from a MODULE. Example to follow .... but we can't stress the importance of namespaces and modules as your application grows. Not put too strongly, all the standard stuff in the libraries is in modules, and it's a very good ides for you to mimic the principle.

Here's an example module:

module Taxcalc
  VAT_RATE = 17.5
  def Taxcalc.net(gross)
    net = gross / (100.0 + VAT_RATE) * 100.0
    return net
  end
  def Taxcalc.tax(gross)
    tax = gross - net(gross)
  end
end

and a program to use it:

require "taxcalc"

amount = 70.50

shopkeeper = Taxcalc.net(amount)
vatman = Taxcalc.tax(amount)

print "#{vatman} to the taxman\n"
print "#{shopkeeper} to the supplier\n"
print "Tax rate is #{Taxcalc::VAT_RATE}\n"

Note that we precede methods with "modulename." so that they're just like a static method, and we precede variables within the module with :: - not something you'll do all the time, but useful (in our example) to get directly at the VAT rate.

The programs runs as you would hope:

earth-wind-and-fire:~/ruby/r119 grahamellis$ ruby wot.rb
10.5 to the taxman
60.0 to the supplier
Tax rate is 17.5
earth-wind-and-fire:~/ruby/r119 grahamellis$

MIXINS

If you include a module within a class, then the members of that module also become available as methods in the class. This is a superb way to add in functionality to a whole lot of classes, and in essence does away with any need for multiple inheritance in very much the same way that Java's interfaces to away with the need for multiple inheritance in that language.

Let's define an application with a a class of invoice objects, and then mix in an updated tax module that defines instance methods as well as module/class methods.

Here's the updates tax module - remember, this is going o be mixed in so it contains a number of methods I want to pull into my Invoice class but no actual objects.

module Tcalc
  VAT_RATE = 17.5
  def getnet
    net = @howmuch / (100.0 + VAT_RATE) * 100.0
    return net
  end
  def gettax
    tax = @howmuch - self.getnet
  end
end

And here's the code that calls in those methods into the Invoice class

require "tcalc"

class Invoice
   include Tcalc # The line that mixes
   def initialize(what,howmuch)
      @what = what
      @howmuch = howmuch
   end
   def getgross
      return @howmuch
   end
   def getwhat
      return @what
   end
end

bills = [Invoice.new("Stefano",240.00),
        Invoice.new("Andy",180.00),
        Invoice.new("Lionel",80),
        Invoice.new("Bruce",60)]

account_line = "%-20s %8.2f %8.2f %8.2f\n"
acl2 = account_line.gsub(".2f","s")

ntot = ttot = gtot = 0.0
print acl2 % ["Descripton", "net", "tax", "gross"]
print acl2 % ["", "=====", "=====", "====="]
bills.each do |bill|
   person = bill.getwhat
   ntot += (net = bill.getnet)
   ttot += (tax = bill.gettax)
   gtot += (gross = bill.getgross)
   print account_line % [person, net, tax, gross]
end
print acl2 % ["", "=====", "=====", "====="]
print account_line % ["TOTAL", ntot, ttot, gtot]


And the result of running that code

earth-wind-and-fire:~/ruby/r119 grahamellis$ ruby mixdem.rb
Descripton net tax gross
                        ===== ===== =====
Stefano 204.26 35.74 240.00
Andy 153.19 26.81 180.00
Lionel 68.09 11.91 80.00
Bruce 51.06 8.94 60.00
                        ===== ===== =====
TOTAL 476.60 83.40 560.00
earth-wind-and-fire:~/ruby/r119 grahamellis$

USING THE COMPARABLE MIXIN

One of the big uses of mixins in Ruby is to bring in standard groups of methods to your own class. A really good example of this is the Comparable module .... if you want to redefine the six operators < <= > >= == and <=> in a class that you've written, then you can do so, or you can make your life easy by using Comparable and just redefining <=>.

Let's compare the delivery order of some letters for Postman Pat, who has gone high Tech and has Ruby doing his sorting for him ... with the assistance of Jess the cat.

"This demonstration defines a class of objects
of type Delivery which are house numbers and the
name of the recipient. The postman needs to see
which object to deliver first and which second,
and in order to do so he goes up the even numbers
then back down the odd numbers.

For readers who are not from the UK, British streets
are usually numbered back and forth across the road
so that you have 1,3,5,7 etc. on one side and 2,4,6,8
etc. on the other. And with modern busy traffic, the
postman does NOT want to keep crossing!!"

class Delivery
   include Comparable
   def initialize(number,name)
      @name=name
      @number=number
   end
   def getnumber
      @number
   end
   def <=> (partner)
      print "I'll ask Jess\n"
      return -1 if @number.modulo(2) != 0 and
   partner.getnumber.modulo(2) == 0
      return 1 if @number.modulo(2) == 0 and
   partner.getnumber.modulo(2) != 0
      return partner.getnumber <=> @number if
   @number.modulo(2) == 0
      return @number <=> partner.getnumber
   end
   def to_s
      "Deliver to #{@name} at #{@number}"
   end
end

gordon = Delivery.new(10,"Mr Dodge")
graham = Delivery.new(404,"Mr Ellis")
reggie = Delivery.new(22,"Dr Dodson")
kim = Delivery.new(25,"Ms Ellis")
chris = Delivery.new(15,"Mr Ellis")

print kim," before ",chris,"\n" if kim < chris
print chris," before ",kim,"\n" if kim >= chris

print reggie," before ",chris,"\n" if reggie < chris
print chris," before ",reggie,"\n" if reggie >= chris

print reggie," before ",graham,"\n" if reggie < graham
print graham," before ",reggie,"\n" if reggie >= graham

print reggie," before ",gordon,"\n" if reggie < gordon
print gordon," before ",reggie,"\n" if reggie >= gordon

print reggie," before ",kim,"\n" if reggie < kim
print kim," before ",reggie,"\n" if reggie >= kim


And running the program:

earth-wind-and-fire:~/ruby/r119 grahamellis$ ruby pat.rb
I'll ask Jess
I'll ask Jess
Deliver to Mr Ellis at 15 before Deliver to Ms Ellis at 25
I'll ask Jess
I'll ask Jess
Deliver to Mr Ellis at 15 before Deliver to Dr Dodson at 22
I'll ask Jess
I'll ask Jess
Deliver to Mr Ellis at 404 before Deliver to Dr Dodson at 22
I'll ask Jess
Deliver to Dr Dodson at 22 before Deliver to Mr Dodge at 10
I'll ask Jess
I'll ask Jess
I'll ask Jess
Deliver to Ms Ellis at 25 before Deliver to Dr Dodson at 22
earth-wind-and-fire:~/ruby/r119 grahamellis$


See also Ruby Programming course

Please note that articles in this section of our web site were current and correct to the best of our ability when published, but by the nature of our business may go out of date quite quickly. The quoting of a price, contract term or any other information in this area of our website is NOT an offer to supply now on those terms - please check back via our main web site

Related Material

Ruby - More Classes and Objects
  [4551] Testing your new class - first steps with cucumber - (2015-10-23)
  [4550] Build up classes into applications sharing data types in Ruby - (2015-10-23)
  [4504] Where does Ruby load modules from, and how to load from current directory - (2015-06-03)
  [4366] Changing what operators do on objects - a comparison across different programming languages - (2014-12-26)
  [3782] Standard methods available on all objects in Ruby - (2012-06-23)
  [3781] Private, Protected, Public in Ruby. What about interfaces and abstract classes in Ruby? - (2012-06-23)
  [3760] Why you should use objects even for short data manipulation programs in Ruby - (2012-06-10)
  [3260] Ruby - a training example that puts many language elements together to demonstrate the whole - (2011-04-23)
  [3158] Ruby training - some fresh examples for string handling applications - (2011-02-05)
  [3154] Changing a class later on - Ruby - (2011-02-02)
  [3142] Private and Public - and things between - (2011-01-22)
  [2980] Ruby - examples of regular expressions, inheritance and polymorphism - (2010-10-02)
  [2977] What is a factory method and why use one? - Example in Ruby - (2010-09-30)
  [2717] The Multiple Inheritance Conundrum, interfaces and mixins - (2010-04-11)
  [2623] Object Oriented Ruby - new examples - (2010-02-03)
  [2620] Direct access to object variable (attributes) in Ruby - (2010-02-02)
  [2616] Defining a static method - Java, Python and Ruby - (2010-02-01)
  [2604] Tips for writing a test program (Ruby / Python / Java) - (2010-01-29)
  [2603] Ruby objects - a primer - (2010-01-29)
  [2601] Ruby - is_a? v instance_of? - what is the difference? - (2010-01-27)
  [2292] Object Orientation in Ruby - intermediate examples - (2009-07-16)
  [1587] Some Ruby programming examples from our course - (2008-03-21)
  [1217] What are factory and singleton classes? - (2007-06-04)
  [656] Think about your design even if you don't use full UML - (2006-03-24)
  [184] MTBF of coffee machines - (2005-01-20)

Ruby Miscellany
  [3799] Ruby Documentation through rdoc - (2012-07-07)
  [3783] Load path, load and require in Ruby, and a change from 1.8 to 1.9 - (2012-06-24)
  [3622] Loading Ruby classes - where does Ruby look? - (2012-02-24)
  [3428] How many days to Christmas? - (2011-09-09)
  [3155] Rake - a build system using code written in Ruby - (2011-02-03)
  [1890] MySQL database from Ruby - an example - (2008-11-16)
  [1889] Ruby mixins, modules, require and include - (2008-11-16)
  [1720] Some Ruby lesser used functions - (2008-07-26)
  [1586] Variable types in Ruby - (2008-03-21)
  [1181] Good Programming practise - where to initialise variables - (2007-05-09)

resource index - Ruby
Solutions centre home page

You'll find shorter technical items at The Horse's Mouth and delegate's questions answered at the Opentalk forum.

At Well House Consultants, we provide training courses on subjects such as Ruby, Lua, Perl, Python, Linux, C, C++, Tcl/Tk, Tomcat, PHP and MySQL. We're asked (and answer) many questions, and answers to those which are of general interest are published in this area of our site.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2019: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01225 708225 • FAX: 01225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho

PAGE: http://www.wellho.net/solutions/ruby-mod ... -ruby.html • PAGE BUILT: Wed Mar 28 07:47:11 2012 • BUILD SYSTEM: wizard