Exemplo n.º 1
0
/*
 * Normalizes the @string@.
 *
 * @example
 *   # Normalizes "ABC" with the default normalizer
 *   Groonga::Normalizer.normalize("AbC") # => "abc"
 *
 * @overload normalize(string)
 *   @return [String] The normalized string
 *   @param [String] string The original string
 */
static VALUE
rb_grn_normalizer_s_normalize (VALUE klass, VALUE rb_string)
{
    VALUE rb_context = Qnil;
    VALUE rb_encoded_string;
    VALUE rb_normalized_string;
    grn_ctx *context = NULL;
    grn_obj *grn_string;
    grn_obj *normalizer = GRN_NORMALIZER_AUTO;
    /* TODO: make customizable */
    int flags = GRN_STRING_REMOVE_BLANK;
    const char *normalized_string;
    unsigned int normalized_string_length;

    context = rb_grn_context_ensure(&rb_context);
    rb_encoded_string = rb_grn_context_rb_string_encode(context, rb_string);
    grn_string = grn_string_open(context,
                                 RSTRING_PTR(rb_encoded_string),
                                 RSTRING_LEN(rb_encoded_string),
                                 normalizer,
                                 flags);
    rb_grn_context_check(context, rb_string);
    grn_string_get_normalized(context, grn_string,
                              &normalized_string, &normalized_string_length,
                              NULL);
    rb_normalized_string =
        rb_grn_context_rb_string_new(context,
                                     normalized_string,
                                     normalized_string_length);
    grn_obj_close(context, grn_string);

    return rb_normalized_string;
}
Exemplo n.º 2
0
/*
 * Executes a prefix-search operation. Prefix-serach operation checks
 * whether `text` starts with `prefix` or not.
 *
 * @example Executes prefix-search operations with the default context
 *   Groonga::Operator::PREFIX.exec("Hello Rroonga", "Hello")   # => true
 *   Groonga::Operator::PREFIX.exec("Hello Rroonga", "Rroonga") # => false
 *
 * @example Executes prefix-search operations with the specified context
 *   context = Groonga::Context.new
 *   Groonga::Operator::PREFIX.exec("Hello Rroonga", "Hello",
 *                                  :context => context) # => true
 *   Groonga::Operator::PREFIX.exec("Hello Rroonga", "Rroonga",
 *                                  :context => context) # => false
 *
 * @overload exec(text, prefix, options={})
 *   @param text [String] The text to be searched.
 *   @param prefix [String] The prefix to be contained.
 *   @param options [::Hash] The options.
 *   @option options [Groonga::Context] (Groonga::Context.default)
 *      The context to executes the operation.
 *   @return [Boolean] `true` if `text` starts with `prefix`, `false`
 *      otherwise.
 */
static VALUE
rb_grn_prefix_operator_exec (int argc, VALUE *argv, VALUE self)
{
    grn_bool have_prefix;
    VALUE rb_text;
    VALUE rb_prefix;
    VALUE rb_options;
    VALUE rb_context;
    grn_ctx *context;
    grn_obj text;
    grn_obj prefix;

    rb_scan_args(argc, argv, "21", &rb_text, &rb_prefix, &rb_options);

    rb_grn_scan_options(rb_options,
                        "context", &rb_context,
                        NULL);
    context = rb_grn_context_ensure(&rb_context);

    GRN_VOID_INIT(&text);
    GRN_VOID_INIT(&prefix);
    RVAL2GRNBULK(rb_text, context, &text);
    RVAL2GRNBULK(rb_prefix, context, &prefix);
    have_prefix = grn_operator_exec_prefix(context, &text, &prefix);
    GRN_OBJ_FIN(context, &text);
    GRN_OBJ_FIN(context, &prefix);

    return CBOOL2RVAL(have_prefix);
}
Exemplo n.º 3
0
/*
 * 既存のデータベースを開く。ブロックを指定した場合はブロッ
 * クに開いたデータベースを渡し、ブロックを抜けるときに閉じ
 * る。
 *
 * @overload new(path, options=nil)
 *   @!macro [new] database.new.arguments
 *     @param options [::Hash] The name and value
 *       pairs. Omitted names are initialized as the default value.
 *     @option options :context (Groonga::Context.default)
 *       データベースを結びつけるコンテキスト。省略すると
 *       {Groonga::Context.default} を利用する。
 *   @!macro database.new.arguments
 *   @return [Groonga::Database]
 * @overload new(path, options=nil)
 *   @!macro database.new.arguments
 *   @yield [database]
 *   @yieldparam [Groonga::Database] database 開いたデータベース
 */
static VALUE
rb_grn_database_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *old_database, *database;
    const char *path;
    VALUE rb_path, options, rb_context;

    rb_scan_args(argc, argv, "11", &rb_path, &options);

    path = StringValuePtr(rb_path);
    rb_grn_scan_options(options,
                        "context", &rb_context,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    old_database = grn_ctx_db(context);
    if (old_database)
        grn_obj_unlink(context, old_database);
    reset_floating_objects(rb_context);
    database = grn_db_open(context, path);
    rb_grn_object_assign(Qnil, self, rb_context, context, database);
    rb_grn_context_check(context, self);

    rb_iv_set(self, "@context", rb_context);
    if (!NIL_P(rb_context))
        rb_iv_set(rb_context, "database", self);

    return Qnil;
}
Exemplo n.º 4
0
/*
 * Gets a configuration value for key.
 *
 * @overload config[](key)
 *   @param [String] key The key.
 *   @return [String, nil] The value associated with `key`.
 *
 * @since 5.0.9
 */
static VALUE
rb_grn_config_get (VALUE self, VALUE rb_key)
{
    VALUE rb_context;
    VALUE rb_value;
    grn_ctx *context;
    const char *key;
    int key_size;
    const char *value;
    uint32_t value_size;

    rb_context = rb_iv_get(self, "@context");
    context = rb_grn_context_ensure(&rb_context);

    rb_key = rb_grn_convert_to_string(rb_key);
    key = RSTRING_PTR(rb_key);
    key_size = RSTRING_LEN(rb_key);

    {
        grn_rc rc;
        rc = grn_config_get(context,
                            key, key_size,
                            &value, &value_size);
        rb_grn_context_check(context, self);
        rb_grn_rc_check(rc, self);
    }

    if (value_size == 0) {
        rb_value = Qnil;
    } else {
        rb_value = rb_grn_context_rb_string_new(context, value, value_size);
    }

    return rb_value;
}
Exemplo n.º 5
0
/*
 * Sets a configuration key and value pair.
 *
 * @overload config[]=(key, value)
 *   @param [String] key The key.
 *   @param [String] value The value to be assigned.
 *   @return [String] `value`.
 */
