• Guides
  • Videos
  • Publications
  • API
  • Github
  • Community
  • Release Notes
  • Plugins
Installing Origen
  • Introduction
  • How to Install
  • How to Install (Windows)
  • Company Customization
  • Understanding Gems
  • Invoking Considerations
  • Workspace Management
Getting Started with Origen
  • Core concepts
  • Creating a New App
  • Directory Structure
  • The Initial Commit
  • Creating New Files
  • Understanding Blocks
  • Application Architecture
Runtime Environment
  • Introduction
  • Mode
  • Environment
  • Target
  • Production Targets
  • Global Setup
  • Load Order
  • Programming
Models
  • Introduction
  • Naming
  • Definition & Hierarchy
  • Adding Attributes
  • Versioning
  • Bugs & Features
  • Package, Mode & Configuration
  • Registers
  • Pins
  • Power Domains
  • Hardware Attributes
  • Parameters
  • Specifications
  • Fuses
  • Generic Components
  • Creating Your Own Components
Compiler (Views)
  • Introduction
  • Creating Templates
  • Using Sub-Templates
  • Helpers
  • Running The Compiler
  • Inline Compiler
Controllers
  • Introduction
  • Shadow Controllers
  • Direct Controllers
Pattern Generator
  • Introduction
  • Creating Patterns
  • Pins
  • Timing and Waiting
  • Registers
  • Documenting Patterns
  • Generating by Name
  • Common API
  • J750 API
  • V93K API
  • UltraFlex API
  • STIL & Other Formats
  • Custom Testers
  • Running The PatGen
  • Concurrent Patterns
Test Program Generator
  • Introduction
  • Philosophy
  • Creating Flows
  • Managing Flow Control
  • Creating an Interface
  • Additional Resources
  • Dynamic Custom Code
  • Characterization API
  • J750 API
  • V93K Common API
  • V93K SMT7 API
  • V93K SMT8 API
  • UltraFLEX API
  • Documenting the Program
  • Creating Custom Testers
  • Running the ProgGen
Decompilation
  • Overview & Example
  • Decompiling, Adding Pins, & Executing
  • Working with Decompiled Patterns
  • Platform Specifics
Simulation
  • Introduction
  • How It Works
  • Compiling the DUT
  • AMS Support
  • Environment Setup
  • Application Setup
  • Simulating Patterns
  • Simulating Flows
  • Direct DUT Manipulation
  • Simulator Log Output
  • Artifacts
  • Debugging
Documentation Generator
  • Introduction
  • Markdown
  • Linking
  • Styling
  • Testing
  • API Generation
  • Deploying
Plugins
  • Introduction
  • Using a Plugin
  • Creating a Plugin
  • Current & Default Plugins
  • Dev Environment
  • Dev Considerations
  • Paths & Origen.root
  • Config & Origen.app
Miscellaneous
  • Revision Control
  • Origen Remotes
  • Lint Testing
  • Session Store
  • LSF API
  • Users, Emails & Maillists
  • Utilities & Helpers
  • Ruby Extensions
  • Logger
  • Adding Commands
  • Overriding Commands
  • Callbacks
  • Application Callbacks
  • Miscellaneous Topics
Advanced Topics
  • Introduction
  • Invocation Customization
  • Custom App Generators

Models

Creating Your Own Components


If you’ve looked at the section on SubBlocks and at the section on Components, you’ll probably notice many similarities. It may seem that SubBlocks are just a more sophisticated and feature rich version of Components.

The Origen::Componentable module (henceforth referred to as just Componentable) is a mixin. The name Componentable is a protologism taking after Ruby’s own Enumerable mixin. By mixing in Componentable with your classes, you will automatically be given methods to add, remove, move, copy, and query objects you’ve added. Now, you may think… “well, that’s easy enough to do on my”, and that’s very true. But, Componentable will handle all that boiler plate code for you while providing a common interface and having an easily managed/updated mixin so that bug fixes and feature enhancements will be felt across all your Componentable classes without any intervention from you (other than updating the Origen version, that is).

