Class: Markbridge::Normalizer::RuleSet
- Inherits:
-
Object
- Object
- Markbridge::Normalizer::RuleSet
- Defined in:
- lib/markbridge/normalizer/rule_set.rb
Overview
Maps a node and its ancestor stack to a strategy.
Matching is exact-class (equivalent to instance_of?): rules are
keyed by Class and looked up via node.class, so an anonymous
Class.new(AST::Element) or any future subclass never accidentally
matches a rule written for the base class. Registering a rule for a
(parent, child) pair that already has one replaces it, so later
layers (Discourse, a consumer's #rule) override earlier ones.
Constant Summary collapse
- NO_MATCH =
[nil, nil].freeze
Instance Method Summary collapse
-
#add(parent:, child:, strategy:) ⇒ self
Register (or replace) a rule.
-
#freeze ⇒ Object
Freeze so a shared instance raises if something tries to change it.
-
#initialize ⇒ RuleSet
constructor
A new instance of RuleSet.
-
#resolve(child, ancestors) ⇒ Array(Object, AST::Element), Array(nil, nil)
Resolve the strategy for
childgiven its ancestor stack (root first).
Constructor Details
#initialize ⇒ RuleSet
Returns a new instance of RuleSet.
16 17 18 19 |
# File 'lib/markbridge/normalizer/rule_set.rb', line 16 def initialize @by_parent = {} # parent_class => { child_class => strategy } @child_classes = Set.new end |
Instance Method Details
#add(parent:, child:, strategy:) ⇒ self
Register (or replace) a rule.
27 28 29 30 31 32 |
# File 'lib/markbridge/normalizer/rule_set.rb', line 27 def add(parent:, child:, strategy:) validate_strategy!(strategy) (@by_parent[parent] ||= {})[child] = strategy @child_classes << child self end |
#freeze ⇒ Object
Freeze so a shared instance raises if something tries to change it.
Freezing @by_parent and its inner hashes is enough: #add writes
there before it touches @child_classes, so a frozen instance raises
on the @by_parent write first. @child_classes is never reached, so
it does not need freezing.
57 58 59 60 61 |
# File 'lib/markbridge/normalizer/rule_set.rb', line 57 def freeze @by_parent.each_value(&:freeze) @by_parent.freeze super end |
#resolve(child, ancestors) ⇒ Array(Object, AST::Element), Array(nil, nil)
Resolve the strategy for child given its ancestor stack (root
first). Returns [strategy, boundary] where boundary is the
outermost ancestor whose class has a rule for +child+'s class, or
NO_MATCH (+[nil, nil]+) when nothing matches.
42 43 44 45 46 47 48 49 50 |
# File 'lib/markbridge/normalizer/rule_set.rb', line 42 def resolve(child, ancestors) child_class = child.class # Skip the ancestor scan for a class no rule targets (most nodes, for # example plain text). The scan below returns the same result for such # a class, so this only saves work. return NO_MATCH unless @child_classes.include?(child_class) scan_ancestors(child_class, ancestors) end |