Class: Moxml::NativeAttachment::Native

Inherits:
Object
  • Object
show all
Defined in:
lib/moxml/native_attachment/native.rb

Overview

Stores Moxml-specific state associated with native adapter objects without polluting their internals.

Uses object_id as key with GC finalizer cleanup to prevent memory leaks. Thread-safe via Monitor (reentrant-safe).

Replaces the anti-pattern of using instance_variable_set/get on foreign library objects (Nokogiri, REXML, Oga, Ox, LibXML nodes).

Examples:

attachments = NativeAttachment.new
attachments.set(native_element, :entity_refs, [])
refs = attachments.get(native_element, :entity_refs)
attachments.key?(native_element, :doctype) #=> false

Instance Method Summary collapse

Constructor Details

#initializeNative

Returns a new instance of Native.



22
23
24
25
26
# File 'lib/moxml/native_attachment/native.rb', line 22

def initialize
  @data = {}
  @finalizer_registered = {}
  @monitor = Monitor.new
end

Instance Method Details

#delete(native, key) ⇒ Object



58
59
60
# File 'lib/moxml/native_attachment/native.rb', line 58

def delete(native, key)
  @monitor.synchronize { @data[native.object_id]&.delete(key) }
end

#get(native, key) ⇒ Object

Reads are lock-free: MRI Hash#[] is atomic under the GVL, and the only mid-write race (set assigns the inner hash before its key) resolves to a miss — the same answer as "not set yet", which every reader treats conservatively. This method sits on per-element hot paths (entity_bearing? on every serialize).



33
34
35
# File 'lib/moxml/native_attachment/native.rb', line 33

def get(native, key)
  @data[native.object_id]&.[](key)
end

#key?(native, key) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
# File 'lib/moxml/native_attachment/native.rb', line 53

def key?(native, key)
  h = @data[native.object_id]
  !h.nil? && h.key?(key)
end

#none_set?(native, keys) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
49
50
51
# File 'lib/moxml/native_attachment/native.rb', line 46

def none_set?(native, keys)
  h = @data[native.object_id]
  return true if h.nil?

  keys.none? { |key| h.key?(key) }
end

#set(native, key, value) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/moxml/native_attachment/native.rb', line 37

def set(native, key, value)
  id = native.object_id
  @monitor.synchronize do
    @data[id] ||= {}
    @data[id][key] = value
    register_finalizer(native, id) unless @finalizer_registered[id]
  end
end