I need to develop an API for users not familiar with scala (neither Java) but familiar with Shell. They will, basically write shell scripts inside a scala class (I know I could just call external shell scripts, but come on! Also, later we will have some functions for common shell tasks).
I was hoping to accomplish something like:
1 object MyCoolScript extends MyMagicTrait {
2 $ "mkdir /tmp/test"
3 $ "cd /tmp/test"
4 $ "wget some-url"
5 }
Being more direct, how can I turn lines 2-4 (or a possibly less concise version) into Seq[String] that I could process in MyMagicTrait?
I know about sys.process.stringToProcess but if I have:
object MyCoolScript extends MyMagicTrait {
"mkdir /tmp/test" !!
"cd /tmp/test" !!
"wget some-url" !!
}
How can I get the result of each command in a concise way? also, I was hoping for a $ "xxx" notation.
Post Answers Update:
Thanks to @debilski, @tenshi and @daniel-c-sobral I was able to come up a very close to the desired implementation: https://gist.github.com/2777994
class Shell {
var elems = Vector[String]()
def >(str: String) = elems :+= str
def run() = elems.map( whatever )
}
val shell = new Shell
shell> "mkdir /tmp/test.dir"
shell> "cd /tmp/test.dir"
Seems that string interpolation that comes with Scala 2.10 can help you here. At first you can implement simple $
method, that simply executes command immediately. In order to make it you need to add this custom method on StringContext
:
object ShellSupport {
implicit class ShellStrings(sc: StringContext) {
def $(args: Any*) =
sc.s(args: _*) split "\n" map (_.trim) filterNot (_.isEmpty) foreach { cmd =>
// your excution logic goes here
println(s"Executing: $cmd")
}
}
}
Now you can use it like this:
import ShellSupport._
val testDir = "/tmp/test"
$"mkdir $testDir"
$"cd $testDir"
$"""
wget some-url
wget another-url
"""
You can take advantage of it's syntax (it's only downside, is that you can't add space between $
and "
) and string interpolation within command.
Now let's try to implement your magic trait. It's generally the same idea, but I'm also using DelayedInit
in order to properly define commands and then automatically execute them during class creation.
trait MyMagicTrait extends DelayedInit {
private var cmds: List[String] = Nil
def commands = cmds
implicit class ShellStrings(sc: StringContext) {
def $(args: Any*) = {
val newCmds = sc.s(args: _*) split "\n" map (_.trim) filterNot (_.isEmpty)
cmds = cmds ++ newCmds
}
}
def delayedInit(x: => Unit) {
// your excution logic goes here
x
cmds map ("Excutintg: " + _) foreach println
}
}
And it's usage:
class MyCoolScript extends MyMagicTrait {
val downloader = "wget"
$"mkdir /tmp/test"
$"cd /tmp/test"
$"""
$downloader some-url
$downloader another-url
"""
}
new MyCoolScript
Both of these solutions produce the same output:
Executing: mkdir /tmp/test
Executing: cd /tmp/test
Executing: wget some-url
Executing: wget another-url
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With