Skip to content

Commit 88e22b3

Browse files
authored
Merge pull request #1 from devalexandre/feature/add-milt-args
Feature/add milt args
2 parents bd659b4 + 8472eb8 commit 88e22b3

4 files changed

Lines changed: 191 additions & 93 deletions

File tree

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
module github.com/devalexandre/pipe
22

33
go 1.20
4+
5+
require github.com/devalexandre/gofn v1.0.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/devalexandre/gofn v1.0.1 h1:+pM0fEU5E4ebYt7ReR3FgQMjyESsHNvROJWU1kLa6lg=
2+
github.com/devalexandre/gofn v1.0.1/go.mod h1:fQLcy6EQZaySBvbJAoxcyjKCHHby01Cm24+IHbJU+qY=

v1/pipe.go

Lines changed: 39 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,55 @@ package v1
22

33
import (
44
"errors"
5-
"fmt"
65
"reflect"
7-
"runtime"
86
)
97

10-
type Pipeline func(args ...interface{}) (interface{}, error)
8+
// Pipeline type.
9+
type Pipeline func(...interface{}) (interface{}, error)
1110

11+
// Pipe creates a pipeline from a series of functions.
1212
func Pipe(fs ...interface{}) Pipeline {
13-
return func(args ...interface{}) (interface{}, error) {
14-
var result interface{}
15-
var err error
16-
17-
inputs := make([]reflect.Value, len(args))
18-
for i, arg := range args {
19-
inputs[i] = reflect.ValueOf(arg)
20-
}
21-
22-
for i, f := range fs {
23-
funcValue := reflect.ValueOf(f)
24-
funcType := funcValue.Type()
25-
26-
if len(inputs) != funcType.NumIn() {
27-
funcName := runtime.FuncForPC(funcValue.Pointer()).Name()
28-
return nil, fmt.Errorf("número incorreto de argumentos para a função: %s", funcName)
29-
}
30-
31-
outputs := funcValue.Call(inputs)
32-
33-
if len(outputs) > 0 {
34-
lastOutput := outputs[len(outputs)-1]
35-
if lastOutput.Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) && !lastOutput.IsNil() {
36-
return nil, lastOutput.Interface().(error)
37-
}
38-
if i == len(fs)-1 && len(outputs) > 0 {
39-
result = outputs[0].Interface()
13+
return func(initialArgs ...interface{}) (interface{}, error) {
14+
var currentArgs []interface{} = initialArgs
15+
for _, f := range fs {
16+
fnVal := reflect.ValueOf(f)
17+
fnType := fnVal.Type()
18+
numIn := fnType.NumIn()
19+
20+
// Prepare the input arguments for the current function.
21+
in := make([]reflect.Value, numIn)
22+
for i := 0; i < numIn; i++ {
23+
if i < len(currentArgs) {
24+
in[i] = reflect.ValueOf(currentArgs[i])
25+
} else if i < len(initialArgs) { // Allow passing manual arguments if not enough currentArgs.
26+
in[i] = reflect.ValueOf(initialArgs[i])
27+
} else {
28+
// If there are not enough arguments to pass to the function, return an error.
29+
return nil, errors.New("not enough arguments to pass to function")
4030
}
4131
}
4232

43-
if len(outputs) > 1 {
44-
inputs = outputs[:len(outputs)-1]
45-
} else {
46-
inputs = []reflect.Value{}
33+
// Call the current function in the pipeline.
34+
results := fnVal.Call(in)
35+
36+
// Assume the last function call results will be used as next input.
37+
currentArgs = []interface{}{} // Reset currentArgs for next function.
38+
for _, result := range results {
39+
if result.Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
40+
if !result.IsNil() { // If the result is an error, return it.
41+
return nil, result.Interface().(error)
42+
}
43+
// If it's a nil error, ignore it for the output.
44+
} else {
45+
currentArgs = append(currentArgs, result.Interface())
46+
}
4747
}
4848
}
4949

50-
return result, err
51-
}
52-
}
53-
54-
func ParseTo(result interface{}, target interface{}) error {
55-
56-
if reflect.TypeOf(target).Kind() != reflect.Ptr {
57-
return errors.New("target deve ser um ponteiro")
58-
}
59-
60-
resultValue := reflect.ValueOf(result)
61-
targetValue := reflect.ValueOf(target).Elem()
62-
63-
if !resultValue.Type().ConvertibleTo(targetValue.Type()) {
64-
return fmt.Errorf("não é possível converter o resultado do tipo %s para o tipo %s",
65-
resultValue.Type(), targetValue.Type())
50+
// Return the final result which should match the last function's output type.
51+
if len(currentArgs) == 1 {
52+
return currentArgs[0], nil // Return single value if only one result.
53+
}
54+
return currentArgs, nil // Return as slice if multiple values.
6655
}
67-
68-
convertedValue := resultValue.Convert(targetValue.Type())
69-
targetValue.Set(convertedValue)
70-
71-
return nil
7256
}

v1/pite_test.go

Lines changed: 148 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,84 @@ package v1
22

33
import (
44
"fmt"
5+
"github.com/devalexandre/gofn/pipe"
6+
"reflect"
57
"strings"
68
"testing"
79
)
810

11+
// Exemplos de funções adaptadas para usar com generics
912
func ToUpper(s string) (string, error) {
1013
return strings.ToUpper(s), nil
1114
}
1215

13-
// Wrapper para strings.TrimSpace que se encaixa na assinatura esperada por Pipe.
1416
func Trim(s string) (string, error) {
1517
return strings.TrimSpace(s), nil
1618
}
1719

18-
func TestPipe(t *testing.T) {
20+
func ValidateCPF(cpf string) (string, error) {
21+
if len(cpf) != 11 {
22+
return "", fmt.Errorf("CPF must have 11 digits")
23+
}
24+
return cpf, nil
25+
}
26+
27+
func FormatCPF(cpf string) (string, error) {
28+
return fmt.Sprintf("%s.%s.%s-%s", cpf[0:3], cpf[3:6], cpf[6:9], cpf[9:11]), nil
29+
}
30+
31+
func Sum(a, b int) (int, error) {
32+
return a + b, nil
33+
}
34+
35+
func Multiply(a int) (int, error) {
36+
return a * 2, nil
37+
}
1938

39+
func ShowResult(result int) (int, error) {
40+
fmt.Println(result)
41+
return result, nil
42+
}
43+
44+
// Estrutura Person e funções de validação ajustadas
45+
type Person struct {
46+
Name string
47+
Email string
48+
Phone string
49+
}
50+
51+
func ValidatePersonName(p Person) (Person, error) {
52+
if p.Name == "" {
53+
return p, fmt.Errorf("Name is required")
54+
}
55+
return p, nil
56+
}
57+
58+
func ValidatePersonEmail(p Person) (Person, error) {
59+
if p.Email == "" || !strings.Contains(p.Email, "@") {
60+
return p, fmt.Errorf("Valid email is required")
61+
}
62+
return p, nil
63+
}
64+
65+
func ValidatePersonPhone(p Person) (Person, error) {
66+
if p.Phone == "" {
67+
return p, fmt.Errorf("Phone is required")
68+
}
69+
return p, nil
70+
}
71+
72+
func SumMore(a, b, c int) (int, error) {
73+
return a + b + c, nil
74+
}
75+
76+
func GenerateTreeNumbers(n int) (int, int, int) {
77+
return n, n * 2, n * 3
78+
}
79+
80+
// Testes ajustados para usar a função Pipe com generics
81+
82+
func TestStringPipeline(t *testing.T) {
2083
pipeline := Pipe(
2184
ToUpper,
2285
Trim,
@@ -34,63 +97,110 @@ func TestPipe(t *testing.T) {
3497
}
3598
}
3699

37-
func TestParseTo(t *testing.T) {
38-
39-
result := "test result"
40-
var target string
100+
func TestCPFPipeline(t *testing.T) {
101+
pipeline := Pipe(
102+
ValidateCPF,
103+
FormatCPF,
104+
)
41105

42-
err := ParseTo(result, &target)
106+
input := "12345678901"
107+
expected := "123.456.789-01"
108+
result, err := pipeline(input)
43109
if err != nil {
44-
t.Errorf("ParseTo returned an error: %v", err)
110+
t.Errorf("Pipeline returned an error: %v", err)
111+
}
112+
113+
if result != expected {
114+
t.Errorf("Expected %s, got %s", expected, result)
45115
}
116+
}
117+
118+
func TestMathPipeline(t *testing.T) {
119+
pipeline := Pipe(
120+
Sum,
121+
Multiply,
122+
ShowResult,
123+
)
46124

47-
if target != result {
48-
t.Errorf("Expected target to be %s, got %s", result, target)
125+
expected := 18
126+
result, err := pipeline(5, 4)
127+
if err != nil {
128+
t.Errorf("Pipeline returned an error: %v", err)
49129
}
50130

51-
var intTarget int
52-
err = ParseTo(result, &intTarget)
53-
if err == nil {
54-
t.Errorf("Expected ParseTo to fail when types are incompatible")
131+
if result != expected {
132+
t.Errorf("Expected %d, got %d", expected, result)
55133
}
56134
}
57135

58-
// Sum recebe dois números e retorna a sua soma.
59-
func Sum(a, b int) (int, error) {
60-
return a + b, nil
61-
}
136+
func TestPersonPipeline(t *testing.T) {
137+
pipeline := Pipe(
138+
ValidatePersonName,
139+
ValidatePersonEmail,
140+
ValidatePersonPhone,
141+
)
142+
143+
input := Person{
144+
Name: "John Doe",
145+
Email: "john.doe@example.com",
146+
Phone: "1234567890",
147+
}
148+
expected := input // assumindo que a entrada é válida e esperada como saída
62149

63-
// IntToString recebe um número e retorna sua representação em string.
64-
func IntToString(n int) (string, error) {
65-
return fmt.Sprintf("%d", n), nil
150+
result, err := pipeline(input)
151+
if err != nil {
152+
t.Errorf("Pipeline returned an error: %v", err)
153+
}
154+
155+
if result != expected {
156+
t.Errorf("Expected %+v, got %+v", expected, result)
157+
}
66158
}
67159

68-
func TestSumPipeline(t *testing.T) {
69-
// Cria o pipeline.
160+
func TestMoreArgs(t *testing.T) {
70161
pipeline := Pipe(
71-
Sum,
72-
IntToString,
162+
GenerateTreeNumbers,
163+
SumMore,
73164
)
74165

75-
// Define a entrada e a saída esperada.
76-
input1 := 5
77-
input2 := 7
78-
expected := "12"
166+
expected := 6
167+
result, err := pipeline(1)
168+
if err != nil {
169+
t.Errorf("Pipeline returned an error: %v", err)
170+
}
171+
172+
if result != expected {
173+
t.Errorf("Expected %d, got %d", expected, result)
174+
}
175+
}
176+
177+
func TestPipeGoFn(t *testing.T) {
178+
data := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
179+
expected := []int{4, 8, 12, 16, 20}
180+
// Definindo o pipeline
181+
process := Pipe(
182+
pipe.Filter(func(i int) bool { return i%2 == 0 }),
183+
pipe.Map(func(i int) int { return i * 2 }),
184+
)
79185

80-
// Executa o pipeline com os números de entrada.
81-
resultInterface, err := pipeline(input1, input2)
186+
// Aplicando o pipeline aos dados
187+
resultInterface, err := process(data)
82188
if err != nil {
83-
t.Fatalf("Pipeline returned an error: %v", err)
189+
fmt.Println("Erro ao processar:", err)
190+
return
84191
}
85192

86-
// Converte o resultado para string.
87-
result, ok := resultInterface.(string)
193+
result, ok := resultInterface.([]int)
88194
if !ok {
89-
t.Fatalf("Failed to convert result to string")
195+
t.Errorf("Expected result type []int, got %T", resultInterface)
90196
}
91197

92-
// Verifica se o resultado é o esperado.
93-
if result != expected {
94-
t.Errorf("Expected %s, got %s", expected, result)
198+
if len(result) != len(expected) {
199+
t.Errorf("Expected %v, got %v", expected, result)
200+
}
201+
202+
if !reflect.DeepEqual(result, expected) {
203+
t.Errorf("Expected %v, got %v", expected, result)
95204
}
205+
96206
}

0 commit comments

Comments
 (0)