static VALUE
rb_grn_config_set (VALUE self, VALUE rb_key, VALUE rb_value)
{
    VALUE rb_value_original = rb_value;
    VALUE rb_context;
    grn_ctx *context;
    const char *key;
    int key_size;
    const char *value;
    int value_size;

    rb_context = rb_iv_get(self, "@context");
    context = rb_grn_context_ensure(&rb_context);

    rb_key = rb_grn_convert_to_string(rb_key);
    key = RSTRING_PTR(rb_key);
    key_size = RSTRING_LEN(rb_key);

    rb_value = rb_grn_convert_to_string(rb_value);
    value = RSTRING_PTR(rb_value);
    value_size = RSTRING_LEN(rb_value);

    {
        grn_rc rc;
        rc = grn_config_set(context,
                            key, key_size,
                            value, value_size);
        rb_grn_context_check(context, self);
        rb_grn_rc_check(rc, self);
    }

    return rb_value_original;
}
Exemplo n.º 6
0
/*
 * Executes a less operation.
 *
 * @example Executes less operations with the default context
 *   Groonga::Operator::LESS.exec(1, 2) # => true
 *   Groonga::Operator::LESS.exec(2, 1) # => false
 *
 * @example Executes less operations with the specified context
 *   context = Groonga::Context.new
 *   Groonga::Operator::LESS.exec(1, 2,
 *                                :context => context) # => true
 *   Groonga::Operator::LESS.exec(2, 1,
 *                                :context => context) # => false
 *
 * @overload exec(x, y, options={})
 *   @param x [::Object] The left hand side value.
 *   @param y [::Object] The right hand side value.
 *   @param options [::Hash] The options.
 *   @option options [Groonga::Context] (Groonga::Context.default)
 *      The context to executes the operation.
 *   @return [Boolean] `true` if `x` is less than `y`, `false`
 *      otherwise.
 */
static VALUE
rb_grn_less_operator_exec (int argc, VALUE *argv, VALUE self)
{
    grn_bool less;
    VALUE rb_x;
    VALUE rb_y;
    VALUE rb_options;
    VALUE rb_context;
    grn_ctx *context;
    grn_obj x;
    grn_obj y;

    rb_scan_args(argc, argv, "21", &rb_x, &rb_y, &rb_options);

    rb_grn_scan_options(rb_options,
                        "context", &rb_context,
                        NULL);
    context = rb_grn_context_ensure(&rb_context);

    GRN_VOID_INIT(&x);
    GRN_VOID_INIT(&y);
    RVAL2GRNBULK(rb_x, context, &x);
    RVAL2GRNBULK(rb_y, context, &y);
    less = grn_operator_exec_less(context, &x, &y);
    GRN_OBJ_FIN(context, &x);
    GRN_OBJ_FIN(context, &y);

    return CBOOL2RVAL(less);
}
Exemplo n.º 7
0
static VALUE
rb_grn_expression_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_obj *expression;
    VALUE options, rb_context, rb_name;
    char *name = NULL;
    unsigned name_size = 0;

    rb_scan_args(argc, argv, "01", &options);
    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "name", &rb_name,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_name)) {
        name = StringValuePtr(rb_name);
        name_size = RSTRING_LEN(rb_name);
    }

    expression = grn_expr_create(context, name, name_size);
    rb_grn_context_check(context, self);
    rb_grn_object_assign(Qnil, self, rb_context, context, expression);
    rb_grn_context_register_floating_object(DATA_PTR(self));

    rb_iv_set(self, "@objects", rb_ary_new());

    return Qnil;
}
Exemplo n.º 8
0
/*
 * @overload register(event_source_name, options={})
 *
 *   Registers Windows Event Log based logger that uses
 *   `event_source_name` as event source name.
 *
 *   @param event_source_name [String] The event source name.
 *   @param options [::Hash]
 *   @option options :context [Groonga::Context] (Groonga::Context.default)
 *     The context to be set logger.
 *
 *   @return [void]
 *
 *   @since 5.0.5
 */
static VALUE
rb_grn_windows_event_logger_s_register (int argc,
                                        VALUE *argv,
                                        VALUE klass)
{
    VALUE rb_event_source_name;
    VALUE rb_options;
    VALUE rb_context;
    const char *event_source_name;
    grn_ctx *context;
    grn_rc rc;

    rb_scan_args(argc, argv, "11", &rb_event_source_name, &rb_options);
    rb_event_source_name = rb_grn_convert_to_string(rb_event_source_name);
    event_source_name = StringValueCStr(rb_event_source_name);

    rb_grn_scan_options(rb_options,
                        "context", &rb_context,
                        NULL);
    context = rb_grn_context_ensure(&rb_context);

    rc = grn_windows_event_logger_set(context, event_source_name);
    rb_grn_context_check(context, rb_event_source_name);
    rb_grn_rc_check(rc, rb_event_source_name);

    return Qnil;
}
Exemplo n.º 9
0
/*
 * 名前が _name_ の型を作成する。
 *
 * @overload new(name, options={})
 *   @param name [String] 作成する型の名前
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value
 *   @option options [Symbol] :type (:variable)
 *     :integer(符号付き整数)、:int(:integerの省略
 *     形)、:unsigned_integer(符号なし整
 *     数)、:uint(:unsigned_integerの省略形)、:float(浮動小数点
 *     数)、:variable(可変長文字列)のいずれかを指定する。省略した場
 *     合は:variableを指定したものと扱う。
 *     :variableを指定した場合は必ず +:size+ を指定しなければいけない。
 *   @option options [Context] :context
 *     型の作成時に利用するGroonga::Contextを指定する。省略すると
 *     Groonga::Context.defaultを用いる。
 *   @option options [Integer] :size
 *     +:option+ が:variableの場合は最大長、それ以外の場合は長さを
 *     指定する(単位:byte)。
 */
