Jade Dungeon

准备工作

安装与配置

vim插件

http://www.vim.org/scripts/script.php?script_id=4298

http://www.quora.com/What-is-the-best-Scala-plugin-for-Vim

https://github.com/derekwyatt/vim-scala

字符编码问题

在默认字符编码为UTF-8的Linux下没问题。

Mac OS X系统的默认字符编码早就改成了UTF-8但它bundle的Java默认字符编码却一直是 MacRoman。在启动REPL时传入参数-Dfile.encoding=UTF-8

用vim、emacs或者你习惯的文本编辑器打开scala命令,比如:

$ vim `which scala`

找到如下行:

[ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M"

-D参数加到JAVA_OPTS里即可。

Vim插件

实现语法高亮:

https://github.com/scala/scala-dist上下载, 复制tool-support/src/vim.vim目录下。

neocomplcache

The built-in vim autocomplete isn't great for Scala but the neocomplcache plugin makes typing out long Scala class or package names easier. There is no semantic analysis behind it so all this plugin does is string matching but I was very surprised to realise that this takes you a long way. To me at least it is adequate.

ctags

为了用ctags实现跳转,添加配置文件~/.ctags

--langdef=scala
--langmap=scala:.scala
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private|protected)?[ \t]*class[ \t]+([a-zA-Z0-9_]+)/\4/c,classes/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private|protected)?[ \t]*object[ \t]+([a-zA-Z0-9_]+)/\4/c,objects/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private|protected)?[ \t]*case class[ \t]+([a-zA-Z0-9_]+)/\4/c,case classes/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private|protected)?[ \t]*case object[ \t]+([a-zA-Z0-9_]+)/\4/c,case objects/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*(private|protected)?[ \t]*trait[ \t]+([a-zA-Z0-9_]+)/\4/t,traits/
--regex-scala=/^[ \t]*type[ \t]+([a-zA-Z0-9_]+)/\1/T,types/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*def[ \t]+([a-zA-Z0-9_]+)/\3/m,methods/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*val[ \t]+([a-zA-Z0-9_]+)/\3/l,constants/
--regex-scala=/^[ \t]*((abstract|final|sealed|implicit|lazy)[ \t]*)*var[ \t]+([a-zA-Z0-9_]+)/\3/l,variables/
--regex-scala=/^[ \t]*package[ \t]+([a-zA-Z0-9_.]+)/\1/p,packages/

建立索引时要在当前项目根目录执行:

ctags -R . --exclude=target --exclude=vendor

By default vim will only look for the tags file in the directory of the file open in the current buffer. If you want vim do move up the directory hierarchy until it has found the file add this to your ~/.vimrc:

set tags=tags;/

Now, if you move the cursor over a type name and press Ctrl-] you will jump to the definition of the type. That's pretty nifty!

If you want to go back to where you were before the jump press Ctrl-T.

Sorting of imports

Based on feedback from a collegue who was complaining that my imports always look messy I have contributed a command to the vim-scala plugin which automatically sorts your import statements.

You can invoke the command with :SortScalaImports and there are two modes on how your imports could be sorted. By default the command goes through the import groups (which are defined as separated by a newline) and orders them alphabetically. This is useful for when you prefer to sort your import into groups yourself like this:

// Utility imports
import com.me
import com.them

// Concurrency imports
import akka....
import scala...
import java...
import spray....

// Domain imports
import com.me.data....
import com.me.data....

The second mode can be enabled by setting the following in your .vimrc:

let g:scala_sort_across_groups=1

This will take all of your imports and puts them into 3 different groups:

  1. Java/Scala core libraries
  2. 3rd party libraries
  3. First party code, a.k.a your own

What is considered first party code can be configured by setting the a regex. I have set it to this, which is for a standard Play app:

import java.text.SimpleDateFormat
import java.util.{ Currency, Locale, UUID, Calendar }
import scala.collection.JavaConversions._
import scala.util.Random

import play.api._
import play.api.mvc._

import controllers.Secured._
import de.mycompany.useful.library.Class
import util._

使用

Scala Shell

使用进入REPL环境的方式:

