1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

test: add examples for function package

This commit is contained in:
dudaodong
2023-01-06 16:12:44 +08:00
parent e21dd07d46
commit be444f521d
4 changed files with 212 additions and 66 deletions

View File

@@ -5,11 +5,13 @@
package function package function
import ( import (
"fmt"
"reflect" "reflect"
"time" "time"
) )
// After creates a function that invokes func once it's called n or more times // After creates a function that invokes func once it's called n or more times.
// Play: https://go.dev/play/p/8mQhkFmsgqs
func After(n int, fn any) func(args ...any) []reflect.Value { func After(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure // Catch programming error while constructing the closure
mustBeFunction(fn) mustBeFunction(fn)
@@ -23,7 +25,8 @@ func After(n int, fn any) func(args ...any) []reflect.Value {
} }
} }
// Before creates a function that invokes func once it's called less than n times // Before creates a function that invokes func once it's called less than n times.
// Play: https://go.dev/play/p/0HqUDIFZ3IL
func Before(n int, fn any) func(args ...any) []reflect.Value { func Before(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure // Catch programming error while constructing the closure
mustBeFunction(fn) mustBeFunction(fn)
@@ -40,41 +43,48 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
} }
} }
// Fn is for curry function which is func(...any) any // CurryFn is for make curry function
type Fn func(...any) any type CurryFn[T any] func(...T) T
// Curry make a curry function // New make a curry function for specific value.
func (f Fn) Curry(i any) func(...any) any { // Play: Todo
return func(values ...any) any { func (cf CurryFn[T]) New(val T) func(...T) T {
v := append([]any{i}, values...) return func(vals ...T) T {
return f(v...) args := append([]T{val}, vals...)
return cf(args...)
} }
} }
// Compose compose the functions from right to left // Compose compose the functions from right to left.
func Compose(fnList ...func(...any) any) func(...any) any { // Play: Todo
return func(s ...any) any { func Compose[T any](fnList ...func(...T) T) func(...T) T {
f := fnList[0] return func(args ...T) T {
restFn := fnList[1:] firstFn := fnList[0]
restFns := fnList[1:]
if len(fnList) == 1 { if len(fnList) == 1 {
return f(s...) return firstFn(args...)
} }
return f(Compose(restFn...)(s...)) fn := Compose(restFns...)
arg := fn(args...)
return firstFn(arg)
} }
} }
// Delay make the function execution after delayed time // Delay make the function execution after delayed time.
// Play: https://go.dev/play/p/Ivtc2ZE-Tye
func Delay(delay time.Duration, fn any, args ...any) { func Delay(delay time.Duration, fn any, args ...any) {
// Catch programming error while constructing the closure // Catch programming error while constructing the closure
mustBeFunction(fn) mustBeFunction(fn)
time.Sleep(delay) time.Sleep(delay)
invokeFunc(fn, args...) unsafeInvokeFunc(fn, args...)
} }
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked. // Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked..
// Play: https://go.dev/play/p/absuEGB_GN7
func Debounced(fn func(), duration time.Duration) func() { func Debounced(fn func(), duration time.Duration) func() {
// Catch programming error while constructing the closure // Catch programming error while constructing the closure
mustBeFunction(fn) mustBeFunction(fn)
@@ -92,7 +102,8 @@ func Debounced(fn func(), duration time.Duration) func() {
return func() { timer.Reset(duration) } return func() { timer.Reset(duration) }
} }
// Schedule invoke function every duration time, util close the returned bool chan // Schedule invoke function every duration time, util close the returned bool channel.
// Play: https://go.dev/play/p/hbON-Xeyn5N
func Schedule(d time.Duration, fn any, args ...any) chan bool { func Schedule(d time.Duration, fn any, args ...any) chan bool {
// Catch programming error while constructing the closure // Catch programming error while constructing the closure
mustBeFunction(fn) mustBeFunction(fn)
@@ -114,6 +125,7 @@ func Schedule(d time.Duration, fn any, args ...any) chan bool {
// Pipeline takes a list of functions and returns a function whose param will be passed into // Pipeline takes a list of functions and returns a function whose param will be passed into
// the functions one by one. // the functions one by one.
// Play: https://go.dev/play/p/mPdUVvj6HD6
func Pipeline[T any](funcs ...func(T) T) func(T) T { func Pipeline[T any](funcs ...func(T) T) func(T) T {
return func(arg T) (result T) { return func(arg T) (result T) {
result = arg result = arg
@@ -123,3 +135,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
return return
} }
} }
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
fv := reflect.ValueOf(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func functionValue(function any) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}
func mustBeFunction(function any) {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
}

View File

@@ -0,0 +1,147 @@
package function
import (
"fmt"
"strings"
"time"
)
func ExampleAfter() {
fn := After(2, func() {
fmt.Println("test")
})
fn()
fn()
// Output:
// test
}
func ExampleBefore() {
fn := Before(2, func() {
fmt.Println("test")
})
fn()
fn()
fn()
fn()
// Output:
// test
// test
}
func ExampleCurryFn_New() {
add := func(a, b int) int {
return a + b
}
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result)
// Output:
// 3
}
func ExampleCompose() {
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
result := transform("aBCde")
fmt.Println(result)
// Output:
// ABCDE
}
func ExampleDelay() {
var print = func(s string) {
fmt.Println(s)
}
Delay(2*time.Second, print, "hello")
// Output:
// hello
}
func ExampleDebounced() {
count := 0
add := func() {
count++
}
debouncedAdd := Debounced(add, 50*time.Microsecond)
debouncedAdd()
debouncedAdd()
debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
// Output:
// 1
// 2
}
func ExampleSchedule() {
var result []string
appendFn := func(s string) {
result = append(result, s)
}
stop := Schedule(1*time.Second, appendFn, "*")
time.Sleep(3 * time.Second)
close(stop)
fmt.Println(result)
// Output:
// [* * *]
}
func ExamplePipeline() {
addOne := func(x int) int {
return x + 1
}
double := func(x int) int {
return 2 * x
}
square := func(x int) int {
return x * x
}
fn := Pipeline(addOne, double, square)
result := fn(2)
fmt.Println(result)
// Output:
// 36
}

View File

@@ -1,39 +0,0 @@
package function
import (
"fmt"
"reflect"
)
func invokeFunc(fn any, args ...any) []reflect.Value {
fv := functionValue(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
fv := reflect.ValueOf(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func functionValue(function any) reflect.Value {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
return v
}
func mustBeFunction(function any) {
v := reflect.ValueOf(function)
if v.Kind() != reflect.Func {
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
}
}

View File

@@ -62,24 +62,26 @@ func TestCurry(t *testing.T) {
add := func(a, b int) int { add := func(a, b int) int {
return a + b return a + b
} }
var addCurry Fn = func(values ...any) any { var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0].(int), values[1].(int)) return add(values[0], values[1])
} }
add1 := addCurry.Curry(1) add1 := addCurry.New(1)
assert.Equal(3, add1(2)) assert.Equal(3, add1(2))
} }
func TestCompose(t *testing.T) { func TestCompose(t *testing.T) {
assert := internal.NewAssert(t, "TestCompose") assert := internal.NewAssert(t, "TestCompose")
toUpper := func(a ...any) any { toUpper := func(strs ...string) string {
return strings.ToUpper(a[0].(string)) return strings.ToUpper(strs[0])
} }
toLower := func(a ...any) any { toLower := func(strs ...string) string {
return strings.ToLower(a[0].(string)) return strings.ToLower(strs[0])
} }
expected := toUpper(toLower("aBCde")) expected := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower) cf := Compose(toUpper, toLower)
res := cf("aBCde") res := cf("aBCde")