From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=AWL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by yquem.inria.fr (Postfix) with ESMTP id 2D23EBBC1 for ; Thu, 13 Mar 2008 17:42:23 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ah0DAMH22EfAXQImh2dsb2JhbACQcgEBAQgKKZc5 X-IronPort-AV: E=Sophos;i="4.25,495,1199660400"; d="scan'208";a="10232677" Received: from discorde.inria.fr ([192.93.2.38]) by mail3-smtp-sop.national.inria.fr with ESMTP; 13 Mar 2008 17:41:59 +0100 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id m2DGfxNf029000 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Thu, 13 Mar 2008 17:41:59 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ah0DAHP22EfBAkMth2dsb2JhbACQcgEBAQgKKZc6 X-IronPort-AV: E=Sophos;i="4.25,495,1199660400"; d="scan'208";a="23732927" Received: from vega.fmf.uni-lj.si (HELO postar.fmf.uni-lj.si) ([193.2.67.45]) by mail4-smtp-sop.national.inria.fr with ESMTP; 13 Mar 2008 17:41:58 +0100 Received: from localhost (unknown [192.168.5.1]) by postar.fmf.uni-lj.si (Postfix) with ESMTP id CF27411BCA7; Thu, 13 Mar 2008 17:41:57 +0100 (CET) X-Virus-Scanned: amavisd-new at spam.fmf.uni-lj.si Received: from postar.fmf.uni-lj.si ([192.168.5.5]) by localhost (spam.fmf.uni-lj.si [192.168.5.1]) (amavisd-new, port 10024) with ESMTP id dxb3-yrYQ7l3; Thu, 13 Mar 2008 17:41:56 +0100 (CET) Received: from [193.2.67.88] (unknown [193.2.67.88]) by postar.fmf.uni-lj.si (Postfix) with ESMTP id 3BB011109B7; Thu, 13 Mar 2008 17:41:48 +0100 (CET) Message-ID: <47D9594C.7080505@fmf.uni-lj.si> Date: Thu, 13 Mar 2008 17:41:48 +0100 From: Andrej Bauer Reply-To: Andrej.Bauer@andrej.com User-Agent: Thunderbird 2.0.0.12 (X11/20080227) MIME-Version: 1.0 To: Ludovic Coquelle , Caml Subject: Re: [Caml-list] invoke function from its name as string References: <47D8CE92.2020009@fmf.uni-lj.si> In-Reply-To: Content-Type: text/plain; charset=ISO-8859-2; format=flowed Content-Transfer-Encoding: 7bit X-Miltered: at discorde with ID 47D95957.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; andrej:01 andrej:01 'make:01 ocaml:01 bool:01 iter:01 failwith:01 ocaml:01 blog:98 blog:98 invoke:01 wrote:01 regex:01 naming:01 caml-list:01 Ludovic Coquelle wrote: > Thanks for this answer. > Problem I'm trying to solve is the following: > > I use 'make_suite' which is a program that do regex matching on source > code to extract a list of function that looks like OUnit tests; from > this list, it write an ocaml source code file which is a test case > that call all the previous functions found. > (see: http://skydeck.com/blog/programming/unit-test-in-ocaml-with-ounit/) I looked at the blog post. The idea is to interleave the source code with special test functions and extract those automatically. You have chosen to do this by searching the source code with regular expressions, looking for functions with a certain name. If I may be honest and will all due respect: this is a really horrible idea. It is fragile, sensitive to mistakes, you have no guarantee that all the test functions were actually found (say what if someone mispells the name of one of them slightly), and so on. It is just really bad. How about the following solution, in which I naively assume that test functions are supposed to return bool, but this is easily fixed. Define a module "Test" somewhat like this: ---test.ml---- (** The list of tests registered by the source code. *) let tests = ref [] (** Register a function as a test. *) let register name test = tests := (name, test) :: !tests (** Run all tests, maybe we can combine this with OUnit? *) let run_tests () = List.iter (fun (name,test) -> if not (test ()) then failwith ("FAILED: " ^ name)) !tests ------------- In your source code, whenever you want to have a test you just write: Test.register "some_name" (fun () -> (*test code here*) *) This is essentially the same overhead as what you have in your current solution, except that it is robust, ocaml will check that it is ok, and you do not have to come up with names of test functions of the form test_... all the time. The names of tests are strings, they can be more descriptive. To run your program, you do not do anything special. There will be a small initialization cost when the test functions are collected in the list. Tu run the tests, you link your source code with something like ---runtest.ml--- Test.run_tests () --------------- You can easily extend this idea to using OUnit inside test.ml or do whatever you like. The important thing is that you do not search the source code in a naive and fragile way that requires to programmer to follow arbitrary naming conventions. Best regards, Andrej