Updates

Changes and improvements to Proc.


Logical Procs, Argument Setters, Value Builders, and UUIDs

May 10, 2021

All new features to expand what's possible in your composed procs.

Logical Procs

Several new procs are introduced for controlling flow through composed procs, including: core.if, core.else, core.unless, and core.when.

Use these new procs to add logical branches to your compositions, supporting more complex workflows. Here's a simple example using core.if and core.else:

core.if(type.number.even) {
  core.echo("even")
} >> core.else {
  core.echo("odd")
}

The composition returns "even" when given an even number, and "odd" otherwise.

Dynamic Arguments

Arguments can now be defined at runtime using core.set. The argument value can be a static value or the result of a partial composition—both resolve to a referenceable value.

Set an argument when you want to refer to a value multiple times in a composed proc. Here's an example that stores a number under a random key in the key-value store:

core.set(
  name: "random_key",
  value: rand.string
)

keyv.set(
  :random_key,
  bucket: "values",
  value: rand.number
)

core.echo(:random_key)

The random key is returned, referenced through the :random_key token.

Value Builders

Certain Procs accept a specific value type as input. It's now possible to build initial values for every built-in type. Builders are available for the following types:

Builders can be called through the respective {type}.build proc, or implicitly through {type}. For example, calling type.string.build and type.string are equivalent.

UUIDs

The new uuid package lets you build and validate RFC 4122 UUIDs, or universally unique identifiers. You can read more about UUIDs and their many uses on Wikipedia.

Other Improvements

  • Base conversion. Adds a new base package for encoding and decoding to and from various bases (limited to Base64 support, but will be expanded over time).

  • More random procs. Three new procs landed in the rand package for generating random values: rand.bytes, rand.hex, and rand.string.

  • Date/Time parsing. Use time.parse to parse date/time strings into a time object.

  • Getting array values. Use type.array.value to get an array value at an index.

  • Splitting strings. Use type.string.split to split a string on a separator.

Forked Composition, Equality, and More

Apr 22, 2021

13 new procs, including 2 that help build better compositions.

Forked Composition

Proc compositions work by passing the result of one proc call as input to the next—this is known as piping. Here's a simple composition to illustrate how piping works in practice:

core.echo("hello")
| type.string.upcase
| type.string.reverse

Calling this composition returns "OLLEH" as the result.

In large compositions this can get unwieldy. This release includes a new core.pipe proc that lets you use the same piping semantics while breaking large compositions into more organized parts. For example, the result of the composition above might need to be stored in the key-value store:

core.echo("hello")
| type.string.upcase
| type.string.reverse
| keyv.set(bucket: "some-bucket", key: "some-key")

It might be more readable to separate the string manipulation logic from the interation with the key-value store. This is now possible with core.pipe:

core.echo("hello")
| core.pipe {
    type.string.upcase
    | type.string.reverse
  }
| keyv.set(bucket: "some-bucket", key: "some-key")

Similarly, it's sometimes desired to perform some work without modifying the input to the next proc call. The new core.fork proc can be used to create a completely isolated fork within a composition:

core.echo("hello")
| core.fork {
    keyv.transform(bucket: "some-bucket", key: "call-count", set: 0) {
      math.add(value: 1)
    }
  }
| type.string.upcase

When called, the key-value store counter is incremented in an isolated fork before passing the original input to type.string.upcase. The result of composition is "HELLO". If we were to use core.pipe instead of core.fork, the return value of keyv.transform would replace the original input of "hello".

Equality Checks

All built-in types now include a proc for checking equality, including:

Every equal proc returns true if the value matches the input, or false otherwise:

type.number.equal(1, value: 2)

Other Improvements

  • Even number check. Adds a new type.number.even proc that returns true or false if a given number is even or odd respectively.

  • Break strings into characters. Adds a new type.string.characters proc that breaks a given string into a character array.

  • Remove characters from a string. Adds a new type.string.chomp proc that removes characters from the start or end of a string.

  • Downcase a string. Adds a new type.string.downcase proc that downcases every character in a string to be lowercase.

  • Check if a string is empty. Adds a new type.string.empty proc that returns true if a given string only contains whitespace.

  • Get a string's length. Adds a new type.string.length proc that returns the length of a given string as an integer.

  • Swap the casing of a string. Adds a new type.string.swapcase proc that swaps the casing of a given string.