Furthermore, Componentable can handle initiailizing Componentable's parent classes. This means that in addition to your class receiving add, remove, query, etc. methods internally, any parent that uses your class will also receive add, remove, query, etc. methods, again, without any intervention.

If this is of interest to you, sections below will discuss how to mixin the Componentable module, how to handle instantiating and initializing your classes, and what the API provides.

Mixing In Componentable

Mixing in Componentable is easy and does not require that any particular methods be defined. You can mix it in by just putting the following into your class:

include Origen::Componentable

Componentable actually contains two APIs: The first is the API provided to the includer class, that is, the class that includes Componentable. This includer class is then added to a parent class.

In other words, the parent class is the one that users of you new Componentable class will interact with. Whereas the includer class acts as the interface between the parent class and the structures that actually hold and maintain the items.

If this is still confusing, it should make more sense as you move through this guide and for now, just know that the class that contains include Origen::Componentable is the includer class and the class that users the componentable class is the parent class.

Contents

There’s quite a few sections to this guide. The marks below should help you jump around appropriately.

  1. The Componentable Class
    1. Booting the Includer
    2. Includer Class API
      1. Adding
      2. Querying
      3. Moving & Copying
      4. Iterating
      5. Removing
    3. Includer Class Organization
    4. Naming the Includer Class
    5. Conclusion
  2. The Parent Class
    1. Booting the Parent
    2. The Parent API
    3. Controlling Accessors on the Parent
    4. Example Parent API
      1. Basics
      2. Adding
      3. Querying
      4. Iterating
      5. Copying & Moving
      6. Deleting
    5. Generic Parent API
      1. Basics
      2. Adding
      3. Querying
      4. Iterating
      5. Copying & Moving
      6. Deleting
  3. Componentable Class
    1. Componentable Class
  4. Componentable Class
  5. Componentable Class

The Componentable Class

Booting the Includer

All that Componentable requires is an instance variable called _componentable_container. This is a generic name that the API below will interact with.

Depending on how you setup your class, you still may not need to do anything. If your componentable class includes Origen::Model, then the boot process will take place automatically. Componentable implements an origen_model_init callback handler for you (see here). This callback will add and initialize this object during the includer class's initialization. So, the following will take care of everything for you:

include Origen::Model
include Origen::Componentable

If you are not using include Origen::Model, you’ll need to take some action yourself. Componentable comes with a method to assist with this: init_includer_class (includer being the class that includes Componentable). Calling this method in your class’s initialize function will accomplish the same thing as including Origen::Model. The usage is:

# Initialze the _componentable_container object
# Note that this is in the Origen::Componentable module's class methods, not in the mixin.

# Initialize internal to the class

class Includer
  include Origen::Componentable

  def initialize(options={})
    Origen::Componentable.init_includer_class(self)
  end
end


# Initialize externally an already existing object
class Includer
  include Origen::Componentable
end

i = Includer.new
Origen::Componentable.init_includer_class(i)

After booting, the includer class is ready!

Includer Class API

This is the API that includer classes will get for free. However, any of these can be overridden or extended to further customize the Compentable object.

The basic API includes these methods:

Adding new objects
add(name, options={}, &block)
#=> adds a new object, :name