static VALUE
rb_grn_type_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context;
    grn_obj *type;
    const char *name = NULL;
    unsigned name_size, size = 0;
    grn_obj_flags flags = 0;
    VALUE rb_name, options, rb_context, rb_type, rb_size;

    rb_scan_args(argc, argv, "11", &rb_name, &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "type", &rb_type,
                        "size", &rb_size,
                        NULL);

    name = StringValuePtr(rb_name);
    name_size = RSTRING_LEN(rb_name);

    context = rb_grn_context_ensure(&rb_context);

    if (NIL_P(rb_type) ||
        rb_grn_equal_option(rb_type, "variable")) {
        flags = GRN_OBJ_KEY_VAR_SIZE;
    } else if (rb_grn_equal_option(rb_type, "integer") ||
               rb_grn_equal_option(rb_type, "int")) {
        flags = GRN_OBJ_KEY_INT;
        size = sizeof(int);
    } else if (rb_grn_equal_option(rb_type, "unsigned_integer") ||
               rb_grn_equal_option(rb_type, "uint")) {
        flags = GRN_OBJ_KEY_UINT;
        size = sizeof(unsigned int);
    } else if (rb_grn_equal_option(rb_type, "float")) {
        flags = GRN_OBJ_KEY_FLOAT;
        size = sizeof(double);
    } else {
        rb_raise(rb_eArgError,
                 ":type should be one of "
                 "[:integer, :int, :unsigned_integer, :uint, "
                 ":float, :variable]: %s",
                 rb_grn_inspect(options));
    }

    if (NIL_P(rb_size)) {
        if (size == 0)
            rb_raise(rb_eArgError, "size is missing: %s",
                     rb_grn_inspect(options));
    } else {
        size = NUM2UINT(rb_size);
    }

    type = grn_type_create(context, name, name_size, flags, size);
    rb_grn_object_assign(Qnil, self, rb_context, context, type);
    rb_grn_context_check(context, rb_ary_new4(argc, argv));

    return Qnil;
}
Exemplo n.º 10
0
/*
 * call-seq:
 *   Groonga::Array.create(options={})                -> Groonga::Array
 *   Groonga::Array.create(options={}) {|table| ... }
 *
 * キーのないテーブルを生成する。ブロックを指定すると、そのブ
 * ロックに生成したテーブルが渡され、ブロックを抜けると自動的
 * にテーブルが破棄される。
 *
 * @example
 *   #無名一時テーブルを生成する。
 *   Groonga::Array.create
 *
 *   #無名永続テーブルを生成する。
 *   Groonga::Array.create(:path => "/tmp/array.grn")
 *
 *   #名前付き永続テーブルを生成する。ただし、ファイル名は気にしない。
 *   Groonga::Array.create(:name => "Bookmarks",
 *                         :persistent => true)
 *
 *   #それぞれのレコードに512バイトの値を格納できる無名一時テーブルを生成する。
 *   Groonga::Array.create(:value => 512)
 *
 * @param [::Hash] options The name and value
 *   pairs. Omitted names are initialized as the default value.
 * @option options [Grrnga::Context] :context (Groonga::Context.default) The context
 *   テーブルが利用するGrrnga::Context
 * @option options :name The name
 *   テーブルの名前。名前をつけると、Groonga::Context#[]に名
 *   前を指定してテーブルを取得することができる。省略すると
 *   無名テーブルになり、テーブルIDでのみ取得できる。
 * @option options :path The path
 *   テーブルを保存するパス。パスを指定すると永続テーブルとな
 *   り、プロセス終了後もレコードは保持される。次回起動時に
 *   Groonga::Context#[]で保存されたレコードを利用することが
 *   できる。省略すると一時テーブルになり、プロセスが終了する
 *   とレコードは破棄される。
 * @option options :persistent The persistent
 *   +true+ を指定すると永続テーブルとなる。 +path+ を省略した
 *   場合は自動的にパスが付加される。 +:context+ で指定した
 *   Groonga::Contextに結びついているデータベースが一時デー
 *   タベースの場合は例外が発生する。
 * @option options :value_type (nil) The value_type
 *   値の型を指定する。省略すると値のための領域を確保しない。
 *   値を保存したい場合は必ず指定すること。
 *   参考: Groonga::Type.new
 * @option options [Groonga::Record#n_sub_records] :sub_records The sub_records
 *   +true+ を指定すると#groupでグループ化したときに、
 *   Groonga::Record#n_sub_recordsでグループに含まれるレコー
 *   ドの件数を取得できる。
 */
static VALUE
rb_grn_array_s_create (int argc, VALUE *argv, VALUE klass)
{
    grn_ctx *context = NULL;
    grn_obj *value_type = NULL, *table;
    const char *name = NULL, *path = NULL;
    unsigned name_size = 0;
    grn_obj_flags flags = GRN_OBJ_TABLE_NO_KEY;
    VALUE rb_table;
    VALUE options, rb_context, rb_name, rb_path, rb_persistent;
    VALUE rb_value_type, rb_sub_records;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
			"context", &rb_context,
			"name", &rb_name,
                        "path", &rb_path,
			"persistent", &rb_persistent,
			"value_type", &rb_value_type,
			"sub_records", &rb_sub_records,
			NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_name)) {
        name = StringValuePtr(rb_name);
	name_size = RSTRING_LEN(rb_name);
	flags |= GRN_OBJ_PERSISTENT;
    }

    if (!NIL_P(rb_path)) {
        path = StringValueCStr(rb_path);
	flags |= GRN_OBJ_PERSISTENT;
    }

    if (RVAL2CBOOL(rb_persistent))
	flags |= GRN_OBJ_PERSISTENT;

    if (!NIL_P(rb_value_type))
	value_type = RVAL2GRNOBJECT(rb_value_type, &context);

    if (RVAL2CBOOL(rb_sub_records))
	flags |= GRN_OBJ_WITH_SUBREC;

    table = grn_table_create(context, name, name_size, path,
			     flags, NULL, value_type);
    if (!table)
	rb_grn_context_check(context, rb_ary_new4(argc, argv));
    rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE);
    rb_grn_context_check(context, rb_table);
    rb_iv_set(rb_table, "@context", rb_context);

    if (rb_block_given_p())
        return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table);
    else
        return rb_table;
}
Exemplo n.º 11
0
/*
 * @overload max_level=(max_level)
 *   Sets the max level of the current logger.
 *
 *   @param max_level [Symbol, String] The max level.
 *
 *   @return [void]
 *
 * @since 5.0.5
 */
static VALUE
rb_grn_logger_s_set_max_level (VALUE klass, VALUE rb_max_level)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;

    context = rb_grn_context_ensure(&rb_context);
    grn_logger_set_max_level(context, RVAL2GRNLOGLEVEL(rb_max_level));

    return Qnil;
}
Exemplo n.º 12
0
/*
 * Sends reopen request to the current query logger. It is useful for
 * rotating log file.
 *
 * @overload reopen
 * @return void
 */
static VALUE
rb_grn_query_logger_s_reopen (VALUE klass)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;

    context = rb_grn_context_ensure(&rb_context);
    grn_query_logger_reopen(context);
    rb_grn_context_check(context, klass);

    return Qnil;
}
Exemplo n.º 13
0
/*
 * @overload max_level
 *   @return [Symbol] The max level of the current logger.
 *
 * @since 5.0.5
 */
static VALUE
rb_grn_logger_s_get_max_level (VALUE klass)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;
    grn_log_level max_level;

    context = rb_grn_context_ensure(&rb_context);
    max_level = grn_logger_get_max_level(context);

    return GRNLOGLEVEL2RVAL(max_level);
}
Exemplo n.º 14
0
static VALUE
rb_grn_logger_s_reopen_with_related_object (VALUE klass, VALUE related_object)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;

    context = rb_grn_context_ensure(&rb_context);
    rb_grn_logger_reset_with_error_check(klass, context);
    grn_logger_reopen(context);
    rb_grn_context_check(context, related_object);

    return Qnil;
}
Exemplo n.º 15
0
/*
 * call-seq:
 *   Groonga::View.create(options={})                -> Groonga::View
 *   Groonga::View.create(options={}) {|table| ... }
 *
 * 複数のテーブルを1つのテーブルとして扱う仮想的なテーブル
 * (ビュー)を生成する。ブロックを指定すると、そのブロック
 * に生成したテーブルが渡され、ブロックを抜けると自動的にテー
 * ブルが破棄される。
 *
 * ビューにテーブルを追加するときはGroonga::View#add_tableを
 * 使う。
 *
 * _options_に指定可能な値は以下の通り。
 *
 * [+:context+]
 *   ビューが利用するGroonga::Context。省略すると
 *   Groonga::Context.defaultを用いる。
 *
 * [+:name+]
 *   ビューの名前。名前をつけると、Groonga::Context#[]に名
 *   前を指定してビューを取得することができる。省略すると
 *   無名ビューになり、ビューIDでのみ取得できる。
 *
 * [+:path+]
 *   ビューを保存するパス。パスを指定すると永続ビューとな
 *   り、プロセス終了後もレコードは保持される。次回起動時に
 *   Groonga::View.openで保存されたビューを利用することが
 *   できる。省略すると一時ビューになり、プロセスが終了する
 *   とビューは破棄される。
 *
 * [+:persistent+]
 *   +true+を指定すると永続ビューとなる。+path+を省略した
 *   場合は自動的にパスが付加される。+:context+で指定した
 *   Groonga::Contextに結びついているデータベースが一時デー
 *   タベースの場合は例外が発生する。
 *
 * 使用例:
 *
 * 無名一時ビューを生成する。
 *   Groonga::View.create
 *
 * 無名永続ブーを生成する。
 *   Groonga::View.create(:path => "/tmp/view.grn")
 *
 * 名前付き永続ビューを生成する。ただし、ファイル名は気に
 * しない。
 *   Groonga::View.create(:name => "Entries",
 *                        :persistent => true)
 *
 * +Users+テーブルと+Dogs+テーブルを横断検索するための
 * るビューを生成する。
 *   entries = Groonga::View.create(:name => "Entries")
 *   entries.add_table("Users")
 *   entries.add_table("Dogs")
 */
