json-canonicalization 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AUTHORS +1 -0
- data/LICENSE +24 -0
- data/README.md +92 -0
- data/VERSION +1 -0
- data/lib/json/canonicalization/version.rb +20 -0
- data/lib/json/canonicalization.rb +83 -0
- data/spec/c14n_spec.rb +11 -0
- data/spec/input/arrays.json +8 -0
- data/spec/input/french.json +6 -0
- data/spec/input/structures.json +8 -0
- data/spec/input/unicode.json +3 -0
- data/spec/input/values.json +5 -0
- data/spec/input/wierd.json +11 -0
- data/spec/number_spec.rb +37 -0
- data/spec/output/arrays.json +1 -0
- data/spec/output/french.json +1 -0
- data/spec/output/structures.json +1 -0
- data/spec/output/unicode.json +1 -0
- data/spec/output/values.json +1 -0
- data/spec/output/wierd.json +1 -0
- data/spec/spec_helper.rb +24 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 75fbded244fc0096ae6a46a90730fbf8a3fe1913d9a58fe60ec9fc91fb238522
|
4
|
+
data.tar.gz: 817b4072f362414762a9cb19eec0551dab9c4290bc8720640faedb050ff64b75
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b8cf4b810ce1ca14b30232cd172d9bb3350b9d0aaaefd7c02cacad1fdb47c87ec7f88091b51c86621319bbeb59df53be34dcb81743b8a70307a90678a19862e
|
7
|
+
data.tar.gz: fc41d6154f7fb136396028f6c03ca3bfbb6e0ce65a676990773ad3361eef48c868990196b63ba790a57e537e12096ac8997036eefc7a7ab1773a94f4672fafcc
|
data/AUTHORS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* Gregg Kellogg <gregg@greggkellogg.net>
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org>
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# json-canonicalization
|
2
|
+
An implementation of the JSON Canonicalization Scheme for Ruby
|
3
|
+
|
4
|
+
Implements version 5 of [draft-rundgren-json-canonicalization-scheme-05](https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-05#page-5).
|
5
|
+
|
6
|
+
[](http://badge.fury.io/rb/json-canonicalization)
|
7
|
+
[](http://travis-ci.org/dryruby/json-canonicalization)
|
8
|
+
[](https://coveralls.io/r/dryruby/json-canonicalization)
|
9
|
+
|
10
|
+
# Description
|
11
|
+
|
12
|
+
Cryptographic operations like hashing and signing depend on that the target
|
13
|
+
data does not change during serialization, transport, or parsing.
|
14
|
+
By applying the rules defined by JCS (JSON Canonicalization Scheme),
|
15
|
+
data provided in the JSON [[RFC8259](https://tools.ietf.org/html/rfc8259)]
|
16
|
+
format can be exchanged "as is", while still being subject to secure cryptographic operations.
|
17
|
+
JCS achieves this by building on the serialization formats for JSON
|
18
|
+
primitives as defined by ECMAScript [[ES6](https://www.ecma-international.org/ecma-262/6.0/index.html)],
|
19
|
+
constraining JSON data to the<br>I-JSON [[RFC7493](https://tools.ietf.org/html//rfc7493)] subset,
|
20
|
+
and through a platform independent property sorting scheme.
|
21
|
+
|
22
|
+
Working document: https://cyberphone.github.io/ietf-json-canon<br>
|
23
|
+
Published IETF Draft: https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-05
|
24
|
+
|
25
|
+
The JSON Canonicalization Scheme concept in a nutshell:
|
26
|
+
- Serialization of primitive JSON data types using methods compatible with ECMAScript's `JSON.stringify()`
|
27
|
+
- Lexicographic sorting of JSON `Object` properties in a *recursive* process
|
28
|
+
- JSON `Array` data is also subject to canonicalization, *but element order remains untouched*
|
29
|
+
|
30
|
+
### Sample Input:
|
31
|
+
```code
|
32
|
+
{
|
33
|
+
"numbers": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001],
|
34
|
+
"string": "\u20ac$\u000F\u000aA'\u0042\u0022\u005c\\\"\/",
|
35
|
+
"literals": [null, true, false]
|
36
|
+
}
|
37
|
+
```
|
38
|
+
### Expected Output:
|
39
|
+
```code
|
40
|
+
{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}
|
41
|
+
```
|
42
|
+
## Usage
|
43
|
+
The library accepts Ruby input and generates canonical JSON via the `#to_json_c14n` method. This is based on the standard JSON gem's version of `#to_json` with overloads for `Hash`, `String` and `Numeric`
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
data = {
|
47
|
+
"numbers" => [
|
48
|
+
333333333.3333333,
|
49
|
+
1.0e+30,
|
50
|
+
4.5,
|
51
|
+
0.002,
|
52
|
+
1.0e-27
|
53
|
+
],
|
54
|
+
"string" => "€$\u000F\nA'B\"\\\\\"/",
|
55
|
+
"literals" => [nil, true, false]
|
56
|
+
}
|
57
|
+
|
58
|
+
puts data.to_json_c14n
|
59
|
+
=>
|
60
|
+
```
|
61
|
+
|
62
|
+
## Documentation
|
63
|
+
Full documentation available on [RubyDoc](http://rubydoc.info/gems/json-canonicalization/file/README.md)
|
64
|
+
|
65
|
+
### Principal Classes
|
66
|
+
* {JSON::Canonicalization}
|
67
|
+
|
68
|
+
## Dependencies
|
69
|
+
* [Ruby](http://ruby-lang.org/) (>= 2.2.2)
|
70
|
+
* [JSON](https://rubygems.org/gems/json) (>= 2.1)
|
71
|
+
|
72
|
+
## Author
|
73
|
+
* [Gregg Kellogg](http://github.com/gkellogg) - <http://kellogg-assoc.com/>
|
74
|
+
|
75
|
+
## Contributing
|
76
|
+
* Do your best to adhere to the existing coding conventions and idioms.
|
77
|
+
* Don't use hard tabs, and don't leave trailing whitespace on any line.
|
78
|
+
* Do document every method you add using [YARD][] annotations. Read the
|
79
|
+
[tutorial][YARD-GS] or just look at the existing code for examples.
|
80
|
+
* Don't touch the `json-ld.gemspec`, `VERSION` or `AUTHORS` files. If you need to
|
81
|
+
change them, do so on your private branch only.
|
82
|
+
* Do feel free to add yourself to the `CREDITS` file and the corresponding
|
83
|
+
list in the the `README`. Alphabetical order applies.
|
84
|
+
* Do note that in order for us to merge any non-trivial changes (as a rule
|
85
|
+
of thumb, additions larger than about 15 lines of code), we need an
|
86
|
+
explicit [public domain dedication][PDD] on record from you.
|
87
|
+
|
88
|
+
##License
|
89
|
+
|
90
|
+
This is free and unencumbered public domain software. For more information,
|
91
|
+
see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
92
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module JSON::Canonicalization::VERSION
|
4
|
+
VERSION_FILE = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..", "..", "VERSION")
|
5
|
+
MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chomp.split(".")
|
6
|
+
|
7
|
+
STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
|
8
|
+
|
9
|
+
##
|
10
|
+
# @return [String]
|
11
|
+
def self.to_s() STRING end
|
12
|
+
|
13
|
+
##
|
14
|
+
# @return [String]
|
15
|
+
def self.to_str() STRING end
|
16
|
+
|
17
|
+
##
|
18
|
+
# @return [Array(Integer, Integer, Integer)]
|
19
|
+
def self.to_a() STRING.split(".") end
|
20
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
$:.unshift(File.expand_path("../ld", __FILE__))
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module JSON
|
7
|
+
##
|
8
|
+
# `JSON::Canonicalization` generates canonical JSON output from Ruby objects
|
9
|
+
module Canonicalization
|
10
|
+
autoload :VERSION, 'json/ld/version'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Object
|
15
|
+
# Default canonicalization output for Ruby objects
|
16
|
+
# @return [String]
|
17
|
+
def to_json_c14n
|
18
|
+
self.to_json
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Array
|
23
|
+
def to_json_c14n
|
24
|
+
'[' + self.map(&:to_json_c14n).join(',') + ']'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Numeric
|
29
|
+
def to_json_c14n
|
30
|
+
raise RangeError if self.is_a?(Float) && (self.nan? || self.infinite?)
|
31
|
+
return "0" if self.zero?
|
32
|
+
num = self
|
33
|
+
if num < 0
|
34
|
+
num, sign = -num, '-'
|
35
|
+
end
|
36
|
+
native_rep = "%.15E" % num
|
37
|
+
decimal, exponential = native_rep.split('E')
|
38
|
+
exp_val = exponential.to_i
|
39
|
+
exponential = exp_val > 0 ? ('+' + exp_val.to_s) : exp_val.to_s
|
40
|
+
|
41
|
+
integral, fractional = decimal.split('.')
|
42
|
+
fractional = fractional.sub(/0+$/, '') # Remove trailing zeros
|
43
|
+
|
44
|
+
if exp_val > 0 && exp_val < 21
|
45
|
+
while exp_val > 0
|
46
|
+
integral += fractional.to_s[0] || '0'
|
47
|
+
fractional = fractional.to_s[1..-1]
|
48
|
+
exp_val -= 1
|
49
|
+
end
|
50
|
+
exponential = nil
|
51
|
+
elsif exp_val == 0
|
52
|
+
exponential = nil
|
53
|
+
elsif exp_val < 0 && exp_val > -7
|
54
|
+
# Small numbers are shown as 0.etc with e-6 as lower limit
|
55
|
+
fractional, integral, exponential = integral + fractional.to_s, '0', nil
|
56
|
+
fractional = ("0" * (-exp_val - 1)) + fractional
|
57
|
+
end
|
58
|
+
|
59
|
+
fractional = nil if fractional.to_s.empty?
|
60
|
+
sign.to_s + integral + (fractional ? ".#{fractional}" : '') + (exponential ? "e#{exponential}" : '')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Hash
|
65
|
+
# Output JSON with keys sorted lexicographically
|
66
|
+
# @return [String]
|
67
|
+
def to_json_c14n
|
68
|
+
"{" + self.
|
69
|
+
keys.
|
70
|
+
sort_by {|k| k.encode(Encoding::UTF_16)}.
|
71
|
+
map {|k| k.to_json_c14n + ':' + self[k].to_json_c14n}
|
72
|
+
.join(',') +
|
73
|
+
'}'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class String
|
78
|
+
# Output JSON with control characters escaped
|
79
|
+
# @return [String]
|
80
|
+
def to_json_c14n
|
81
|
+
self.to_json
|
82
|
+
end
|
83
|
+
end
|
data/spec/c14n_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "conversions" do
|
4
|
+
Dir.glob(File.expand_path("../input/*.json", __FILE__)).each do |input|
|
5
|
+
it "converts #{input.split('/').last}" do
|
6
|
+
expected = File.read(input.sub('input', 'output'))
|
7
|
+
data = JSON.parse(File.read(input))
|
8
|
+
expect(data.to_json_c14n).to eq expected
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{
|
2
|
+
"\u20ac": "Euro Sign",
|
3
|
+
"\r": "Carriage Return",
|
4
|
+
"\u000a": "Newline",
|
5
|
+
"1": "One",
|
6
|
+
"\u0080": "Control\u007f",
|
7
|
+
"\ud83d\ude02": "Smiley",
|
8
|
+
"\u00f6": "Latin Small Letter O With Diaeresis",
|
9
|
+
"\ufb33": "Hebrew Letter Dalet With Dagesh",
|
10
|
+
"</script>": "Browser Challenge"
|
11
|
+
}
|
data/spec/number_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "conversions" do
|
4
|
+
{
|
5
|
+
-1/0.0 => RangeError,
|
6
|
+
-9007199254740992 => '-9007199254740992',
|
7
|
+
0 => '0',
|
8
|
+
0.000001 => '0.000001',
|
9
|
+
0/0.0 => RangeError,
|
10
|
+
1/0.0 => RangeError,
|
11
|
+
1e+21 => '1e+21',
|
12
|
+
9.999999999999997e+22 => '9.999999999999997e+22',
|
13
|
+
9.999999999999997e-7 => '9.999999999999997e-7',
|
14
|
+
9007199254740992 => '9007199254740992',
|
15
|
+
9007199254740994 => '9007199254740994',
|
16
|
+
9007199254740996 => '9007199254740996',
|
17
|
+
999999999999999700000 => '999999999999999700000',
|
18
|
+
999999999999999900000 => '999999999999999900000',
|
19
|
+
# -5e-324 => '-5e-324', # Outside Ruby Range
|
20
|
+
# 1.0000000000000001e+23 => '1.0000000000000001e+23', # Outside Ruby Range
|
21
|
+
# 295147905179352830000 => '295147905179352830000', # Outside Ruby Range
|
22
|
+
#-1.7976931348623157e+308 => '-1.7976931348623157e+308', # Outside Ruby Range
|
23
|
+
#1.7976931348623157e+308 => '1.7976931348623157e+308', # Outside Ruby Range
|
24
|
+
#1e+23 => '1e+23', # Outside Ruby
|
25
|
+
#5e-324 => '5e-324', # Outside Ruby Range
|
26
|
+
}.each do |data, expected|
|
27
|
+
if expected.is_a?(String)
|
28
|
+
it "converts #{data} to #{expected}" do
|
29
|
+
expect(data.to_json_c14n).to eq expected
|
30
|
+
end
|
31
|
+
else
|
32
|
+
it "raises #{expected} for #{data}" do
|
33
|
+
expect {data.to_json_c14n}.to raise_error(expected)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
[56,{"1":[],"10":null,"d":true}]
|
@@ -0,0 +1 @@
|
|
1
|
+
{"peach":"This sorting order","péché":"is wrong according to French","pêche":"but canonicalization MUST","sin":"ignore locale"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"":"empty","1":{"\n":56,"f":{"F":5,"f":"hi"}},"10":{},"111":[{"E":"no","e":"yes"}],"A":{},"a":{}}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"Unnormalized Unicode":"Å"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"literals":[null,true,false],"numbers":[333333333.3333333,1e+30,4.5,0.002,1e-27],"string":"€$\u000f\nA'B\"\\\\\"/"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"\n":"Newline","\r":"Carriage Return","1":"One","</script>":"Browser Challenge","":"Control","ö":"Latin Small Letter O With Diaeresis","€":"Euro Sign","😂":"Smiley","דּ":"Hebrew Letter Dalet With Dagesh"}
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift(File.join("../../lib", __FILE__))
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'simplecov'
|
8
|
+
require 'coveralls' unless ENV['NOCOVERALLS']
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
11
|
+
(Coveralls::SimpleCov::Formatter unless ENV['NOCOVERALLS'])
|
12
|
+
])
|
13
|
+
SimpleCov.start do
|
14
|
+
add_filter "/spec/"
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'json/canonicalization'
|
20
|
+
|
21
|
+
::RSpec.configure do |c|
|
22
|
+
c.filter_run focus: true
|
23
|
+
c.run_all_when_everything_filtered = true
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-canonicalization
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gregg Kellogg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: yard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.9'
|
41
|
+
description: JSON::Canonicalization generates canonical JSON output from Ruby objects.
|
42
|
+
email:
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- AUTHORS
|
48
|
+
- LICENSE
|
49
|
+
- README.md
|
50
|
+
- VERSION
|
51
|
+
- lib/json/canonicalization.rb
|
52
|
+
- lib/json/canonicalization/version.rb
|
53
|
+
- spec/c14n_spec.rb
|
54
|
+
- spec/input/arrays.json
|
55
|
+
- spec/input/french.json
|
56
|
+
- spec/input/structures.json
|
57
|
+
- spec/input/unicode.json
|
58
|
+
- spec/input/values.json
|
59
|
+
- spec/input/wierd.json
|
60
|
+
- spec/number_spec.rb
|
61
|
+
- spec/output/arrays.json
|
62
|
+
- spec/output/french.json
|
63
|
+
- spec/output/structures.json
|
64
|
+
- spec/output/unicode.json
|
65
|
+
- spec/output/values.json
|
66
|
+
- spec/output/wierd.json
|
67
|
+
- spec/spec_helper.rb
|
68
|
+
homepage: http://github.com/dryruby/json-canonicalization
|
69
|
+
licenses:
|
70
|
+
- Unlicense
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.2.2
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubygems_version: 3.0.2
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: JSON Canonicalization for Ruby.
|
91
|
+
test_files:
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
- spec/c14n_spec.rb
|
94
|
+
- spec/number_spec.rb
|
95
|
+
- spec/input/french.json
|
96
|
+
- spec/input/arrays.json
|
97
|
+
- spec/input/structures.json
|
98
|
+
- spec/input/unicode.json
|
99
|
+
- spec/input/wierd.json
|
100
|
+
- spec/input/values.json
|
101
|
+
- spec/output/french.json
|
102
|
+
- spec/output/arrays.json
|
103
|
+
- spec/output/structures.json
|
104
|
+
- spec/output/unicode.json
|
105
|
+
- spec/output/wierd.json
|
106
|
+
- spec/output/values.json
|