module PlainText::Util

Contains some utility methods for use in this module and classes.

@author Masa Sakano (Wise Babel Ltd)

Private Instance Methods

arind2ranges(arin) click to toggle source

Make the Array of Ranges from an Array of positive Integers

@example

arind2ranges [1,2,3,6,7,9]
# => [(1..3), (6..7), (9..9)]

@param arin [Array<Integer>] @return [Array<Range>]

# File lib/plain_text/util.rb, line 23
def arind2ranges(arin)
  arout = []
  (curi = curf = arin[0]) || raise("arin should not be empty.")
  arin.each do |i|
    if i > curf + 1
      arout.push(curi..curf)
      curi = curf = i
    else
      curf = i
    end
  end
  arout.push(curi..curf)
  arout  
end
even_odd_arrays(ary, size_even: false, filler: "") click to toggle source

Returns a pair of Arrays of even and odd number-indices of the original Array

@example

even_odd_arrays([33,44,55], size_even: true)
# => [[33, 55], [44, ""]]

@param ary [Array] @param size_even: [Boolean] if true (Def: false), the sizes of the returned arrays are guaranteed to be identical. @param filler: [Object] if size_even: is true and if matching is performed, this filler is added at the end of the last element.

# File lib/plain_text/util.rb, line 48
def even_odd_arrays(ary, size_even: false, filler: "")
  ar_even = select.with_index { |_, i| i.even? } rescue select.each_with_index { |_, i| i.even? } # Rescue for Ruby 2.1 or earlier
  ar_odd  = select.with_index { |_, i| i.odd? }  rescue select.each_with_index { |_, i| i.odd? }  # Rescue for Ruby 2.1 or earlier
  if size_even && (ar_even.size != ar_odd.size)
    ar_odd.push filler
    raise "Should not happern." if (ar_even.size != ar_odd.size)
  end
  [ar_even, ar_odd]
end
like_range?(obj) click to toggle source

Returns true if obj is like Range (duck-typing).

@param obj [Object]

# File lib/plain_text/util.rb, line 141
def like_range?(obj)
  obj.respond_to? :exclude_end?
end
positive_array_index(i, ary=nil) click to toggle source

Returns a non-negative Array index for self

If positive or zero, it returns i. If the negative index is out of range, it returns nil.

