fop_lang
Fop (Filter and OPerations language) is a tiny, experimental language for filtering and operating on text. Think of it like awk but with the condition and action segments combined.
This is a Ruby implementation with both a library interface and a bin command.
Installation
$ gem install fop_lang
You may use fop in a Ruby script:
require 'fop_lang'
f = Fop('foo {N+1}')
f.apply('foo 1')
=> "foo 2"
f.apply('bar 1')
=> nil
or run fop from the command line:
$ echo 'foo 1' | fop 'foo {N+1}'
foo 2
$ echo 'bar 1' | fop 'foo {N+1}'
Syntax
Text /(R|r)egex/ {N+1}
The above program demonstrates a text match, a regex match, and a match expression. If the input matches all three segments, output is given. If the input was Text regex 5, the output would be Text regex 6.
Text match
Text and ` ` in the above example.
The input must match this text exactly. Whitespace is part of the match. Wildcards (*) are allowed. Special characters (*/{}\) may be escaped with \.
The output of a text match will be the matching input.
Regex match
/(R|r)egex/ in the above example.
Regular expressions may be placed between /s. If the regular expression contains a /, you may escape it with \. Special regex characters like []()+.* may also be escaped with \.
The output of a regex match will be the matching input.
Match expression
{N+1} in the above example.
A match expression both matches on input and modifies that input. An expression is made up of 1 - 3 parts:
- The match, e.g.
Nfor numeric. - The operator, e.g.
+for addition (optional). - The argument, e.g
1for “add one” (required for most operators).
The output of a match expression will be the modified matching input. If no operator is given, the output will be the matching input.
Matches
Nmatches one or more consecutive digits.Amatches one or more letters (lower or upper case).Wmatches alphanumeric chars and underscores.*greedily matches everything after it./regex/matches on the supplied regex. Capture groups may be referenced in the argument as$1,$2, etc.
Operators
=Replace the matching character(s) with the given argument. If no argument is given, drop the matching chars.>Append the argument to the matching value.<Prepend the argument to the matching value.+Perform addition on the matching number and the argument.-Subtract the argument from the matching number.
Whitespace
Inside of match expressions, whitespace is an optional seperator of terms, i.e. { N + 1 } is the same as {N+1}. This means that any spaces in string arguments must be escaped. For example, replacing a word with foo bar looks like {W = foo\ bar}.
Examples
Release Number Example
This example takes in GitHub branch names, decides if they’re release branches, and if so, increments the version number.
f = Fop('release-{N}.{N+1}.{N=0}')
puts f.apply('release-5.99.1')
=> 'release-5.100.0'
puts f.apply('release-5')
=> nil
# doesn't match the pattern
More Examples
f = Fop('release-{N=5}.{N+1}.{N=0}')
puts f.apply('release-4.99.1')
=> 'release-5.100.0'
f = Fop('rel{/(ease)?/=}-{N=5}.{N+1}.{N=0}')
puts f.apply('release-4.99.1')
=> 'rel-5.100.0'
puts f.apply('rel-4.99.1')
=> 'rel-5.100.0'
f = Fop('release-*{N=5}.{N+100}.{N=0}')
puts f.apply('release-foo-4.100.1')
=> 'release-foo-5.200.0'
f = Fop('release-{N=5}.{N+1}.{N=0}{*=}')
puts f.apply('release-4.100.1.foo.bar')
=> 'release-5.101.0'
f = Fop('{W=version}-{N=5}.{N+1}.{N=0}')
puts f.apply('release-4.100.1')
=> 'version-5.101.0'