8de5b49cdf 2010-11-09 kinaba: /** 8de5b49cdf 2010-11-09 kinaba: * Authors: k.inaba 8de5b49cdf 2010-11-09 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 8de5b49cdf 2010-11-09 kinaba: * 8de5b49cdf 2010-11-09 kinaba: * Common tricks and utilities for programming in D. 8de5b49cdf 2010-11-09 kinaba: */ 8de5b49cdf 2010-11-09 kinaba: module tricks.tricks; 8de5b49cdf 2010-11-09 kinaba: import tricks.test; 8de5b49cdf 2010-11-09 kinaba: import std.array : appender; 8de5b49cdf 2010-11-09 kinaba: import std.format : formattedWrite; 8de5b49cdf 2010-11-09 kinaba: import core.exception : AssertError; 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Simple Wrapper for std.format.doFormat 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: string sprintf(string fmt, T...)(T params) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: auto writer = appender!string(); 8de5b49cdf 2010-11-09 kinaba: formattedWrite(writer, fmt, params); 8de5b49cdf 2010-11-09 kinaba: return writer.data; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: assert( sprintf!"%s == %d"("1+2", 3) == "1+2 == 3" ); 8de5b49cdf 2010-11-09 kinaba: assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Create an exception with automatically completed filename and lineno information 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: auto genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: static if( T.length > 0 && is(T[$-1] : Throwable) ) 8de5b49cdf 2010-11-09 kinaba: return new ExceptionType(params[0..$-1], fn, ln, params[$-1]); 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: return new ExceptionType(params, fn, ln); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg").file, "" ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg").line, 0 ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( genex!Exception("msg",new Exception("bar")).next, Exception.init ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Mixing-in the bean constructor for a class 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleConstructor() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: static if( is(typeof(super) == Object) || super.tupleof.length==0 ) 8de5b49cdf 2010-11-09 kinaba: this( typeof(this.tupleof) params ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: static if(this.tupleof.length>0) 8de5b49cdf 2010-11-09 kinaba: this.tupleof = params; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: this( typeof(super.tupleof) ps, typeof(this.tupleof) params ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: // including (only) the direct super class members 8de5b49cdf 2010-11-09 kinaba: // may not always be a desirable choice, but should work for many cases 8de5b49cdf 2010-11-09 kinaba: super(ps); 8de5b49cdf 2010-11-09 kinaba: static if(this.tupleof.length>0) 8de5b49cdf 2010-11-09 kinaba: this.tupleof = params; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).x, 1 ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).y, "foo" ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp) ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp(1)) ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Temp("foo",1)) ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: class Tomp : Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: real z; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).x, 1 ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 ); 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, new Tomp(3.14)) ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: // shiyo- desu. Don't use in this way. 8de5b49cdf 2010-11-09 kinaba: // Tamp tries to call new Tomp(real) (because it only sees Tomp's members), 8de5b49cdf 2010-11-09 kinaba: // but it fails because Tomp takes (int,string,real). 8de5b49cdf 2010-11-09 kinaba: assert( !__traits(compiles, { 8de5b49cdf 2010-11-09 kinaba: class Tamp : Tomp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: }) ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Mixing-in the MOST-DERIVED-member-wise comparator for a class 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleCompare() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: override bool opEquals(Object rhs_) const 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: foreach(i,_; this.tupleof) 8de5b49cdf 2010-11-09 kinaba: if( this.tupleof[i] != rhs.tupleof[i] ) 8de5b49cdf 2010-11-09 kinaba: return false; 8de5b49cdf 2010-11-09 kinaba: return true; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: override hash_t toHash() const 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: hash_t h = 0; 8de5b49cdf 2010-11-09 kinaba: foreach(mem; this.tupleof) 8de5b49cdf 2010-11-09 kinaba: h += typeid(mem).getHash(&mem); 8de5b49cdf 2010-11-09 kinaba: return h; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: override int opCmp(Object rhs_) const 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if( auto rhs = cast(typeof(this))rhs_ ) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: foreach(i,_; this.tupleof) 8de5b49cdf 2010-11-09 kinaba: if(auto c = typeid(_).compare(&this.tupleof[i],&rhs.tupleof[i])) 8de5b49cdf 2010-11-09 kinaba: return c; 8de5b49cdf 2010-11-09 kinaba: return 0; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_))); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( new Temp(1,"foo"), new Temp(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( new Temp(1,"foo"), new Temp(2,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_ne( new Temp(1,"foo"), new Temp(1,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_gt( new Temp(1,"foo"), new Temp(1,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_lt( new Temp(1,"foo"), new Temp(2,"bar") ); 8de5b49cdf 2010-11-09 kinaba: assert_ge( new Temp(1,"foo"), new Temp(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: class TempDummy 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Mixing-in a simple toString method 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleToString() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: override string toString() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: string str = sprintf!"%s("(typeof(this).stringof); 8de5b49cdf 2010-11-09 kinaba: foreach(i,mem; this.tupleof) 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if(i) str ~= ","; 8de5b49cdf 2010-11-09 kinaba: static if( is(typeof(mem) == std.bigint.BigInt) ) 8de5b49cdf 2010-11-09 kinaba: str ~= std.bigint.toDecimalString(mem); 8de5b49cdf 2010-11-09 kinaba: else 8de5b49cdf 2010-11-09 kinaba: str ~= sprintf!"%s"(mem); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: return str ~ ")"; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: version(unittest) import std.bigint; 8de5b49cdf 2010-11-09 kinaba: unittest 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: class Temp 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: int x; 8de5b49cdf 2010-11-09 kinaba: string y; 8de5b49cdf 2010-11-09 kinaba: BigInt z; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleToString; 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: assert_eq( (new Temp(1,"foo",BigInt(42))).toString(), "Temp(1,foo,42)" ); 8de5b49cdf 2010-11-09 kinaba: } 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /// Everything is in 8de5b49cdf 2010-11-09 kinaba: 8de5b49cdf 2010-11-09 kinaba: /*mixin*/ 8de5b49cdf 2010-11-09 kinaba: template SimpleClass() 8de5b49cdf 2010-11-09 kinaba: { 8de5b49cdf 2010-11-09 kinaba: mixin SimpleConstructor; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleCompare; 8de5b49cdf 2010-11-09 kinaba: mixin SimpleToString; 8de5b49cdf 2010-11-09 kinaba: }