lib/origen/sub_blocks.rb in origen-0.59.8 vs lib/origen/sub_blocks.rb in origen-0.60.0

- old
+ new

@@ -315,14 +315,40 @@ block = Placeholder.new(self, name, options) # Allow additional attributes to be added to an existing sub-block if it hasn't # been instantiated yet. This is not supported yet for instantiated sub-blocks since # there are probably a lot more corner-cases to consider, and hopefully no one will # really need this anyway. - if sub_blocks[name] && !sub_blocks[name].is_a?(Placeholder) - fail "You have already defined a sub-block named #{name} within class #{self.class}" + # Note that override is to recreate an existing sub-block, not adding additional + # attributes to an existing one + if options[:override] + sub_blocks.delete(name) + if options[:class_name] + begin + constantizable = !!options[:class_name].constantize + rescue NameError + constantizable = false + end + # this is to handle the case where a previously instantiated subblock wont allow + # the current class name to exist + # e.g. NamespaceA::B::C + # => NameSpaceX::Y::Z + # After requiring the files, constants become sane again: + # e.g. NamespaceA::B::C + # => NameSpaceA::B::C + if constantizable && (options[:class_name] != options[:class_name].constantize.to_s) + block_dir = options[:block_file] || _find_block_dir(options) + Dir.glob("#{block_dir}/*.rb").each do |file| + require file + end + end + end + else + if sub_blocks[name] && !sub_blocks[name].is_a?(Placeholder) + fail "You have already defined a sub-block named #{name} within class #{self.class}" + end end - if respond_to?(name) + if respond_to?(name) && !(singleton_class.instance_methods.include?(name) && options[:override]) callers = Origen.split_caller_line caller[0] Origen.log.warning "The sub_block defined at #{Pathname.new(callers[0]).relative_path_from(Pathname.pwd)}:#{callers[1]} is overriding an existing method called #{name}" end define_singleton_method name do sub_blocks[name] @@ -401,9 +427,36 @@ def namespace self.class.to_s.sub(/::[^:]*$/, '') end private + + # @api private + # find the block directory path containing the namespace of options[:class_name] + def _find_block_dir(options, current_path = nil, remaining_namespace = nil) + current_path ||= Pathname.new("#{Origen.root}/app/blocks") + remaining_namespace ||= options[:class_name].split('::')[1..-1].map(&:underscore) + current_namespace = remaining_namespace.shift + if current_namespace + if current_path.join(current_namespace).exist? + return _find_block_dir(options, current_path.join(current_namespace), remaining_namespace) + elsif current_path.join("derivatives/#{current_namespace}").exist? + return _find_block_dir(options, current_path.join("derivatives/#{current_namespace}"), remaining_namespace) + elsif current_path.join("sub_blocks/#{current_namespace}").exist? + return _find_block_dir(options, current_path.join("sub_blocks/#{current_namespace}"), remaining_namespace) + else + Origen.log.error "Could not find block dir for namespace #{options[:class_name]}!" + fail + end + else + if current_path.join('model.rb').exist? + return current_path.to_s + else + Origen.log.error "Could not find block dir for namespace #{options[:class_name]}!" + fail + end + end + end def instantiate_sub_block(name, klass, options) return sub_blocks[name] unless sub_blocks[name].is_a?(Placeholder) sub_blocks[name] = klass.new(options.merge(parent: self, name: name)) end