I have a Perl library i use to read some information from a file (closed format).
This library reads a file and returns an array of objects with the result.
Now i have to integrate that library (cannot implement it in cocoa right now) in a cocoa app. Basically call it and try to show the results in a list.
Is there some kind of bridge to call Perl libraries from ObjectiveC and get the results?
I've read something about using NSTask to call a perl script directly, and parse the result, but i wonder if it could be possible to do that call directly.
best regards.
You are perfectly right: NSTask is on Cocoa (not Cocoa-Touch) the right class for you. You can launch any subprocess, considering that this subprocess will inherit the environment from you main task (but of course you can apply different settings, e.g. the run directory).
The advantage with respect to "system()" is that NSTask "launch" method is non blocking so you can use it for long aysnchronous jobs (and be notified when it is over).
For the specific case of perl, just run the perl script as in command line: "/usr/bin/perl ..."
Finally you can make a try with PerlObjCBridge (link: PerlObjCBridge.pm man page) for a sort of interprocess communication between Objective-C objects and perl.
If you want a bridge, take a look at PerlObjCBridge. If you just want to call the script, I believe you can just use system(). Something like this:
system( [scriptCallNSString UTF8String] );
Related
How could I automate interactions with command line programs that expose a text terminal interface with Perl 6 for testing purposes?
If you want to use Perl 6 to automate execution or testing of console applications, I think you're going to use NativeCall to interact with the expect library. Once expect is installed, man libexpect will show its API documentation, though the way of accessing the documentation (such as the manpage name) may differ per package distribution.
Expect has APIs to launch a program, wait for text to appear on the (emulated) console (to "expect" text), and send text to the console (to emulate typing). The most common use case is to automate programs which require password input. Expect is often scripted--it is an interpreter--but there's no reason not to use it from a higher level programming language.
Edit: I somewhat answered the wrong question. The OP is interested in testing Perl 6 modules with Perl 6. That said, using expect to launch a second Perl 6 interpreter which uses the module is still the strongest, most strict way to test the application. You don't need to know what type of terminal library the module uses, because expect should be compatible with nearly all of them. You can send text to the STDIN pipe of a subprocess, but that's not as strong as the subprocess (console) communication you can get from expect. I don't know if there's a way to hijack whichever terminal library the module uses and communicate with it directly.
If it's just a plain interface, you could just run the program and collect output. The currently-experimental Testo module has is-run routine. You could use that directly, or if experimental status is bothersome, copy the guts of it into your own helper routine.
Take a look at Sparrow6 Task Check Language - Perl6 based DSL to verify text output. I've done a lot terminal apps testing using it.
I'm at a point in a project where I need to call system commands. I originally started looking at NSTask (as that seems to be the most popular approach) but recently i just came across the system command. It looks like a far easier setup that NSTask. I've seen some questions/answers that say NSTask is the better approach, but I don't see
What are the advantages/disadvantages between the two
In what cases would one more likely to be used than the other
Any help/links/thoughts/ideas? (and yes.. i did a google search)
NSTask:
Can run his task in the background. Allows you to send interrupts and kills to the underlying process, and allows you to suspend or resume the underlying process without setting up threads yourself. Can also run synchronously if that's what you want.
Let's you work back and forth with Cocoa classes, like NSStrings without having to do a buncha conversions.
Let's you set I/O streams for the underlying process that differ from the caller's.
Better supported across all Apple platforms (like iOS) than system(3) -- I don't think system even works on iOS.
Requires Cocoa and Objective-C.
Doesn't interpret shell arguments or do path expansions of arguments.
system(3):
Better supported across all Unix-like platforms.
Can run a task with a one-liner.
Only requires C.
Runs in a shell and will interpret working directory and arguments like /bin/sh would.
For a Cocoa app I always use NSTask; I only use system if I'm doing something that must be C-only or I know will have to run under non-Mac environments. As it is, system is pretty brittle and the more robust solution is doing a fork-exec, because it allows you more control over streams and concurrent operation.
There are some differences. For some of them it is probably har to say in general, whether it is an advantage or not.
system() starts a shell. NSTask don't.
system() blocks. NSTask run asynchronously.
system() only takes args. NSTask works with pipes.
system() has only an integer exit code. NSTask works with pipes. (Yes, mentioned again. This is for output.)
system() takes a complete command line. To NSTask args can be passed in an array.
system() runs on the current directory. To NSTask you can pass a working directory.
This are some differences out of my mind without rechecking the documentation. It is an overview.
Basically I'm wondering if I can compile code that a user inputs in a mac app (I'm trying to make an OCaml text editor that compiles your code) using executables that are already available in the user's system, such as ocamlc etc. I don't have any code to show or anything because I'm still figuring out if/how I could build this mac app. Not really sure what other info I should include, so just ask. Thanks!
You can use either Sys.command "<your shell command>" or Unix.open_process* and Unix.create_process commands. See man Sys and man Unix for more information.
In Objective-C, C, and C++, and a multitude of other languages, use system(3). Also see:
exec(3)
popen(3)
If you are using Objective-C, check out NSTask.
If not, look at popen. popen gives your parent process control over the I/O streams.
Are there any frameworks for say, putting a display like in Terminal.app in MY app, and then displaying text on it like usual output to STDOUT? Complete with scrollback and etc.?
You may want to look at iTerm, an open-source terminal emulator written in Cocoa. If you really want terminal emulation, you might be able to lift from that framework.
This thread has a couple suggestions. The first is very UNIX'y - you use pipe() to map stdout to a new location. Then you'd need another process or a thread that reads that pipe and displays it into an NSTextView. The other approach that I liked as it seems cleaner and less resource intensive is to replace the File_writer_t _write proc in the stdout() FILE pointer with the hook that you want, which write the output into an NSTextView.
I am a objective-c newbe and am wondering how to run a shell script in objective-c easiest way possible. I don't care about any of the output. I have tried system(), exec() and execl() and an NSTask. Those methods don't work for some reason... This is the shell script I am trying to run:
"mount_webdav http://idisk.mac.com/idisk_username/ /Volumes/idisk_username"
(Basically mounting my iDisk). Also, no password-boxes or any indication of it working shows.
It will work in applescript, and I have created the mount-point directory. None of the methods above do anything at all, or crash the application for some weird reason.
NSTask supplies everything you need. This should work:
NSArray *args=[NSArray arrayWithObjects:#"http://idisk.mac.com/idisk_username/",#"/Volumes/idisk_username",nil];
NSTask *mountTask=[[NSTask alloc] init];
[mountTask setLaunchPath:#"/sbin/mount_webdav"];
[mountTask launch];
Test all the complete command path and args from the command line first. I haven't used mount_webdav but I think it requires more args than you supplied.
Don't use shell scripts when you can help it. They're a good way to introduce serious bugs when you parameterize the script (e.g., mount_webdav %# %#).
Instead, use either NSTask, fork/exec directly, or (in Python) the subprocess module. You'll pass the three arguments as an array, rather than as a single string.
NSTask would be the way to do this in Cocoa. You might want to go over your code again, read up on the documentation for it (also look at the sample code there), and post specific questions about its usage here if you run into problems.