Class: NumScaler

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

Overview

See README for practical examples.

Constant Summary collapse

VERSION =

NumScaler version string

'0.0.5'
EPSILON =

Epsilon defines rounding precision

14
MODES =

Available clamping modes

[:strict, :cycle, :clamp]

Instance Method Summary collapse

Constructor Details

#initialize(from, to, options = {}) ⇒ NumScaler

Additional options:

  • :mode - specify clamping mode (default: :strict)
  • :precision - specify Float rounding (default: EPSILON)

Precision defines number of significant decimal digits for rounding.

Current clamping modes:

  • :strict - raise ArgumentError for out-of-range number (default)
  • :clamp - clamp number to source range
  • :cycle - treat range as a circle of values

Parameters:

  • from (Range)

    source range

  • to (Range)

    target range

  • options (Hash) (defaults to: {})

    additional options

Raises:

  • (ArgumentError)

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/numscaler.rb', line 28

def initialize(from, to, options = {})
  @mode = options[:mode] || MODES.first
  @prec = options[:precision] || EPSILON

  raise ArgumentError, 'Unknown mode' unless MODES.member? @mode
  raise ArgumentError, 'Precision out of range' unless @prec > 0

  @src = { :orig  => from.min,
           :range => from.max.to_f - from.min.to_f,
           :max   => from.max.to_f,
           :min   => from.min.to_f }
  @tgt = { :orig  => to.min,
           :range => to.max.to_f - to.min.to_f,
           :max   => to.max.to_f,
           :min   => to.min.to_f }
end

Instance Method Details

#calc(num, a, b) ⇒ Numeric (private)

Perform actual calculation:

  1. First check and if necessary apply clamping
  2. Then convert between ranges
  3. Lastly check how to exactly return the result and do so

Parameters:

  • num (Numeric)

    number to convert

  • a (Hash)

    source range data

  • b (Hash)

    target range data

Returns:

  • (Numeric)

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/numscaler.rb', line 68

def calc(num, a, b)
  num = num.to_f

  unless num.between?(a[:min], a[:max])
    num = case @mode
          when :cycle
            ((num - a[:min]) % (a[:range])) + a[:min]
          when :clamp
            num > a[:max] ? a[:max] : a[:min]
          when :strict
            raise ArgumentError, 'Number out of range'
          end
  end

  res = (((num - a[:min]) * b[:range]) / a[:range]) + b[:min]

  case b[:orig]
  when Integer
    res.round
  else
    res.round(@prec)
  end
end

#from(num) ⇒ Numeric

Convert number from source to target

Parameters:

  • num (Numeric)

Returns:

  • (Numeric)

49
# File 'lib/numscaler.rb', line 49

def from(num); calc(num, @src, @tgt); end

#to(num) ⇒ Numeric

Convert number from target to source

Parameters:

  • num (Numeric)

Returns:

  • (Numeric)

55
# File 'lib/numscaler.rb', line 55

def to(num);   calc(num, @tgt, @src); end