UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Write your scripts in Swift with Beak

It’s a smart and simple way to run code by function.

Paul Hudson       @twostraws

If you’re visiting here it’s because you’re already sold on Swift as a great language for apps, but have you ever considered using it for scripting? If not, a new GitHub project from Yonas Kolb is here to convince you otherwise: it’s called Beak and it lets your run Swift code straight from the command line.

To get started, run these three commands from your Mac’s terminal:

git clone https://github.com/yonaskolb/Beak.git
cd Beak
swift run beak run install

That builds and installs Beak, which means it’s ready to run any Swift scripts you need.

Let’s try it out now. Create a new Swift file on your desktop called factors.swift and give it this content:

import Foundation

public func calculate() {
    let number = 100
    let factors = (1...number).filter { number % $0 == 0 }
    print(factors.reduce("Factors: ") { $0 + String($1) + " " })
}

That creates a single function called calculate(), which creates an array of numbers that divide equally into 100, then prints them out as a single string.

To run that using Beak you need to write a command that does the following:

  • Specifies factors.swift as its input filename.
  • Tells it to run a single function from the file.
  • Provides the function name to run.

Run this command now:

beak --path factors.swift run calculate

You specify the function name you want to run, so a single Swift script can contain as many related functions as you want.

As well as run you can also use list to show the list of available functions:

beak --path factors.swift list

That will show you there’s only function available, which is our calculate() function.

Tip: Beak can only see functions that are marked as public. If you want a function for internal use only – i.e., not exposed by the list command – just don’t declare it as public.

Right now our function uses a hard-coded input value, but Beak can process arguments from the command-line and convert them into function arguments.

Try changing the function to this:

public func calculate(number: Int) {
    let factors = (1...number).filter { number % $0 == 0 }
    print(factors.reduce("Factors: ") { $0 + String($1) + " " })
}

When using the calculate() method now, you need to run it like this:

beak --path factors.swift run calculate --number 1000

Now that we have a command that takes input, you might want to try using the “function” option for Beak, which provides more details on a specific function. For example:

beak --path factors.swift function calculate

That will say calculate() takes one argument called number, which is an Int. However, if you want more useful output you should add some Markdown comments to your code, like this:

/// Calculates the factors for a given number
/// - Parameters:
///   - number: the input number to use
public func calculate(number: Int) {
    let factors = (1...number).filter { number % $0 == 0 }
    print(factors.reduce("Factors: ") { $0 + String($1) + " " })
}

These comments are exactly the same format used by Xcode and other Swift tools, so you should already be familiar with them – if not, now would be a good time to investigate my Pro Swift book! If you run Beak’s “function” command now you’ll get much more useful help.

At this point I hope you’re certainly curious to try Swift scripting yourself, but before we’re done I want to demonstrate one last, important feature: cleaning up the commands.

So far we’ve been using commands like this one:

beak --path factors.swift run calculate --number 1000

While it’s certainly nice and clear, it’s also supremely clumsy. Fortunately Beak supports shebang lines, which means you can add a special line to the start of your Swift scripts that allows you to make your scripts into standalone commands.

Modify factors.swift to this:

#!/usr/bin/env beak run --path
import Foundation

/// Calculates the factors for a given number
/// - Parameters:
///   - number: the input number to use
public func calculate(number: Int) {
    let factors = (1...number).filter { number % $0 == 0 }
    print(factors.reduce("Factors: ") { $0 + String($1) + " " })
}

That first line is the shebang line: it tells Unix systems that the rest of this file should be passed to Beak as its input.

Now run this command from your terminal:

chmod a+x factors.swift

That marks factors.swift as being executable (X) for all (A) users. You can now run this instead:

./factors.swift calculate --number 100 

That’s slightly better, but now try running this command:

mv factors.swift /usr/local/bin/factors

That moves factors.swift to the directory containing your local commands, while also renaming it just to “factors”.

Now your command becomes this:

factors calculate --number 100

To make it even shorter (because why not?), you can mark the parameter as unnamed like this:

public func calculate(_ number: Int) {

(Note: make sure you edit /usr/local/bin/factors!)

Because the parameter is unnamed, you no longer need to specify --number on the command line. So, your command becomes just this:

factors calculate 100

I think you’ll agree that’s much easier to remember!

So, go and give Beak a try. Swift is slowly evolving into a full-stack language (Server-Side Swift, anyone?), and Beak is just one more great step in that direction.

Link: Beak

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.