Class: TreRegex::Regex

Inherits:
Object
  • Object
show all
Defined in:
lib/tre_regex.rb

Overview

User-Facing Ruby Class

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pattern, ignore_case: false) ⇒ Regex

Returns a new instance of Regex.

Raises:



83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/tre_regex.rb', line 83

def initialize(pattern, ignore_case: false)
  @pattern = pattern
  # Allocate a safe 256-byte buffer in C memory for the regex_t struc
  @preg = FFI::MemoryPointer.new(:char, 256)

  flags = Native::REG_EXTENDED
  flags |= Native::REG_ICASE if ignore_case

  res = Native.tre_regcomp(@preg, pattern, flags)
  raise TreRegex::Error, "Failed to compile regex pattern: #{pattern}" if res != 0

  # Garbage Collection Hook: Tell Ruby to free the C memory when this object is destroyed
  ObjectSpace.define_finalizer(self, self.class.finalize(@preg))
end

Instance Attribute Details

#patternObject (readonly)

Returns the value of attribute pattern.



81
82
83
# File 'lib/tre_regex.rb', line 81

def pattern
  @pattern
end

Class Method Details

.finalize(preg_ptr) ⇒ Object

The GC finalizer proc



99
100
101
102
103
104
# File 'lib/tre_regex.rb', line 99

def self.finalize(preg_ptr)
  proc do
    Native.tre_regfree(preg_ptr)
    preg_ptr.free
  end
end

Instance Method Details

#exec(text, options = {}) ⇒ Object



110
111
112
113
114
115
# File 'lib/tre_regex.rb', line 110

def exec(text, options = {})
  ptr = FFI::MemoryPointer.from_string(text)
  m_info = execute_match(ptr, text.bytesize, options)

  m_info ? extract_match_payload(text, 0, 0, m_info).first : nil
end

#match_all(text, options = {}) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/tre_regex.rb', line 117

def match_all(text, options = {})
  return enum_for(:match_all, text, options) unless block_given?

  ptr = FFI::MemoryPointer.from_string(text)
  b_off = c_off = 0

  while b_off <= text.bytesize
    m_info = execute_match(ptr + b_off, text.bytesize - b_off, options)
    break unless m_info

    payload, adv_b, adv_c = extract_match_payload(text, b_off, c_off, m_info)
    yield payload

    break if adv_b.zero? && b_off == text.bytesize

    # Zero-width infinite loop protection
    if adv_b.zero?
      adv_b = text.byteslice(b_off..).chr.bytesize
      adv_c = 1
    end

    b_off += adv_b
    c_off += adv_c
  end
end

#test?(text, options = {}) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/tre_regex.rb', line 106

def test?(text, options = {})
  !exec(text, options).nil?
end