Module: AsciiChem::RingBonds
- Defined in:
- lib/asciichem/ring_bonds.rb
Overview
Derives ring bonds from atoms with matching ring_closures digits.
Single source of truth for the "find ring bond pairs" algorithm —
used by the Layout walker (to emit additional edges), the
ModelAdapter walker (to emit additional canonical bonds), and the
UnclosedRingCheck linter (to flag unmatched digits).
Algorithm: walk atoms in source order. For each digit on each atom, if we've seen it before (open ring), the current atom closes the ring — yield a RingBond pairing them, and clear the open record. Otherwise, record the current atom as the ring's opener.
Multiple digits on one atom (C12) open/close multiple rings in
parallel. Digit "0" through "9" are supported in any order.
Defined Under Namespace
Classes: RingBond
Class Method Summary collapse
-
.each_in(molecule) ⇒ Object
Yields each RingBond to the block.
-
.unclosed_atoms(molecule) ⇒ Object
Returns atoms whose ring_closures digits have no matching partner.
Class Method Details
.each_in(molecule) ⇒ Object
Yields each RingBond to the block. Walks the molecule in source
order so from_atom always precedes to_atom.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/asciichem/ring_bonds.rb', line 22 def self.each_in(molecule) open_rings = {} walk_atoms(molecule) do |atom| next unless atom.ring_closures atom.ring_closures.to_s.each_char do |digit| if open_rings.key?(digit) yield RingBond.new(digit: digit, from_atom: open_rings[digit], to_atom: atom) open_rings.delete(digit) else open_rings[digit] = atom end end end end |
.unclosed_atoms(molecule) ⇒ Object
Returns atoms whose ring_closures digits have no matching partner. Used by the UnclosedRingCheck linter.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/asciichem/ring_bonds.rb', line 40 def self.unclosed_atoms(molecule) open_rings = {} unclosed = [] walk_atoms(molecule) do |atom| next unless atom.ring_closures atom.ring_closures.to_s.each_char do |digit| if open_rings.key?(digit) open_rings.delete(digit) else open_rings[digit] = atom end end end open_rings.each_value { |atom| unclosed << atom } unclosed end |