@param i [Integer] @param ary [Array, Integer, nil] Reference Array or its size (Array#size) or nil (interpreted as self#size (untested)). @return [Integer, NilClass] nil if out of range to the negative. Note in most cases in Ruby default, it raises IndexError. See the code of {#positive_array_index_checked} @raise [TypeError] if non-integer is specified. @raise [ArgumentError] if ary is neither an Array nor Integer, or more specifically, it does not have size method or ary.size does not return Integer or similar.

# File lib/plain_text/util.rb, line 68
def positive_array_index(i, ary=nil)
  arysize = (ary ? (ary.respond_to?(:to_int) ? ary.to_int : ary.size) : size)
  i2 = i.to_int rescue (raise TypeError, sprintf("no implicit conversion of #{i.class} into Integer (i=#{i.inspect},ary=#{ary.inspect})"))
  return i2 if i2 >= 0
  ret = arysize + i2 rescue (raise ArgumentError, "Reference is neither an Array nor Integer.")
  (ret < 0) ? nil : ret
end
positive_array_index_checked(index_in, ary=nil, accept_too_big: true, varname: nil) click to toggle source

Returns a non-negative Array index for self, performing a check.

Exception is raised if it is out of range.

Wrapper for {#positive_array_index}

@param index_in [Integer] Index to check and convert from. Potentially negative integer. @param ary [Array, Integer, nil] Reference Array or its size (Array#size) or nil (interpreted as self#size (untested)). @param accept_too_big: [Boolean, NilClass] if true (Default), a positive index larger than the last array index is returned as it is. If nil, the last index + 1 is accepted but raises an Exception for anything larger. If false, any index larger than the last index raises an Exception. @param varname: [NilClass, String] Name of the variable (or nil) to be used for error messages. @return [Integer] Non-negative index; i.e., if index=-1 is specified for an Array with a size of 3, the returned value is 2 (the last index of it). @raise [IndexError] if the index is out of the range to negative. @raise [ArgumentError] if ary is neither an Array nor Integer, or more specifically, it does not have size method or ary.size does not return Integer or similar.

# File lib/plain_text/util.rb, line 90
def positive_array_index_checked(index_in, ary=nil, accept_too_big: true, varname: nil)
  # def self.positive_valid_index_for_array(index_in, ary, varname: nil)
  errmsgs = {}
  %w(of for).each do |i|
    errmsgs[i] = (varname ? "." : sprintf(" %s %s.", i, varname)) 
  end
  
  arysize = (ary ? (ary.respond_to?(:to_int) ? ary.to_int : ary.size) : size)
  index = positive_array_index(index_in, arysize)  # guaranteed to be Integer or nil (or ArgumentError)
  raise IndexError, sprintf("index (%s) too small for array; minimum: -%d", index_in, arysize) if !index  # Ruby default Error message (except the variable "index" as opposed to "index_in is used in the true Ruby default).
  if index_in >= 0
    last_index = arysize - 1
    errnote1 = nil
    if    (index >  last_index + 1) && !accept_too_big
      errnote1 = ' (or +1)'
    elsif (index == last_index + 1) && (false == accept_too_big)
      errnote1 = " "
    end
    raise IndexError, sprintf("Specified index (%s) is larger than the last index (%d)%s%s", index_in, last_index, errnote1, errmsgs['of']) if errnote1
  end
  index
end
raise_typeerror(var, to_class, verbose: $DEBUG) click to toggle source

Raise TypeError

Call as +raise_typeerror(var_name)+ from instance methods, providing this Module is included in the Class/Module.

@param var [Object] @param to_class [String, Class] class name converted into. @option verbose: [Boolean] ($DEBUG) @raise [TypeError]

# File lib/plain_text/util.rb, line 154
def raise_typeerror(var, to_class, verbose: $DEBUG)
  msg1 = (verbose ? sprintf("(<= %s)", var.inspect) : "")
  to_class_str = (to_class.name rescue to_class.to_str)
  raise TypeError, sprintf("no implicit conversion of %s%s into %s", var.class, msg1, to_class_str)
end
to_ary_positive_index(from, arref, flatten: true, sortuniq: true, **kwd) click to toggle source

Converts Array or Range to an Array with positive indices.

@param from [Array, Range] @param arref [Array, Integer] Reference Array or its size (Array#size) or nil (interpreted as self#size). @param flatten: [Boolean] If true (Default), if elements are Range, they are unfolded. If false and if an Array containing a Range, Exception is raised. @param sortuniq: [Boolean] If true (Default), the return is sorted and uniq-ed. @return [Array, nil] nil if arref is empty or if out of range to the negative. Note in most cases in Ruby default, it raises IndexError. See the code of {#positive_array_index_checked} @raise [TypeError] if non-integer is specified. @raise [ArgumentError] if arref is neither an Array nor Integer, or more specifically, it does not have size method or arref.size does not return Integer or similar.

# File lib/plain_text/util.rb, line 122
def to_ary_positive_index(from, arref, flatten: true, sortuniq: true, **kwd)
  arrefsize = (arref ? (arref.respond_to?(:to_int) ? arref.to_int : arref.size) : size)
  return nil if arrefsize < 1
  if flatten
    from = [from].flatten.map{|ec| like_range?(ec) ? send(__method__, ec, arrefsize, flatten: false, sortuniq: sortuniq, **kwd) : ec }.flatten
  end
  if like_range?(from)
    i_beg = positive_array_index_checked(from.begin, arrefsize, **kwd)
    n = from.end
    i_end = ((n.nil? || n == Float::INFINITY) ? arrefsize-1 : positive_array_index_checked(n, arrefsize, **kwd))
    return (from.exclude_end? ? (i_beg...i_end) : (i_beg..i_end)).to_a
  end
  ret = from.map{|i| positive_array_index_checked(i, arrefsize, **kwd)}
  (sortuniq ? ret.sort.uniq : ret) 
end