mirror of https://github.com/KLayout/klayout.git
WIP: keyword arguments for Ruby
This commit is contained in:
parent
702bcbe924
commit
8f9b904d87
|
|
@ -26,6 +26,7 @@
|
|||
#include "gsiExpression.h"
|
||||
#include "gsiSignals.h"
|
||||
#include "gsiInspector.h"
|
||||
#include "gsiVariantArgs.h"
|
||||
#include "tlString.h"
|
||||
#include "tlInternational.h"
|
||||
#include "tlException.h"
|
||||
|
|
@ -163,6 +164,24 @@ RubyStackTraceProvider::stack_depth ()
|
|||
}
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
static inline int
|
||||
num_args (const gsi::MethodBase *m)
|
||||
{
|
||||
return int (m->end_arguments () - m->begin_arguments ());
|
||||
}
|
||||
|
||||
static VALUE
|
||||
get_kwarg (const gsi::ArgType &atype, VALUE kwargs)
|
||||
{
|
||||
if (kwargs != Qnil) {
|
||||
return rb_hash_lookup2 (kwargs, rb_id2sym (rb_intern (atype.spec ()->name ().c_str ())), Qnil);
|
||||
} else {
|
||||
return Qnil;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// The lookup table for the method overload resolution
|
||||
|
||||
|
|
@ -277,15 +296,19 @@ public:
|
|||
return m_methods.end ();
|
||||
}
|
||||
|
||||
const gsi::MethodBase *get_variant (int argc, VALUE *argv, bool block_given, bool is_ctor, bool is_static, bool is_const) const
|
||||
const gsi::MethodBase *get_variant (int argc, VALUE *argv, VALUE kwargs, bool block_given, bool is_ctor, bool is_static, bool is_const) const
|
||||
{
|
||||
// caching can't work for arrays or hashes - in this case, give up
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
bool nocache = (kwargs != Qnil);
|
||||
|
||||
for (int i = 0; i < argc && ! nocache; ++i) {
|
||||
int t = TYPE (argv[i]);
|
||||
if (t == T_ARRAY || t == T_HASH) {
|
||||
return find_variant (argc, argv, block_given, is_ctor, is_static, is_const);
|
||||
}
|
||||
nocache = (t == T_ARRAY || t == T_HASH);
|
||||
}
|
||||
|
||||
if (nocache) {
|
||||
return find_variant (argc, argv, kwargs, block_given, is_ctor, is_static, is_const);
|
||||
}
|
||||
|
||||
// try to find the variant in the cache
|
||||
|
|
@ -296,13 +319,79 @@ public:
|
|||
return v->second;
|
||||
}
|
||||
|
||||
const gsi::MethodBase *meth = find_variant (argc, argv, block_given, is_ctor, is_static, is_const);
|
||||
const gsi::MethodBase *meth = find_variant (argc, argv, kwargs, block_given, is_ctor, is_static, is_const);
|
||||
m_variants[key] = meth;
|
||||
return meth;
|
||||
}
|
||||
|
||||
private:
|
||||
const gsi::MethodBase *find_variant (int argc, VALUE *argv, bool block_given, bool is_ctor, bool is_static, bool is_const) const
|
||||
static bool
|
||||
compatible_with_args (const gsi::MethodBase *m, int argc, VALUE kwargs)
|
||||
{
|
||||
int nargs = num_args (m);
|
||||
|
||||
if (argc >= nargs) {
|
||||
// no more arguments to consider
|
||||
return argc == nargs && (kwargs == Qnil || rb_hash_size_num (kwargs) == 0);
|
||||
}
|
||||
|
||||
if (kwargs != Qnil) {
|
||||
|
||||
int nkwargs = int (rb_hash_size_num (kwargs));
|
||||
int kwargs_taken = 0;
|
||||
|
||||
while (argc < nargs) {
|
||||
const gsi::ArgType &atype = m->begin_arguments () [argc];
|
||||
VALUE rb_arg = rb_hash_lookup2 (kwargs, rb_id2sym (rb_intern (atype.spec ()->name ().c_str ())), Qnil);
|
||||
if (rb_arg == Qnil) {
|
||||
if (! atype.spec ()->has_default ()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
++kwargs_taken;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
|
||||
// matches if all keyword arguments are taken
|
||||
return kwargs_taken == nkwargs;
|
||||
|
||||
} else {
|
||||
|
||||
while (argc < nargs) {
|
||||
const gsi::ArgType &atype = m->begin_arguments () [argc];
|
||||
if (! atype.spec ()->has_default ()) {
|
||||
return false;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
describe_overload (const gsi::MethodBase *m, int argc, VALUE kwargs)
|
||||
{
|
||||
std::string res = m->to_string ();
|
||||
if (compatible_with_args (m, argc, kwargs)) {
|
||||
res += " " + tl::to_string (tr ("[match candidate]"));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string
|
||||
describe_overloads (int argc, VALUE kwargs) const
|
||||
{
|
||||
std::string res;
|
||||
for (auto m = begin (); m != end (); ++m) {
|
||||
res += std::string (" ") + describe_overload (*m, argc, kwargs) + "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const gsi::MethodBase *find_variant (int argc, VALUE *argv, VALUE kwargs, bool block_given, bool is_ctor, bool is_static, bool is_const) const
|
||||
{
|
||||
// get number of candidates by argument count
|
||||
const gsi::MethodBase *meth = 0;
|
||||
|
|
@ -334,7 +423,7 @@ private:
|
|||
|
||||
// ignore callbacks
|
||||
|
||||
} else if ((*m)->compatible_with_num_args (argc)) {
|
||||
} else if (compatible_with_args (*m, argc, kwargs)) {
|
||||
|
||||
++candidates;
|
||||
meth = *m;
|
||||
|
|
@ -344,7 +433,7 @@ private:
|
|||
}
|
||||
|
||||
// no method found, but the ctor was requested - implement that method as replacement for the default "initialize"
|
||||
if (! meth && argc == 0 && is_ctor) {
|
||||
if (! meth && argc == 0 && is_ctor && kwargs == Qnil) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -366,7 +455,7 @@ private:
|
|||
nargs_s += tl::to_string (*na);
|
||||
}
|
||||
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid number of arguments (got %d, expected %s)")), argc, nargs_s));
|
||||
throw tl::Exception (tl::to_string (tr ("Can't match arguments. Variants are:\n")) + describe_overloads (argc, kwargs));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -383,13 +472,16 @@ private:
|
|||
if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
|
||||
|
||||
// check arguments (count and type)
|
||||
bool is_valid = (*m)->compatible_with_num_args (argc);
|
||||
bool is_valid = compatible_with_args (*m, argc, kwargs);
|
||||
int sc = 0;
|
||||
VALUE *av = argv;
|
||||
for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); is_valid && av < argv + argc && a != (*m)->end_arguments (); ++a, ++av) {
|
||||
if (test_arg (*a, *av, false /*strict*/)) {
|
||||
int i = 0;
|
||||
for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); is_valid && a != (*m)->end_arguments (); ++a, ++i) {
|
||||
VALUE arg = i >= argc ? get_kwarg (*a, kwargs) : argv[i];
|
||||
if (arg == Qnil) {
|
||||
is_valid = a->spec ()->has_default ();
|
||||
} else if (test_arg (*a, arg, false /*strict*/)) {
|
||||
++sc;
|
||||
} else if (test_arg (*a, *av, true /*loose*/)) {
|
||||
} else if (test_arg (*a, arg, true /*loose*/)) {
|
||||
// non-scoring match
|
||||
} else {
|
||||
is_valid = false;
|
||||
|
|
@ -414,12 +506,17 @@ private:
|
|||
|
||||
if (is_valid) {
|
||||
|
||||
// otherwise take the candidate with the better score
|
||||
if (candidates > 0 && sc > score) {
|
||||
candidates = 1;
|
||||
meth = *m;
|
||||
score = sc;
|
||||
} else if (candidates == 0 || sc == score) {
|
||||
// otherwise take the candidate with the better score or the least number of arguments (faster)
|
||||
if (candidates > 0) {
|
||||
if (sc > score || (sc == score && num_args (meth) > num_args (*m))) {
|
||||
candidates = 1;
|
||||
meth = *m;
|
||||
score = sc;
|
||||
} else if (sc == score && num_args (meth) == num_args (*m)) {
|
||||
++candidates;
|
||||
meth = *m;
|
||||
}
|
||||
} else {
|
||||
++candidates;
|
||||
meth = *m;
|
||||
score = sc;
|
||||
|
|
@ -434,11 +531,11 @@ private:
|
|||
}
|
||||
|
||||
if (! meth) {
|
||||
throw tl::Exception (tl::to_string (tr ("No overload with matching arguments")));
|
||||
throw tl::TypeError (tl::to_string (tr ("No overload with matching arguments. Variants are:\n")) + describe_overloads (argc, kwargs));
|
||||
}
|
||||
|
||||
if (candidates > 1) {
|
||||
throw tl::Exception (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments")));
|
||||
throw tl::TypeError (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments. Variants are:\n")) + describe_overloads (argc, kwargs));
|
||||
}
|
||||
|
||||
if (is_const && ! meth->is_const ()) {
|
||||
|
|
@ -943,16 +1040,64 @@ static gsi::ArgType create_void_type ()
|
|||
|
||||
static gsi::ArgType s_void_type = create_void_type ();
|
||||
|
||||
void
|
||||
push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, int argc, tl::Heap &heap)
|
||||
static int get_kwargs_keys (VALUE key, VALUE, VALUE arg)
|
||||
{
|
||||
int i = 0;
|
||||
std::set<std::string> *names = reinterpret_cast<std::set<std::string> *> (arg);
|
||||
names->insert (ruby2c<std::string> (key));
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, int argc, VALUE kwargs, tl::Heap &heap)
|
||||
{
|
||||
int iarg = 0;
|
||||
int kwargs_taken = 0;
|
||||
int nkwargs = kwargs == Qnil ? 0 : int (rb_hash_size_num (kwargs));
|
||||
|
||||
try {
|
||||
|
||||
VALUE *av = argv;
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && av < argv + argc; ++a, ++av, ++i) {
|
||||
push_arg (*a, arglist, *av, heap);
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a, ++iarg) {
|
||||
|
||||
VALUE arg = iarg >= argc ? get_kwarg (*a, kwargs) : argv[iarg];
|
||||
if (arg == Qnil) {
|
||||
if (a->spec ()->has_default ()) {
|
||||
if (kwargs_taken == nkwargs) {
|
||||
// leave it to the consumer to establish the default values (that is faster)
|
||||
break;
|
||||
}
|
||||
tl::Variant def_value = a->spec ()->default_value ();
|
||||
gsi::push_arg (arglist, *a, def_value, &heap);
|
||||
} else {
|
||||
throw tl::Exception (tl::to_string ("No argument provided (positional or keyword) and no default value available"));
|
||||
}
|
||||
} else {
|
||||
if (iarg >= argc) {
|
||||
++kwargs_taken;
|
||||
}
|
||||
push_arg (*a, arglist, arg, heap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (kwargs_taken != nkwargs) {
|
||||
|
||||
// check if there are any left-over keyword parameters with unknown names
|
||||
|
||||
std::set<std::string> invalid_names;
|
||||
rb_hash_foreach (kwargs, &get_kwargs_keys, reinterpret_cast<VALUE> (&invalid_names));
|
||||
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a) {
|
||||
invalid_names.erase (a->spec ()->name ());
|
||||
}
|
||||
|
||||
if (invalid_names.size () > 1) {
|
||||
std::string names_str = tl::join (invalid_names.begin (), invalid_names.end (), ", ");
|
||||
throw tl::Exception (tl::to_string (tr ("Unknown keyword parameters: ")) + names_str);
|
||||
} else if (invalid_names.size () == 1) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unknown keyword parameter: ")) + *invalid_names.begin ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
|
@ -960,28 +1105,34 @@ push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, i
|
|||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, 0, arglist, heap);
|
||||
pull_arg (*a, 0, arglist, heap);
|
||||
}
|
||||
|
||||
const gsi::ArgSpecBase *arg_spec = meth->begin_arguments () [i].spec ();
|
||||
if (iarg < num_args (meth)) {
|
||||
|
||||
const gsi::ArgSpecBase *arg_spec = meth->begin_arguments () [iarg].spec ();
|
||||
|
||||
std::string msg;
|
||||
if (arg_spec && ! arg_spec->name ().empty ()) {
|
||||
msg = tl::sprintf (tl::to_string (tr ("%s for argument #%d ('%s')")), ex.basic_msg (), iarg + 1, arg_spec->name ());
|
||||
} else {
|
||||
msg = tl::sprintf (tl::to_string (tr ("%s for argument #%d")), ex.basic_msg (), iarg + 1);
|
||||
}
|
||||
|
||||
tl::Exception new_ex (msg);
|
||||
new_ex.set_first_chance (ex.first_chance ());
|
||||
throw new_ex;
|
||||
|
||||
std::string msg;
|
||||
if (arg_spec && ! arg_spec->name ().empty ()) {
|
||||
msg = tl::sprintf (tl::to_string (tr ("%s for argument #%d ('%s')")), ex.basic_msg (), i + 1, arg_spec->name ());
|
||||
} else {
|
||||
msg = tl::sprintf (tl::to_string (tr ("%s for argument #%d")), ex.basic_msg (), i + 1);
|
||||
throw;
|
||||
}
|
||||
|
||||
tl::Exception new_ex (msg);
|
||||
new_ex.set_first_chance (ex.first_chance ());
|
||||
throw new_ex;
|
||||
|
||||
} catch (...) {
|
||||
|
||||
// In case of an error upon write, pop the arguments to clean them up.
|
||||
// Without this, there is a risk to keep dead objects on the stack.
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && arglist; ++a) {
|
||||
pop_arg (*a, 0, arglist, heap);
|
||||
pull_arg (*a, 0, arglist, heap);
|
||||
}
|
||||
|
||||
throw;
|
||||
|
|
@ -996,6 +1147,15 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
RBA_TRY
|
||||
|
||||
VALUE kwargs = Qnil;
|
||||
bool check_last = true;
|
||||
#if HAVE_RUBY_VERSION_CODE>=20700
|
||||
check_last = rb_keyword_given_p ();
|
||||
#endif
|
||||
if (check_last && argc > 0 && RB_TYPE_P (argv[argc - 1], T_HASH)) {
|
||||
kwargs = argv[--argc];
|
||||
}
|
||||
|
||||
tl::Heap heap;
|
||||
|
||||
const gsi::ClassBase *cls_decl;
|
||||
|
|
@ -1027,7 +1187,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
}
|
||||
|
||||
const gsi::MethodBase *meth = mt->entry (mid).get_variant (argc, argv, rb_block_given_p (), ctor, p == 0, p != 0 && p->const_ref ());
|
||||
const gsi::MethodBase *meth = mt->entry (mid).get_variant (argc, argv, kwargs, rb_block_given_p (), ctor, p == 0, p != 0 && p->const_ref ());
|
||||
|
||||
if (! meth) {
|
||||
|
||||
|
|
@ -1070,7 +1230,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
{
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
push_args (arglist, meth, argv, argc, heap);
|
||||
push_args (arglist, meth, argv, argc, kwargs, heap);
|
||||
meth->call (0, arglist, retlist);
|
||||
}
|
||||
|
||||
|
|
@ -1124,7 +1284,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
{
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
push_args (arglist, meth, argv, argc, heap);
|
||||
push_args (arglist, meth, argv, argc, kwargs, heap);
|
||||
meth->call (obj, arglist, retlist);
|
||||
}
|
||||
|
||||
|
|
@ -1143,7 +1303,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
rr.reset ();
|
||||
iter->get (rr);
|
||||
|
||||
VALUE value = pop_arg (meth->ret_type (), p, rr, heap);
|
||||
VALUE value = pull_arg (meth->ret_type (), p, rr, heap);
|
||||
rba_yield_checked (value);
|
||||
|
||||
iter->inc ();
|
||||
|
|
@ -1163,7 +1323,7 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor)
|
|||
|
||||
} else {
|
||||
|
||||
ret = pop_arg (meth->ret_type (), p, retlist, heap);
|
||||
ret = pull_arg (meth->ret_type (), p, retlist, heap);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1834,7 +1994,7 @@ public:
|
|||
gsi::SerialArgs arglist (c->meth->argsize ());
|
||||
c->meth->call (0, arglist, retlist);
|
||||
tl::Heap heap;
|
||||
VALUE ret = pop_arg (c->meth->ret_type (), 0, retlist, heap);
|
||||
VALUE ret = pull_arg (c->meth->ret_type (), 0, retlist, heap);
|
||||
rb_define_const (c->klass, c->name.c_str (), ret);
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
|
|
|
|||
|
|
@ -416,7 +416,7 @@ public:
|
|||
meth->call (obj, arglist, retlist);
|
||||
|
||||
tl::Heap heap;
|
||||
return pop_arg (meth->ret_type (), p, retlist, heap);
|
||||
return pull_arg (meth->ret_type (), p, retlist, heap);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ Proxy::call (int id, gsi::SerialArgs &args, gsi::SerialArgs &ret) const
|
|||
|
||||
// TODO: callbacks with default arguments?
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
rb_ary_push (argv, pop_arg (*a, 0, args, heap));
|
||||
rb_ary_push (argv, pull_arg (*a, 0, args, heap));
|
||||
}
|
||||
|
||||
VALUE rb_ret = rba_funcall2_checked (m_self, mid, RARRAY_LEN (argv), RARRAY_PTR (argv));
|
||||
|
|
@ -827,7 +827,7 @@ void SignalHandler::call (const gsi::MethodBase *meth, gsi::SerialArgs &args, gs
|
|||
|
||||
// TODO: signals with default arguments?
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); args && a != meth->end_arguments (); ++a) {
|
||||
rb_ary_push (argv, pop_arg (*a, 0, args, heap));
|
||||
rb_ary_push (argv, pull_arg (*a, 0, args, heap));
|
||||
}
|
||||
|
||||
// call the signal handlers ... the last one will deliver the return value
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
namespace rba
|
||||
{
|
||||
|
||||
void push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, int argc, tl::Heap &heap);
|
||||
void push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, int argc, VALUE kwargs, tl::Heap &heap);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Serialization adaptors for strings, variants, vectors and maps
|
||||
|
|
@ -521,7 +521,7 @@ struct writer <gsi::ObjectType>
|
|||
gsi::SerialArgs retlist (meth->retsize ());
|
||||
gsi::SerialArgs arglist (meth->argsize ());
|
||||
|
||||
push_args (arglist, meth, RARRAY_PTR (arg), n, *heap);
|
||||
push_args (arglist, meth, RARRAY_PTR (arg), n, Qnil, *heap);
|
||||
|
||||
meth->call (0, arglist, retlist);
|
||||
|
||||
|
|
@ -1026,10 +1026,10 @@ size_t RubyBasedMapAdaptor::serial_size () const
|
|||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Pops an argument from the call or return stack
|
||||
// Pulls an argument from the front of an argument queue
|
||||
|
||||
VALUE
|
||||
pop_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl::Heap &heap)
|
||||
pull_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl::Heap &heap)
|
||||
{
|
||||
VALUE ret = Qnil;
|
||||
gsi::do_on_type<reader> () (atype.type (), &aserial, &ret, self, atype, &heap);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class Proxy;
|
|||
*
|
||||
* "self" is a reference to the object that the method is called on or 0 if there is no such object.
|
||||
*/
|
||||
VALUE pop_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl::Heap &heap);
|
||||
VALUE pull_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl::Heap &heap);
|
||||
|
||||
/**
|
||||
* @brief Pushes an argument on the call or return stack
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ void run_rubytest (tl::TestBase * /*_this*/, const std::string &fn)
|
|||
#define RUBYTEST(n, file) \
|
||||
TEST(n) { run_rubytest(_this, file); }
|
||||
|
||||
RUBYTEST (kwargsTest, "kwargs.rb")
|
||||
RUBYTEST (antTest, "antTest.rb")
|
||||
RUBYTEST (dbBooleanTest, "dbBooleanTest.rb")
|
||||
RUBYTEST (dbBoxTest, "dbBoxTest.rb")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
# KLayout Layout Viewer
|
||||
# Copyright (C) 2006-2023 Matthias Koefferlein
|
||||
#
|
||||
# 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 2 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, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
if !$:.member?(File::dirname($0))
|
||||
$:.push(File::dirname($0))
|
||||
end
|
||||
|
||||
load("test_prologue.rb")
|
||||
|
||||
|
||||
# NOTE: RBA::CplxTrans and RBA::Trans and good test cases
|
||||
# for the keyword arguments feature
|
||||
|
||||
class KWArgs_TestClass < TestBase
|
||||
|
||||
def test_1
|
||||
|
||||
t = RBA::CplxTrans::new()
|
||||
assert_equal(t.to_s, "r0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(1.5)
|
||||
assert_equal(t.to_s, "r0 *1.5 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(1, 2)
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(1, y: 2)
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(x: 1, y: 2)
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(u: RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(u: RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(u: [1, 2])
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(mag: 1.5)
|
||||
assert_equal(t.to_s, "r0 *1.5 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(1.5, 45, true, 1, 2)
|
||||
assert_equal(t.to_s, "m22.5 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(1.5, 45, true, RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "m22.5 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(1.5, x: 1, y: 2, mirrx: true, rot: 45)
|
||||
assert_equal(t.to_s, "m22.5 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0)
|
||||
assert_equal(t.to_s, "m0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0, u: RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "m0 *1 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0, mag: 1.5, u: RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "m0 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0, 1.5, RBA::DVector::new(1, 2))
|
||||
assert_equal(t.to_s, "m0 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0, mag: 1.5, x: 1, y: 2)
|
||||
assert_equal(t.to_s, "m0 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::CplxTrans::M0, 1.5, 1, 2)
|
||||
assert_equal(t.to_s, "m0 *1.5 1,2")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::VCplxTrans::M0)
|
||||
assert_equal(t.to_s, "m0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::ICplxTrans::M0)
|
||||
assert_equal(t.to_s, "m0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::DCplxTrans::M0)
|
||||
assert_equal(t.to_s, "m0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::Trans::M0)
|
||||
assert_equal(t.to_s, "m0 *1 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::Trans::M0, 1.5)
|
||||
assert_equal(t.to_s, "m0 *1.5 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(RBA::Trans::M0, mag: 1.5)
|
||||
assert_equal(t.to_s, "m0 *1.5 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new(t: RBA::Trans::M0, mag: 1.5)
|
||||
assert_equal(t.to_s, "m0 *1.5 0,0")
|
||||
|
||||
t = RBA::CplxTrans::new
|
||||
t.disp = [1, 2]
|
||||
assert_equal(t.to_s, "r0 *1 1,2")
|
||||
|
||||
t = RBA::ICplxTrans::new(15, 25)
|
||||
assert_equal(t.to_s(dbu: 0.01), "r0 *1 0.15000,0.25000")
|
||||
|
||||
end
|
||||
|
||||
def test_2
|
||||
|
||||
t = RBA::Trans::new(RBA::Trans::M0, 1, 2)
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(RBA::Trans::M0, x: 1, y: 2)
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(RBA::Trans::M0, RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(RBA::Trans::M0, u: RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(rot: 3, mirrx: true)
|
||||
assert_equal(t.to_s, "m135 0,0")
|
||||
|
||||
t = RBA::Trans::new(rot: 3, mirrx: true, x: 1, y: 2)
|
||||
assert_equal(t.to_s, "m135 1,2")
|
||||
|
||||
t = RBA::Trans::new(3, true, 1, 2)
|
||||
assert_equal(t.to_s, "m135 1,2")
|
||||
|
||||
t = RBA::Trans::new(3, true, RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "m135 1,2")
|
||||
|
||||
t = RBA::Trans::new(rot: 3, mirrx: true, u: RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "m135 1,2")
|
||||
|
||||
t = RBA::Trans::new
|
||||
assert_equal(t.to_s, "r0 0,0")
|
||||
|
||||
t = RBA::Trans::new(RBA::DTrans::M0)
|
||||
assert_equal(t.to_s, "m0 0,0")
|
||||
|
||||
t = RBA::Trans::new(RBA::DTrans::M0, 1, 2)
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(RBA::DTrans::M0, x: 1, y: 2)
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(c: RBA::DTrans::M0, x: 1, y: 2)
|
||||
assert_equal(t.to_s, "m0 1,2")
|
||||
|
||||
t = RBA::Trans::new(RBA::Vector::new(1, 2))
|
||||
assert_equal(t.to_s, "r0 1,2")
|
||||
|
||||
t = RBA::Trans::new(1, 2)
|
||||
assert_equal(t.to_s, "r0 1,2")
|
||||
|
||||
end
|
||||
|
||||
def test_3
|
||||
|
||||
begin
|
||||
t = RBA::CplxTrans::new(1.5, 2.5)
|
||||
t.to_s(dbu: "17")
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s, "TypeError: no implicit conversion to float from string for argument #2 ('dbu') in CplxTrans::to_s")
|
||||
end
|
||||
|
||||
begin
|
||||
t = RBA::CplxTrans::new("17")
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s.index("No overload with matching arguments."), 0)
|
||||
end
|
||||
|
||||
begin
|
||||
t = RBA::CplxTrans::new(uu: 17)
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s.index("Can't match arguments."), 0)
|
||||
end
|
||||
|
||||
begin
|
||||
t = RBA::CplxTrans::new(u: "17")
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s.index("No overload with matching arguments."), 0)
|
||||
end
|
||||
|
||||
begin
|
||||
t = RBA::Trans::new("17")
|
||||
assert_equal(true, false)
|
||||
rescue => ex
|
||||
assert_equal(ex.to_s.index("No overload with matching arguments."), 0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
||||
Loading…
Reference in New Issue