Module: Hecks::Bluebook::Expression::CanonicalForm

Defined in:
lib/hecks/bluebook/expression/canonical_form.rb

Defined Under Namespace

Classes: Rule

Constant Summary collapse

STRATEGIES =
Hecks::Vocabulary.fetch("NormalisationStrategy")
RULES =

READ, NOT RESTATED — the admitted normalisation rules, projected from the grammar chapter by bin/expression_projection exactly as the evaluator's operator table is. See Evaluator::PROJECTION for why a projection rather than a boot.

JSON.parse(
  File.read(File.join(__dir__, "projection.json")), symbolize_names: true
).fetch(:normalisations).map { |row| Rule.new(**row) }.freeze

Class Method Summary collapse

Class Method Details

.apply(source) ⇒ Object



34
35
36
# File 'lib/hecks/bluebook/expression/canonical_form.rb', line 34

def apply(source)
  RULES.sort_by(&:position).reduce(source.to_s) { |text, rule| step(text, rule) }.strip
end

.replace(text, rule) ⇒ Object



47
48
49
50
51
# File 'lib/hecks/bluebook/expression/canonical_form.rb', line 47

def replace(text, rule)
  return text.gsub(rule.source_token, rule.replacement) if rule.boundary == "none"

  text.gsub(/#{Regexp.escape(rule.source_token)}(?![[:alnum:]_])/, rule.replacement)
end

.step(text, rule) ⇒ Object



38
39
40
41
42
43
44
45
# File 'lib/hecks/bluebook/expression/canonical_form.rb', line 38

def step(text, rule)
  case rule.strategy
  when "collapse_whitespace" then text.gsub(/\s+/, " ")
  when "replace"             then replace(text, rule)
  else
    raise ArgumentError, "#{rule.strategy.inspect} is not a linked normalisation strategy"
  end
end

.tableObject



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/hecks/bluebook/expression/canonical_form.rb', line 22

def table
  RULES.sort_by(&:position).map do |rule|
    {
      strategy:     rule.strategy,
      source_token: rule.source_token,
      replacement:  rule.replacement,
      boundary:     rule.boundary,
      position:     rule.position.to_s
    }
  end
end