diff options
author | 2006-09-23 06:41:55 +0000 | |
---|---|---|
committer | 2006-09-23 06:41:55 +0000 | |
commit | e544ea1c4ea59000f53582a4f1a52b89caa1db8f (patch) | |
tree | 6e0716a464b6fc4cd42cc63c793a7ec8a667f9f7 /ruby | |
parent | 837ed5227bbe789d97eea6c323619706678b32ff (diff) | |
download | paludis-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.am | 58 | ||||
-rw-r--r-- | ruby/name.cc | 131 | ||||
-rw-r--r-- | ruby/name_TEST.rb | 130 | ||||
-rw-r--r-- | ruby/paludis_ruby.cc | 62 | ||||
-rw-r--r-- | ruby/paludis_ruby.hh | 43 | ||||
-rw-r--r-- | ruby/paludis_ruby_TEST.rb | 11 |
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 + |