static VALUE
rb_grn_view_s_create (int argc, VALUE *argv, VALUE klass)
{
    grn_ctx *context;
    grn_obj *table;
    const char *name = NULL, *path = NULL;
    unsigned name_size = 0;
    grn_obj_flags flags = GRN_TABLE_VIEW;
    VALUE rb_table;
    VALUE options, rb_context, rb_name, rb_path, rb_persistent;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "name", &rb_name,
                        "path", &rb_path,
                        "persistent", &rb_persistent,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_name)) {
        name = StringValuePtr(rb_name);
        name_size = RSTRING_LEN(rb_name);
        flags |= GRN_OBJ_PERSISTENT;
    }

    if (!NIL_P(rb_path)) {
        path = StringValueCStr(rb_path);
        flags |= GRN_OBJ_PERSISTENT;
    }

    if (RVAL2CBOOL(rb_persistent))
        flags |= GRN_OBJ_PERSISTENT;

    table = grn_table_create(context, name, name_size, path, flags, NULL, NULL);
    if (!table)
        rb_grn_context_check(context, rb_ary_new4(argc, argv));
    rb_table = GRNOBJECT2RVAL(klass, context, table, RB_GRN_TRUE);

    if (rb_block_given_p())
        return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table);
    else
        return rb_table;
}
Exemplo n.º 16
0
/*
 * 新しくデータベースを作成する。
 * _options_ にはハッシュでオプションを指定する。
 *
 * @example
 *   # 一時データベースを作成:
 *   Groonga::Database.create
 *
 *   # 永続データベースを作成:
 *   Groonga::Database.create(:path => "/tmp/db.groonga")
 *
 * @overload create(options=nil)
 *   @return [Groonga::Database] 作成されたデータベースを返す。
 *   @param [::Hash] options The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :path
 *     データベースを保存するパス。省略すると一時データベース
 *     となる。
 *   @option options :context (Groonga::Context.default)
 *     データベースを結びつけるコンテキスト。省略すると
 *     {Groonga::Context.default} を利用する。
 */
static VALUE
rb_grn_database_s_create (int argc, VALUE *argv, VALUE klass)
{
    grn_ctx *context;
    grn_obj *old_database, *database;
    grn_db_create_optarg create_args;
    const char *path = NULL;
    VALUE rb_database;
    VALUE rb_path, options, rb_context, builtin_type_names;
    grn_bool owner;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "path", &rb_path,
                        "context", &rb_context,
                        "builtin_type_names", &builtin_type_names,
                        NULL);

    if (!NIL_P(rb_path))
        path = StringValuePtr(rb_path);
    context = rb_grn_context_ensure(&rb_context);

    create_args.builtin_type_names = NULL;
    create_args.n_builtin_type_names = 0;

    old_database = grn_ctx_db(context);
    if (old_database)
        grn_obj_unlink(context, old_database);
    reset_floating_objects(rb_context);
    database = grn_db_create(context, path, &create_args);
    rb_grn_context_check(context, rb_ary_new_from_values(argc, argv));
    owner = (context->flags & GRN_CTX_PER_DB) ? GRN_FALSE : GRN_TRUE;
    rb_database = GRNOBJECT2RVAL(klass, context, database, owner);
    rb_iv_set(rb_database, "@context", rb_context);
    if (!NIL_P(rb_context))
        rb_iv_set(rb_context, "database", rb_database);
    rb_grn_context_check(context, rb_ary_new_from_values(argc, argv));

    if (rb_block_given_p())
        return rb_ensure(rb_yield, rb_database,
                         rb_grn_database_close, rb_database);
    else
        return rb_database;
}
Exemplo n.º 17
0
static VALUE
rb_grn_query_logger_s_unregister (VALUE klass)
{
    VALUE current_logger;
    VALUE rb_context = Qnil;
    grn_ctx *context;

    current_logger = rb_cv_get(klass, "@@current_logger");
    if (NIL_P(current_logger))
        return Qnil;

    rb_cv_set(klass, "@@current_logger", Qnil);

    context = rb_grn_context_ensure(&rb_context);
    grn_query_logger_set(context, NULL);
    rb_grn_context_check(context, klass);

    return Qnil;
}
Exemplo n.º 18
0
/*
 * Unregisters the specified request.
 *
 * @example Unregister a request by ID
 *   request_id = "request-29"
 *   Groonga::RequestCanceler.unregister(request_id)
 *
 * @overload unregister(request_id)
 *   @param request_id [String] The ID of request to be unregistered.
 *   @return [void]
 *
 * @since 6.0.2
 */
static VALUE
rb_grn_request_canceler_s_unregister (int argc, VALUE *argv, VALUE module)
{
    VALUE rb_request_id;
    VALUE rb_options;
    VALUE rb_context;
    const char *request_id;
    unsigned int request_id_size;
    grn_ctx *context;

    rb_scan_args(argc, argv, "11", &rb_request_id, &rb_options);
    rb_grn_scan_options(rb_options,
                        "context", &rb_context,
                        NULL);
    context = rb_grn_context_ensure(&rb_context);

    request_id = StringValuePtr(rb_request_id);
    request_id_size = RSTRING_LEN(rb_request_id);
    grn_request_canceler_unregister(context, request_id, request_id_size);

    return Qnil;
}
Exemplo n.º 19
0
/*
 * Logs a message.
 *
 * @overload log(message, options={})
 *   @param message [String] The log message.
 *   @param options [::Hash]
 *   @option options :context [Groonga::Context] (Groonga::Context.default)
 *     The context for the message.
 *   @option options :flags [nil, Integer, String] (0)
 *     The flags for the message.
 *
 *     The flags are passed to query logger. You can custom query
 *     logger behavior by the flags. For example, you can omit elapsed
 *     time by passing `Groonga::QueryLogger::COMMAND` flag or
 *     `Groonga::QueryLogger::DESTINATION`.
 *
 *     If `:flags` value is `String`, parsed by
 *     {Groonga::QueryLogger.parse}.
 *
 *     `nil` equals to `0`.
 *   @option options :mark [String] ("")
 *     The mark for the message.
 *
 *     Normally, a character is used as a mark such as `":"`, `"<"` and `">"`.
 *   @return [void]
 *
 * @since 5.0.2
 */
