forked from protocolbuffers/protobuf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This follows the other examples so that it can be used as a tutorial, such as the ones at: https://developers.google.com/protocol-buffers/docs/tutorials Even though Go generally does not use Makefiles, I added targets for the Go examples to be consistent with the other languages. Edit: Fix Travis run. Change to use $HOME instead of ~. Add protoc to path. GOPATH entry cannot start with shell metacharacter '~': "~/gocode" Edit(2): Fix Go code style to address comments.
- Loading branch information
Showing
8 changed files
with
410 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"strings" | ||
|
||
"github.com/golang/protobuf/proto" | ||
pb "github.com/google/protobuf/examples/tutorial" | ||
) | ||
|
||
func promptForAddress(r io.Reader) (*pb.Person, error) { | ||
// A protocol buffer can be created like any struct. | ||
p := &pb.Person{} | ||
|
||
rd := bufio.NewReader(r) | ||
fmt.Print("Enter person ID number: ") | ||
// An int32 field in the .proto file is represented as an int32 field | ||
// in the generated Go struct. | ||
if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil { | ||
return p, err | ||
} | ||
|
||
fmt.Print("Enter name: ") | ||
name, err := rd.ReadString('\n') | ||
if err != nil { | ||
return p, err | ||
} | ||
// A string field in the .proto file results in a string field in Go. | ||
// We trim the whitespace because rd.ReadString includes the trailing | ||
// newline character in its output. | ||
p.Name = strings.TrimSpace(name) | ||
|
||
fmt.Print("Enter email address (blank for none): ") | ||
email, err := rd.ReadString('\n') | ||
if err != nil { | ||
return p, err | ||
} | ||
p.Email = strings.TrimSpace(email) | ||
|
||
for { | ||
fmt.Print("Enter a phone number (or leave blank to finish): ") | ||
phone, err := rd.ReadString('\n') | ||
if err != nil { | ||
return p, err | ||
} | ||
phone = strings.TrimSpace(phone) | ||
if phone == "" { | ||
break | ||
} | ||
// The PhoneNumber message type is nested within the Person | ||
// message in the .proto file. This results in a Go struct | ||
// named using the name of the parent prefixed to the name of | ||
// the nested message. Just as with pb.Person, it can be | ||
// created like any other struct. | ||
pn := &pb.Person_PhoneNumber{ | ||
Number: phone, | ||
} | ||
|
||
fmt.Print("Is this a mobile, home, or work phone? ") | ||
ptype, err := rd.ReadString('\n') | ||
if err != nil { | ||
return p, err | ||
} | ||
ptype = strings.TrimSpace(ptype) | ||
|
||
// A proto enum results in a Go constant for each enum value. | ||
switch ptype { | ||
case "mobile": | ||
pn.Type = pb.Person_MOBILE | ||
case "home": | ||
pn.Type = pb.Person_HOME | ||
case "work": | ||
pn.Type = pb.Person_WORK | ||
default: | ||
fmt.Printf("Unknown phone type %q. Using default.\n", ptype) | ||
} | ||
|
||
// A repeated proto field maps to a slice field in Go. We can | ||
// append to it like any other slice. | ||
p.Phones = append(p.Phones, pn) | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
// Main reads the entire address book from a file, adds one person based on | ||
// user input, then writes it back out to the same file. | ||
func main() { | ||
if len(os.Args) != 2 { | ||
log.Fatalf("Usage: %s ADDRESS_BOOK_FILE\n", os.Args[0]) | ||
} | ||
fname := os.Args[1] | ||
|
||
// Read the existing address book. | ||
in, err := ioutil.ReadFile(fname) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
fmt.Printf("%s: File not found. Creating new file.\n", fname) | ||
} else { | ||
log.Fatalln("Error reading file:", err) | ||
} | ||
} | ||
book := &pb.AddressBook{} | ||
if err := proto.Unmarshal(in, book); err != nil { | ||
log.Fatalln("Failed to parse address book:", err) | ||
} | ||
|
||
// Add an address. | ||
addr, err := promptForAddress(os.Stdin) | ||
if err != nil { | ||
log.Fatalln("Error with address:", err) | ||
} | ||
book.People = append(book.People, addr) | ||
|
||
// Write the new address book back to disk. | ||
out, err := proto.Marshal(book) | ||
if err != nil { | ||
log.Fatalln("Failed to encode address book:", err) | ||
} | ||
if err := ioutil.WriteFile(fname, out, 0644); err != nil { | ||
log.Fatalln("Failed to write address book:", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package main | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"github.com/golang/protobuf/proto" | ||
pb "github.com/google/protobuf/examples/tutorial" | ||
) | ||
|
||
func TestPromptForAddressReturnsAddress(t *testing.T) { | ||
in := `12345 | ||
Example Name | ||
name@example.com | ||
123-456-7890 | ||
home | ||
222-222-2222 | ||
mobile | ||
111-111-1111 | ||
work | ||
777-777-7777 | ||
unknown | ||
` | ||
got, err := promptForAddress(strings.NewReader(in)) | ||
if err != nil { | ||
t.Fatalf("promptForAddress(%q) had unexpected error: %s", in, err.Error()) | ||
} | ||
if got.Id != 12345 { | ||
t.Errorf("promptForAddress(%q) got %d, want ID %d", in, got.Id, 12345) | ||
} | ||
if got.Name != "Example Name" { | ||
t.Errorf("promptForAddress(%q) => want name %q, got %q", "Example Name", got.Name) | ||
} | ||
if got.Email != "name@example.com" { | ||
t.Errorf("promptForAddress(%q) => want email %q, got %q", "name@example.com", got.Email) | ||
} | ||
|
||
want := []*pb.Person_PhoneNumber{ | ||
{Number: "123-456-7890", Type: pb.Person_HOME}, | ||
{Number: "222-222-2222", Type: pb.Person_MOBILE}, | ||
{Number: "111-111-1111", Type: pb.Person_WORK}, | ||
{Number: "777-777-7777", Type: pb.Person_MOBILE}, | ||
} | ||
if len(got.Phones) != len(want) { | ||
t.Errorf("want %d phone numbers, got %d", len(want), len(got.Phones)) | ||
} | ||
phones := len(got.Phones) | ||
if phones > len(want) { | ||
phones = len(want) | ||
} | ||
for i := 0; i < phones; i++ { | ||
if !proto.Equal(got.Phones[i], want[i]) { | ||
t.Errorf("want phone %q, got %q", *want[i], *got.Phones[i]) | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
|
||
"github.com/golang/protobuf/proto" | ||
pb "github.com/google/protobuf/examples/tutorial" | ||
) | ||
|
||
func listPeople(w io.Writer, book *pb.AddressBook) { | ||
for _, p := range book.People { | ||
fmt.Fprintln(w, "Person ID:", p.Id) | ||
fmt.Fprintln(w, " Name:", p.Name) | ||
if p.Email != "" { | ||
fmt.Fprintln(w, " E-mail address:", p.Email) | ||
} | ||
|
||
for _, pn := range p.Phones { | ||
switch pn.Type { | ||
case pb.Person_MOBILE: | ||
fmt.Fprint(w, " Mobile phone #: ") | ||
case pb.Person_HOME: | ||
fmt.Fprint(w, " Home phone #: ") | ||
case pb.Person_WORK: | ||
fmt.Fprint(w, " Work phone #: ") | ||
} | ||
fmt.Fprintln(w, pn.Number) | ||
} | ||
} | ||
} | ||
|
||
// Main reads the entire address book from a file and prints all the | ||
// information inside. | ||
func main() { | ||
if len(os.Args) != 2 { | ||
log.Fatalf("Usage: %s ADDRESS_BOOK_FILE\n", os.Args[0]) | ||
} | ||
fname := os.Args[1] | ||
|
||
// Read the existing address book. | ||
in, err := ioutil.ReadFile(fname) | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
fmt.Printf("%s: File not found. Creating new file.\n", fname) | ||
} else { | ||
log.Fatalln("Error reading file:", err) | ||
} | ||
} | ||
book := &pb.AddressBook{} | ||
if err := proto.Unmarshal(in, book); err != nil { | ||
log.Fatalln("Failed to parse address book:", err) | ||
} | ||
|
||
listPeople(os.Stdout, book) | ||
} |
Oops, something went wrong.