add(name, class_name: ClassToAdd
#=> adds a new object of class ClassToAdd

add(name) do |n|
  n.class_name ClassToAdd
end
#=> (also) adds a new object of class ClassToAdd using block syntax

Querying objects
list
#=> list the available names in the componentable container

has?(name)
#=> returns true if and object with :name has been added

[](name)
#=> returns the object at :name, or nil if :name has not been added

Moving and copying objects
copy(to_copy, to_location, options = {})
#=> # copies an object from to_copy to to_location, cloning the object

move(to_move, new_name, option={})
#=> Moves an object from to_move to new_name

Iterating through objects
each(&block)
#=> runs the generic :each method from enumerable across the underlying componentable container hash

select(&block)
#=> runs the generic :select method from enumerable across the underlying componentable container hash

instances_of(class_name)
#=> returns an array of all the names of class :class_name

Removing objects
# aliased as :remove
delete(to_delete)
#=> deletes the object at :to_delete, returning the object

# aliased as :clear and :remove_all
delete_all
#=> deletes everything in the componentable container

All of these will operate on the componentable_container object and all are provided to you. These methods will also be called by the parent class to perform these operations, but more on that later. You should just know that undefining these methods or changing around their arguments will change the way that the parent class will need to interact with the includer class.

Includer Class Organization

In order to use this to the full power provided, the namespacing must be set up rather specifically. You can always boot the classes manually, so don’t let this put you off from creating your own Componentable Classes but the example namespacing below will show you the recommended way of organizing the modules and classes such that the parent class can bring in you new Componentable class with a single line.

As will be covered in later when booting the parent class, the goal is to bring in your Componentable class as a single line. If you decided to name your Componentable class MyTest for example, then what we’re looking for in the parent class is simply:

class Parent
  include Origen::Model
  include MyTest
end

Well, what’s the problem with this right now? MyTest isn’t a module. Its a class. We can’t include a class, Ruby won’t let us. But we can do is namespace our MyTest class in a module also named MyTest, in this case. When this module is included, Componentable will signal to Origen that this module MyTest contains Componentable classes that must be booted. So, a simple implementation may look like:

module MyTest
  class MyTest
    include Origen::Model
    include Origen::Componentable
  end
end

Note that the name of the module actually isn’t important. As long as the module contains some Componentable classes everything will go as expected. You aren’t even limited to a single class per module. If you have a few Componentable classes in a module, they will each be booted.

module MyTests

  class MyBasicTest
    include Origen::Model
    include Origen::Componentable
  end
  
  class MyIntermediateTest
    include Origen::Model
    include Origen::Componentable
  end
  
  class MyAdvancedTest
    include Origen::Model
    include Origen::Componentable
  end

end

An in-depth explanation of how this occurs is out of scope right now, but you can see the section on advanced booting if you wish to know more and get a developers perspective.

Naming The Includer Class

Define the API based on the name of the includer class? Yep! When trying to add the parent API, two names will be used: the singleton_name and the plural_name. The process for this is:

  1. Use Ruby’s/Rail’s underscore method as the singleton_name
  2. Apply a few general rules that covers most cases for pluralizing. This will be the plural_name

In general, this will just be adding an s to the singleton_name, but it can handle a few other cases, such as:

  • ‘is’ -> ‘es’ (as in ‘analysis’ -> ‘analyses’)
  • ’s/h/ch/sh/x/z’ -> ‘es’ (as in ‘bus’ -> ‘buses’, or ‘box’ -> ‘boxes’)
  • ‘on’ -> ‘a’ (as in ‘criterion’ -> ‘criteria’)
  • all other cases will just ‘s’ appended (as in ‘component’ -> ‘components’)

You can run this method on your class yourself in interactive mode. This returns a Hash with keys singleton_name and plural_name. For example:

Origen::Componentable.componentable_names(Origen::Component)

{
  singleton_name: :component
  plural_name: :components
}

Origen::Componentable.componentable_names(MyTest)

{
  singleton_name: :my_test
  plural_name: :my_tests
}

We here at Origen are engineers, not writers, and not interested in figuring out all rules of how to make everything plural (I can tell you, the author of this particular section is a native english speaker, and still got half rules wrong before looking them up). So, if you don’t like the name Compomentable gave you, no problem! You can define it yourself using two class constants (not instance variables). The following examples will show this:

class MyTest
  COMPONENTABLE_SINGLETON_NAME = 'just_test'
end

# This will take the 'just_test' singleton_name, and pluralize it as using that name
{
  singleton_name: :just_test
  plural_name: :just_tests
}
class MyTest
  COMPONENTABLE_PLURAL_NAME = 'just_tests'
end

# This will evaluate the singleton name as normal, but use the given plural name
{
  singleton_name: :my_test
  plural_name: :just_tests
}
class MyTest
  COMPONENTABLE_SINGLETON_NAME = 'test'
  COMPONENTABLE_PLURAL_NAME = 'tests'
end

# This will use both the provided singletoneand plural name.
{
  singleton_name: :test
  plural_name: :tests
}

Ruby itself has some requirements though. Due to how these names will be used, they can’t start with a capital letter. So, even if you define a COMPONENTABLE_SINGLETON_NAME and/or a COMPONENTABLE_PLURAL_NAME name, they are getting downcased either way or Ruby won’t let us run anything.

Note that even this breaks down for words like deer, as Componentable requires that the singleton name and plural name be different (otherwise methods will step on each other), and will complain if this is not met. So, apologies, but you’ll have to keep the plural of your Deer class as Deers, which is technically correct actually, but not really important so… moving on.

Includer Class Conclusion

This covers everything the includer class gets for free. Next, we’ll discuss the parent class.

For information on customizing the includer class you can jump here, but this may not make as much sense without first getting the parent’s perspective.

The Parent Class

The parent API is really what is interesting. When you use the generic Origen components, say, for example, on your $dut, you use methods like $dut.add_component, $dut.components_of_class, $dut.has_component?, etc. But where do these methods come from? You would think that these are part of Origen, that somewhere deep in bowels of the code base are a bunch generic methods to operate on some Component class somewhere. But, that’s not true.

Those methods are added by booting the parent class of a Componentable includer class

Booting the Parent

Since we can’t do much without booting the parent class, we’ll cover that now. Booting the parent is more involved than booting the includer. That said, if the includer class is set up a certain way, as discussed here then the boot process for the parent can be automated as well. Booting the parent class includer has two steps:

  1. Instantiate the includer class as an instance variable on the parent class.
  2. Define the API on the parent class based on the name of the includer class.

The easiest way is just to let Origen to do it for you. Like the includer class, including Origen::Model will let us hook into the intializer to take care of booting the parent for you.

Danger! This requires that your includer class is also either an includer of code>Origen::Model</code> OR intializes itself. If not, you'll end up with a fully built parent-API and its very own instance variable pointing to an includer class... that has no comopnentable container. As you can imagine, all of the attempt to use the includer will result is errors. You can boot it yourself there in the parent as discussed here. This can also be used to boot includer classes that are not setup as described here.

If we let Origen do it, and if our includer classes are setup as shown in the includer organization section, we can simply do this by include the module, including Origen::Model and going on our way.


class Parent
  include Origen::Model
  include MyTest
end

parent = Parent.new
parent.my_test #=> Instance of MyTest Componentable class.
parent.list_my_tests #=> list the current added my_tests, in this case, []

But, say we want to boot it directly. That is, not rely on Origen. We can do that using the method Origen::Componentable.init_parent_class (class method within the Origen::Componentable namespace). We can give this both the instance of the parent class and the includer class and it will handle booting for you. For example:


# Internal to the parent class
class Parent
  #include MyTest #=> nevermind, don't need this right now.

  def intiailize
    Origen::Componentable.init_parent_class(self, MyTest)
  end
end

# External to the parent class
class Parent
  #include MyTest #=> nevermind.

  def intiailize
    #Origen::Componentable.init_parent_class(self, MyTest) #=> Nevermind this too.
  end
end

p = Parent.new
Origen::Componentable.init_parent_class(p, MyTest)

And… we’re done! Now we’ve got the parent booted up and we’re ready to start using it.

The Parent API

Now, the API for the parent is bit trickier… as its not static. What exactly the parent API is will be dependent on what you’ve named your class.

Continuing on with our MyTest includer class example, we can use the naming convention here to know that:

  1. The singleton name is: my_test
  2. The plural name is: my_tests

After booting, we’ll be able to use our includer class on the parent:


p.my_test   #=> MyTest object
p.my_tests  #=> {}

p.add_my_tests(:test1)
p.list_my_tests #=> ["test1"]

p.add_my_tests(:test2) do |t|
  t.class_name TestClass
end

p.list_my_tests #=> ["test1", "test2"]

p.my_tests["test1].do_something
#=> run method :do_something with object at name "test1"

Since this API is not static, its more difficult to document. The generic API is actually just placeholders that can be found here.

This API will show which Componentable method is called. So, calling the method from the parent class boils down to calling an includer class method and all of relevent and defined options will be passed down to it. You can review the full includer API here.

Controlling Accessors on the Parent

As with compoments, we added COMPONENTABLE_ADDS_ACCESSORS = true constant in the MyTest class. So, we can expect:

p.test1 #=> Object stored in MyTest at name :test1
p.test2 #=> Object stored in MyTest at name :test2

But, say we already had method :test1 on the parent? The result would be a Origen::Componentable::NameInUseError. And if we had multiple test classes, and all had a :test1 and all decided to add COMPONENTABLE_ADDS_ACCESSORS = true, what can our parent do?

For a new example, say we have two includer classes: MyClockingTest and MyPowerTest, and both decided that COMPONENTABLE_ADDS_ACCESSORS = true. Also, our specification says that both need to have a test named :test1. We have a few ways we can deal with this.

First, we can just disable all accessors on the parent unconditionally (including components). This takes away the ability for us to use parent.test1, but now we can have parent.my_clocking_tests[:test1] and parent.my_power_tests[:test1] coexisting. We can do this by setting an attr_reader or defining a method :disable_componentable_accessors and having it return true. Everytime an accessor is added, it will see that on the parent and decide against adding said accessor.

But, we can also dictate which includer classes shouldn’t have accessors and which should. Maybe we want to disable only the accessors on MyClockingTest and MyPowerTest, but leave them for Compoonents.

If you define the method :disable_componentable_accessors to instead take an argument, Componentable will give it the includer class requesting to add an accessor, as a class name. We can write a method like so to do this:

def disable_componentable_accessors includer_class
  if includer_class == MyClockingTest || includer_class == MyPowerTest
    true
  else
    false
  end
end

You can build this method however you see fit on the parent to only get the accessors you want from the various includers.

An Example API

Using our MyTest includer class again, imported by our Parent parent class, the full API we have available on the parent is below. You can skip to here to view the API in generic terms.

We know from before that the singleton_name is :my_test and that plural_name is :my_tests. With these in mind, the API on the parent class will resolve to:

Basics
# Retrieving an instance of the MyTest object
parent.my_test 
  #=> instance of MyTest 

# Retrieving MyTest's componentable container
parent.my_test._componentable_container
parent.my_tests
  #=> Hash with indifferent access

# Retrieving MyTest instance variable directly on the parent
instance_variable_get("@_my_test".to_sym) #=> instance variable on the parent class

Adding
# Adding Objects
# These methods correspond to a my_test.add call.
parent.my_test(name, options={}, &block)
parent.my_tests(name, options={}, &block)
parent.add_my_test(name, options={}, &block)
# add_my_test is aliased to:
  #=> add_my_tests

Querying
# Listing Names of Objects
# These methods correspond to a my_test.list call
parent.list_my_tests

# Querying Objects
# These methods correspond to a my_test.instances_of call
parent.my_tests_of_class(class_name)
# my_tests_of_class is aliased to:
  #=> my_tests_instances_of
  #=> my_tests_of_type

Iterating
# Emumerating
# These methods correspond to a my_test.each call
parent.my_tests(&block)
parent.each_my_test(&block)
# each_my_test is aliased to:
  #=> all_my_tests

# Selecting
# These methods correspond to a my_test.select call
parent.select_my_tests(&block)
# select_my_tests is aliased to:
  #=> select_my_test

Copying and Moving
# Copying
# These methods correspond to a my_test.copy call
parent.copy_my_test(to_copy, to_location, options={})
# copy_my_test is aliased to:
  #=> copy_my_tests

# Moving
# These methods correspond to a my_test.move call
parent.move_my_test(to_move, to_location, options={})
# move_my_test is aliased to:
  #=> move_my_tests

Deleting
# Deleting Single Objects
# These methods correspond to a my_test.delete call
parent.delete_my_test(name)
# delete_my_test is aliased to:
  #=> delete_my_tests
  #=> remove_my_test
  #=> remove_my_tests

# Deleting All Objects
# These methods correspond to a my_test.delete_all call
parent.delete_all_my_tests
# delete_all_my_tests is aliased to:
  #=> clear_my_tests
  #=> remove_all_my_tests

Also recall, that these methods link directly back to just calling the corresponding method on the includer class, so the full method documentation (parameters, options, return values, exception raised, etc.) can be found back at the includer class’ API.

Generic Parent API

In more generic terms, adding an includer to a parent yields the following API on the parent class:

Recall here that you can use the methods _singleton_name and _plural_name on an instance of an includer class to query those names. You can also use the class method Origen::Componentable.componentable_names(includer) to get a hash containing the keys :singleton and :plural, either with an instance of the includer class or with the class directly.

Once again, these methods link directly back to just calling the corresponding method on the includer class, so the full method documentation can be found back at the includer class’ API.

Basics
# Retrieving an instance of the includer class object
parent.<singleton_name> #=> instance of the includer class

# Retrieving an instance of the includer class's componentable container
parent.<singleton_name>._componentable_container
parent.<plural_name>

# Retrieving the includer instance variable directly
instance_variable_get("@_<singleton_name>".to_sym) #=> instance variable on the parent class

Adding
# Adding Objects
# These methods correspond to a <singleton_name>.add call.
parent.<singleton_name>(name, options={}, &block)
parent.<plural_name>(name, options={}, &block)
parent.add_<singleton_name>(name, options={}, &block)
# add_<singleton_name> is aliased to:
  #=> add_<includer_plural_name>

Querying
# Listing Names of Objects
# These methods correspond to a <singleton_name>.list call
parent.list_<plural_name>

# Querying Objects
# These methods correspond to a <singleton_name>.instances_of call
parent.<plural_name>_of_class(class_name)
# <plural_name>_of_class is aliased to:
  #=> <plural_name>_instances_of
  #=> <plural_name>_of_type

Iterating
# Emumerating
# These methods correspond to a <singleton_name>.each call
parent.<plural_name>(&block)
parent.each_<singleton_name>(&block)
# each_<singleton_name> is aliased to:
  #=> all_<plural_name>

# Selecting
# These methods correspond to a <singleton_name>.select call
parent.select_<plural_name>(&block)
# select_<plural_name> is aliased to:
  #=> select_<singleton_name>

Copying and Moving
# Copying
# These methods correspond to a <singleton_name>.copy call
parent.copy_<singleton_name>(to_copy, to_location, options={})
# copy_<singleton_name> is aliased to:
  #=> copy_<plural_name>

# Moving
# These methods correspond to a <singleton_name>.move call
parent.move_<singleton_name>(to_move, to_location, options={})
# move_<singleton_name> is aliased to:
  #=> move_<plural_name>

Deleting
# Deleting Single Objects
# These methods correspond to a <singleton_name>.delete call
parent.delete_<singleton_name>(name)
# delete_<singleton_name> is aliased to:
  #=> delete_<plural_name>
  #=> remove_<singleton_name>
  #=> remove_<plural_name>

# Deleting All Objects
# These methods correspond to a <singleton_name>.delete_all call
parent.delete_all_<plural_name>
# delete_all_<plural_name> is aliased to:
  #=> clear_<plural_name>
  #=> remove_all_<plural_name>

Customizing Your Componentable Class

This section will go over some ways to further customize the Componentable class. Recall that any of the Componentable class’s API can be overridden by the includer class.

Adding New Items

Most likely, you will want to override the add method to cover how to add your custom components. The standard add method will simply instantiate the given class (or a default class if none is given), check that the name doesn’t already exist, add the component, then provide an accessor if set to do so. Not much. It does a bit more if given an instances option, but that is handled as well. However, add is actually split into a few methods that you can use if you override add.

The add method itself calls two methods: _split_by_instances and _add.

_split_by_instances is responsible for cutting up the options given into chunks for each instance. You can see the component’s page on multiple instances for a refresher but this will the instances option handling for your class in check with other Componentable classes. Once split up, each individual instance and its options are given to the _add method.

_add does three things: it puts in some default options, calls the _instantiate_class method and calls the </code>_push_accessor</code> method. Most likely, this is what you’ll want to override. From here, you can build in any defaults/settings that you want and throw errors if things are missing or incorrect. Then you can finish up by calling the two aforementioned methods. For example, the code for the default _add is just:

def _add(name, options={}, &block)
  # Add the name and parent to the options if they aren't already given
  # If the parent isn't available on the includer class, it will remain nil.
  options = {
    name: name,
    parent: parent
  }.merge(options)
  
  if block_given?
    collector = Origen::Utility::Collector.new
    yield collector
    options.merge!(collector.store)
  end
  
  # Instantiate the class. This will place the object in the @_componentable_container at the indicated name
  _instantiate_class(name, options)
  
  # Create an accessor for the new item, if indicated to do so.
  _push_accessor(name, options)
  
  @_componentable_container[name]
end

So feel free to override that, adding some custom behavior for your class.

Warning: This is still a new feature, and some better ways to override this may come around. Check the release notes for any changes to how _add should be overridden, if any.

Advanced Booting

This section is just as more for Origen developers than it is for users. Booting these classes took some behind the scenes work that most users will never see. But, there’s some assumptions that are made (in addition to the ones here) that can adversely affect booting.

Here, we’ll briefly touch on the behind-the-scenes actions taken to boot Componentable.

First, when you setup the module as:

module MyTest
  class MyTest
    include Origen::Model
    include Origen::Componentable
  end
end

The line include Origen::Componentable will trigger Componentable's included? method to kick off. This adds the callback origen_model_init to the MyTest module (not the class). This allows the module, in this case MyTest, to boot the MyTest class upon being included in a parent class. So, with this, we have an additional assumption that module MyTest does not have an origen_model_init callback already.

In most cases, the module housing the Componentable classes will do just that. They won’t have other stuff in them. But in them event that it does have its own origen_model_init, Componentable can still function with some workaround. All that needs to happen is a manual call to Origen::Componentable.init_parent_class(klass, self), where klass is the Componentable class to boot. In this case, MyTest. For example:

module MyTest
  def origen_model_init(klass, options={})
    # ...
    
    # Add booting the Componentable classes
    Origen::Componentable.init_parent_class(klass, self)
  end
  
  class MyTest
    include Origen::Model
    include Origen::Componentable
  end
end

This will be called for every class containing Origen::Componentable in the model.

Notes on Anonymous Classes

Componentable can be used with anonymous classes, but since anonymous classes don’t have a name, obvisously, one will need to be provided. Recall from the section on naming that you can override the class name by defining the class constant COMPONENTABLE_SINGLETON_NAME. This will ‘name’ the anonymous class so that Componentable can generate the parent API. Failing to provide this to an anonymous class results in a Origen::Componentable::Error exception.


Comments

Generated with the Origen Semiconductor Developer's Kit

Origen is released under the terms of the MIT license