--(morgan-laptop:pts/8)-(13-03-15 9:04:57)-(~/workspace/study/scala)
\-(morgan:%) >>> scala
Welcome to Scala version 2.9.2 (OpenJDK 64-Bit Server VM, Java 1.7.0_15).
Type in expressions to have them evaluated.
Type :help for more information.

scala> 

Control+a到行头、Control+e到行尾,输入回车自动换行。

发现输错了,再按几个回车就退出了。

退出Scala Shellexit:quit:q

在REPL环境中只能一行一行读取,所以如果要换行的话,不能让一行在语法上看起来已经 结束:

scala> if(x > 0) { 1
     | } else if(x == 0) 0 else -1
res1: Int = 1

复制代码到REPL

在REPL中输入:paste -raw粘贴代码,按下Control + D

REPL中引入外部文件

也可以在Scala Shell中通过:load选项导入一个外部的脚本文件,如: :load script.scala

传递参数给REPL

在系统shell中还可以用参数-e传递语句与参数给Scala:

$ scala -e "println(\"\"+args(0)+\",\"+args(1))" welcome "hello world"
No such file or class on classpath: hello
welcome, hello world

脚本

脚本文件,可以接收一个参数并输出欢迎信息:

/* 可以接收一个参数 */
println("Hello, " + args(0) + "!")

调用脚本:scala命令、文件名、参数

--(morgan-laptop:pts/8)-(13-03-14 23:28:27)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> scala helloarg.scala Jade
Hello, Jade!

可以通过循环处理多个参数的:

args.foreach( arg => println(arg) )

调用:

--(morgan-laptop:pts/8)-(13-03-14 23:49:39)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> scala pa.scala Scala is even more fun      
Scala
is
even
more
fun

Scala会把脚本放到一个名为Main类中的main()方法里,可以用-savecompiled选项 来生成Jar文件查看生成的字节码。

如果有多个脚本文件,scala会默认在同一目录中所有的文件中查找需要的类;如果有需要 的文件在不同的目录里,可以在sourcepath参数中指定要查找的目录:

$ scala -sourcepath .:module1:module2 myApp.scala

如果需要的脚本里的内容已经编译过了,可以不编译这些脚本。如果生成的字节码不在当前 目录下要用classpath指定类文件的位置就可以了,-d表示字节码存放的位置:

$ scala -d . -classpath .:module1:module2 myApp.scala

OS可执行脚本

Unix下可执行脚本:

#!/bin/sh
	exec scala "$0" "$@"
!#

println("hello," + arg(0) + "!")

执行:

$ chmod +x helloarg

$ ./helloarg globe

Windows下可执行脚本:

::#!
@echo off
call scala %0 %*
goto :eof
::!#

println("hello," + arg(0) + "!")

执行:

> helloarg.bat globe

Scala程序

main方法

先看一个工具类,它根据字符串来计算出检验和:

import scala.collection.mutable.Map

class ChecksumAccumulator {
	private var sum = 0
	def add(b: Byte) { sum += b }
	def checksum(): Int =  ~(sum &0xFF) + 1
}

object ChecksumAccumulator {
	private val cache = Map[String, Int]()

	def calculate(s: String): Int =
		if( cache.contains(s) ) {
			cache(s)
		} else {
			val acc = new ChecksumAccumulator
			for (c <- s)
				acc.add(c.toByte)
			val cs = acc.checksum()
			cache += (s -> cs)
			cs
		}
}

然后是主程序。独立运行的程序一定要有main方法(仅有一个参数Array[String]而且 结果类型为Unit)的单例对象。

import ChecksumAccumulator.calculate

object Summer {

	def main(args: Array[String]) {
		for (arg <- args)
			println(arg + " -> " + calculate(arg))
	}

}

编译Scala程序:

--(morgan-laptop:pts/8)-(13-03-15 0:28:39)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> scalac ChecksumAccumulator.scala Summer.scala

有一个fast Scala compiler的后台进程可以在第一次被调用后一直跑在后台, 节省一下每次编译的速度:

--(morgan-laptop:pts/8)-(13-03-15 0:29:11)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> fsc ChecksumAccumulator.scala Summer.scala   

可以关掉这个后台进程:

--(morgan-laptop:pts/8)-(13-03-15 0:29:11)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> fsc -shutdown

