Exheredludis/ruby/contents.cc

391 lines
13 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2006, 2007 Richard Brown
* Copyright (c) 2009, 2010 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
* Public License version 2, as published by the Free Software Foundation.
*
* Paludis 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, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <paludis_ruby.hh>
#include <paludis/contents.hh>
#include <paludis/util/wrapped_forward_iterator.hh>
#include <ruby.h>
using namespace paludis;
using namespace paludis::ruby;
namespace
{
static VALUE c_contents;
static VALUE c_contents_entry;
static VALUE c_contents_file_entry;
static VALUE c_contents_dir_entry;
static VALUE c_contents_sym_entry;
static VALUE c_contents_other_entry;
struct V
{
VALUE value;
std::shared_ptr<const ContentsEntry> mm;
V(std::shared_ptr<const ContentsEntry> _m) :
mm(_m)
{
}
void visit(const ContentsFileEntry &)
{
value = Data_Wrap_Struct(c_contents_file_entry, 0, &Common<std::shared_ptr<const ContentsEntry> >::free,
new std::shared_ptr<const ContentsEntry>(mm));
}
void visit(const ContentsDirEntry &)
{
value = Data_Wrap_Struct(c_contents_dir_entry, 0, &Common<std::shared_ptr<const ContentsEntry> >::free,
new std::shared_ptr<const ContentsEntry>(mm));
}
void visit(const ContentsOtherEntry &)
{
value = Data_Wrap_Struct(c_contents_other_entry, 0, &Common<std::shared_ptr<const ContentsEntry> >::free,
new std::shared_ptr<const ContentsEntry>(mm));
}
void visit(const ContentsSymEntry &)
{
value = Data_Wrap_Struct(c_contents_sym_entry, 0, &Common<std::shared_ptr<const ContentsEntry> >::free,
new std::shared_ptr<const ContentsEntry>(mm));
}
};
VALUE
contents_entry_to_value(std::shared_ptr<const ContentsEntry> m)
{
try
{
V v(m);
m->accept(v);
return v.value;
}
catch (const std::exception & e)
{
exception_to_ruby_exception(e);
}
}
VALUE
contents_init(VALUE self)
{
return self;
}
VALUE
contents_new(VALUE self)
{
std::shared_ptr<Contents> * ptr(0);
try
{
ptr = new std::shared_ptr<Contents>(new Contents());
VALUE tdata(Data_Wrap_Struct(self, 0, &Common<std::shared_ptr<Contents> >::free, ptr));
rb_obj_call_init(tdata, 0, 0);
return tdata;
}
catch (const std::exception & e)
{
delete ptr;
exception_to_ruby_exception(e);
}
}
/*
* call-seq:
* add(contents_entry)
*
* Add a new entry.
*/
VALUE contents_add(VALUE self, VALUE v)
{
if (rb_obj_is_kind_of(v, c_contents_entry))
{
try
{
std::shared_ptr<Contents> * self_ptr;
Data_Get_Struct(self, std::shared_ptr<Contents>, self_ptr);
std::shared_ptr<const ContentsEntry> * v_ptr;
Data_Get_Struct(v, std::shared_ptr<const ContentsEntry>, v_ptr);
(*self_ptr)->add(*v_ptr);
return self;
}
catch (const std::exception & e)
{
exception_to_ruby_exception(e);
}
}
else
{
rb_raise(rb_eTypeError, "Can't convert %s into ContentsEntry", rb_obj_classname(v));
}
}
/*
* call-seq:
* each {|contents_entry| block}
*
* Iterate through our entries.
*/
VALUE
contents_each(VALUE self)
{
std::shared_ptr<Contents> * ptr;
Data_Get_Struct(self, std::shared_ptr<Contents>, ptr);
for (Contents::ConstIterator i ((*ptr)->begin()), i_end((*ptr)->end()) ; i != i_end; ++i)
rb_yield(contents_entry_to_value(*i));
return self;
}
VALUE
contents_entry_init(int, VALUE *, VALUE self)
{
return self;
}
template <typename A_>
struct ContentsNew
{
static VALUE
contents_entry_new(int argc, VALUE * argv, VALUE self)
{
typename std::shared_ptr<const ContentsEntry> * ptr(0);
try
{
if (1 == argc)
{
ptr = new std::shared_ptr<const ContentsEntry>(std::make_shared<A_>(
FSPath(StringValuePtr(argv[0]))));
}
else
{
rb_raise(rb_eArgError, "ContentsEntry expects one argument, but got %d",argc);
}
VALUE tdata(Data_Wrap_Struct(self, 0, &Common<std::shared_ptr<const ContentsEntry> >::free, ptr));
rb_obj_call_init(tdata, argc, argv);
return tdata;
}
catch (const std::exception & e)
{
delete ptr;
exception_to_ruby_exception(e);
}
}
};
VALUE contents_file_entry_new(int argc, VALUE * argv, VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr(0);
try
{
if (2 == argc)
{
ptr = new std::shared_ptr<const ContentsEntry>(std::make_shared<ContentsFileEntry>(
FSPath(StringValuePtr(argv[0])), StringValuePtr(argv[1])));
}
else
{
rb_raise(rb_eArgError, "ContentsSymEntry expects two arguments, but got %d",argc);
}
VALUE tdata(Data_Wrap_Struct(self, 0, &Common<std::shared_ptr<const ContentsEntry> >::free, ptr));
rb_obj_call_init(tdata, argc, argv);
return tdata;
}
catch (const std::exception & e)
{
delete ptr;
exception_to_ruby_exception(e);
}
}
VALUE contents_sym_entry_new(int argc, VALUE * argv, VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr(0);
try
{
if (3 == argc)
{
ptr = new std::shared_ptr<const ContentsEntry>(std::make_shared<ContentsSymEntry>(
FSPath(StringValuePtr(argv[0])), StringValuePtr(argv[1]), StringValuePtr(argv[2])));
}
else
{
rb_raise(rb_eArgError, "ContentsSymEntry expects three arguments, but got %d",argc);
}
VALUE tdata(Data_Wrap_Struct(self, 0, &Common<std::shared_ptr<const ContentsEntry> >::free, ptr));
rb_obj_call_init(tdata, argc, argv);
return tdata;
}
catch (const std::exception & e)
{
delete ptr;
exception_to_ruby_exception(e);
}
}
/*
* Document-method: location_key
*
* Returns our location
*/
static VALUE
contents_entry_location_key(VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr;
Data_Get_Struct(self, std::shared_ptr<const ContentsEntry>, ptr);
return metadata_key_to_value((*ptr)->location_key());
}
static VALUE
contents_file_entry_part_key(VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr;
Data_Get_Struct(self, std::shared_ptr<const ContentsEntry>, ptr);
return metadata_key_to_value((std::static_pointer_cast<const ContentsFileEntry>(*ptr))->part_key());
}
/*
* Document-method: target_key
*
* Returns our target (as per readlink)
*/
static VALUE
contents_sym_entry_target_key(VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr;
Data_Get_Struct(self, std::shared_ptr<const ContentsEntry>, ptr);
return metadata_key_to_value((std::static_pointer_cast<const ContentsSymEntry>(*ptr))->target_key());
}
static VALUE
contents_sym_entry_part_key(VALUE self)
{
std::shared_ptr<const ContentsEntry> * ptr;
Data_Get_Struct(self, std::shared_ptr<const ContentsEntry>, ptr);
return metadata_key_to_value((std::static_pointer_cast<const ContentsSymEntry>(*ptr))->part_key());
}
/*
* call-seq:
* each_metadata {|key| block } -> Nil
*
* Our metadata.
*/
VALUE
contents_entry_each_metadata(VALUE self)
{
std::shared_ptr<const ContentsEntry> * self_ptr;
Data_Get_Struct(self, std::shared_ptr<const ContentsEntry>, self_ptr);
for (ContentsEntry::MetadataConstIterator it((*self_ptr)->begin_metadata()),
it_end((*self_ptr)->end_metadata()); it_end != it; ++it)
{
VALUE val(metadata_key_to_value(*it));
if (Qnil != val)
rb_yield(val);
}
return Qnil;
}
void do_register_contents()
{
/*
* Document-class: Paludis::Contents
*
* A package's contents. Includes Enumerable[http://www.ruby-doc.org/core/classes/Enumerable.html],
* but not Comparable.
*/
c_contents = rb_define_class_under(paludis_module(), "Contents", rb_cObject);
rb_include_module(c_contents, rb_mEnumerable);
rb_define_singleton_method(c_contents, "new", RUBY_FUNC_CAST(&contents_new), 0);
rb_define_method(c_contents, "initialize", RUBY_FUNC_CAST(&contents_init), 0);
rb_define_method(c_contents, "each", RUBY_FUNC_CAST(&contents_each), 0);
rb_define_method(c_contents, "add", RUBY_FUNC_CAST(&contents_add), 1);
/*
* Document-class: Paludis::ContentsEntry
*
* Base class for a ContentsEntry
*/
c_contents_entry = rb_define_class_under(paludis_module(), "ContentsEntry", rb_cObject);
rb_funcall(c_contents_entry, rb_intern("private_class_method"), 1, rb_str_new2("new"));
rb_define_method(c_contents_entry, "location_key", RUBY_FUNC_CAST(&contents_entry_location_key), 0);
rb_define_method(c_contents_entry, "initialize", RUBY_FUNC_CAST(&contents_entry_init),-1);
rb_define_method(c_contents_entry, "each_metadata", RUBY_FUNC_CAST(&contents_entry_each_metadata), 0);
/*
* Document-class: Paludis::ContentsFileEntry
*
* A file ContentsEntry
*/
c_contents_file_entry = rb_define_class_under(paludis_module(), "ContentsFileEntry", c_contents_entry);
rb_define_singleton_method(c_contents_file_entry, "new", RUBY_FUNC_CAST(&contents_file_entry_new), -1);
rb_define_method(c_contents_file_entry, "part_key", RUBY_FUNC_CAST(&contents_file_entry_part_key), 0);
/*
* Document-class: Paludis::ContentsDirEntry
*
* A directory ContentsEntry
*/
c_contents_dir_entry = rb_define_class_under(paludis_module(), "ContentsDirEntry", c_contents_entry);
rb_define_singleton_method(c_contents_dir_entry, "new", RUBY_FUNC_CAST((&ContentsNew<ContentsDirEntry>::contents_entry_new)), -1);
/*
* Document-class: Paludis::ContentsOtherEntry
*
* An 'other' ContentsEntry
*/
c_contents_other_entry = rb_define_class_under(paludis_module(), "ContentsOtherEntry", c_contents_entry);
rb_define_singleton_method(c_contents_other_entry, "new", RUBY_FUNC_CAST((&ContentsNew<ContentsOtherEntry>::contents_entry_new)), -1);
/*
* Document-class: Paludis::ContentsSymEntry
*
* A symlink ContentsEntry
*/
c_contents_sym_entry = rb_define_class_under(paludis_module(), "ContentsSymEntry", c_contents_entry);
rb_define_singleton_method(c_contents_sym_entry, "new", RUBY_FUNC_CAST(&contents_sym_entry_new), -1);
rb_define_method(c_contents_sym_entry, "target_key", RUBY_FUNC_CAST(&contents_sym_entry_target_key), 0);
rb_define_method(c_contents_sym_entry, "part_key", RUBY_FUNC_CAST(&contents_sym_entry_part_key), 0);
}
}
VALUE
paludis::ruby::contents_to_value(std::shared_ptr<const Contents> m)
{
std::shared_ptr<const Contents> * m_ptr(0);
try
{
m_ptr = new std::shared_ptr<const Contents>(m);
return Data_Wrap_Struct(c_contents, 0, &Common<std::shared_ptr<const Contents> >::free, m_ptr);
}
catch (const std::exception & e)
{
delete m_ptr;
exception_to_ruby_exception(e);
}
}
RegisterRubyClass::Register paludis_ruby_register_contents PALUDIS_ATTRIBUTE((used))
(&do_register_contents);