RFC8259 8259

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +61 -0
  3. data/.rspec +4 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +58 -0
  6. data/LICENSE.txt +40 -0
  7. data/README.txt +1 -0
  8. data/RFC8259 +899 -0
  9. data/RFC8259.gemspec +89 -0
  10. data/Rakefile +86 -0
  11. data/lib/RFC8259.rb +94 -0
  12. data/lib/RFC8259/array.rb +136 -0
  13. data/lib/RFC8259/dumper.rb +255 -0
  14. data/lib/RFC8259/false.rb +79 -0
  15. data/lib/RFC8259/null.rb +79 -0
  16. data/lib/RFC8259/number.rb +149 -0
  17. data/lib/RFC8259/object.rb +137 -0
  18. data/lib/RFC8259/parser.ry +275 -0
  19. data/lib/RFC8259/string.rb +226 -0
  20. data/lib/RFC8259/true.rb +79 -0
  21. data/lib/RFC8259/value.rb +96 -0
  22. data/lib/RFC8259/version.rb +46 -0
  23. data/spec/RFC8259_spec.rb +305 -0
  24. data/spec/acceptance/README.txt +66 -0
  25. data/spec/acceptance/invalid/0001-ws/0001-verical-tab.txt +1 -0
  26. data/spec/acceptance/invalid/0001-ws/0002-null.txt +0 -0
  27. data/spec/acceptance/invalid/0001-ws/0003-space-in-number-1.txt +1 -0
  28. data/spec/acceptance/invalid/0001-ws/0004-space-in-number-2.txt +1 -0
  29. data/spec/acceptance/invalid/0001-ws/0005-space-in-number-3.txt +1 -0
  30. data/spec/acceptance/invalid/0001-ws/0006-space-in-number-4.txt +1 -0
  31. data/spec/acceptance/invalid/0001-ws/0007-space-in-number-5.txt +1 -0
  32. data/spec/acceptance/invalid/0001-ws/0008-space-in-number-6.txt +1 -0
  33. data/spec/acceptance/invalid/0001-ws/0009-space-in-literal.txt +1 -0
  34. data/spec/acceptance/invalid/0001-ws/0010-Unicode-LINE_SEPARATOR.txt +1 -0
  35. data/spec/acceptance/invalid/0002-comments/0001-C-style.txt +1 -0
  36. data/spec/acceptance/invalid/0002-comments/0002-C-plusplus-style.txt +2 -0
  37. data/spec/acceptance/invalid/0002-comments/0003-sh-style.txt +2 -0
  38. data/spec/acceptance/invalid/0002-comments/0004-python-docstring.txt +3 -0
  39. data/spec/acceptance/invalid/0002-comments/0005-SQL-style.txt +2 -0
  40. data/spec/acceptance/invalid/0002-comments/0006-BASIC-style.txt +2 -0
  41. data/spec/acceptance/invalid/0003-literals/0001-FALSE.txt +1 -0
  42. data/spec/acceptance/invalid/0003-literals/0002-NULL.txt +1 -0
  43. data/spec/acceptance/invalid/0003-literals/0003-TRUE.txt +1 -0
  44. data/spec/acceptance/invalid/0003-literals/0004-NUL.txt +1 -0
  45. data/spec/acceptance/invalid/0003-literals/0005-nil.txt +1 -0
  46. data/spec/acceptance/invalid/0003-literals/0006-undef.txt +1 -0
  47. data/spec/acceptance/invalid/0003-literals/0007-modifier.txt +1 -0
  48. data/spec/acceptance/invalid/0003-literals/0008-undefined.txt +1 -0
  49. data/spec/acceptance/invalid/0004-numbers/0001-omit-zero.txt +1 -0
  50. data/spec/acceptance/invalid/0004-numbers/0002-minus-dot.txt +1 -0
  51. data/spec/acceptance/invalid/0004-numbers/0003-missing-frac.txt +1 -0
  52. data/spec/acceptance/invalid/0004-numbers/0004-missing-exp.txt +1 -0
  53. data/spec/acceptance/invalid/0004-numbers/0005-octal.txt +1 -0
  54. data/spec/acceptance/invalid/0004-numbers/0006-hexadecimal.txt +1 -0
  55. data/spec/acceptance/invalid/0004-numbers/0007-comma.txt +1 -0
  56. data/spec/acceptance/invalid/0004-numbers/0008-perl-underscore.txt +1 -0
  57. data/spec/acceptance/invalid/0004-numbers/0009-NaN.txt +1 -0
  58. data/spec/acceptance/invalid/0004-numbers/0010-Inf.txt +1 -0
  59. data/spec/acceptance/invalid/0004-numbers/0011-Infinity.txt +1 -0
  60. data/spec/acceptance/invalid/0005-strings/0000-NUL.txt +0 -0
  61. data/spec/acceptance/invalid/0005-strings/0001-not-terminated.txt +1 -0
  62. data/spec/acceptance/invalid/0005-strings/0002-single-quote.txt +1 -0
  63. data/spec/acceptance/invalid/0005-strings/0003-back-quote.txt +1 -0
  64. data/spec/acceptance/invalid/0005-strings/0004-carriage-return.txt +1 -0
  65. data/spec/acceptance/invalid/0005-strings/0005-line-feed.txt +2 -0
  66. data/spec/acceptance/invalid/0005-strings/0006-unknown-escape-a.txt +1 -0
  67. data/spec/acceptance/invalid/0005-strings/0007-unknown-escape-perl-style.txt +1 -0
  68. data/spec/acceptance/invalid/0005-strings/0008-unknown-escape-C-style.txt +1 -0
  69. data/spec/acceptance/invalid/0005-strings/0009-unknown-escape-ruby-style.txt +1 -0
  70. data/spec/acceptance/invalid/0005-strings/0010-escape-too-short.txt +1 -0
  71. data/spec/acceptance/invalid/0005-strings/0011-C-string-concat.txt +1 -0
  72. data/spec/acceptance/invalid/0005-strings/0012-perl-string-concat.txt +1 -0
  73. data/spec/acceptance/invalid/0005-strings/0013-Java-string-concat.txt +1 -0
  74. data/spec/acceptance/invalid/0006-encodings/0001-CESU-8.txt +1 -0
  75. data/spec/acceptance/invalid/0006-encodings/0002-Windows-31J.txt +1 -0
  76. data/spec/acceptance/invalid/0006-encodings/0003-EBCDIC.txt +1 -0
  77. data/spec/acceptance/invalid/0006-encodings/0004-overlong-utf8.txt +1 -0
  78. data/spec/acceptance/invalid/0007-arrays/0001-lacks-open.txt +1 -0
  79. data/spec/acceptance/invalid/0007-arrays/0002-lacks-close.txt +1 -0
  80. data/spec/acceptance/invalid/0007-arrays/0003-interleaving-parens.txt +1 -0
  81. data/spec/acceptance/invalid/0007-arrays/0004-dangling-comma.txt +1 -0
  82. data/spec/acceptance/invalid/0007-arrays/0005-missing-comma.txt +1 -0
  83. data/spec/acceptance/invalid/0007-arrays/0006-colon-instead-of-comma.txt +1 -0
  84. data/spec/acceptance/invalid/0008-hashes/0001-key-missing.txt +1 -0
  85. data/spec/acceptance/invalid/0008-hashes/0002-value-missing.txt +1 -0
  86. data/spec/acceptance/invalid/0008-hashes/0003-true-key.txt +1 -0
  87. data/spec/acceptance/invalid/0008-hashes/0004-false-key.txt +1 -0
  88. data/spec/acceptance/invalid/0008-hashes/0005-null-key.txt +1 -0
  89. data/spec/acceptance/invalid/0008-hashes/0006-numeric-key.txt +1 -0
  90. data/spec/acceptance/invalid/0008-hashes/0007-array-key.txt +1 -0
  91. data/spec/acceptance/invalid/0008-hashes/0008-hash-key.txt +1 -0
  92. data/spec/acceptance/invalid/0008-hashes/0009-key-not-escaped.txt +4 -0
  93. data/spec/acceptance/invalid/0009-javascriptisms/0001-JSONP.txt +1 -0
  94. data/spec/acceptance/invalid/0009-javascriptisms/0002-new-Array.txt +3 -0
  95. data/spec/acceptance/invalid/0009-javascriptisms/0003-new-Date.txt +1 -0
  96. data/spec/acceptance/invalid/0009-javascriptisms/0004-new-Error.txt +1 -0
  97. data/spec/acceptance/invalid/0009-javascriptisms/0005-Math.txt +1 -0
  98. data/spec/acceptance/invalid/0009-javascriptisms/0006-regular-expression.txt +1 -0
  99. data/spec/acceptance/invalid/0009-javascriptisms/0007-function.txt +7 -0
  100. data/spec/acceptance/invalid/0009-javascriptisms/0008-this.txt +1 -0
  101. data/spec/acceptance/invalid/0009-javascriptisms/0009-plusplus.txt +3 -0
  102. data/spec/acceptance/invalid/0009-javascriptisms/0010-ternary-operator.txt +1 -0
  103. data/spec/acceptance/valid/0001-ws/0001-space.json +1 -0
  104. data/spec/acceptance/valid/0001-ws/0002-tab.json +1 -0
  105. data/spec/acceptance/valid/0001-ws/0003-lf.json +1 -0
  106. data/spec/acceptance/valid/0001-ws/0004-cr.json +1 -0
  107. data/spec/acceptance/valid/0001-ws/0005-before.json +1 -0
  108. data/spec/acceptance/valid/0001-ws/0006-after.json +1 -0
  109. data/spec/acceptance/valid/0001-ws/0007-around-comma.json +3 -0
  110. data/spec/acceptance/valid/0001-ws/0008-around-colon.json +3 -0
  111. data/spec/acceptance/valid/0002-bare-values/0001-false.json +1 -0
  112. data/spec/acceptance/valid/0002-bare-values/0002-null.json +1 -0
  113. data/spec/acceptance/valid/0002-bare-values/0003-true.json +1 -0
  114. data/spec/acceptance/valid/0002-bare-values/0004-number.json +1 -0
  115. data/spec/acceptance/valid/0002-bare-values/0005-string.json +1 -0
  116. data/spec/acceptance/valid/0003-literals/0001-false.json +1 -0
  117. data/spec/acceptance/valid/0003-literals/0002-null.json +1 -0
  118. data/spec/acceptance/valid/0003-literals/0003-true.json +1 -0
  119. data/spec/acceptance/valid/0004-numbers/0000-zero.json +1 -0
  120. data/spec/acceptance/valid/0004-numbers/0001-one.json +1 -0
  121. data/spec/acceptance/valid/0004-numbers/0002-two.json +1 -0
  122. data/spec/acceptance/valid/0004-numbers/0003-three.json +1 -0
  123. data/spec/acceptance/valid/0004-numbers/0004-four.json +1 -0
  124. data/spec/acceptance/valid/0004-numbers/0005-five.json +1 -0
  125. data/spec/acceptance/valid/0004-numbers/0006-six.json +1 -0
  126. data/spec/acceptance/valid/0004-numbers/0007-seven.json +1 -0
  127. data/spec/acceptance/valid/0004-numbers/0008-eight.json +1 -0
  128. data/spec/acceptance/valid/0004-numbers/0009-nine.json +1 -0
  129. data/spec/acceptance/valid/0004-numbers/0010-ten.json +1 -0
  130. data/spec/acceptance/valid/0004-numbers/0011-minus.json +1 -0
  131. data/spec/acceptance/valid/0004-numbers/0012-fraction.json +1 -0
  132. data/spec/acceptance/valid/0004-numbers/0013-exponent.json +1 -0
  133. data/spec/acceptance/valid/0004-numbers/0014-exponent-minus.json +1 -0
  134. data/spec/acceptance/valid/0004-numbers/0015-exponent-plus.json +1 -0
  135. data/spec/acceptance/valid/0004-numbers/0016-complex.json +1 -0
  136. data/spec/acceptance/valid/0004-numbers/0017-DBL_MAX.json +1 -0
  137. data/spec/acceptance/valid/0004-numbers/0018-DBL_MIN.json +1 -0
  138. data/spec/acceptance/valid/0004-numbers/0019-subnormal-number.json +1 -0
  139. data/spec/acceptance/valid/0004-numbers/0020-1E400.json +1 -0
  140. data/spec/acceptance/valid/0004-numbers/0021-pi.json +1 -0
  141. data/spec/acceptance/valid/0004-numbers/0022-UINT32_MAX.json +1 -0
  142. data/spec/acceptance/valid/0004-numbers/0023-UINT64_MAX.json +1 -0
  143. data/spec/acceptance/valid/0004-numbers/0024-INT64_MIN.json +1 -0
  144. data/spec/acceptance/valid/0004-numbers/0025-high-resolution-zero.json +1 -0
  145. data/spec/acceptance/valid/0004-numbers/0026-high-resolution-100.json +1 -0
  146. data/spec/acceptance/valid/0005-strings/0001-empty.json +1 -0
  147. data/spec/acceptance/valid/0005-strings/0002-basic-latin.json +1 -0
  148. data/spec/acceptance/valid/0005-strings/0003-escapes.json +1 -0
  149. data/spec/acceptance/valid/0005-strings/0004-raw-unicode.json +1 -0
  150. data/spec/acceptance/valid/0005-strings/0005-escaped-unicode.json +1 -0
  151. data/spec/acceptance/valid/0005-strings/0006-escaped-NUL.json +1 -0
  152. data/spec/acceptance/valid/0005-strings/0007-escaped-invalid-unicode-still-valid-as-json.json +1 -0
  153. data/spec/acceptance/valid/0005-strings/0008-ruby-json-gem-cant-handle-this.json +1 -0
  154. data/spec/acceptance/valid/0005-strings/0009-unescaped-invalid-javascript-still-valid-as-json.json +1 -0
  155. data/spec/acceptance/valid/0005-strings/0010-escaped-separated-surrogate.json +1 -0
  156. data/spec/acceptance/valid/0005-strings/0011-escaped-surrogate-then-normal.json +1 -0
  157. data/spec/acceptance/valid/0006-m17n/0001-genesis.json +6 -0
  158. data/spec/acceptance/valid/0006-m17n/0002-heart-sutra.json +5 -0
  159. data/spec/acceptance/valid/0006-m17n/0003-escaped-valid-surrogate-pair.json +1 -0
  160. data/spec/acceptance/valid/0006-m17n/0004-unescaped-valid-supplementary-multilingual-plane.json +1 -0
  161. data/spec/acceptance/valid/0007-arrays/0000-empty.json +1 -0
  162. data/spec/acceptance/valid/0007-arrays/0001-one-element.json +1 -0
  163. data/spec/acceptance/valid/0007-arrays/0002-multiple-elements.json +33 -0
  164. data/spec/acceptance/valid/0007-arrays/0003-various-types.json +1 -0
  165. data/spec/acceptance/valid/0007-arrays/0004-nested.json +17 -0
  166. data/spec/acceptance/valid/0008-hashes/0000-empty.json +1 -0
  167. data/spec/acceptance/valid/0008-hashes/0001-onekey.json +1 -0
  168. data/spec/acceptance/valid/0008-hashes/0002-many-keys.json +5 -0
  169. data/spec/acceptance/valid/0008-hashes/0003-empty-key.json +3 -0
  170. data/spec/acceptance/valid/0008-hashes/0004-true-value.json +3 -0
  171. data/spec/acceptance/valid/0008-hashes/0005-false-value.json +3 -0
  172. data/spec/acceptance/valid/0008-hashes/0006-null-value.json +3 -0
  173. data/spec/acceptance/valid/0008-hashes/0007-string-value.json +3 -0
  174. data/spec/acceptance/valid/0008-hashes/0008-numeric-value.json +3 -0
  175. data/spec/acceptance/valid/0008-hashes/0009-array-value.json +8 -0
  176. data/spec/acceptance/valid/0008-hashes/0010-hash-value.json +20 -0
  177. data/spec/acceptance/valid/0008-hashes/0011-duplicate-key.json +4 -0
  178. data/spec/acceptance/valid/0008-hashes/0012-duplicate-key-in-different-representations.json +4 -0
  179. data/spec/acceptance/valid/0009-complicated/0001-jsonschema.json +46 -0
  180. data/spec/acceptance/valid/0009-complicated/0002-example-in-RFC7159-section-13.json +14 -0
  181. data/spec/acceptance/valid/0009-complicated/0003-example-in-RFC7159-section-13.json +22 -0
  182. data/spec/spec_helper.rb +60 -0
  183. metadata +530 -0
