Class: Ryac::SiteBucketMapping

Inherits:
Object
  • Object
show all
Defined in:
lib/ryac/analysis/site_bucket_mapping.rb,
sig/ryac/analysis/site_bucket_mapping.rbs

Overview

One (cpath, name) → sites table for the sigil families: instance and class variables differ only in their sigil, and a name of sigil + one character is already minimal.

Buckets merge along inheritance, and the merge records an alias so a site added afterwards lands in the merged bucket instead of silently resurrecting the child's. After assign_short_names the table is sealed: anything arriving later would miss renaming, so the phase that got its order wrong fails loudly instead.

Instance Method Summary collapse

Constructor Details

#initialize(prefix:) ⇒ SiteBucketMapping

Returns a new instance of SiteBucketMapping.

Parameters:

  • prefix: (String)


14
15
16
17
18
19
20
21
22
23
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 14

def initialize(prefix:)
  @prefix = prefix
  @kept_name_max = prefix.size + 1
  @buckets = {}
  @cpath_to_canonical = {}
  @excluded_cpaths = Set.new
  @reserved_names = {}
  @node_short_names = {}
  @frozen = false
end

Instance Method Details

#add_site(cpath, name, node) ⇒ void

This method returns an undefined value.

Parameters:

  • cpath (Array[Symbol])
  • name (Symbol)
  • node (Object)


25
26
27
28
29
30
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 25

def add_site(cpath, name, node)
  check_open!('site added')
  canonical = resolve_canonical(cpath)
  @buckets[canonical] ||= {}
  (@buckets[canonical][name] ||= []) << node
end

#assign_short_names ⇒ void

This method returns an undefined value.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 76

def assign_short_names
  @buckets.each do |cpath, names|
    next if @excluded_cpaths.include?(cpath)

    existing_names = Set.new
    names.each_key do |name|
      existing_names << name.to_s if name.to_s.size <= @kept_name_max
    end
    reserved = @reserved_names[cpath]
    existing_names.merge(reserved) if reserved

    generator = NameGenerator.new(existing_names, prefix: @prefix)
    sorted = names.sort_by do |name, nodes|
      -(name.to_s.size * nodes.size)
    end

    sorted.each do |name, nodes|
      next if name.to_s.size <= @kept_name_max

      short_name = generator.next_name
      savings = (name.to_s.size - short_name.size) * nodes.size
      next unless savings > 0

      nodes.each { |n| @node_short_names[AstUtils.location_key(n)] = short_name }
    end
  end
  @frozen = true
end

#check_open!(action) ⇒ void

This method returns an undefined value.

Parameters:

  • action (String)

Raises:



111
112
113
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 111

def check_open!(action)
  raise InternalError, "#{@prefix}-mapping: #{action} after assign_short_names" if @frozen
end

#each_canonical_cpath {|arg0| ... } ⇒ void

This method returns an undefined value.

Yields:

Yield Parameters:

  • arg0 (Array[Symbol])

Yield Returns:

  • (void)


44
45
46
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 44

def each_canonical_cpath(&block)
  @buckets.each_key(&block)
end

#exclude_cpath(cpath) ⇒ void

This method returns an undefined value.

Parameters:

  • cpath (Array[Symbol])


32
33
34
35
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 32

def exclude_cpath(cpath)
  check_open!('cpath excluded')
  @excluded_cpaths << resolve_canonical(cpath)
end

#merge_with_ancestor(child_cpath, ancestor_cpath) ⇒ void

This method returns an undefined value.

Parameters:

  • child_cpath (Array[Symbol])
  • ancestor_cpath (Array[Symbol])


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 48

def merge_with_ancestor(child_cpath, ancestor_cpath)
  check_open!('merge')
  child_canonical = resolve_canonical(child_cpath)
  ancestor_canonical = resolve_canonical(ancestor_cpath)
  return if child_canonical == ancestor_canonical
  return unless @buckets.key?(ancestor_canonical)

  child_entry = @buckets[child_canonical]
  return unless child_entry

  # Recorded before the sites move: from here on, a site added for the
  # child cpath belongs to the merged bucket.
  @cpath_to_canonical[child_canonical] = ancestor_canonical

  ancestor_entry = @buckets[ancestor_canonical]
  child_entry.keys.each do |name|
    child_nodes = child_entry.delete(name)
    next unless child_nodes
    if ancestor_entry.key?(name)
      ancestor_entry[name].concat(child_nodes)
    else
      ancestor_entry[name] = child_nodes
    end
  end

  @buckets.delete(child_canonical) if child_entry.none?
end

#node_mapping ⇒ Hash[[Integer, Integer], String]

Returns:

  • (Hash[[Integer, Integer], String])


105
106
107
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 105

def node_mapping
  @node_short_names.dup
end

#reserve_name(cpath, short_name) ⇒ void

This method returns an undefined value.

Parameters:

  • cpath (Array[Symbol])
  • short_name (String)


37
38
39
40
41
42
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 37

def reserve_name(cpath, short_name)
  check_open!('name reserved')
  canonical = resolve_canonical(cpath)
  @reserved_names[canonical] ||= Set.new
  @reserved_names[canonical] << short_name
end

#resolve_canonical(cpath) ⇒ Array[Symbol]

Parameters:

  • cpath (Array[Symbol])

Returns:

  • (Array[Symbol])


115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ryac/analysis/site_bucket_mapping.rb', line 115

def resolve_canonical(cpath)
  return cpath unless @cpath_to_canonical.key?(cpath)

  current = cpath
  seen = Set.new
  while @cpath_to_canonical.key?(current) && !seen.include?(current)
    seen << current
    current = @cpath_to_canonical[current]
  end
  current
end