Module: Origen::Componentable

Included in:
Origen::Component::Component
Defined in:
lib/origen/componentable.rb

Overview

Protologism taking after Enumerable, stating that this object can behave like an Origen Component

Defined Under Namespace

Classes: Error, NameDoesNotExistError, NameInUseError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.add_included_callback(othermod) ⇒ Object

These are split in case the included module actually has an :included method defined and the user wants to bootstrap setting up the add_included_callback manually. Note that someone making a module to house a Componentable class is very unlikely to do this, but it could still happen.



29
30
31
32
33
# File 'lib/origen/componentable.rb', line 29

def self.add_included_callback(othermod)
  othermod.define_singleton_method(:origen_model_init) do |klass, options = {}|
    Origen::Componentable.init_parent_class(klass, self)
  end
end

.componentable_names(klass) ⇒ Object



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/origen/componentable.rb', line 293

def self.componentable_names(klass)
  unless klass.is_a?(Class)
    # If we were given an instance of a class, get its actual class.
    klass = klass.class
  end
  names = {}

  # Evaluate the singleton name. This will be the class name or the class constant
  #  COMPONENTABLE_SINGLETON_NAME, if it's defined.
  # The only corner case here is if the class is anonymous, then a COMPONENTABLE_SINGLETON_NAME is required.
  if klass.const_defined?(:COMPONENTABLE_SINGLETON_NAME)
    names[:singleton] = klass.const_get(:COMPONENTABLE_SINGLETON_NAME).downcase.to_sym
  else
    # Check if this is an anonymous class. If so, complain that COMPONENTABLE_SINGLETON_NAME is required
    if !klass.respond_to?(:name) || klass.name.nil? # || klass.name.start_with?('#<Class:')
      if klass.const_defined?(:COMPONENTABLE_PLURAL_NAME)
        # Have a more specific error saying the plural name was found but isn't sufficient.
        fail Origen::Componentable::Error, 'Anonymous classes that include the Componentable module must define COMPONENTABLE_SINGLETON_NAME, even if COMPONENTABLE_PLURAL_NAME is defined'
      else
        fail Origen::Componentable::Error, 'Anonymous classes that include the Componentable module must define COMPONENTABLE_SINGLETON_NAME'
      end
    else
      if klass.name.include?('::')
        names[:singleton] = klass.name.split('::').last.underscore.to_sym
      else
        names[:singleton] = klass.name.underscore.to_sym
      end
    end
  end

  if klass.const_defined?(:COMPONENTABLE_PLURAL_NAME)
    name = klass.const_get(:COMPONENTABLE_PLURAL_NAME).downcase.to_sym

    # do a quick check to make sure that the plural name and singleton name aren't set to the same thing
    if name == names[:singleton]
      fail Origen::Componentable::Error, "Componentable including class cannot define both COMPONENTABLE_SINGLETON_NAME and COMPONENTABLE_PLURAL_NAME to '#{name}'"
    end
  else
    name = names[:singleton].to_s

    # Only deal with a few cases here, I'm not interested in figuring out every
    # english rule to pluralize everything. Examples:
    #   deer => deers (not deer, though technically I think deers is actually a word, but an odd one)
    #   goose => gooses (not geese)
    #   dwarf => dwarfs (not dwarves)
    # If the user is concerned about this, they can supply their own
    # name pluralizing their class name directly.
    if name.match(/is$/)
      #   analysis => analyses
      name.gsub!(/is$/, 'es')
    elsif name.match(/[sxz]$|sh$|ch$/)
      # if the names ends with s, h, ch, sh, x, z: append 'es'. Examples:
      #   bus => buses
      #   stress => stresses
      #   box => boxes
      #   branch => branches
      #   brush => brushes
      #   tax => taxes
      #   buzz => buzzes
      name += 'es'
    elsif name.match(/on$/)
      #   criterion => criteria
      name.gsub!(/on$/, 'a')
    else
      # just append a single 's'. Examples:
      #   component => components
      #   sub_block => sub_blocks
      #   tool => tools
      name += 's'
    end
    name = name.to_sym
  end
  names[:plural] = name

  names