static VALUE
rb_grn_query_logger_s_log (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_message;
    const char *message;
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_flags;
    unsigned int flags = GRN_QUERY_LOG_NONE;
    VALUE rb_mark;
    const char *mark = "";
    VALUE rb_options;

    rb_scan_args(argc, argv, "11", &rb_message, &rb_options);

    message = StringValueCStr(rb_message);

    rb_grn_scan_options(rb_options,
                        "context", &rb_context,
                        "flags",   &rb_flags,
                        "mark",    &rb_mark,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_flags)) {
        flags = rb_funcall(mGrnQueryLoggerFlags, id_parse, 2,
                           rb_flags, UINT2NUM(flags));
    }
    if (!NIL_P(rb_mark)) {
        mark = StringValueCStr(rb_mark);
    }

    grn_query_logger_put(context, flags, mark, "%s", message);

    return Qnil;
}
Exemplo n.º 20
0
/*
 * call-seq:
 *   Groonga::Snippet.new(options={})
 *
 * スニペットを作成する。_options_に指定可能な値は以下の通
 * り。
 *
 * [+:context+]
 *   スキーマ作成時に使用するGroonga::Contextを指定する。
 *   省略した場合はGroonga::Context.defaultを使用する。
 *
 * [+:normalize+]
 *   キーワード文字列・スニペット元の文字列を正規化するかど
 *   うか。省略した場合は+false+で正規化しない。
 *
 * [+:skip_leading_spaces+]
 *   先頭の空白を無視するかどうか。省略した場合は+false+で無
 *   視しない。
 *
 * [+:width+]
 *   スニペット文字列の長さ。省略した場合は100文字。
 *
 * [+:max_results+]
 *   生成するスニペットの最大数。省略した場合は3。
 *
 * [+:html_escape+]
 *   スニペット内の+<+, +>+, +&+, +"+をHTMLエスケープするか
 *   どうか。省略した場合は+false+で、HTMLエスケープしない。
 *
 * [+:default_open_tag+]
 *   デフォルトの開始タグ。省略した場合は""(空文字列)
 *
 * [+:default_close_tag+]
 *   デフォルトの終了タグ。省略した場合は""(空文字列)
 */
static VALUE
rb_grn_snippet_initialize (int argc, VALUE *argv, VALUE self)
{
    RbGrnSnippet *rb_grn_snippet;
    grn_ctx *context = NULL;
    grn_snip *snippet = NULL;
    VALUE options;
    VALUE rb_context, rb_normalize, rb_skip_leading_spaces;
    VALUE rb_width, rb_max_results, rb_default_open_tag, rb_default_close_tag;
    VALUE rb_html_escape;
    int flags = GRN_SNIP_COPY_TAG;
    unsigned int width = 100;
    unsigned int max_results = 3;
    char *default_open_tag = NULL;
    unsigned int default_open_tag_length = 0;
    char *default_close_tag = NULL;
    unsigned int default_close_tag_length = 0;
    grn_snip_mapping *mapping = NULL;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "normalize", &rb_normalize,
                        "skip_leading_spaces", &rb_skip_leading_spaces,
                        "width", &rb_width,
                        "max_results", &rb_max_results,
                        "default_open_tag", &rb_default_open_tag,
                        "default_close_tag", &rb_default_close_tag,
                        "html_escape", &rb_html_escape,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (RVAL2CBOOL(rb_normalize))
        flags |= GRN_SNIP_NORMALIZE;
    if (RVAL2CBOOL(rb_skip_leading_spaces))
        flags |= GRN_SNIP_SKIP_LEADING_SPACES;

    if (!NIL_P(rb_width))
        width = NUM2UINT(rb_width);

    if (!NIL_P(rb_max_results))
        max_results = NUM2UINT(rb_max_results);

    if (!NIL_P(rb_default_open_tag)) {
        default_open_tag = StringValuePtr(rb_default_open_tag);
        default_open_tag_length = RSTRING_LEN(rb_default_open_tag);
    }

    if (!NIL_P(rb_default_close_tag)) {
        default_close_tag = StringValuePtr(rb_default_close_tag);
        default_close_tag_length = RSTRING_LEN(rb_default_close_tag);
    }

    if (RVAL2CBOOL(rb_html_escape))
        mapping = (grn_snip_mapping *)-1;

    snippet = grn_snip_open(context, flags, width, max_results,
                            default_open_tag, default_open_tag_length,
                            default_close_tag, default_close_tag_length,
                            mapping);
    rb_grn_context_check(context, rb_ary_new4(argc, argv));

    rb_grn_snippet = ALLOC(RbGrnSnippet);
    DATA_PTR(self) = rb_grn_snippet;
    rb_grn_snippet->context = context;
    rb_grn_snippet->snippet = snippet;
    rb_grn_snippet->owner = RB_GRN_TRUE;

    rb_iv_set(self, "@context", rb_context);

    return Qnil;
}
Exemplo n.º 21
0
/*
 * groongaがログを出力する度に呼び出されるブロックを登録する。
 *
 * @overload register(options={})
 *   @yield [event, level, time, title, message, location]
 *     _event_ と _level_ はSymbol、それ以外は全て文字列で渡される。
 *     _event_ と _level_ 以外
 *     の4つについては _options_ で +false+ を指定することでブロックに
 *     渡さないようにすることができ、その場合は空文字列が実際には渡される。
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :max_level (:notice)
 *     ログのレベルを +:none+ ,  +:emergency+ ,  +:alert+ ,
 *     +:critical+ , +:error+ , +:warning+ , +:notice+ , +:info+ ,
 *     +:debug+ ,  +:dump+ のいずれかで指定する。それより重要度が
 *     低いログはブロックに渡されなくなる。デフォルトでは +:notice+ 。
 *   @option options :time
 *     ログが出力された時間をブロックに渡したいなら +true+ を指
 *     定する。デフォルトでは渡す。
 *   @option options :title
 *     ログのタイトルをブロックに渡したいなら +true+ を指定す
 *     る。デフォルトでは渡す。
 *     (FIXME: groongaで実装されていない?)
 *   @option options :message
 *     ログのメッセージをブロックに渡したいなら +true+ を指定す
 *     る。デフォルトでは渡す。
 *   @option options :location
 *     ログの発生元のプロセスIDとgroongaのソースコードのファイ
 *     ル名、行番号、関数名をブロックに渡したいなら +true+ を指
 *     定する。デフォルトでは渡す。
 */