编译完后可以看到生成的.class文件:

--(morgan-laptop:pts/8)-(13-03-15 0:44:31)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> ls *.class
ChecksumAccumulator$$anonfun$calculate$1.class  ChecksumAccumulator$.class    Summer.class
ChecksumAccumulator.class                       Summer$$anonfun$main$1.class  Summer$.class

运行编译出来的类文件:

--(morgan-laptop:pts/8)-(13-03-15 0:30:58)-(~/workspace/study/scala/tmp)
\-(morgan:%) >>> scala Summer of love
of -> -213
love -> -182

使用jdb调试main方法

简单的例子:

object hello {
	def main(args: Array[String]): Unit = {
		println("Hello, world!")
			var a = 10
			var b = 20
			var c = a + b
			println(c)

			var d = 1 + a;
		if(d == 11) {
			println("aaaaaaaaa")
		}
	}
}

编译:

$ scalac -g:vars hello.scala
$ ls
 hello.class  'hello$.class'   hello.scala

scala程序会包含scala的jar包,但是java程序要指定scala的jar包位置:

$ scala hello
Hello, world!
30
aaaaaaaaa

$ java -cp ./:/$SCALA_HOME/lib/scala-library.jar hello
Hello, world!
30
aaaaaaaaa

所以使用jdb时,也要指定scala的jar包位置:

jdb -classpath ./:/$SCALA_HOME/lib/scala-library.jar hello
Initializing jdb ...
> stop in hello.main
Deferring breakpoint hello.main.
It will be set after the class is loaded.
>

因为main方法在object对象中,所以断点打在hello.main方法中是没有用的:

> stop in hello.main
Deferring breakpoint hello.main.
It will be set after the class is loaded.
> run
run hello
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
> 
VM Started: Set deferred breakpoint hello.main

Breakpoint hit: "thread=main", hello.main(), line=-1 bci=0

main[1] locals
Local variable information not available.  Compile with -g to generate variable information
main[1] 

断点要打在hello$.main方法上:

> stop in hello$.main
Deferring breakpoint hello$.main.
It will be set after the class is loaded.
> run
run hello
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
> 
VM Started: Set deferred breakpoint hello$.main

Breakpoint hit: "thread=main", hello$.main(), line=3 bci=0
3            println("Hello, world!")

