metaruby package from metaruby repo


Package Summary

Tags No category tags.
License LGPLv3
Build type ROSBUILD

Repository Summary

Checkout URI
VCS Type git
VCS Version master
Last Updated 2022-08-10
CI status No Continuous Integration
Tags No category tags.
Contributing Help Wanted (0)
Good First Issues (0)
Pull Requests to Review (0)

Package Description

Additional Links

No additional links.


  • Sylvain Joyeux/sylvain.joyeux


No additional authors.

Build Status Gem Version Documentation

Metamodelling in the Ruby type system

MetaRuby is a library that allows to (ab)use the Ruby type system to create reflexive programs: create a specialized modelling API (a.k.a. "a DSL") at the class/module level and then get access to this model information from the objects.

This page will describe the various functionality that metaruby provides to help modelling in Ruby.

This page will reuse one of the most overused example of modelling: a car and colors.


Using MetaRuby, models can either be represented by Ruby classes or by Ruby modules. You use the first one when you want to model something from which an object can be created, in our example: a car. You use the second for things that cannot be instanciated, but can be used as attributes of another object, in our example: a color.

Another point of terminology: metamodel. The metamodel is the model-of-the-model, i.e. it is the bits and pieces that allow to describe a model (the model itself describing an object). As you will see, metamodels in MetaRuby are all described in modules.

Models as classes

The metamodel of models that are represented by classes must include {MetaRuby::ModelAsClass} and are then used to extend said class

module Models
  module Car
    include MetaRuby::ModelAsClass
class Car
  extend Models::Car

Then, creating a new Car model is done by subclassing the Car class:

class Peugeot < Car
  # Call methods from the modelling DSL defined by Models::Car

This creates a named model, i.e. a model that can be accessed by name. Another way is to create an anonymous model by calling {MetaRuby::ModelAsClass#new_submodel new_submodel}:

model = Car.new_submodel do
  # Call methods from the modelling DSL defined by Models::Car

Note that this mechanism naturally extends to submodels-of-submodels, e.g.

class P806 < Peugeot
  # Call methods from the modelling DSL defined by Models::Car

Models as modules

The metamodel of models that are represented by modules must include {MetaRuby::ModelAsModule} and are then used to extend said module

module Models
  module Color
    include MetaRuby::ModelAsModule
module Color
  extend Models::Color

Then, creating a new Color model is done by calling {MetaRuby::ModelAsModule#new_submodel new_submodel} on Color

red = Color.new_submodel

A common pattern is to define a method on the Module class, that creates new models and assigns them to constants. MetaRuby provides a helper method for this purpose, that we strongly recommend you use:

class Module
  def color(name, &block)
    MetaRuby::ModelAsModule.create_and_register_submodel(self, name, Color, &block)

Which can then be used with:

module MyNamespace
  color 'Red' do
    # Call methods from the color modelling DSL defined by Models::Color

The new Red color model can then be accessed with MyNamespace::Red

A model hierarchy can be built by telling MetaRuby that a given model provides another one, for instance:

color 'Yellow' do
  provides Red
  provides Green

And, finally, a class-based model can provide a module-based one:

class Peugeot < Car
  # All peugeots are yellow
  provides Yellow


One important part of the whole modelling is to list attributes of the things that are getting modelled. The important bit being the definition of what should happen when creating a new submodel for an existing model. Even though we will use the class-as-model representation in all the following examples, the exact same mechanisms are available in the model-as-module. The only difference is that a class-as-model is a submodel of all its parent classes while a class-as-module is a submodel of all the other modules it provides.

Zero-or-one attributes

These are attributes that hold at most one value (and possibly none). The typical example is the predicate (boolean attribute)

module Models::Car
  include MetaRuby::ModelAsClass

  # Attribute inherited along the hierarchy of models
class SportsCar < Car
  # Make the default number of doors of all sports car 2
  number_of_doors 2
class ASportsCar < SportsCar
  # Actually, this one has a trunk
  number_of_doors 3
class AnotherSportsCar < SportsCar
Car.number_of_doors => nil
SportsCar.number_of_doors => 2
ASportsCar.number_of_doors => 3
AnotherSportsCar.number_of_doors => 2 # Inherited from SportsCar

Set attributes

These are attributes that hold a set of values. When taking into account the hierarchy of models, the set for a model X is the union of all the sets of X and all its parents:

module Models::Car
  include MetaRuby::ModelAsClass
  # Attribute inherited along the hierarchy of models
  inherited_attribute("material", "materials")
class Car
  extend Models::Car
  materials << 'iron' # all cars contain iron
class Peugeot < Car
  materials << 'plastic' # additionally, all peugeot cars contain plastic
Car.each_material.to_a => ['iron']
Peugeot.each_material.to_a => ['iron', 'plastic']
Car.all_materials => ['iron']
Peugeot.all_materials => ['iron', 'plastic']
Car.self_materials => ['iron']
Peugeot.self_materials => ['plastic']

Named attributes

In certain situations, elements of the sets that we represented in the previous section can actually have names (where the names are actually part of the modelling).

module Models::Car
  include MetaRuby::ModelAsClass
  # Attribute inherited along the hierarchy of models
  inherited_attribute("door_color", "door_colors")
  def number_of_doors
class Car
  extend Models::Car
  door_colors['driver'] = Color # There is a driver door, but we don't know
                                # the color
  door_colors['other'] = Color # There is another door, but we don't know
                                # the color
class Peugeot < Car
  # All peugeot have a red driver door and a green trunk door
  door_colors['driver'] = Red
  door_colors['trunk'] = Green
Car.self_door_colors => {'driver' => Color, 'other' => Color }
Car.all_door_colors => {'driver' => Color, 'other' => Color }
Peugeot.self_door_colors => {'driver' => Red, 'trunk' => Green }
Peugeot.self_door_colors => {'driver' => Red, 'other' => Color, 'trunk' => Green }

Value promotion

In some cases, one need to modify the values inherited from the parent models before they can become proper attributes of the child model, commonly because the objects stored in the attributes refer to the model they are part of. For instance, let's assume we have a Door object defined thus:

Door = Struct :car_model, :color


Car.doors['driver'] =, Color)
Car.doors['other'] =, Color)