static VALUE
rb_grn_logger_s_register (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_logger, rb_callback;
    VALUE rb_options, rb_max_level;
    VALUE rb_time, rb_title, rb_message, rb_location;
    VALUE rb_flags;
    grn_log_level max_level = GRN_LOG_DEFAULT_LEVEL;
    int flags = 0;

    rb_scan_args(argc, argv, "02&", &rb_logger, &rb_options, &rb_callback);

    if (rb_block_given_p()) {
        if (!NIL_P(rb_logger)) {
            rb_options = rb_logger;
        }
        rb_logger = rb_funcall(rb_cGrnCallbackLogger, id_new, 1, rb_callback);
    }

    rb_grn_scan_options(rb_options,
                        "max_level", &rb_max_level,
                        "time",      &rb_time,
                        "title",     &rb_title,
                        "message",   &rb_message,
                        "location",  &rb_location,
                        "flags",     &rb_flags,
                        NULL);
    if (!NIL_P(rb_max_level)) {
        max_level = RVAL2GRNLOGLEVEL(rb_max_level);
    }

    if (NIL_P(rb_time) || CBOOL2RVAL(rb_time)) {
        flags |= GRN_LOG_TIME;
    }
    if (NIL_P(rb_title) || CBOOL2RVAL(rb_title)) {
        flags |= GRN_LOG_TITLE;
    }
    if (NIL_P(rb_message) || CBOOL2RVAL(rb_message)) {
        flags |= GRN_LOG_MESSAGE;
    }
    if (NIL_P(rb_location) || CBOOL2RVAL(rb_location)) {
        flags |= GRN_LOG_LOCATION;
    }
    if (!NIL_P(rb_flags)) {
        flags = rb_funcall(rb_mGrnLoggerFlags, id_parse, 2,
                           INT2NUM(flags), rb_flags);
    }

    rb_grn_logger.max_level = max_level;
    rb_grn_logger.flags = flags;
    rb_grn_logger.user_data = (void *)rb_logger;

    context = rb_grn_context_ensure(&rb_context);
    grn_logger_set(context, &rb_grn_logger);
    rb_grn_context_check(context, rb_logger);
    rb_cv_set(klass, "@@current_logger", rb_logger);

    return Qnil;
}
Exemplo n.º 22
0
/*
 * Registers a query logger or a callback that is called when a
 * query log event is emitted.
 *
 * @overload register(logger, options={})
 *   @param logger [#log, #reopen, #fin] The query logger. It is easy to
 *     inherit {QueryLogger}.
 *
 *   @!macro query-logger.register.options
 *     @param options [::Hash] The options.
 *     @option options [Symbol, String, Integer or nil] :flags (:default)
 *       Flags describe what query log should be logged.
 *
 *       If `flags` is String, it is parsed by {QueryLogger::Flags.parse}.
 *
 *   @return void
 *
 * @overload register(options={})
 *   @yield [action, flag, timestamp, info, message]
 *     ...
 *
 *   @!macro query-logger.register.options
 */
static VALUE
rb_grn_query_logger_s_register (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_logger, rb_callback;
    VALUE rb_options, rb_command, rb_result_code, rb_destination;
    VALUE rb_cache, rb_size, rb_score, rb_default, rb_all, rb_flags;
    unsigned int flags = GRN_QUERY_LOG_NONE;

    rb_scan_args(argc, argv, "02&", &rb_logger, &rb_options, &rb_callback);

    if (rb_block_given_p()) {
        rb_logger = rb_funcall(cGrnCallbackQueryLogger, id_new, 1, rb_callback);
    }

    rb_grn_scan_options(rb_options,
                        "command",     &rb_command,
                        "result_code", &rb_result_code,
                        "destination", &rb_destination,
                        "cache",       &rb_cache,
                        "size",        &rb_size,
                        "score",       &rb_score,
                        "default",     &rb_default,
                        "all",         &rb_all,
                        "flags",       &rb_flags,
                        NULL);

    if (RVAL2CBOOL(rb_command)) {
        flags |= GRN_QUERY_LOG_COMMAND;
    }
    if (RVAL2CBOOL(rb_result_code)) {
        flags |= GRN_QUERY_LOG_RESULT_CODE;
    }
    if (RVAL2CBOOL(rb_destination)) {
        flags |= GRN_QUERY_LOG_DESTINATION;
    }
    if (RVAL2CBOOL(rb_cache)) {
        flags |= GRN_QUERY_LOG_CACHE;
    }
    if (RVAL2CBOOL(rb_size)) {
        flags |= GRN_QUERY_LOG_SIZE;
    }
    if (RVAL2CBOOL(rb_score)) {
        flags |= GRN_QUERY_LOG_SCORE;
    }
    if (RVAL2CBOOL(rb_default)) {
        flags |= GRN_QUERY_LOG_DEFAULT;
    }
    if (RVAL2CBOOL(rb_all)) {
        flags |= GRN_QUERY_LOG_ALL;
    }
    if (!NIL_P(rb_flags)) {
        flags = rb_funcall(mGrnQueryLoggerFlags, id_parse, 2,
                           rb_flags, UINT2NUM(flags));
    }

    rb_grn_query_logger.flags     = flags;
    rb_grn_query_logger.user_data = (void *)rb_logger;

    context = rb_grn_context_ensure(&rb_context);
    grn_query_logger_set(context, &rb_grn_query_logger);
    rb_grn_context_check(context, rb_logger);
    rb_cv_set(klass, "@@current_logger", rb_logger);

    return Qnil;
}
Exemplo n.º 23
0
/*
 * Logs a message.
 *
 * @overload log(message, options={})
 *   @param message [String] The log message.
 *   @param options [::Hash]
 *   @option options :context [Groonga::Context] (Groonga::Context.default)
 *     The context for the message.
 *   @option options :level [nil, :none, :emergency, :alert, :critical,
 *     :error, :warning, :notice, :info, :debug, :dump] (:notice)
 *     The level for the message.
 *
 *     `nil` equals to `:notice`.
 *   @option options :file [nil, String] (nil)
 *     The file name where the message is occurred.
 *
 *     If all of `:file`, `:line` and `:function` are nil, these
 *     values are guessed from `Kernel.#caller_locations` result.
 *   @option options :line [nil, Integer] (nil)
 *     The line number where the message is occurred.
 *   @option options :function [nil, String] (nil)
 *     The function or related name such as method name where the
 *     message is occurred.
 *   @return [void]
 *
 * @since 5.0.2
 */