main[1] locals
Method arguments:
args = instance of java.lang.String[0] (id=485)
Local variables:
main[1] list
1    object hello {
2        def main(args: Array[String]): Unit = {
3 =>         println("Hello, world!")
4            var a = 10
5            var b = 20
6            var c = a + b
7            println(c)
8    
9            var d = 1 + a;
10            if(d == 11) {
main[1] 

App特质

扩展App特质,然后把程序代码放入构造器方法中:

object Hello extends App {
	print("Hello World!")
}

通过args属性得到命令行参数:

object Hello extends App {

	if (args.length > 0)
		println("Hello, " + args(0))
	else
		println("Hello, World!")

}

在调用程序时设置了参数scala.time的话,程序退出时还会显示消耗的时间:

$ scalac Hello.scala
$ scala -Dscala.time Hello Fred
Hello, Fred
[total 4ms]

原理是App特质是扩展自DelayedInit,它会把初始化方法都挪到delayedInit()方法 中。在那里有显示初始化时间的动作。

Application特质

还有一个早期版本的方法:Application特质的方式实现应用程序,但是有局限:

  • 在静态初始化方法中执行程序动作,不被编译器优化;
  • 不能访问命令行参数;
  • 只能在单线程下用。

所以不推荐用它。

形式类似于:

object MyApp extends Application {
	println("Hello")
}	

脚本与程序的区别

脚本必须以表达式结束,而程序以定义结尾。尝试以scala解释器运行程序会报错。

构建工具

Ant任务

相关的Ant任务有scalacfscscaladoc,这里只介绍scalac

scala.home=/opt/morganstudio/language/scala
compile.version=1.7
deploy.name=scala-example
<?xml version="1.0" encoding="UTF-8"?>
<project name="scala-example" default="init" basedir=".">
	<description>scala example</description>
	<property file="build.properties" />

	<property name="sources.dir" value="sources" />
	<property name="build.dir" value="build" />

	<target name="init">
		<property name="scala-library.jar" 
			value="${scala.home}/lib/scala-library.jar" />
		<path id="build.classpath">
			<pathelement location="${scala-library.jar}"   />
			<pathelement location="${build.dir}"   />
		</path>
		<taskdef resource="scala/tools/ant/antlib.xml">
			<classpath>
				<pathelement location="${scala.home}/lib/scala-compiler.jar"   />
				<pathelement location="${scala-library.jar}"   />
			</classpath>
		</taskdef>
	</target>

	<target name="build" depends="init">
		<mkdir dir="${build.dir}"   />
		<scalac srcdir="${sources.dir}"
			destdir="${build.dir}"
			classpathref="build.classpath">
			<include name="**/*.scala"   />
		</scalac>
	</target>

	<target name="run" depends="build">
		<java classname="Summer"
			classpathref="build.classpath">
		</java>
	</target>
</project>

以后可能会用到的jar包还有scala-actors.jarscala-dbc.jar.

maven构建

相关文档:http://davidb.github.io/scala-maven-plugin

https://www.assembla.com/wiki/show/scala-ide/With_M2Eclipse

  • 注意不同版本的Scala字节码有差异,所以要指明版本。
  • 加入了插件以后要指定版本,如果不清楚的话调用时加上-U选项。

archetype:generate

mvn archetype:generate \
      -DarchetypeGroupId=org.scala-tools.archetypes \
      -DarchetypeArtifactId=scala-archetype-simple  \
      -DremoteRepositories=http://scala-tools.org/repo-releases \
      -DgroupId=me.arganzheng.study.scala \
      -DartifactId=scala-helloworld \
      -Dversion=1.0-SNAPSHOT

一个简单的例子:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/maven-v4_0_0.xsd">

	<modelVersion>4.0.0</modelVersion>
	<groupId>org.scala-lang.demo</groupId>
	<artifactId>scala-test</artifactId>
	<packaging>jar</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Demo of maven for Scala Lang website</name>
	<url>http://scala-lang.org</url>

	<properties>
		<scala.version>2.10.2</scala.version>
	</properties>

	<build>
		<sourceDirectory>src/main/scala</sourceDirectory>
		<testSourceDirectory>src/test/scala</testSourceDirectory>

		<plugins>
			<plugin>
				<groupId>net.alchim31.maven</groupId>
				<artifactId>scala-maven-plugin</artifactId>
				<version>3.1.5</version>
				<executions>
					<execution>
						<goals>
							<goal>compile</goal>
							<goal>testCompile</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<scalaVersion>${scala.version}</scalaVersion>
				</configuration>
			</plugin>
		</plugins>

	</build>

</project>

对于无用的警告信息「Multiple Versions of Scala Libraries Detected」 可通过scalaCompatVersion参数去掉:

<plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>3.1.6</version>
    <configuration>
        <scalaCompatVersion>${scala.binary.version}</scalaCompatVersion>
        <scalaVersion>${scala.version}</scalaVersion>
    </configuration>
    <!-- other settings-->
</plugin>

Where in my case I have scala.binary.version property defined as

<scala.binary.version>2.10</scala.binary.version>

内存参数配置

<project>
  ...
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>3.1.5</version>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <jvmArgs>
            <jvmArg>-Xms64m</jvmArg>
            <jvmArg>-Xmx1024m</jvmArg>
          </jvmArgs>
        </configuration>
      </plugin>
  ...
</project>

编译开关

<project>
  ...
  <plugin>
    <groupId>net.alchim31.maven</groupId>
    <artifactId>scala-maven-plugin</artifactId>
    <version>3.1.5</version>
    <configuration>
      <args>
        <arg>-unchecked</arg>
        <arg>-deprecation</arg>
        <arg>-explaintypes</arg>
      </args>
    </configuration>
  </plugin>
  ...
</project>

使用本地的scala's jar

可以不用maven库里的scala版本而是本地scala.home变量指定的版本。但不要这样部署 与安装,这样会搞坏工程的。这里用到了:

  • ${scala.home}/lib/scala-library.jar
  • ${scala.home}/lib/scala-compiler.jar
mvn compile -Dscala.home=<path/of/scalaHome>

运行

运行Scala程序

直接指定类启动,不需要在pom文件中定义启动器:

mvn scala:run -DmainClass=Example -DaddArgs="arg0|arg2|arg3|arg4"

还可以指定一个启动器加上更多的参数信息:

定义Scala语言依赖;定义启动器指定运行类与id、参数,启动器可以有多个

<project xmlns="http://maven.apache.org/POM/4.0.0" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
	http://maven.apache.org/maven-v4_0_0.xsd">

	<modelVersion>4.0.0</modelVersion>
	<groupId>org.scala-lang.demo</groupId>
	<artifactId>scala-test</artifactId>
	<packaging>jar</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>Demo of maven for Scala Lang website</name>
	<url>http://scala-lang.org</url>

	<properties>
		<scala.version>2.10.2</scala.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.scala-lang</groupId>
			<artifactId>scala-library</artifactId>
			<version>2.10.2</version>
		</dependency>
	</dependencies>

	<build>
		<sourceDirectory>src/main/scala</sourceDirectory>
		<testSourceDirectory>src/test/scala</testSourceDirectory>
		<plugins>
			<plugin>
				<groupId>net.alchim31.maven</groupId>
				<artifactId>scala-maven-plugin</artifactId>
				<version>3.1.5</version>
				<configuration>
					<scalaVersion>${scala.version}</scalaVersion>
					<launchers>
						<launcher>
							<id>foo</id>
							<mainClass>Example</mainClass>
							<args>
								<arg>Hello</arg>
								<arg>World</arg>
							</args>
						</launcher>
					</launchers>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

指定启动器id启动:

mvn scala:run -Dlauncher=foo

scala console

http://scala-tools.org/mvnsites/maven-scala-plugin/usage_console.html

运行单元测试

导入ScalaTest与Junit包;定义编译测试任务;

	<dependencies>
		<dependency>
			<groupId>org.scala-lang</groupId>
			<artifactId>scala-library</artifactId>
			<version>2.10.2</version>
		</dependency>
		<dependency>
			<groupId>org.scalatest</groupId>
			<artifactId>scalatest_2.10</artifactId>
			<version>1.9.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<sourceDirectory>src/main/scala</sourceDirectory>
		<testSourceDirectory>src/test/scala</testSourceDirectory>
		<plugins>
			<plugin>
				<groupId>net.alchim31.maven</groupId>
				<artifactId>scala-maven-plugin</artifactId>
				<version>3.1.5</version>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.12</version>
			</plugin>
		</plugins>
	</build>

不过我测试中好像surefire插件一段不加上也能启用sufire任务。

在Scala程序里@RunWith注解让surefire能找到继承自FunSuite的测试类:

package com.tysonhamilton.scalatest.test

import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite
import org.junit.runner.RunWith

@RunWith(classOf[JUnitRunner])
class TestUnitTest extends FunSuite {
	test("TwoPlusTwo") {
		val twoPlusTwo = 2 + 2
		assert(twoPlusTwo == 4)
	}
}

运行的命令:

  • maven:clean
  • scala:compile
  • scala:testCompile
  • surefire:test

还可以把测试用例的编译与运行放到Maven的生命周期中去:

	<build>
		<sourceDirectory>src/main/scala</sourceDirectory>
		<testSourceDirectory>src/test/scala</testSourceDirectory>
		<plugins>
			<plugin>
				<groupId>net.alchim31.maven</groupId>
				<artifactId>scala-maven-plugin</artifactId>
				<version>3.1.5</version>
				<executions>
					<execution>
						<id>compile-scala</id>
						<phase>compile</phase>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
					<execution>
						<id>compile-tests-scala</id>
						<phase>compile</phase>
						<goals>
							<goal>testCompile</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>2.12</version>
				<executions>
					<execution>
						<id>surefire-test</id>
						<phase>test</phase>
						<goals>
							<goal>test</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

这样就并到三个周期里去了:

  • maven:clean
  • maven:compile
  • maven:test

生成API Doc

  • mvn scala:doc


构建混合Java与Scala

<build>
	<pluginManagement>
		<plugins>
			<plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>scala-maven-plugin</artifactId>
        <version>3.1.5</version>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
			</plugin>
		</plugins>
	</pluginManagement>
	<plugins>
		<plugin>
      <groupId>net.alchim31.maven</groupId>
      <artifactId>scala-maven-plugin</artifactId>
			<executions>
				<execution>
					<id>scala-compile-first</id>
					<phase>process-resources</phase>
					<goals>
					  <goal>add-source</goal>
						<goal>compile</goal>
					</goals>
				</execution>
				<execution>
					<id>scala-test-compile</id>
					<phase>process-test-resources</phase>
					<goals>
						<goal>testCompile</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<executions>
				<execution>
					<phase>compile</phase>
					<goals>
						<goal>compile</goal>
					</goals>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

sufire结合ScalaTest测试

<build>
   <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-surefire-plugin</artifactId>
       <configuration>
         <includes>
           <include>**/*Tests.java</include>
         </includes>
         <excludes>
           <exclude>**/Abstract*.java</exclude>
         </excludes>
       </configuration>
     </plugin>
   </plugins>
 </build>

运行指定的测试类:

mvn test -Dtest=[ClassName]

[ClassName]为要运行的测试类的类名(不要带扩展名),多个测试类间用逗号连接即可, 类名支持*通配符,范例:

mvn test -Dtest=MyClassTest mvn test -Dtest=MyClass1Test,MyClass2Test mvn test -Dtest=MyClass*Test,YourClassTest mvn test -Dtest=MyClassTest

运行测试类中指定的方法:(这个需要maven-surefire-plugin:2.7.3以上版本才能支持)

mvn test -Dtest=[ClassName]#[MethodName]

[MethodName]为要运行的方法名,支持*通配符,范例:

  • mvn test -Dtest=MyClassTest#test1
  • mvn test -Dtest=MyClassTest#*test*

sbt















配置国内代理库

感谢 OSChina 提供了 Maven Center 的镜像, 配置添加它有助于提升下载速度.

[repositories]
  local
  oschina:http://maven.oschina.net/content/groups/public/ 

若你知道其他更快的镜像库, 同上配置. 一般互联网企业部署了供内部使用的镜像库(如 nexus ), 也可以配置于此.

兼容 Ivy 路径布局

大多数中心仓库(repository)是 Maven 的路径布局, 这就导致 SBT 的插件和部分 Ivy 依赖无法从其下载.

[repositories]
  local
  oschina:http://maven.oschina.net/content/groups/public/ 
  oschina-ivy:http://maven.oschina.net/content/groups/public/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext] 

精简 url 列表

远程仓库越多越全, 可以基本避免下载不到的问题. 但是, 也可能让下载的时间更长, 让你不愿在等待而放弃下载.

因为, 下载过程中 SBT 会串行的 "询问" 列表中所有的远程仓库, 无论是否找得到.

当依赖树越大, 整个下载的过程就更漫长. 若再遇到响应慢的仓库, 情况恶化的令人发指.

推荐列表策略是:

  1. 本地仓库
  2. 国内(或内网)镜像仓库
  3. 国外官方仓库, 通常#注释掉, 待上面不管用时, 去掉#再做尝试

上面办法不管用

建议使用你熟悉的网络嗅探手段查清具体原因, 对症下药了.

一个可行的方案

  1. 下载 HTTP 代理工具 mitmproxy, 并运行它
  2. 启动 SBT时, 附加参数-Dhttp.proxyHost=loalhost -Dhttp.proxyPort=8080, 这会将 SBT 所有的 HTTP 请求经由 mitmproxy转发
  3. 通过 mitmproxy 来分析 HTTP 请求失败的具体原因

eclipse

maven里增加scala模板:

「preferences」>「Maven」>「Archetypes」>「Add Remote Catalog」

http://repo1.maven.org/maven2/archetype-catalog.xml

新建Archetype:

Group Id: net.alchim31.maven
Artifact Id: scala-archetype-simple
Version:1.5

以后新建Maven项目,选这个Archtype就可以了。

Install the m2eclipse-scala plugin

There is a configurer for m2eclipse that will setup Scala projects for you. You can install it using the directions here:

http://github.com/sonatype/m2eclipse-scala