end

.included(othermod) ⇒ Object

In order for Origen to bootstrap using a generic callback, we’ll work a bit backwards. When this module is included by an ‘includer’, it will give



21
22
23
# File 'lib/origen/componentable.rb', line 21

def self.included(othermod)
  add_included_callback(othermod)
end

.init_includer_class(klass_instance) ⇒ Object

Initializes the class that included Componentable (the ‘includer’). All of the singleton methods will be added per Ruby, but the includer still needs to be booted by:

1) Creating and initializing the instance attribute (_componentable_container)
2) Defining a method to get the container directly.
   For example, the Component class will automatically have a :components method that references the
   _componentable_container.


46
47
48
49
50
51
52
53
54
55
# File 'lib/origen/componentable.rb', line 46

def self.init_includer_class(klass_instance)
  klass_instance.instance_variable_set(:@_componentable_container, {}.with_indifferent_access)
  klass_instance.class.class_eval do
    attr_reader :_componentable_container

    define_method Origen::Componentable.componentable_names(klass_instance)[:plural] do
      @_componentable_container
    end
  end
end

.init_parent_class(parent_class, includer_class) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/origen/componentable.rb', line 73

def self.init_parent_class(parent_class, includer_class)
  # includer_single_name = begin
  #  if includer_class.name.include?('::')
  #    name = includer_class.name.split('::').last.underscore
  #  else
  #    name = includer_class.name.underscore
  #  end
  # end
  # includer_plural_name = Origen::Componentable.componentable_names(includer_class)[:plural]

  names = Componentable.componentable_names(includer_class)
  includer_single_name = names[:singleton]
  includer_plural_name = names[:plural]

  unless parent_class.is_a?(Class)
    inc = parent_class.instance_variable_set("@_#{includer_single_name}".to_sym, includer_class.new)
    inc.parent = parent_class
    parent_class = parent_class.class
  end

  # If the includer's singleton name is taken (i.e., the parent already has a method <includer_single_name>),
  # raise an error since the 'proper' way to interact with the includer directly is from this method.
  if !Origen::Componentable.parent_class_evaled?(parent_class, includer_single_name) && parent_class.method_defined?(includer_single_name.to_sym)
    fail Origen::Componentable::Error, "Class #{parent_class.name} provides a method :#{includer_single_name} already. Cannot include Componentable class #{includer_class.name} in this object!"
  end

  # for everything that's not the singleton name method or the @_<singleton_name> instance variable, having the method
  # already exists is a warning, not an error.
  methods_to_add = [
    includer_plural_name.to_sym,

    # Add methods
    "add_#{includer_single_name}".to_sym,
    "add_#{includer_plural_name}".to_sym,

    # Listing/Querying methods
    "list_#{includer_plural_name}".to_sym,
    "#{includer_plural_name}_of_class".to_sym,
    "#{includer_plural_name}_instances_of".to_sym,
    "#{includer_plural_name}_of_type".to_sym,
    "#{includer_single_name}?".to_sym,
    "has_#{includer_single_name}?".to_sym,

    # Enumeration methods
    "each_#{includer_single_name}".to_sym,
    "all_#{includer_plural_name}".to_sym,
    "select_#{includer_plural_name}".to_sym,
    "select_#{includer_single_name}".to_sym,

    # Copying/Moving methods
    "copy_#{includer_single_name}".to_sym,
    "copy_#{includer_plural_name}".to_sym,
    "move_#{includer_single_name}".to_sym,
    "move_#{includer_plural_name}".to_sym,

    # Deleting individual item methods
    "delete_#{includer_single_name}".to_sym,
    "delete_#{includer_plural_name}".to_sym,
    "remove_#{includer_single_name}".to_sym,
    "remove_#{includer_plural_name}".to_sym,
    "delete_#{includer_single_name}!".to_sym,
    "delete_#{includer_plural_name}!".to_sym,
    "remove_#{includer_single_name}!".to_sym,
    "remove_#{includer_plural_name}!".to_sym,

    # Deleting all items methods
    "delete_all_#{includer_plural_name}".to_sym,
    "clear_#{includer_plural_name}".to_sym,
    "remove_all_#{includer_plural_name}".to_sym
  ]
  unless Origen::Componentable.parent_class_evaled?(parent_class, includer_single_name)
    methods_to_add.each do |m|
      if parent_class.method_defined?(m)
        Origen.log.warning "Componentable: Parent class #{parent_class.name} already defines a method #{m}. This method will not be used by Componentable"
      end
    end
    parent_class.instance_variable_set("@_#{includer_single_name}_evaled".to_sym, true)
  end

  parent_class.class_eval do
    # Note that all of these just trace back to the root method.

    # Define the root method (singleton-named method)
    # If any arguments are given, it behaves as an :add method.
    # Otherwise, it returns the underlying object itself.
    define_method includer_single_name.to_sym do |*args, &block|
      if args.size == 0
        # No arguments, so just return the class instance
        instance_variable_get("@_#{includer_single_name}".to_sym)
      else
        # Arguments were provided, so treating this as an :add attempt
        instance_variable_get("@_#{includer_single_name}".to_sym).add(*args, &block)
      end
    end

    # Define the plural-named method.
    # If arguments are given, then it behaves as an :add attempt, with or without a block.
    # If a block is given without any arguments, it will behave as an :each operation and call the block.
    # if no arguments are given, it will return the underlying HASH (not the object).
    #   This allows for plural_name[name] to
    define_method "#{includer_plural_name}".to_sym do |*args, &block|
      if block && args.size == 0
        instance_variable_get("@_#{includer_single_name}".to_sym).each(&block)
      elsif args.size == 0
        instance_variable_get("@_#{includer_single_name}".to_sym)._componentable_container
      else
        instance_variable_get("@_#{includer_single_name}".to_sym).add(*args, &block)
      end
    end

    # define the various 'add' methods
    # what we'll actually do is just define one method then alias all the others together.
    # Currently, this includes:
    #   <includer_plural_name>, add_<includer_single_name>, add_
    define_method "add_#{includer_single_name}".to_sym do |name, options = {}, &block|
      instance_variable_get("@_#{includer_single_name}".to_sym).add(name, options, &block)
    end
    alias_method "add_#{includer_plural_name}".to_sym, "add_#{includer_single_name}".to_sym

    # define listing and getting methods
    define_method "list_#{includer_plural_name}".to_sym do
      instance_variable_get("@_#{includer_single_name}".to_sym).list
    end

    # define the querying object types
    define_method "#{includer_plural_name}_of_class".to_sym do |klass, options = {}|
      instance_variable_get("@_#{includer_single_name}".to_sym).instances_of(klass, options)
    end
    alias_method "#{includer_plural_name}_instances_of".to_sym, "#{includer_plural_name}_of_class".to_sym
    alias_method "#{includer_plural_name}_of_type".to_sym, "#{includer_plural_name}_of_class".to_sym

    # define the querying instance existance
    define_method "#{includer_single_name}?".to_sym do |name|
      instance_variable_get("@_#{includer_single_name}".to_sym).has?(name)
    end
    alias_method "has_#{includer_single_name}?".to_sym, "#{includer_single_name}?".to_sym

    # define some of commonly used enumerate methods
    define_method "each_#{includer_single_name}".to_sym do |&block|
      instance_variable_get("@_#{includer_single_name}".to_sym).each(&block)
    end
    alias_method "all_#{includer_plural_name}".to_sym, "each_#{includer_single_name}".to_sym

    define_method "select_#{includer_plural_name}".to_sym do |&block|
      instance_variable_get("@_#{includer_single_name}".to_sym).select(&block)
    end
    alias_method "select_#{includer_single_name}".to_sym, "select_#{includer_plural_name}".to_sym

    # define the copying/moving methods
    define_method "copy_#{includer_single_name}".to_sym do |to_copy, to_location, options = {}|
      instance_variable_get("@_#{includer_single_name}".to_sym).copy(to_copy, to_location, options)
    end
    alias_method "copy_#{includer_plural_name}".to_sym, "copy_#{includer_single_name}".to_sym

    define_method "move_#{includer_single_name}".to_sym do |to_move, to_location|
      instance_variable_get("@_#{includer_single_name}".to_sym).move(to_move, to_location)
    end
    alias_method "move_#{includer_plural_name}".to_sym, "move_#{includer_single_name}".to_sym

    # define the deleting single instance methods
    define_method "delete_#{includer_single_name}".to_sym do |name|
      instance_variable_get("@_#{includer_single_name}".to_sym).delete(name)
    end
    alias_method "delete_#{includer_plural_name}".to_sym, "delete_#{includer_single_name}".to_sym
    alias_method "remove_#{includer_single_name}".to_sym, "delete_#{includer_single_name}".to_sym
    alias_method "remove_#{includer_plural_name}".to_sym, "delete_#{includer_single_name}".to_sym

    define_method "delete_#{includer_single_name}!".to_sym do |name|
      instance_variable_get("@_#{includer_single_name}".to_sym).delete!(name)
    end
    alias_method "delete_#{includer_plural_name}!".to_sym, "delete_#{includer_single_name}!".to_sym
    alias_method "remove_#{includer_single_name}!".to_sym, "delete_#{includer_single_name}!".to_sym
    alias_method "remove_#{includer_plural_name}!".to_sym, "delete_#{includer_single_name}!".to_sym

    # define the deleting all instances methods
    define_method "delete_all_#{includer_plural_name}".to_sym do
      instance_variable_get("@_#{includer_single_name}".to_sym).delete_all
    end
    alias_method "clear_#{includer_plural_name}".to_sym, "delete_all_#{includer_plural_name}".to_sym
    alias_method "remove_all_#{includer_plural_name}".to_sym, "delete_all_#{includer_plural_name}".to_sym
  end
