Class: Poro::ContextFactories::NamespaceFactory

Inherits:
Poro::ContextFactory show all
Defined in:
lib/poro/context_factories/namespace_factory.rb

Overview

The NamespaceFactory uses the module namespace of the class to determine which factory should be used to create a class instance.

On initialization, the default factory should be set. Until other factories are registerd, all classes will recieve contexts created by this factory.

Other factories can be registered against various namespaces. Namespaces are given as a string and are evaluated from the bottom up. For example, if a factory is registered against the class Foo::Bar, then Foo::Bar and Foo::Bar::Baz would each recieve contexts created via that factory, while contexts registered against Foo::Zap would use the default context.

Defined Under Namespace

Classes: CacheNode

Instance Method Summary collapse

Methods inherited from Poro::ContextFactory

#context_managed_class?, #fetch, has_instance?, instance, instance=

Constructor Details

#initialize(default_factory = nil) {|_self| ... } ⇒ NamespaceFactory

Initialize this namespace factory instance with the given default factory. Use register_factory to add more kinds of factories to this app.

If given a block, it is yielded self for further configuration. This departs slightly from the standard of yielding a Class or Class and Context for configuration, but as this is more useful for practicle applications. (It also doesn’t configure a context itself, so giving separate blocks to the sub-factories given to it is more appropriate.

Yields:

  • (_self)

Yield Parameters:



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/poro/context_factories/namespace_factory.rb', line 27

def initialize(default_factory=nil)
  @root_node = CacheNode.new
  @root_node.factory = default_factory
  
  yield(self) if block_given?
  
  super() do |klass|
    factory = self.fetch_factory(klass)
    factory.nil? ? nil : factory.fetch(klass)
  end
end

Instance Method Details

#fetch_factory(namespace = '') ⇒ Object

Fetches the factory for a given namespace.

This grabs the factory for the most specific matching namespace.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/poro/context_factories/namespace_factory.rb', line 67

def fetch_factory(namespace='')
  namespace_stack = namespace.to_s.split('::')
  
  lookup_block = lambda do |namespace_stack, last_seen_factory, node|
    last_seen_factory = node.factory || last_seen_factory
    if( namespace_stack.length == 0 )
      last_seen_factory
    elsif( !(node.children.include?(namespace_stack[0])) )
      last_seen_factory
    else
      name, *rest = namespace_stack
      lookup_block.call(rest, last_seen_factory, node.children[name])
    end
  end
  
  return lookup_block.call(namespace_stack, nil, @root_node)
end

#register_factory(factory, namespace = '') ⇒ Object

Registers a factory for a given namespace, given by a string. If a factory is already registered for this namespace, it overrides it.

This registers the given factory not only for this namespace, but for any sub-namespaces that haven’t been specifically overriden. Sub-namespace overrides can be registered either before or after the namespace it overrides.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/poro/context_factories/namespace_factory.rb', line 45

def register_factory(factory, namespace='')
  namespace_stack = namespace.to_s.split('::')
  
  parse_block = lambda do |factory, namespace_stack, node|
    if( namespace_stack.length == 0 )
      node.factory = factory
    else
      name, *rest = namespace_stack
      child_node = node.children[name] || CacheNode.new
      node.children[name] = child_node
      parse_block.call(factory, rest, child_node)
    end
  end
  
  parse_block.call(factory, namespace_stack, @root_node)
  
  return factory
end