IronRuby - Wrong number of arguments - ironruby

I just started using IronRuby. This is my test class:
class Program
{
static void Main(string[] args)
{
var path = #"C:\Users\frays\Desktop\test.rb";
var engine = Ruby.CreateEngine();
var scope = engine.Runtime.CreateScope();
scope.SetVariable("sendNext", new Action<string>(SendNext));
engine.ExecuteFile(path, scope);
Console.Read();
}
private static void SendNext(string text)
{
Console.WriteLine(text);
}
}
And this is my test script:
sendNext 'heyyy'
However, when trying to run the program it throws an exception saying wrong number of arguments (1 for 0), even though the method definitely takes a string as an argument.

This says that it is not possible Calling IronRuby from C# with a delegate but you can just call the invoke method.
sendNext.Invoke( 'heyyy')

Related

How to retrieve the value from the event listener from another class in java?

I have a program to get the values from a Bar code scanner(using jssc library) and it returns value as expected using event listener but I need to access that value from another class.
I tried to instantiate BarcodeScanner class to main method (ProcessTicket class) and called scannerHandler method and also called the getter method of model class to retrieve value but the getter method runs before the scan is completed. Could you please help me to achieve this?
public class BarcodeScanner {
public static Object SerialPortReader;
static SerialPort serialPort;
public void scannerHandler() {
serialPort = new SerialPort("COM4");
try{
serialPort.openPort();//Open serial port
//Set params. Also set params by this string:
serialPort.setParams(9600, 8, 1, 0);
serialPort.setParams(9600, 8, 1, 0);
serialPort.writeString(new String(new byte[]{0x02})); //triggers barcode scanner
serialPort.addEventListener(new SerialPortReader());//Add SerialPortEventListenerS
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
public static class SerialPortReader implements SerialPortEventListener {
String str;
String value;
public void serialEvent(SerialPortEvent event) {
if (event.isRXCHAR() && event.getEventValue() > 0) {//If data is available
//Check bytes count in the input buffer
try {
byte[] bytesCont = serialPort.readBytes(14);
str = new String(bytesCont);
ModelClass modelClass = new ModelClass();
modelClass.setBarcodeValue(str);
} catch (SerialPortException e) {
e.printStackTrace();
}
}
}
My ProcessTicket.java Class
public class ProcessTicket {
public static void main(String[] args) throws SQLException, SerialPortException {
BarcodeScanner bSC = new BarcodeScanner();
bSC.scannerHandler();
BarcodeScanner.SerialPortReader portReader = new BarcodeScanner.SerialPortReader();
ModelClass modelClass = new ModelClass();
String value = modelClass.getBarcodeValue();
System.out.println(value);
}
}
The main problem here is that you're treating an inherently asynchronous operation (reading from an external sensor in the real world) as if it's synchronous.
I simulated that external sensor stuff to make a standalone app that tests your business logic:
HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava.java
package com.stackoverflow;
/**
* https://stackoverflow.com/questions/57452205/how-to-retrieve-the-value-from-the-event-listener-from-another-class-in-java
*/
public class HowToRetrieveTheValueFromTheEventListenerFromAnotherClassInJava {
public static void main(String[] args) {
BarcodeScanner barcodeScanner = new BarcodeScanner((String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
});
barcodeScanner.startScan();
MockUser.startScanningStuffLol();
}
}
That call to MockUser.startScanningStuffLol() is only necessary because I'm testing this just in code, without using a real barcode scanner. Please don't focus on it. I'll post its implementation if you ask, but otherwise I'm assuming that your OS/Java/hardware are working the way they were designed to work, and you can just test this with those tools instead of my MockUser software simulation.
Here are the rest of the classes that you need to implement this:
BarcodeScannedCallback.java
package com.stackoverflow;
public interface BarcodeScannedCallback {
void callback(String barcode);
}
Since we're dealing with an asynchronous operation, we can't just start it and then check for a return value, like we would with a synchronous operation. Instead, we need to pass in a function that will be called once the operation is complete, and just wait for it to finish. BarcodeScannedCallback is the signature of that function (in other words, a description of how that function needs to be structured). It takes one string parameter, and returns nothing.
The implementation of BarcodeScannedCallback is this function that I've already mentioned above, which I'm passing into the BarcodeScanner constructor:
(String barcode) -> {
System.out.println("Barcode scanned: " + barcode);
}
As you can see, this function takes one string parameter, and returns nothing. So, it's an implementation of the BarcodeScannedCallback interface.
Now for the last class: the one that bridges our main method and the serial port, using the above interface.
BarcodeScanner.java
package com.stackoverflow;
public class BarcodeScanner implements SerialPortEventListener {
private SerialPort serialPort;
private final BarcodeScannedCallback callback;
public void startScan() {
try {
serialPort = new SerialPort("COM4");
serialPort.openPort();
serialPort.addEventListener(this);
// Also you can set params by this string: serialPort.setParams(9600, 8, 1, 0);
serialPort.setParams(9600, 8, 1, 0);
// Triggers barcode scanner.
serialPort.writeString(new String(new byte[]{0x02}));
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
#Override
public void serialEvent(SerialPortEvent event) {
boolean isDataAvailable = event.isRXCHAR() && event.getEventValue() > 0;
if (isDataAvailable) {
try {
byte[] bytesCont = serialPort.readBytes(14);
String barcode = new String(bytesCont);
callback.callback(barcode);
} catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
public BarcodeScanner(BarcodeScannedCallback callback) {
this.callback = callback;
}
}
So here's the full lifecycle of these events:
You create a BarcodeScanner.
You tell the BarcodeScanner, via the implementation of BarcodeScannedCallback that you pass into its constructor, what code to run once it receives a barcode over the serial port.
You call startScan on the BarcodeScanner, which opens the serial port and starts waiting for the user to scan a barcode.
The user scans a barcode. This data is transmitted over the serial port. The operating system's implementation of SerialPort calls BarcodeScanner.serialEvent.
Your implementation of serialEvent does its validations, pulls the data from the serial port and converts it from bytes to a string, and calls the BarcodeScannedCallback function that was passed in at the beginning.
When I run this (with my MockUser class setting up a background thread that "scans" a barcode every 3 seconds), I get this output:
Barcode scanned: 420L0L
Barcode scanned: 007
Barcode scanned: 12345
In your case, you should be able to scan 3 barcodes with your real-world barcode scanner, and get the same results.
Note that you may need to do something to keep the main method's thread from ending prematurely, depending on the context that you're running this in.
If you're running it in an Android app or a web server, those frameworks keep their main thread running indefinitely, until you kill the app/server.
But if you're running it as a custom command-line app (which it seems like you're doing, based on the existence of a main method), you will need to do something to keep it alive until you decide to kill it. The simplest way is to put an infinite loop like while (true); on the last line of your main method.

Mockito: Verifying a method was called with a functional parameter

I have a simple scenario in which am trying to verify some behavior when a method is called (i.e. that a certain method was called with given parameter, a function pointer in this scenario). Below are my classes:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
AppBootStrapper bootStrapper = context.getBean(AppBootStrapper.class);
bootStrapper.start();
}
}
#Component
public class AppBootStrapper {
private NetworkScanner networkScanner;
private PacketConsumer packetConsumer;
public AppBootStrapper(NetworkScanner networkScanner, PacketConsumer packetConsumer) {
this.networkScanner = networkScanner;
this.packetConsumer = packetConsumer;
}
public void start() {
networkScanner.addConsumer(packetConsumer::consumePacket);
networkScanner.startScan();
}
}
#Component
public class NetworkScanner {
private List<Consumer<String>> consumers = new ArrayList<>();
public void startScan(){
Executors.newSingleThreadExecutor().submit(() -> {
while(true) {
// do some scanning and get/parse packets
consumers.forEach(consumer -> consumer.accept("Package Data"));
}
});
}
public void addConsumer(Consumer<String> consumer) {
this.consumers.add(consumer);
}
}
#Component
public class PacketConsumer {
public void consumePacket(String packet) {
System.out.println("Packet received: " + packet);
}
}
#RunWith(JUnit4.class)
public class AppBootStrapperTest {
#Test
public void start() throws Exception {
NetworkScanner networkScanner = mock(NetworkScanner.class);
PacketConsumer packetConsumer = mock(PacketConsumer.class);
AppBootStrapper appBootStrapper = new AppBootStrapper(networkScanner, packetConsumer);
appBootStrapper.start();
verify(networkScanner).addConsumer(packetConsumer::consumePacket);
verify(networkScanner, times(1)).startScan();
}
}
I want to verify that bootStrapper did in fact do proper setup by registering the packet consumer(there might be other consumers registered later on, but this one is mandatory) and then called startScan. I get the following error message when I execute the test case:
Argument(s) are different! Wanted:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapperTest$$Lambda$8/438123546#282308c3
);
-> at com.spring.starter.AppBootStrapperTest.start(AppBootStrapperTest.java:24)
Actual invocation has different arguments:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapper$$Lambda$7/920446957#5dda14d0
);
-> at com.spring.starter.AppBootStrapper.start(AppBootStrapper.java:12)
From the exception, clearly the function pointers aren't the same.
Am I approaching this the right way? Is there something basic I am missing? I played around and had a consumer injected into PacketConsumer just to see if it made a different and that was OK, but I know that's certainly not the right way to go.
Any help, perspectives on this would be greatly appreciated.
Java doesn't have any concept of "function pointers"; when you see:
networkScanner.addConsumer(packetConsumer::consumePacket);
What Java actually compiles is (the equivalent of):
networkScanner.addConsumer(new Consumer<String>() {
#Override void accept(String packet) {
packetConsumer.consumePacket(packet);
}
});
This anonymous inner class happens to be called AppBootStrapper$$Lambda$7. Because it doesn't (and shouldn't) define an equals method, it will never be equal to the anonymous inner class that the compiler generates in your test, which happens to be called AppBootStrapperTest$$Lambda$8. This is regardless of the fact that the method bodies are the same, and are built in the same way from the same method reference.
If you generate the Consumer explicitly in your test and save it as a static final Consumer<String> field, then you can pass that reference in the test and compare it; at that point, reference equality should hold. This should work with a lambda expression or method reference just fine.
A more apt test would probably verify(packetConsumer, atLeastOnce()).consumePacket(...), as the contents of the lambda are an implementation detail and you're really more concerned about how your component collaborates with other components. The abstraction here should be at the consumePacket level, not at the addConsumer level.
See the comments and answer on this SO question.

Measure sub time into a method

I am using PostSharp to log performance and other statistics on some methods. I was asked to measure the performance and time taken on some sub tasks, such as calling an external web service, or a large database, etc.
For example, I have a method with the AoPLoggingAttribute applied. AoPLoggingAttribute inherits from OnMethodBoundaryAspect, so it supports all know methods (OnEntry, OnExit, OnSuccess, etc)
[AoPLogging]
public MyClass[] MyMainMethod(string myid)
{
//Some code here
LongExecutingTask();
//Rest of the code here
}
What is the best approach to measure the time taken by LongExecutingTask ? I don't care if it's part of the total executing time, but somehow I need to know the time taken from this task.
If you want to use postsharp you could make a timer aspect like this
public class TimingAttribute : OnMethodBoundaryAspect
{
Stopwatch timer = new Stopwatch();
public override void OnEntry(MethodExecutionArgs args)
{
timer.Reset();
timer.Start();
base.OnEntry(args);
}
public override void OnExit(MethodExecutionArgs args)
{
timer.Stop();
Console.WriteLine("Execution took {0} milli-seconds", timer.ElapsedMilliseconds);
base.OnExit(args);
}
}
Now just attach the aspect to the method you want to time
[Timing]
public void LongExecutingTask() {}
Remember that postsharp, or AOP in general, works by attaching to the method being called. Not by adding code insert your main method (or whereever you are calling the methods)
Update: If you really want to keep track of the whole callstack you could do something like this
public class TimingAttribute : OnMethodBoundaryAspect
{
static List<Stopwatch> callstack = new List<Stopwatch>();
static int callstackDepth = 0;
public override void OnEntry(MethodExecutionArgs args)
{
var timer = new Stopwatch();
timer.Start();
callstack.Add(timer);
++callstackDepth;
base.OnEntry(args);
}
public override void OnExit(MethodExecutionArgs args)
{
--callstackDepth;
var timer = callstack[callstackDepth];
timer.Stop();
if (callstackDepth == 0) {
//Add code to print out all the results
Console.WriteLine("Execution took {0} milli-seconds", timer.ElapsedMilliseconds);
callstack.Clear();
}
base.OnExit(args);
}
}
Now this only works with 1 single callstack. If you were to have 2 LongExecutingTasks in your main method you would have to think about how you want to report over thoes. But maybe this gives you an idea how you could keep track of the whole callstack.
You must assign your timer to the MethodExecutionArgs in order to get accurate results in a multi-threaded environment. PostSharp internally assigns to a static class, so any members risk being overwritten by concurrent invocations.
public class TimingAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
args.MethodExecutionTag = Stopwatch.StartNew();
}
public override void OnExit(MethodExecutionArgs args)
{
var sw = (Stopwatch)args.MethodExecutionTag;
sw.Stop();
System.Diagnostics.Debug.WriteLine("{0} executed in {1} seconds", args.Method.Name,
sw.ElapsedMilliseconds / 1000);
}
}

