Why can't I do a method call after a #Grab declaration in a Groovy script? - syntax

I'm trying to build a DSL and using a Global AST Transform to do it. The script is compiling with groovyc fine, but I'd like to be able to be able to have a user use Grab/Grape to pull the JAR and just have it execute right away as a groovy script.
I then found that I couldn't do it correctly because there's a parsing error in the script if there isn't a method declaration or import statement after the #Grab call.
Here's an example:
#Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
println "Hello World!"
It looks like it should work, but it complains (here's the output the GroovyConsole Script):
startup failed:
Script1.groovy: 4: unexpected token: println # line 4, column 1.
println "hello"
^
1 error
Trying different things makes it work, like an import statement:
#Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
import groovy.lang.Object
println "Hello World!" ​
Or a method declation:
#Grab(group='mysql', module='mysql-connector-java', version='5.1.6')
def hello() {}
println "Hello World!"
Is this a bug in the parser?
​

Grab can only be applied as an annotation to certain targets
#Target(value={CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PARAMETER,TYPE})
So you need to annotate one of those things (like you are seeing)
There is unfortunately no way in Java (and hence Groovy) of annotations just appearing in the middle of code.

test this
import static groovy.grape.Grape.grab
grab(group: "mysql", module: "mysql-connector-java", version: "5.1.6")
println "Hello World!"

Related

How to write Rspec test for running file from command line?

I have a Ruby project with a UNIX executable file called parse located in a bin subfolder in my project root directory.
At the moment it's just this:
#!/usr/bin/env ruby
# frozen_string_literal: true
puts 'hello world'
The file can be executed on the command line when this command is run from the project root directory: bin/parse
It works fine, but I also want to write a passing Rspec test for it.
I have this spec file:
RSpec.describe "end-to-end application behaviour" do
subject { system('bin/parse') }
it 'prints the expected messsage to stdout' do
expect { subject }.to output(
'hello world'
).to_stdout
end
end
When I run it I get the test failure:
expected block to output "hello world" to stdout, but output nothing
This is the location of my spec file relative to my project root: spec/integration/parse_spec.rb
I tried placing require and require_relative statements in that spec file with the paths to the parse executable, in case that would help, but I just kept getting:
LoadError: cannot load such file
Does anyone know how I can write a test in that file that will pass and prove the parse executable behaviour works?
Don't Use the RSpec Output Matcher
RSpec has a built-in output matcher than can test both where output goes, as well as its contents. However, it's testing where your Ruby output goes, not whether some external application is using standard input or standard error. You're going to have to make some different assumptions about your code.
You can avoid driving yourself nuts by comparing strings rather than testing the underlying shell or your output streams. For example, consider:
RSpec.describe "parse utility output" do
it "prints the right string on standard output" do
expect(`echo hello world`).to start_with("hello world")
end
it "shows nothing on standard output when it prints to stderr" do
expect(`echo foo >&2 > /dev/null`).to be_empty
end
end
Just replace the echo statements with the correct invocation of parse for your system, perhaps by setting PATH directly in your shell, using a utility like direnv, or by modifying ENV["PATH"] in your spec or spec_helper.
As a rule of thumb, RSpec isn't really meant for testing command-line applications. If you want to do that, consider using the Aruba framework to exercise your command-line applications. It's best to use RSpec to test the results of methods or the output of commands, rather than trying to test basic functionality. Of course, your mileage may vary.
Use ‍to_stdout_from_any_process instead of to_stdout:
expect { subject }.to output('hello world').to_stdout_from_any_process

How to call ruby class from Groovy class and execute it from groovy class

I wrote a ruby class which has print statement. Then i wrote a Groovy class which invokes this ruby class and executes
I tried like Process.execute("ruby.exe test.rb")
Ruby code-->
class Test
puts "hello, I am ruby"
end
Groovy code-->
class TestGroovy {
static main(String[] args) {
Process.execute("ruby.exe test.rb")
}
}
i need to get output as hello, I am ruby when i run TestGroovy.
From the docs:
Groovy provides a simple way to execute command line processes. Simply write the command line as a string and call the execute() method. E.g., on a *nix machine (or a windows machine with appropriate *nix commands installed), you can execute this:
def process = "ls -l".execute() // <1>
println "Found text ${process.text}" // <2>
executes the ls command in an external process
consume the output of the command and retrieve the tex
You can execute Ruby code from Groovy or Java code using a JSR-223 script engine. Here is an example Groovy script:
#Grab('org.jruby:jruby:9.2.5.0')
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
ScriptEngine engine = new ScriptEngineManager().getEngineByName('jruby')
engine.eval('puts "Hello world!"')
eval() also accepts a java.io.Reader which you could get from your file path. There are lots more details on ways to run Ruby from Java/Groovy here: https://github.com/jruby/jruby/wiki/RedBridge

Tests, using Aruba with Rspec, failing with `run` is not available from within an example (e.g. an `it` block)

I need to test a console application and check printed output, using rspec script. Example:
RSpec.describe 'Test Suite', type: :aruba do
it "has aruba set up" do
command = run("echo 'hello world'")
stop_all_commands
expect(command.output).to eq("hello world\n")
end
It fails with:
Failure/Error: command = run("echo 'hello world'")
`run` is not available from within an example (e.g. an `it` block) or from constructs that run in the scope of an example (e.g. `before`, `let`, etc). It is only available on an example group (e.g. a `describe` or `context` block).
Aruba version 0.14.6, Rspec 3.7.0. Will appreciate any help. Thanks.
As the error implies, you cannot call run within the it block. Aruba's documentation can get a bit confusing here because of the various branches, but the run method is still available in the still branch, with documentation found here.
Following the documentation, instead of defining command within the it block, we can instead define it outside the block using let:
RSpec.describe 'Test Suite', type: :aruba do
context "aruba test" do
let(:command) { run("echo 'hello world'") }
it "has aruba set up" do
stop_all_commands
expect(command.output).to eq("hello world\n")
end
end
end

Groovy script can't execute() external process

Main question: Would groovy's execute() method allow me to run a command that takes a file as an argument, any maybe run the command in background mode?
Here is my issue. I was able to use groovy's execute() for simple commands like ls for example. Suppose now I want to start a process like Kafka from a groovy script (end result is to replace bash files with groovy scripts). So I start with these lines:
def kafkaHome = "Users/mememe/kafka_2.11-0.9.0.1"
def zkStart = "$kafkaHome/bin/zookeeper-server-start.sh"
def zkPropsFile = "$kafkaHome/config/zookeeper.properties"
Now, executing the command below form my mac terminal:
/Users/mememe/kafka_2.11-0.9.0.1/bin/zookeeper-server-start.sh /Users/mememe/kafka_2.11-0.9.0.1/config/zookeeper.properties
starts up the the process just fine. And, executing this statement:
println "$zkStart $zkPropsFile"
prints the above command line as is. However, executing this command from within the groovy script:
println "$zkStart $zkPropsFile".execute().text
simply hangs! And trying this:
println "$zkStart $zkPropsFile &".execute().text
where I make it a background process goes further, but starts complaining about the input file and throws this exception:
java.lang.NumberFormatException: For input string: "/Users/mememe/kafka_2.11-0.9.0.1/config/zookeeper.properties"
Trying this gives the same exception as above:
def proc = ["$zkStart", "$zkPropsFile", "&"].execute()
println proc.text
What am I missing please? Thank you.
Yes, try using the consumeProcessOutpusStream() method:
def os = new File("/some/path/toyour/file.log").newOutputStream()
"$zkStart $zkPropsFile".execute().consumeProcessOutputStream(os)
You can find the the method in the Groovy docs for the Process class:
http://docs.groovy-lang.org/docs/groovy-1.7.2/html/groovy-jdk/java/lang/Process.html
Which states:
Gets the output and error streams from a process and reads them to keep the process from blocking due to a full output buffer. The stream data is thrown away but blocking due to a full output buffer is avoided. Use this method if you don't care about the standard or error output and just want the process to run silently - use carefully however, because since the stream data is thrown away, it might be difficult to track down when something goes wrong. For this, two Threads are started, so this method will return immediately.

Ruby script - does not print 'Hello world!' from the command line

I have the following code in the script a.rb.
def main
puts "Hello World!"
end
When I run ruby a.rb on the command line, it doesn't display anything.
Why is this happening?
Unlike languages like C/C++/Java, Ruby does't have a main method that's called at program startup. The name main is not special.
You defined a method named main, but never call1 it.
def main
puts "Hello World!"
end
main # here, call the method
1: Technically, calling methods should be called sending messages, the idea comes from Smalltalk.

Resources