Suggestions

Last Posts

  • Java: Thread notification

    Greetings. I thought I’d share a technique I like to use to have my threads work together. Here is the plot: you have a pool of working threads that do some heaving lifting operations, time consuming. They are here waiting for the next job to process, (...)

  • Java: full duplex socket communication

    Hello world. Today I’d like to share with you a piece of code to have a full duplex communication between Java Sockets. The idea is to open a ServerSocket on a dedicated port, and then to have several client Sockets to connect to it. The clients will use a (...)

  • The great journey of a little ICMP packet across the wide and dangerous Internet

    In this article we are going to see how an ICMP packet (a "ping") finds its way to reach a machine at the other side of the planet, and come back, all of it in a matter of milliseconds. Our case study We will not study every possible type of network that (...)

  • Tip: Linux immutable files

    Under Linux, using an EXT file system, you can make a file "immutable," meaning that nobody can change it, not even root. Here is how it’s done (as root): sudo chattr +i <file> To revert the operation, you type (as root): sudo chattr -i <file> (...)

  • Buffer Overflows: hacking the stack, again

    Here is another small tutorial where we will dig a little further into what is possible with the stack. Preparation In order for this tutorial to work, please temporarily deactivate the OS protection against Buffer Overflows: $ cat (...)

  • Buffer Overflows, a first approach

    Nearly half of security breaches come from Buffer Overflows. Buffer Overflows take advantage of a flaw in the code that created an application. The code basically allocates some memory but stores more data in it than what has been allocated. The result is (...)

  • Ruby metaprogramming

    To be able to understand this article about ruby metaclasses, you need to have in mind some basics of the Ruby language. Discovering the existence of metaclasses Ruby allows you to define methods on any object: o = Object.new def o.hello "Hello !" end (...)

  • Ruby fundamental concepts

    This post will lay out some important facts about the Ruby language in preparation of another post about Ruby metaprogramming. 1. Methods visibility public : always accessible. private : accessible only for that instance. It is often said that private (...)

  • Add a new hard drive to LVM partition

    Are you reaching the maximum capacity of your LVM partition? It is time to extend! We will see in this article how to add a new hard drive to a LVM partition. So shut your machine down, add the new hard drive, then start the machine again and read on! (...)

  • Ruby and oracle shared libraries

    You may experience the same problem as below if you are using the ruby-oci8 gem to connect to an oracle database: require ’oci8’ $ ruby test.rb /usr/lib/ruby/gems/1.8/gems/ruby-oci8-1.0.6/lib/oci8lib.so: libclntsh.so.10.1: cannot open shared object file: No (...)

  • Shell: cd current directory

    Quick post to share a useful command that I often use in my scripts to make sure that I know where "I am": cd $(readlink -f $(dirname $0)) Explanation: $0 is the first element of the command line invoked = the script itself dirname will give us the (...)

  • Launch a batch script without the command line window

    Hi folks, today we are going to talk a bit about a useful windows scripting trick that allows you to launch a batch script without seeing the extra CMD window popping up. Using a .exe launcher So you already have a batch file. The solution to avoid the (...)

  • Linux: File descriptor limits

    Sometimes a software can be refused the opening of a new resource by the Operating System because it has reached the maximum number of file descriptors used. This is usually cause by a code poorly implemented forgetting to properly close() the resources (...)

  • Redhat ssh auto login

    When you try to setup auto ssh login on a RedHat machine, don’t forget to setup the .ssh/ directory permissions so that only you can write on it : chmod a-w -R ~/.ssh chmod u+w -R ~/.ssh Otherwise the auto login will never (...)

  • Maven java webapp and jetty

    I very often use the jetty-maven-plugin in my Java Webapps. Basically it allows you to be able to run any webapp right after having checked out the project with the simple command: mvn jetty:run-exploded Then go by default on http://localhost:8080/ and (...)

  • CVSNT : read only

    Quick tip to share how to set your CVSNT in a read-only mode. The only thing you have to do is to create an empty file there: $CVSROOT/CVSROOT/writers And that’s it! No writers allowed means that nobody can write anything, job done. Source : CVS NT (...)

  • Creating and Applying Patches

    You sometimes need to use patches to hold some code changes to keep it safe and eventually apply it again later. Using Subversion You can easily create a path file with SVN like this: $ svn diff Index: testfile (...)

  • Max execution time with ruby threads

    This post will describe a way to define a maximum execution time for an operation using threads. Let’s start with a really simple program that takes 5 seconds to run : start=Time.now sleep 5 puts "Script finished in #Time.now-start" Let’s (...)

  • JVM Out Of Memory notification

    This is a quick tip for how to be notified of an OutOfMemory exception from the JVM. This is made possible using the option: -XX:OnOutOfMemoryError option of the JVM. Let’s write a simple program that is going to allocate a lot of memory: public class Oom (...)

  • 12
    18

    Ruby metaprogramming

    To be able to understand this article about ruby metaclasses, you need to have in mind some basics of the Ruby language.

    Discovering the existence of metaclasses

    Ruby allows you to define methods on any object:

    o = Object.new

    def o.hello
     "Hello !"
    end

    puts o.hello            #=> "Hello !"
    puts Object.new.hello   #=> undefined method `hello'

    Here we defined the method hello only for the instance ’o’ of Object. Any other instance of Object will not have this method.

    How is that possible since only Class objects can have methods? In fact, Ruby has a internal mechanism that creates a "metaclass" to store these object specific methods.

    What is a metaclass exactly?

    If I were forced to define what a metaclass is, I would say that it’s a hidden class attached to a particular object:

    - It is a class: it contains methods
    - It is hidden: metaclasses are more or less part of Ruby’s black magic and it is not so simple to access/manipulate these. We’ll come back to this later.
    - It is specific to an object: each object has its own metaclass.

    There is a very peculiar way to get to a metaclass’ context:

    class Foo
     class << self
       # At this point we are in the context of Foo's metaclass
       puts self
     end
    end       #=> #<Class:Foo>

    The special result #<Class:Foo> is specific to metaclasses. This syntax means: "I am an instance of Class attached to Foo."

    From the previous example, we can define a generic method on the Object class to access the metaclass of any object:

    class Object
     def meta
       class << self
         self
       end
     end
    end

    We can then write:

    class Foo
    end

    puts Foo.meta        #=> #<Class:Foo>
    puts Foo.new.meta    #=> #<Class:#<Foo:0xb7cb19cc>>

    Notice that the metaclass of an instance of Foo is specific to this instance #<Foo:0xb7cb19cc>.

    Defining methods on metaclasses

    Let’s check what has been said before: metaclasses store the methods of its attached object:

    class Foo
    end

    f = Foo.new

    def f.hello
     puts "Hello !"
    end

    f.hello                                          #=> Hello !
    puts f.meta.instance_methods.include?("hello")   #=> true
    puts f.singleton_methods.include?("hello")       #=> true

    The method directly defined on the object is stored in its metaclass. Another way to do the exact same thing would be to define the method in the metaclass’ context:

    class Foo
    end

    f = Foo.new

    class << f
     def hello
       puts "Hello !"
     end
    end

    f.hello                                          #=> Hello !
    puts f.meta.instance_methods.include?("hello")   #=> true
    puts f.singleton_methods.include?("hello")       #=> true

    Same thing here, we defined the method directly on the object metaclass. Same result: the method is available for this object only.

    As you know, classes are themselves instances (of Class), so they have their own metaclass as well. It is possible to use their metaclass to define methods on them:

    class Foo
     def self.hello
       puts "Hello !"
     end
    end

    Foo.hello                                          #=> Hello !
    puts Foo.meta.instance_methods.include?("hello")   #=> true
    puts Foo.singleton_methods.include?("hello")       #=> true

    Do you recognize it? It is the usual way to write a class method!

    You could also write:

    class Foo
    end

    class << Foo
     def hello
       puts "Hello !"
     end
    end

    Foo.hello                                          #=> Hello !
    puts Foo.meta.instance_methods.include?("hello")   #=> true
    puts Foo.singleton_methods.include?("hello")       #=> true

    It is equivalent.

    Unified behavior

    The management of the classes in Ruby is similar to the management of any other object. This is an attractive feature of Ruby. Classes store the methods for their instances, and if you want these classes to have methods too, you just do the same thing with their metaclass.

    The Object class define the method singleton_methods. It returns a list of the methods that can be called on an object (Module, Class or regular Object).

    Matz’s Ruby Interpreter (MRI)

    The C implementation of Matz’s Ruby Interpreter defines 3 basic structures:

    struct RBasic {  
       unsigned long flags;  
       VALUE klass;  
    };

    struct RObject {  
       struct RBasic basic;  
       struct st_table *iv_tbl;  
    };

    struct RClass {  
       struct RBasic basic;  
       struct st_table *iv_tbl;  
       struct st_table *m_tbl;  
       VALUE super;  
    };

    A Ruby Object is a RObject, containing:

    - a reference to a RClass: value klass
    - state flags: unsigned long flags ( designed to store information like taint, freeze, etc. )
    - a map of the instance variables: struct st_table *iv_tbl

    A Ruby Class is a RClass, containing:

    - a reference to a RClass, state flags and instance variables like an Object. This is the reason why we consider that a Ruby class can be seen as an object.
    - a map of the methods: struct st_table *m_tbl
    - a reference to a RClass "super" pointing to the superclass: VALUE super

    Important note about the relationship of these C structures:

    For a given RClass rc, the super RClass of the klass of rc is the klass of the super RClass of rc.

    I know it sounds complicated but consider this example:

    class Foo
    end

    class Bar < Foo
    end

    The RObjects and RClasses at work here can be represented like this:

    - the klass of the super RClass of Bar is: Foo’s metaclass
    - the super RClass of the klass of Bar is: Foo’s metaclass

    It’s just how it has been coded. This is hidden from Ruby:

    class Foo
    end

    class Bar < Foo
    end

    puts Bar.meta.superclass   #=> #<Class:Class>
    puts Bar.superclass.meta   #=> #<Class:Foo>

    Ruby considers that any metaclass’ superclass is the metaclass of Class.

    Search order for a method

    When you call a method on an object, where does Ruby search for this method?

    Well here is how it works:

    - The search begins in the methods of the RClass of this RObject
    - From there it will search up all of its super RClasses until it finds the method

    So for the previous example with Bar < Foo, a call like Bar.new.hello would follow this path to find the method ’hello’:

    - search in Bar
    - search in Foo
    - search in Object

    This ensures the inheritance of instance methods.

    The same way, a call to Bar.hello would follow this path:

    - search in Bar.meta
    - search in Foo.meta
    - search in Object.meta
    - search in Class

    This ensures the inheritance of class methods.

    Open classes

    A class definition is never sealed in Ruby. They remain "open":

    class Foo
     def self.load_hello
       def hello
         puts "Hello !"
       end
     end
    end

    begin
     Foo.new.hello  #=> dynamic_methods.rb:9: undefined method `hello' for ...
    rescue
     Foo.load_hello
     Foo.new.hello  #=> Hello !
    end

    The method hello has been loaded dynamically.

    Extending classes

    There is a widely accepted way to extend an existing model in the Ruby community.

    Let’s create a simple acts_as_* module. Let’s make a "acts_as_taggable" to associate a tag to an object. The tag will contain anything you want. It will be basically similar to the behavior of attr_accessor.

    A way to do that is to add this capability on the super class (like ActiveRecord does), and then call the feature in a subclass.

    model.rb:

    require 'acts_as_taggable'

    class MyBase
     include Acts::Taggable
    end

    class Foo < MyBase
     acts_as_taggable :info
    end

    class Bar < MyBase
     acts_as_taggable :comment
    end

    The file ’acts_as_taggble.rb’ will contain the definition of the module Acts::Taggable:

    module Acts
     module Taggable

       def self.included(base)
         puts self   #=> Displays Acts::Taggable

         # adds ClassMethods instance methods to the class object 'base'
         base.extend(ClassMethods)
       end

       module ClassMethods

         def acts_as_taggable( name )
           puts self   #=> Displays Foo, then Bar
         end

       end

     end

    When the module will be included by MyBase, the method "included" will be invoked on the Acts::Taggable module (self) with the including class as a parameter (base).

    With this parameter (base=MyBase) of type Class, we are going to add the methods of another module, usually called "ClassMethods". In our case, act_as_taggable will be added to MyBase’s singleton_methods (so they will be class methods).

    This acts_as_taggable method will be used in the context of the caller. "self" will represent the class that will actually use act_as_taggable (Foo, Bar), not the module nor the superclass (MyBase).

    The job of act_as_taggable when actually invoked is to dynamically define a getter and a setter method on the class:

    module Acts
     module Taggable

       def self.included(base)
         # adds ClassMethods instance methods to the class object 'base'
         base.extend(ClassMethods)
       end

       module ClassMethods
         
         def acts_as_taggable( name )
           class_eval <<-END_CE
             def #{name}=(t)
               @tag=t
             end
             def #{name}
               @tag
             end
           END_CE
         end

       end

     end
    end

    The class_eval method will define the info et info= methods on Foo, and comment et comment= on Bar. Those are the accessor methods for the instance variable @tag.

    require 'model'

    f = Foo.new
    f.info = "This class is beautiful !"

    b = Bar.new
    b.comment = "I'm just another class"

    puts f.info               #=> "This class is beautiful !"
    puts b.comment            #=> "I'm just another class"

    Voila

    We are done for now. I hope some of you found some answers and/or questions in this article :) See you soon!

    Resources

    - An infoQ conference by Dave Thomas about Ruby metaprogramming basics
    - An article about Ruby metaclasses and why they are useful
    - An article by Patrick Farley explaining the different implementations of the MRI
    - The Ruby hacker guide chapter 4 about the MRI implementation
    - A screencast by Dave Thomas


  • pre-moderation

    This forum is moderated beforehand: your contribution will only appear after being validated by a site administrator.

    Any message or comment?
    • (To create paragraphs, you simply leave blank lines.)

    Who are you? (optional)

enfants soldats