How do I call instance method from string? - crystal-lang

Let's say I have a class
class MyClass
def sayMyName()
puts "I am unknown"
end
end
and I have stored this method name in a variable: methodName = "saymyName"
I want to call this method by using above variable, something like this:
instance = MyClass.new
instance[methodName]
I know it can be called using a macro but I don't get how? Please someone provide an example with explanation.
Update 1
There is already an answer for this: Calling methods dynamically (Crystal-lang)
but this doesn't answer how to do it when methods are inside a class.

I have adapted the example given in the update:
class Foo
def method1
puts "i'm method1"
end
def method2
puts "i'm method2"
end
def method3
puts "i'm method3"
end
def bar
{ "ctrl": -> { method1 },
"shift": -> { method2 },
"alt": -> { method3 }
}
end
def [](method)
bar[method]
end
end
binding = ["ctrl", "shift", "alt"].sample
foo = Foo.new
foo[binding].call #=> one of them
Working Example

Related

Scalamock: Mocking call by-name function with arguments

In following code snippet, I need to ensure that BinaryConverter#intToStr is invoked.
import org.scalamock.scalatest.MockFactory
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
class Foo {
def foo(x: Int)(b: => String): String = b
}
class BinaryConverter {
def intToStr(x: Int): String = x.toBinaryString
}
class Converter(fooBar: Foo, converter: BinaryConverter) {
def convert2Bin(x: Int): String = fooBar.foo(x)(converter.intToStr(x))
}
class FooTest extends AnyFlatSpec with Matchers with MockFactory {
val mockFoo: Foo = mock[Foo]
val mockBinConverter: BinaryConverter = mock[BinaryConverter]
val converter = new Converter(mockFoo, mockBinConverter)
behavior of "Foo"
it should "mock foo doesn't work" in {
(mockBinConverter.intToStr _).expects(2).returns("Mock 10")
(mockFoo.foo(_: Int)(_: String)).expects(2, *).onCall(_.productElement(1).asInstanceOf[Int => String](2))
converter.convert2Bin(2) shouldBe "Mock 10"
}
}
I've tried to use onCall product but get Converter$$Lambda$132/182531396 cannot be cast to scala.Function1. Although, same code works when casting a parameterless function to Function0, .asInstanceOf[() => String]()
Now, I understand the mistake I was making; I was trying to cast the curried call-by-name argument of the Foo#foo to be the function that was placed in it, in above sample it's BinaryConverter#intToStr(x: Int): String.
Instead, parameter should be cast to () => String and then invoked so the code inside can be executed.
(mockFoo.foo(_: Int)(_: String)).expects(2, *).onCall(_.productElement(1).asInstanceOf[() => String]())

equivalent of ruby `block_given?` in crystal

Ruby has this method called the block_given in it so that we can check to see if a block is passed and process accordingly if given. Is there an equivalent method in crystal?
Crystal does not have it for a moment. But you can have similar behavior using method overloading:
def foo
foo {}
end
def foo
yield
end
foo { }
foo
If you absolutely must know whether a block was given, you can do something like this:
def foo(block : (String ->)? = nil)
if block
block.call("Block given")
else
puts "No block given"
end
end
def foo(&block : String ->)
foo(block)
end
foo { |s| puts s }
foo
(For more information on Proc syntax, see https://crystal-lang.org/reference/syntax_and_semantics/type_grammar.html#proc)

Is it possible to import a class defined in a .groovy script from a GroovyTestCase?

I have a groovy script defined, which includes an inner class
foo.groovy:
// does something
Bar {
int foobar() {
return 1
}
}
// Does something else
Why I have the class defined in the script is a longer story, but it's necessary, unless I want to make a big redesign of the project structure (And the customer doesn't want to pay for this time)
Anyway, I have a GroovyTestCase, where I want to call this class from.
I want to do something like this:
class Test extends GroovyTestCase {
void testSomething() {
Bar bar = new Bar()
assertTrue(1, bar.foobar())
}
}
Is it possible to reference a class defined in a groovy script? If so, how?
foo.groovy
println "foooo 01"
class Bar {
int foobar() {
return 1
}
}
println "foooo 02"
Test.groovy (you can make it as a class)
def shell = new GroovyShell()
//parse script
def script = shell.parse(new File("/11/foo.groovy"))
//get class loader used for script parsing
def cl = shell.getClassLoader()
//get list of parsed/loaded classes
println cl.getLoadedClasses() // [class Bar, class foo]
def bar = cl.loadClass('Bar').newInstance()
println bar.foobar() // 1
but beware! if your foo.groovy script loaded some other classes that you want to access in testcase, you have to do it through the same shell classloader, otherwise there could be strange errors like could not assign String to String...

