Class: SOF::Cycle::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/sof/cycle/registry.rb

Overview

The set of classes that handle cycle kinds.

Registration is explicit — a class joins by declaring what it handles (see Cycle.handles), not by subclassing. Inheriting from Cycle for any other reason, such as a test double or an abstract intermediate, then carries no hidden side effect.

The registry is also what the parser reads to recognise notations, so an application can add a kind of its own and have its notation parse without reopening this gem.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRegistry

Returns a new instance of Registry.



18
19
20
21
# File 'lib/sof/cycle/registry.rb', line 18

def initialize
  @cycle_classes = []
  @notation_pattern = nil
end

Class Method Details

.instanceObject



16
# File 'lib/sof/cycle/registry.rb', line 16

def self.instance = @instance ||= new

Instance Method Details

#cycle_classesObject



47
# File 'lib/sof/cycle/registry.rb', line 47

def cycle_classes = @cycle_classes.dup

#for_notation_id(notation_id) ⇒ Object

The class declaring notation_id — the letter(s) that open a cycle's notation, such as "L" or "LE".



57
58
59
60
# File 'lib/sof/cycle/registry.rb', line 57

def for_notation_id(notation_id)
  @cycle_classes.find { |klass| klass.notation_id == notation_id } ||
    raise(InvalidKind, "'#{notation_id}' is not a valid kind of Cycle")
end

#handling(kind) ⇒ Object

The class declaring kind.



50
51
52
53
# File 'lib/sof/cycle/registry.rb', line 50

def handling(kind)
  @cycle_classes.find { |klass| klass.handles?(kind) } ||
    raise(InvalidKind, "':#{kind}' is not a valid kind of Cycle")
end

#notation_idsObject

Registered notation ids, longest first. A volume-only cycle has none, so it contributes nothing to parse.



64
65
66
# File 'lib/sof/cycle/registry.rb', line 64

def notation_ids
  @cycle_classes.filter_map(&:notation_id).uniq.sort_by { |id| [-id.length, id] }
end

#notation_patternObject

The alternation the parser splices into its pattern. Rebuilt whenever a class registers, so a kind added at runtime is recognised from then on.



70
71
72
# File 'lib/sof/cycle/registry.rb', line 70

def notation_pattern
  @notation_pattern ||= notation_ids.map { Regexp.escape(it) }.join("|")
end

#register(cycle_class) ⇒ Object

Add a handler, displacing any already handling the same kind or notation id. That is what lets an application override a built-in kind — declare a class handling :lookback and it takes over "L" — as well as add one of its own. Re-registering the same class is a no-op, so a reloaded file accumulates no duplicates.

Returns the class, so a declaration can use the result.



30
31
32
33
34
35
36
37
# File 'lib/sof/cycle/registry.rb', line 30

def register(cycle_class)
  displaced = @cycle_classes.reject { |klass| klass.equal?(cycle_class) }
    .select { |klass| conflicts?(klass, cycle_class) }
  @cycle_classes -= displaced
  @cycle_classes << cycle_class unless @cycle_classes.include?(cycle_class)
  @notation_pattern = nil
  cycle_class
end

#unregister(cycle_class) ⇒ Object

Drop a handler. Mainly for an application undoing an override, and for tests that register a throwaway kind.



41
42
43
44
45
# File 'lib/sof/cycle/registry.rb', line 41

def unregister(cycle_class)
  @cycle_classes.delete(cycle_class)
  @notation_pattern = nil
  cycle_class
end