RFC8259 8259

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.
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: