Class: Bases::Number

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

Overview

The main class provided by Bases. It represents a base-agnostic number which can be forced to be interpreted in any base and then converted in any base.

Instance Method Summary collapse

Constructor Details

#initialize(value) ⇒ Number

Create a new instance from a given value. If that value is an intance of a subclass of Integer (a Bignum or a Fixnum), it will be assumed to be in base 10 and any call to in_base on the new instance will result in an exception.

If it is a String, no base will be assumed; if there are spaces in the string, they're used to separate the multicharacter digits, otherwise each character is assumed to be a digit.

It value is an Array, each element in the array is assumed to be a digit. The array is read like a normal number, where digits on the left are more significative than digits on the right.

Parameters:

Raises:



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/bases/number.rb', line 23

def initialize(value)
  case value
  when Integer
    @source_base = helpers.base_to_array(10)
    @value = value
  when String
    @digits = (value =~ /\s/) ? value.split : value.split('')
  when Array
    @digits = value.map(&:to_s)
  else
    fail Bases::InvalidValueError, "#{value} isn't a valid value"
  end
end

Instance Method Details

#algorithmsObject (private)

A facility method for accessing the Algorithms module.



156
157
158
# File 'lib/bases/number.rb', line 156

def algorithms
  Bases::Algorithms
end

#helpersObject (private)

A facility method for accessing the Helpers module.



161
162
163
# File 'lib/bases/number.rb', line 161

def helpers
  Bases::Helpers
end

#in_base(base) ⇒ Object

Set the source base of the current number. The base can be either a number (like 2 for binary or 16 for hexadecimal) or an array. In the latter case, the array is considered the whole base. For example, the binary base would be represented as [0, 1]; another binary base could be [:a, :b] and so on.

Note that when the base is an integer up to 36, the native Ruby Integer#to_i(base) method is used for efficiency and clarity. However, this means that digits in a base 36 are numbers and letters, while digits in base 37 and more are only numbers (interpreted as multichar digits).

self is returned in order to allow nice-looking chaining.

Parameters:

Returns:

  • self

Raises:

  • (WrongDigitsError)

    if there are digits in the previously specified value that are not present in base.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/bases/number.rb', line 54

def in_base(base)
  @source_base = helpers.base_to_array(base)

  if native_ruby_base?(base)
    @value = @digits.join('').to_i(base)
    return self
  end

  # Make sure `@digits` contains only valid digits.
  unless helpers.only_valid_digits?(@digits, @source_base)
    fail Bases::WrongDigitsError,
      "Some digits weren't in base #{base}"
  end

  @value = algorithms.convert_from_base(@digits, @source_base)
  self
end

#in_binaryself

Specify that the current number is in binary representation. This is just a shortcut for in_base(2) or in_base([0, 1]).

Returns:

  • (self)


131
132
133
# File 'lib/bases/number.rb', line 131

def in_binary
  in_base(2)
end

#in_hexself

Note:

If you want to parse an hexadecimal number ignoring case-sensitivity, you can't use in_base(Bases::HEX) since that assumes upper case digits. You have to use in_hex, which internally just calls String#hex.

Specify that the current number is in hexadecimal representation.

Returns:

  • (self)


122
123
124
125
126
# File 'lib/bases/number.rb', line 122

def in_hex
  @source_base = helpers.base_to_array(16)
  @value = @digits.join('').hex
  self
end

#native_ruby_base?(base) ⇒ Boolean (private)

Returns:

  • (Boolean)


151
152
153
# File 'lib/bases/number.rb', line 151

def native_ruby_base?(base)
  base.is_a?(Integer) && base.between?(2, 36)
end

#to_base(new_base, opts = {}) ⇒ Array<String>|String

Return a string representation of the current number in a new_base. A string representation is always returned, even if new_base is 10. If you're using base 10 and want an integer, just call to_i on the resulting string.

Examples:

With the default separator

Number.new(3).to_base(2) #=> '11'

With a different separator

Number.new(3).to_base(2, separator: ' ~ ') #=> '1 ~ 1'

Parameters:

  • new_base (Integer|Array)

    The same as in in_base

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

    A small hash of options

Options Hash (opts):

  • :array (bool)

    If true, return the result as an array of digits; otherwise, return a string. This defaults to false.

Returns:

Raises:

  • (NoBaseSpecifiedError)

    if no source base was specified (either by passing an integer to the constructor or by using the in_base method)



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/bases/number.rb', line 89

def to_base(new_base, opts = {})
  opts[:array] = false if opts[:array].nil?

  unless defined?(@source_base)
    fail Bases::NoBaseSpecifiedError, 'No base was specified'
  end

  # Let's apply the base conversion algorithm, which returns an array of
  # digits.
  res = if native_ruby_base?(new_base)
          @value.to_s(new_base).split('')
        else
          algorithms.convert_to_base(@value, helpers.base_to_array(new_base))
        end

  opts[:array] ? res : res.join('')
end

#to_binaryString

Just an alias to to_base(2).

Returns:

See Also:



138
139
140
# File 'lib/bases/number.rb', line 138

def to_binary
  to_base(2)
end

#to_hexString

Just an alias to to_base(Bases::HEX).

Returns:

See Also:

  • Numer#to_base


145
146
147
# File 'lib/bases/number.rb', line 145

def to_hex
  to_base(16)
end

#to_iInteger

This function assumes you want the output in base 10 and returns an integer instead of a string (which would be returned after a call to to_base(10)). This was introduced so that to_i is adapted to the standard of returning an integer (in base 10, as Ruby represents integers).

Returns:



112
113
114
# File 'lib/bases/number.rb', line 112

def to_i
  to_base(10).to_i
end