Add a new_batch_http_request() method to services

This method can be used to get a BatchHttpRequest object with the
batch_uri calculated from the rootUrl and batchPath fields from the
discovery doc.

Without this change, users have to know what the batch url for newer api
endpoints is. For example:
batch = BatchHttpRequest(batch_uri=http://zoo.googleapis.com/batch)

With this change, the syntax is easier:
zoo = build('zoo', 'v1', http=http)
batch = zoo.new_batch_http_request()
diff --git a/googleapiclient/discovery.py b/googleapiclient/discovery.py
index f3e5690..10c4473 100644
--- a/googleapiclient/discovery.py
+++ b/googleapiclient/discovery.py
@@ -56,6 +56,7 @@
 from googleapiclient.errors import UnacceptableMimeTypeError
 from googleapiclient.errors import UnknownApiNameOrVersion
 from googleapiclient.errors import UnknownFileType
+from googleapiclient.http import BatchHttpRequest
 from googleapiclient.http import HttpRequest
 from googleapiclient.http import MediaFileUpload
 from googleapiclient.http import MediaUpload
@@ -950,6 +951,14 @@
     self._add_next_methods(self._resourceDesc, self._schema)
 
   def _add_basic_methods(self, resourceDesc, rootDesc, schema):
+    # If this is the root Resource, add a new_batch_http_request() method.
+    if resourceDesc == rootDesc:
+      batch_uri = '%s%s' % (
+        rootDesc['rootUrl'], rootDesc.get('batchPath', 'batch'))
+      def new_batch_http_request(callback=None):
+        return BatchHttpRequest(callback=callback, batch_uri=batch_uri)
+      self._set_dynamic_attr('new_batch_http_request', new_batch_http_request)
+
     # Add basic methods to Resource
     if 'methods' in resourceDesc:
       for methodName, methodDesc in six.iteritems(resourceDesc['methods']):
diff --git a/tests/data/zoo.json b/tests/data/zoo.json
index 38cb686..3a4c775 100644
--- a/tests/data/zoo.json
+++ b/tests/data/zoo.json
@@ -4,6 +4,7 @@
  "version": "v1",
  "description": "Zoo API used for testing",
  "basePath": "/zoo/",
+ "batchPath": "batchZoo",
  "rootUrl": "https://www.googleapis.com/",
  "servicePath": "zoo/v1/",
  "rpcPath": "/rpc",
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
index 1f2b38c..2b9b2e6 100644
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -55,6 +55,7 @@
 from googleapiclient.errors import MediaUploadSizeError
 from googleapiclient.errors import ResumableUploadError
 from googleapiclient.errors import UnacceptableMimeTypeError
+from googleapiclient.http import BatchHttpRequest
 from googleapiclient.http import HttpMock
 from googleapiclient.http import HttpMockSequence
 from googleapiclient.http import MediaFileUpload
@@ -514,6 +515,22 @@
 
     self.assertEqual(request.method, 'PATCH')
 
+  def test_batch_request_from_discovery(self):
+    self.http = HttpMock(datafile('zoo.json'), {'status': '200'})
+    # zoo defines a batchPath
+    zoo = build('zoo', 'v1', http=self.http)
+    batch_request = zoo.new_batch_http_request()
+    self.assertEqual(batch_request._batch_uri,
+                     "https://www.googleapis.com/batchZoo")
+
+  def test_batch_request_from_default(self):
+    self.http = HttpMock(datafile('plus.json'), {'status': '200'})
+    # plus does not define a batchPath
+    plus = build('plus', 'v1', http=self.http)
+    batch_request = plus.new_batch_http_request()
+    self.assertEqual(batch_request._batch_uri,
+                     "https://www.googleapis.com/batch")
+
   def test_tunnel_patch(self):
     http = HttpMockSequence([
       ({'status': '200'}, open(datafile('zoo.json'), 'rb').read()),
@@ -1066,6 +1083,7 @@
                             'load',
                             'loadNoTemplate',
                             'my',
+                            'new_batch_http_request',
                             'query',
                             'scopedAnimals']