module Origen::Loader
This module is responsible for enhancing how Ruby requires and loads files to support loading of classes and modules from an application’s app dir without having to require them.
It also implements the <model>.load_block method that loads files from app/blocks.
Public Class Methods
Source
# File lib/origen/loader.rb, line 25 def self._unload(path, name, children) path << name children.each do |name, children| _unload(path, name, children) end const = path.join('::') if @loaded_consts[const] path[0...-1].join('::').constantize.send :remove_const, path.last # puts "******** Unloading: #{const}" end path.pop end
@api private
Source
# File lib/origen/loader.rb, line 427 def self.disable_origen_load_extensions! ModuleConstMissing.exclude_from(Module) end
Source
# File lib/origen/loader.rb, line 423 def self.enable_origen_load_extensions! Module.class_eval { include ModuleConstMissing } end
Source
# File lib/origen/loader.rb, line 56 def self.load_attributes(file, model) if model.respond_to?(:is_an_origen_model?) attributes = model.attributes.dup else attributes = {} end vars = model.instance_variables if load_block_file(file, model) # Update the value of any pre-existing attribute that could have just changed attributes.each do |a, v| attributes[a] = model.instance_variable_get("@#{a}") end # And add any new ones that were encountered for the first time (model.instance_variables - vars).each do |var| val = model.instance_variable_get(var) attribute = var.to_s.sub('@', '') attributes[attribute.to_sym] = val unless model.respond_to?(attribute) model.define_singleton_method(attribute) do instance_variable_get(var) end end if val == true || val == false attribute += '?' unless model.respond_to?(attribute) model.define_singleton_method(attribute) do instance_variable_get(var) end end end end if model.respond_to?(:is_an_origen_model?) attributes.freeze model.instance_variable_set(:@attributes, attributes) end true end end
@api private
Source
# File lib/origen/loader.rb, line 123 def self.load_block(model, options = {}) model = model.model # Ensure we have a handle on the model and not its controller loaded = nil if local_app = options[:app] || model.app if options[:path] local_full_paths = Array(options[:path]) else local_full_paths = model.class.to_s.split('::') local_full_paths.shift # Throw away the app namespace local_full_paths = [local_full_paths.join('/')] end app_paths_map = { local_app => local_full_paths } inherit_app = nil inherited_sub_blocks_files = [] if options[:inherit] # update app_paths_map with the relevant inherited files inherit_full_paths = options[:inherit].split('::') inherit_app = Origen.app(inherit_full_paths.shift.underscore.to_sym) inherit_full_paths = [inherit_full_paths.join('/')] # merge to get inherit ordered in the beginning app_paths_map = { inherit_app => inherit_full_paths }.merge(app_paths_map) end # load the inherit files, then the current app's block files app_paths_map.each do |app, full_paths| full_paths.each do |full_path| paths = full_path.to_s.split('/') key = '' only = Array(options[:only]) if options[:only] except = Array(options[:except]) if options[:except] path = paths.map(&:underscore).join('/') # If the path refers to a nested sub-block then don't load the full hierarchy since they # don't support inheritance or derivatives, modify the paths array so that only the sub-block # level will be loaded and nothing else. paths = [path] if app.blocks_files[path] && app.blocks_files[path][:_sub_block] # These will be loaded first, followed by the rest in an undefined order. # Attributes and parameters are first so that they may be referenced in the other files. # Sub-blocks was added early due to a corner case issue that could be encountered if the pins or # regs imported an Origen exported file that defined a module with the same name as a sub-block # class, in that case the sub-block class would not be auto-loaded. load_first = [:attributes, :parameters, :sub_blocks] load_first.each do |type| unless (only && !only.include?(type)) || (except && except.include?(type)) with_parameters_transaction(type) do paths.each_with_index do |path, i| key = i == 0 ? path.underscore : "#{key}/#{path.underscore}" if app.blocks_files[key] && app.blocks_files[key][type] app.blocks_files[key][type].each do |f| if type == :attributes success = load_attributes(f, model) elsif type == :sub_blocks && app == inherit_app # handle inherited sub blocks later inherited_sub_blocks_files << f else success = load_block_file(f, model) end loaded ||= success end end end end end end # Now load the rest paths.each_with_index do |path, i| key = i == 0 ? path.underscore : "#{key}/#{path.underscore}" if app.blocks_files[key] app.blocks_files[key].each do |type, files| unless type == :_sub_block || load_first.include?(type) || (only && !only.include?(type)) || (except && except.include?(type)) files.each { |f| success = load_block_file(f, model); loaded ||= success } end end end end end end # Now load the inherited sub blocks, but don't override any existing sub blocks this model has already defined inherited_sub_blocks_files.each do |f| model.instance_variable_set(:@_inherited_sub_blocks_mode, true) load_block_file(f, model) model.instance_variable_set(:@_inherited_sub_blocks_mode, false) end end # pass down any bugs/features from the inherited block class if options[:inherit] inherited_ancestors = options[:inherit].constantize.ancestors inherited_features = inherited_ancestors.map do |a| a.respond_to?(:features) ? a.features : {} end inherited_features = inherited_features.reject(&:empty?).reverse.reduce({}, :merge) inherited_bugs = inherited_ancestors.map do |a| a.respond_to?(:bugs) ? a.bugs : {} end inherited_bugs = inherited_bugs.reject(&:empty?).reverse.reduce({}, :merge) unless options[:disable_feature_inheritance] model.class.instance_variable_set(:@features, inherited_features.merge(model.class.features)) end unless options[:disable_bug_inheritance] model.class.instance_variable_set(:@bugs, inherited_bugs.merge(model.class.bugs)) end end loaded end
If a block definition exists for the given model, then this will load it and apply it to the model. if options is passed, it will first try to load the files for the class name contained in that option, even if its from a plugin app. Additionally, any bugs/features will be inherited as well unless disable_bug_inheritance or disable_feature_inheritance options are passed Returns true if a model is found and loaded, otherwise nil.
Source
# File lib/origen/loader.rb, line 96 def self.load_block_file(file, model) file = file.to_s if File.exist?(file) File.open(file, 'r') do |f| model.instance_eval(f.read, file) end end true end
@api private
Source
# File lib/origen/loader.rb, line 39 def self.record_const(name) @consts_hierarchy ||= {} @loaded_consts ||= {} @loaded_consts[name] = true pointer = nil name.split('::').each do |name| if pointer pointer[name] ||= {} pointer = pointer[name] else @consts_hierarchy[name] ||= {} pointer = @consts_hierarchy[name] end end end
@api private
Source
# File lib/origen/loader.rb, line 10 def self.unload # puts "******** LOADED CONSTS@ #{@loaded_consts}" path = [] (@consts_hierarchy || {}).each do |name, children| _unload(path, name, children) end @consts_hierarchy = {} @loaded_consts = {} (Origen.app.plugins + [Origen.app]).each do |app| app.instance_variable_set(:@blocks_files, nil) end nil end
@api private
Unload all constants (classes and modules) that have been auto-loaded since this was last called
Source
# File lib/origen/loader.rb, line 107 def self.with_parameters_transaction(type) if type == :parameters Origen::Parameters.transaction do yield end else yield end end
@api private