I am trying to get the following code snippet from GitHub to work so that I can use OpenNLP tools in Groovy scripts.
(OpenNLP class from https://gist.github.com/nagaimasato/1178725)
#!/usr/bin/env groovy
#Grapes(
#Grab(
group='org.apache.opennlp',
module='opennlp-tools',
version='1.5.3'
)
)
import opennlp.tools.tokenize.*
import opennlp.tools.postag.*
OpenNLP nlp = new OpenNLP()
def tokens = nlp.workTokenize("Hello world")
println tokens
class OpenNLP {
static TokenizerModel tokenizerModel
static POSModel posModel
static {
def classLoader = OpenNLP.class.classLoader
classLoader.getResource('opennlp/en-token.bin').withInputStream {
tokenizerModel = new TokenizerModel(it)
}
classLoader.getResource('opennlp/en-pos-maxent.bin').withInputStream {
posModel = new POSModel(it)
}
}
Tokenizer tokenizer
POSTagger tagger
OpenNLP() {
tokenizer = new TokenizerME(tokenizerModel)
tagger = new POSTaggerME(posModel)
}
List workTokenize(String text) {
return tokenizer.tokenize(text)
}
List posTag(List tokens) {
return [tokens, tagger.tag(tokens)].transpose()
}
}
I get the following error when I try to run the script:
Caught: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
at Greetings.class$(Greetings.groovy)
at Greetings.$get$$class$OpenNLP(Greetings.groovy)
at Greetings.run(Greetings.groovy:13)
Caused by: java.lang.NullPointerException: Cannot invoke method withInputStream() on null object
at OpenNLP.<clinit>(Greetings.groovy:25)
... 3 more
I have en-token.bin and en-pos-maxent.bin in the right place for the script to find, but classLoader.getResource("opennlp/en-token.bin") is indeed null when I print it. Any ideas?
Make sure the en-token.bin and en-pos-maxent.bin files are in a directory named opennlp and that the classpath includes the parent directory of opennlp.
Note that ./ is included in the classpath when you execute your Groovy script, so if you have your opennlp directory in the same directory as your Groovy script and you also invoke the Groovy script while you are in that directory, it should work (at least it worked for me). But if you execute the script while you are not currently in that directory (e.g. by using a path like path/to/script.groovy) it won't work. In that case, you can just invoke it using groovy -cp path/to path/to/script.groovy, thus putting the parent directory of your opennlp directory into the classpath manually.
Related
After reading many threads I am stuck on this very simple task.
I have a sandbox project with only two files :
src/main/groovy/classes/foo
package classes.foo
class Foo{
#Override
String toString() {
return "Foo"
}
}
and src/main/groovy/scripts/script.groovy
package scripts
import classes.Foo
def foo = new Foo()
print foo.toString()
Now if I run the command :
groovy src/main/groovy/scripts/script.groovy
I get the following error :
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
src\main\groovy\scripts\utils\script.groovy: 3: unable to resolve class classes.Foo
# line 3, column 1.
import classes.Foo
^
1 error
How can I use my class Foo in my script script.groovy ?
As suggested by dagget, I had to specify the classpath based on my root folder which in my case is groovy :
groovy -cp src/main/groovy src/main/groovy/scripts/script.groovy
The following two classes in the same package:
Imported.groovy
class Imported {
static class Inner {
}
}
Main.groovy
import Imported
class Main {
static main(args) {
new Imported.Inner()
}
}
When run:
$ groovy Main.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/tmp/Main.groovy: 5: unable to resolve class Imported.Inner
# line 5, column 5.
new Imported.Inner()
^
1 error
Any reason this is happening? How to properly import static nested classes?
Just compile Imported.groovy: groovyc Imported.groovy so that you have Imported.class and Imported$Inner.class.
Then simply invoke groovy Main.groovy and it should work.
If you want to have some "import/include" functionality, check Including a groovy script in another groovy and how to simply import a groovy file in another groovy script.
I have a groovy script that need to run a method inside a class inside an external groovy script.
I know how to run a method within an external groovy script:
new GroovyShell().parse( new File( 'foo.groovy' ) ).with {
method()
}
But what if the method is inside a class? I tried this but it gave me an error.
new GroovyShell().parse( new File( 'foo.groovy' ) ).with {
theclass.method()
}
You can use Java reflection to create new instance of a Class that is located in another script:
File sourceFile = new File("D:\\anoutherScript.groovy")
//here you have to update your classloader with external script
getClass().getClassLoader().addURL(sourceFile.toURI().toURL())
GroovyObject obj = Class.forName("ClassInAnotherObject").newInstance()
obj.doSth()
Script in your external file would be like that:
class ClassInAnotherObject{
def doSth(){
}
}
but there could be more classes in script file, also some more instructions and method call. Just like normal groovy script.
I want to use the Sauce Labs Java REST API to send Pass/Fail status back to the Sauce Labs dashboard. I am using Geb+Spock, and my Gradle build creates a test results directory where results are output in XML. My problem is that the results XML file doesn't seem to be generated until after the Spock specification's cleanupSpec() exits. This causes my code to report the results of the previous test run, rather than the current one. Clearly not what I want!
Is there some way to get to the results from within cleanupSpec() without relying on the XML? Or a way to get the results to file earlier? Or some alternative that will be much better than either of those?
Some code:
In build.gradle, I specify the testResultsDir. This is where the XML file is written after the Spock specifications exit:
drivers.each { driver ->
task "${driver}Test"(type: Test) {
cleanTest
systemProperty "geb.env", driver
testResultsDir = file("$buildDir/test-results/${driver}")
systemProperty "proj.test.resultsDir", testResultsDir
}
}
Here is the setupSpec() and cleanupSpec() in my LoginSpec class:
class LoginSpec extends GebSpec {
#Shared def SauceREST client = new SauceREST("redactedName", "redactedKey")
#Shared def sauceJobID
#Shared def allSpecsPass = true
def setupSpec() {
sauceJobID = driver.getSessionId().toString()
}
def cleanupSpec() {
def String specResultsDir = System.getProperty("proj.test.resultsDir") ?: "./build/test-results"
def String specResultsFile = this.getClass().getName()
def String specResultsXML = "${specResultsDir}/TEST-${specResultsFile}.xml"
def testsuiteResults = new XmlSlurper().parse( new File( specResultsXML ))
// read error and failure counts from the XML
def errors = testsuiteResults.#errors.text()?.toInteger()
def failures = testsuiteResults.#failures.text()?.toInteger()
if ( (errors + failures) > 0 ) { allSpecsPass = false }
if ( allSpecsPass ) {
client.jobPassed(sauceJobID)
} else {
client.jobFailed(sauceJobID)
}
}
}
The rest of this class contains login specifications that do not interact with SauceLabs. When I read the XML, it turns out that it was written at the end of the previous LoginSpec run. I need a way to get to the values of the current run.
Thanks!
Test reports are generated after a Specification has finished execution and the generation is performed by the build system, so in your case by Gradle. Spock has no knowledge of that so you are unable to get that information from within the test.
You can on the other hand quite easily get that information from Gradle. Test task has two methods that might be of interest to you here: addTestListener() and afterSuite(). It seems that the cleaner solution here would be to use the first method, implement a test listener and put your logic in afterSuite() of the listener (and not the task configuration). You would probably need to put that listener implementation in buildSrc as it looks like you have a dependency on SauceREST and you would need to build and compile your listener class before being able to use it as an argument to addTestListener() in build.gradle of your project.
Following on from erdi's suggestion, I've created a Sauce Gradle helper library, which provides a Test Listener that parses the test XML output and invokes the Sauce REST API to set the pass/fail status.
The library can be included by adding the following to your build.gradle file:
import com.saucelabs.gradle.SauceListener
buildscript {
repositories {
mavenCentral()
maven {
url "https://repository-saucelabs.forge.cloudbees.com/release"
}
}
dependencies {
classpath group: 'com.saucelabs', name: 'saucerest', version: '1.0.2'
classpath group: 'com.saucelabs', name: 'sauce_java_common', version: '1.0.14'
classpath group: 'com.saucelabs.gradle', name: 'sauce-gradle-plugin', version: '0.0.1'
}
}
gradle.addListener(new SauceListener("YOUR_SAUCE_USERNAME", "YOUR_SAUCE_ACCESS_KEY"))
You will also need to output the Selenium session id for each test, so that the SauceListener can associate the Sauce Job with the pass/fail status. To do this, include the following output in the stdout:
SauceOnDemandSessionID=SELENIUM_SESSION_ID
Is there a standard or recommended getopts library for Groovy that will allow me to quickly process long and short command line arguements in Groovy?
groovy foo.groovy --fname=foo.txt --output=foo.html --verbose
You could also simply use Groovy CliBuilder (which internally uses Apache Commons Cli).
You will find a good example of how it works here=> http://www.reverttoconsole.com/blog/codesnippets/groovy-clibuilder-in-practice/
def cli = new CliBuilder()
cli.with {
usage: 'Self'
h longOpt:'help', 'usage information'
i longOpt:'input', 'input file', args:1
o longOpt:'output', 'output file',args:1
a longOpt:'action', 'action to invoke',args:1
d longOpt:'directory','process all files of directory', args:1
}
def opt = cli.parse(args)
def action
if( args.length == 0) {
cli.usage()
return
}
if( opt.h ) {
cli.usage()
return
}
if( opt.i ) {
input = opt.i
}
...
One of the major strengths of Groovy is interoperability with Java. Therefore, when looking for libraries to use in Groovy, my first instinct is to look for existing Java libraries.
Args4j is a concise and elegant library for parsing command line options and it works perfectly with Groovy classes. I've rewritten parts of the tutorial to work with Groovy.
Consider the following Groovy class:
import org.kohsuke.args4j.Option;
class Business {
#Option(name="-name",usage="Sets a name")
String name
public void run() {
println("Business-Logic")
println("-name: " + name)
}
}
Compile it with:
groovyc -classpath .:args4j-2.0.12/args4j-2.0.12.jar Business.groovy
and run it with
java -cp .:args4j-2.0.12/args4j-2.0.12.jar:/usr/share/java/groovy/embeddable/groovy-all-1.6.4.jar -Dmainclass=Business org.kohsuke.args4j.Starter -name sample
To get the output
Business-Logic
-name: sample
Once upon a time I wrote the Groovy Option Parser to accomplish this task. It's pretty straight forward and has some niceties.
Apache Commons CLI is another Java library that you could use in Groovy