From 06bf04500ba282052d38adf428219968ae62bb54 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Sat, 22 May 2010 08:45:40 +0300 Subject: [PATCH 1/6] Initial ruby bindings --- bindings/ruby/database.c | 321 ++++++++++++++++++++++++++++++++++++++ bindings/ruby/defs.h | 300 +++++++++++++++++++++++++++++++++++ bindings/ruby/directory.c | 104 ++++++++++++ bindings/ruby/extconf.rb | 15 ++ bindings/ruby/filenames.c | 43 +++++ bindings/ruby/gc.c | 268 +++++++++++++++++++++++++++++++ bindings/ruby/init.c | 272 ++++++++++++++++++++++++++++++++ bindings/ruby/message.c | 303 +++++++++++++++++++++++++++++++++++ bindings/ruby/messages.c | 74 +++++++++ bindings/ruby/query.c | 88 +++++++++++ bindings/ruby/rdoc.sh | 10 ++ bindings/ruby/status.c | 49 ++++++ bindings/ruby/tags.c | 46 ++++++ bindings/ruby/thread.c | 180 +++++++++++++++++++++ bindings/ruby/threads.c | 50 ++++++ 15 files changed, 2123 insertions(+) create mode 100644 bindings/ruby/database.c create mode 100644 bindings/ruby/defs.h create mode 100644 bindings/ruby/directory.c create mode 100644 bindings/ruby/extconf.rb create mode 100644 bindings/ruby/filenames.c create mode 100644 bindings/ruby/gc.c create mode 100644 bindings/ruby/init.c create mode 100644 bindings/ruby/message.c create mode 100644 bindings/ruby/messages.c create mode 100644 bindings/ruby/query.c create mode 100755 bindings/ruby/rdoc.sh create mode 100644 bindings/ruby/status.c create mode 100644 bindings/ruby/tags.c create mode 100644 bindings/ruby/thread.c create mode 100644 bindings/ruby/threads.c diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c new file mode 100644 index 00000000..44ee6817 --- /dev/null +++ b/bindings/ruby/database.c @@ -0,0 +1,321 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: Notmuch::Database.new(path, [{:create => false, :mode => notmuch::MODE_READ_ONLY}]) => DB + * + * Create or open a notmuch database using the given path. + * If :create is +true+, create the database instead of opening. + * The argument :mode specifies the open mode of the database. + */ +VALUE +notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) +{ + const char *path; + int create, mode; + notmuch_rb_database_t *db; + VALUE modev, dbv; + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + /* Check arguments */ + if (argc < 1 || argc > 2) + rb_raise(rb_eTypeError, "Wrong number of arguments"); + + SafeStringValue(argv[0]); + path = RSTRING_PTR(argv[0]); + + if (argc == 2) { + Check_Type(argv[1], T_HASH); + create = RTEST(rb_hash_aref(argv[1], ID2SYM(ID_db_create))); + modev = rb_hash_aref(argv[1], ID2SYM(ID_db_mode)); + if (NIL_P(modev)) + mode = NOTMUCH_DATABASE_MODE_READ_ONLY; + else if (!FIXNUM_P(modev)) + rb_raise(rb_eTypeError, ":mode isn't a Fixnum"); + else { + mode = FIX2INT(modev); + switch (mode) { + case NOTMUCH_DATABASE_MODE_READ_ONLY: + case NOTMUCH_DATABASE_MODE_READ_WRITE: + break; + default: + rb_raise(rb_eTypeError, "Invalid mode"); + } + } + } + else { + create = 0; + mode = NOTMUCH_DATABASE_MODE_READ_ONLY; + } + + dbv = Data_Make_Struct(klass, notmuch_rb_database_t, NULL, notmuch_rb_database_free, db); + db->nm_db = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); + if (!db->nm_db) + rb_raise(notmuch_rb_eDatabaseError, "failed to open database"); + + return dbv; +} + +/* + * call-seq: DB.close => nil + * + * Close the notmuch database. + */ +VALUE +notmuch_rb_database_close(VALUE self) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (db->nm_db) { + notmuch_database_close(db->nm_db); + db->nm_db = NULL; + } + + return Qnil; +} + +/* + * call-seq: DB.path => String + * + * Return the path of the database + */ +VALUE +notmuch_rb_database_path(VALUE self) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + + return rb_str_new2(notmuch_database_get_path(db->nm_db)); +} + +/* + * call-seq: DB.version => Fixnum + * + * Return the version of the database + */ +VALUE +notmuch_rb_database_version(VALUE self) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + + return INT2FIX(notmuch_database_get_version(db->nm_db)); +} + +/* + * call-seq: DB.needs_upgrade? => true or false + * + * Return the +true+ if the database needs upgrading, +false+ otherwise + */ +VALUE +notmuch_rb_database_needs_upgrade(VALUE self) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + + return notmuch_database_needs_upgrade(db->nm_db) ? Qtrue : Qfalse; +} + +static void +notmuch_rb_upgrade_notify(void *closure, double progress) +{ + VALUE *block = (VALUE *)closure; + rb_funcall(*block, ID_call, 1, rb_float_new(progress)); +} + +/* + * call-seq: DB.upgrade [{|progress| block }] => nil + * + * Upgrade the database. + * + * If a block is given the block is called with a progress indicator as a + * floating point value in the range of [0.0..1.0]. + */ +VALUE +notmuch_rb_database_upgrade(VALUE self) +{ + notmuch_status_t ret; + void (*pnotify) (void *closure, double progress); + notmuch_rb_database_t *db; + VALUE block; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + + if (rb_block_given_p()) { + pnotify = notmuch_rb_upgrade_notify; + block = rb_block_proc(); + } + else + pnotify = NULL; + + ret = notmuch_database_upgrade(db->nm_db, pnotify, pnotify ? &block : NULL); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: DB.get_directory(path) => DIR + * + * Retrieve a directory object from the database for 'path' + */ +VALUE +notmuch_rb_database_get_directory(VALUE self, VALUE pathv) +{ + const char *path; + notmuch_rb_directory_t *dir; + notmuch_rb_database_t *db; + VALUE dirv; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(pathv); + path = RSTRING_PTR(pathv); + + dirv = Data_Make_Struct(notmuch_rb_cDirectory, notmuch_rb_directory_t, + notmuch_rb_directory_mark, notmuch_rb_directory_free, dir); + dir->nm_dir = notmuch_database_get_directory(db->nm_db, path); + dir->db = self; + if (!dir->nm_dir) + rb_raise(notmuch_rb_eXapianError, "Xapian exception"); + + return dirv; +} + +/* + * call-seq: DB.add_message(path) => MESSAGE, isdup + * + * Add a message to the database and return it + * +isdup+ is a boolean that specifies whether the added message was a + * duplicate. + */ +VALUE +notmuch_rb_database_add_message(VALUE self, VALUE pathv) +{ + const char *path; + notmuch_status_t ret; + notmuch_rb_message_t *message; + notmuch_rb_database_t *db; + VALUE messagev; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(pathv); + path = RSTRING_PTR(pathv); + + messagev = Data_Make_Struct(notmuch_rb_cMessage, notmuch_rb_message_t, + notmuch_rb_message_mark, notmuch_rb_message_free, message); + ret = notmuch_database_add_message(db->nm_db, path, &message->nm_message); + message->parent = self; + notmuch_rb_status_raise(ret); + return rb_assoc_new(messagev, (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse); +} + +/* + * call-seq: DB.remove_message(path) => isdup + * + * Remove a message from the database. + * +isdup+ is a boolean that specifies whether the removed message was a + * duplicate. + */ +VALUE +notmuch_rb_database_remove_message(VALUE self, VALUE pathv) +{ + const char *path; + notmuch_status_t ret; + notmuch_rb_database_t *db; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(pathv); + path = RSTRING_PTR(pathv); + + ret = notmuch_database_remove_message(db->nm_db, path); + notmuch_rb_status_raise(ret); + return (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse; +} + +/* + * call-seq: DB.query(query) => QUERY + * + * Retrieve a query object for the query string 'query' + */ +VALUE +notmuch_rb_database_query_create(VALUE self, VALUE qstrv) +{ + const char *qstr; + notmuch_rb_query_t *query; + notmuch_rb_database_t *db; + VALUE queryv; + + Data_Get_Struct(self, notmuch_rb_database_t, db); + if (!db->nm_db) + rb_raise(rb_eRuntimeError, "Database closed"); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(qstrv); + qstr = RSTRING_PTR(qstrv); + + queryv = Data_Make_Struct(notmuch_rb_cQuery, notmuch_rb_query_t, + notmuch_rb_query_mark, notmuch_rb_query_free, query); + query->nm_query = notmuch_query_create(db->nm_db, qstr); + query->db = self; + if (!query->nm_query) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return queryv; +} diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h new file mode 100644 index 00000000..1973d26e --- /dev/null +++ b/bindings/ruby/defs.h @@ -0,0 +1,300 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#ifndef DEFS_H +#define DEFS_H + +#include +#include + +VALUE notmuch_rb_cDatabase; +VALUE notmuch_rb_cDirectory; +VALUE notmuch_rb_cFileNames; +VALUE notmuch_rb_cQuery; +VALUE notmuch_rb_cThreads; +VALUE notmuch_rb_cThread; +VALUE notmuch_rb_cMessages; +VALUE notmuch_rb_cMessage; +VALUE notmuch_rb_cTags; + +VALUE notmuch_rb_eBaseError; +VALUE notmuch_rb_eDatabaseError; +VALUE notmuch_rb_eMemoryError; +VALUE notmuch_rb_eReadOnlyError; +VALUE notmuch_rb_eXapianError; +VALUE notmuch_rb_eFileError; +VALUE notmuch_rb_eFileNotEmailError; +VALUE notmuch_rb_eNullPointerError; +VALUE notmuch_rb_eTagTooLongError; +VALUE notmuch_rb_eUnbalancedFreezeThawError; + +ID ID_call; +ID ID_db_create; +ID ID_db_mode; + +typedef struct { + notmuch_database_t *nm_db; +} notmuch_rb_database_t; + +typedef struct { + notmuch_directory_t *nm_dir; + VALUE db; +} notmuch_rb_directory_t; + +typedef struct { + notmuch_filenames_t *nm_flist; + VALUE dir; +} notmuch_rb_filenames_t; + +typedef struct { + notmuch_query_t *nm_query; + VALUE db; +} notmuch_rb_query_t; + +typedef struct { + notmuch_threads_t *nm_threads; + VALUE query; +} notmuch_rb_threads_t; + +typedef struct { + notmuch_messages_t *nm_messages; + VALUE parent; +} notmuch_rb_messages_t; + +typedef struct { + notmuch_thread_t *nm_thread; + VALUE threads; +} notmuch_rb_thread_t; + +typedef struct { + notmuch_message_t *nm_message; + VALUE parent; +} notmuch_rb_message_t; + +typedef struct { + notmuch_tags_t *nm_tags; + VALUE parent; +} notmuch_rb_tags_t; + +/* status.c */ +void +notmuch_rb_status_raise(notmuch_status_t status); + +/* gc.c */ +void +notmuch_rb_database_free(notmuch_rb_database_t *db); + +void +notmuch_rb_directory_mark(notmuch_rb_directory_t *dir); + +void +notmuch_rb_directory_free(notmuch_rb_directory_t *dir); + +void +notmuch_rb_filenames_mark(notmuch_rb_filenames_t *flist); + +void +notmuch_rb_filenames_free(notmuch_rb_filenames_t *flist); + +void +notmuch_rb_query_mark(notmuch_rb_query_t *query); + +void +notmuch_rb_query_free(notmuch_rb_query_t *query); + +void +notmuch_rb_threads_mark(notmuch_rb_threads_t *threads); + +void +notmuch_rb_threads_free(notmuch_rb_threads_t *threads); + +void +notmuch_rb_messages_mark(notmuch_rb_messages_t *messages); + +void +notmuch_rb_messages_free(notmuch_rb_messages_t *messages); + +void +notmuch_rb_thread_mark(notmuch_rb_thread_t *thread); + +void +notmuch_rb_thread_free(notmuch_rb_thread_t *thread); + +void +notmuch_rb_message_mark(notmuch_rb_message_t *message); + +void +notmuch_rb_message_free(notmuch_rb_message_t *message); + +void +notmuch_rb_tags_mark(notmuch_rb_tags_t *tags); + +void +notmuch_rb_tags_free(notmuch_rb_tags_t *tags); + +/* database.c */ +VALUE +notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass); + +VALUE +notmuch_rb_database_close(VALUE self); + +VALUE +notmuch_rb_database_path(VALUE self); + +VALUE +notmuch_rb_database_version(VALUE self); + +VALUE +notmuch_rb_database_needs_upgrade(VALUE self); + +VALUE +notmuch_rb_database_upgrade(VALUE self); + +VALUE +notmuch_rb_database_get_directory(VALUE self, VALUE pathv); + +VALUE +notmuch_rb_database_add_message(VALUE self, VALUE pathv); + +VALUE +notmuch_rb_database_remove_message(VALUE self, VALUE pathv); + +VALUE +notmuch_rb_database_query_create(VALUE self, VALUE qstrv); + +/* directory.c */ +VALUE +notmuch_rb_directory_get_mtime(VALUE self); + +VALUE +notmuch_rb_directory_set_mtime(VALUE self, VALUE mtimev); + +VALUE +notmuch_rb_directory_get_child_files(VALUE self); + +VALUE +notmuch_rb_directory_get_child_directories(VALUE self); + +/* filenames.c */ +VALUE +notmuch_rb_filenames_each(VALUE self); + +/* query.c */ +VALUE +notmuch_rb_query_set_sort(VALUE self, VALUE sortv); + +VALUE +notmuch_rb_query_search_threads(VALUE self); + +VALUE +notmuch_rb_query_search_messages(VALUE self); + +/* threads.c */ +VALUE +notmuch_rb_threads_each(VALUE self); + +/* messages.c */ +VALUE +notmuch_rb_messages_each(VALUE self); + +VALUE +notmuch_rb_messages_collect_tags(VALUE self); + +/* thread.c */ +VALUE +notmuch_rb_thread_get_thread_id(VALUE self); + +VALUE +notmuch_rb_thread_get_total_messages(VALUE self); + +VALUE +notmuch_rb_thread_get_toplevel_messages(VALUE self); + +VALUE +notmuch_rb_thread_get_matched_messages(VALUE self); + +VALUE +notmuch_rb_thread_get_authors(VALUE self); + +VALUE +notmuch_rb_thread_get_subject(VALUE self); + +VALUE +notmuch_rb_thread_get_oldest_date(VALUE self); + +VALUE +notmuch_rb_thread_get_newest_date(VALUE self); + +VALUE +notmuch_rb_thread_get_tags(VALUE self); + +/* message.c */ +VALUE +notmuch_rb_message_get_message_id(VALUE self); + +VALUE +notmuch_rb_message_get_thread_id(VALUE self); + +VALUE +notmuch_rb_message_get_replies(VALUE self); + +VALUE +notmuch_rb_message_get_filename(VALUE self); + +VALUE +notmuch_rb_message_get_flag(VALUE self, VALUE flagv); + +VALUE +notmuch_rb_message_set_flag(VALUE self, VALUE flagv, VALUE valuev); + +VALUE +notmuch_rb_message_get_date(VALUE self); + +VALUE +notmuch_rb_message_get_header(VALUE self, VALUE headerv); + +VALUE +notmuch_rb_message_get_tags(VALUE self); + +VALUE +notmuch_rb_message_add_tag(VALUE self, VALUE tagv); + +VALUE +notmuch_rb_message_remove_tag(VALUE self, VALUE tagv); + +VALUE +notmuch_rb_message_remove_all_tags(VALUE self); + +VALUE +notmuch_rb_message_freeze(VALUE self); + +VALUE +notmuch_rb_message_thaw(VALUE self); + +/* tags.c */ +VALUE +notmuch_rb_tags_each(VALUE self); + +/* init.c */ +void +Init_notmuch(void); + +#endif diff --git a/bindings/ruby/directory.c b/bindings/ruby/directory.c new file mode 100644 index 00000000..46fe11cf --- /dev/null +++ b/bindings/ruby/directory.c @@ -0,0 +1,104 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: DIR.mtime => fixnum + * + * Returns the mtime of the directory or +0+ if no mtime has been previously + * stored. + */ +VALUE +notmuch_rb_directory_get_mtime(VALUE self) +{ + notmuch_rb_directory_t *dir; + + Data_Get_Struct(self, notmuch_rb_directory_t, dir); + + return UINT2NUM(notmuch_directory_get_mtime(dir->nm_dir)); +} + +/* + * call-seq: DIR.mtime=(fixnum) => nil + * + * Store an mtime within the database for the directory object. + */ +VALUE +notmuch_rb_directory_set_mtime(VALUE self, VALUE mtimev) +{ + notmuch_status_t ret; + notmuch_rb_directory_t *dir; + + Data_Get_Struct(self, notmuch_rb_directory_t, dir); + + if (!FIXNUM_P(mtimev)) + rb_raise(rb_eTypeError, "First argument not a fixnum"); + + ret = notmuch_directory_set_mtime(dir->nm_dir, FIX2UINT(mtimev)); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: DIR.child_files => FILENAMES + * + * Return a Notmuch::FileNames object, which is an +Enumerable+ listing all the + * filenames of messages in the database within the given directory. + */ +VALUE +notmuch_rb_directory_get_child_files(VALUE self) +{ + notmuch_rb_directory_t *dir; + notmuch_rb_filenames_t *flist; + VALUE flistv; + + Data_Get_Struct(self, notmuch_rb_directory_t, dir); + + flistv = Data_Make_Struct(notmuch_rb_cFileNames, notmuch_rb_filenames_t, + notmuch_rb_filenames_mark, notmuch_rb_filenames_free, flist); + flist->dir = self; + flist->nm_flist = notmuch_directory_get_child_files(dir->nm_dir); + + return flistv; +} + +/* + * call-seq: DIR.child_directories => FILENAMES + * + * Return a Notmuch::FileNames object, which is an +Enumerable+ listing all the + * directories in the database within the given directory. + */ +VALUE +notmuch_rb_directory_get_child_directories(VALUE self) +{ + notmuch_rb_directory_t *dir; + notmuch_rb_filenames_t *flist; + VALUE flistv; + + Data_Get_Struct(self, notmuch_rb_directory_t, dir); + + flistv = Data_Make_Struct(notmuch_rb_cFileNames, notmuch_rb_filenames_t, + notmuch_rb_filenames_mark, notmuch_rb_filenames_free, flist); + flist->dir = self; + flist->nm_flist = notmuch_directory_get_child_directories(dir->nm_dir); + + return flistv; +} diff --git a/bindings/ruby/extconf.rb b/bindings/ruby/extconf.rb new file mode 100644 index 00000000..a9d9d42b --- /dev/null +++ b/bindings/ruby/extconf.rb @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +# coding: utf-8 +# vim: set sw=2 sts=2 et nowrap fenc=utf-8 : +# Copyright 2010 Ali Polatel +# Distributed under the terms of the GNU General Public License v3 + +require 'mkmf' + +# Notmuch Library +find_header('notmuch.h', '../../lib') +find_library('notmuch', 'notmuch_database_create', '../../lib') + +# Create Makefile +dir_config('notmuch') +create_makefile('notmuch') diff --git a/bindings/ruby/filenames.c b/bindings/ruby/filenames.c new file mode 100644 index 00000000..44a16522 --- /dev/null +++ b/bindings/ruby/filenames.c @@ -0,0 +1,43 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: FILENAMES.each {|item| block } => FILENAMES + * + * Calls +block+ once for each element in +self+, passing that element as a + * parameter. + */ +VALUE +notmuch_rb_filenames_each(VALUE self) +{ + notmuch_rb_filenames_t *flist; + + Data_Get_Struct(self, notmuch_rb_filenames_t, flist); + if (!flist->nm_flist) + return self; + + for (; notmuch_filenames_valid(flist->nm_flist); + notmuch_filenames_move_to_next(flist->nm_flist)) + rb_yield(rb_str_new2(notmuch_filenames_get(flist->nm_flist))); + + return self; +} diff --git a/bindings/ruby/gc.c b/bindings/ruby/gc.c new file mode 100644 index 00000000..3b515905 --- /dev/null +++ b/bindings/ruby/gc.c @@ -0,0 +1,268 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +#include + +static notmuch_rb_database_t * +_notmuch_rb_messages_db(notmuch_rb_messages_t *messages); + +static notmuch_rb_database_t * +_notmuch_rb_message_db(notmuch_rb_message_t *message) +{ + notmuch_rb_messages_t *messages; + notmuch_rb_database_t *db; + + if (rb_obj_is_instance_of(message->parent, notmuch_rb_cDatabase)) { + Data_Get_Struct(message->parent, notmuch_rb_database_t, db); + } + else if (rb_obj_is_instance_of(message->parent, notmuch_rb_cMessages)) { + Data_Get_Struct(message->parent, notmuch_rb_messages_t, messages); + db = _notmuch_rb_messages_db(messages); + } + else + rb_bug("message's parent is neither database nor messages"); + + return db; +} + +static notmuch_rb_database_t * +_notmuch_rb_messages_db(notmuch_rb_messages_t *messages) +{ + notmuch_rb_query_t *query; + notmuch_rb_thread_t *thread; + notmuch_rb_message_t *message; + notmuch_rb_threads_t *threads; + notmuch_rb_database_t *db; + + if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cQuery)) { + Data_Get_Struct(messages->parent, notmuch_rb_query_t, query); + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + } + else if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cThread)) { + Data_Get_Struct(messages->parent, notmuch_rb_thread_t, thread); + Data_Get_Struct(thread->threads, notmuch_rb_threads_t, threads); + Data_Get_Struct(threads->query, notmuch_rb_query_t, query); + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + } + else if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cMessage)) { + Data_Get_Struct(messages->parent, notmuch_rb_message_t, message); + db = _notmuch_rb_message_db(message); + } + else + rb_bug("messages' parent is neither query nor thread nor message"); + + return db; +} + +static notmuch_rb_database_t * +_notmuch_rb_thread_db(notmuch_rb_thread_t *thread) +{ + notmuch_rb_threads_t *threads; + notmuch_rb_query_t *query; + notmuch_rb_database_t *db; + + Data_Get_Struct(thread->threads, notmuch_rb_threads_t, threads); + Data_Get_Struct(threads->query, notmuch_rb_query_t, query); + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + + return db; +} + +void +notmuch_rb_database_free(notmuch_rb_database_t *db) +{ + if (db->nm_db) + notmuch_database_close(db->nm_db); + + free(db); +} + +void +notmuch_rb_directory_mark(notmuch_rb_directory_t *dir) +{ + rb_gc_mark(dir->db); +} + +void +notmuch_rb_directory_free(notmuch_rb_directory_t *dir) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + + if (db->nm_db && dir->nm_dir) + notmuch_directory_destroy(dir->nm_dir); + + free(dir); +} + +void +notmuch_rb_filenames_mark(notmuch_rb_filenames_t *flist) +{ + rb_gc_mark(flist->dir); +} + +void +notmuch_rb_filenames_free(notmuch_rb_filenames_t *flist) +{ + notmuch_rb_directory_t *dir; + notmuch_rb_database_t *db; + + Data_Get_Struct(flist->dir, notmuch_rb_directory_t, dir); + Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + + if (db->nm_db && flist->nm_flist) + notmuch_filenames_destroy(flist->nm_flist); + + free(flist); +} + +void +notmuch_rb_query_mark(notmuch_rb_query_t *query) +{ + rb_gc_mark(query->db); +} + +void +notmuch_rb_query_free(notmuch_rb_query_t *query) +{ + notmuch_rb_database_t *db; + + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + + if (db->nm_db && query->nm_query) + notmuch_query_destroy(query->nm_query); + + free(query); +} + +void +notmuch_rb_threads_mark(notmuch_rb_threads_t *threads) +{ + rb_gc_mark(threads->query); +} + +void +notmuch_rb_threads_free(notmuch_rb_threads_t *threads) +{ + notmuch_rb_query_t *query; + notmuch_rb_database_t *db; + + Data_Get_Struct(threads->query, notmuch_rb_query_t, query); + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + + if (db->nm_db && threads->nm_threads) + notmuch_threads_destroy(threads->nm_threads); + + free(threads); +} + +void +notmuch_rb_messages_mark(notmuch_rb_messages_t *messages) +{ + rb_gc_mark(messages->parent); +} + +void +notmuch_rb_messages_free(notmuch_rb_messages_t *messages) +{ + notmuch_rb_database_t *db; + + db = _notmuch_rb_messages_db(messages); + + if (db->nm_db && messages->nm_messages) + notmuch_messages_destroy(messages->nm_messages); + + free(messages); +} + +void +notmuch_rb_thread_mark(notmuch_rb_thread_t *thread) +{ + rb_gc_mark(thread->threads); +} + +void +notmuch_rb_thread_free(notmuch_rb_thread_t *thread) +{ + notmuch_rb_database_t *db; + + db = _notmuch_rb_thread_db(thread); + + if (db->nm_db && thread->nm_thread) + notmuch_thread_destroy(thread->nm_thread); + + free(thread); +} + +void +notmuch_rb_message_mark(notmuch_rb_message_t *message) +{ + rb_gc_mark(message->parent); +} + +void +notmuch_rb_message_free(notmuch_rb_message_t *message) +{ + notmuch_rb_database_t *db; + + db = _notmuch_rb_message_db(message); + if (db->nm_db && message->nm_message) + notmuch_message_destroy(message->nm_message); + + free(message); +} + +void +notmuch_rb_tags_mark(notmuch_rb_tags_t *tags) +{ + rb_gc_mark(tags->parent); +} + +void +notmuch_rb_tags_free(notmuch_rb_tags_t *tags) +{ + notmuch_rb_message_t *message; + notmuch_rb_messages_t *messages; + notmuch_rb_thread_t *thread; + notmuch_rb_database_t *db; + + if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cThread)) { + Data_Get_Struct(tags->parent, notmuch_rb_thread_t, thread); + db = _notmuch_rb_thread_db(thread); + } + else if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cMessage)) { + Data_Get_Struct(tags->parent, notmuch_rb_message_t, message); + db = _notmuch_rb_message_db(message); + } + else if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cMessages)) { + Data_Get_Struct(tags->parent, notmuch_rb_messages_t, messages); + db = _notmuch_rb_messages_db(messages); + } + else + rb_bug("tags' parent is neither thread nor message nor messages"); + + if (db->nm_db && tags->nm_tags) + notmuch_tags_destroy(tags->nm_tags); + + free(tags); +} diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c new file mode 100644 index 00000000..61077ccb --- /dev/null +++ b/bindings/ruby/init.c @@ -0,0 +1,272 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * Document-module: Notmuch + * + * == Summary + * + * Ruby extension to the notmuch mail library. + * + * == Constants + * + * - Notmuch::MODE_READ_ONLY + * + * Open the database in read only mode. + * + * - Notmuch::MODE_READ_WRITE + * + * Open the database in read write mode. + * + * - Notmuch::TAG_MAX + * + * Maximum allowed length of a tag + */ + +/* + * Document-class: Notmuch::Database + * + * Notmuch database interaction + */ + +/* + * Document-class: Notmuch::Directory + * + * Notmuch directory + */ + +/* + * Document-class: Notmuch::FileNames + * + * Notmuch file names + */ + +/* + * Document-class: Notmuch::Query + * + * Notmuch query + */ + +/* + * Document-class: Notmuch::Threads + * + * Notmuch threads + */ + +/* + * Document-class: Notmuch::Messages + * + * Notmuch messages + */ + +/* + * Document-class: Notmuch::Thread + * + * Notmuch thread + */ + +/* + * Document-class: Notmuch::Message + * + * Notmuch message + */ + +/* + * Document-class: Notmuch::Tags + * + * Notmuch tags + */ + +/* + * Document-class: Notmuch::BaseError + * + * Base class for all notmuch exceptions + */ + +/* + * Document-class: Notmuch::DatabaseError + * + * Raised when the database can't be created or opened. + */ + +/* + * Document-class: Notmuch::MemoryError + * + * Raised when notmuch is out of memory + */ + +/* + * Document-class: Notmuch::ReadOnlyError + * + * Raised when an attempt was made to write to a database opened in read-only + * mode. + */ + +/* + * Document-class: Notmuch::XapianError + * + * Raised when a Xapian exception occurs + */ + +/* + * Document-class: Notmuch::FileError + * + * Raised when an error occurs trying to read or write to a file. + */ + +/* + * Document-class: Notmuch::FileNotEmailError + * + * Raised when a file is presented that doesn't appear to be an email message. + */ + +/* + * Document-class: Notmuch::NullPointerError + * + * Raised when the user erroneously passes a +NULL+ pointer to a notmuch + * function. + */ + +/* + * Document-class: Notmuch::TagTooLongError + * + * Raised when a tag value is too long (exceeds Notmuch::TAG_MAX) + */ + +/* + * Document-class: Notmuch::UnbalancedFreezeThawError + * + * Raised when the notmuch_message_thaw function has been called more times + * than notmuch_message_freeze. + */ + +#define RDOC_HATE 1 + +void +Init_notmuch(void) +{ + VALUE mod; + + ID_call = rb_intern("call"); + ID_db_create = rb_intern("create"); + ID_db_mode = rb_intern("mode"); + + mod = rb_define_module("Notmuch"); + + rb_define_const(mod, "MODE_READ_ONLY", INT2FIX(NOTMUCH_DATABASE_MODE_READ_ONLY)); + rb_define_const(mod, "MODE_READ_WRITE", INT2FIX(NOTMUCH_DATABASE_MODE_READ_WRITE)); + rb_define_const(mod, "SORT_OLDEST_FIRST", INT2FIX(NOTMUCH_SORT_OLDEST_FIRST)); + rb_define_const(mod, "SORT_NEWEST_FIRST", INT2FIX(NOTMUCH_SORT_NEWEST_FIRST)); + rb_define_const(mod, "SORT_MESSAGE_ID", INT2FIX(NOTMUCH_SORT_MESSAGE_ID)); + rb_define_const(mod, "SORT_UNSORTED", INT2FIX(NOTMUCH_SORT_UNSORTED)); + rb_define_const(mod, "MESSAGE_FLAG_MATCH", INT2FIX(NOTMUCH_MESSAGE_FLAG_MATCH)); + rb_define_const(mod, "TAG_MAX", INT2FIX(NOTMUCH_TAG_MAX)); + + notmuch_rb_eBaseError = rb_define_class_under(mod, "BaseError", rb_eStandardError); + notmuch_rb_eDatabaseError = rb_define_class_under(mod, "DatabaseError", notmuch_rb_eBaseError); + notmuch_rb_eMemoryError = rb_define_class_under(mod, "MemoryError", notmuch_rb_eBaseError); + notmuch_rb_eReadOnlyError = rb_define_class_under(mod, "ReadOnlyError", notmuch_rb_eBaseError); + notmuch_rb_eXapianError = rb_define_class_under(mod, "XapianError", notmuch_rb_eBaseError); + notmuch_rb_eFileError = rb_define_class_under(mod, "FileError", notmuch_rb_eBaseError); + notmuch_rb_eFileNotEmailError = rb_define_class_under(mod, "FileNotEmailError", notmuch_rb_eBaseError); + notmuch_rb_eNullPointerError = rb_define_class_under(mod, "NullPointerError", notmuch_rb_eBaseError); + notmuch_rb_eTagTooLongError = rb_define_class_under(mod, "TagTooLongError", notmuch_rb_eBaseError); + notmuch_rb_eUnbalancedFreezeThawError = rb_define_class_under(mod, "UnbalancedFreezeThawError", + notmuch_rb_eBaseError); + + notmuch_rb_cDatabase = rb_define_class_under(mod, "Database", rb_cObject); + rb_define_singleton_method(notmuch_rb_cDatabase, "new", notmuch_rb_database_new, -1); + rb_define_method(notmuch_rb_cDatabase, "close", notmuch_rb_database_close, 0); + rb_define_method(notmuch_rb_cDatabase, "path", notmuch_rb_database_path, 0); + rb_define_method(notmuch_rb_cDatabase, "version", notmuch_rb_database_version, 0); + rb_define_method(notmuch_rb_cDatabase, "needs_upgrade?", notmuch_rb_database_needs_upgrade, 0); + rb_define_method(notmuch_rb_cDatabase, "upgrade!", notmuch_rb_database_upgrade, 0); + rb_define_method(notmuch_rb_cDatabase, "get_directory", notmuch_rb_database_get_directory, 1); + rb_define_method(notmuch_rb_cDatabase, "add_message", notmuch_rb_database_add_message, 1); + rb_define_method(notmuch_rb_cDatabase, "remove_message", notmuch_rb_database_remove_message, 1); + rb_define_method(notmuch_rb_cDatabase, "query", notmuch_rb_database_query_create, 1); + + notmuch_rb_cDirectory = rb_define_class_under(mod, "Directory", rb_cObject); + rb_undef_method(notmuch_rb_cDirectory, "initialize"); + rb_define_method(notmuch_rb_cDirectory, "mtime", notmuch_rb_directory_get_mtime, 0); + rb_define_method(notmuch_rb_cDirectory, "mtime=", notmuch_rb_directory_set_mtime, 1); + rb_define_method(notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); + rb_define_method(notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); + + notmuch_rb_cFileNames = rb_define_class_under(mod, "FileNames", rb_cObject); + rb_undef_method(notmuch_rb_cFileNames, "initialize"); + rb_define_method(notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); + rb_include_module(notmuch_rb_cFileNames, rb_mEnumerable); + + notmuch_rb_cQuery = rb_define_class_under(mod, "Query", rb_cObject); + rb_undef_method(notmuch_rb_cQuery, "initialize"); + rb_define_method(notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); + rb_define_method(notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); + rb_define_method(notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); + + notmuch_rb_cThreads = rb_define_class_under(mod, "Threads", rb_cObject); + rb_undef_method(notmuch_rb_cThreads, "initialize"); + rb_define_method(notmuch_rb_cThreads, "each", notmuch_rb_threads_each, 0); + rb_include_module(notmuch_rb_cThreads, rb_mEnumerable); + + notmuch_rb_cMessages = rb_define_class_under(mod, "Messages", rb_cObject); + rb_undef_method(notmuch_rb_cMessages, "initialize"); + rb_define_method(notmuch_rb_cMessages, "each", notmuch_rb_messages_each, 0); + rb_define_method(notmuch_rb_cMessages, "tags", notmuch_rb_messages_collect_tags, 0); + rb_include_module(notmuch_rb_cMessages, rb_mEnumerable); + + notmuch_rb_cThread = rb_define_class_under(mod, "Thread", rb_cObject); + rb_undef_method(notmuch_rb_cThread, "initialize"); + rb_define_method(notmuch_rb_cThread, "thread_id", notmuch_rb_thread_get_thread_id, 0); + rb_define_method(notmuch_rb_cThread, "total_messages", notmuch_rb_thread_get_total_messages, 0); + rb_define_method(notmuch_rb_cThread, "toplevel_messages", notmuch_rb_thread_get_toplevel_messages, 0); + rb_define_method(notmuch_rb_cThread, "matched_messages", notmuch_rb_thread_get_matched_messages, 0); + rb_define_method(notmuch_rb_cThread, "authors", notmuch_rb_thread_get_authors, 0); + rb_define_method(notmuch_rb_cThread, "subject", notmuch_rb_thread_get_subject, 0); + rb_define_method(notmuch_rb_cThread, "oldest_date", notmuch_rb_thread_get_oldest_date, 0); + rb_define_method(notmuch_rb_cThread, "newest_date", notmuch_rb_thread_get_newest_date, 0); + rb_define_method(notmuch_rb_cThread, "tags", notmuch_rb_thread_get_tags, 0); + + notmuch_rb_cMessage = rb_define_class_under(mod, "Message", rb_cObject); + rb_undef_method(notmuch_rb_cMessage, "initialize"); + rb_define_method(notmuch_rb_cMessage, "message_id", notmuch_rb_message_get_message_id, 0); + rb_define_method(notmuch_rb_cMessage, "thread_id", notmuch_rb_message_get_thread_id, 0); + rb_define_method(notmuch_rb_cMessage, "replies", notmuch_rb_message_get_replies, 0); + rb_define_method(notmuch_rb_cMessage, "filename", notmuch_rb_message_get_filename, 0); + rb_define_method(notmuch_rb_cMessage, "get_flag", notmuch_rb_message_get_flag, 1); + rb_define_method(notmuch_rb_cMessage, "set_flag", notmuch_rb_message_set_flag, 2); + rb_define_method(notmuch_rb_cMessage, "date", notmuch_rb_message_get_date, 0); + rb_define_method(notmuch_rb_cMessage, "header", notmuch_rb_message_get_header, 1); + rb_define_alias(notmuch_rb_cMessage, "[]", "header"); + rb_define_method(notmuch_rb_cMessage, "tags", notmuch_rb_message_get_tags, 0); + rb_define_method(notmuch_rb_cMessage, "add_tag", notmuch_rb_message_add_tag, 1); + rb_define_alias(notmuch_rb_cMessage, "<<", "add_tag"); + rb_define_method(notmuch_rb_cMessage, "remove_tag", notmuch_rb_message_remove_tag, 1); + rb_define_method(notmuch_rb_cMessage, "remove_all_tags", notmuch_rb_message_remove_all_tags, 0); + rb_define_method(notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); + rb_define_method(notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); + + notmuch_rb_cTags = rb_define_class_under(mod, "Tags", rb_cObject); + rb_undef_method(notmuch_rb_cTags, "initialize"); + rb_define_method(notmuch_rb_cTags, "each", notmuch_rb_tags_each, 0); + rb_include_module(notmuch_rb_cTags, rb_mEnumerable); +} diff --git a/bindings/ruby/message.c b/bindings/ruby/message.c new file mode 100644 index 00000000..6c7a0391 --- /dev/null +++ b/bindings/ruby/message.c @@ -0,0 +1,303 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: MESSAGE.message_id => String + * + * Get the message ID of 'message'. + */ +VALUE +notmuch_rb_message_get_message_id(VALUE self) +{ + const char *msgid; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + msgid = notmuch_message_get_message_id(message->nm_message); + return msgid ? rb_str_new2(msgid) : Qnil; +} + +/* + * call-seq: MESSAGE.thread_id => String + * + * Get the thread ID of 'message'. + */ +VALUE +notmuch_rb_message_get_thread_id(VALUE self) +{ + const char *tid; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + tid = notmuch_message_get_thread_id(message->nm_message); + return tid ? rb_str_new2(tid) : Qnil; +} + +/* + * call-seq: MESSAGE.replies => MESSAGES + * + * Get a Notmuch::Messages enumerable for all of the replies to 'message'. + */ +VALUE +notmuch_rb_message_get_replies(VALUE self) +{ + notmuch_rb_messages_t *messages; + notmuch_rb_message_t *message; + VALUE messagesv; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, + notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); + messages->nm_messages = notmuch_message_get_replies(message->nm_message); + messages->parent = self; + + return messages->nm_messages ? messagesv : Qnil; +} + +/* + * call-seq: MESSAGE.filename => String + * + * Get a filename for the email corresponding to 'message' + */ +VALUE +notmuch_rb_message_get_filename(VALUE self) +{ + const char *fname; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + fname = notmuch_message_get_filename(message->nm_message); + return fname ? rb_str_new2(fname) : Qnil; +} + +/* + * call-seq: MESSAGE.get_flag(flag) => true or false + * + * Get a value of a flag for the email corresponding to 'message' + */ +VALUE +notmuch_rb_message_get_flag(VALUE self, VALUE flagv) +{ + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + if (!FIXNUM_P(flagv)) + rb_raise(rb_eTypeError, "Flag not a Fixnum"); + + return notmuch_message_get_flag(message->nm_message, FIX2INT(flagv)) ? Qtrue : Qfalse; +} + +/* + * call-seq: MESSAGE.set_flag(flag, value) => nil + * + * Set a value of a flag for the email corresponding to 'message' + */ +VALUE +notmuch_rb_message_set_flag(VALUE self, VALUE flagv, VALUE valuev) +{ + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + if (!FIXNUM_P(flagv)) + rb_raise(rb_eTypeError, "Flag not a Fixnum"); + + notmuch_message_set_flag(message->nm_message, FIX2INT(flagv), RTEST(valuev)); + return Qnil; +} + +/* + * call-seq: MESSAGE.date => Fixnum + * + * Get the date of 'message' + */ +VALUE +notmuch_rb_message_get_date(VALUE self) +{ + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + return UINT2NUM(notmuch_message_get_date(message->nm_message)); +} + +/* + * call-seq: MESSAGE.header(name) => String + * + * Get the value of the specified header from 'message' + */ +VALUE +notmuch_rb_message_get_header(VALUE self, VALUE headerv) +{ + const char *header, *value; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(headerv); + header = RSTRING_PTR(headerv); + + value = notmuch_message_get_header(message->nm_message, header); + if (!value) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return rb_str_new2(value); +} + +/* + * call-seq: MESSAGE.tags => TAGS + * + * Get a Notmuch::Tags enumerable for all of the tags of 'message'. + */ +VALUE +notmuch_rb_message_get_tags(VALUE self) +{ + notmuch_rb_message_t *message; + notmuch_rb_tags_t *tags; + VALUE tagsv; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, + notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); + tags->nm_tags = notmuch_message_get_tags(message->nm_message); + tags->parent = self; + if (!tags->nm_tags) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return tagsv; +} + +/* + * call-seq: MESSAGE.add_tag(tag) => true + * + * Add a tag to the 'message' + */ +VALUE +notmuch_rb_message_add_tag(VALUE self, VALUE tagv) +{ + const char *tag; + notmuch_status_t ret; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(tagv); + tag = RSTRING_PTR(tagv); + + ret = notmuch_message_add_tag(message->nm_message, tag); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: MESSAGE.remove_tag(tag) => true + * + * Remove a tag from the 'message' + */ +VALUE +notmuch_rb_message_remove_tag(VALUE self, VALUE tagv) +{ + const char *tag; + notmuch_status_t ret; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + +#if !defined(RSTRING_PTR) +#define RSTRING_PTR(v) (RSTRING((v))->ptr) +#endif /* !defined(RSTRING_PTR) */ + + SafeStringValue(tagv); + tag = RSTRING_PTR(tagv); + + ret = notmuch_message_remove_tag(message->nm_message, tag); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: MESSAGE.remove_all_tags => true + * + * Remove all tags of the 'message' + */ +VALUE +notmuch_rb_message_remove_all_tags(VALUE self) +{ + notmuch_status_t ret; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + ret = notmuch_message_remove_all_tags(message->nm_message); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: MESSAGE.freeze => true + * + * Freeze the 'message' + */ +VALUE +notmuch_rb_message_freeze(VALUE self) +{ + notmuch_status_t ret; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + ret = notmuch_message_freeze(message->nm_message); + notmuch_rb_status_raise(ret); + return Qtrue; +} + +/* + * call-seq: MESSAGE.thaw => true + * + * Thaw a 'message' + */ +VALUE +notmuch_rb_message_thaw(VALUE self) +{ + notmuch_status_t ret; + notmuch_rb_message_t *message; + + Data_Get_Struct(self, notmuch_rb_message_t, message); + + ret = notmuch_message_thaw(message->nm_message); + notmuch_rb_status_raise(ret); + return Qtrue; +} diff --git a/bindings/ruby/messages.c b/bindings/ruby/messages.c new file mode 100644 index 00000000..6b296b32 --- /dev/null +++ b/bindings/ruby/messages.c @@ -0,0 +1,74 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* call-seq: MESSAGES.each {|item| block } => MESSAGES + * + * Calls +block+ once for each message in +self+, passing that element as a + * parameter. + */ +VALUE +notmuch_rb_messages_each(VALUE self) +{ + notmuch_rb_message_t *message; + notmuch_rb_messages_t *messages; + VALUE messagev; + + Data_Get_Struct(self, notmuch_rb_messages_t, messages); + if (!messages->nm_messages) + return self; + + for (; notmuch_messages_valid(messages->nm_messages); + notmuch_messages_move_to_next(messages->nm_messages)) + { + messagev = Data_Make_Struct(notmuch_rb_cMessage, notmuch_rb_message_t, + notmuch_rb_message_mark, notmuch_rb_message_free, message); + message->nm_message = notmuch_messages_get(messages->nm_messages); + message->parent = self; + rb_yield(messagev); + } + + return self; +} + +/* + * call-seq: MESSAGES.tags => TAGS + * + * Collect tags from the messages + */ +VALUE +notmuch_rb_messages_collect_tags(VALUE self) +{ + notmuch_rb_tags_t *tags; + notmuch_rb_messages_t *messages; + VALUE tagsv; + + Data_Get_Struct(self, notmuch_rb_messages_t, messages); + + tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, + notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); + tags->nm_tags = notmuch_messages_collect_tags(messages->nm_messages); + tags->parent = self; + if (!tags->nm_tags) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return tagsv; +} diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c new file mode 100644 index 00000000..50edf170 --- /dev/null +++ b/bindings/ruby/query.c @@ -0,0 +1,88 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: QUERY.sort=(fixnum) => nil + * + * Set sort type of the +QUERY+ + */ +VALUE +notmuch_rb_query_set_sort(VALUE self, VALUE sortv) +{ + notmuch_rb_query_t *query; + + Data_Get_Struct(self, notmuch_rb_query_t, query); + + if (!FIXNUM_P(sortv)) + rb_raise(rb_eTypeError, "Not a fixnum"); + + notmuch_query_set_sort(query->nm_query, FIX2UINT(sortv)); + return Qnil; +} + +/* + * call-seq: QUERY.search_threads => THREADS + * + * Search for threads + */ +VALUE +notmuch_rb_query_search_threads(VALUE self) +{ + notmuch_rb_query_t *query; + notmuch_rb_threads_t *threads; + VALUE threadsv; + + Data_Get_Struct(self, notmuch_rb_query_t, query); + + threadsv = Data_Make_Struct(notmuch_rb_cThreads, notmuch_rb_threads_t, + notmuch_rb_threads_mark, notmuch_rb_threads_free, threads); + threads->nm_threads = notmuch_query_search_threads(query->nm_query); + threads->query = self; + if (!threads->nm_threads) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return threadsv; +} + +/* + * call-seq: QUERY.search_messages => MESSAGES + * + * Search for messages + */ +VALUE +notmuch_rb_query_search_messages(VALUE self) +{ + notmuch_rb_query_t *query; + notmuch_rb_messages_t *messages; + VALUE messagesv; + + Data_Get_Struct(self, notmuch_rb_query_t, query); + + messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, + notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); + messages->nm_messages = notmuch_query_search_messages(query->nm_query); + messages->parent = self; + if (!messages->nm_messages) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return messagesv; +} diff --git a/bindings/ruby/rdoc.sh b/bindings/ruby/rdoc.sh new file mode 100755 index 00000000..0e86818a --- /dev/null +++ b/bindings/ruby/rdoc.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# vim: set sw=4 et sts=4 tw=80 : + +# RDoc fails to document C extension split into many files. +# This is a hack to generate documentation properly. + +rm -fr ruby +cat *.c > rdoc-sucks.c +rdoc --main 'Notmuch' --title 'Notmuch Ruby API' --op ruby rdoc-sucks.c +rm -f rdoc-sucks.c diff --git a/bindings/ruby/status.c b/bindings/ruby/status.c new file mode 100644 index 00000000..3d106ca9 --- /dev/null +++ b/bindings/ruby/status.c @@ -0,0 +1,49 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +void +notmuch_rb_status_raise(notmuch_status_t status) +{ + switch (status) { + case NOTMUCH_STATUS_SUCCESS: + case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: + break; + case NOTMUCH_STATUS_OUT_OF_MEMORY: + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + case NOTMUCH_STATUS_READ_ONLY_DATABASE: + rb_raise(notmuch_rb_eReadOnlyError, "read-only database"); + case NOTMUCH_STATUS_XAPIAN_EXCEPTION: + rb_raise(notmuch_rb_eXapianError, "xapian exception"); + case NOTMUCH_STATUS_FILE_ERROR: + rb_raise(notmuch_rb_eFileError, "failed to read/write file"); + case NOTMUCH_STATUS_FILE_NOT_EMAIL: + rb_raise(notmuch_rb_eFileNotEmailError, "file not email"); + case NOTMUCH_STATUS_NULL_POINTER: + rb_raise(notmuch_rb_eNullPointerError, "null pointer"); + case NOTMUCH_STATUS_TAG_TOO_LONG: + rb_raise(notmuch_rb_eTagTooLongError, "tag too long"); + case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW: + rb_raise(notmuch_rb_eUnbalancedFreezeThawError, "unbalanced freeze/thaw"); + default: + rb_raise(notmuch_rb_eBaseError, "unknown notmuch error"); + } +} diff --git a/bindings/ruby/tags.c b/bindings/ruby/tags.c new file mode 100644 index 00000000..d0a5054a --- /dev/null +++ b/bindings/ruby/tags.c @@ -0,0 +1,46 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: TAGS.each {|item| block } => TAGS + * + * Calls +block+ once for each element in +self+, passing that element as a + * parameter. + */ +VALUE +notmuch_rb_tags_each(VALUE self) +{ + const char *tag; + notmuch_rb_tags_t *tags; + + Data_Get_Struct(self, notmuch_rb_tags_t, tags); + if (!tags->nm_tags) + return self; + + for (; notmuch_tags_valid(tags->nm_tags); + notmuch_tags_move_to_next(tags->nm_tags)) { + tag = notmuch_tags_get(tags->nm_tags); + rb_yield(tag ? rb_str_new2(tag) : Qnil); + } + + return self; +} diff --git a/bindings/ruby/thread.c b/bindings/ruby/thread.c new file mode 100644 index 00000000..72a86b8f --- /dev/null +++ b/bindings/ruby/thread.c @@ -0,0 +1,180 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* + * call-seq: THREAD.thread_id => String + * + * Returns the thread id + */ +VALUE +notmuch_rb_thread_get_thread_id(VALUE self) +{ + const char *tid; + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + tid = notmuch_thread_get_thread_id(thread->nm_thread); + return tid ? rb_str_new2(tid) : Qnil; +} + +/* + * call-seq: THREAD.total_messages => fixnum + * + * Returns the number of total messages + */ +VALUE +notmuch_rb_thread_get_total_messages(VALUE self) +{ + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + return INT2FIX(notmuch_thread_get_total_messages(thread->nm_thread)); +} + +/* + * call-seq: THREAD.toplevel_messages => MESSAGES + * + * Get a Notmuch::Messages iterator for the top level messages in thread. + */ +VALUE +notmuch_rb_thread_get_toplevel_messages(VALUE self) +{ + notmuch_rb_messages_t *messages; + notmuch_rb_thread_t *thread; + VALUE messagesv; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, + notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); + messages->nm_messages = notmuch_thread_get_toplevel_messages(thread->nm_thread); + messages->parent = self; + if (!messages->nm_messages) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return messagesv; +} + +/* + * call-seq: THREAD.matched_messages => fixnum + * + * Get the number of messages in thread that matched the search + */ +VALUE +notmuch_rb_thread_get_matched_messages(VALUE self) +{ + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + return INT2FIX(notmuch_thread_get_matched_messages(thread->nm_thread)); +} + +/* + * call-seq: THREAD.authors => String + * + * Get a comma-separated list of the names of the authors. + */ +VALUE +notmuch_rb_thread_get_authors(VALUE self) +{ + const char *authors; + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + authors = notmuch_thread_get_authors(thread->nm_thread); + return authors ? rb_str_new2(authors) : Qnil; +} + +/* + * call-seq: THREAD.subject => String + * + * Returns the subject of the thread + */ +VALUE +notmuch_rb_thread_get_subject(VALUE self) +{ + const char *subject; + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + subject = notmuch_thread_get_subject(thread->nm_thread); + return subject ? rb_str_new2(subject) : Qnil; +} + +/* + * call-seq: THREAD.oldest_date => Fixnum + * + * Get the date of the oldest message in thread. + */ +VALUE +notmuch_rb_thread_get_oldest_date(VALUE self) +{ + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + return UINT2NUM(notmuch_thread_get_oldest_date(thread->nm_thread)); +} + +/* + * call-seq: THREAD.newest_date => fixnum + * + * Get the date of the newest message in thread. + */ +VALUE +notmuch_rb_thread_get_newest_date(VALUE self) +{ + notmuch_rb_thread_t *thread; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + return UINT2NUM(notmuch_thread_get_newest_date(thread->nm_thread)); +} + +/* + * call-seq: THREAD.tags => TAGS + * + * Get a Notmuch::Tags iterator for the tags of the thread + */ +VALUE +notmuch_rb_thread_get_tags(VALUE self) +{ + notmuch_rb_thread_t *thread; + notmuch_rb_tags_t *tags; + VALUE tagsv; + + Data_Get_Struct(self, notmuch_rb_thread_t, thread); + + tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, + notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); + tags->nm_tags = notmuch_thread_get_tags(thread->nm_thread); + tags->parent = self; + if (!tags->nm_tags) + rb_raise(notmuch_rb_eMemoryError, "out of memory"); + + return tagsv; +} diff --git a/bindings/ruby/threads.c b/bindings/ruby/threads.c new file mode 100644 index 00000000..cee6afbe --- /dev/null +++ b/bindings/ruby/threads.c @@ -0,0 +1,50 @@ +/* The Ruby interface to the notmuch mail library + * + * Copyright © 2010 Ali Polatel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ . + * + * Author: Ali Polatel + */ + +#include "defs.h" + +/* call-seq: THREADS.each {|item| block } => THREADS + * + * Calls +block+ once for each thread in +self+, passing that element as a + * parameter. + */ +VALUE +notmuch_rb_threads_each(VALUE self) +{ + notmuch_rb_thread_t *thread; + notmuch_rb_threads_t *threads; + VALUE threadv; + + Data_Get_Struct(self, notmuch_rb_threads_t, threads); + if (!threads->nm_threads) + return self; + + for (; notmuch_threads_valid(threads->nm_threads); + notmuch_threads_move_to_next(threads->nm_threads)) + { + threadv = Data_Make_Struct(notmuch_rb_cThread, notmuch_rb_thread_t, + notmuch_rb_thread_mark, notmuch_rb_thread_free, thread); + thread->nm_thread = notmuch_threads_get(threads->nm_threads); + thread->threads = self; + rb_yield(threadv); + } + + return self; +} From 8312e7efeabd5883fe84ef9d38b316ecaa5b4793 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Sun, 23 May 2010 11:42:52 +0300 Subject: [PATCH 2/6] ruby: fix documentation of DB.upgrade! --- bindings/ruby/database.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index 44ee6817..fae5af28 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -156,7 +156,7 @@ notmuch_rb_upgrade_notify(void *closure, double progress) } /* - * call-seq: DB.upgrade [{|progress| block }] => nil + * call-seq: DB.upgrade! [{|progress| block }] => nil * * Upgrade the database. * From 35925e6e5be58ca33d8f40f1d6ec44b4e7799713 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Mon, 24 May 2010 19:17:04 +0300 Subject: [PATCH 3/6] ruby: First attempt at fixing gc for ruby-1.9 --- bindings/ruby/gc.c | 54 +++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/bindings/ruby/gc.c b/bindings/ruby/gc.c index 3b515905..37b089f4 100644 --- a/bindings/ruby/gc.c +++ b/bindings/ruby/gc.c @@ -39,7 +39,7 @@ _notmuch_rb_message_db(notmuch_rb_message_t *message) db = _notmuch_rb_messages_db(messages); } else - rb_bug("message's parent is neither database nor messages"); + db = NULL; return db; } @@ -68,7 +68,7 @@ _notmuch_rb_messages_db(notmuch_rb_messages_t *messages) db = _notmuch_rb_message_db(message); } else - rb_bug("messages' parent is neither query nor thread nor message"); + db = NULL; return db; } @@ -107,9 +107,12 @@ notmuch_rb_directory_free(notmuch_rb_directory_t *dir) { notmuch_rb_database_t *db; - Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + if (rb_obj_is_instance_of(dir->db, notmuch_rb_cDatabase)) + Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + else + db = NULL; - if (db->nm_db && dir->nm_dir) + if (db && db->nm_db && dir->nm_dir) notmuch_directory_destroy(dir->nm_dir); free(dir); @@ -127,10 +130,17 @@ notmuch_rb_filenames_free(notmuch_rb_filenames_t *flist) notmuch_rb_directory_t *dir; notmuch_rb_database_t *db; - Data_Get_Struct(flist->dir, notmuch_rb_directory_t, dir); - Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + if (rb_obj_is_instance_of(flist->dir, notmuch_rb_cDirectory)) { + Data_Get_Struct(flist->dir, notmuch_rb_directory_t, dir); + if (rb_obj_is_instance_of(dir->db, notmuch_rb_cDatabase)) + Data_Get_Struct(dir->db, notmuch_rb_database_t, db); + else + db = NULL; + } + else + db = NULL; - if (db->nm_db && flist->nm_flist) + if (db && db->nm_db && flist->nm_flist) notmuch_filenames_destroy(flist->nm_flist); free(flist); @@ -147,9 +157,12 @@ notmuch_rb_query_free(notmuch_rb_query_t *query) { notmuch_rb_database_t *db; - Data_Get_Struct(query->db, notmuch_rb_database_t, db); + if (rb_obj_is_instance_of(query->db, notmuch_rb_cDatabase)) + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + else + db = NULL; - if (db->nm_db && query->nm_query) + if (db && db->nm_db && query->nm_query) notmuch_query_destroy(query->nm_query); free(query); @@ -167,10 +180,17 @@ notmuch_rb_threads_free(notmuch_rb_threads_t *threads) notmuch_rb_query_t *query; notmuch_rb_database_t *db; - Data_Get_Struct(threads->query, notmuch_rb_query_t, query); - Data_Get_Struct(query->db, notmuch_rb_database_t, db); + if (rb_obj_is_instance_of(threads->query, notmuch_rb_cQuery)) { + Data_Get_Struct(threads->query, notmuch_rb_query_t, query); + if (rb_obj_is_instance_of(query->db, notmuch_rb_cDatabase)) + Data_Get_Struct(query->db, notmuch_rb_database_t, db); + else + db = NULL; + } + else + db = NULL; - if (db->nm_db && threads->nm_threads) + if (db && db->nm_db && threads->nm_threads) notmuch_threads_destroy(threads->nm_threads); free(threads); @@ -189,7 +209,7 @@ notmuch_rb_messages_free(notmuch_rb_messages_t *messages) db = _notmuch_rb_messages_db(messages); - if (db->nm_db && messages->nm_messages) + if (db && db->nm_db && messages->nm_messages) notmuch_messages_destroy(messages->nm_messages); free(messages); @@ -208,7 +228,7 @@ notmuch_rb_thread_free(notmuch_rb_thread_t *thread) db = _notmuch_rb_thread_db(thread); - if (db->nm_db && thread->nm_thread) + if (db && db->nm_db && thread->nm_thread) notmuch_thread_destroy(thread->nm_thread); free(thread); @@ -226,7 +246,7 @@ notmuch_rb_message_free(notmuch_rb_message_t *message) notmuch_rb_database_t *db; db = _notmuch_rb_message_db(message); - if (db->nm_db && message->nm_message) + if (db && db->nm_db && message->nm_message) notmuch_message_destroy(message->nm_message); free(message); @@ -259,9 +279,9 @@ notmuch_rb_tags_free(notmuch_rb_tags_t *tags) db = _notmuch_rb_messages_db(messages); } else - rb_bug("tags' parent is neither thread nor message nor messages"); + return; - if (db->nm_db && tags->nm_tags) + if (db && db->nm_db && tags->nm_tags) notmuch_tags_destroy(tags->nm_tags); free(tags); From c7893408bbe6904ae7da97aa203587af4ec2fac7 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Wed, 26 May 2010 18:54:25 +0300 Subject: [PATCH 4/6] ruby: Kill garbage collection related cruft. Let the user destroy objects that she wants explicitly. It's not possible to specify the order objects are garbage collected. See id:86y6f8v838.fsf@harikalardiyari.ev on ruby-talk for more information. --- bindings/ruby/database.c | 118 ++++++---------- bindings/ruby/defs.h | 120 ++++------------ bindings/ruby/directory.c | 58 ++++---- bindings/ruby/filenames.c | 28 +++- bindings/ruby/gc.c | 288 -------------------------------------- bindings/ruby/init.c | 8 ++ bindings/ruby/message.c | 138 ++++++++++-------- bindings/ruby/messages.c | 55 ++++---- bindings/ruby/query.c | 60 ++++---- bindings/ruby/tags.c | 30 +++- bindings/ruby/thread.c | 104 ++++++++------ bindings/ruby/threads.c | 38 +++-- 12 files changed, 383 insertions(+), 662 deletions(-) delete mode 100644 bindings/ruby/gc.c diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index fae5af28..e767819b 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -32,8 +32,8 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) { const char *path; int create, mode; - notmuch_rb_database_t *db; - VALUE modev, dbv; + notmuch_database_t *db; + VALUE modev; #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -70,12 +70,11 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) mode = NOTMUCH_DATABASE_MODE_READ_ONLY; } - dbv = Data_Make_Struct(klass, notmuch_rb_database_t, NULL, notmuch_rb_database_free, db); - db->nm_db = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); - if (!db->nm_db) + db = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); + if (!db) rb_raise(notmuch_rb_eDatabaseError, "failed to open database"); - return dbv; + return Data_Wrap_Struct(klass, NULL, NULL, db); } /* @@ -86,13 +85,10 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) VALUE notmuch_rb_database_close(VALUE self) { - notmuch_rb_database_t *db; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (db->nm_db) { - notmuch_database_close(db->nm_db); - db->nm_db = NULL; - } + Data_Get_Struct(self, notmuch_database_t, db); + notmuch_database_close(db); return Qnil; } @@ -105,13 +101,11 @@ notmuch_rb_database_close(VALUE self) VALUE notmuch_rb_database_path(VALUE self) { - notmuch_rb_database_t *db; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); - return rb_str_new2(notmuch_database_get_path(db->nm_db)); + return rb_str_new2(notmuch_database_get_path(db)); } /* @@ -122,13 +116,11 @@ notmuch_rb_database_path(VALUE self) VALUE notmuch_rb_database_version(VALUE self) { - notmuch_rb_database_t *db; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); - return INT2FIX(notmuch_database_get_version(db->nm_db)); + return INT2FIX(notmuch_database_get_version(db)); } /* @@ -139,13 +131,11 @@ notmuch_rb_database_version(VALUE self) VALUE notmuch_rb_database_needs_upgrade(VALUE self) { - notmuch_rb_database_t *db; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); - return notmuch_database_needs_upgrade(db->nm_db) ? Qtrue : Qfalse; + return notmuch_database_needs_upgrade(db) ? Qtrue : Qfalse; } static void @@ -168,12 +158,10 @@ notmuch_rb_database_upgrade(VALUE self) { notmuch_status_t ret; void (*pnotify) (void *closure, double progress); - notmuch_rb_database_t *db; + notmuch_database_t *db; VALUE block; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); if (rb_block_given_p()) { pnotify = notmuch_rb_upgrade_notify; @@ -182,8 +170,9 @@ notmuch_rb_database_upgrade(VALUE self) else pnotify = NULL; - ret = notmuch_database_upgrade(db->nm_db, pnotify, pnotify ? &block : NULL); + ret = notmuch_database_upgrade(db, pnotify, pnotify ? &block : NULL); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -196,13 +185,10 @@ VALUE notmuch_rb_database_get_directory(VALUE self, VALUE pathv) { const char *path; - notmuch_rb_directory_t *dir; - notmuch_rb_database_t *db; - VALUE dirv; + notmuch_directory_t *dir; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -211,20 +197,18 @@ notmuch_rb_database_get_directory(VALUE self, VALUE pathv) SafeStringValue(pathv); path = RSTRING_PTR(pathv); - dirv = Data_Make_Struct(notmuch_rb_cDirectory, notmuch_rb_directory_t, - notmuch_rb_directory_mark, notmuch_rb_directory_free, dir); - dir->nm_dir = notmuch_database_get_directory(db->nm_db, path); - dir->db = self; - if (!dir->nm_dir) + dir = notmuch_database_get_directory(db, path); + if (!dir) rb_raise(notmuch_rb_eXapianError, "Xapian exception"); - return dirv; + return Data_Wrap_Struct(notmuch_rb_cDirectory, NULL, NULL, dir); } /* * call-seq: DB.add_message(path) => MESSAGE, isdup * - * Add a message to the database and return it + * Add a message to the database and return it. + * * +isdup+ is a boolean that specifies whether the added message was a * duplicate. */ @@ -233,13 +217,10 @@ notmuch_rb_database_add_message(VALUE self, VALUE pathv) { const char *path; notmuch_status_t ret; - notmuch_rb_message_t *message; - notmuch_rb_database_t *db; - VALUE messagev; + notmuch_message_t *message; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -248,18 +229,17 @@ notmuch_rb_database_add_message(VALUE self, VALUE pathv) SafeStringValue(pathv); path = RSTRING_PTR(pathv); - messagev = Data_Make_Struct(notmuch_rb_cMessage, notmuch_rb_message_t, - notmuch_rb_message_mark, notmuch_rb_message_free, message); - ret = notmuch_database_add_message(db->nm_db, path, &message->nm_message); - message->parent = self; + ret = notmuch_database_add_message(db, path, &message); notmuch_rb_status_raise(ret); - return rb_assoc_new(messagev, (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse); + return rb_assoc_new(Data_Wrap_Struct(notmuch_rb_cMessage, NULL, NULL, message), + (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse); } /* * call-seq: DB.remove_message(path) => isdup * * Remove a message from the database. + * * +isdup+ is a boolean that specifies whether the removed message was a * duplicate. */ @@ -268,11 +248,9 @@ notmuch_rb_database_remove_message(VALUE self, VALUE pathv) { const char *path; notmuch_status_t ret; - notmuch_rb_database_t *db; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -281,7 +259,7 @@ notmuch_rb_database_remove_message(VALUE self, VALUE pathv) SafeStringValue(pathv); path = RSTRING_PTR(pathv); - ret = notmuch_database_remove_message(db->nm_db, path); + ret = notmuch_database_remove_message(db, path); notmuch_rb_status_raise(ret); return (ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) ? Qtrue : Qfalse; } @@ -295,13 +273,10 @@ VALUE notmuch_rb_database_query_create(VALUE self, VALUE qstrv) { const char *qstr; - notmuch_rb_query_t *query; - notmuch_rb_database_t *db; - VALUE queryv; + notmuch_query_t *query; + notmuch_database_t *db; - Data_Get_Struct(self, notmuch_rb_database_t, db); - if (!db->nm_db) - rb_raise(rb_eRuntimeError, "Database closed"); + Data_Get_Struct(self, notmuch_database_t, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -310,12 +285,9 @@ notmuch_rb_database_query_create(VALUE self, VALUE qstrv) SafeStringValue(qstrv); qstr = RSTRING_PTR(qstrv); - queryv = Data_Make_Struct(notmuch_rb_cQuery, notmuch_rb_query_t, - notmuch_rb_query_mark, notmuch_rb_query_free, query); - query->nm_query = notmuch_query_create(db->nm_db, qstr); - query->db = self; - if (!query->nm_query) + query = notmuch_query_create(db, qstr); + if (!query) rb_raise(notmuch_rb_eMemoryError, "out of memory"); - return queryv; + return Data_Wrap_Struct(notmuch_rb_cQuery, NULL, NULL, query); } diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index 1973d26e..f36b7227 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -49,106 +49,10 @@ ID ID_call; ID ID_db_create; ID ID_db_mode; -typedef struct { - notmuch_database_t *nm_db; -} notmuch_rb_database_t; - -typedef struct { - notmuch_directory_t *nm_dir; - VALUE db; -} notmuch_rb_directory_t; - -typedef struct { - notmuch_filenames_t *nm_flist; - VALUE dir; -} notmuch_rb_filenames_t; - -typedef struct { - notmuch_query_t *nm_query; - VALUE db; -} notmuch_rb_query_t; - -typedef struct { - notmuch_threads_t *nm_threads; - VALUE query; -} notmuch_rb_threads_t; - -typedef struct { - notmuch_messages_t *nm_messages; - VALUE parent; -} notmuch_rb_messages_t; - -typedef struct { - notmuch_thread_t *nm_thread; - VALUE threads; -} notmuch_rb_thread_t; - -typedef struct { - notmuch_message_t *nm_message; - VALUE parent; -} notmuch_rb_message_t; - -typedef struct { - notmuch_tags_t *nm_tags; - VALUE parent; -} notmuch_rb_tags_t; - /* status.c */ void notmuch_rb_status_raise(notmuch_status_t status); -/* gc.c */ -void -notmuch_rb_database_free(notmuch_rb_database_t *db); - -void -notmuch_rb_directory_mark(notmuch_rb_directory_t *dir); - -void -notmuch_rb_directory_free(notmuch_rb_directory_t *dir); - -void -notmuch_rb_filenames_mark(notmuch_rb_filenames_t *flist); - -void -notmuch_rb_filenames_free(notmuch_rb_filenames_t *flist); - -void -notmuch_rb_query_mark(notmuch_rb_query_t *query); - -void -notmuch_rb_query_free(notmuch_rb_query_t *query); - -void -notmuch_rb_threads_mark(notmuch_rb_threads_t *threads); - -void -notmuch_rb_threads_free(notmuch_rb_threads_t *threads); - -void -notmuch_rb_messages_mark(notmuch_rb_messages_t *messages); - -void -notmuch_rb_messages_free(notmuch_rb_messages_t *messages); - -void -notmuch_rb_thread_mark(notmuch_rb_thread_t *thread); - -void -notmuch_rb_thread_free(notmuch_rb_thread_t *thread); - -void -notmuch_rb_message_mark(notmuch_rb_message_t *message); - -void -notmuch_rb_message_free(notmuch_rb_message_t *message); - -void -notmuch_rb_tags_mark(notmuch_rb_tags_t *tags); - -void -notmuch_rb_tags_free(notmuch_rb_tags_t *tags); - /* database.c */ VALUE notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass); @@ -181,6 +85,9 @@ VALUE notmuch_rb_database_query_create(VALUE self, VALUE qstrv); /* directory.c */ +VALUE +notmuch_rb_directory_destroy(VALUE self); + VALUE notmuch_rb_directory_get_mtime(VALUE self); @@ -194,10 +101,16 @@ VALUE notmuch_rb_directory_get_child_directories(VALUE self); /* filenames.c */ +VALUE +notmuch_rb_filenames_destroy(VALUE self); + VALUE notmuch_rb_filenames_each(VALUE self); /* query.c */ +VALUE +notmuch_rb_query_destroy(VALUE self); + VALUE notmuch_rb_query_set_sort(VALUE self, VALUE sortv); @@ -208,10 +121,16 @@ VALUE notmuch_rb_query_search_messages(VALUE self); /* threads.c */ +VALUE +notmuch_rb_threads_destroy(VALUE self); + VALUE notmuch_rb_threads_each(VALUE self); /* messages.c */ +VALUE +notmuch_rb_messages_destroy(VALUE self); + VALUE notmuch_rb_messages_each(VALUE self); @@ -219,6 +138,9 @@ VALUE notmuch_rb_messages_collect_tags(VALUE self); /* thread.c */ +VALUE +notmuch_rb_thread_destroy(VALUE self); + VALUE notmuch_rb_thread_get_thread_id(VALUE self); @@ -247,6 +169,9 @@ VALUE notmuch_rb_thread_get_tags(VALUE self); /* message.c */ +VALUE +notmuch_rb_message_destroy(VALUE self); + VALUE notmuch_rb_message_get_message_id(VALUE self); @@ -290,6 +215,9 @@ VALUE notmuch_rb_message_thaw(VALUE self); /* tags.c */ +VALUE +notmuch_rb_tags_destroy(VALUE self); + VALUE notmuch_rb_tags_each(VALUE self); diff --git a/bindings/ruby/directory.c b/bindings/ruby/directory.c index 46fe11cf..e73658c1 100644 --- a/bindings/ruby/directory.c +++ b/bindings/ruby/directory.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: DIR.destroy => nil + * + * Destroys the directory, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_directory_destroy(VALUE self) +{ + notmuch_directory_t *dir; + + Data_Get_Struct(self, notmuch_directory_t, dir); + + notmuch_directory_destroy(dir); + + return Qnil; +} + /* * call-seq: DIR.mtime => fixnum * @@ -29,11 +46,11 @@ VALUE notmuch_rb_directory_get_mtime(VALUE self) { - notmuch_rb_directory_t *dir; + notmuch_directory_t *dir; - Data_Get_Struct(self, notmuch_rb_directory_t, dir); + Data_Get_Struct(self, notmuch_directory_t, dir); - return UINT2NUM(notmuch_directory_get_mtime(dir->nm_dir)); + return UINT2NUM(notmuch_directory_get_mtime(dir)); } /* @@ -45,15 +62,16 @@ VALUE notmuch_rb_directory_set_mtime(VALUE self, VALUE mtimev) { notmuch_status_t ret; - notmuch_rb_directory_t *dir; + notmuch_directory_t *dir; - Data_Get_Struct(self, notmuch_rb_directory_t, dir); + Data_Get_Struct(self, notmuch_directory_t, dir); if (!FIXNUM_P(mtimev)) rb_raise(rb_eTypeError, "First argument not a fixnum"); - ret = notmuch_directory_set_mtime(dir->nm_dir, FIX2UINT(mtimev)); + ret = notmuch_directory_set_mtime(dir, FIX2UINT(mtimev)); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -66,18 +84,14 @@ notmuch_rb_directory_set_mtime(VALUE self, VALUE mtimev) VALUE notmuch_rb_directory_get_child_files(VALUE self) { - notmuch_rb_directory_t *dir; - notmuch_rb_filenames_t *flist; - VALUE flistv; + notmuch_directory_t *dir; + notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_rb_directory_t, dir); + Data_Get_Struct(self, notmuch_directory_t, dir); - flistv = Data_Make_Struct(notmuch_rb_cFileNames, notmuch_rb_filenames_t, - notmuch_rb_filenames_mark, notmuch_rb_filenames_free, flist); - flist->dir = self; - flist->nm_flist = notmuch_directory_get_child_files(dir->nm_dir); + fnames = notmuch_directory_get_child_files(dir); - return flistv; + return Data_Wrap_Struct(notmuch_rb_cFileNames, NULL, NULL, fnames); } /* @@ -89,16 +103,12 @@ notmuch_rb_directory_get_child_files(VALUE self) VALUE notmuch_rb_directory_get_child_directories(VALUE self) { - notmuch_rb_directory_t *dir; - notmuch_rb_filenames_t *flist; - VALUE flistv; + notmuch_directory_t *dir; + notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_rb_directory_t, dir); + Data_Get_Struct(self, notmuch_directory_t, dir); - flistv = Data_Make_Struct(notmuch_rb_cFileNames, notmuch_rb_filenames_t, - notmuch_rb_filenames_mark, notmuch_rb_filenames_free, flist); - flist->dir = self; - flist->nm_flist = notmuch_directory_get_child_directories(dir->nm_dir); + fnames = notmuch_directory_get_child_directories(dir); - return flistv; + return Data_Wrap_Struct(notmuch_rb_cFileNames, NULL, NULL, fnames); } diff --git a/bindings/ruby/filenames.c b/bindings/ruby/filenames.c index 44a16522..23553ab1 100644 --- a/bindings/ruby/filenames.c +++ b/bindings/ruby/filenames.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: FILENAMES.destroy => nil + * + * Destroys the filenames, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_filenames_destroy(VALUE self) +{ + notmuch_filenames_t *fnames; + + Data_Get_Struct(self, notmuch_filenames_t, fnames); + + notmuch_filenames_destroy(fnames); + + return Qnil; +} + /* * call-seq: FILENAMES.each {|item| block } => FILENAMES * @@ -29,15 +46,14 @@ VALUE notmuch_rb_filenames_each(VALUE self) { - notmuch_rb_filenames_t *flist; + notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_rb_filenames_t, flist); - if (!flist->nm_flist) + Data_Get_Struct(self, notmuch_filenames_t, fnames); + if (!fnames) return self; - for (; notmuch_filenames_valid(flist->nm_flist); - notmuch_filenames_move_to_next(flist->nm_flist)) - rb_yield(rb_str_new2(notmuch_filenames_get(flist->nm_flist))); + for (; notmuch_filenames_valid(fnames); notmuch_filenames_move_to_next(fnames)) + rb_yield(rb_str_new2(notmuch_filenames_get(fnames))); return self; } diff --git a/bindings/ruby/gc.c b/bindings/ruby/gc.c deleted file mode 100644 index 37b089f4..00000000 --- a/bindings/ruby/gc.c +++ /dev/null @@ -1,288 +0,0 @@ -/* The Ruby interface to the notmuch mail library - * - * Copyright © 2010 Ali Polatel - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/ . - * - * Author: Ali Polatel - */ - -#include "defs.h" - -#include - -static notmuch_rb_database_t * -_notmuch_rb_messages_db(notmuch_rb_messages_t *messages); - -static notmuch_rb_database_t * -_notmuch_rb_message_db(notmuch_rb_message_t *message) -{ - notmuch_rb_messages_t *messages; - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(message->parent, notmuch_rb_cDatabase)) { - Data_Get_Struct(message->parent, notmuch_rb_database_t, db); - } - else if (rb_obj_is_instance_of(message->parent, notmuch_rb_cMessages)) { - Data_Get_Struct(message->parent, notmuch_rb_messages_t, messages); - db = _notmuch_rb_messages_db(messages); - } - else - db = NULL; - - return db; -} - -static notmuch_rb_database_t * -_notmuch_rb_messages_db(notmuch_rb_messages_t *messages) -{ - notmuch_rb_query_t *query; - notmuch_rb_thread_t *thread; - notmuch_rb_message_t *message; - notmuch_rb_threads_t *threads; - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cQuery)) { - Data_Get_Struct(messages->parent, notmuch_rb_query_t, query); - Data_Get_Struct(query->db, notmuch_rb_database_t, db); - } - else if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cThread)) { - Data_Get_Struct(messages->parent, notmuch_rb_thread_t, thread); - Data_Get_Struct(thread->threads, notmuch_rb_threads_t, threads); - Data_Get_Struct(threads->query, notmuch_rb_query_t, query); - Data_Get_Struct(query->db, notmuch_rb_database_t, db); - } - else if (rb_obj_is_instance_of(messages->parent, notmuch_rb_cMessage)) { - Data_Get_Struct(messages->parent, notmuch_rb_message_t, message); - db = _notmuch_rb_message_db(message); - } - else - db = NULL; - - return db; -} - -static notmuch_rb_database_t * -_notmuch_rb_thread_db(notmuch_rb_thread_t *thread) -{ - notmuch_rb_threads_t *threads; - notmuch_rb_query_t *query; - notmuch_rb_database_t *db; - - Data_Get_Struct(thread->threads, notmuch_rb_threads_t, threads); - Data_Get_Struct(threads->query, notmuch_rb_query_t, query); - Data_Get_Struct(query->db, notmuch_rb_database_t, db); - - return db; -} - -void -notmuch_rb_database_free(notmuch_rb_database_t *db) -{ - if (db->nm_db) - notmuch_database_close(db->nm_db); - - free(db); -} - -void -notmuch_rb_directory_mark(notmuch_rb_directory_t *dir) -{ - rb_gc_mark(dir->db); -} - -void -notmuch_rb_directory_free(notmuch_rb_directory_t *dir) -{ - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(dir->db, notmuch_rb_cDatabase)) - Data_Get_Struct(dir->db, notmuch_rb_database_t, db); - else - db = NULL; - - if (db && db->nm_db && dir->nm_dir) - notmuch_directory_destroy(dir->nm_dir); - - free(dir); -} - -void -notmuch_rb_filenames_mark(notmuch_rb_filenames_t *flist) -{ - rb_gc_mark(flist->dir); -} - -void -notmuch_rb_filenames_free(notmuch_rb_filenames_t *flist) -{ - notmuch_rb_directory_t *dir; - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(flist->dir, notmuch_rb_cDirectory)) { - Data_Get_Struct(flist->dir, notmuch_rb_directory_t, dir); - if (rb_obj_is_instance_of(dir->db, notmuch_rb_cDatabase)) - Data_Get_Struct(dir->db, notmuch_rb_database_t, db); - else - db = NULL; - } - else - db = NULL; - - if (db && db->nm_db && flist->nm_flist) - notmuch_filenames_destroy(flist->nm_flist); - - free(flist); -} - -void -notmuch_rb_query_mark(notmuch_rb_query_t *query) -{ - rb_gc_mark(query->db); -} - -void -notmuch_rb_query_free(notmuch_rb_query_t *query) -{ - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(query->db, notmuch_rb_cDatabase)) - Data_Get_Struct(query->db, notmuch_rb_database_t, db); - else - db = NULL; - - if (db && db->nm_db && query->nm_query) - notmuch_query_destroy(query->nm_query); - - free(query); -} - -void -notmuch_rb_threads_mark(notmuch_rb_threads_t *threads) -{ - rb_gc_mark(threads->query); -} - -void -notmuch_rb_threads_free(notmuch_rb_threads_t *threads) -{ - notmuch_rb_query_t *query; - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(threads->query, notmuch_rb_cQuery)) { - Data_Get_Struct(threads->query, notmuch_rb_query_t, query); - if (rb_obj_is_instance_of(query->db, notmuch_rb_cDatabase)) - Data_Get_Struct(query->db, notmuch_rb_database_t, db); - else - db = NULL; - } - else - db = NULL; - - if (db && db->nm_db && threads->nm_threads) - notmuch_threads_destroy(threads->nm_threads); - - free(threads); -} - -void -notmuch_rb_messages_mark(notmuch_rb_messages_t *messages) -{ - rb_gc_mark(messages->parent); -} - -void -notmuch_rb_messages_free(notmuch_rb_messages_t *messages) -{ - notmuch_rb_database_t *db; - - db = _notmuch_rb_messages_db(messages); - - if (db && db->nm_db && messages->nm_messages) - notmuch_messages_destroy(messages->nm_messages); - - free(messages); -} - -void -notmuch_rb_thread_mark(notmuch_rb_thread_t *thread) -{ - rb_gc_mark(thread->threads); -} - -void -notmuch_rb_thread_free(notmuch_rb_thread_t *thread) -{ - notmuch_rb_database_t *db; - - db = _notmuch_rb_thread_db(thread); - - if (db && db->nm_db && thread->nm_thread) - notmuch_thread_destroy(thread->nm_thread); - - free(thread); -} - -void -notmuch_rb_message_mark(notmuch_rb_message_t *message) -{ - rb_gc_mark(message->parent); -} - -void -notmuch_rb_message_free(notmuch_rb_message_t *message) -{ - notmuch_rb_database_t *db; - - db = _notmuch_rb_message_db(message); - if (db && db->nm_db && message->nm_message) - notmuch_message_destroy(message->nm_message); - - free(message); -} - -void -notmuch_rb_tags_mark(notmuch_rb_tags_t *tags) -{ - rb_gc_mark(tags->parent); -} - -void -notmuch_rb_tags_free(notmuch_rb_tags_t *tags) -{ - notmuch_rb_message_t *message; - notmuch_rb_messages_t *messages; - notmuch_rb_thread_t *thread; - notmuch_rb_database_t *db; - - if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cThread)) { - Data_Get_Struct(tags->parent, notmuch_rb_thread_t, thread); - db = _notmuch_rb_thread_db(thread); - } - else if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cMessage)) { - Data_Get_Struct(tags->parent, notmuch_rb_message_t, message); - db = _notmuch_rb_message_db(message); - } - else if (rb_obj_is_instance_of(tags->parent, notmuch_rb_cMessages)) { - Data_Get_Struct(tags->parent, notmuch_rb_messages_t, messages); - db = _notmuch_rb_messages_db(messages); - } - else - return; - - if (db && db->nm_db && tags->nm_tags) - notmuch_tags_destroy(tags->nm_tags); - - free(tags); -} diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index 61077ccb..4fdd018c 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -207,6 +207,7 @@ Init_notmuch(void) notmuch_rb_cDirectory = rb_define_class_under(mod, "Directory", rb_cObject); rb_undef_method(notmuch_rb_cDirectory, "initialize"); + rb_define_method(notmuch_rb_cDirectory, "destroy", notmuch_rb_directory_destroy, 0); rb_define_method(notmuch_rb_cDirectory, "mtime", notmuch_rb_directory_get_mtime, 0); rb_define_method(notmuch_rb_cDirectory, "mtime=", notmuch_rb_directory_set_mtime, 1); rb_define_method(notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); @@ -214,28 +215,33 @@ Init_notmuch(void) notmuch_rb_cFileNames = rb_define_class_under(mod, "FileNames", rb_cObject); rb_undef_method(notmuch_rb_cFileNames, "initialize"); + rb_define_method(notmuch_rb_cFileNames, "destroy", notmuch_rb_filenames_destroy, 0); rb_define_method(notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); rb_include_module(notmuch_rb_cFileNames, rb_mEnumerable); notmuch_rb_cQuery = rb_define_class_under(mod, "Query", rb_cObject); rb_undef_method(notmuch_rb_cQuery, "initialize"); + rb_define_method(notmuch_rb_cQuery, "destroy", notmuch_rb_query_destroy, 0); rb_define_method(notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); rb_define_method(notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); rb_define_method(notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); notmuch_rb_cThreads = rb_define_class_under(mod, "Threads", rb_cObject); rb_undef_method(notmuch_rb_cThreads, "initialize"); + rb_define_method(notmuch_rb_cThreads, "destroy", notmuch_rb_threads_destroy, 0); rb_define_method(notmuch_rb_cThreads, "each", notmuch_rb_threads_each, 0); rb_include_module(notmuch_rb_cThreads, rb_mEnumerable); notmuch_rb_cMessages = rb_define_class_under(mod, "Messages", rb_cObject); rb_undef_method(notmuch_rb_cMessages, "initialize"); + rb_define_method(notmuch_rb_cMessages, "destroy", notmuch_rb_messages_destroy, 0); rb_define_method(notmuch_rb_cMessages, "each", notmuch_rb_messages_each, 0); rb_define_method(notmuch_rb_cMessages, "tags", notmuch_rb_messages_collect_tags, 0); rb_include_module(notmuch_rb_cMessages, rb_mEnumerable); notmuch_rb_cThread = rb_define_class_under(mod, "Thread", rb_cObject); rb_undef_method(notmuch_rb_cThread, "initialize"); + rb_define_method(notmuch_rb_cThread, "destroy", notmuch_rb_thread_destroy, 0); rb_define_method(notmuch_rb_cThread, "thread_id", notmuch_rb_thread_get_thread_id, 0); rb_define_method(notmuch_rb_cThread, "total_messages", notmuch_rb_thread_get_total_messages, 0); rb_define_method(notmuch_rb_cThread, "toplevel_messages", notmuch_rb_thread_get_toplevel_messages, 0); @@ -248,6 +254,7 @@ Init_notmuch(void) notmuch_rb_cMessage = rb_define_class_under(mod, "Message", rb_cObject); rb_undef_method(notmuch_rb_cMessage, "initialize"); + rb_define_method(notmuch_rb_cMessage, "destroy", notmuch_rb_message_destroy, 0); rb_define_method(notmuch_rb_cMessage, "message_id", notmuch_rb_message_get_message_id, 0); rb_define_method(notmuch_rb_cMessage, "thread_id", notmuch_rb_message_get_thread_id, 0); rb_define_method(notmuch_rb_cMessage, "replies", notmuch_rb_message_get_replies, 0); @@ -267,6 +274,7 @@ Init_notmuch(void) notmuch_rb_cTags = rb_define_class_under(mod, "Tags", rb_cObject); rb_undef_method(notmuch_rb_cTags, "initialize"); + rb_define_method(notmuch_rb_cTags, "destroy", notmuch_rb_tags_destroy, 0); rb_define_method(notmuch_rb_cTags, "each", notmuch_rb_tags_each, 0); rb_include_module(notmuch_rb_cTags, rb_mEnumerable); } diff --git a/bindings/ruby/message.c b/bindings/ruby/message.c index 6c7a0391..2babfd04 100644 --- a/bindings/ruby/message.c +++ b/bindings/ruby/message.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: MESSAGE.destroy => nil + * + * Destroys the message, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_message_destroy(VALUE self) +{ + notmuch_message_t *message; + + Data_Get_Struct(self, notmuch_message_t, message); + + notmuch_message_destroy(message); + + return Qnil; +} + /* * call-seq: MESSAGE.message_id => String * @@ -29,12 +46,13 @@ VALUE notmuch_rb_message_get_message_id(VALUE self) { const char *msgid; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - msgid = notmuch_message_get_message_id(message->nm_message); - return msgid ? rb_str_new2(msgid) : Qnil; + msgid = notmuch_message_get_message_id(message); + + return rb_str_new2(msgid); } /* @@ -46,12 +64,13 @@ VALUE notmuch_rb_message_get_thread_id(VALUE self) { const char *tid; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - tid = notmuch_message_get_thread_id(message->nm_message); - return tid ? rb_str_new2(tid) : Qnil; + tid = notmuch_message_get_thread_id(message); + + return rb_str_new2(tid); } /* @@ -62,18 +81,14 @@ notmuch_rb_message_get_thread_id(VALUE self) VALUE notmuch_rb_message_get_replies(VALUE self) { - notmuch_rb_messages_t *messages; - notmuch_rb_message_t *message; - VALUE messagesv; + notmuch_messages_t *messages; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, - notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); - messages->nm_messages = notmuch_message_get_replies(message->nm_message); - messages->parent = self; + messages = notmuch_message_get_replies(message); - return messages->nm_messages ? messagesv : Qnil; + return Data_Wrap_Struct(notmuch_rb_cMessages, NULL, NULL, messages); } /* @@ -85,12 +100,13 @@ VALUE notmuch_rb_message_get_filename(VALUE self) { const char *fname; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - fname = notmuch_message_get_filename(message->nm_message); - return fname ? rb_str_new2(fname) : Qnil; + fname = notmuch_message_get_filename(message); + + return rb_str_new2(fname); } /* @@ -101,14 +117,14 @@ notmuch_rb_message_get_filename(VALUE self) VALUE notmuch_rb_message_get_flag(VALUE self, VALUE flagv) { - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); if (!FIXNUM_P(flagv)) rb_raise(rb_eTypeError, "Flag not a Fixnum"); - return notmuch_message_get_flag(message->nm_message, FIX2INT(flagv)) ? Qtrue : Qfalse; + return notmuch_message_get_flag(message, FIX2INT(flagv)) ? Qtrue : Qfalse; } /* @@ -119,14 +135,15 @@ notmuch_rb_message_get_flag(VALUE self, VALUE flagv) VALUE notmuch_rb_message_set_flag(VALUE self, VALUE flagv, VALUE valuev) { - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); if (!FIXNUM_P(flagv)) rb_raise(rb_eTypeError, "Flag not a Fixnum"); - notmuch_message_set_flag(message->nm_message, FIX2INT(flagv), RTEST(valuev)); + notmuch_message_set_flag(message, FIX2INT(flagv), RTEST(valuev)); + return Qnil; } @@ -138,11 +155,11 @@ notmuch_rb_message_set_flag(VALUE self, VALUE flagv, VALUE valuev) VALUE notmuch_rb_message_get_date(VALUE self) { - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - return UINT2NUM(notmuch_message_get_date(message->nm_message)); + return UINT2NUM(notmuch_message_get_date(message)); } /* @@ -154,9 +171,9 @@ VALUE notmuch_rb_message_get_header(VALUE self, VALUE headerv) { const char *header, *value; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -165,9 +182,9 @@ notmuch_rb_message_get_header(VALUE self, VALUE headerv) SafeStringValue(headerv); header = RSTRING_PTR(headerv); - value = notmuch_message_get_header(message->nm_message, header); + value = notmuch_message_get_header(message, header); if (!value) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); return rb_str_new2(value); } @@ -180,20 +197,16 @@ notmuch_rb_message_get_header(VALUE self, VALUE headerv) VALUE notmuch_rb_message_get_tags(VALUE self) { - notmuch_rb_message_t *message; - notmuch_rb_tags_t *tags; - VALUE tagsv; + notmuch_message_t *message; + notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, - notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); - tags->nm_tags = notmuch_message_get_tags(message->nm_message); - tags->parent = self; - if (!tags->nm_tags) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + tags = notmuch_message_get_tags(message); + if (!tags) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return tagsv; + return Data_Wrap_Struct(notmuch_rb_cTags, NULL, NULL, tags); } /* @@ -206,9 +219,9 @@ notmuch_rb_message_add_tag(VALUE self, VALUE tagv) { const char *tag; notmuch_status_t ret; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -217,8 +230,9 @@ notmuch_rb_message_add_tag(VALUE self, VALUE tagv) SafeStringValue(tagv); tag = RSTRING_PTR(tagv); - ret = notmuch_message_add_tag(message->nm_message, tag); + ret = notmuch_message_add_tag(message, tag); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -232,9 +246,9 @@ notmuch_rb_message_remove_tag(VALUE self, VALUE tagv) { const char *tag; notmuch_status_t ret; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -243,8 +257,9 @@ notmuch_rb_message_remove_tag(VALUE self, VALUE tagv) SafeStringValue(tagv); tag = RSTRING_PTR(tagv); - ret = notmuch_message_remove_tag(message->nm_message, tag); + ret = notmuch_message_remove_tag(message, tag); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -257,12 +272,13 @@ VALUE notmuch_rb_message_remove_all_tags(VALUE self) { notmuch_status_t ret; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - ret = notmuch_message_remove_all_tags(message->nm_message); + ret = notmuch_message_remove_all_tags(message); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -275,12 +291,13 @@ VALUE notmuch_rb_message_freeze(VALUE self) { notmuch_status_t ret; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - ret = notmuch_message_freeze(message->nm_message); + ret = notmuch_message_freeze(message); notmuch_rb_status_raise(ret); + return Qtrue; } @@ -293,11 +310,12 @@ VALUE notmuch_rb_message_thaw(VALUE self) { notmuch_status_t ret; - notmuch_rb_message_t *message; + notmuch_message_t *message; - Data_Get_Struct(self, notmuch_rb_message_t, message); + Data_Get_Struct(self, notmuch_message_t, message); - ret = notmuch_message_thaw(message->nm_message); + ret = notmuch_message_thaw(message); notmuch_rb_status_raise(ret); + return Qtrue; } diff --git a/bindings/ruby/messages.c b/bindings/ruby/messages.c index 6b296b32..94b0b0da 100644 --- a/bindings/ruby/messages.c +++ b/bindings/ruby/messages.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: MESSAGES.destroy => nil + * + * Destroys the messages, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_messages_destroy(VALUE self) +{ + notmuch_messages_t *fnames; + + Data_Get_Struct(self, notmuch_messages_t, fnames); + + notmuch_messages_destroy(fnames); + + return Qnil; +} + /* call-seq: MESSAGES.each {|item| block } => MESSAGES * * Calls +block+ once for each message in +self+, passing that element as a @@ -28,22 +45,16 @@ VALUE notmuch_rb_messages_each(VALUE self) { - notmuch_rb_message_t *message; - notmuch_rb_messages_t *messages; - VALUE messagev; + notmuch_message_t *message; + notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_rb_messages_t, messages); - if (!messages->nm_messages) + Data_Get_Struct(self, notmuch_messages_t, messages); + if (!messages) return self; - for (; notmuch_messages_valid(messages->nm_messages); - notmuch_messages_move_to_next(messages->nm_messages)) - { - messagev = Data_Make_Struct(notmuch_rb_cMessage, notmuch_rb_message_t, - notmuch_rb_message_mark, notmuch_rb_message_free, message); - message->nm_message = notmuch_messages_get(messages->nm_messages); - message->parent = self; - rb_yield(messagev); + for (; notmuch_messages_valid(messages); notmuch_messages_move_to_next(messages)) { + message = notmuch_messages_get(messages); + rb_yield(Data_Wrap_Struct(notmuch_rb_cMessage, NULL, NULL, message)); } return self; @@ -57,18 +68,14 @@ notmuch_rb_messages_each(VALUE self) VALUE notmuch_rb_messages_collect_tags(VALUE self) { - notmuch_rb_tags_t *tags; - notmuch_rb_messages_t *messages; - VALUE tagsv; + notmuch_tags_t *tags; + notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_rb_messages_t, messages); + Data_Get_Struct(self, notmuch_messages_t, messages); - tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, - notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); - tags->nm_tags = notmuch_messages_collect_tags(messages->nm_messages); - tags->parent = self; - if (!tags->nm_tags) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + tags = notmuch_messages_collect_tags(messages); + if (!tags) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return tagsv; + return Data_Wrap_Struct(notmuch_rb_cTags, NULL, NULL, tags); } diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c index 50edf170..5140c008 100644 --- a/bindings/ruby/query.c +++ b/bindings/ruby/query.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: QUERY.destroy => nil + * + * Destroys the query, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_query_destroy(VALUE self) +{ + notmuch_query_t *query; + + Data_Get_Struct(self, notmuch_query_t, query); + + notmuch_query_destroy(query); + + return Qnil; +} + /* * call-seq: QUERY.sort=(fixnum) => nil * @@ -28,14 +45,15 @@ VALUE notmuch_rb_query_set_sort(VALUE self, VALUE sortv) { - notmuch_rb_query_t *query; + notmuch_query_t *query; - Data_Get_Struct(self, notmuch_rb_query_t, query); + Data_Get_Struct(self, notmuch_query_t, query); if (!FIXNUM_P(sortv)) rb_raise(rb_eTypeError, "Not a fixnum"); - notmuch_query_set_sort(query->nm_query, FIX2UINT(sortv)); + notmuch_query_set_sort(query, FIX2UINT(sortv)); + return Qnil; } @@ -47,20 +65,16 @@ notmuch_rb_query_set_sort(VALUE self, VALUE sortv) VALUE notmuch_rb_query_search_threads(VALUE self) { - notmuch_rb_query_t *query; - notmuch_rb_threads_t *threads; - VALUE threadsv; + notmuch_query_t *query; + notmuch_threads_t *threads; - Data_Get_Struct(self, notmuch_rb_query_t, query); + Data_Get_Struct(self, notmuch_query_t, query); - threadsv = Data_Make_Struct(notmuch_rb_cThreads, notmuch_rb_threads_t, - notmuch_rb_threads_mark, notmuch_rb_threads_free, threads); - threads->nm_threads = notmuch_query_search_threads(query->nm_query); - threads->query = self; - if (!threads->nm_threads) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + threads = notmuch_query_search_threads(query); + if (!threads) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return threadsv; + return Data_Wrap_Struct(notmuch_rb_cThreads, NULL, NULL, threads); } /* @@ -71,18 +85,14 @@ notmuch_rb_query_search_threads(VALUE self) VALUE notmuch_rb_query_search_messages(VALUE self) { - notmuch_rb_query_t *query; - notmuch_rb_messages_t *messages; - VALUE messagesv; + notmuch_query_t *query; + notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_rb_query_t, query); + Data_Get_Struct(self, notmuch_query_t, query); - messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, - notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); - messages->nm_messages = notmuch_query_search_messages(query->nm_query); - messages->parent = self; - if (!messages->nm_messages) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + messages = notmuch_query_search_messages(query); + if (!messages) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return messagesv; + return Data_Wrap_Struct(notmuch_rb_cMessages, NULL, NULL, messages); } diff --git a/bindings/ruby/tags.c b/bindings/ruby/tags.c index d0a5054a..7ca03b6f 100644 --- a/bindings/ruby/tags.c +++ b/bindings/ruby/tags.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: tags.destroy => nil + * + * Destroys the tags, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_tags_destroy(VALUE self) +{ + notmuch_tags_t *tags; + + Data_Get_Struct(self, notmuch_tags_t, tags); + + notmuch_tags_destroy(tags); + + return Qnil; +} + /* * call-seq: TAGS.each {|item| block } => TAGS * @@ -30,16 +47,15 @@ VALUE notmuch_rb_tags_each(VALUE self) { const char *tag; - notmuch_rb_tags_t *tags; + notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_rb_tags_t, tags); - if (!tags->nm_tags) + Data_Get_Struct(self, notmuch_tags_t, tags); + if (!tags) return self; - for (; notmuch_tags_valid(tags->nm_tags); - notmuch_tags_move_to_next(tags->nm_tags)) { - tag = notmuch_tags_get(tags->nm_tags); - rb_yield(tag ? rb_str_new2(tag) : Qnil); + for (; notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags)) { + tag = notmuch_tags_get(tags); + rb_yield(rb_str_new2(tag)); } return self; diff --git a/bindings/ruby/thread.c b/bindings/ruby/thread.c index 72a86b8f..5534fe3f 100644 --- a/bindings/ruby/thread.c +++ b/bindings/ruby/thread.c @@ -20,6 +20,23 @@ #include "defs.h" +/* + * call-seq: THREAD.destroy => nil + * + * Destroys the thread, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_thread_destroy(VALUE self) +{ + notmuch_thread_t *thread; + + Data_Get_Struct(self, notmuch_thread_t, thread); + + notmuch_thread_destroy(thread); + + return Qnil; +} + /* * call-seq: THREAD.thread_id => String * @@ -29,12 +46,13 @@ VALUE notmuch_rb_thread_get_thread_id(VALUE self) { const char *tid; - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - tid = notmuch_thread_get_thread_id(thread->nm_thread); - return tid ? rb_str_new2(tid) : Qnil; + tid = notmuch_thread_get_thread_id(thread); + + return rb_str_new2(tid); } /* @@ -45,11 +63,11 @@ notmuch_rb_thread_get_thread_id(VALUE self) VALUE notmuch_rb_thread_get_total_messages(VALUE self) { - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - return INT2FIX(notmuch_thread_get_total_messages(thread->nm_thread)); + return INT2FIX(notmuch_thread_get_total_messages(thread)); } /* @@ -60,20 +78,16 @@ notmuch_rb_thread_get_total_messages(VALUE self) VALUE notmuch_rb_thread_get_toplevel_messages(VALUE self) { - notmuch_rb_messages_t *messages; - notmuch_rb_thread_t *thread; - VALUE messagesv; + notmuch_messages_t *messages; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - messagesv = Data_Make_Struct(notmuch_rb_cMessages, notmuch_rb_messages_t, - notmuch_rb_messages_mark, notmuch_rb_messages_free, messages); - messages->nm_messages = notmuch_thread_get_toplevel_messages(thread->nm_thread); - messages->parent = self; - if (!messages->nm_messages) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + messages = notmuch_thread_get_toplevel_messages(thread); + if (!messages) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return messagesv; + return Data_Wrap_Struct(notmuch_rb_cMessages, NULL, NULL, messages); } /* @@ -84,11 +98,11 @@ notmuch_rb_thread_get_toplevel_messages(VALUE self) VALUE notmuch_rb_thread_get_matched_messages(VALUE self) { - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - return INT2FIX(notmuch_thread_get_matched_messages(thread->nm_thread)); + return INT2FIX(notmuch_thread_get_matched_messages(thread)); } /* @@ -100,12 +114,13 @@ VALUE notmuch_rb_thread_get_authors(VALUE self) { const char *authors; - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - authors = notmuch_thread_get_authors(thread->nm_thread); - return authors ? rb_str_new2(authors) : Qnil; + authors = notmuch_thread_get_authors(thread); + + return rb_str_new2(authors); } /* @@ -117,12 +132,13 @@ VALUE notmuch_rb_thread_get_subject(VALUE self) { const char *subject; - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - subject = notmuch_thread_get_subject(thread->nm_thread); - return subject ? rb_str_new2(subject) : Qnil; + subject = notmuch_thread_get_subject(thread); + + return rb_str_new2(subject); } /* @@ -133,11 +149,11 @@ notmuch_rb_thread_get_subject(VALUE self) VALUE notmuch_rb_thread_get_oldest_date(VALUE self) { - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - return UINT2NUM(notmuch_thread_get_oldest_date(thread->nm_thread)); + return UINT2NUM(notmuch_thread_get_oldest_date(thread)); } /* @@ -148,11 +164,11 @@ notmuch_rb_thread_get_oldest_date(VALUE self) VALUE notmuch_rb_thread_get_newest_date(VALUE self) { - notmuch_rb_thread_t *thread; + notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - return UINT2NUM(notmuch_thread_get_newest_date(thread->nm_thread)); + return UINT2NUM(notmuch_thread_get_newest_date(thread)); } /* @@ -163,18 +179,14 @@ notmuch_rb_thread_get_newest_date(VALUE self) VALUE notmuch_rb_thread_get_tags(VALUE self) { - notmuch_rb_thread_t *thread; - notmuch_rb_tags_t *tags; - VALUE tagsv; + notmuch_thread_t *thread; + notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_rb_thread_t, thread); + Data_Get_Struct(self, notmuch_thread_t, thread); - tagsv = Data_Make_Struct(notmuch_rb_cTags, notmuch_rb_tags_t, - notmuch_rb_tags_mark, notmuch_rb_tags_free, tags); - tags->nm_tags = notmuch_thread_get_tags(thread->nm_thread); - tags->parent = self; - if (!tags->nm_tags) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + tags = notmuch_thread_get_tags(thread); + if (!tags) + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); - return tagsv; + return Data_Wrap_Struct(notmuch_rb_cTags, NULL, NULL, tags); } diff --git a/bindings/ruby/threads.c b/bindings/ruby/threads.c index cee6afbe..09906975 100644 --- a/bindings/ruby/threads.c +++ b/bindings/ruby/threads.c @@ -20,6 +20,24 @@ #include "defs.h" +/* + * call-seq: THREADS.destroy => nil + * + * Destroys the threads, freeing all resources allocated for it. + */ +VALUE +notmuch_rb_threads_destroy(VALUE self) +{ + notmuch_threads_t *threads; + + Data_Get_Struct(self, notmuch_threads_t, threads); + + notmuch_threads_destroy(threads); + + return Qnil; +} + + /* call-seq: THREADS.each {|item| block } => THREADS * * Calls +block+ once for each thread in +self+, passing that element as a @@ -28,22 +46,16 @@ VALUE notmuch_rb_threads_each(VALUE self) { - notmuch_rb_thread_t *thread; - notmuch_rb_threads_t *threads; - VALUE threadv; + notmuch_thread_t *thread; + notmuch_threads_t *threads; - Data_Get_Struct(self, notmuch_rb_threads_t, threads); - if (!threads->nm_threads) + Data_Get_Struct(self, notmuch_threads_t, threads); + if (!threads) return self; - for (; notmuch_threads_valid(threads->nm_threads); - notmuch_threads_move_to_next(threads->nm_threads)) - { - threadv = Data_Make_Struct(notmuch_rb_cThread, notmuch_rb_thread_t, - notmuch_rb_thread_mark, notmuch_rb_thread_free, thread); - thread->nm_thread = notmuch_threads_get(threads->nm_threads); - thread->threads = self; - rb_yield(threadv); + for (; notmuch_threads_valid(threads); notmuch_threads_move_to_next(threads)) { + thread = notmuch_threads_get(threads); + rb_yield(Data_Wrap_Struct(notmuch_rb_cThread, NULL, NULL, thread)); } return self; From d2a457a5d8238c54445a8a6066f79c112ebd3a04 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Wed, 26 May 2010 19:10:40 +0300 Subject: [PATCH 5/6] ruby: Use rb_scan_args() --- bindings/ruby/database.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index e767819b..6824efdc 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -33,6 +33,7 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) const char *path; int create, mode; notmuch_database_t *db; + VALUE pathv, hashv; VALUE modev; #if !defined(RSTRING_PTR) @@ -40,16 +41,15 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) #endif /* !defined(RSTRING_PTR) */ /* Check arguments */ - if (argc < 1 || argc > 2) - rb_raise(rb_eTypeError, "Wrong number of arguments"); + rb_scan_args(argc, argv, "11", &pathv, &hashv); - SafeStringValue(argv[0]); - path = RSTRING_PTR(argv[0]); + SafeStringValue(pathv); + path = RSTRING_PTR(pathv); - if (argc == 2) { - Check_Type(argv[1], T_HASH); - create = RTEST(rb_hash_aref(argv[1], ID2SYM(ID_db_create))); - modev = rb_hash_aref(argv[1], ID2SYM(ID_db_mode)); + if (!NIL_P(hashv)) { + Check_Type(hashv, T_HASH); + create = RTEST(rb_hash_aref(hashv, ID2SYM(ID_db_create))); + modev = rb_hash_aref(hashv, ID2SYM(ID_db_mode)); if (NIL_P(modev)) mode = NOTMUCH_DATABASE_MODE_READ_ONLY; else if (!FIXNUM_P(modev)) @@ -72,7 +72,7 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) db = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); if (!db) - rb_raise(notmuch_rb_eDatabaseError, "failed to open database"); + rb_raise(notmuch_rb_eDatabaseError, "Failed to open database"); return Data_Wrap_Struct(klass, NULL, NULL, db); } From 5c9e385591b66fa20cbb186393c48c52831a23b7 Mon Sep 17 00:00:00 2001 From: Ali Polatel Date: Wed, 26 May 2010 20:56:07 +0300 Subject: [PATCH 6/6] ruby: Don't barf if an object is destroyed more than once Raise RuntimeError instead. Also revise Notmuch::Database a bit. Add Notmuch::Database.open singleton method. --- bindings/ruby/database.c | 60 +++++++++++++++++++++-------- bindings/ruby/defs.h | 80 ++++++++++++++++++++++++++++++++++++++- bindings/ruby/directory.c | 9 +++-- bindings/ruby/filenames.c | 7 ++-- bindings/ruby/init.c | 22 ++++++----- bindings/ruby/message.c | 31 +++++++-------- bindings/ruby/messages.c | 13 +++---- bindings/ruby/query.c | 11 +++--- bindings/ruby/tags.c | 9 ++--- bindings/ruby/thread.c | 21 +++++----- bindings/ruby/threads.c | 6 +-- 11 files changed, 188 insertions(+), 81 deletions(-) diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c index 6824efdc..f4edd773 100644 --- a/bindings/ruby/database.c +++ b/bindings/ruby/database.c @@ -20,19 +20,26 @@ #include "defs.h" +VALUE +notmuch_rb_database_alloc(VALUE klass) +{ + return Data_Wrap_Struct(klass, NULL, NULL, NULL); +} + /* - * call-seq: Notmuch::Database.new(path, [{:create => false, :mode => notmuch::MODE_READ_ONLY}]) => DB + * call-seq: Notmuch::Database.new(path [, {:create => false, :mode => Notmuch::MODE_READ_ONLY}]) => DB * * Create or open a notmuch database using the given path. + * * If :create is +true+, create the database instead of opening. + * * The argument :mode specifies the open mode of the database. */ VALUE -notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) +notmuch_rb_database_initialize(int argc, VALUE *argv, VALUE self) { const char *path; int create, mode; - notmuch_database_t *db; VALUE pathv, hashv; VALUE modev; @@ -70,11 +77,31 @@ notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass) mode = NOTMUCH_DATABASE_MODE_READ_ONLY; } - db = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); - if (!db) + Check_Type(self, T_DATA); + DATA_PTR(self) = create ? notmuch_database_create(path) : notmuch_database_open(path, mode); + if (!DATA_PTR(self)) rb_raise(notmuch_rb_eDatabaseError, "Failed to open database"); - return Data_Wrap_Struct(klass, NULL, NULL, db); + return self; +} + +/* + * call-seq: Notmuch::Database.open(path [, ahash]) {|db| ...} + * + * Identical to new, except that when it is called with a block, it yields with + * the new instance and closes it, and returns the result which is returned from + * the block. + */ +VALUE +notmuch_rb_database_open(int argc, VALUE *argv, VALUE klass) +{ + VALUE obj; + + obj = rb_class_new_instance(argc, argv, klass); + if (!rb_block_given_p()) + return obj; + + return rb_ensure(rb_yield, obj, notmuch_rb_database_close, obj); } /* @@ -87,8 +114,9 @@ notmuch_rb_database_close(VALUE self) { notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); notmuch_database_close(db); + DATA_PTR(self) = NULL; return Qnil; } @@ -103,7 +131,7 @@ notmuch_rb_database_path(VALUE self) { notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); return rb_str_new2(notmuch_database_get_path(db)); } @@ -118,7 +146,7 @@ notmuch_rb_database_version(VALUE self) { notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); return INT2FIX(notmuch_database_get_version(db)); } @@ -133,7 +161,7 @@ notmuch_rb_database_needs_upgrade(VALUE self) { notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); return notmuch_database_needs_upgrade(db) ? Qtrue : Qfalse; } @@ -161,7 +189,7 @@ notmuch_rb_database_upgrade(VALUE self) notmuch_database_t *db; VALUE block; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); if (rb_block_given_p()) { pnotify = notmuch_rb_upgrade_notify; @@ -188,7 +216,7 @@ notmuch_rb_database_get_directory(VALUE self, VALUE pathv) notmuch_directory_t *dir; notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -220,7 +248,7 @@ notmuch_rb_database_add_message(VALUE self, VALUE pathv) notmuch_message_t *message; notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -250,7 +278,7 @@ notmuch_rb_database_remove_message(VALUE self, VALUE pathv) notmuch_status_t ret; notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -276,7 +304,7 @@ notmuch_rb_database_query_create(VALUE self, VALUE qstrv) notmuch_query_t *query; notmuch_database_t *db; - Data_Get_Struct(self, notmuch_database_t, db); + Data_Get_Notmuch_Database(self, db); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -287,7 +315,7 @@ notmuch_rb_database_query_create(VALUE self, VALUE qstrv) query = notmuch_query_create(db, qstr); if (!query) - rb_raise(notmuch_rb_eMemoryError, "out of memory"); + rb_raise(notmuch_rb_eMemoryError, "Out of memory"); return Data_Wrap_Struct(notmuch_rb_cQuery, NULL, NULL, query); } diff --git a/bindings/ruby/defs.h b/bindings/ruby/defs.h index f36b7227..b1be5a30 100644 --- a/bindings/ruby/defs.h +++ b/bindings/ruby/defs.h @@ -49,13 +49,91 @@ ID ID_call; ID ID_db_create; ID ID_db_mode; +#define Data_Get_Notmuch_Database(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "database closed"); \ + Data_Get_Struct(obj, notmuch_database_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Directory(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "directory destroyed"); \ + Data_Get_Struct(obj, notmuch_directory_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_FileNames(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "filenames destroyed"); \ + Data_Get_Struct(obj, notmuch_filenames_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Query(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "query destroyed"); \ + Data_Get_Struct(obj, notmuch_query_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Threads(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "threads destroyed"); \ + Data_Get_Struct(obj, notmuch_threads_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Messages(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "messages destroyed"); \ + Data_Get_Struct(obj, notmuch_messages_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Thread(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "thread destroyed"); \ + Data_Get_Struct(obj, notmuch_thread_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Message(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "message destroyed"); \ + Data_Get_Struct(obj, notmuch_message_t, ptr); \ + } while(0) + +#define Data_Get_Notmuch_Tags(obj, ptr) \ + do { \ + Check_Type(obj, T_DATA); \ + if (DATA_PTR(obj) == NULL) \ + rb_raise(rb_eRuntimeError, "tags destroyed"); \ + Data_Get_Struct(obj, notmuch_tags_t, ptr); \ + } while(0) + /* status.c */ void notmuch_rb_status_raise(notmuch_status_t status); /* database.c */ VALUE -notmuch_rb_database_new(int argc, VALUE *argv, VALUE klass); +notmuch_rb_database_alloc(VALUE klass); + +VALUE +notmuch_rb_database_initialize(int argc, VALUE *argv, VALUE klass); + +VALUE +notmuch_rb_database_open(int argc, VALUE *argv, VALUE klass); VALUE notmuch_rb_database_close(VALUE self); diff --git a/bindings/ruby/directory.c b/bindings/ruby/directory.c index e73658c1..36dcb8be 100644 --- a/bindings/ruby/directory.c +++ b/bindings/ruby/directory.c @@ -33,6 +33,7 @@ notmuch_rb_directory_destroy(VALUE self) Data_Get_Struct(self, notmuch_directory_t, dir); notmuch_directory_destroy(dir); + DATA_PTR(self) = NULL; return Qnil; } @@ -48,7 +49,7 @@ notmuch_rb_directory_get_mtime(VALUE self) { notmuch_directory_t *dir; - Data_Get_Struct(self, notmuch_directory_t, dir); + Data_Get_Notmuch_Directory(self, dir); return UINT2NUM(notmuch_directory_get_mtime(dir)); } @@ -64,7 +65,7 @@ notmuch_rb_directory_set_mtime(VALUE self, VALUE mtimev) notmuch_status_t ret; notmuch_directory_t *dir; - Data_Get_Struct(self, notmuch_directory_t, dir); + Data_Get_Notmuch_Directory(self, dir); if (!FIXNUM_P(mtimev)) rb_raise(rb_eTypeError, "First argument not a fixnum"); @@ -87,7 +88,7 @@ notmuch_rb_directory_get_child_files(VALUE self) notmuch_directory_t *dir; notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_directory_t, dir); + Data_Get_Notmuch_Directory(self, dir); fnames = notmuch_directory_get_child_files(dir); @@ -106,7 +107,7 @@ notmuch_rb_directory_get_child_directories(VALUE self) notmuch_directory_t *dir; notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_directory_t, dir); + Data_Get_Notmuch_Directory(self, dir); fnames = notmuch_directory_get_child_directories(dir); diff --git a/bindings/ruby/filenames.c b/bindings/ruby/filenames.c index 23553ab1..faaa9a0a 100644 --- a/bindings/ruby/filenames.c +++ b/bindings/ruby/filenames.c @@ -30,9 +30,10 @@ notmuch_rb_filenames_destroy(VALUE self) { notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_filenames_t, fnames); + Data_Get_Notmuch_FileNames(self, fnames); notmuch_filenames_destroy(fnames); + DATA_PTR(self) = NULL; return Qnil; } @@ -48,9 +49,7 @@ notmuch_rb_filenames_each(VALUE self) { notmuch_filenames_t *fnames; - Data_Get_Struct(self, notmuch_filenames_t, fnames); - if (!fnames) - return self; + Data_Get_Notmuch_FileNames(self, fnames); for (; notmuch_filenames_valid(fnames); notmuch_filenames_move_to_next(fnames)) rb_yield(rb_str_new2(notmuch_filenames_get(fnames))); diff --git a/bindings/ruby/init.c b/bindings/ruby/init.c index 4fdd018c..e19b0356 100644 --- a/bindings/ruby/init.c +++ b/bindings/ruby/init.c @@ -193,8 +193,10 @@ Init_notmuch(void) notmuch_rb_eUnbalancedFreezeThawError = rb_define_class_under(mod, "UnbalancedFreezeThawError", notmuch_rb_eBaseError); - notmuch_rb_cDatabase = rb_define_class_under(mod, "Database", rb_cObject); - rb_define_singleton_method(notmuch_rb_cDatabase, "new", notmuch_rb_database_new, -1); + notmuch_rb_cDatabase = rb_define_class_under(mod, "Database", rb_cData); + rb_define_alloc_func(notmuch_rb_cDatabase, notmuch_rb_database_alloc); + rb_define_singleton_method(notmuch_rb_cDatabase, "open", notmuch_rb_database_open, -1); + rb_define_method(notmuch_rb_cDatabase, "initialize", notmuch_rb_database_initialize, -1); rb_define_method(notmuch_rb_cDatabase, "close", notmuch_rb_database_close, 0); rb_define_method(notmuch_rb_cDatabase, "path", notmuch_rb_database_path, 0); rb_define_method(notmuch_rb_cDatabase, "version", notmuch_rb_database_version, 0); @@ -205,7 +207,7 @@ Init_notmuch(void) rb_define_method(notmuch_rb_cDatabase, "remove_message", notmuch_rb_database_remove_message, 1); rb_define_method(notmuch_rb_cDatabase, "query", notmuch_rb_database_query_create, 1); - notmuch_rb_cDirectory = rb_define_class_under(mod, "Directory", rb_cObject); + notmuch_rb_cDirectory = rb_define_class_under(mod, "Directory", rb_cData); rb_undef_method(notmuch_rb_cDirectory, "initialize"); rb_define_method(notmuch_rb_cDirectory, "destroy", notmuch_rb_directory_destroy, 0); rb_define_method(notmuch_rb_cDirectory, "mtime", notmuch_rb_directory_get_mtime, 0); @@ -213,33 +215,33 @@ Init_notmuch(void) rb_define_method(notmuch_rb_cDirectory, "child_files", notmuch_rb_directory_get_child_files, 0); rb_define_method(notmuch_rb_cDirectory, "child_directories", notmuch_rb_directory_get_child_directories, 0); - notmuch_rb_cFileNames = rb_define_class_under(mod, "FileNames", rb_cObject); + notmuch_rb_cFileNames = rb_define_class_under(mod, "FileNames", rb_cData); rb_undef_method(notmuch_rb_cFileNames, "initialize"); rb_define_method(notmuch_rb_cFileNames, "destroy", notmuch_rb_filenames_destroy, 0); rb_define_method(notmuch_rb_cFileNames, "each", notmuch_rb_filenames_each, 0); rb_include_module(notmuch_rb_cFileNames, rb_mEnumerable); - notmuch_rb_cQuery = rb_define_class_under(mod, "Query", rb_cObject); + notmuch_rb_cQuery = rb_define_class_under(mod, "Query", rb_cData); rb_undef_method(notmuch_rb_cQuery, "initialize"); rb_define_method(notmuch_rb_cQuery, "destroy", notmuch_rb_query_destroy, 0); rb_define_method(notmuch_rb_cQuery, "sort=", notmuch_rb_query_set_sort, 1); rb_define_method(notmuch_rb_cQuery, "search_threads", notmuch_rb_query_search_threads, 0); rb_define_method(notmuch_rb_cQuery, "search_messages", notmuch_rb_query_search_messages, 0); - notmuch_rb_cThreads = rb_define_class_under(mod, "Threads", rb_cObject); + notmuch_rb_cThreads = rb_define_class_under(mod, "Threads", rb_cData); rb_undef_method(notmuch_rb_cThreads, "initialize"); rb_define_method(notmuch_rb_cThreads, "destroy", notmuch_rb_threads_destroy, 0); rb_define_method(notmuch_rb_cThreads, "each", notmuch_rb_threads_each, 0); rb_include_module(notmuch_rb_cThreads, rb_mEnumerable); - notmuch_rb_cMessages = rb_define_class_under(mod, "Messages", rb_cObject); + notmuch_rb_cMessages = rb_define_class_under(mod, "Messages", rb_cData); rb_undef_method(notmuch_rb_cMessages, "initialize"); rb_define_method(notmuch_rb_cMessages, "destroy", notmuch_rb_messages_destroy, 0); rb_define_method(notmuch_rb_cMessages, "each", notmuch_rb_messages_each, 0); rb_define_method(notmuch_rb_cMessages, "tags", notmuch_rb_messages_collect_tags, 0); rb_include_module(notmuch_rb_cMessages, rb_mEnumerable); - notmuch_rb_cThread = rb_define_class_under(mod, "Thread", rb_cObject); + notmuch_rb_cThread = rb_define_class_under(mod, "Thread", rb_cData); rb_undef_method(notmuch_rb_cThread, "initialize"); rb_define_method(notmuch_rb_cThread, "destroy", notmuch_rb_thread_destroy, 0); rb_define_method(notmuch_rb_cThread, "thread_id", notmuch_rb_thread_get_thread_id, 0); @@ -252,7 +254,7 @@ Init_notmuch(void) rb_define_method(notmuch_rb_cThread, "newest_date", notmuch_rb_thread_get_newest_date, 0); rb_define_method(notmuch_rb_cThread, "tags", notmuch_rb_thread_get_tags, 0); - notmuch_rb_cMessage = rb_define_class_under(mod, "Message", rb_cObject); + notmuch_rb_cMessage = rb_define_class_under(mod, "Message", rb_cData); rb_undef_method(notmuch_rb_cMessage, "initialize"); rb_define_method(notmuch_rb_cMessage, "destroy", notmuch_rb_message_destroy, 0); rb_define_method(notmuch_rb_cMessage, "message_id", notmuch_rb_message_get_message_id, 0); @@ -272,7 +274,7 @@ Init_notmuch(void) rb_define_method(notmuch_rb_cMessage, "freeze", notmuch_rb_message_freeze, 0); rb_define_method(notmuch_rb_cMessage, "thaw", notmuch_rb_message_thaw, 0); - notmuch_rb_cTags = rb_define_class_under(mod, "Tags", rb_cObject); + notmuch_rb_cTags = rb_define_class_under(mod, "Tags", rb_cData); rb_undef_method(notmuch_rb_cTags, "initialize"); rb_define_method(notmuch_rb_cTags, "destroy", notmuch_rb_tags_destroy, 0); rb_define_method(notmuch_rb_cTags, "each", notmuch_rb_tags_each, 0); diff --git a/bindings/ruby/message.c b/bindings/ruby/message.c index 2babfd04..f97e1a4e 100644 --- a/bindings/ruby/message.c +++ b/bindings/ruby/message.c @@ -30,9 +30,10 @@ notmuch_rb_message_destroy(VALUE self) { notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); notmuch_message_destroy(message); + DATA_PTR(self) = NULL; return Qnil; } @@ -48,7 +49,7 @@ notmuch_rb_message_get_message_id(VALUE self) const char *msgid; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); msgid = notmuch_message_get_message_id(message); @@ -66,7 +67,7 @@ notmuch_rb_message_get_thread_id(VALUE self) const char *tid; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); tid = notmuch_message_get_thread_id(message); @@ -84,7 +85,7 @@ notmuch_rb_message_get_replies(VALUE self) notmuch_messages_t *messages; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); messages = notmuch_message_get_replies(message); @@ -102,7 +103,7 @@ notmuch_rb_message_get_filename(VALUE self) const char *fname; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); fname = notmuch_message_get_filename(message); @@ -119,7 +120,7 @@ notmuch_rb_message_get_flag(VALUE self, VALUE flagv) { notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); if (!FIXNUM_P(flagv)) rb_raise(rb_eTypeError, "Flag not a Fixnum"); @@ -137,7 +138,7 @@ notmuch_rb_message_set_flag(VALUE self, VALUE flagv, VALUE valuev) { notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); if (!FIXNUM_P(flagv)) rb_raise(rb_eTypeError, "Flag not a Fixnum"); @@ -157,7 +158,7 @@ notmuch_rb_message_get_date(VALUE self) { notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); return UINT2NUM(notmuch_message_get_date(message)); } @@ -173,7 +174,7 @@ notmuch_rb_message_get_header(VALUE self, VALUE headerv) const char *header, *value; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -200,7 +201,7 @@ notmuch_rb_message_get_tags(VALUE self) notmuch_message_t *message; notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); tags = notmuch_message_get_tags(message); if (!tags) @@ -221,7 +222,7 @@ notmuch_rb_message_add_tag(VALUE self, VALUE tagv) notmuch_status_t ret; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -248,7 +249,7 @@ notmuch_rb_message_remove_tag(VALUE self, VALUE tagv) notmuch_status_t ret; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); #if !defined(RSTRING_PTR) #define RSTRING_PTR(v) (RSTRING((v))->ptr) @@ -274,7 +275,7 @@ notmuch_rb_message_remove_all_tags(VALUE self) notmuch_status_t ret; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); ret = notmuch_message_remove_all_tags(message); notmuch_rb_status_raise(ret); @@ -293,7 +294,7 @@ notmuch_rb_message_freeze(VALUE self) notmuch_status_t ret; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); ret = notmuch_message_freeze(message); notmuch_rb_status_raise(ret); @@ -312,7 +313,7 @@ notmuch_rb_message_thaw(VALUE self) notmuch_status_t ret; notmuch_message_t *message; - Data_Get_Struct(self, notmuch_message_t, message); + Data_Get_Notmuch_Message(self, message); ret = notmuch_message_thaw(message); notmuch_rb_status_raise(ret); diff --git a/bindings/ruby/messages.c b/bindings/ruby/messages.c index 94b0b0da..35b5d146 100644 --- a/bindings/ruby/messages.c +++ b/bindings/ruby/messages.c @@ -28,11 +28,12 @@ VALUE notmuch_rb_messages_destroy(VALUE self) { - notmuch_messages_t *fnames; + notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_messages_t, fnames); + Data_Get_Notmuch_Messages(self, messages); - notmuch_messages_destroy(fnames); + notmuch_messages_destroy(messages); + DATA_PTR(self) = NULL; return Qnil; } @@ -48,9 +49,7 @@ notmuch_rb_messages_each(VALUE self) notmuch_message_t *message; notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_messages_t, messages); - if (!messages) - return self; + Data_Get_Notmuch_Messages(self, messages); for (; notmuch_messages_valid(messages); notmuch_messages_move_to_next(messages)) { message = notmuch_messages_get(messages); @@ -71,7 +70,7 @@ notmuch_rb_messages_collect_tags(VALUE self) notmuch_tags_t *tags; notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_messages_t, messages); + Data_Get_Notmuch_Messages(self, messages); tags = notmuch_messages_collect_tags(messages); if (!tags) diff --git a/bindings/ruby/query.c b/bindings/ruby/query.c index 5140c008..c5b8a4cc 100644 --- a/bindings/ruby/query.c +++ b/bindings/ruby/query.c @@ -30,9 +30,10 @@ notmuch_rb_query_destroy(VALUE self) { notmuch_query_t *query; - Data_Get_Struct(self, notmuch_query_t, query); + Data_Get_Notmuch_Query(self, query); notmuch_query_destroy(query); + DATA_PTR(self) = NULL; return Qnil; } @@ -47,10 +48,10 @@ notmuch_rb_query_set_sort(VALUE self, VALUE sortv) { notmuch_query_t *query; - Data_Get_Struct(self, notmuch_query_t, query); + Data_Get_Notmuch_Query(self, query); if (!FIXNUM_P(sortv)) - rb_raise(rb_eTypeError, "Not a fixnum"); + rb_raise(rb_eTypeError, "Not a Fixnum"); notmuch_query_set_sort(query, FIX2UINT(sortv)); @@ -68,7 +69,7 @@ notmuch_rb_query_search_threads(VALUE self) notmuch_query_t *query; notmuch_threads_t *threads; - Data_Get_Struct(self, notmuch_query_t, query); + Data_Get_Notmuch_Query(self, query); threads = notmuch_query_search_threads(query); if (!threads) @@ -88,7 +89,7 @@ notmuch_rb_query_search_messages(VALUE self) notmuch_query_t *query; notmuch_messages_t *messages; - Data_Get_Struct(self, notmuch_query_t, query); + Data_Get_Notmuch_Query(self, query); messages = notmuch_query_search_messages(query); if (!messages) diff --git a/bindings/ruby/tags.c b/bindings/ruby/tags.c index 7ca03b6f..d7cd941d 100644 --- a/bindings/ruby/tags.c +++ b/bindings/ruby/tags.c @@ -21,7 +21,7 @@ #include "defs.h" /* - * call-seq: tags.destroy => nil + * call-seq: TAGS.destroy => nil * * Destroys the tags, freeing all resources allocated for it. */ @@ -30,9 +30,10 @@ notmuch_rb_tags_destroy(VALUE self) { notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_tags_t, tags); + Data_Get_Notmuch_Tags(self, tags); notmuch_tags_destroy(tags); + DATA_PTR(self) = NULL; return Qnil; } @@ -49,9 +50,7 @@ notmuch_rb_tags_each(VALUE self) const char *tag; notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_tags_t, tags); - if (!tags) - return self; + Data_Get_Notmuch_Tags(self, tags); for (; notmuch_tags_valid(tags); notmuch_tags_move_to_next(tags)) { tag = notmuch_tags_get(tags); diff --git a/bindings/ruby/thread.c b/bindings/ruby/thread.c index 5534fe3f..e5c87366 100644 --- a/bindings/ruby/thread.c +++ b/bindings/ruby/thread.c @@ -30,9 +30,10 @@ notmuch_rb_thread_destroy(VALUE self) { notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); notmuch_thread_destroy(thread); + DATA_PTR(self) = NULL; return Qnil; } @@ -48,7 +49,7 @@ notmuch_rb_thread_get_thread_id(VALUE self) const char *tid; notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); tid = notmuch_thread_get_thread_id(thread); @@ -65,7 +66,7 @@ notmuch_rb_thread_get_total_messages(VALUE self) { notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); return INT2FIX(notmuch_thread_get_total_messages(thread)); } @@ -81,7 +82,7 @@ notmuch_rb_thread_get_toplevel_messages(VALUE self) notmuch_messages_t *messages; notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); messages = notmuch_thread_get_toplevel_messages(thread); if (!messages) @@ -100,7 +101,7 @@ notmuch_rb_thread_get_matched_messages(VALUE self) { notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); return INT2FIX(notmuch_thread_get_matched_messages(thread)); } @@ -116,7 +117,7 @@ notmuch_rb_thread_get_authors(VALUE self) const char *authors; notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); authors = notmuch_thread_get_authors(thread); @@ -134,7 +135,7 @@ notmuch_rb_thread_get_subject(VALUE self) const char *subject; notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); subject = notmuch_thread_get_subject(thread); @@ -151,7 +152,7 @@ notmuch_rb_thread_get_oldest_date(VALUE self) { notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); return UINT2NUM(notmuch_thread_get_oldest_date(thread)); } @@ -166,7 +167,7 @@ notmuch_rb_thread_get_newest_date(VALUE self) { notmuch_thread_t *thread; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); return UINT2NUM(notmuch_thread_get_newest_date(thread)); } @@ -182,7 +183,7 @@ notmuch_rb_thread_get_tags(VALUE self) notmuch_thread_t *thread; notmuch_tags_t *tags; - Data_Get_Struct(self, notmuch_thread_t, thread); + Data_Get_Notmuch_Thread(self, thread); tags = notmuch_thread_get_tags(thread); if (!tags) diff --git a/bindings/ruby/threads.c b/bindings/ruby/threads.c index 09906975..abd51212 100644 --- a/bindings/ruby/threads.c +++ b/bindings/ruby/threads.c @@ -33,11 +33,11 @@ notmuch_rb_threads_destroy(VALUE self) Data_Get_Struct(self, notmuch_threads_t, threads); notmuch_threads_destroy(threads); + DATA_PTR(self) = NULL; return Qnil; } - /* call-seq: THREADS.each {|item| block } => THREADS * * Calls +block+ once for each thread in +self+, passing that element as a @@ -49,9 +49,7 @@ notmuch_rb_threads_each(VALUE self) notmuch_thread_t *thread; notmuch_threads_t *threads; - Data_Get_Struct(self, notmuch_threads_t, threads); - if (!threads) - return self; + Data_Get_Notmuch_Threads(self, threads); for (; notmuch_threads_valid(threads); notmuch_threads_move_to_next(threads)) { thread = notmuch_threads_get(threads);