How to strip host information from an hdfs path

I have an hdfs path hdfs://host1:8899/path/to/file. I want to strip the host1 and port programmatically. As result, it should be hdfs:/path/tofile. Is there any helper method can do that?
"Is there any helper method can do that?"
Doesn't really take much to create your own. Just use the basic String class utility functions like split(), indexOf(), substring(), etc.
Something like this would do (with Java, though most languages have those methods):
public class TestPath {
public static void main(String[] args) throws Exception {
String path = "hdfs://localhost:9000/path/to/file";
System.out.println(getPathWithoutHostAndPort(path));
}
public static String getPathWithoutHostAndPort(String path) {
String[] array = path.split("(//)");
int indexOfFirstSlash = array[1].indexOf("/");
StringBuilder builder = new StringBuilder();
builder.append(array[0]).append(array[1].substring(indexOfFirstSlash));
return builder.toString();
}
}
Result: hdfs:/path/to/file

Why can't I define an Action in line in a method expecting a delegate?

Given the following MSDN sample code, why can't I define the Action delegate "inline":
public static void Main(string[] args)
{
Action someAction = () => Console.WriteLine("Hello from the thread pool!");
Task.Factory.StartNew(someAction);
}
...so "inline" like:
public static void Main(string[] args)
{
Task.Factory.StartNew(Action someAction = () => Console.WriteLine("etc."));
}
Thanks,
Scott
This isn't valid C#:
public static void Main(string[] args)
{
Task.Factory.StartNew(Action someAction = () => Console.WriteLine("etc."));
}
Do this instead:
public static void Main(string[] args)
{
Task.Factory.StartNew(() => Console.WriteLine("etc."));
}
You're trying to delegate a variable within a method call. Just removing the variable declaration may be fine:
public static void Main(string[] args)
{
Task.Factory.StartNew(() => Console.WriteLine("etc."));
}
Here the Action is inferred not from the lambda expression itself, but from the method call it's trying to make. Normal overload resolution is performed, and the compiler tries to convert the lambda expression to the relevant parameter type. If the parameter type were just Delegate (e.g. Control.Invoke) then type inference would fail because the compiler wouldn't have any concrete target types to try to convert to.
If that doesn't work (I can't easily test it atm) then you just need a cast to tell it which delegate type the lambda expression should be converted to:
public static void Main(string[] args)
{
Task.Factory.StartNew((Action)(() => Console.WriteLine("etc.")));
}
To be honest though, at that point I'd prefer to see a separate variable in terms of readability.
You are including the declaration statement, which is not a legal expression. Try:
Task.Factory.StartNew(() => Console.WriteLine("etc."));
If you call an API where the type of the delegate can't be inferred, you can use a cast or call the delegate constructor explicitly:
Task.Factory.StartNew((Action)(() => Console.WriteLine("etc.")));
Task.Factory.StartNew(new Action(() => Console.WriteLine("etc.")));
I wouldn't know tbh, but I think you can do:
public static void Main(string[] args)
{
Task.Factory.StartNew(delegate() {Console.WriteLine("etc.");});
}

Resources