static VALUE
rb_grn_logger_s_log (int argc, VALUE *argv, VALUE klass)
{
    VALUE rb_message;
    const char *message;
    VALUE rb_context = Qnil;
    grn_ctx *context;
    VALUE rb_level;
    grn_log_level level = GRN_LOG_DEFAULT_LEVEL;
    VALUE rb_file;
    const char *file = NULL;
    VALUE rb_line;
    int line = 0;
    VALUE rb_function;
    const char *function = NULL;
    VALUE rb_options;

    rb_scan_args(argc, argv, "11", &rb_message, &rb_options);

    message = StringValueCStr(rb_message);

    rb_grn_scan_options(rb_options,
                        "context",  &rb_context,
                        "level",    &rb_level,
                        "file",     &rb_file,
                        "line",     &rb_line,
                        "function", &rb_function,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_level)) {
        level = RVAL2GRNLOGLEVEL(rb_level);
    }

    if (NIL_P(rb_file) && NIL_P(rb_line) && NIL_P(rb_function)) {
        VALUE rb_locations;
        VALUE rb_location;
        rb_locations = rb_funcall(rb_cObject,
                                  id_caller_locations,
                                  2,
                                  INT2NUM(1), INT2NUM(1));
        rb_location = RARRAY_PTR(rb_locations)[0];
        rb_file = rb_funcall(rb_location, id_path, 0);
        rb_line = rb_funcall(rb_location, id_lineno, 0);
        rb_function = rb_funcall(rb_location, id_label, 0);
    }

    if (!NIL_P(rb_file)) {
        file = StringValueCStr(rb_file);
    }
    if (!NIL_P(rb_line)) {
        line = NUM2INT(rb_line);
    }
    if (!NIL_P(rb_function)) {
        function = StringValueCStr(rb_function);
    }

    grn_logger_put(context, level, file, line, function, "%s", message);

    return Qnil;
}
Exemplo n.º 24
0
/*
 * スニペットを作成する。
 *
 * @overload new(options={})
 *   @param options [::Hash] The name and value
 *     pairs. Omitted names are initialized as the default value.
 *   @option options :context (Groonga::Context.default)
 *     スキーマ作成時に使用するGroonga::Contextを指定する。
 *   @option options :normalize
 *     キーワード文字列・スニペット元の文字列を正規化するかどうか。
 *     省略した場合は +false+ で正規化しない。
 *   @option options :skip_leading_spaces (false)
 *     先頭の空白を無視するかどうか。省略した場合は +false+ で無視しない。
 *   @option options :width (100)
 *     スニペット文字列の長さ。省略した場合は100文字。
 *   @option options :max_results (3)
 *     生成するスニペットの最大数。省略した場合は3。
 *   @option options :html_escape (false)
 *     スニペット内の +<+ , +>+ , +&+ , +"+ をHTMLエスケープするかどうか。
 *     省略した場合は +false+ で、HTMLエスケープしない。
 *   @option options :default_open_tag ("")
 *     デフォルトの開始タグ。省略した場合は""(空文字列)
 *   @option options :default_close_tag ("")
 *     デフォルトの終了タグ。省略した場合は""(空文字列)
 */
static VALUE
rb_grn_snippet_initialize (int argc, VALUE *argv, VALUE self)
{
    grn_ctx *context = NULL;
    grn_snip *snippet = NULL;
    VALUE options;
    VALUE rb_context, rb_normalize, rb_skip_leading_spaces;
    VALUE rb_width, rb_max_results, rb_default_open_tag, rb_default_close_tag;
    VALUE rb_html_escape;
    int flags = GRN_SNIP_COPY_TAG;
    unsigned int width = 100;
    unsigned int max_results = 3;
    char *default_open_tag = NULL;
    unsigned int default_open_tag_length = 0;
    char *default_close_tag = NULL;
    unsigned int default_close_tag_length = 0;
    grn_snip_mapping *mapping = NULL;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "normalize", &rb_normalize,
                        "skip_leading_spaces", &rb_skip_leading_spaces,
                        "width", &rb_width,
                        "max_results", &rb_max_results,
                        "default_open_tag", &rb_default_open_tag,
                        "default_close_tag", &rb_default_close_tag,
                        "html_escape", &rb_html_escape,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);
    if (!grn_ctx_db(context)) {
        rb_raise(rb_eArgError,
                 "Groonga::Context should be associated with a database by "
                 "Groonga::Database#open or #create: %s",
                 rb_grn_inspect(rb_context));
    }

    if (RVAL2CBOOL(rb_normalize))
        flags |= GRN_SNIP_NORMALIZE;
    if (RVAL2CBOOL(rb_skip_leading_spaces))
        flags |= GRN_SNIP_SKIP_LEADING_SPACES;

    if (!NIL_P(rb_width))
        width = NUM2UINT(rb_width);

    if (!NIL_P(rb_max_results))
        max_results = NUM2UINT(rb_max_results);

    if (!NIL_P(rb_default_open_tag)) {
        default_open_tag = StringValuePtr(rb_default_open_tag);
        default_open_tag_length = RSTRING_LEN(rb_default_open_tag);
    }

    if (!NIL_P(rb_default_close_tag)) {
        default_close_tag = StringValuePtr(rb_default_close_tag);
        default_close_tag_length = RSTRING_LEN(rb_default_close_tag);
    }

    if (RVAL2CBOOL(rb_html_escape))
        mapping = (grn_snip_mapping *)-1;

    snippet = grn_snip_open(context, flags, width, max_results,
                            default_open_tag, default_open_tag_length,
                            default_close_tag, default_close_tag_length,
                            mapping);
    rb_grn_context_check(context, rb_ary_new4(argc, argv));

    rb_grn_object_assign(Qnil, self, rb_context, context, (grn_obj *)snippet);
    rb_grn_context_register_floating_object(DATA_PTR(self));

    rb_iv_set(self, "@context", rb_context);

    return Qnil;
}
Exemplo n.º 25
0
/*
 * It creates a table that manages records by double array trie.
 * ブロックを指定すると、そのブロックに生成したテーブルが渡さ
 * れ、ブロックを抜けると自動的にテーブルが破棄される。
 *
 * @example
 *   #無名一時テーブルを生成する。
 *   Groonga::DoubleArrayTrie.create
 *
 *   #無名永続テーブルを生成する。
 *   Groonga::DoubleArrayTrie.create(:path => "/tmp/hash.grn")
 *
 *   #名前付き永続テーブルを生成する。ただし、ファイル名は気に
 *   #しない。
 *   Groonga::DoubleArrayTrie.create(:name => "Bookmarks",
 *                                   :persistent => true)
 *
 *   #それぞれのレコードに512バイトの値を格納できる無名一時テー
 *   #ブルを生成する。
 *   Groonga::DoubleArrayTrie.create(:value => 512)
 *
 *   #キーとして文字列を使用する無名一時テーブルを生成する。
 *   Groonga::DoubleArrayTrie.create(:key_type => Groonga::Type::SHORT_TEXT)
 *
 *   #キーとして文字列を使用する無名一時テーブルを生成する。
 *   #(キーの種類を表すオブジェクトは文字列で指定。)
 *   Groonga::DoubleArrayTrie.create(:key_type => "ShortText")
 *
 *   #キーとしてBookmarksテーブルのレコードを使用す
 *   #る無名一時テーブルを生成する。
 *   bookmarks = Groonga::DoubleArrayTrie.create(:name => "Bookmarks")
 *   Groonga::DoubleArrayTrie.create(:key_type => bookmarks)
 *
 *   #キーとしてBookmarksテーブルのレコードを使用す
 *   #る無名一時テーブルを生成する。
 *   #(テーブルは文字列で指定。)
 *   Groonga::DoubleArrayTrie.create(:name => "Bookmarks")
 *   Groonga::DoubleArrayTrie.create(:key_type => "Bookmarks")
 *
 *   #全文検索用のトークンをバイグラムで切り出す無名一時テーブ
 *   #ルを生成する。
 *   bookmarks = Groonga::DoubleArrayTrie.create(:name => "Bookmarks")
 *   bookmarks.define_column("comment", "Text")
 *   terms = Groonga::DoubleArrayTrie.create(:name => "Terms",
 *                                           :default_tokenizer => "TokenBigram")
 *   terms.define_index_column("content", bookmarks,
 *                             :source => "Bookmarks.comment")
 *
 * @overload create(options={})
 *   @return [Groonga::DoubleArrayTrie]
 *   @!macro [new] double-array-trie.create.options
 *     @param [::Hash] options The name and value
 *       pairs. Omitted names are initialized as the default value.
 *     @option options [Groonga::Context] :context (Groonga::Context.default)
 *       テーブルが利用する {Groonga::Context} 。
 *     @option options :name
 *       テーブルの名前。名前をつけると、 {Groonga::Context#[]} に名
 *       前を指定してテーブルを取得することができる。省略すると
 *       無名テーブルになり、テーブルIDでのみ取得できる。
 *     @option options :path
 *       テーブルを保存するパス。パスを指定すると永続テーブルとな
 *       り、プロセス終了後もレコードは保持される。次回起動時に
 *       {Groonga::Context#[]} で保存されたレコードを利用する
 *       ことができる。省略すると一時テーブルになり、プロセスが終
 *       了するとレコードは破棄される。
 *     @option options :persistent
 *       +true+ を指定すると永続テーブルとなる。 +path+ を省略した
 *       場合は自動的にパスが付加される。 +:context+ で指定した
 *       {Groonga::Context} に結びついているデータベースが一時デー
 *       タベースの場合は例外が発生する。
 *
 *     @option options :key_normalize (false) Keys are normalized
 *       if this value is @true@.
 *
 *       @deprecated Use @:normalizer => "NormalizerAuto"@ instead.
 *
 *     @option options :key_with_sis
 *       +true+ を指定するとキーの文字列の全suffixが自動的に登
 *       録される。
 *     @option options :key_type
 *       キーの種類を示すオブジェクトを指定する。キーの種類には型
 *       名("Int32"や"ShortText"など)または {Groonga::Type} または
 *       テーブル( {Groonga::Array} 、{Groonga::Hash} 、
 *       {Groonga::DoubleArrayTrie} のどれか)を指定する。
 *       {Groonga::Type} を指定した場合は、その型が示す範囲の値をキー
 *       として使用する。ただし、キーの最大サイズは4096バイトで
 *       あるため、 {Groonga::Type::TEXT} や {Groonga::Type::LONG_TEXT}
 *       は使用できない。
 *
 *       テーブルを指定した場合はレコードIDをキーとして使用する。
 *       指定したテーブルの {Groonga::Record} をキーとして使用するこ
 *       ともでき、その場合は自動的に {Groonga::Record} からレコード
 *       IDを取得する。
 *
 *       省略した場合はShortText型をキーとして使用する。この場合、
 *       4096バイトまで使用可能である。
 *     @option options :value_type
 *       値の型を指定する。省略すると値のための領域を確保しない。
 *       値を保存したい場合は必ず指定すること。
 *
 *       参考: {Groonga::Type.new}
 *
 *     @option options :default_tokenizer
 *       {Groonga::IndexColumn} で使用するトークナイザを指定する。
 *       デフォルトでは何も設定されていないので、テーブルに
 *       {Groonga::IndexColumn} を定義する場合は
 *       @"TokenBigram"@ などを指定する必要がある。
 *
 *     @option options [::Array<String, Groonga::Procedure>, nil]
 *       :token_filters (nil) The token filters to be used in the
 *       table.
 *
 *     @option options :sub_records
 *       +true+ を指定すると {#group} でグループ化したときに、
 *       {Groonga::Record#n_sub_records} でグループに含まれるレコー
 *       ドの件数を取得できる。
 *
 *     @option options [String, Groonga::Procedure, nil] :normalizer
 *       The normalizer that is used by {Groonga::IndexColumn}. You
 *       can specify this by normalizer name as String such as
 *       @"NormalizerAuto"@ or normalizer object.
 *
 *   @!macro double-array-trie.create.options
 * @overload create(options={})
 *   @yield [table]
 *   @!macro double-array-trie.create.options
 */
