cybernetlab/ensure_it

View on GitHub
lib/ensure_it/ensure_integer.rb

Summary

Maintainability
C
7 hrs
Test Coverage
module EnsureIt
  patch Object do
    def ensure_integer(default: nil, **opts)
      default
    end

    def ensure_integer!(**opts)
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch String do
    def ensure_integer(default: nil, **opts)
      catch(:wrong) { return EnsureIt.ensure_integer_string(self, **opts) }
      default
    end

    def ensure_integer!(**opts)
      catch(:wrong) { return EnsureIt.ensure_integer_string(self, **opts) }
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch Integer do
    def ensure_integer(default: nil, **opts)
      return self if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(self, **opts) }
      default
    end

    def ensure_integer!(**opts)
      return self if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(self, **opts) }
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch Float do
    def ensure_integer(default: nil, **opts)
      return round if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(round, **opts) }
      default
    end

    def ensure_integer!(**opts)
      return round if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(round, **opts) }
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch Rational do
    def ensure_integer(default: nil, **opts)
      return round if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(round, **opts) }
      default
    end

    def ensure_integer!(**opts)
      return round if opts.empty?
      catch(:wrong) { return EnsureIt.ensure_integer(round, **opts) }
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch TrueClass do
    def ensure_integer(default: nil, boolean: nil, **opts)
      if boolean == true || boolean.is_a?(Integer)
        value = boolean == true ? 1 : boolean
        return value if opts.empty?
        catch(:wrong) { return EnsureIt.ensure_integer(value, **opts) }
      end
      default
    end

    def ensure_integer!(boolean: nil, **opts)
      if boolean == true || boolean.is_a?(Integer)
        value = boolean == true ? 1 : boolean
        return value if opts.empty?
        catch(:wrong) { return EnsureIt.ensure_integer(value, **opts) }
      end
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  patch FalseClass do
    def ensure_integer(default: nil, boolean: nil, **opts)
      if boolean == true || boolean.is_a?(Integer)
        return 0 if opts.empty?
        catch(:wrong) { return EnsureIt.ensure_integer(0, **opts) }
      end
      default
    end

    def ensure_integer!(default: nil, values: nil, boolean: nil, **opts)
      if boolean == true || boolean.is_a?(Integer)
        return 0 if opts.empty?
        catch(:wrong) { return EnsureIt.ensure_integer(0, **opts) }
      end
      EnsureIt.raise_error(:ensure_integer!,
                           **EnsureIt::ensure_integer_error(**opts))
    end
  end

  OCT_REGEXP = /\A0\d+\z/
  INT_REGEXP = /\A[+\-]?\d[\d_]*\z/
  HEX_REGEXP = /\A0x[0-9a-zA-Z]+\z/
  BIN_REGEXP = /\A0b[01]+\z/

  def self.ensure_integer(int, values: nil, **opts)
    throw :wrong if values.is_a?(Array) && !values.include?(int)
    int
  end

  def self.ensure_integer_string(str, **opts)
    value = case str
      when OCT_REGEXP then opts[:octal] == true ? str.to_i(8) : str.to_i
      when INT_REGEXP then str.to_i
      when HEX_REGEXP then str[2..-1].to_i(16)
      when BIN_REGEXP then str[2..-1].to_i(2)
      else throw :wrong
    end
    return value if opts.empty?
    return EnsureIt.ensure_integer(value, **opts)
  end

  def self.ensure_integer_error(**opts)
    unless opts.key?(:message)
      opts[:message] = '#{subject} should be an integer or be able' \
                       ' to convert to it'
    end
    opts
  end
end