{"id":120,"date":"2006-06-15T23:29:21","date_gmt":"2006-06-16T04:29:21","guid":{"rendered":"http:\/\/www.juixe.com\/techknow\/index.php\/2006\/06\/15\/mixins-in-ruby\/"},"modified":"2012-01-11T13:03:17","modified_gmt":"2012-01-11T20:03:17","slug":"mixins-in-ruby","status":"publish","type":"post","link":"http:\/\/juixe.com\/techknow\/index.php\/2006\/06\/15\/mixins-in-ruby\/","title":{"rendered":"Ruby Mixin Tutorial"},"content":{"rendered":"<p>In Java you just have classes (both abstract and concrete) and interfaces.  The Ruby language provides classes, modules, and a mix of both.  In this post I want to dive into mixins in Ruby.<\/p>\n<p>In the Ruby language a mixin is a class that is mixed with a module.  In other words the implementation of the class and module are joined, intertwined, combined, etc.  A mixin is a different mechanism to the extend construct used to add concrete implementation to a class.  With a mixin you can extend from a module instead of a class.  Before we get started with the mixin examples let me first explain what a module is.<\/p>\n<p>I think of a module as a degenerate abstract class.  A module can&#8217;t be instantiated and no class can directly extend it but a module can fully implement methods.  A class can leverage the implementation of a module by including the module&#8217;s methods.  A module can define methods that can be shared in different and separate classes either at the class or instance level.<\/p>\n<p>Let me define a module, albeit a trivial one, that would convert a numeric integer value to English.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Convert a integer value to English.\r\nmodule Stringify\r\n  # Requires an instance variable @value\r\n  def stringify\r\n    if @value == 1\r\n      &quot;One&quot;\r\n    elsif @value == 2\r\n      &quot;Two&quot;\r\n    elsif @value == 3\r\n      &quot;Three&quot;\r\n    end\r\n  end\r\nend\r\n<\/pre>\n<p>Note that the Stringify module makes use of a @value instance variable.  The class that will be mixed with this module needs to define and set a @value instance variable since the Stringify module uses it but does not define it.  In addition to instance variables a module could invoke methods defined not in the module itself but in the class that it will be mixed with.<\/p>\n<p>Now let me construct a self contained module that is not dependent on the implementation of any class that it can be mixed with.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# A Math module akin to Java Math class.\r\nmodule Math\r\n  # Could be called as a class, static, method\r\n  def add(val_one, val_two)\r\n    BigInteger.new(val_one + val_two)\r\n  end\r\nend\r\n<\/pre>\n<p>The methods in the Math module are intended to be invoked like class methods, also known as static methods.  The add method in the Math module accepts two integer values and returns an instance of BigInteger.  Let me now define the mixin BigInteger class.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Base Number class\r\nclass Number\r\n  def intValue\r\n    @value\r\n  end\r\nend\r\n\r\n# BigInteger extends Number\r\nclass BigInteger &lt; Number\r\n\r\n\r\n  # Add instance methods from Stringify\r\n  include Stringify\r\n\r\n  # Add class methods from Math\r\n  extend Math\r\n\r\n  # Add a constructor with one parameter\r\n  def initialize(value)\r\n    @value = value\r\n  end\r\nend\r\n<\/pre>\n<p><!--more--><br \/>\nI loosely modeled the BigInteger and Number classes after the Java versions.  The BigInteger class defines one constructor and directly inherits one method from the Number base class.  To mix in the methods implemented in the Stringify and Math modules with the BigInteger class you will note the usage of the include and extend methods, respectively.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Create a new object\r\nbigint1 = BigInteger.new(10)\r\n# Call a method inherited from the base class\r\nputs bigint1.intValue   # --&gt; 10\r\n<\/pre>\n<p>The extend method will mix a module&#8217;s methods at the class level.  The method defined in the Math module can be used as a class\/static method.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Call class method extended from Math\r\nbigint2 = BigInteger.add(-2, 4)\r\nputs bigint2.intValue   # --&gt; 2\r\n<\/pre>\n<p>The include method will mix a module&#8217;s methods at the instance level, meaning that the methods will become instance methods.  The method defined in the Stringify module can be used as an instance method.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Call a method included from Stringify\r\nputs bigint2.stringify   # --&gt; 'Two'\r\n<\/pre>\n<p>There is another use of the extend method.  You can enhance an object instance by mixing it with a module at run time!  This is a powerful  feature.  Let me create a module that will be used to extend an object, changing its responsibilities at runtime.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Format a numeric value as a currency\r\nmodule CurrencyFormatter\r\n  def format\r\n    &quot;$#{@value}&quot;\r\n  end\r\nend\r\n<\/pre>\n<p>To mix an object instance with a module you can do the following:<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\n# Add the module methods to\r\n# this object instance, only!\r\nbigint2.extend CurrencyFormatter\r\nputs bigint2.format   # --&gt; '$2'\r\n<\/pre>\n<p>Calling the extend method on an an instance will only extend that one object, objects of the same class will not be extended with the new functionality.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\nputs bigint1.format   # will generate an error\r\n<\/pre>\n<p>Modules that will be mixed with a class via the include or extend method could define something like a contructor or initializer method to the module.  The module initializer method will be invoked at the time the module is mixed with a class.  When a class extends a module the module&#8217;s self.extended method will be invoked:<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\nmodule Math\r\n  def self.extended(base)\r\n    # Initialize module.\r\n  end\r\nend\r\n<\/pre>\n<p>The self prefix indicates that the method is a static module level method.  The base parameter in the static extended method will be either an instance object or class object of the class that extended the module depending whether you extend a object or class, respectively.<\/p>\n<p>When a class includes a module the module&#8217;s self.included method will be invoked.<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\nmodule Stringify\r\n  def self.included(base)\r\n    # Initialize module.\r\n  end\r\nend\r\n<\/pre>\n<p>The base parameter will be a class object for the class that includes the module.<\/p>\n<p>It is important to note that inside the included and extended initializer methods you can include and extend other modules, here is an example of that:<\/p>\n<pre class=\"brush: ruby; title: ; notranslate\" title=\"\">\r\nmodule Stringify\r\n  def self.included(base)\r\n    base.extend SomeOtherModule\r\n  end\r\nend\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>In Java you just have classes (both abstract and concrete) and interfaces. The Ruby language provides classes, modules, and a mix of both. In this post I want to dive into mixins in Ruby. In the Ruby language a mixin is a class that is mixed with a module. In other words the implementation of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","footnotes":""},"categories":[19,22,3],"tags":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p902K-1W","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/posts\/120"}],"collection":[{"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/comments?post=120"}],"version-history":[{"count":2,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/posts\/120\/revisions"}],"predecessor-version":[{"id":1514,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/posts\/120\/revisions\/1514"}],"wp:attachment":[{"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/media?parent=120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/categories?post=120"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/juixe.com\/techknow\/index.php\/wp-json\/wp\/v2\/tags?post=120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}