Peugeot.find_door('driver').car_model => Car

In most cases, we would like to have this last value be Peugeot. This can be done by defining a promotion method on the metamodel before the inherited attribute is defined:

module Models::Car
  # Called to promote a door model from its immediate supermodel to this
  # model
  def promote_door(door_name, door)
    # You have to create a new door object !
    door = door.dup
    door.car_model = self

  # Define the attribute *after* the promotion method
  inherited_attribute("door", "doors")

Model Registration

The last bit that MetaRuby takes care of is to register all models that have been defined, allowing to browse them by type. For instance, all models based on the Car model can be enumerated with:


Because this mechanism keeps a reference on all model objects, it is necessary to clear the registered submodels dealing with e.g. tests that create submodels on the fly. This is done by calling {MetaRuby::Registration#clear_submodels clear_submodels} in the tests teardown:


This will only clear anonymous models. Models that are created either by subclassing a model class or by using {MetaRuby::ModelAsModule.create_and_register_submodel} are marked as {MetaRuby::Registration#permanent_model?} and therefore protected from removal by #clear_submodel

Adding options to the submodel creation process

If you need to customize the submodel creation process, for instance by providing options to the subprocess, do so by overloading #setup_submodel. Do NOT overload #new_submodel unless you really know what you are doing, and pass the options as an option hash


Wiki Tutorials

See ROS Wiki Tutorials for more details.

Source Tutorials

Not currently indexed.

Package Dependencies

Deps Name
0 bundler
1 utilrb
0 kramdown

System Dependencies

No direct system dependencies.

Dependant Packages

No known dependants.

Launch files

No launch files found


No message files found.


No service files found


No plugins found.

Recent questions tagged metaruby at Robotics Stack Exchange