@@ -0,0 +1,89 @@
1
+ #! /your/favourite/path/to/gem
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright (c) 2014 Urabe, Shyouhei. All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # - Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # - Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in
14
+ # the documentation and/or other materials provided with the
15
+ # distribution.
16
+ #
17
+ # - Neither the name of Internet Society, IETF or IETF Trust, nor the
18
+ # names of specific contributors, may be used to endorse or promote
19
+ # products derived from this software without specific prior written
20
+ # permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ # coding: utf-8
35
+
36
+ # hack avoid namespace pollution
37
+ path = File.expand_path 'lib/RFC8259/version.rb', __dir__
38
+ content = File.read path
39
+ version = Module.new.module_eval <<-'end'
40
+ RFC8259 = Module.new
41
+ eval content, binding, path
42
+ end
43
+
44
+ Gem::Specification.new do |spec|
45
+ spec.name = 'RFC8259'
46
+ spec.version = version
47
+ spec.authors = %w'Urabe, Shyouhei'
48
+ spec.email = %w'shyouhei@ruby-lang.org'
49
+ spec.summary = 'RFC8259 parser / generator'
50
+ spec.description = <<-'end'.gsub(/[\n\s]+/, ' ').strip
51
+ A JSON parser/generator that conforms (I believe) to RFC8259 "The
52
+ JavaScript Object Notation (JSON) Data Interchange Format". This gem
53
+ honors the syntax as possible. The generator guarantees that a parsed
54
+ valid properly rounds-trip to identical valid JSON representation.
55
+ end
56
+ spec.homepage = 'http://github.com/shyouhei/RFC8259'
57
+ spec.license = "Simplified BSD License" # consult LICENSE.txt
58
+
59
+ spec.files = `git ls-files -z`.split("\x0") + %w'lib/RFC8259/parser.rb'
60
+ spec.executables = %w''
61
+ spec.test_files = spec.files.grep(%r{^spec/})
62
+ spec.require_paths = %w'lib'
63
+
64
+ spec.required_ruby_version = '~> 2.0'
65
+ spec.add_development_dependency 'bundler', '~> 1.5'
66
+ spec.add_development_dependency 'rake', '~> 10.1'
67
+ spec.add_development_dependency 'rdoc', '~> 4.0'
68
+ spec.add_development_dependency 'yard', '~> 0.8'
69
+ spec.add_development_dependency 'rspec', '~> 2.14'
70
+ spec.add_development_dependency 'simplecov', '>= 0'
71
+ spec.add_development_dependency 'racc', '~> 1.4.11'
72
+ # racc runtime is inside ruby's stdlib so no runtime dependency.
73
+
74
+ # below are only for comparisons
75
+ spec.add_development_dependency 'json' # 1.8.1 tested
76
+ spec.add_development_dependency 'yajl-ruby' # 1.2.0 tested
77
+ spec.add_development_dependency 'oj' # 2.6.1 tested
78
+ end
79
+
80
+ #
81
+ # Local Variables:
82
+ # mode: ruby
83
+ # coding: utf-8-unix
84
+ # indent-tabs-mode: t
85
+ # tab-width: 3
86
+ # ruby-indent-level: 3
87
+ # fill-column: 79
88
+ # default-justification: full
89
+ # End:
@@ -0,0 +1,86 @@
1
+ #! /your/favourite/path/to/rake
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright (c) 2014 Urabe, Shyouhei. All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # - Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # - Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in
14
+ # the documentation and/or other materials provided with the
15
+ # distribution.
16
+ #
17
+ # - Neither the name of Internet Society, IETF or IETF Trust, nor the
18
+ # names of specific contributors, may be used to endorse or promote
19
+ # products derived from this software without specific prior written
20
+ # permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ require 'rubygems'
35
+ require 'bundler'
36
+ require 'rake'
37
+ begin
38
+ require "bundler/gem_tasks"
39
+ Bundler.setup(:default, :development)
40
+ rescue Bundler::BundlerError => e
41
+ $stderr.puts e.message
42
+ $stderr.puts "Run `bundle install` to install missing gems"
43
+ exit e.status_code
44
+ end
45
+
46
+ require 'rspec/core'
47
+ require 'rspec/core/rake_task'
48
+ RSpec::Core::RakeTask.new(:spec) do |spec|
49
+ spec.pattern = FileList['spec/**/*_spec.rb']
50
+ end
51
+
52
+ require 'yard'
53
+ YARD::Rake::YardocTask.new
54
+
55
+ task yard: 'lib/RFC8259/parser.rb'
56
+ task rdoc: 'lib/RFC8259/parser.rb'
57
+ task build: 'lib/RFC8259/parser.rb'
58
+ task spec: 'lib/RFC8259/parser.rb'
59
+ file 'lib/RFC8259/parser.rb' => %w'lib/RFC8259/parser.ry' do |t|
60
+ sh "bundle exec racc --debug --output-file=#{t.name} #{t.prerequisites.first}"
61
+ end
62
+
63
+ desc "a la rails console"
64
+ task :console do
65
+ require_relative 'lib/RFC8259'
66
+ require 'json'
67
+ require 'yajl'
68
+ require 'oj'
69
+ require 'irb'
70
+ require 'irb/completion'
71
+ ARGV.clear
72
+ IRB.start
73
+ end
74
+
75
+ task default: :spec
76
+
77
+ #
78
+ # Local Variables:
79
+ # mode: ruby
80
+ # coding: utf-8-unix
81
+ # indent-tabs-mode: t
82
+ # tab-width: 3
83
+ # ruby-indent-level: 3
84
+ # fill-column: 79
85
+ # default-justification: full
86
+ # End:
@@ -0,0 +1,94 @@
1
+ #! /your/favourite/path/to/ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright (c) 2014 Urabe, Shyouhei. All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # - Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # - Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in
14
+ # the documentation and/or other materials provided with the
15
+ # distribution.
16
+ #
17
+ # - Neither the name of Internet Society, IETF or IETF Trust, nor the
18
+ # names of specific contributors, may be used to endorse or promote
19
+ # products derived from this software without specific prior written
20
+ # permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ # This is a RFC8259-conforming JSON parser/generator.
35
+ module RFC8259
36
+ require_relative 'RFC8259/parser'
37
+ require_relative 'RFC8259/value'
38
+ require_relative 'RFC8259/dumper'
39
+
40
+ # This is our Marshal.load -compat API
41
+ # @param [::String, IO] str The input
42
+ # @param [true, false] plain Output to be plain-old ruby object, or not.
43
+ # @return [::Object] Evaluated plain-old ruby object
44
+ # @return [RFC8259::Value] Evaluated JSON value object
45
+ # @raise [Racc::ParseError] The input is invalid
46
+ # @raise [Encoding::CompatibilityError] The input is invalid
47
+ def self.load str, plain: false
48
+ ast = RFC8259::Parser.new.parse str
49
+ obj = RFC8259::Value.from_ast ast
50
+ if plain
51
+ return obj.plain_old_ruby_object
52
+ else
53
+ return obj
54
+ end
55
+ end
56
+
57
+ # This is our Marshal.dump -compat API
58
+ # @param [::Object] obj The input (should be JSONable)
59
+ # @param [IO] port IO port to dump obj into
60
+ # @param [Fixnum] indent indent depth
61
+ # @param [Numeric] width page width (see {::PP})
62
+ # @return [::String] Dumped valid JSON text representation
63
+ # @return [port] Indicates the output went to the port.
64
+ # @raise [TypeError] obj not JSONable
65
+ # @raise [Errno::ELOOP] Cyclic relation(s) detected
66
+ def self.dump obj, port: ''.encode(Encoding::UTF_8), indent: 4, width: Math.atanh(1)
67
+ bag = RFC8259::Dumper.new port, indent, width
68
+ bag.start_dump obj
69
+ return port
70
+ end
71
+
72
+ # (Experimental) Sometimes JSON is required somewhere inside of a
73
+ # pretty-print, and you might want to inherit the indentation(s) of
74
+ # surrounding PP structure. In order to do so here we propose a dump
75
+ # variant that takes a PP object rather than destination IO.
76
+ # @param [::Object] obj The input (should be JSONable)
77
+ # @param [PP] pp The PP.
78
+ def self.pp_object pp, obj, indent=4
79
+ bag = RFC8259::Dumper.new nil, indent, nil, pp
80
+ bag.start_dump obj
81
+ return nil
82
+ end
83
+ end
84
+
85
+ #
86
+ # Local Variables:
87
+ # mode: ruby
88
+ # coding: utf-8-unix
89
+ # indent-tabs-mode: t
90
+ # tab-width: 3
91
+ # ruby-indent-level: 3
92
+ # fill-column: 79
93
+ # default-justification: full
94
+ # End:
@@ -0,0 +1,136 @@
1
+ #! /your/favourite/path/to/ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright (c) 2014 Urabe, Shyouhei. All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # - Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # - Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in
14
+ # the documentation and/or other materials provided with the
15
+ # distribution.
16
+ #
17
+ # - Neither the name of Internet Society, IETF or IETF Trust, nor the
18
+ # names of specific contributors, may be used to endorse or promote
19
+ # products derived from this software without specific prior written
20
+ # permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ # The Arrays, as described in RFC8259 section 5.
35
+ class RFC8259::Array < RFC8259::Value
36
+
37
+ # Parse the AST from parser, and convert into corrsponding values.
38
+ # @param [::Array] ast the AST, generated by the parser
39
+ # @return [Array] evaluated instance
40
+ # @raise [ArgumentError] malformed input
41
+ def self.from_ast ast
42
+ type, *ary = *ast
43
+ raise ArgumentError, "not an object: #{ast.inspect}" if type != :array
44
+ ary.map! do |a|
45
+ RFC8259::Value.from_ast a
46
+ end
47
+ new ary
48
+ end
49
+
50
+ # fetch the index
51
+ # @param [Integer] idx index to obtain
52
+ # @return [Value] corresponding value
53
+ # @return [nil] not found / out of bounds
54
+ def [] idx
55
+ @array[idx]
56
+ end
57
+
58
+ # iterate over the contents
59
+ # @yield [RFC8259::Value] element
60
+ def each &b
61
+ @array.each(&b)
62
+ end
63
+
64
+ # @return [Integer] the count of elements
65
+ def size
66
+ @array.size
67
+ end
68
+
69
+ alias length size
70
+
71
+ # equality
72
+ # @param [Array] other comparison target
73
+ # @return [true] they are equal
74
+ # @return [false] otherwise.
75
+ def == other
76
+ return false unless length == other.length
77
+ @array.each_index do |i|
78
+ j = @array[i]
79
+ k = other[i]
80
+ return false unless j == k
81
+ end
82
+ return true
83
+ end
84
+
85
+ # @return [::Array] converted array
86
+ def plain_old_ruby_object
87
+ @array.map do |i|
88
+ i.plain_old_ruby_object
89
+ end
90
+ end
91
+
92
+ alias to_a plain_old_ruby_object
93
+ alias to_ary plain_old_ruby_object
94
+
95
+ # JSON gem compat
96
+ # @return [::String] JSONified representation
97
+ def to_json
98
+ RFC8259::Dumper.new.dump self
99
+ end
100
+
101
+ # @return [::String] the array in string
102
+ def inspect
103
+ sprintf "#<%p:%#016x %p>", self.class, self.object_id << 1, @array
104
+ end
105
+
106
+ # For pretty print
107
+ # @param [PP] pp the pp
108
+ def pretty_print pp
109
+ hdr = sprintf '#<%p:%#016x', self.class, self.object_id << 1
110
+ pp.group 1, hdr, '>' do
111
+ pp.text ' '
112
+ RFC8259::Dumper.kandr pp, 1, @array.each, '[', ']' do |i|
113
+ i.pretty_print pp
114
+ end
115
+ end
116
+ end
117
+
118
+ private
119
+ private_class_method:new
120
+ # @private
121
+ def initialize ary
122
+ @array = ary
123
+ @array.freeze
124
+ end
125
+ end
126
+
127
+ #
128
+ # Local Variables:
129
+ # mode: ruby
130
+ # coding: utf-8-unix
131
+ # indent-tabs-mode: t
132
+ # tab-width: 3
133
+ # ruby-indent-level: 3
134
+ # fill-column: 79
135
+ # default-justification: full
136
+ # End:
@@ -0,0 +1,255 @@
1
+ #! /your/favourite/path/to/ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright (c) 2014 Urabe, Shyouhei. All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # - Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # - Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in
14
+ # the documentation and/or other materials provided with the
15
+ # distribution.
16
+ #
17
+ # - Neither the name of Internet Society, IETF or IETF Trust, nor the
18
+ # names of specific contributors, may be used to endorse or promote
19
+ # products derived from this software without specific prior written
20
+ # permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ require_relative 'value'
35
+ require 'prettyprint'
36
+
37
+ # Dumps ruby object into JSON string
38
+ class RFC8259::Dumper
39
+
40
+ # much like PP#object_group, except that it indents like K&R.
41
+ def self.kandr pp, indent, enum, open, close
42
+ pp.text open
43
+ pp.group_sub do
44
+ pp.nest indent do
45
+ enum.with_index do |a, i|
46
+ if i > 0
47
+ pp.text ','
48
+ end
49
+ pp.breakable ' '
50
+ yield a
51
+ end
52
+ end
53
+ pp.breakable ' '
54
+ end
55
+ pp.text close
56
+ end
57
+
58
+ # @param [#<<] port output destination
59
+ def initialize port, indent = 4, width = 79, pp = PrettyPrint.new(port, width)
60
+ @port = port
61
+ @bag = Hash.new
62
+ @indent = indent
63
+ @pp = pp
64
+ @bag.compare_by_identity
65
+ end
66
+
67
+ # @param [::Object] target target to dump
68
+ # @return [self] self.
69
+ def start_dump target
70
+ dump target
71
+ return self
72
+ ensure
73
+ @bag.clear
74
+ @pp.flush
75
+ end
76
+
77
+ private
78
+
79
+ def dump obj
80
+ obj2 = try_convert obj
81
+ case obj2
82
+ when ::Array, RFC8259::Array then
83
+ kandr obj2, :each, '[', ']' do |i|
84
+ dump i
85
+ end
86
+ when ::Hash, RFC8259::Object then
87
+ kandr obj2, :each_pair, '{', '}' do |(i, j)|
88
+ case i
89
+ when ::String, RFC8259::String
90
+ dump i
91
+ else
92
+ dump i.to_str # should raise for non-string-ish
93
+ end
94
+ @pp.text ': '
95
+ dump j
96
+ end
97
+ when RFC8259::Value then
98
+ obj3 = obj2.to_json
99
+ @pp.text obj3
100
+ when ::String then
101
+ obj3 = try_escape_string obj2
102
+ @pp.text '"'
103
+ @pp.text obj3
104
+ @pp.text '"'
105
+ when ::Numeric then
106
+ obj3 = try_stringize_numeric obj2
107
+ @pp.text obj3
108
+ when ::TrueClass then
109
+ @pp.text 'true'
110
+ when ::FalseClass then
111
+ @pp.text 'false'
112
+ when ::NilClass then
113
+ @pp.text 'null'
114
+ else
115
+ begin
116
+ # Try fallback
117
+ @pp.text obj2.to_json
118
+ rescue NoMethodError
119
+ raise TypeError, "not JSONable: #{obj}"
120
+ end
121
+ end
122
+ end
123
+
124
+ # Check repetition. JSON is a true tree -- no cyclic lists, nor even direct
125
+ # acyclic graphs are allowed. We check that here.
126
+ #
127
+ # - strings, numbers, booleans are all OK to appear multiple times.
128
+ # - empty arrays and empty hashes are special-cased OK.
129
+ # - other cases are subject to appear exactly once.
130
+ def ensure_unique obj
131
+ if @bag.include? obj and not obj.empty?
132
+ raise Errno::ELOOP, "target appears twice: #{obj.inspect}"
133
+ else
134
+ begin
135
+ @bag.store obj, obj
136
+ yield
137
+ ensure
138
+ @bag.delete obj
139
+ end
140
+ end
141
+ end
142
+
143
+ # much like PP#object_group, except that it indents like K&R.
144
+ def kandr obj, method, open, close
145
+ ensure_unique obj do
146
+ enum = obj.enum_for method
147
+ RFC8259::Dumper.kandr @pp, @indent, enum, open, close do |obj|
148
+ yield obj
149
+ end
150
+ end
151
+ end
152
+
153
+ def try_convert obj
154
+ case obj
155
+ when RFC8259::Value, Hash, Array, String, Integer, Float, BigDecimal, TrueClass, FalseClass, NilClass
156
+ return obj
157
+ else
158
+ begin
159
+ return obj.to_hash
160
+ rescue NoMethodError
161
+ begin
162
+ return obj.to_ary
163
+ rescue NoMethodError
164
+ begin
165
+ return obj.to_str
166
+ rescue NoMethodError
167
+ begin
168
+ return obj.to_int
169
+ rescue NoMethodError
170
+ begin
171
+ return obj.to_f
172
+ rescue NoMethodError
173
+ raise TypeError, "not JSONable: #{obj.class}"
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+
182
+ def try_escape_string str
183
+ buf = nil
184
+
185
+ begin
186
+ # fast path
187
+ if str.valid_encoding?
188
+ str2 = str.encode Encoding::UTF_8
189
+ buf = str2.unpack('U*')
190
+ end
191
+ rescue Encoding::UndefinedConversionError
192
+ # str might be invalid, but that's OK as per RFC8259 section 8.2.
193
+ end
194
+
195
+ unless buf
196
+ case str.encoding
197
+ when Encoding::UTF_32BE then buf = str.unpack 'N*'
198
+ when Encoding::UTF_32LE then buf = str.unpack 'V*'
199
+ when Encoding::UTF_16BE then buf = str.unpack 'n*'
200
+ when Encoding::UTF_16LE then buf = str.unpack 'v*'
201
+ when Encoding::UTF_8,
202
+ Encoding::UTF8_MAC,
203
+ Encoding::US_ASCII then buf = str.unpack 'U*'
204
+ else buf = str.unpack 'C*' # fallback
205
+ end
206
+ end
207
+
208
+ # We don't escape \/, because that seems to be de facto standard.
209
+ return buf.inject '' do |r, i|
210
+ c = nil
211
+ case i
212
+ when 0x22 then c = '\\"' # " quotation mark U+0022
213
+ when 0x5C then c = '\\\\' # \ reverse solidus U+005C
214
+ # when 0x2F then c = '\\/' # / solidus U+002F
215
+ when 0x08 then c = '\\b' # b backspace U+0008
216
+ when 0x0C then c = '\\f' # f form feed U+000C
217
+ when 0x0A then c = '\\n' # n line feed U+000A
218
+ when 0x0D then c = '\\r' # r carriage return U+000D
219
+ when 0x09 then c = '\\t' # t tab U+0009
220
+ when 0x00..0x1F, 0xD800..0xDFFF then
221
+ c = sprintf '\\u%04X', i
222
+ else
223
+ c = [i].pack 'U'
224
+ end
225
+ r << c
226
+ end
227
+ end
228
+
229
+ def try_stringize_numeric num
230
+ case num
231
+ when Float, BigDecimal
232
+ if num.finite?
233
+ # FIXME: does this lose precision?
234
+ num.to_s
235
+ else
236
+ raise TypeError, "not JSONable: #{num.inspect}"
237
+ end
238
+ when Integer
239
+ return num.to_s
240
+ else
241
+ raise TypeError, "not JSONable: #{num.inspect}"
242
+ end
243
+ end
244
+ end
245
+
246
+ #
247
+ # Local Variables:
248
+ # mode: ruby
249
+ # coding: utf-8-unix
250
+ # indent-tabs-mode: t
251
+ # tab-width: 3
252
+ # ruby-indent-level: 3
253
+ # fill-column: 79
254
+ # default-justification: full
255
+ # End: