Class: Occi::Core::RendererFactory

Inherits:
Object
  • Object
show all
Includes:
Helpers::ArgumentValidator, Singleton, Yell::Loggable
Defined in:
lib/occi/core/renderer_factory.rb

Overview

A singleton factory class offering convenient access to all available renderer classes. Factory can be customized using the `required_methods` and `namespace` attributes.

Author:

Constant Summary collapse

REQUIRED_METHODS =

Methods expected on supported renderer classes

%i[renderer? formats render].freeze
NAMESPACE =

Parent namespace of all supported renderer classes

Occi::Core::Renderers

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args = {}) ⇒ RendererFactory

Constructs an instance of the `RendererFactory` class. Since this class is a singleton, `new` (or `initialize`) are not supposed to be called directly. Use attribute accessors to change settings on existing factories.

Options Hash (args):

  • :required_methods (Array) — default: `REQUIRED_METHODS`

    list of required renderer methods

  • :namespace (Module) — default: `NAMESPACE`

    module containing renderer candidates


31
32
33
34
35
36
37
38
39
# File 'lib/occi/core/renderer_factory.rb', line 31

def initialize(args = {})
  default_args! args

  logger.debug "Initializing RendererFactory with #{args.inspect}"
  @required_methods = args.fetch(:required_methods)
  @namespace = args.fetch(:namespace)

  reload!
end

Instance Attribute Details

#namespaceModule

module containing renderer candidates


11
12
13
# File 'lib/occi/core/renderer_factory.rb', line 11

def namespace
  @namespace
end

#required_methodsArray

list of required renderer methods


11
12
13
# File 'lib/occi/core/renderer_factory.rb', line 11

def required_methods
  @required_methods
end

Class Method Details

.classes_from(namespace) ⇒ Array

Returns all classes from the given namespace.


187
188
189
# File 'lib/occi/core/renderer_factory.rb', line 187

def classes_from(namespace)
  constants_from(namespace).select { |const| const.is_a? Class }
end

.constants_from(namespace) ⇒ Array

Returns all constants from the given namespace. The list may contain constants other than classes, from the given namespace and needs to be refined further.


174
175
176
177
178
179
180
181
# File 'lib/occi/core/renderer_factory.rb', line 174

def constants_from(namespace)
  unless namespace.is_a? Module
    raise Occi::Core::Errors::RendererError, "#{namespace.inspect} " \
          'is not a Module'
  end
  logger.debug "RendererFactory looking for renderers in #{namespace}"
  namespace.constants.collect { |const| namespace.const_get(const) }
end

.namespaceModule

Returns the default renderer namespace.


164
165
166
# File 'lib/occi/core/renderer_factory.rb', line 164

def namespace
  NAMESPACE
end

.required_methodsArray

Lists default methods required from any supported renderer.


157
158
159
# File 'lib/occi/core/renderer_factory.rb', line 157

def required_methods
  REQUIRED_METHODS
end

Instance Method Details

#formatsArray

Lists available rendering `format`s.

Examples:

formats # => ['text', 'json', 'headers']

53
54
55
# File 'lib/occi/core/renderer_factory.rb', line 53

def formats
  renderers.keys
end

#reload!Object


42
43
44
45
# File 'lib/occi/core/renderer_factory.rb', line 42

def reload!
  logger.debug 'Clearing RendererFactory cache for renderer reload'
  @ravail_cache = nil
end

#renderer?(candidate) ⇒ TrueClass, FalseClass

Checks whether the given object can act as a renderer.

Examples:

renderer? TextRenderer # => true
renderer? NilClass     # => false

111
112
113
114
115
116
117
118
119
120
121
# File 'lib/occi/core/renderer_factory.rb', line 111

def renderer?(candidate)
  begin
    renderer_with_methods! candidate
    renderer_with_formats! candidate
  rescue Occi::Core::Errors::RendererError => ex
    logger.debug "Renderer validation failed with #{ex.message}"
    return false
  end

  candidate.renderer?
end

#renderer_classesArray

Lists available renderers as an Array of renderer classes.

Examples:

renderer_classes #=> [Occi::Core::Renderers::TextRenderer]

99
100
101
# File 'lib/occi/core/renderer_factory.rb', line 99

def renderer_classes
  self.class.classes_from(namespace).select { |cand| renderer? cand }
end

#renderer_for(format) ⇒ Class

Returns a renderer corresponding with the given `format`. If no such renderer exists, `Occi::Core::Errors::RenderingError` error is raised.

Examples:

renderer_for 'text'   # => Occi::Core::Renderers::TextRenderer
renderer_for 'tewat?' # => !Error: Occi::Core::Errors::RenderingError!

85
86
87
88
89
90
91
# File 'lib/occi/core/renderer_factory.rb', line 85

def renderer_for(format)
  if format.blank?
    raise Occi::Core::Errors::RenderingError,
          'Cannot return a renderer for an unspecified format'
  end
  renderers[format] || raise(Occi::Core::Errors::RenderingError, "No renderer for #{format.inspect}")
end

#renderer_with_formats!(candidate) ⇒ Object

Ensures that the renderer candidate passed as an argument exposes supported formats. If that is not the case, an `Occi::Core::Errors::RendererError` error is raised.


142
143
144
145
146
147
148
149
150
151
# File 'lib/occi/core/renderer_factory.rb', line 142

def renderer_with_formats!(candidate)
  unless candidate.respond_to?(:formats)
    raise Occi::Core::Errors::RendererError, "#{candidate.inspect} " \
          "does not respond to 'formats'"
  end

  return unless candidate.formats.blank?
  raise Occi::Core::Errors::RendererError, "#{candidate.inspect} " \
        'does not expose any supported formats'
end

#renderer_with_methods!(candidate) ⇒ Object

Ensures that the renderer candidate passed as an argument exposes all required methods. If that is not the case, an `Occi::Core::Errors::RendererError` error is raised.


128
129
130
131
132
133
134
135
# File 'lib/occi/core/renderer_factory.rb', line 128

def renderer_with_methods!(candidate)
  required_methods.each do |method|
    unless candidate.respond_to?(method)
      raise Occi::Core::Errors::RendererError, "#{candidate.inspect} " \
            "does not respond to #{method.inspect}"
    end
  end
end

#renderersHash

Lists available renderers as a Hash mapping `format` to `Renderer` class.

Examples:

renderers # => { 'text' => TextRenderer }

63
64
65
66
67
68
69
70
71
72
73
# File 'lib/occi/core/renderer_factory.rb', line 63

def renderers
  return @ravail_cache if @ravail_cache
  @ravail_cache = {}

  renderer_classes.each do |rndr_klass|
    logger.debug "RendererFactory registering #{rndr_klass} for #{rndr_klass.formats}"
    rndr_klass.formats.each { |rndr_klass_f| @ravail_cache[rndr_klass_f] = rndr_klass }
  end

  @ravail_cache
end