File Annotation
Not logged in
4198578702 2010-11-07        kinaba: /**
4198578702 2010-11-07        kinaba:  * Authors: k.inaba
4198578702 2010-11-07        kinaba:  * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4198578702 2010-11-07        kinaba:  *
4198578702 2010-11-07        kinaba:  * Common tricks and utilities for programming in D.
423f308350 2010-11-07        kinaba:  */
4198578702 2010-11-07        kinaba: module polemy.tricks;
b0d8d7875b 2010-11-08        kinaba: import std.array      : appender;
b0d8d7875b 2010-11-08        kinaba: import std.format     : formattedWrite;
b0d8d7875b 2010-11-08        kinaba: import core.exception : onAssertErrorMsg, AssertError;
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: /// Simple Wrapper for std.format.doFormat
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: string sprintf(string fmt, T...)(T params)
423f308350 2010-11-07        kinaba: {
b0d8d7875b 2010-11-08        kinaba: 	auto writer = appender!string();
b0d8d7875b 2010-11-08        kinaba: 	formattedWrite(writer, fmt, params);
423f308350 2010-11-07        kinaba: 	return writer.data;
423f308350 2010-11-07        kinaba: }
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: unittest
423f308350 2010-11-07        kinaba: {
5e407d7cf8 2010-11-08        kinaba: 	assert( sprintf!"%s == %d"("1+2", 3)   == "1+2 == 3" );
423f308350 2010-11-07        kinaba: 	assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" );
423f308350 2010-11-07        kinaba: }
423f308350 2010-11-07        kinaba: 
61998c472a 2010-11-08        kinaba: /// Unittest helper that asserts an expression must throw something
61998c472a 2010-11-08        kinaba: 
61998c472a 2010-11-08        kinaba: void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
61998c472a 2010-11-08        kinaba: {
61998c472a 2010-11-08        kinaba: 	try {
61998c472a 2010-11-08        kinaba: 		t();
61998c472a 2010-11-08        kinaba: 	} catch(ExceptionType) {
61998c472a 2010-11-08        kinaba: 		return;
61998c472a 2010-11-08        kinaba: 	} catch(Throwable e) {
b0d8d7875b 2010-11-08        kinaba: 		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
61998c472a 2010-11-08        kinaba: 	}
b0d8d7875b 2010-11-08        kinaba: 	onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption");
61998c472a 2010-11-08        kinaba: }
61998c472a 2010-11-08        kinaba: 
61998c472a 2010-11-08        kinaba: /// Unittest helper that asserts an expression must not throw anything
61998c472a 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: void assert_nothrow(T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="")
61998c472a 2010-11-08        kinaba: {
61998c472a 2010-11-08        kinaba: 	try {
61998c472a 2010-11-08        kinaba: 		t();
61998c472a 2010-11-08        kinaba: 	} catch(Throwable e) {
b0d8d7875b 2010-11-08        kinaba: 		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
b0d8d7875b 2010-11-08        kinaba: 	}
b0d8d7875b 2010-11-08        kinaba: }
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: unittest
b0d8d7875b 2010-11-08        kinaba: {
b0d8d7875b 2010-11-08        kinaba: 	auto error = {throw new Error("hello");};
b0d8d7875b 2010-11-08        kinaba: 	auto nothing = (){};
b0d8d7875b 2010-11-08        kinaba: 	auto assertError = {assert(0);};
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	assert_nothrow          ( assert_nothrow(nothing()) );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_nothrow(error()) );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_nothrow(assertError()) );
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	assert_nothrow          ( assert_throw!Error(error()) );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_throw!Error(nothing()) );
b0d8d7875b 2010-11-08        kinaba: 	assert_nothrow          ( assert_throw!Error(assertError()) );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_throw!AssertError(error()) );
b0d8d7875b 2010-11-08        kinaba: }
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: /// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >=
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: template assertOp(string op)
b0d8d7875b 2010-11-08        kinaba: {
b0d8d7875b 2010-11-08        kinaba: 	void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="")
b0d8d7875b 2010-11-08        kinaba: 	{
b0d8d7875b 2010-11-08        kinaba: 		try {
b0d8d7875b 2010-11-08        kinaba: 			if( mixin("a"~op~"b") ) return;
b0d8d7875b 2010-11-08        kinaba: 		} catch(Throwable e) {
b0d8d7875b 2010-11-08        kinaba: 			onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e));
b0d8d7875b 2010-11-08        kinaba: 		}
b0d8d7875b 2010-11-08        kinaba: 		onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b));
61998c472a 2010-11-08        kinaba: 	}
b0d8d7875b 2010-11-08        kinaba: }
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`==`) assert_eq;
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`!=`) assert_ne;
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`<`)  assert_lt;
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`<=`) assert_le;
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`>`)  assert_gt;
b0d8d7875b 2010-11-08        kinaba: alias assertOp!(`>=`) assert_ge;
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: unittest
b0d8d7875b 2010-11-08        kinaba: {
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_eq(1, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_ne(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_lt(0, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_le(0, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_le(0, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_gt(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_ge(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_nothrow( assert_ge(0, 0) );
b0d8d7875b 2010-11-08        kinaba: 
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_eq(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_ne(1, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_lt(1, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_lt(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_le(1, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_gt(0, 0) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_gt(0, 1) );
5e407d7cf8 2010-11-08        kinaba: 	assert_throw!AssertError( assert_ge(0, 1) );
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	class Temp { bool opEquals(int x){return x/x==x;} }
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_eq(new Temp, 0) );
b0d8d7875b 2010-11-08        kinaba: 	assert_nothrow          ( assert_eq(new Temp, 1) );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( assert_eq(new Temp, 2) );
61998c472a 2010-11-08        kinaba: }
61998c472a 2010-11-08        kinaba: 
61998c472a 2010-11-08        kinaba: /* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */
61998c472a 2010-11-08        kinaba: 
423f308350 2010-11-07        kinaba: /// Mixing-in the bean constructor for a class
423f308350 2010-11-07        kinaba: 
80ff567c75 2010-11-08        kinaba: /*mixin*/
80ff567c75 2010-11-08        kinaba: template SimpleConstructor()
423f308350 2010-11-07        kinaba: {
423f308350 2010-11-07        kinaba: 	static if( is(typeof(super) == Object) || super.tupleof.length==0 )
423f308350 2010-11-07        kinaba: 		this( typeof(this.tupleof) params )
423f308350 2010-11-07        kinaba: 		{
0569f7b8c2 2010-11-07        kinaba: 			static if(this.tupleof.length>0)
0569f7b8c2 2010-11-07        kinaba: 				this.tupleof = params;
423f308350 2010-11-07        kinaba: 		}
423f308350 2010-11-07        kinaba: 	else
423f308350 2010-11-07        kinaba: 		this( typeof(super.tupleof) ps, typeof(this.tupleof) params )
423f308350 2010-11-07        kinaba: 		{
61998c472a 2010-11-08        kinaba: 			// including (only) the direct super class members
61998c472a 2010-11-08        kinaba: 			// may not always be a desirable choice, but should work for many cases
423f308350 2010-11-07        kinaba: 			super(ps);
0569f7b8c2 2010-11-07        kinaba: 			static if(this.tupleof.length>0)
0569f7b8c2 2010-11-07        kinaba: 				this.tupleof = params;
0569f7b8c2 2010-11-07        kinaba: 		}
0569f7b8c2 2010-11-07        kinaba: }
0569f7b8c2 2010-11-07        kinaba: 
61998c472a 2010-11-08        kinaba: unittest
61998c472a 2010-11-08        kinaba: {
61998c472a 2010-11-08        kinaba: 	class Temp
61998c472a 2010-11-08        kinaba: 	{
61998c472a 2010-11-08        kinaba: 		int x;
61998c472a 2010-11-08        kinaba: 		string y;
61998c472a 2010-11-08        kinaba: 		mixin SimpleConstructor;
61998c472a 2010-11-08        kinaba: 	}
61998c472a 2010-11-08        kinaba: 	assert_eq( (new Temp(1,"foo")).x, 1 );
61998c472a 2010-11-08        kinaba: 	assert_eq( (new Temp(1,"foo")).y, "foo" );
61998c472a 2010-11-08        kinaba: 	assert( !__traits(compiles, new Temp) );
61998c472a 2010-11-08        kinaba: 	assert( !__traits(compiles, new Temp(1)) );
61998c472a 2010-11-08        kinaba: 	assert( !__traits(compiles, new Temp("foo",1)) );
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	class Tomp : Temp
b0d8d7875b 2010-11-08        kinaba: 	{
b0d8d7875b 2010-11-08        kinaba: 		real z;
b0d8d7875b 2010-11-08        kinaba: 		mixin SimpleConstructor;
b0d8d7875b 2010-11-08        kinaba: 	}
b0d8d7875b 2010-11-08        kinaba: 	assert_eq( (new Tomp(1,"foo",2.5)).x, 1 );
b0d8d7875b 2010-11-08        kinaba: 	assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" );
b0d8d7875b 2010-11-08        kinaba: 	assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 );
b0d8d7875b 2010-11-08        kinaba: 	assert( !__traits(compiles, new Tomp(3.14)) );
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	// shiyo- desu. Don't use in this way.
b0d8d7875b 2010-11-08        kinaba: 	//   Tamp tries to call new Tomp(real) (because it only sees Tomp's members),
b0d8d7875b 2010-11-08        kinaba: 	//   but it fails because Tomp takes (int,string,real).
b0d8d7875b 2010-11-08        kinaba: 	assert( !__traits(compiles, {
b0d8d7875b 2010-11-08        kinaba: 		class Tamp : Tomp
b0d8d7875b 2010-11-08        kinaba: 		{
b0d8d7875b 2010-11-08        kinaba: 			mixin SimpleConstructor;
b0d8d7875b 2010-11-08        kinaba: 		}
b0d8d7875b 2010-11-08        kinaba: 	}) );
61998c472a 2010-11-08        kinaba: }
61998c472a 2010-11-08        kinaba: 
820e7198cc 2010-11-07        kinaba: /// Mixing-in the MOST-DERIVED-member-wise comparator for a class
423f308350 2010-11-07        kinaba: 
80ff567c75 2010-11-08        kinaba: /*mixin*/
80ff567c75 2010-11-08        kinaba: template SimpleCompare()
423f308350 2010-11-07        kinaba: {
423f308350 2010-11-07        kinaba: 	override bool opEquals(Object rhs_) const
423f308350 2010-11-07        kinaba: 	{
423f308350 2010-11-07        kinaba: 		if( auto rhs = cast(typeof(this))rhs_ )
423f308350 2010-11-07        kinaba: 		{
423f308350 2010-11-07        kinaba: 			foreach(i,_; this.tupleof)
423f308350 2010-11-07        kinaba: 				if( this.tupleof[i] != rhs.tupleof[i] )
423f308350 2010-11-07        kinaba: 					return false;
423f308350 2010-11-07        kinaba: 			return true;
423f308350 2010-11-07        kinaba: 		}
423f308350 2010-11-07        kinaba: 		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
423f308350 2010-11-07        kinaba: 	}
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: 	override hash_t toHash() const
423f308350 2010-11-07        kinaba: 	{
423f308350 2010-11-07        kinaba: 		hash_t h = 0;
423f308350 2010-11-07        kinaba: 		foreach(mem; this.tupleof)
423f308350 2010-11-07        kinaba: 			h += typeid(mem).getHash(&mem);
423f308350 2010-11-07        kinaba: 		return h;
423f308350 2010-11-07        kinaba: 	}
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: 	override int opCmp(Object rhs_) const
423f308350 2010-11-07        kinaba: 	{
423f308350 2010-11-07        kinaba: 		if( auto rhs = cast(typeof(this))rhs_ )
423f308350 2010-11-07        kinaba: 		{
423f308350 2010-11-07        kinaba: 			foreach(i,_; this.tupleof)
423f308350 2010-11-07        kinaba: 				if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i]))
423f308350 2010-11-07        kinaba: 					return c;
423f308350 2010-11-07        kinaba: 			return 0;
423f308350 2010-11-07        kinaba: 		}
423f308350 2010-11-07        kinaba: 		assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
423f308350 2010-11-07        kinaba: 	}
423f308350 2010-11-07        kinaba: }
423f308350 2010-11-07        kinaba: 
423f308350 2010-11-07        kinaba: unittest
423f308350 2010-11-07        kinaba: {
423f308350 2010-11-07        kinaba: 	class Temp
423f308350 2010-11-07        kinaba: 	{
423f308350 2010-11-07        kinaba: 		int x;
423f308350 2010-11-07        kinaba: 		string y;
423f308350 2010-11-07        kinaba: 		mixin SimpleConstructor;
423f308350 2010-11-07        kinaba: 		mixin SimpleCompare;
423f308350 2010-11-07        kinaba: 	}
61998c472a 2010-11-08        kinaba: 	assert_eq( new Temp(1,"foo"), new Temp(1,"foo") );
61998c472a 2010-11-08        kinaba: 	assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash );
61998c472a 2010-11-08        kinaba: 	assert_ne( new Temp(1,"foo"), new Temp(2,"foo") );
61998c472a 2010-11-08        kinaba: 	assert_ne( new Temp(1,"foo"), new Temp(1,"bar") );
61998c472a 2010-11-08        kinaba: 	assert_gt( new Temp(1,"foo"), new Temp(1,"bar") );
61998c472a 2010-11-08        kinaba: 	assert_lt( new Temp(1,"foo"), new Temp(2,"bar") );
b0d8d7875b 2010-11-08        kinaba: 	assert_ge( new Temp(1,"foo"), new Temp(1,"foo") );
b0d8d7875b 2010-11-08        kinaba: 
b0d8d7875b 2010-11-08        kinaba: 	class TempDummy
b0d8d7875b 2010-11-08        kinaba: 	{
b0d8d7875b 2010-11-08        kinaba: 		int x;
b0d8d7875b 2010-11-08        kinaba: 		string y;
b0d8d7875b 2010-11-08        kinaba: 		mixin SimpleConstructor;
b0d8d7875b 2010-11-08        kinaba: 		mixin SimpleCompare;
b0d8d7875b 2010-11-08        kinaba: 	}
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") );
b0d8d7875b 2010-11-08        kinaba: 	assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") );
077506b38c 2010-11-08        kinaba: }
077506b38c 2010-11-08        kinaba: 
077506b38c 2010-11-08        kinaba: /// Mixing-in a simple toString method
077506b38c 2010-11-08        kinaba: 
80ff567c75 2010-11-08        kinaba: /*mixin*/
80ff567c75 2010-11-08        kinaba: template SimpleToString()
077506b38c 2010-11-08        kinaba: {
077506b38c 2010-11-08        kinaba: 	override string toString()
077506b38c 2010-11-08        kinaba: 	{
077506b38c 2010-11-08        kinaba: 		string str = sprintf!"%s("(typeof(this).stringof);
077506b38c 2010-11-08        kinaba: 		foreach(i,mem; this.tupleof)
077506b38c 2010-11-08        kinaba: 		{
077506b38c 2010-11-08        kinaba: 			if(i) str ~= ",";
077506b38c 2010-11-08        kinaba: 			static if( is(typeof(mem) == std.bigint.BigInt) )
077506b38c 2010-11-08        kinaba: 				str ~= std.bigint.toDecimalString(mem);
077506b38c 2010-11-08        kinaba: 			else
077506b38c 2010-11-08        kinaba: 				str ~= sprintf!"%s"(mem);
077506b38c 2010-11-08        kinaba: 		}
077506b38c 2010-11-08        kinaba: 		return str ~ ")";
077506b38c 2010-11-08        kinaba: 	}
077506b38c 2010-11-08        kinaba: }
077506b38c 2010-11-08        kinaba: 
077506b38c 2010-11-08        kinaba: version(unittest) import std.bigint;
077506b38c 2010-11-08        kinaba: unittest
077506b38c 2010-11-08        kinaba: {
077506b38c 2010-11-08        kinaba: 	class Temp
077506b38c 2010-11-08        kinaba: 	{
077506b38c 2010-11-08        kinaba: 		int x;
077506b38c 2010-11-08        kinaba: 		string y;
077506b38c 2010-11-08        kinaba: 		BigInt z;
077506b38c 2010-11-08        kinaba: 		mixin SimpleConstructor;
077506b38c 2010-11-08        kinaba: 		mixin SimpleToString;
077506b38c 2010-11-08        kinaba: 	}
077506b38c 2010-11-08        kinaba: 	assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" );
80ff567c75 2010-11-08        kinaba: }
80ff567c75 2010-11-08        kinaba: 
80ff567c75 2010-11-08        kinaba: /// Everything is in
80ff567c75 2010-11-08        kinaba: 
80ff567c75 2010-11-08        kinaba: /*mixin*/
80ff567c75 2010-11-08        kinaba: template SimpleClass()
80ff567c75 2010-11-08        kinaba: {
80ff567c75 2010-11-08        kinaba: 	mixin SimpleConstructor;
80ff567c75 2010-11-08        kinaba: 	mixin SimpleCompare;
80ff567c75 2010-11-08        kinaba: 	mixin SimpleToString;
423f308350 2010-11-07        kinaba: }