end

.origen_model_init(klass, options = {}) ⇒ Object

When Origen’s model initializer is included, all Componentable objects will be automatically booted.



36
37
38
# File 'lib/origen/componentable.rb', line 36

def self.origen_model_init(klass, options = {})
  Origen::Componentable.init_includer_class(klass)
end

.parent_class_evaled?(parent_class, includer_singleton_name) ⇒ Boolean

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/origen/componentable.rb', line 57

def self.parent_class_evaled?(parent_class, includer_singleton_name)
  evaled = parent_class.instance_variable_get("@_#{includer_singleton_name}_evaled")
  if evaled.nil?
    # Check that this class isn't inheriting from another class that uses Componentable things.
    # If so, the API is inherited and is fine, so set the evaled value for that class to true.
    parent_class.ancestors.each do |ancestor|
      if ancestor.instance_variable_get("@_#{includer_singleton_name}_evaled")
        parent_class.instance_variable_set("@_#{includer_singleton_name}_evaled", true)
        evaled = true
        break
      end
    end
  end
  evaled
end

Instance Method Details

#[](name) ⇒ Object



515
516
517
# File 'lib/origen/componentable.rb', line 515

def [](name)
  @_componentable_container[name]
end

#_add(name, options = {}, &block) ⇒ ComponentableObject