static VALUE
rb_grn_double_array_trie_s_create (int argc, VALUE *argv, VALUE klass)
{
    grn_ctx *context;
    grn_obj *key_type = NULL, *value_type = NULL, *table;
    const char *name = NULL, *path = NULL;
    unsigned name_size = 0;
    grn_obj_flags flags = GRN_OBJ_TABLE_DAT_KEY;
    VALUE rb_table;
    VALUE options, rb_context, rb_name, rb_path, rb_persistent;
    VALUE rb_key_normalize, rb_key_with_sis, rb_key_type;
    VALUE rb_value_type;
    VALUE rb_default_tokenizer;
    VALUE rb_token_filters;
    VALUE rb_sub_records;
    VALUE rb_normalizer;

    rb_scan_args(argc, argv, "01", &options);

    rb_grn_scan_options(options,
                        "context", &rb_context,
                        "name", &rb_name,
                        "path", &rb_path,
                        "persistent", &rb_persistent,
                        "key_normalize", &rb_key_normalize,
                        "key_with_sis", &rb_key_with_sis,
                        "key_type", &rb_key_type,
                        "value_type", &rb_value_type,
                        "default_tokenizer", &rb_default_tokenizer,
                        "token_filters", &rb_token_filters,
                        "sub_records", &rb_sub_records,
                        "normalizer", &rb_normalizer,
                        NULL);

    context = rb_grn_context_ensure(&rb_context);

    if (!NIL_P(rb_name)) {
        name = StringValuePtr(rb_name);
        name_size = RSTRING_LEN(rb_name);
        flags |= GRN_OBJ_PERSISTENT;
    }

    if (!NIL_P(rb_path)) {
        path = StringValueCStr(rb_path);
        flags |= GRN_OBJ_PERSISTENT;
    }

    if (RVAL2CBOOL(rb_persistent))
        flags |= GRN_OBJ_PERSISTENT;

    if (RVAL2CBOOL(rb_key_normalize))
        flags |= GRN_OBJ_KEY_NORMALIZE;

    if (RVAL2CBOOL(rb_key_with_sis))
        flags |= GRN_OBJ_KEY_WITH_SIS;

    if (NIL_P(rb_key_type)) {
        key_type = grn_ctx_at(context, GRN_DB_SHORT_TEXT);
    } else {
        key_type = RVAL2GRNOBJECT(rb_key_type, &context);
    }

    if (!NIL_P(rb_value_type))
        value_type = RVAL2GRNOBJECT(rb_value_type, &context);

    if (RVAL2CBOOL(rb_sub_records))
        flags |= GRN_OBJ_WITH_SUBREC;

    table = grn_table_create(context, name, name_size, path,
                             flags, key_type, value_type);
    if (!table)
        rb_grn_context_check(context, rb_ary_new4(argc, argv));
    rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE);

    if (!NIL_P(rb_default_tokenizer))
        rb_funcall(rb_table, rb_intern("default_tokenizer="), 1,
                   rb_default_tokenizer);
    if (!NIL_P(rb_token_filters))
        rb_funcall(rb_table, rb_intern("token_filters="), 1,
                   rb_token_filters);
    if (!NIL_P(rb_normalizer))
        rb_funcall(rb_table, rb_intern("normalizer="), 1,
                   rb_normalizer);

    if (rb_block_given_p())
        return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table);
    else
        return rb_table;
}