Shown below is a sample code.
Assume that "hi" and "hello" are complex objects and have to be evaluated inside the method.
The code below gives me:
Process finished with exit code -1
Expected result is an "Unrolled" explanation of what passed and failed.
Code:
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
#Unroll
class DataTableTest extends Specification {
def "#actual should equal #expected"() {
#Shared def hi = "hi"
#Shared def hello = "hello"
expect:
actual == expected
where:
actual | expected
hi | hi
hi | hello
}
}
I dont think you can even define Shared vars inside a method as their purpose is to be reusable in other methods as they are high-cost calculated variables. Try to set up the shared variables in the class scope.
Related
let's say I have a Configuration class in a Jenkins shared library written like this
class Configuration {
String param1, param2
Closure closure1
}
There's also a helper class like this
class Helper {
String helperMethod(String arg1, Closure closure1) {
// some invocation to closure 1
}
}
Within the var folder there's a dynamic pipeline in a pipeline.groovy file like this:
def call(Configuration config) {
node {
stage {
def helper = new Helper()
helper.helperMethod('foo') { config.closure1 it }
}
}
}
Finally I'm trying to use the shared library in another repo like this,
#Library('my-library')
import com.mylibrary.configuration.Configuration
def baz = { it.toUpperCase() }
def config = new Configuration(
param1: 'foo',
param2: 'bar',
closure1: baz
)
pipeline(config)
The problem is that baz get transformed to org.jenkinsci.plugins.workflow.cps.CpsClosure2 and helperMethod throws a MissingMethodException because of the type mismatch between CpsClosure2 and the expected groovy.lang.Closure
I've tried:
Using the #NonCPS annotation in baz
Strong typing the closure through a functional interface and trying to pass it to the config like closure1: baz as MyStronglyTypedClosure
Removing the closure typing in the helperMethod definition
Using helper.helperMethod('foo', config.closure1) instead of helper.helperMethod('foo') { config.closure1 it }
to no avail :(
Is there any workaround to receive the closure in the configuration so it can be used correctly in the helper class? Thanks in advance
MissingMethodException is usually thrown when you are invoking functions incorrectly or inexistent function, it rarely has to do with CPS closures, which indeed as dagget mentioned, extends standard java closures. I strongly recommend you to use testing frameworks like Spock (with Jenkins extension) to be able to detect errors beforehand.
I am trying to make it so that all of my page and module references can autocomplete in intellij.
Due to some sort of bug I am unable to do this like one normally would. (see here for more details: How to have geb static content recognized form test script )
In order to work around the above mentioned bug. I opted to create "getters" for all of my static content.
for example:
The Page:
class MyPage extends Page{
static content = {
tab {$(By.xpath("somexpath")}
}
Navigator tab(){
return tab
}
}
The Script:
//imagine we are in the middle of a feature method here
def test = at MyPage
test.tab().click()
So all of the above code works as I expect it to, and I want to redo my pages like this so that I can have autocomplete from the script side. Problems occur when I try to use this same technique for modules.
For example:
class MyPage extends Page{
static content = {
mod {module(new MyModule())}
}
MyModule mod(){
return mod
}
}
If I try and access mod from the script like so
//imagine we are in the middle of a feature method here
def test = at MyPage
test.mod().someModContentMaybe().click()
I get the following error:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'MyPage' -> mod: 'MyModule' with class 'geb.content.TemplateDerivedPageContent' to class 'MyModule'
If I try to do the following in the page object:
class MyPage extends Page{
static content = {
mod {module(new MyModule())}
}
MyModule mod(){
return new MyModule()
}
}
I get the following error when attempting to access the module from the script:
geb.error.ModuleInstanceNotInitializedException: Instance of module class MyModule has not been initialized. Please pass it to Navigable.module() or Navigator.module() before using it.
I guess it wants me to take an instantiated Navigator Object and and to call module(MyModule) but I am not sure how this works or how one would decide which Navigator Object to call module from.
All in all, I just want to be able to autocomplete module Names and static content from my scripts.
The Book of Geb's section about modules answers your question. You should not manually call the module's constructor, but instead instead use the syntax described right at the beginning of the chapter. This solution gets rid of the exception and also solves the code completion problem for me:
static content = {
mod { module MyModule }
}
Now that the exception is gone here is how to add the getter you asked for:
def myModule() { mod }
You're getting a GroovyCastException when returning content that contains a module from a method whose return type is a class which extends geb.Module because navigators and modules returned from content definitions get wrapped in geb.content.TemplateDerivedPageContent.
You can unwrap them using the as keyword as explained in the manual section about unwrapping modules returned from the content DSL. So, for one of your examples it would look like this:
MyModule mod(){
mod as MyModule
}
I think the problem is you content block. Modules are defined via Navigators' module method:
static content = {
mod { $("div.module").module(MyModule)
}
So no constructor calling required.
I am trying to use a NumericProperty but getting Type errors when trying to use it as a value
My code looks like this
from kivy.properties import NumericProperty
from kivy.uix.widget import Widget
class Segment(Widget):
def __init__(self, segments):
super(Segment, self).__init__()
self.segments = NumericPropery(segments)
def build(self):
for i in range(0, self.segments):
# Do something
I get an error :
for i in range(0, self.segments):
TypeError: range() integer end argument expected, got kivy.properties.NumericProperty.
so I tried using self.segments.get() instead, but then I got this error
TypeError: get() takes exactly one argument (0 given)
apperently the get function expects <kivy._event.EventDispatcher> object argument
Any idea how to get around this?
I had a similar problem with this code ...
class GameModel(object):
some_number = NumericProperty(1)
def __init__(self):
self.some_number = 2
... which raised the error:
TypeError: Argument 'obj' has incorrect type (expected kivy._event.EventDispatcher, got GameModel)
I did declare the property at class level though. In my case the problem was that the class itself was not derived from a Kivy Widget class or - as stated in the error message - from an EventDispatcher Object
Deriving from EventDispatcher fixed my problem:
class GameModel(EventDispatcher):
Hope this is helpful for someone else some day ;-)
You have to declare properties at class level.
class Segment(Widget):
segments = NumericProperty()
This will give the correct behaviour. The problem is that properties do their own management of per-instance values and interacting with the eventloop etc.. If you don't declare them at class level, they don't get to do this, so your functions only see the NumericProperty itself (which is your problem).
How can I get a value from message properties outside of GSPs? For instance, the equivalent of
<g:message code="some.message"/>
but in a controller?
Inside a controller or a taglib, you can use the following :
g.message(code: 'some.message')
However, inside domain classes or services, you need to inject messageSource and call getMessage() method from Sping class AbstractMessageSource.
This snippet shows you how to do that:
import org.springframework.context.i18n.LocaleContextHolder as LCH
...
class MyServiceOrMyDomain {
def messageSource
...
messageSource.getMessage(code, msgArgs, defaultMsg, LCH.getLocale())
...
}
You can also import the validation tag lib and use it grab the message source.
import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
def g = new ValidationTagLib()
g.message(error: error)
I've tried to use the new Groovy Grape capability in Groovy 1.6-beta-2 but I get an error message;
unable to resolve class com.jidesoft.swing.JideSplitButton
from the Groovy Console (/opt/groovy/groovy-1.6-beta-2/bin/groovyConsole) when running the stock example;
import com.jidesoft.swing.JideSplitButton
#Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,)')
public class TestClassAnnotation {
public static String testMethod () {
return JideSplitButton.class.name
}
}
I even tried running the grape command line tool to ensure the library is imported. Like this;
$ /opt/groovy/groovy-1.6-beta-2/bin/grape install com.jidesoft jide-oss
which does install the library just fine. How do I get the code to run/compile correctly from the groovyConsole?
There is still some kinks in working out the startup/kill switch routine. For Beta-2 do this in it's own script first:
groovy.grape.Grape.initGrape()
Another issue you will run into deals with the joys of using an unbounded upper range. Jide-oss from 2.3.0 onward has been compiling their code to Java 6 bytecodes, so you will need to either run the console in Java 6 (which is what you would want to do for Swing anyway) or set an upper limit on the ranges, like so
import com.jidesoft.swing.JideSplitButton
#Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,2.3.0)')
public class TestClassAnnotation {
public static String testMethod () {
return JideSplitButton.class.name
}
}
new TestClassAnnotation().testMethod()
I finally got it working for Groovy Shell (1.6.5, JVM: 1.6.0_13). This should be documented better.
First at the command line...
grape install org.codehaus.groovy.modules.http-builder http-builder 0.5.0-RC2
Then in groovysh...
groovy:000> import groovy.grape.Grape
groovy:000> Grape.grab(group:'org.codehaus.groovy.modules.http-builder', module:'http-builder', version:'0.5.0-RC2')
groovy:000> def http= new groovyx.net.http.HTTPBuilder('http://rovio')
===> groovyx.net.http.HTTPBuilder#91520
The #grab is better used in a file than the shell.
Ok. Seems like this a short working demo (running from the groovyConsole)
groovy.grape.Grape.initGrape()
#Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,2.3.0)')
public class UsedToExposeAnnotationToComplier {}
com.jidesoft.swing.JideSplitButton.class.name
When run it produces
Result: "com.jidesoft.swing.JideSplitButton"
Very cool!!
The import statement must appear after the grabs.
Ps. At least one import statement must exists after the grabs
#Grab(group='com.jidesoft', module='jide-oss', version='[2.2.1,)')
import com.jidesoft.swing.JideSplitButton
public class TestClassAnnotation {
public static String testMethod () {
return JideSplitButton.class.name
}
}
Different example using latest RC-2 (note: Grab annotates createEmptyInts):
// create and use a primitive array
import org.apache.commons.collections.primitives.ArrayIntList
#Grab(group='commons-primitives', module='commons-primitives', version='1.0')
def createEmptyInts() { new ArrayIntList() }
def ints = createEmptyInts()
ints.add(0, 42)
assert ints.size() == 1
assert ints.get(0) == 42
Another example (note: Grab annotates getHtml):
// find the PDF links in the Java 1.5.0 documentation
#Grab(group='org.ccil.cowan.tagsoup', module='tagsoup', version='0.9.7')
def getHtml() {
def parser = new XmlParser(new org.ccil.cowan.tagsoup.Parser())
parser.parse("http://java.sun.com/j2se/1.5.0/download-pdf.html")
}
html.body.'**'.a.#href.grep(~/.*\.pdf/).each{ println it }
Another example (note: Grab annotates getFruit):
// Google Collections example
import com.google.common.collect.HashBiMap
#Grab(group='com.google.code.google-collections', module='google-collect', version='snapshot-20080530')
def getFruit() { [grape:'purple', lemon:'yellow', orange:'orange'] as HashBiMap }
assert fruit.inverse().yellow == 'lemon'