Note:

All options added will be passed to the subclasses instantiation.

Note:

The options is only valid for the stock :add method.

Note:

Any extra options provided are still passed to the subclasses instantiation.

Adds a new item to the componentable container.

Parameters:

  • name (Symbol)

    Name to reference the new component object.

  • options (Hash) (defaults to: {})

    Customizations for both the add method and for the class’s instantiation.

Options Hash (options):

  • class_name (Class, String)

    The class to instaniate the component at :name as.

Returns:

  • (ComponentableObject)

    The instantiated class at :name

Raises:



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/origen/componentable.rb', line 430

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)

  options = Origen::Utility.collector(hash: options, merge_method: :keep_hash, &block).to_h

  # 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

#_instantiate_class(name, options) ⇒ Object



449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/origen/componentable.rb', line 449

def _instantiate_class(name, options)
  if @_componentable_container.key?(name)
    fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{name} is already in use."
  end

  if options[:class_name]
    class_name = options.delete(:class_name)

    unless Object.const_defined?(class_name.to_s)
      fail Origen::Componentable::NameDoesNotExistError, "class_name option '#{class_name}' cannot be found"
    end

    # Instantiate the given class
    if class_name.is_a?(String)
      @_componentable_container[name] = eval(class_name).new(options)
    else
      @_componentable_container[name] = class_name.new(options)
    end
  else
    # Instantiate a standard Component if no class given
    @_componentable_container[name] = Origen::Component::Default.new(options)
  end
  @_componentable_container[name]
