class MatchSkeleton
Class MatchSkeleton
¶ ↑
To represent {MatchData} with much less memory use
Attributes
The position {Regexp} match has started. For example, both
/x/.match('0000x', 0) /x/.match('0000x', 3)
give the same (equal) {MatchData}. This instance variable {#pos_begin} holds the position (0 or 3 in the cases above), if set explicitly.
The same as {MatchData#regexp}.
The same as {MatchData#string} but it is identical to the original string. If the original string is modified destructively, this too is modified.
Public Class Methods
Constructor
If the second argument is omitted, it is taken from the first argument with +MatchData#string+. However, it would spoil the whole point of using this class, given +MatchData#string+ always “dups” the original string and uses up extra memory space! If you do not specify the second argument, this class offers almost identical functions but works slower, save from the bonus information of pos_begin
, which can be added in this initialization in this class.
The point of using this class is to save the memory when you make multiple applications with many Regexp to the identical instance of String (with the same object_id) and if you want to keep the results of the Regexp match as MatchData
or equivalent. So, do not forget to specify the second argument in this initialization!
@param md [MatchData] @param string [String] If not specified, it is taken from the first argument. @param pos_begin
: [Integer] The position where {Regexp} match has started.
# File lib/match_skeleton.rb, line 53 def initialize(md, string=nil, pos_begin: nil) size_str = md.string.size if string && string.size != size_str raise ArgumentError, 'The first parameter is obligatory.' end @string = (string || md.string) @regexp = md.regexp @pre_match = (0...md.pre_match.size) # {Range} @post_match = ((size_str-md.post_match.size)...size_str) # {Range} # @offsets is Hash of Range-s with the keys of both Integer and possibly Symbol # if names exist. names = md.names ar_off = (0..(md.size-1)).map do |n| ar = md.offset(n) (ar.first...ar.last) end @offsets = {} ar_off.each_with_index do |ev, ei| @offsets[ei] = ev ej = ei - 1 @offsets[names[ej]] = ev if (ej >= 0 && names[ej]) end @pos_begin = pos_begin end
Public Instance Methods
Comparable with {MatchSkeleton} and {MatchData}
A difference in {#pos_begin} is not taken into account.
@param obj [Object] The methods of {#string}, {#regexp}, {#pre_match} have to be defined and return the same to be true. Practically, only {MatchSkeleton} and {MatchData} may return true. @return [Boolean] @see eql?
# File lib/match_skeleton.rb, line 87 def ==(obj) !!((defined?(obj.string) && string == obj.string) && (defined?(obj.regexp) && regexp == obj.regexp) && (defined?(obj.pre_match) && pre_match == obj.pre_match) && (defined?(obj.post_match) && post_match == obj.post_match)) # nb., defined?() can return nil, and then nil (not false) will be returned. end
The same as {MatchData#[]}
@param i [Integer, Range, Symbol, String] @param j [Integer, NilClass] @return [String, Array, NilClass] @raise [IndexError] if an invalid argument(s) is given.
# File lib/match_skeleton.rb, line 101 def [](i, j=nil) if j to_a[i, j] elsif defined?(i.to_sym) i = i.to_s raise IndexError, sprintf("undefined group name reference: %s", i) if !names.include?(i) offset2string(i) else to_a[i] end end
The same as {MatchData#begin}
@param n [Integer] @return [Integer]
# File lib/match_skeleton.rb, line 117 def begin(n) offset(n)[0] end
The same as {MatchData#captures}
@return [Array]
# File lib/match_skeleton.rb, line 124 def captures to_a[1..-1] end
The same as {MatchData#end}
@param n [Integer] @return [Integer]
# File lib/match_skeleton.rb, line 132 def end(n) offset(n)[1] end
Similar to {MatchData#inspect}
@return [String]
# File lib/match_skeleton.rb, line 156 def inspect core = '' ar = (names.empty? ? captures : names) ar.each_with_index do |ev, ei| core << sprintf(" %d:%s", ei, ev.inspect) end sprintf("#<%s %s%s>", self.class.to_s, self[0].inspect, core) end
The same as {MatchData#names} and {Regexp#names}
@return [Array<String>]
# File lib/match_skeleton.rb, line 168 def names regexp.names end
The same as {MatchData#offset}
Due to the change in Ruby 2.6 rubyreferences.github.io/rubychanges/2.6.html#endless-range-1 the old routines would raise an Excetion when the end range is nil, that is, there is no match for MatchData#, hence needed updating.
@param n [Integer] @return [Array<integer>]
# File lib/match_skeleton.rb, line 181 def offset(n) if defined?(n.to_sym) n = n.to_s raise IndexError, sprintf("undefined group name reference: %s", n) if !names.include?(n) end ## This used to work before Ruby 2.6 # [@offsets[n].first, # @offsets[n].last] [:first, :last].map do |ec| begin @offsets[n].public_send ec rescue RangeError nil end end end
The same as {MatchData#post_match}
@return [String]
# File lib/match_skeleton.rb, line 210 def post_match @string[@post_match] end
The same as {MatchData#pre_match}
@return [String]
# File lib/match_skeleton.rb, line 203 def pre_match @string[@pre_match] end
The same as {MatchData#size}
@return [Integer]
# File lib/match_skeleton.rb, line 217 def size to_a.size end
The same as {MatchData#to_a}
@return [Array]
# File lib/match_skeleton.rb, line 225 def to_a indices = @offsets.keys.sort indices.delete_if { |i| !defined?(i.divmod) } indices.map { |i| offset2string(i) } end
The same as {MatchData#to_s}
@return [String]
# File lib/match_skeleton.rb, line 234 def to_s self[0] end
The same as {MatchData#values_at}
@param *rest [Integer, Symbol, String] @return [Array]
# File lib/match_skeleton.rb, line 242 def values_at(*rest) locary = to_a rest.map do |i| locary[i] end end
Private Instance Methods
@note Due to the change in Ruby 2.6, k.last may raise RangeError.
In this instance, k.first must be always nil when k.last is nil. So, k.last would not be evaluated when k.last is nil. But it is playing safe (by adding "rescue").
# File lib/match_skeleton.rb, line 257 def offset2string(i) k = @offsets[i] (k.first && (k.last rescue nil)) ? string[k] : nil end