aboutsummaryrefslogtreecommitdiff
path: root/ruby
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-09-23 06:41:55 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-09-23 06:41:55 +0000
commite544ea1c4ea59000f53582a4f1a52b89caa1db8f (patch)
tree6e0716a464b6fc4cd42cc63c793a7ec8a667f9f7 /ruby
parent837ed5227bbe789d97eea6c323619706678b32ff (diff)
downloadpaludis-e544ea1c4ea59000f53582a4f1a52b89caa1db8f.tar.gz
paludis-e544ea1c4ea59000f53582a4f1a52b89caa1db8f.tar.xz
Add the start of a Ruby interface. Tidy up some of the makefiles.
Diffstat (limited to 'ruby')
-rw-r--r--ruby/Makefile.am58
-rw-r--r--ruby/name.cc131
-rw-r--r--ruby/name_TEST.rb130
-rw-r--r--ruby/paludis_ruby.cc62
-rw-r--r--ruby/paludis_ruby.hh43
-rw-r--r--ruby/paludis_ruby_TEST.rb11
6 files changed, 435 insertions, 0 deletions
diff --git a/ruby/Makefile.am b/ruby/Makefile.am
new file mode 100644
index 000000000..28b20827d
--- /dev/null
+++ b/ruby/Makefile.am
@@ -0,0 +1,58 @@
+SUBDIRS = .
+
+AM_CXXFLAGS = -I$(top_srcdir) -I$(srcdir)/ \
+ @PALUDIS_CXXFLAGS_WITHOUT_PEDANTIC@ \
+ @PALUDIS_CXXFLAGS_NO_WREDUNDANT_DECLS@ \
+ @PALUDIS_CXXFLAGS_NO_WOLD_STYLE_CAST@
+
+DEFS= \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda *.o *.so
+MAINTAINERCLEANFILES = Makefile.in
+
+IF_RUBY_TESTS = paludis_ruby_TEST.rb name_TEST.rb
+IF_RUBY_SOURCES = paludis_ruby.cc paludis_ruby.hh name.cc
+EXTRA_DIST = $(IF_RUBY_TESTS) $(IF_RUBY_SOURCES)
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_NO_GLOBAL_HOOKS="yes" \
+ PALUDIS_NO_XTERM_TITLES="yes" \
+ PALUDIS_EBUILD_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_srcdir)/ebuild/`" \
+ PALUDIS_EBUILD_DIR_FALLBACK="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/ebuild/`" \
+ PALUDIS_REPOSITORY_SO_DIR="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/paludis/repositories`" \
+ LD_LIBRARY_PATH="`$(top_srcdir)/ebuild/utils/canonicalise $(top_builddir)/paludis/.libs`" \
+ ruby -I ./
+
+if ENABLE_RUBY
+
+TESTS = $(IF_RUBY_TESTS)
+OUR_OBJECTS = name.o paludis_ruby.o
+noinst_DATA = $(OUR_OBJECTS)
+rubylibdir = $(DESTDIR)/@RUBY_SITEARCHDIR@
+rubylib_DATA = Paludis.so
+
+OUR_CXXCOMPILE = $(CXX) -fPIC $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ -I. -I@RUBY_SITEARCHDIR@ -I@RUBY_ARCHDIR@ -c
+
+paludis_ruby.o : paludis_ruby.cc paludis_ruby.hh
+ $(OUR_CXXCOMPILE) -o $@ $(srcdir)/paludis_ruby.cc
+
+name.o : name.cc paludis_ruby.hh
+ $(OUR_CXXCOMPILE) -o $@ $(srcdir)/name.cc
+
+Paludis.so : $(OUR_OBJECTS)
+ $(CXX) -fPIC -shared $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -I@RUBY_SITEARCHDIR@ -l@RUBY_SONAME@ \
+ -L$(top_builddir)/paludis/.libs -lpaludis -o $@ $^
+
+clean-local :
+ rm -fr Paludis.so .checkimage || true
+
+endif
+
diff --git a/ruby/name.cc b/ruby/name.cc
new file mode 100644
index 000000000..928d5b1ec
--- /dev/null
+++ b/ruby/name.cc
@@ -0,0 +1,131 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include <paludis_ruby.hh>
+#include <paludis/name.hh>
+#include <paludis/util/compare.hh>
+#include <ruby.h>
+
+using namespace paludis;
+using namespace paludis::ruby;
+
+#define RUBY_FUNC_CAST(x) reinterpret_cast<VALUE (*)(...)>(x)
+
+namespace
+{
+ template <typename T_, typename E_>
+ struct NameWrapper
+ {
+ static VALUE c_class;
+ static VALUE c_class_except;
+
+ static void
+ name_part_error_free(void * ptr)
+ {
+ delete static_cast<std::string *>(ptr);
+ }
+
+ static VALUE
+ name_part_error_new(VALUE the_class, VALUE value)
+ {
+ VALUE argv[1];
+ std::string * ptr(new std::string(STR2CSTR(value)));
+ VALUE tdata(Data_Wrap_Struct(the_class, 0, &name_part_error_free, ptr));
+ argv[0] = value;
+ rb_obj_call_init(tdata, 1, argv);
+ rb_call_super(1, &value);
+ return tdata;
+ }
+
+ static VALUE
+ name_part_error_init(VALUE self, VALUE)
+ {
+ return self;
+ }
+
+ static void
+ name_part_free(void * ptr)
+ {
+ delete static_cast<T_ *>(ptr);
+ }
+
+ static VALUE
+ name_part_new(VALUE the_class, VALUE value)
+ {
+ VALUE argv[1];
+ T_ * ptr(0);
+ try
+ {
+ ptr = new T_(std::string(STR2CSTR(value)));
+ VALUE tdata(Data_Wrap_Struct(the_class, 0, &name_part_free, ptr));
+ argv[0] = value;
+ rb_obj_call_init(tdata, 1, argv);
+ return tdata;
+ }
+ catch (const NameError & e)
+ {
+ delete ptr;
+ rb_raise(c_class_except, e.message().c_str());
+ }
+ catch (const std::exception & e)
+ {
+ delete ptr;
+ exception_to_ruby_exception(e);
+ }
+ }
+
+ static VALUE
+ name_part_compare(VALUE left, VALUE right)
+ {
+ T_ * left_ptr, * right_ptr;
+ Data_Get_Struct(left, T_, left_ptr);
+ Data_Get_Struct(right, T_, right_ptr);
+
+ return INT2FIX(compare(*left_ptr, *right_ptr));
+ }
+
+ static VALUE
+ name_part_to_s(VALUE left)
+ {
+ T_ * left_ptr;
+ Data_Get_Struct(left, T_, left_ptr);
+
+ return rb_str_new2(left_ptr->data().c_str());
+ }
+
+ static VALUE
+ name_part_init(VALUE self, VALUE)
+ {
+ return self;
+ }
+
+ static void do_register(const std::string & name)
+ {
+ c_class = rb_define_class(name.c_str(), rb_cObject);
+ rb_define_singleton_method(c_class, "new", RUBY_FUNC_CAST(&name_part_new), 1);
+ rb_define_method(c_class, "initialize", RUBY_FUNC_CAST(&name_part_init), 1);
+ rb_define_method(c_class, "<=>", RUBY_FUNC_CAST(&name_part_compare), 1);
+ rb_include_module(c_class, rb_mComparable);
+ rb_define_method(c_class, "to_s", RUBY_FUNC_CAST(&name_part_to_s), 0);
+
+ c_class_except = rb_define_class((name + "Error").c_str(), rb_eRuntimeError);
+ rb_define_singleton_method(c_class_except, "new", RUBY_FUNC_CAST(&name_part_error_new), 1);
+ rb_define_method(c_class_except, "initialize", RUBY_FUNC_CAST(&name_part_error_init), 1);
+ }
+ };
+
+ template <typename T_, typename E_> VALUE NameWrapper<T_, E_>::c_class;
+ template <typename T_, typename E_> VALUE NameWrapper<T_, E_>::c_class_except;
+
+ void do_register_names()
+ {
+ NameWrapper<PackageNamePart, PackageNamePartError>::do_register("PackageNamePart");
+ NameWrapper<CategoryNamePart, CategoryNamePartError>::do_register("CategoryNamePart");
+ NameWrapper<UseFlagName, UseFlagNameError>::do_register("UseFlagName");
+ NameWrapper<SlotName, SlotNameError>::do_register("SlotName");
+ NameWrapper<RepositoryName, RepositoryNameError>::do_register("RepositoryName");
+ NameWrapper<KeywordName, KeywordNameError>::do_register("KeywordName");
+ }
+}
+
+RegisterRubyClass::Register paludis_ruby_register_name PALUDIS_ATTRIBUTE((used)) (&do_register_names);
+
diff --git a/ruby/name_TEST.rb b/ruby/name_TEST.rb
new file mode 100644
index 000000000..6e35cc399
--- /dev/null
+++ b/ruby/name_TEST.rb
@@ -0,0 +1,130 @@
+#!/usr/bin/ruby
+# vim: set sw=4 sts=4 et tw=80 :
+
+require 'test/unit'
+require 'Paludis'
+
+module NameTestCaseBase
+ def valid_name_foo
+ return "foo"
+ end
+
+ def valid_name_bar
+ return "bar"
+ end
+
+ def bad_name
+ return "foo~"
+ end
+
+ def test_create
+ x = name_type().new(valid_name_foo())
+ end
+
+ def test_assign
+ x = name_type().new(valid_name_foo())
+ y = x
+ end
+
+ def test_compare
+ x = name_type().new(valid_name_foo())
+ y = name_type().new(valid_name_foo())
+ z = name_type().new(valid_name_bar())
+ assert x == y
+ assert y != z
+ assert z < x
+ assert x > z
+ assert_raise TypeError do
+ x < valid_name_foo()
+ end
+ end
+
+ def test_create_errors
+ assert_raise error_type() do
+ x = name_type().new(bad_name())
+ end
+ assert_raise error_type() do
+ x = name_type().new("")
+ end
+ end
+
+ def test_to_s
+ x = name_type().new(valid_name_foo())
+ y = name_type().new(valid_name_bar())
+ assert x.to_s == valid_name_foo()
+ assert y.to_s == valid_name_bar()
+ end
+end
+
+class TestCase_PackageNamePart < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return PackageNamePartError
+ end
+
+ def name_type
+ return PackageNamePart
+ end
+end
+
+class TestCase_CategoryNamePart < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return CategoryNamePartError
+ end
+
+ def name_type
+ return CategoryNamePart
+ end
+end
+
+class TestCase_UseFlagName < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return UseFlagNameError
+ end
+
+ def name_type
+ return UseFlagName
+ end
+end
+
+class TestCase_RepositoryName < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return RepositoryNameError
+ end
+
+ def name_type
+ return RepositoryName
+ end
+end
+
+class TestCase_SlotName < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return SlotNameError
+ end
+
+ def name_type
+ return SlotName
+ end
+end
+
+class TestCase_KeywordName < Test::Unit::TestCase
+ include NameTestCaseBase
+
+ def error_type
+ return KeywordNameError
+ end
+
+ def name_type
+ return KeywordName
+ end
+end
+
diff --git a/ruby/paludis_ruby.cc b/ruby/paludis_ruby.cc
new file mode 100644
index 000000000..d70e48039
--- /dev/null
+++ b/ruby/paludis_ruby.cc
@@ -0,0 +1,62 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include <paludis/paludis.hh>
+#include <paludis_ruby.hh>
+#include <ruby.h>
+#include <list>
+
+using namespace paludis;
+using namespace paludis::ruby;
+
+namespace paludis
+{
+ template<>
+ struct Implementation<RegisterRubyClass> :
+ InternalCounted<Implementation<RegisterRubyClass> >
+ {
+ std::list<void (*)()> funcs;
+ };
+}
+
+RegisterRubyClass::RegisterRubyClass() :
+ PrivateImplementationPattern<RegisterRubyClass>(new Implementation<RegisterRubyClass>)
+{
+}
+
+RegisterRubyClass::~RegisterRubyClass()
+{
+}
+
+void
+RegisterRubyClass::execute() const
+{
+ for (std::list<void (*)()>::const_iterator f(_imp->funcs.begin()), f_end(_imp->funcs.end()) ;
+ f != f_end ; ++f)
+ (*f)();
+}
+
+RegisterRubyClass::Register::Register(void (* f)())
+{
+ RegisterRubyClass::get_instance()->_imp->funcs.push_back(f);
+}
+
+void paludis::ruby::exception_to_ruby_exception(const std::exception & ee)
+{
+ if (0 != dynamic_cast<const paludis::InternalError *>(&ee))
+ rb_raise(rb_eRuntimeError, "Unexpected paludis::InternalError: %s (%s)",
+ dynamic_cast<const paludis::InternalError *>(&ee)->message().c_str(), ee.what());
+ else if (0 != dynamic_cast<const paludis::Exception *>(&ee))
+ rb_raise(rb_eRuntimeError, "Caught paludis::Exception: %s (%s)",
+ dynamic_cast<const paludis::Exception *>(&ee)->message().c_str(), ee.what());
+ else
+ rb_raise(rb_eRuntimeError, "Unexpected std::exception: (%s)", ee.what());
+}
+
+extern "C"
+{
+ void Init_Paludis()
+ {
+ RegisterRubyClass::get_instance()->execute();
+ }
+}
+
diff --git a/ruby/paludis_ruby.hh b/ruby/paludis_ruby.hh
new file mode 100644
index 000000000..74e929605
--- /dev/null
+++ b/ruby/paludis_ruby.hh
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_RUBY_RUBY_PALUDIS_RUBY_HH
+#define PALUDIS_GUARD_RUBY_RUBY_PALUDIS_RUBY_HH 1
+
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/exception.hh>
+
+namespace paludis
+{
+ namespace ruby
+ {
+ void exception_to_ruby_exception(const std::exception &) PALUDIS_ATTRIBUTE((noreturn));
+
+ class RegisterRubyClass :
+ public InstantiationPolicy<RegisterRubyClass, instantiation_method::SingletonAsNeededTag>,
+ private PrivateImplementationPattern<RegisterRubyClass>
+ {
+ friend class InstantiationPolicy<RegisterRubyClass, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ RegisterRubyClass();
+ ~RegisterRubyClass();
+
+ public:
+ class Register;
+ friend class Register;
+
+ void execute() const;
+ };
+
+ class RegisterRubyClass::Register :
+ public InstantiationPolicy<RegisterRubyClass, instantiation_method::NonCopyableTag>
+ {
+ public:
+ Register(void (* func)());
+ };
+ }
+}
+
+#endif
diff --git a/ruby/paludis_ruby_TEST.rb b/ruby/paludis_ruby_TEST.rb
new file mode 100644
index 000000000..77cdfc27f
--- /dev/null
+++ b/ruby/paludis_ruby_TEST.rb
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+# vim: set sw=4 sts=4 et tw=80 :
+
+require 'test/unit'
+
+class TC_Basic < Test::Unit::TestCase
+ def test_require
+ require 'Paludis'
+ end
+end
+