How to call groovy inner class - groovy-console

This is my code, and I try to call the method in the inner class as shown below (the last line, ic = new oc.Inner()). But I get error.
I am using groovy console, and according to groovy documentation I expect that the Inner class can be called from outer class. I am not sure about the syntax.
class Outer {
private String privateStr = 'some string'
def callInnerMethod() {
new Inner().methodA()
}
class Inner {
def methodA() {
println "${privateStr}."
}
}
}
Outer oc = new Outer()
ic = new oc.Inner()
This is what I get as result:
startup failed:
Script1.groovy: 14: unable to resolve class oc.Inner
# line 14, column 6.
ic = new oc.Inner()
^
1 error

How about this:
def ic = new Outer.Inner()
This will likely only work if your inner class is static.

def oc = new Outer()
def ic = new Outer.Inner(oc)
https://groovy-lang.org/differences.html#_creating_instances_of_non_static_inner_classes

Related

How to declare static global values and define them later in Scala?

Primary goal
I want to use some static vals in a class so that I don't have to pass them as function parameters.
My approach
Since I want them to be static, I am declaring them in the companion object. But I cannot assign them values when I declare them, for some reasons. So I am following the below approach.
case class DemoParams(name: String)
class Demo {
def foo = {
println("Demo params name is: ", Demo.demoParams.name) // Works fine
anotherFoo(Demo.demoParams.name) // Throws NPE !
}
def anotherFoo(someName: String) = {
// some code
}
}
object Demo {
var demoParams: DemoParams = _ // Declare here
def apply() = new Demo()
def run = {
demoParams = DemoParams(name = "Salmon") // Define here
val demoObj = Demo()
demoObj.foo
}
def main() = {
run
}
}
Demo.main()
I am able to print Demo.demoParams but surprisingly, this throws a NullPointerException when I pass Demo.demoParams to another function, while running the Spark app on a cluster.
Questions
Firstly, is this the right way of declaring static values and defining them later? I would prefer to not use vars and use immutable vals. Is there a better alternative?
Second, could you think of any reason I would be getting a NPE while passing Demo.demoParams.name to another function?
Your code works fine and doesn't throw anything (after fixing a few compile errors).
But ... Don't do this, it's ... yucky :/
How about passing params to the class as ... well ... params instead?
case class Demo(params: DemoParams) {
def foo() = {
println("Demo params name is: " + params.name)
}
}
object Demo {
def run() = {
val demoParams = DemoParams(name = "Salmon")
val demoObj = Demo(demoParams)
demoObj.foo()
}
}
Not sure this is the best alternative, but consider using a trait, which still keeps you in the FP zone by avoiding the use of var:
case class DemoParams(name: String)
trait Demo {
val demoParams: DemoParams
}
Then just define it where you need it, and it's ready for use:
object MainApp extends App {
val demoObj = new Demo {
override val demoParams: DemoParams = DemoParams(name = "Salmon")
}
println("Demo params name is: ", demoObj.demoParams.name) // (Demo params name is: ,Salmon)
anotherFoo(demoObj.demoParams.name) // Salmon
def anotherFoo(name: String): Unit = println(name)
}
About the second question, without the actual code one can only guess (this sample code does not throw NPE). Probably somewhere you are using it without defining it previously, because var demoParams: DemoParams = _ just initializes demoParams to the default value of the reference type DemoParams, which is null in this case, and you get NPE when you try to access the name value of a null object. This is why using var is discouraged.

Unable to mock method using pytest-mock

