Merge pull request #7 from saicheems/client_options

Add client options
diff --git a/gax.go b/call_option.go
similarity index 89%
rename from gax.go
rename to call_option.go
index c20ed4f..3f0e3f6 100644
--- a/gax.go
+++ b/call_option.go
@@ -7,14 +7,14 @@
 )
 
 type CallOption interface {
-	Resolve(*callSettings)
+	resolve(*callSettings)
 }
 
 type callOptions []CallOption
 
-func (opts callOptions) Resolve(s *callSettings) *callSettings {
+func (opts callOptions) resolve(s *callSettings) *callSettings {
 	for _, opt := range opts {
-		opt.Resolve(s)
+		opt.resolve(s)
 	}
 	return s
 }
@@ -46,7 +46,7 @@
 
 type withTimeout time.Duration
 
-func (w withTimeout) Resolve(s *callSettings) {
+func (w withTimeout) resolve(s *callSettings) {
 	s.timeout = time.Duration(w)
 }
 
@@ -58,7 +58,7 @@
 
 type withRetryCodes []codes.Code
 
-func (w withRetryCodes) Resolve(s *callSettings) {
+func (w withRetryCodes) resolve(s *callSettings) {
 	s.retrySettings.retryCodes = make(map[codes.Code]bool)
 	for _, code := range []codes.Code(w) {
 		s.retrySettings.retryCodes[code] = true
@@ -73,7 +73,7 @@
 
 type withDelayTimeoutSettings multipliableDuration
 
-func (w withDelayTimeoutSettings) Resolve(s *callSettings) {
+func (w withDelayTimeoutSettings) resolve(s *callSettings) {
 	s.retrySettings.backoffSettings.delayTimeoutSettings = multipliableDuration(w)
 }
 
@@ -93,7 +93,7 @@
 
 type withRPCTimeoutSettings multipliableDuration
 
-func (w withRPCTimeoutSettings) Resolve(s *callSettings) {
+func (w withRPCTimeoutSettings) resolve(s *callSettings) {
 	s.retrySettings.backoffSettings.rpcTimeoutSettings = multipliableDuration(w)
 }
 
@@ -110,7 +110,7 @@
 
 type withTotalRetryTimeout time.Duration
 
-func (w withTotalRetryTimeout) Resolve(s *callSettings) {
+func (w withTotalRetryTimeout) resolve(s *callSettings) {
 	s.retrySettings.backoffSettings.totalTimeout = time.Duration(w)
 }
 
diff --git a/gax_test.go b/call_option_test.go
similarity index 92%
rename from gax_test.go
rename to call_option_test.go
index 7bf6ba6..6d4190b 100644
--- a/gax_test.go
+++ b/call_option_test.go
@@ -8,8 +8,8 @@
 	"google.golang.org/grpc/codes"
 )
 
-var (
-	expected = &callSettings{
+func TestCallOptionsPieceByPiece(t *testing.T) {
+	expected := &callSettings{
 		time.Second * 1,
 		retrySettings{
 			map[codes.Code]bool{codes.Unavailable: true, codes.DeadlineExceeded: true},
@@ -20,9 +20,7 @@
 			},
 		},
 	}
-)
 
-func TestCallOptionsPieceByPiece(t *testing.T) {
 	settings := &callSettings{}
 	opts := []CallOption{
 		WithTimeout(time.Second * 1),
@@ -31,7 +29,7 @@
 		WithRPCTimeoutSettings(time.Second*5, time.Second*7, 6.0),
 		WithTotalRetryTimeout(time.Second * 8),
 	}
-	callOptions(opts).Resolve(settings)
+	callOptions(opts).resolve(settings)
 
 	if !reflect.DeepEqual(settings, expected) {
 		t.Errorf("settings don't match their expected configuration")
diff --git a/client_option.go b/client_option.go
new file mode 100644
index 0000000..b03544d
--- /dev/null
+++ b/client_option.go
@@ -0,0 +1,61 @@
+package gax
+
+type ClientOption interface {
+	resolve(*clientSettings)
+}
+
+type clientOptions []ClientOption
+
+func (opts clientOptions) resolve(s *clientSettings) *clientSettings {
+	for _, opt := range opts {
+		opt.resolve(s)
+	}
+	return s
+}
+
+type clientSettings struct {
+	apiName    string
+	apiVersion string
+	endpoint   string
+	scopes     []string
+}
+
+type withAPIName string
+
+func (w withAPIName) resolve(s *clientSettings) {
+	s.apiName = string(w)
+}
+
+func WithAPIName(apiName string) ClientOption {
+	return withAPIName(apiName)
+}
+
+type withAPIVersion string
+
+func (w withAPIVersion) resolve(s *clientSettings) {
+	s.apiVersion = string(w)
+}
+
+func WithAPIVersion(apiVersion string) ClientOption {
+	return withAPIVersion(apiVersion)
+}
+
+type withEndpoint string
+
+func (w withEndpoint) resolve(s *clientSettings) {
+	s.endpoint = string(w)
+}
+
+func WithEndpoint(endpoint string) ClientOption {
+	return withEndpoint(endpoint)
+}
+
+type withScopes []string
+
+func (w withScopes) resolve(s *clientSettings) {
+	s.scopes = append(s.scopes[:0], w...)
+}
+
+func WithScopes(scopes ...string) ClientOption {
+	return withScopes(scopes)
+}
diff --git a/client_option_test.go b/client_option_test.go
new file mode 100644
index 0000000..35710ec
--- /dev/null
+++ b/client_option_test.go
@@ -0,0 +1,28 @@
+package gax
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestClientOptionsPieceByPiece(t *testing.T) {
+	expected := &clientSettings{
+		"myapi",
+		"v0.1.0",
+		"https://example.com:443",
+		[]string{"https://example.com/auth/helloworld", "https://example.com/auth/otherthing"},
+	}
+
+	settings := &clientSettings{}
+	opts := []ClientOption{
+		WithAPIName("myapi"),
+		WithAPIVersion("v0.1.0"),
+		WithEndpoint("https://example.com:443"),
+		WithScopes("https://example.com/auth/helloworld", "https://example.com/auth/otherthing"),
+	}
+	clientOptions(opts).resolve(settings)
+
+	if !reflect.DeepEqual(settings, expected) {
+		t.Errorf("settings don't match their expected configuration")
+	}
+}
diff --git a/dial.go b/dial.go
new file mode 100644
index 0000000..336be35
--- /dev/null
+++ b/dial.go
@@ -0,0 +1,26 @@
+package gax
+
+import (
+	"fmt"
+
+	"golang.org/x/net/context"
+	"golang.org/x/oauth2/google"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"google.golang.org/grpc/credentials/oauth"
+)
+
+func DialGRPC(ctx context.Context, opts ...ClientOption) (*grpc.ClientConn, error) {
+	settings := &clientSettings{}
+	clientOptions(opts).resolve(settings)
+
+	tokenSource, err := google.DefaultTokenSource(ctx, settings.scopes...)
+	if err != nil {
+		return nil, fmt.Errorf("google.DefaultTokenSource: %v", err)
+	}
+	grpcOpts := []grpc.DialOption{
+		grpc.WithPerRPCCredentials(oauth.TokenSource{TokenSource: tokenSource}),
+		grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
+	}
+	return grpc.Dial(settings.endpoint, grpcOpts...)
+}
diff --git a/api_callable.go b/invoke.go
similarity index 97%
rename from api_callable.go
rename to invoke.go
index 10b79a5..86841a3 100644
--- a/api_callable.go
+++ b/invoke.go
@@ -58,7 +58,7 @@
 // Invoke calls stub with a child of context modified by the specified options.
 func Invoke(ctx context.Context, stub APICall, opts ...CallOption) error {
 	settings := &callSettings{}
-	callOptions(opts).Resolve(settings)
+	callOptions(opts).resolve(settings)
 	if len(settings.retrySettings.retryCodes) > 0 {
 		return invokeWithRetry(ctx, stub, settings.retrySettings)
 	}
diff --git a/api_callable_test.go b/invoke_test.go
similarity index 100%
rename from api_callable_test.go
rename to invoke_test.go