end

#_plural_nameObject

Gets the plural name of the class.



268
269
270
271
272
273
# File 'lib/origen/componentable.rb', line 268

def _plural_name
  @plural_name || begin
    @plural_name = Origen::Componentable.componentable_names(self)[:plural]
    @singleton_name = Origen::Componentable.componentable_names(self)[:singleton]
  end
end

#_push_accessor(name, options) ⇒ Object



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/origen/componentable.rb', line 474

def _push_accessor(name, options)
  if parent
    def push_accessor(name)
      if parent.respond_to?(name.to_sym)
        Origen.log.warn("Componentable: #{_singleton_name} is trying to add an accessor for item :#{name} to parent #{parent.class.name} but that method already exist! No accessor will be added.")
      else
        parent.send(:eval, "define_singleton_method :#{name.to_sym} do; #{_singleton_name}[:#{name}]; end")
      end
    end

    if self.class.const_defined?(:COMPONENTABLE_ADDS_ACCESSORS) && self.class.const_get(:COMPONENTABLE_ADDS_ACCESSORS)
      if parent.respond_to?(:disable_componentable_accessors)
        if parent.method(:disable_componentable_accessors).arity >= 1
          unless parent.disable_componentable_accessors(self.class)
            push_accessor(name)
          end
        else
          unless parent.disable_componentable_accessors
            push_accessor(name)
          end
        end
      else
        push_accessor(name)
      end
    end
  end
end

#_singleton_nameObject

Gets the singleton name of the class.



276
277
278
279
280
281
# File 'lib/origen/componentable.rb', line 276

def _singleton_name
  @singleton_name || begin
    @plural_name = Origen::Componentable.componentable_names(self)[:plural]
    @singleton_name = Origen::Componentable.componentable_names(self)[:singleton]
  end
end

#_split_by_instances(name, options = {}, &block) ⇒ Object



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/origen/componentable.rb', line 380

def _split_by_instances(name, options = {}, &block)
  if !options[:instances].nil? && options[:instances] > 1
    instances = {}
    options[:instances].times do |i|
      opts = {}

      # merge the given options with any that are overriden with the block.
      options = Origen::Utility.collector(hash: options, merge_method: :keep_hash, &block).to_h

      # go through the options one by one now and make sure that each element is either an array to be split
      # by the instances, or is a single object. If not one of these two, complain.
      options.each do |key, val|
        if val.is_a?(Array)
          if val.size == 1
            # An array with a single element. This is fine. Just take that single element as the contents.
            # Note: this is a workaround for the corner case of wanting to pass in an array as an option
            # with a size that doesn't match the number of instances.
            opts[key] = val.first
          elsif val.size != options[:instances]
            # The number of elements in the option doesn't match the number of instances, and it greater than
            # a single element.
            fail Origen::Componentable::Error, "Error when adding #{name}: size of given option :#{key} (#{val.size}) does not match the number of instances specified (#{options[:instances]})"
          else
            # use the index number to grab the correct value for this instance
            opts[key] = val[i]
          end
        else
          opts[key] = val
        end
      end

      # set the instance's name and add it and its options to the list to be added
      instances["#{name}#{i}".to_sym] = opts
    end
    instances
  else
    options = Origen::Utility.collector(hash: options, merge_method: :keep_hash, &block).to_h
    { name => options }
  end
