1package main 2 3import "go/ast" 4 5// because "interface" is a keyword... 6type iface struct { 7 name, stubname, rcvrName *ast.Ident 8 methods []method 9} 10 11func (i iface) stubName() *ast.Ident { 12 return i.stubname 13} 14 15func (i iface) stubStructDecl() ast.Decl { 16 return structDecl(i.stubName(), &ast.FieldList{}) 17} 18 19func (i iface) endpointsStruct() ast.Decl { 20 fl := &ast.FieldList{} 21 for _, m := range i.methods { 22 fl.List = append(fl.List, &ast.Field{Names: []*ast.Ident{m.name}, Type: sel(id("endpoint"), id("Endpoint"))}) 23 } 24 return structDecl(id("Endpoints"), fl) 25} 26 27func (i iface) httpHandler() ast.Decl { 28 handlerFn := fetchFuncDecl("NewHTTPHandler") 29 30 // does this "inlining" process merit a helper akin to replaceIdent? 31 handleCalls := []ast.Stmt{} 32 for _, m := range i.methods { 33 handleCall := fetchFuncDecl("inlineHandlerBuilder").Body.List[0].(*ast.ExprStmt).X.(*ast.CallExpr) 34 35 handleCall = replaceLit(handleCall, `"/bar"`, `"`+m.pathName()+`"`).(*ast.CallExpr) 36 handleCall = replaceIdent(handleCall, "ExampleEndpoint", m.name).(*ast.CallExpr) 37 handleCall = replaceIdent(handleCall, "DecodeExampleRequest", m.decodeFuncName()).(*ast.CallExpr) 38 handleCall = replaceIdent(handleCall, "EncodeExampleResponse", m.encodeFuncName()).(*ast.CallExpr) 39 40 handleCalls = append(handleCalls, &ast.ExprStmt{X: handleCall}) 41 } 42 43 pasteStmts(handlerFn.Body, 1, handleCalls) 44 45 return handlerFn 46} 47 48func (i iface) reciever() *ast.Field { 49 return field(i.receiverName(), i.stubName()) 50} 51 52func (i iface) receiverName() *ast.Ident { 53 if i.rcvrName != nil { 54 return i.rcvrName 55 } 56 scope := ast.NewScope(nil) 57 for _, meth := range i.methods { 58 for _, arg := range meth.params { 59 if arg.name != nil { 60 scope.Insert(ast.NewObj(ast.Var, arg.name.Name)) 61 } 62 } 63 for _, arg := range meth.results { 64 if arg.name != nil { 65 scope.Insert(ast.NewObj(ast.Var, arg.name.Name)) 66 } 67 } 68 } 69 return id(unexport(inventName(i.name, scope).Name)) 70} 71