== Implicit Conversions

Some Ruby methods accept one or more objects
that can be either:
* <i>Of a given class</i>, and so accepted as is.
* <i>Implicitly convertible to that class</i>, in which case
  the called method converts the object.

For each of the relevant classes, the conversion is done by calling
a specific conversion method:

* Array: +to_ary+
* Hash: +to_hash+
* Integer: +to_int+
* String: +to_str+

=== Array-Convertible Objects

An <i>Array-convertible object</i> is an object that:
* Has instance method +to_ary+.
* The method accepts no arguments.
* The method returns an object +obj+ for which <tt>obj.kind_of?(Array)</tt> returns +true+.

The examples in this section use method <tt>Array#replace</tt>,
which accepts an Array-convertible argument.

This class is Array-convertible:

    class ArrayConvertible
      def to_ary
        [:foo, 'bar', 2]
      end
    end
    a = []
    a.replace(ArrayConvertible.new) # => [:foo, "bar", 2]

This class is not Array-convertible (no +to_ary+ method):

    class NotArrayConvertible; end
    a = []
    # Raises TypeError (no implicit conversion of NotArrayConvertible into Array)
    a.replace(NotArrayConvertible.new)

This class is not Array-convertible (method +to_ary+ takes arguments):

    class NotArrayConvertible
      def to_ary(x)
        [:foo, 'bar', 2]
      end
    end
    a = []
    # Raises ArgumentError (wrong number of arguments (given 0, expected 1))
    a.replace(NotArrayConvertible.new)

This class is not Array-convertible (method +to_ary+ returns non-Array):

    class NotArrayConvertible
      def to_ary
        :foo
      end
    end
    a = []
    # Raises TypeError (can't convert NotArrayConvertible to Array (NotArrayConvertible#to_ary gives Symbol))
    a.replace(NotArrayConvertible.new)

=== Hash-Convertible Objects

A <i>Hash-convertible object</i> is an object that:
* Has instance method +to_hash+.
* The method accepts no arguments.
* The method returns an object +obj+ for which <tt>obj.kind_of?(Hash)</tt> returns +true+.

The examples in this section use method <tt>Hash#merge</tt>,
which accepts a Hash-convertible argument.

This class is Hash-convertible:

    class HashConvertible
      def to_hash
        {foo: 0, bar: 1, baz: 2}
      end
    end
    h = {}
    h.merge(HashConvertible.new) # => {:foo=>0, :bar=>1, :baz=>2}

This class is not Hash-convertible (no +to_hash+ method):

    class NotHashConvertible; end
    h = {}
    # Raises TypeError (no implicit conversion of NotHashConvertible into Hash)
    h.merge(NotHashConvertible.new)

This class is not Hash-convertible (method +to_hash+ takes arguments):

    class NotHashConvertible
      def to_hash(x)
        {foo: 0, bar: 1, baz: 2}
      end
    end
    h = {}
    # Raises ArgumentError (wrong number of arguments (given 0, expected 1))
    h.merge(NotHashConvertible.new)

This class is not Hash-convertible (method +to_hash+ returns non-Hash):

    class NotHashConvertible
      def to_hash
        :foo
      end
    end
    h = {}
    # Raises TypeError (can't convert NotHashConvertible to Hash (ToHashReturnsNonHash#to_hash gives Symbol))
    h.merge(NotHashConvertible.new)

=== Integer-Convertible Objects

An <i>Integer-convertible object</i> is an object that:
* Has instance method +to_int+.
* The method accepts no arguments.
* The method returns an object +obj+ for which <tt>obj.kind_of?(Integer)</tt> returns +true+.

The examples in this section use method <tt>Array.new</tt>,
which accepts an Integer-convertible argument.

This user-defined class is Integer-convertible:

    class IntegerConvertible
      def to_int
        3
      end
    end
    a = Array.new(IntegerConvertible.new).size
    a # => 3

This class is not Integer-convertible (method +to_int+ takes arguments):

    class NotIntegerConvertible
      def to_int(x)
        3
      end
    end
    # Raises ArgumentError (wrong number of arguments (given 0, expected 1))
    Array.new(NotIntegerConvertible.new)

This class is not Integer-convertible (method +to_int+ returns non-Integer):

    class NotIntegerConvertible
      def to_int
        :foo
      end
    end
    # Raises TypeError (can't convert NotIntegerConvertible to Integer (NotIntegerConvertible#to_int gives Symbol))
    Array.new(NotIntegerConvertible.new)

=== String-Convertible Objects

A <i>String-convertible object</i> is an object that:
* Has instance method +to_str+.
* The method accepts no arguments.
* The method returns an object +obj+ for which <tt>obj.kind_of?(String)</tt> returns +true+.

The examples in this section use method <tt>String::new</tt>,
which accepts a String-convertible argument.

This class is String-convertible:

    class StringConvertible
      def to_str
        'foo'
      end
    end
    String.new(StringConvertible.new) # => "foo"

This class is not String-convertible (no +to_str+ method):

    class NotStringConvertible; end
    # Raises TypeError (no implicit conversion of NotStringConvertible into String)
    String.new(NotStringConvertible.new)

This class is not String-convertible (method +to_str+ takes arguments):

    class NotStringConvertible
      def to_str(x)
        'foo'
      end
    end
    # Raises ArgumentError (wrong number of arguments (given 0, expected 1))
    String.new(NotStringConvertible.new)

This class is not String-convertible (method +to_str+ returns non-String):

    class NotStringConvertible
      def to_str
        :foo
      end
    end
    # Raises TypeError (can't convert NotStringConvertible to String (NotStringConvertible#to_str gives Symbol))
    String.new(NotStringConvertible.new)
