Fixed serialization for custom ints and floats.

[GitHub issue #57](https://github.com/dpranke/pyjson5/issues/57)
Fixed serialization for objects that subclass `int` or `float`:
Previously we would use the objects __str__ implementation, but
that might result in an illegal JSON5 value if the object had
customized __str__ to return something illegal. Instead,
we follow the lead of the `JSON` module and call `int.__repr__`
or `float.__repr__` directly.

While I was at it, I added tests for dumps(-inf) and dumps(nan)
when those were supposed to be disallowed by `allow_nan=False`.
diff --git a/README.md b/README.md
index 7c54fa7..ec846d1 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,16 @@
 
 ## Version History / Release Notes
 
+* v0.9.9 (2022-08-01)
+    * [GitHub issue #57](https://github.com/dpranke/pyjson5/issues/57)
+      Fixed serialization for objects that subclass `int` or `float`:
+      Previously we would use the objects __str__ implementation, but
+      that might result in an illegal JSON5 value if the object had
+      customized __str__ to return something illegal. Instead,
+      we follow the lead of the `JSON` module and call `int.__repr__`
+      or `float.__repr__` directly.
+    * While I was at it, I added tests for dumps(-inf) and dumps(nan)
+      when those were supposed to be disallowed by `allow_nan=False`.
 * v0.9.8 (2022-05-08)
     * [GitHub issue #47](https://github.com/dpranke/pyjson5/issues/47)
       Fixed error reporting in some cases due to how parsing was handling
diff --git a/json5/lib.py b/json5/lib.py
index e56e825..6b3056e 100644
--- a/json5/lib.py
+++ b/json5/lib.py
@@ -264,15 +264,36 @@
         s = u'false'
     elif obj is None:
         s = u'null'
+    elif obj == math.inf:
+        if allow_nan:
+            s = u'Infinity'
+        else:
+            raise ValueError()
+    elif obj == -math.inf:
+        if allow_nan:
+            s = u'-Infinity'
+        else:
+            raise ValueError()
+    elif isinstance(obj, float) and math.isnan(obj):
+        if allow_nan:
+            s = u'NaN'
+        else:
+            raise ValueError()
     elif isinstance(obj, str_types):
         if (is_key and _is_ident(obj) and not quote_keys
             and not _is_reserved_word(obj)):
             return True, obj
         return True, _dump_str(obj, ensure_ascii)
-    elif isinstance(obj, float):
-        s = _dump_float(obj,allow_nan)
     elif isinstance(obj, int):
-        s = str(obj)
+        # Subclasses of `int` and `float` may have custom
+        # __repr__ or __str__ methods, but the `JSON` library
+        # ignores them in order to ensure that the representation
+        # are just bare numbers. In order to match JSON's behavior
+        # we call the methods of the `float` and `int` class directly.
+        s = int.__repr__(obj)
+    elif isinstance(obj, float):
+        # See comment above for int
+        s = float.__repr__(obj)
     else:
         s = None
 
@@ -403,20 +424,6 @@
             end_str + u']')
 
 
-def _dump_float(obj, allow_nan):
-    if allow_nan:
-        if math.isnan(obj):
-            return 'NaN'
-        if obj == float('inf'):
-            return 'Infinity'
-        if obj == float('-inf'):
-            return '-Infinity'
-    elif math.isnan(obj) or obj == float('inf') or obj == float('-inf'):
-        raise ValueError('Out of range float values '
-                         'are not JSON compliant')
-    return str(obj)
-
-
 def _dump_str(obj, ensure_ascii):
     ret = ['"']
     for ch in obj:
diff --git a/json5/version.py b/json5/version.py
index ed8c2f6..0a39014 100644
--- a/json5/version.py
+++ b/json5/version.py
@@ -12,4 +12,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-VERSION = '0.9.8'
+VERSION = '0.9.9'
diff --git a/tests/lib_test.py b/tests/lib_test.py
index a6d2473..68842e7 100644
--- a/tests/lib_test.py
+++ b/tests/lib_test.py
@@ -347,13 +347,20 @@
         self.assertEqual(json5.dumps(MyArray()), '[0, 1, 1]')
 
     def test_custom_numbers(self):
+        # See https://github.com/dpranke/pyjson5/issues/57: we
+        # need to ensure that we use the bare int.__repr__ and
+        # float.__repr__ in order to get legal JSON values when
+        # people have custom subclasses with customer __repr__ methods.
+        # (This is what JSON does and we want to match it).
         class MyInt(int):
-            pass
+            def __repr__(self):
+                return 'fail'
 
         self.assertEqual(json5.dumps(MyInt(5)), '5')
 
         class MyFloat(float):
-            pass
+            def __repr__(self):
+                return 'fail'
 
         self.assertEqual(json5.dumps(MyFloat(0.5)), '0.5')
 
@@ -427,6 +434,10 @@
 
         self.assertRaises(ValueError, json5.dumps,
                           float('inf'), allow_nan=False)
+        self.assertRaises(ValueError, json5.dumps,
+                          float('-inf'), allow_nan=False)
+        self.assertRaises(ValueError, json5.dumps,
+                          float('nan'), allow_nan=False)
 
     def test_null(self):
         self.check(None, 'null')