I have a class 'MyClass' with code as below.
class MyClass:
def __init__(update_type_id='1')
self.update_type_id = update_type_id
self._cursor = <database_connection).cursor()
def update_start_dt(self):
self._update_job_ctrl_start_dt()
def _update_job_ctrl_start_dt(self):
update_sql, v_1 = self._get_update_sql(self._update_type_id)
logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
def _get_update_sql(self, update_type_id: int) -> Tuple:
sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
self._run_sql(sql)
record = self._cursor.fetchone()
if record:
return record
else:
logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
raise Exception
def _run_sql(self, sql_statement: str):
try:
self._cursor.execute(sql_statement)
except (Exception, Error) as e:
logger.error(f'Error {e} encountered when reading from table')
raise e
I am trying to write a test function using pytest-mock which will test the update_start_dt method. The method internally invokes a series of private methods and I am having difficulty in mocking the code which runs through all the private methods. Can anyone help me to understand in what all ways we can mock?
I tried to refer multiple online websites but couldn't get a complete picture.
class TestMyClass:
def test_update_start_dt(mocker,mock_get_connection,mock_run_sql):
mock_manager = mocker.Mock()
mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
mock_get_update_sql.return_value = ('123','234')
myclass = MyClass(update_type_id='1')
myclass.update_start_dt()
I am getting error as below for above test code
update_sql, v_1 = self._get_update_sql(self._update_type_id)
ValueError: not enough values to unpack (expected 2, got 0)
The issue here is that you are patching on a Mock object that you are creating, for the purposes of your test you do not need to explicitly create a Mock object. Shown below is how you would test it instead, where we patch directly on the class.
class MyClass:
def __init__(self, update_type_id='1'):
self._update_type_id = update_type_id
self._cursor = None
def update_start_dt(self):
self._update_job_ctrl_start_dt()
def _update_job_ctrl_start_dt(self):
update_sql, v_1 = self._get_update_sql(self._update_type_id)
logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
def _get_update_sql(self, update_type_id: int):
sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
self._run_sql(sql)
record = self._cursor.fetchone()
if record:
return record
else:
logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
raise Exception
def _run_sql(self, sql_statement: str):
try:
self._cursor.execute(sql_statement)
except (Exception, Error) as e:
logger.error(f'Error {e} encountered when reading from table')
raise e
def test_update_start_dt(mocker):
mock_get_update_sql = mocker.patch.object(MyClass, "_get_update_sql")
mock_get_update_sql.return_value = ("123", "234")
myclass = MyClass(update_type_id='1')
myclass.update_start_dt()
=========================================== test session starts ============================================
platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
rootdir: ***
plugins: mock-3.7.0
collected 1 item
test_script.py . [100%]
======================================= 1 passed, 1 warning in 0.01s =======================================
Your code would work if you called the Mock object you created instead of the class. That is shown below.
def test_update_start_dt(mocker):
mock_manager = mocker.Mock()
mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
mock_get_update_sql.return_value = ('123','234')
# Notice how we use `mock_manager` instead of MyClass
# tests will now pass
myclass = mock_manager(update_type_id='1')
myclass.update_start_dt()
Hopefully you see what the issue is now.

Early initializer `new {} with SomeTrait` fails

There seems to be a subtlety when using early initializer syntax.
trait Base { def callMe = "callMe" }
trait Proxy { this: Base => def call = s"proxied: $callMe" }
val base1 = new Base { } // non-early init works
val baseFail = new { } with Base // error: trait Base is abstract; cannot be instantiated
val base2 = new { val n=1 } with Base // why does this fix the failure?
val proxy = new { } with Base with Proxy // why doesn't this fail?
Why does the baseFail line fail, while the other vals don't?
The error message is also confusing - I'm not trying to instantiate Base, only mix it in.
When you write new { } with Base, there technically aren't any early definitions. According to the SLS 5.1.6, the compiler looks for a pattern like this:
EarlyDefs ::= `{' [EarlyDef {semi EarlyDef}] `}' `with'
EarlyDef ::= {Annotation} {Modifier} PatVarDef
Though it doesn't explicitly say what happens when the sequences of definitions is empty, it seems to just remove them, because when you compile val a = new { val x = 1 } with Base, you get something like this after the parsing phase:
val a = {
final class $anon extends Base {
val x = _;
def <init>() = {
val x = 1;
super.<init>();
()
}
};
new $anon()
}
But if you empty the braces, you simply get:
val a = new Base()
Which is illegal, as is new Base.
To summarize:
Is an anonymous class, which is allowed
:
val base1 = new Base { }
Simplifies to new Base, which is illegal:
val baseFail = new { } with Base
Is a proper early definition (not empty) which is allowed:
val base2 = new { val n=1 } with Base
Simplifies to new Base with Proxy which is also allowed:
val proxy = new { } with Base with Proxy
new { } with Base { } also compiles, but it's exactly the same as new Base { }, so there's no reason to write it that way.
I am not sure, but the simplest explanation I can think of for this behavior is that the empty early initializer is simply optimized away, so it's equivalent to val baseFail = new Base and val proxy = new Base with Proxy. new Base fails with the same error message, and new Base with Proxy is legal because it's an anonymous class. If so, I think it's technically a compiler bug, but quite a minor one.

