Releases: abs-lang/abs
v2.2.1
v2.2.0
A fresh new minor release of ABS: always be shipping! 🚢
Interactive REPL through the @cli module
The @cli.repl()
mode allows to run interactive REPLs based on the commands registered within the CLI:
cli = require('@cli')
res = {"count": 0}
@cli.cmd("count", "prints a counter", {})
f counter(arguments, flags) {
echo(res.count)
}
@cli.cmd("incr", "Increment our counter", {})
f incr(arguments, flags) {
res.count += 1
return "ok"
}
@cli.cmd("incr_by", "Increment our counter", {})
f incr_by(arguments, flags) {
echo("Increment by how much?")
n = stdin().number()
res.count += n
return "ok"
}
cli.repl()
You can see it in action:
$ ./cli
help
Available commands:
* count - prints a counter
* help - print this help message
* incr - Increment our counter
* incr_by - Increment our counter
count
0
incr
ok
incr
ok
count
2
incr_by
Increment by how much?
-10
ok
count
-8
Memoizing through @util.memoize
A new @util
native module was introduced to allow memoization of functions:
memo = require('@util').memoize
@memo(60)
f long_task(x, y) {
sleep(1000)
return "done"
}
echo(long_task(1, 1)) # waits 1s
echo(long_task(1, 1)) # immediate
echo(long_task(1, 1)) # immediate
sleep(61000) # sleep for a min...
echo(long_task(1, 1)) # waits 1s
echo(long_task(1, 2)) # waits 1s
New function: unix_ms
unix_ms()
returns the current Unix epoch, in milliseconds.
unix_ms() # 1594049453157
See ya! 👋
v2.1.0
A fresh new minor release of ABS: always be shipping! 🚢
Optional function parameters
You can now make a parameter optional by specifying its
default value:
f greet(name, greeting = "hello") {
echo("$greeting $name!")
}
greet("user") # hello user!
greet("user", "hola") # hola user!
A default value can be any expression (doesn't have to be a literal):
f test(x = 1){x}; test() # 1
f test(x = "test".split("")){x}; test() # ["t", "e", "s", "t"]
f test(x = {}){x}; test() # {}
y = 100; f test(x = y){x}; test() # 100
x = 100; f test(x = x){x}; test() # 100
x = 100; f test(x = x){x}; test(1) # 1
Note that mandatory arguments always need to be declared
before optional ones:
f(x = null, y){}
# parser errors:
# found mandatory parameter after optional one
# [1:13] f(x = null, y){}
Descending number ranges
Number ranges (x..y
) now support generating ranges in descending order:
3..1 # [3, 2, 1]
See ya! 👋
v2.0.0
A fresh new major release of ABS: always be shipping! 🚢
This release was originally intended to be out as 1.13.0
, but a backward-incompatible change forced us to shift gears. Don't fear the upgrade as the incompatible changes are extremely easy to address -- and there's only 3 of them.
Let's get rollin'!
Introducing the ABS standard library
🚀 🚀 🚀 this is a big one! 🚀 🚀 🚀
We've started to integrate a standard library within ABS, with modules such as runtime
and cli
to help you build apps with ease. Requiring a module from the standard library is extremely simple:
runtime = require('@runtime')
runtime.version # 2.0.0
Standard modules are required through the @
prefix. To learn more about ABS's standard library visit the documentation.
Building CLI applications with the @cli module
As part of the initial rollout of the standard library, we've included a @cli
module that helps you building CLI applications. It has a simple API that takes advantage of decorators:
#!/usr/bin/env abs
cli = require('@cli')
@cli.cmd("ip", "finds our IP address", {})
f ip_address(arguments, flags) {
return `curl icanhazip.com`
}
@cli.cmd("date", "Is it Friday already?", {"format": ""})
f date(arguments, flags) {
format = flags.format
return `date ${format}`
}
cli.run()
You can save this script as cli
and make it executable with chmod +x ./cli
. Then you will be able to use the CLI app:
$ ./cli
Available commands:
* date - Is it Friday already?
* help - print this help message
* ip - finds our IP address
$ ./cli help
Available commands:
* date - Is it Friday already?
* help - print this help message
* ip - finds our IP address
$ ./cli ip
87.201.252.69
$ ./cli date
Sat Apr 4 18:06:35 +04 2020
$ ./cli date --format +%s
1586009212
Fresh new decorators
Decorators have gone through a major revamp and are now 100% compatible with Python's ones, which we find extremely powerful:
f uppercase(fn) {
return f() {
return fn(...).upper()
}
}
@uppercase
f stringer(x) {
return x.str()
}
stringer({}) # "{}"
stringer(12) # "12"
stringer("hello") # "HELLO"
The revamp was needed in order to allow any kind of expression to be used as a decorator, and not just plain functions -- for example:
@decorator
@decorator()
@module.decorator()
Deprecated functions
We have removed the functions slice
and contains
, which were available on both arrays and strings. They have been deprecated for a while and can be easily replaced by the index notation ([1, 2, 3].slice(0, 1)
is equivalent to [1, 2, 3][:1]
) and the in
operator ([1, 2, 3].includes(1)
is equivalent to 1 in [1, 2, 3]
).
Upgrade guide to ABS 2
We've recapped these 3 backwards-incompatible changes in a simple upgrade guide.
Misc
- fixed a panic when converting index ranges to strings (#364)
See ya! 👋
v1.12.1
v1.12.0
A new minor release of ABS: always be shipping! 🚢
Function bonanza!
We've been adding a plethora of functions in this release -- check'em out!
array.chunk(size)
Splits the array into chunks of the given size:
[1, 2, 3].chunk(2) # [[1, 2], [3]]
[1, 2, 3].chunk(10) # [[1,2,3]]
[1, 2, 3].chunk(1.2) # argument to chunk must be a positive integer, got '1.2'
array.intersect(other_array)
Computes the intersection between 2 arrays:
[1, 2, 3].intersect([]) # []
[1, 2, 3].intersect([3]) # [3]
[1, 2, 3].intersect([3, 1]) # [1, 3]
[1, 2, 3].intersect([1, 2, 3, 4]) # [1, 2, 3]
array.diff(other_array)
Computes the difference between 2 arrays,
returning elements that are only on the first array:
[1, 2, 3].diff([]) # [1, 2, 3]
[1, 2, 3].diff([3]) # [1, 2]
[1, 2, 3].diff([3, 1]) # [2]
[1, 2, 3].diff([1, 2, 3, 4]) # []
For symmetric difference see diff_symmetric(...)
array.diff_symmetric(other_array)
Computes the symmetric difference
between 2 arrays (elements that are only on either of the 2):
[1, 2, 3].diff([]) # [1, 2, 3]
[1, 2, 3].diff([3]) # [1, 2]
[1, 2, 3].diff([3, 1]) # [2]
[1, 2, 3].diff([1, 2, 3, 4]) # [4]
array.union(other_array)
Computes the union
between 2 arrays:
[1, 2, 3].union([1, 2, 3, 4]) # [1, 2, 3, 4]
[1, 2, 3].union([3]) # [1, 2, 3]
[].union([3, 1]) # [3, 1]
[1, 2].union([3, 4]) # [1, 2, 3, 4]
array.flatten()
Flattens an array a single level deep:
[[1, 2], 3, [4]].flatten([1, 2, 3, 4]) # [1, 2, 3, 4]
[[1, 2, 3, 4]].flatten([1, 2, 3, 4]) # [1, 2, 3, 4]
array.flatten_deep()
Flattens an array recursively until no member is an array:
[[[1, 2], [[[[3]]]], [4]]].flatten_deep() # [1, 2, 3, 4]
[[1, [2, 3], 4]].flatten_deep() # [1, 2, 3, 4]
array.max()
Finds the highest number in an array:
[].max() # NULL
[0, 5, -10, 100].max() # 100
array.min()
Finds the lowest number in an array:
[].min() # NULL
[0, 5, -10, 100].min() # -10
array.reduce(fn, accumulator)
Reduces the array to a value by iterating through its elements and applying fn
to them:
[1, 2, 3, 4].reduce(f(value, element) { return value + element }, 0) # 10
[1, 2, 3, 4].reduce(f(value, element) { return value + element }, 10) # 20
array.partition(fn)
Partitions the array by applying fn
to all of its elements
and using the result of the function invocation as the key to partition by:
f odd(n) {
return !!(n % 2)
}
[0, 1, 2, 3, 4, 5].partition(odd) # [[0, 2, 4], [1, 3, 5]]
[1, "1", {}].partition(str) # [[1, "1"], [{}]]
number.between(min, max)
Checks whether the number is between min
and max
:
10.between(0, 100) # true
10.between(10, 100) # true
10.between(11, 100) # false
number.clamp(min, max)
Clamps the number between min and max:
10.clamp(0, 100) # 10
10.clamp(0, 5) # 5
10.clamp(50, 100) # 50
1.5.clamp(2.5, 3) # 2.5
string.camel()
Converts the string to camelCase:
"a short sentence".camel() # aShortSentence
string.snake()
Converts the string to snake_case:
"a short sentence".snake() # a_short_sentence
string.kebab()
Converts the string to kebab-case:
"a short sentence".snake() # a-short-sentence
Shorthand syntax for array.find(...)
A shorthand syntax supports passing a hash and comparing
elements to the given hash:
[null, {"key": "val", "test": 123}].find({"key": "val"}) # {"key": "val", "test": 123}
Misc
v1.11.4
v1.11.3
v1.11.2
This is a patch release that upgrades ABS to be built through Go 1.14. Ther are no changes to the language besides the improvements brought by this new release of Go.
v1.11.1
This is a bugfix release that fixes a regression introduced in 1.10.1
: early returns from within for
and for in
loops were enabled for all return values, not just explicit ones.
An explicit return is defined as using the return
keyword:
for x in 1..10 {
return x
}
but the early return feature was enabled also for implicit returns:
for x in 1..10 {
x <-- this loop only runs one, and return the first value of x
}
which would make code such as this fail:
list = []
for x in 1..10 {
list.push(x) <-- this will be considered an implicit return, and only run once
}
This was fixed with #325.
Please note that the 1.10.x
branch will not see a backport of this fix.