diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..919ce1f --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..639900d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..25be34f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dsl.go b/dsl.go new file mode 100644 index 0000000..dec4929 --- /dev/null +++ b/dsl.go @@ -0,0 +1,41 @@ +package hy_go_function + +type operation string + +const ( + filter = operation("filter") + maps = operation("map") + flatMap = operation("flatmap") +) + +type DSL struct { + function []interface{} + value interface{} + operations []operation +} + +func Of(value interface{}) DSL { + return DSL{ + value: value, + } +} + +func (d DSL) Filter(predicate interface{}) DSL { + d.operations = append(d.operations, filter) + d.function = append(d.function, predicate) + return d +} + +func (d DSL) FlatMap(function interface{}) DSL { + d.operations = append(d.operations, flatMap) + d.function = append(d.function, function) + return d +} + +func (d DSL) Map(function interface{}) DSL { + d.operations = append(d.operations, maps) + d.function = append(d.function, function) + return d +} + + diff --git a/dsl_test.go b/dsl_test.go new file mode 100644 index 0000000..a7dc676 --- /dev/null +++ b/dsl_test.go @@ -0,0 +1,113 @@ +package hy_go_function + +import ( + "fmt" + "hy-go-function/internal" + "strconv" + "testing" +) + +func Test_Stream(t *testing.T) { + array := []string{ + "1", "2", "3", + } + result := Of(array).Map(func(i string) int { + atoi, err := strconv.Atoi(i) + if err != nil { + return 0 + } + return atoi + }).Filter(func(i int) bool { + if i == 1 { + return false + } + return true + }).Map(func(i int) int { + return i + 5 + }).Execute() + + println(fmt.Sprintf("result : %v", result)) +} + +func Test_filterEmpty(t *testing.T) { + array := []string{ + } + result := internal.DoFilter(array, func(i string) bool { + if i == "1" { + return false + } + return true + }) + + println(fmt.Sprintf("result : %v", result)) +} + +func Test_filter(t *testing.T) { + array := []string{ + "1", "2", "3", + } + result := internal.DoFilter(array, func(i string) bool { + if i == "1" { + return false + } + return true + }) + + println(fmt.Sprintf("result : %v", result)) + + result2 := internal.DoFilter(1, func(i int) bool { + if i != 1 { + return false + } + return true + }) + + println(fmt.Sprintf("result : %v", result2)) +} + +func Test_mapEmpty(t *testing.T) { + array := []string{ + } + result := internal.DoMap(array, func(i string) int { + if i == "1" { + return 1 + } + return 2 + }) + + println(fmt.Sprintf("result : %v", result)) +} + +func Test_map(t *testing.T) { + array := []string{ + "1", "2", "3", + } + result := internal.DoMap(array, func(i string) int { + if i == "1" { + return 1 + } + return 2 + }) + + println(fmt.Sprintf("result : %v", result)) + + result2 := internal.DoMap(1, func(i int) int { return i + 1}) + + println(fmt.Sprintf("result2 : %v", result2)) +} +func Test_flatmap(t *testing.T) { + array := [][]string{ + {"1", "2", "3"}, + {"1", "2", "3"}, + } + result := internal.DoFlatMap(array, func(i []string) []string { + return i + }) + + println(fmt.Sprintf("result : %v", result)) + + result2 := internal.DoMap(1, func(i int) int { return i + 1}) + + println(fmt.Sprintf("result2 : %v", result2)) +} + diff --git a/execute.go b/execute.go new file mode 100644 index 0000000..1dd307b --- /dev/null +++ b/execute.go @@ -0,0 +1,21 @@ +package hy_go_function + +import "hy-go-function/internal" + +func (d DSL) Execute() interface{} { + for i, operation := range d.operations { + if d.value == nil { + return nil + } + + switch operation { + case filter: + d.value = internal.DoFilter(d.value, d.function[i]) + case maps: + d.value = internal.DoMap(d.value, d.function[i]) + case flatMap: + d.value = internal.DoFlatMap(d.value, d.function[i]) + } + } + return d.value +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2060b19 --- /dev/null +++ b/go.mod @@ -0,0 +1 @@ +module "hy-go-function" \ No newline at end of file diff --git a/hy-go-function.iml b/hy-go-function.iml new file mode 100644 index 0000000..eacc75a --- /dev/null +++ b/hy-go-function.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/internal/do_filter.go b/internal/do_filter.go new file mode 100644 index 0000000..f4b7b9e --- /dev/null +++ b/internal/do_filter.go @@ -0,0 +1,37 @@ +package internal + +import "reflect" + +func DoFilter(array interface{}, predicate interface{}) interface{} { + funcValue := reflect.ValueOf(predicate) + funcType := funcValue.Type() + + if funcType.Out(0).Kind() != reflect.Bool { + panic("type not boolean") + } + + inValue := reflect.ValueOf(array) + inType := inValue.Type() + + if inType.Kind() != reflect.Slice && inType.Kind() != reflect.Array { + result := funcValue.Call([]reflect.Value{inValue})[0].Interface().(bool) + if result { + return inValue + } else { + return nil + } + } + + resultSliceType := reflect.SliceOf(inType.Elem()) + resultSlice := reflect.MakeSlice(resultSliceType, 0, 0) + + for i := 0; i < inValue.Len(); i++ { + elem := inValue.Index(i) + result := funcValue.Call([]reflect.Value{elem})[0].Interface().(bool) + if result { + resultSlice = reflect.Append(resultSlice, elem) + } + } + + return resultSlice.Interface() +} diff --git a/internal/do_flatmap.go b/internal/do_flatmap.go new file mode 100644 index 0000000..e04cbbd --- /dev/null +++ b/internal/do_flatmap.go @@ -0,0 +1,31 @@ +package internal + +import ( + "reflect" +) + +func DoFlatMap(input interface{}, function interface{}) interface{} { + funcValue := reflect.ValueOf(function) + funcType := funcValue.Type() + + inValue := reflect.ValueOf(input) + inType := inValue.Type() + if inType.Kind() != reflect.Slice && inType.Kind() != reflect.Array { + result := funcValue.Call([]reflect.Value{inValue})[0] + return result.Interface() + } + + resultSliceType := reflect.SliceOf(funcType.Out(0).Elem()) + resultSlice := reflect.MakeSlice(resultSliceType, 0, 0) + for i := 0; i < inValue.Len(); i++ { + elem := inValue.Index(i) + result := funcValue.Call([]reflect.Value{elem})[0] + for j := 0; j < result.Len(); j++ { + e := result.Index(j) + resultSlice = reflect.Append(resultSlice, e) + } + } + + return resultSlice.Interface() +} + diff --git a/internal/do_map.go b/internal/do_map.go new file mode 100644 index 0000000..433176c --- /dev/null +++ b/internal/do_map.go @@ -0,0 +1,25 @@ +package internal + +import "reflect" + +func DoMap(input interface{}, function interface{}) interface{} { + funcValue := reflect.ValueOf(function) + funcType := funcValue.Type() + + inValue := reflect.ValueOf(input) + inType := inValue.Type() + if inType.Kind() != reflect.Slice && inType.Kind() != reflect.Array { + result := funcValue.Call([]reflect.Value{inValue})[0] + return result.Interface() + } + + resultSliceType := reflect.SliceOf(funcType.Out(0)) + resultSlice := reflect.MakeSlice(resultSliceType, 0, 0) + for i := 0; i < inValue.Len(); i++ { + elem := inValue.Index(i) + result := funcValue.Call([]reflect.Value{elem})[0] + resultSlice = reflect.Append(resultSlice, result) + } + + return resultSlice.Interface() +}