Inner function in Python

def getMessage1(self, id, queueName):
uuid = id
def onMessage(ch, method, properties, body):
if uuid in body:
requeued_messages = self.channel.stop_consuming()
return body
self.channel.basic_consume(consumer_callback = onMessage, queue = queueName, no_ack = True)
self.channel.start_consuming()
return onMessage(ch, method, properties, body)
#global name 'ch' is not defined
I am trying to define two function as shown in the code. I am try to return body to the inner function and I also want to the same body to return to my outer function i.e getMessage1.
But this above code returns me with
"function onMessage at 0x0000000006642128" not the "body"
and also I want my inner function to get the come out of the loop only when the uuid is present in the body.
Returned body is a string
here is the basic_consume function that I am using
def basic_consume(self, consumer_callback,
queue='',
no_ack=False,
exclusive=False,
consumer_tag=None,
arguments=None):
"""Sends the AMQP command Basic.Consume to the broker and binds messages
for the consumer_tag to the consumer callback. If you do not pass in
a consumer_tag, one will be automatically generated for you. Returns
the consumer tag.
For more information on basic_consume, see:
http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.consume
:param method consumer_callback: The method to callback when consuming
with the signature consumer_callback(channel, method, properties,
body), where
channel: pika.Channel
method: pika.spec.Basic.Deliver
properties: pika.spec.BasicProperties
body: str, unicode, or bytes
In order for getMessage1 to return the body from onMessage, you need to return the call of onMessage. As it stands now, you're returning a function.
Consider these two examples:
def foo():
def bar():
return "This is from Bar"
return bar()
print foo()
Result:
This is from Bar
vs
def foo():
def bar():
return "This is from Bar"
return bar
print foo()
Result:
<function bar at 0x0270E070>
You get the message function onMessage at 0x0000000006642128 because your return statement return onMessage returns the function onMessage without evaluating the results. If you want to evaluate the function you need something like return onMessage(channel, method, properties, body) with the values/variables you want evaluated inside the parentheses. Below is a working example of an inner and outer function:
def sumOfSquares(a,b):
def square(c):
return (c*c)
return square(a)+square(b)
print(sumOfSquares(2,3))
I don't see a loop in either function. Please provide more information on the second part of your question.

Mock a single method of unit under test in Groovy

I have a simple class like
class SomeClass {
def foo() {
def bar= bar()
switch( bar ) {
return something based on format
}
}
def bar() {
return someValue
}
}
I've already written complete unit tests for the bar(). Now I need to write unit tests for foo() which is heavily dependant on the use of bar() method. I don't want to duplicate the setup phase as done for bar(), so I'd like to mock it by simply returning values I want.
I'm aware that Groovy supports this sort of "mocking" easily by simply defining it like SomeClass.property = "Hello World". Also, this can be done with collaborators as SomeClass.service = myMockedService. But I've not found a way to accomplish this with methods inside the unit under tests. Is there?
I tried with MockFor as in
def uut = new MockFor( SomeClass )
uut.demand.bar{ /* some values */ }
uut.use {
assert uut.foo() == expected
}
but it gives me
groovy.lang.MissingMethodException: No signature of method: groovy.mock.interceptor.MockFor.foo() is applicable for argument types: () values: []
UPDATE
In fact, I came up with a simple solution of using sub-classing. In the test method I create a subclass of SomeClass where I override the method I wish to mock/stub. After this, using an instance of the subclass gives me what I need.
This seems a bit rough, though. Any other suggestions on this?
If you want to mock the value returned by bar() for a single instance of SomeClass you can use metaprogramming. Try the following in the Groovy console:
class SomeClass {
def foo() {
}
def bar() {
return 'real value'
}
}
def uut = new SomeClass()
uut.metaClass.bar = {
return 'mock value'
}
assert 'mock value' == uut.bar()
If you want to mock bar() for all instances of SomeClass, replace this:
uut.metaClass.bar = {
return 'mock value'
}
with:
SomeClass.metaClass.bar = {
return 'mock value'
}