As pointed out in my last post Yeti http://mth.github.com/yeti/ is functional statically typed programming language for JVM with full typeinference. The language is simple but still gives a lot of power https://github.com/mth/yeti/wiki. In its feeling it comes very close to the agility of dynamic-languages, but of course remaining statically typechecked.
One way to run Yeti-Code is to use the yeti.jar directly. This is very well described in the yeti tutorial http://linux.ee/~mzz/yeti/intro.html.
In this post I want to show you how to use the yeti-maven-plugin https://github.com/chrisichris/yeti-maven-plugin
Advantages of using the yeti-maven-plugin
When you hear maven-plugin do not shy away it is not more work than using the yeti.jar directly, contrary it gives you a few advantages:
- It is easier to manage the classpath especially using jars both for running with the REPL and compiling
- It is a standard way to compile and test, distribute etc your yeti-code and integrates well if you want to also code parts in Java (or other JVM- languages)
- yetidoc can be produced
- a mavenproject is understood by all ides. A pure YETI-project as above not
Starting a Yeti Maven project and basic Usage
To start a maven-yeti-project you have to
- Install maven 2 or greater (If you are a Java-Programmer you very propably have that already) http://maven.apache.org/run-maven/index.html
- Download the yeti-project-template.zip file from the downloads section of the yeti-maven-plugin https://github.com/chrisichris/yeti-maven-plugin
- Unpack the file in a directory of your choice and name it as you project.
- Change in the pom.xml file the contents of the groupId, artifactId and name tags to your projects name
<groupId>your.groupId</groupId> <artifactId>your-artifactId</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>your projects name</name>
Now your maven project is setup and read to use.
You can put your yeti module files in the src/main/yeti directory or side-by-beside with your java files in src/main/java – for test files the corresponding src/test directories are used.
You can use all the mvn commands ie
mvn install In all these commands the yeti sources get compiled, tested, jared up etc exactly like the Java sources.
And you can start the interactive REPL:
mvn -Dyeti-compile=false clean compile yeti:repl
This will first clean than compile the Java sources and start the REPL with the full project classpath (including test-classes dependencies etc). The yeti sources are not compiled in this case (
-Dyeti-compile=false), because the REPL will pick up the sources itself directly and compile them.
Interactive Development with the REPL
Yeti is new so Yeti does not yet have the IDE support Java has.
Among other things that means that when you code Yeti the IDE does not show you instantly compile errors you might have made. Instead you always have to edit your file, save it go to the command prompt, call compile (or reload the module in the repl), see a compile-error, fix it and start all over again. That’s boring lost time.
The yeti-maven-plugins REPL helps here.
In the repl you can define arbitrary yeti-code which gets executed each time you change sources.
You can use this facility to execute
load module.name commands each time you save your changed code. This way the REPL will (re)compile the module immidiately in the console, and you do not have to repeat the above circle.
Try it out: create a yeti module: src/yeti/example/immediateCompile.yeti (if you have started the project from the yeti-project-template.zip file – as described above – this file is already present)
module example.immediateCompile; "just an example showing the immediate compile function of the repl";
From the shell start the REPL and in the REPL add a monitor which will load the immediateCompile module whenever the a source-file is changed.
mvn -Dyeti-compile=false clean compile yeti:repl .... Ready to take your commands 🙂 yeti>-s.addMonitor "recompile monitor" \(s.branche "load example.immediateCompile"); <p>shell:added monitor 1: recompile monitor: <code$> yeti> ...
And now just modify in you editor the code of your module. Save it and see the compiliation output.
Ie introduce a bug:
module example.immediateCompile; this is a bug "just an example showing the immediate compile function of the repl";
Save the file and you should (quite) immidiately see the compiler result on the repl.
yeti> yeti>monitor: yeti>----------------------- branche start: load example.immediateCompile yeti>load example.immediateCompile example/immediateCompile.yeti:3:1: Unknown identifier: this branche end: load example.immediateCompile ------------------------ yeti>
In the repl you see that the code
load example.immediateResult is executed and that the compiler showed the error:
example/immediateCompile.yeti:3:1: Unknown identifier: this.
Correct the bug in your source file.
module example.immediateCompile; "this is no bug anymore"
Save it and you get automatically on the repl
------------------------ yeti>monitor: yeti>----------------------- branche start: load example.immediateCompile yeti>load example.immediateCompile "this is no bug anymore" is string branche end: load example.immediateCompile ------------------------
The module was compiled, executed and returned
"this is no bug anymore" is string. So everything works fine.
Using the REPL to run Continously rudimentary Tests
As we saw the monitor we added to load the module did not only compile the module it actually compiles and runs it too.
This can be of course used to also test modules as soon as you change them.
To do so instead of loading the main-source module you define a test module under
src/test/yeti which in turn loads the main module and checks its result.
Lets do that:
Create a file src/test/yeti/example/testImmediateCompile.yeti:
module example.testImmediateCompile; t = load example.immediateCompile; if t != "this is no bug anymore" then failWith "wrong result \(t)" fi; "test immediateResult was ok"
This module first loads the example.immediateCompile module than checks the returned string. If it does not fit it fails with an exception. Otherwise it finishes normally confirming that the module under test is ok.
Before we add a monitor for the new test module, we turn off the old monitor, using
-s.showMonitors() to find its id and than calling
-s.removeMonitor id to remove it.
Than we add the new monitor:
yeti>-s.showMonitors() shell:monitors: 1: true: recompile: <code$> yeti>-s.removeMonitor 1 shell:removed monitor 1 yeti> yeti>-s.addMonitor "testImmediateCompile" \(s.branche "load example.testImmediateCompile");
And now the module is not only recompiled each time you change and save it but also tested – very similar as in dynamic languages and even better than what the very advanced Java-IDEs provide.
This is of course no nice test-framework. A way to test yeti properly will be handled in a next blog-post.
But for having fun with Yeti it is a good start.
And if you are not board don’t forget to read the readme for the yeti-maven-plugin it has a few additional infos https://github.com/chrisichris/yeti-maven-plugin