Extending Inner class

I am trying to replicate my problem on a smaller example.
I am getting compilation error at the shown location in the following code snippet.
class Outer {
class Inner
}
object OuterUtil {
val obj = new Outer
object xyz extends obj.Inner
//do something with xyz
}
//-------------------
object OuterUtil2 {
var m_obj: Outer = null
def createOuter() = {
m_obj = new Outer
}
def anotherMethod() {
//Compilation error here: stable identifier required,
//but OuterUtil2.this.m_obj found.
object xyz extends m_obj.Inner
}
}
object Test {
OuterUtil2.createOuter
OuterUtil2.anotherMethod
}
OuterUtil is working fine.
In OuterUtil2, I am splitting the functionality into two functions. I am storing the Outer instance m_obj as a member var. The createOuter method creates and stores the Outer instance in m_obj. In anotherMethod, I am getting compilation error. How to fix OuterUtil2?
The prefix of a type (ie, the m_obj in m_obj.Inner) must be a stable value; a var doesn't cut it. You could make that a val and move the initialization out of createOuter.
If you just want to solve the problem with your function, here is a solution (by fixing the var to a val in the function)
def anotherMethod = {
val obj = m_obj
new obj.Inner
}
Another solution would be to use some options, however to overpass the stable identifier method, you have to define a val out of m_obj value. This solution is more elegant because you don't have null pointer exceptions if m_obj is not defined.
object OuterUtil2 {
var m_obj: Option[Outer] = None
def createOuter {
m_obj = Some(new Outer)
}
def anotherMethod = {
m_obj match{
case None => None
case Some(_) => val obj = m_obj.get; Some(new obj.Inner)
}
}
}

Scala: Can I reproduce anonymous class creation with a factory method?

As far as I understand it, Scala creates an anonymous class if I create a class using the new keyword and follow the class name with a constructor:
class MyClass {
def doStuff() {
// ...
}
}
val mc = new MyClass {
doStuff()
}
The nice thing being that all the code in the constructor is in the scope of the new object.
Is there a way I can reproduce this syntax where the class is created by a factory method rather than the new keyword? i.e. make the following code work:
val mf = new MyFactory
val mc = mf.MyClass {
doStuff()
}
I can't find a way to do it but Scala has so much to it that this might be pretty easy!
Using an import as suggested by #Ricky below I can get:
val mf = MyFactory;
val mc = mf.MyClass
{
import mc._
doStuff()
}
(Where the blank line before the block is needed) but that code block is not a constructor.
You can do this, but you still have to keep the new keyword, and create the nested class as a path-dependent type:
class Bippy(x: Int) {
class Bop {
def getIt = x
}
}
val bip = new Bippy(7)
val bop = new bip.Bop
bop.getIt // yields 7
val bop2 = new bip.Bop{ override def getIt = 42 }
bop2.getIt // yields 42
I don't think it's possible. However, a common pattern is to add a parameter to factory methods which takes a function modifying the created object:
trait MyClass {
var name = ""
def doStuff():Unit
}
class Foo extends MyClass {
def doStuff() { println("FOO: " + name) }
}
trait MyClassFactory {
def make: MyClass
def apply( body: MyClass => Unit ) = {
val mc = make
body(mc)
mc
}
}
object FooFactory extends MyClassFactory {
def make = new Foo
}
You can then create and modify instance with a syntax close to your example:
val foo = FooFactory { f=>
f.name = "Joe"
f.doStuff
}
It sounds like you're just looking to mix in a trait. Instead of calling myFactoryMethod(classOf[Foo]] which ideally would do (if Scala permitted it):
new T {
override def toString = "My implementation here."
}
you can instead write
trait MyImplementation {
override def toString = "My implementation here."
}
new Foo with MyImplementation
However, if you are just looking to get the members of the new object accessible without qualification, remember you can import from any stable identifier:
val foo = new Bar
import foo._
println(baz) //where baz is a member of foo.