Init_fiddle_handle(void)
{
    /*
     * Document-class: Fiddle::Handle
     *
     * The Fiddle::Handle is the manner to access the dynamic library
     *
     * == Example
     *
     * === Setup
     *
     *   libc_so = "/lib64/libc.so.6"
     *   => "/lib64/libc.so.6"
     *   @handle = Fiddle::Handle.new(libc_so)
     *   => #<Fiddle::Handle:0x00000000d69ef8>
     *
     * === Setup, with flags
     *
     *   libc_so = "/lib64/libc.so.6"
     *   => "/lib64/libc.so.6"
     *   @handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
     *   => #<Fiddle::Handle:0x00000000d69ef8>
     *
     * See RTLD_LAZY and RTLD_GLOBAL
     *
     * === Addresses to symbols
     *
     *   strcpy_addr = @handle['strcpy']
     *   => 140062278451968
     *
     * or
     *
     *   strcpy_addr = @handle.sym('strcpy')
     *   => 140062278451968
     *
     */
    rb_cHandle = rb_define_class_under(mFiddle, "Handle", rb_cObject);
    rb_define_alloc_func(rb_cHandle, rb_fiddle_handle_s_allocate);
    rb_define_singleton_method(rb_cHandle, "sym", rb_fiddle_handle_s_sym, 1);
    rb_define_singleton_method(rb_cHandle, "[]", rb_fiddle_handle_s_sym,  1);

    /* Document-const: NEXT
     *
     * A predefined pseudo-handle of RTLD_NEXT
     *
     * Which will find the next occurrence of a function in the search order
     * after the current library.
     */
    rb_define_const(rb_cHandle, "NEXT", predefined_fiddle_handle(RTLD_NEXT));

    /* Document-const: DEFAULT
     *
     * A predefined pseudo-handle of RTLD_DEFAULT
     *
     * Which will find the first occurrence of the desired symbol using the
     * default library search order
     */
    rb_define_const(rb_cHandle, "DEFAULT", predefined_fiddle_handle(RTLD_DEFAULT));

    /* Document-const: RTLD_GLOBAL
     *
     * rtld Fiddle::Handle flag.
     *
     * The symbols defined by this library will be made available for symbol
     * resolution of subsequently loaded libraries.
     */
    rb_define_const(rb_cHandle, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));

    /* Document-const: RTLD_LAZY
     *
     * rtld Fiddle::Handle flag.
     *
     * Perform lazy binding.  Only resolve symbols as the code that references
     * them is executed.  If the  symbol is never referenced, then it is never
     * resolved.  (Lazy binding is only performed for function references;
     * references to variables are always immediately bound when the library
     * is loaded.)
     */
    rb_define_const(rb_cHandle, "RTLD_LAZY",   INT2NUM(RTLD_LAZY));

    /* Document-const: RTLD_NOW
     *
     * rtld Fiddle::Handle flag.
     *
     * If this value is specified or the environment variable LD_BIND_NOW is
     * set to a nonempty string, all undefined symbols in the library are
     * resolved before Fiddle.dlopen returns.  If this cannot be done an error
     * is returned.
     */
    rb_define_const(rb_cHandle, "RTLD_NOW",    INT2NUM(RTLD_NOW));

    rb_define_method(rb_cHandle, "initialize", rb_fiddle_handle_initialize, -1);
    rb_define_method(rb_cHandle, "to_i", rb_fiddle_handle_to_i, 0);
    rb_define_method(rb_cHandle, "close", rb_fiddle_handle_close, 0);
    rb_define_method(rb_cHandle, "sym",  rb_fiddle_handle_sym, 1);
    rb_define_method(rb_cHandle, "[]",  rb_fiddle_handle_sym,  1);
    rb_define_method(rb_cHandle, "disable_close", rb_fiddle_handle_disable_close, 0);
    rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);
    rb_define_method(rb_cHandle, "close_enabled?", rb_fiddle_handle_close_enabled_p, 0);
}