end

#add(name, options = {}, &block) ⇒ Object



370
371
372
373
374
375
376
377
378
# File 'lib/origen/componentable.rb', line 370

def add(name, options = {}, &block)
  instances = _split_by_instances(name, options, &block)
  return_instances = []
  instances.each do |n, opts|
    return_instances << _add(n, opts)
  end

  return_instances.size == 1 ? return_instances.first : return_instances
end

#copy(to_copy, to_location, options = {}) ⇒ Object

Copies the component at :to_copy to :to_location. Default is to deep copy (i.e. clone) the to_copy, resulting in two independent components.

Parameters:

  • to_copy (Symbol)

    Name of the component to copy.

  • to_location (Symbol)

    Name to copy to.

  • options (Hash) (defaults to: {})

    Customization options.

Options Hash (options):

  • :deep_copy (true, false) — default: true

    Indicates whether to deep copy (clone) the component or just copy the a reference to the component.

  • :override (true, false) — default: false

    Indicates if the object at :to_location should be overridden if it already exists.

Raises:

  • (Origen::Componentable::NameInUseError)

    Raised if :to_location is already in use and the :override option is not specified.

  • (Origen::Componentable::NameDoesNotExistsError)

    Raised if :to_copy name does not exists.



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/origen/componentable.rb', line 529

def copy(to_copy, to_location, options = {})
  deep_copy = options.key?(:deep_copy) ? options[:deep_copy] : true
  overwrite = options[:overwrite] || false

  if @_componentable_container.key?(to_location) && !overwrite
    # The copy location already exists and override was not specified
    fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{to_location} is already in use"
  end

  unless @_componentable_container.key?(to_copy)
    # The to copy name doesn't exist
    fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_copy} does not exist"
  end

  if deep_copy
    @_componentable_container[to_location] = @_componentable_container[to_copy].clone
  else
    @_componentable_container[to_location] = @_componentable_container[to_copy]
  end
end

#delete(to_delete) ⇒ Hash(Symbol, <ComponentableItem>) Also known as: remove

Deletes a component from the componentable container

Parameters:

  • name (Symbol)

    Name of component to delete

Returns:

  • (Hash(Symbol, <ComponentableItem>))

    containing the name of the component deleted and its component.

Raises:

  • (Origen::Componentable::NameDoesNotExistsError)

    Raised if :to_copy name does not exists.



577
578
579
580
581
582
# File 'lib/origen/componentable.rb', line 577

def delete(to_delete)
  obj = delete!(to_delete)
  fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_delete} does not exist" if obj.nil?

  obj
end

#delete!(to_delete) ⇒ Hash(Symbol, <ComponentableItem>)? Also known as: remove!

Same as the :delete method but raises an error if :name doesn’t exists.

Parameters:

  • name (Symbol)

    Name oof the component to delete.

Returns:

  • (Hash(Symbol, <ComponentableItem>), nil)

    Hash containing the name of the component deleted and its component. Nil if the name doesn’t exist.



588
589
590
591
592
593
594
595
596
597
598
# File 'lib/origen/componentable.rb', line 588

def delete!(to_delete)
  need_to_undef = parent && parent.respond_to?(to_delete) && parent.send(to_delete).eql?(@_componentable_container[to_delete])

  obj = @_componentable_container.delete(to_delete)

  if need_to_undef
    parent.instance_eval "undef #{to_delete}"
  end

  obj
end

#delete_allHash(Symbol, <ComponentableItem>) Also known as: clear, remove_all

Deletes all of the components in the container.

Returns:

  • (Hash(Symbol, <ComponentableItem>))

    Hash containing all of the deleted items.



603
604
605
606
607
608
609
610
611
# File 'lib/origen/componentable.rb', line 603

def delete_all
  # delete individual objects one by one, making sure to delete all accessors as well
  returns = {}
  @_componentable_container.each do |key, val|
    delete!(key)
    returns[key] = val
  end
  returns
end

#each(&block) ⇒ Object

Implementation for an each method



629
630
631
# File 'lib/origen/componentable.rb', line 629

def each(&block)
  @_componentable_container.each(&block)
end

#has?(name) ⇒ true, false

Checks if a component exist in the componentable container.

Parameters:

  • name (Symbol)

    Name to query existance of.

Returns:

  • (true, false)

    True if :name exists, False otherwise.



511
512
513
# File 'lib/origen/componentable.rb', line 511

def has?(name)
  @_componentable_container.include?(name)
end

#instances_of(class_name, options = {}) ⇒ Array <Strings>

Locates all names whose object is a :class_name object.

Parameters:

  • class_name (Class, Instance of Class)

    Class to search componentable container for. This can either be the class name, or can be an instance of the class to search for.

Returns:

  • (Array <Strings>)

    An array listing all of the names in the componentable container which are a :class_name.



618
619
620
621
622
623
624
625
626
# File 'lib/origen/componentable.rb', line 618

def instances_of(class_name, options = {})
  unless class_name.is_a?(Class)
    # class_name is actually an instance of the class to search for, not the class itself.
    class_name = class_name.class
  end
  @_componentable_container.select do |name, component|
    component.is_a?(class_name)
  end.keys
end

#listArray<Symbol>

List the items in the componentable container

Returns:

  • (Array<Symbol>)

    Componentable container item names.



504
505
506
# File 'lib/origen/componentable.rb', line 504

def list
  @_componentable_container.keys
end

#move(to_move, new_name, options = {}) ⇒ Symbol

Moves a component object from one name to another.

Parameters:

  • to_move (Symbol)

    Component name to move elsewhere.

  • new_name (Symbol)

    New name to give to the component from :to_move.

Returns:

  • (Symbol)

    The component moved.

Raises:

  • (Origen::Componentable::NameInUseError)

    Raised if :new_name is already in use and the :override option is not specified.

  • (Origen::Componentable::NameDoesNotExistsError)

    Raised if :to_move name does not exists.



556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/origen/componentable.rb', line 556

def move(to_move, new_name, options = {})
  overwrite = options[:overwrite] || false

  if @_componentable_container.key?(new_name) && !overwrite
    # The move location already exists and override was not specified
    fail Origen::Componentable::NameInUseError, "#{_singleton_name} name :#{new_name} is already in use"
  end

  unless @_componentable_container.key?(to_move)
    # The to_move name doesn't exist
    fail Origen::Componentable::NameDoesNotExistError, "#{_singleton_name} name :#{to_move} does not exist"
  end

  to_move_object = @_componentable_container.delete(to_move)
  @_componentable_container[new_name] = to_move_object
end

#parentObject

Gets the parent of the includer class.



284
285
286
# File 'lib/origen/componentable.rb', line 284

def parent
  @parent
end

#parent=(p) ⇒ Object

Sets the parent of the includer class



289
290
291
# File 'lib/origen/componentable.rb', line 289

def parent=(p)
  @parent = p
end

#select(&block) ⇒ Object

Implementation for a select method



634
635
636
# File 'lib/origen/componentable.rb', line 634

def select(&block)
  @_componentable_container.select(&block)
end