JSON
JSON (JavaScript Object Notation)
JSON은 가벼운 데이터 교환 형식(lightweight data-interchange format)이에요.
출처: Ruby 3.3 API
본문
JSON 값은 다음 중 하나예요.
- 큰따옴표로 감싼 텍스트:
"foo". - 숫자:
1,1.0,2.0e2. - 불리언:
true,false. - null:
null. - 배열: 대괄호로 감싼 값들의 순서 있는 목록:
["foo", 1, 1.0, 2.0e2, true, false, null] - 객체: 중괄호로 감싼 이름/값 쌍들의 모음. 각 이름은 큰따옴표로 감싼 텍스트이고, 값은 어떤 JSON 값이든 될 수 있어요:
{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}
JSON 배열이나 객체는 어떤 깊이로든 중첩된 배열, 객체, 스칼라를 담을 수 있어요.
{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}
[{"foo": 0, "bar": 1}, ["baz", 2]]
JSON 모듈 사용하기 (Using Module JSON)
코드에서 JSON 모듈을 사용하려면 다음으로 시작해요.
require 'json'
여기의 모든 예시는 이 require가 되었다고 가정해요.
JSON 파싱 (Parsing JSON)
JSON 데이터를 담은 String을 두 메서드 중 하나로 파싱할 수 있어요.
JSON.parse(source, opts)JSON.parse!(source, opts)
여기서:
source는 Ruby 객체예요.opts는 허용되는 입력과 출력 형식을 제어하는 옵션을 담은 Hash 객체예요.
두 메서드의 차이는 JSON.parse!가 일부 검사를 생략해서 어떤 source 데이터에는 안전하지 않을 수 있다는 거예요. 신뢰할 수 있는 소스의 데이터에만 사용하세요. 덜 신뢰하는 소스에는 더 안전한 JSON.parse를 사용해요.
JSON 배열 파싱 (Parsing JSON Arrays)
source가 JSON 배열이면 JSON.parse는 기본적으로 Ruby Array를 돌려줘요.
json = '["foo", 1, 1.0, 2.0e2, true, false, null]'
ruby = JSON.parse(json)
ruby # => ["foo", 1, 1.0, 200.0, true, false, nil]
ruby.class # => Array
JSON 배열은 어떤 깊이로든 중첩된 배열, 객체, 스칼라를 담을 수 있어요.
json = '[{"foo": 0, "bar": 1}, ["baz", 2]]'
JSON.parse(json) # => [{"foo"=>0, "bar"=>1}, ["baz", 2]]
JSON 객체 파싱 (Parsing JSON Objects)
source가 JSON 객체이면 JSON.parse는 기본적으로 Ruby Hash를 돌려줘요.
json = '{"a": "foo", "b": 1, "c": 1.0, "d": 2.0e2, "e": true, "f": false, "g": null}'
ruby = JSON.parse(json)
ruby # => {"a"=>"foo", "b"=>1, "c"=>1.0, "d"=>200.0, "e"=>true, "f"=>false, "g"=>nil}
ruby.class # => Hash
JSON 객체는 어떤 깊이로든 중첩된 배열, 객체, 스칼라를 담을 수 있어요.
json = '{"foo": {"bar": 1, "baz": 2}, "bat": [0, 1, 2]}'
JSON.parse(json) # => {"foo"=>{"bar"=>1, "baz"=>2}, "bat"=>[0, 1, 2]}
JSON 스칼라 파싱 (Parsing JSON Scalars)
source가 JSON 스칼라(배열이나 객체가 아닌)이면 JSON.parse는 Ruby 스칼라를 돌려줘요.
String:
ruby = JSON.parse('"foo"')
ruby # => 'foo'
ruby.class # => String
Integer:
ruby = JSON.parse('1')
ruby # => 1
ruby.class # => Integer
Float:
ruby = JSON.parse('1.0')
ruby # => 1.0
ruby.class # => Float
ruby = JSON.parse('2.0e2')
ruby # => 200
ruby.class # => Float
Boolean:
ruby = JSON.parse('true')
ruby # => true
ruby.class # => TrueClass
ruby = JSON.parse('false')
ruby # => false
ruby.class # => FalseClass
Null:
ruby = JSON.parse('null')
ruby # => nil
ruby.class # => NilClass
파싱 옵션 (Parsing Options)
입력 옵션 (Input Options)
옵션 max_nesting (Integer)은 허용되는 최대 중첩 깊이를 지정해요. 기본값은 100이고, false를 지정하면 깊이 검사를 비활성화해요.
기본값과 함께:
source = '[0, [1, [2, [3]]]]'
ruby = JSON.parse(source)
ruby # => [0, [1, [2, [3]]]]
너무 깊은 경우:
# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.parse(source, {max_nesting: 1})
잘못된 값:
# Raises TypeError (wrong argument type Symbol (expected Fixnum)):
JSON.parse(source, {max_nesting: :foo})
옵션 allow_nan (boolean)은 source에서 NaN, Infinity, MinusInfinity를 허용할지 지정해요. 기본값은 false예요.
기본값과 함께:
# Raises JSON::ParserError (225: unexpected token at '[NaN]'):
JSON.parse('[NaN]')
# Raises JSON::ParserError (232: unexpected token at '[Infinity]'):
JSON.parse('[Infinity]')
# Raises JSON::ParserError (248: unexpected token at '[-Infinity]'):
JSON.parse('[-Infinity]')
허용:
source = '[NaN, Infinity, -Infinity]'
ruby = JSON.parse(source, {allow_nan: true})
ruby # => [NaN, Infinity, -Infinity]
출력 옵션 (Output Options)
옵션 symbolize_names (boolean)은 돌려주는 Hash 키가 Symbol이어야 하는지 지정해요. 기본값은 false (String 사용).
기본값과 함께:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
Symbol 사용:
ruby = JSON.parse(source, {symbolize_names: true})
ruby # => {:a=>"foo", :b=>1.0, :c=>true, :d=>false, :e=>nil}
옵션 object_class (Class)은 각 JSON 객체에 쓸 Ruby 클래스를 지정해요. 기본값은 Hash예요.
기본값과 함께:
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby.class # => Hash
OpenStruct 클래스 사용:
ruby = JSON.parse(source, {object_class: OpenStruct})
ruby # => #<OpenStruct a="foo", b=1.0, c=true, d=false, e=nil>
옵션 array_class (Class)은 각 JSON 배열에 쓸 Ruby 클래스를 지정해요. 기본값은 Array예요.
기본값과 함께:
source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby.class # => Array
Set 클래스 사용:
ruby = JSON.parse(source, {array_class: Set})
ruby # => #<Set: {"foo", 1.0, true, false, nil}>
옵션 create_additions (boolean)은 파싱에서 JSON 추가(addition)를 사용할지 지정해요. "JSON Additions" 참고.
JSON 생성 (Generating JSON)
JSON 데이터를 담은 Ruby String을 만들려면 JSON.generate(source, opts) 메서드를 사용해요.
source는 Ruby 객체예요.opts는 허용되는 입력과 출력 형식을 제어하는 옵션을 담은 Hash 객체예요.
배열에서 JSON 생성 (Generating JSON from Arrays)
source가 Ruby Array이면 JSON.generate는 JSON 배열을 담은 String을 돌려줘요.
ruby = [0, 's', :foo]
json = JSON.generate(ruby)
json # => '[0,"s","foo"]'
Ruby Array 배열은 어떤 깊이로든 중첩된 배열, 해시, 스칼라를 담을 수 있어요.
ruby = [0, [1, 2], {foo: 3, bar: 4}]
json = JSON.generate(ruby)
json # => '[0,[1,2],{"foo":3,"bar":4}]'
해시에서 JSON 생성 (Generating JSON from Hashes)
source가 Ruby Hash이면 JSON.generate는 JSON 객체를 담은 String을 돌려줘요.
ruby = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(ruby)
json # => '{"foo":0,"bar":"s","baz":"bat"}'
Ruby Hash 배열은 어떤 깊이로든 중첩된 배열, 해시, 스칼라를 담을 수 있어요.
ruby = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.generate(ruby)
json # => '{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}'
다른 객체에서 JSON 생성 (Generating JSON from Other Objects)
source가 Array도 Hash도 아니면, 생성된 JSON 데이터는 source의 클래스에 따라 달라져요.
source가 Ruby Integer나 Float이면 JSON.generate는 JSON 숫자를 담은 String을 돌려줘요.
JSON.generate(42) # => '42'
JSON.generate(0.42) # => '0.42'
source가 Ruby String이면 JSON.generate는 JSON 문자열(큰따옴표 포함)을 담은 String을 돌려줘요.
JSON.generate('A string') # => '"A string"'
source가 true, false, nil이면 JSON.generate는 대응하는 JSON 토큰을 담은 String을 돌려줘요.
JSON.generate(true) # => 'true'
JSON.generate(false) # => 'false'
JSON.generate(nil) # => 'null'
source가 위의 어느 것도 아니면 JSON.generate는 source의 JSON 문자열 표현을 담은 String을 돌려줘요.
JSON.generate(:foo) # => '"foo"'
JSON.generate(Complex(0, 0)) # => '"0+0i"'
JSON.generate(Dir.new('.')) # => '"#<Dir>"'
생성 옵션 (Generating Options)
입력 옵션 (Input Options)
옵션 allow_nan (boolean)은 NaN, Infinity, -Infinity를 생성할 수 있는지 지정해요. 기본값은 false예요.
기본값과 함께:
# Raises JSON::GeneratorError (920: NaN not allowed in JSON):
JSON.generate(JSON::NaN)
# Raises JSON::GeneratorError (917: Infinity not allowed in JSON):
JSON.generate(JSON::Infinity)
# Raises JSON::GeneratorError (917: -Infinity not allowed in JSON):
JSON.generate(JSON::MinusInfinity)
허용:
ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
옵션 max_nesting (Integer)은 obj에서의 최대 중첩 깊이를 지정해요. 기본값은 100이에요.
기본값과 함께:
obj = [[[[[[0]]]]]]
JSON.generate(obj) # => '[[[[[[0]]]]]]'
너무 깊은 경우:
# Raises JSON::NestingError (nesting of 2 is too deep):
JSON.generate(obj, max_nesting: 2)
이스케이프 옵션 (Escaping Options)
옵션 script_safe (boolean)은 '\u2028', '\u2029', '/'를 이스케이프해서 JSON 객체가 script 태그에 안전하게 삽입되도록 할지 지정해요.
옵션 ascii_only (boolean)은 ASCII 범위 밖의 모든 문자를 이스케이프할지 지정해요.
출력 옵션 (Output Options)
기본 형식 옵션들은 가장 압축된 JSON 데이터를 생성해요. 모두 한 줄에, 공백 없이요.
이 형식 옵션들을 사용해서 공백을 이용한 더 열린 형식의 JSON 데이터를 생성할 수 있어요. JSON.pretty_generate도 참고하세요.
- 옵션
array_nl(String)은 각 JSON 배열 뒤에 삽입할 문자열(보통 개행)을 지정해요. 기본값은 빈 String''. - 옵션
object_nl(String)은 각 JSON 객체 뒤에 삽입할 문자열(보통 개행)을 지정해요. 기본값은 빈 String''. - 옵션
indent(String)은 들여쓰기에 쓸 문자열(보통 공백)을 지정해요. 기본값은 빈 String''.array_nl이나object_nl이 개행을 지정하지 않으면 효과가 없어요. - 옵션
space(String)은 각 JSON 객체 쌍의 콜론 뒤에 삽입할 문자열(보통 공백)을 지정해요. 기본값은 빈 String''. - 옵션
space_before(String)은 각 JSON 객체 쌍의 콜론 앞에 삽입할 문자열(보통 공백)을 지정해요. 기본값은 빈 String''.
이 예시에서 obj를 먼저 가장 짧은 JSON 데이터(공백 없음) 생성에 쓰고, 다시 모든 형식 옵션을 지정해 사용해요.
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.generate(obj)
puts 'Compact:', json
opts = {
array_nl: "\n",
object_nl: "\n",
indent: ' ',
space_before: ' ',
space: ' '
}
puts 'Open:', JSON.generate(obj, opts)
출력:
Compact:
{"foo":["bar","baz"],"bat":{"bam":0,"bad":1}}
Open:
{
"foo" : [
"bar",
"baz"
],
"bat" : {
"bam" : 0,
"bad" : 1
}
}
JSON 추가 (JSON Additions)
String이 아닌 객체를 Ruby에서 JSON으로 갔다가 다시(round trip) 오면, 처음 시작한 객체 대신 새로운 String을 얻게 돼요.
ruby0 = Range.new(0, 2)
json = JSON.generate(ruby0)
json # => '0..2"'
ruby1 = JSON.parse(json)
ruby1 # => '0..2'
ruby1.class # => String
JSON 추가(addition)를 사용하면 원래 객체를 보존할 수 있어요. 추가는 Ruby 클래스의 확장이라서:
JSON.generate는 JSON 문자열에 더 많은 정보를 저장해요.- 옵션
create_additions로 호출된JSON.parse는 그 정보를 사용해 적절한 Ruby 객체를 만들어요.
이 예시는 Range가 JSON으로 생성되고 Ruby로 다시 파싱되는 걸 보여줘요. Range용 추가를 쓰지 않은 경우와 쓴 경우 모두요.
ruby = Range.new(0, 2)
# This passage does not use the addition for Range.
json0 = JSON.generate(ruby)
ruby0 = JSON.parse(json0)
# This passage uses the addition for Range.
require 'json/add/range'
json1 = JSON.generate(ruby)
ruby1 = JSON.parse(json1, create_additions: true)
# Make a nice display.
display = <<EOT
Generated JSON:
Without addition: #{json0} (#{json0.class})
With addition: #{json1} (#{json1.class})
Parsed JSON:
Without addition: #{ruby0.inspect} (#{ruby0.class})
With addition: #{ruby1.inspect} (#{ruby1.class})
EOT
puts display
이 출력은 다른 결과를 보여줘요.
Generated JSON:
Without addition: "0..2" (String)
With addition: {"json_class":"Range","a":[0,2,false]} (String)
Parsed JSON:
Without addition: "0..2" (String)
With addition: 0..2 (Range)
JSON 모듈은 특정 클래스들에 대한 추가를 포함해요. 직접 커스텀 추가를 만들 수도 있어요. "Custom JSON Additions" 참고.
내장 추가 (Built-in Additions)
JSON 모듈은 특정 클래스들에 대한 추가를 포함해요. 추가를 사용하려면 그 소스를 require해요.
- BigDecimal:
require 'json/add/bigdecimal' - Complex:
require 'json/add/complex' - Date:
require 'json/add/date' - DateTime:
require 'json/add/date_time' - Exception:
require 'json/add/exception' - OpenStruct:
require 'json/add/ostruct' - Range:
require 'json/add/range' - Rational:
require 'json/add/rational' - Regexp:
require 'json/add/regexp' - Set:
require 'json/add/set' - Struct:
require 'json/add/struct' - Symbol:
require 'json/add/symbol' - Time:
require 'json/add/time'
구두점을 줄이려고 아래 예시들은 보통의 inspect 대신 puts로 생성된 JSON을 보여줘요.
BigDecimal:
require 'json/add/bigdecimal'
ruby0 = BigDecimal(0) # 0.0
json = JSON.generate(ruby0) # {"json_class":"BigDecimal","b":"27:0.0"}
ruby1 = JSON.parse(json, create_additions: true) # 0.0
ruby1.class # => BigDecimal
Complex:
require 'json/add/complex'
ruby0 = Complex(1+0i) # 1+0i
json = JSON.generate(ruby0) # {"json_class":"Complex","r":1,"i":0}
ruby1 = JSON.parse(json, create_additions: true) # 1+0i
ruby1.class # Complex
Date:
require 'json/add/date'
ruby0 = Date.today # 2020-05-02
json = JSON.generate(ruby0) # {"json_class":"Date","y":2020,"m":5,"d":2,"sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02
ruby1.class # Date
DateTime:
require 'json/add/date_time'
ruby0 = DateTime.now # 2020-05-02T10:38:13-05:00
json = JSON.generate(ruby0) # {"json_class":"DateTime","y":2020,"m":5,"d":2,"H":10,"M":38,"S":13,"of":"-5/24","sg":2299161.0}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02T10:38:13-05:00
ruby1.class # DateTime
Exception (RuntimeError를 포함한 하위 클래스들):
require 'json/add/exception'
ruby0 = Exception.new('A message') # A message
json = JSON.generate(ruby0) # {"json_class":"Exception","m":"A message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # A message
ruby1.class # Exception
ruby0 = RuntimeError.new('Another message') # Another message
json = JSON.generate(ruby0) # {"json_class":"RuntimeError","m":"Another message","b":null}
ruby1 = JSON.parse(json, create_additions: true) # Another message
ruby1.class # RuntimeError
OpenStruct:
require 'json/add/ostruct'
ruby0 = OpenStruct.new(name: 'Matz', language: 'Ruby') # #<OpenStruct name="Matz", language="Ruby">
json = JSON.generate(ruby0) # {"json_class":"OpenStruct","t":{"name":"Matz","language":"Ruby"}}
ruby1 = JSON.parse(json, create_additions: true) # #<OpenStruct name="Matz", language="Ruby">
ruby1.class # OpenStruct
Range:
require 'json/add/range'
ruby0 = Range.new(0, 2) # 0..2
json = JSON.generate(ruby0) # {"json_class":"Range","a":[0,2,false]}
ruby1 = JSON.parse(json, create_additions: true) # 0..2
ruby1.class # Range
Rational:
require 'json/add/rational'
ruby0 = Rational(1, 3) # 1/3
json = JSON.generate(ruby0) # {"json_class":"Rational","n":1,"d":3}
ruby1 = JSON.parse(json, create_additions: true) # 1/3
ruby1.class # Rational
Regexp:
require 'json/add/regexp'
ruby0 = Regexp.new('foo') # (?-mix:foo)
json = JSON.generate(ruby0) # {"json_class":"Regexp","o":0,"s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # (?-mix:foo)
ruby1.class # Regexp
Set:
require 'json/add/set'
ruby0 = Set.new([0, 1, 2]) # #<Set: {0, 1, 2}>
json = JSON.generate(ruby0) # {"json_class":"Set","a":[0,1,2]}
ruby1 = JSON.parse(json, create_additions: true) # #<Set: {0, 1, 2}>
ruby1.class # Set
Struct:
require 'json/add/struct'
Customer = Struct.new(:name, :address) # Customer
ruby0 = Customer.new("Dave", "123 Main") # #<struct Customer name="Dave", address="123 Main">
json = JSON.generate(ruby0) # {"json_class":"Customer","v":["Dave","123 Main"]}
ruby1 = JSON.parse(json, create_additions: true) # #<struct Customer name="Dave", address="123 Main">
ruby1.class # Customer
Symbol:
require 'json/add/symbol'
ruby0 = :foo # foo
json = JSON.generate(ruby0) # {"json_class":"Symbol","s":"foo"}
ruby1 = JSON.parse(json, create_additions: true) # foo
ruby1.class # Symbol
Time:
require 'json/add/time'
ruby0 = Time.now # 2020-05-02 11:28:26 -0500
json = JSON.generate(ruby0) # {"json_class":"Time","s":1588436906,"n":840560000}
ruby1 = JSON.parse(json, create_additions: true) # 2020-05-02 11:28:26 -0500
ruby1.class # Time
커스텀 JSON 추가 (Custom JSON Additions)
제공된 JSON 추가 외에도, Ruby 내장 클래스나 사용자 정의 클래스용으로 직접 JSON 추가를 만들 수 있어요.
여기 사용자 정의 클래스 Foo가 있어요.
class Foo
attr_accessor :bar, :baz
def initialize(bar, baz)
self.bar = bar
self.baz = baz
end
end
그에 대한 JSON 추가는 다음과 같아요.
# Extend class Foo with JSON addition.
class Foo
# Serialize Foo object with its class name and arguments
def to_json(*args)
{
JSON.create_id => self.class.name,
'a' => [ bar, baz ]
}.to_json(*args)
end
# Deserialize JSON string by constructing new Foo object with arguments.
def self.json_create(object)
new(*object['a'])
end
end
시연:
require 'json'
# This Foo object has no custom addition.
foo0 = Foo.new(0, 1)
json0 = JSON.generate(foo0)
obj0 = JSON.parse(json0)
# Lood the custom addition.
require_relative 'foo_addition'
# This foo has the custom addition.
foo1 = Foo.new(0, 1)
json1 = JSON.generate(foo1)
obj1 = JSON.parse(json1, create_additions: true)
# Make a nice display.
display = <<EOT
Generated JSON:
Without custom addition: #{json0} (#{json0.class})
With custom addition: #{json1} (#{json1.class})
Parsed JSON:
Without custom addition: #{obj0.inspect} (#{obj0.class})
With custom addition: #{obj1.inspect} (#{obj1.class})
EOT
puts display
출력:
Generated JSON:
Without custom addition: "#<Foo:0x0000000006534e80>" (String)
With custom addition: {"json_class":"Foo","a":[0,1]} (String)
Parsed JSON:
Without custom addition: "#<Foo:0x0000000006534e80>" (String)
With custom addition: #<Foo:0x0000000006473bb8 @bar=0, @baz=1> (Foo)
Constants (상수)
CREATE_ID_TLS_KEYDEFAULT_CREATE_IDInfinityJSON_LOADEDMinusInfinityNOT_SETNaNVERSION— JSON 버전.
Attributes (속성)
dump_default_options [RW]
JSON.dump 메서드의 기본 옵션을 설정하거나 돌려줘요. 처음에는:
opts = JSON.dump_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
generator [R]
JSON이 사용하는 JSON 생성기 모듈을 돌려줘요. 이것은 JSON::Ext::Generator 또는 JSON::Pure::Generator예요.
JSON.generator # => JSON::Ext::Generator
load_default_options [RW]
JSON.load 메서드의 기본 옵션을 설정하거나 돌려줘요. 처음에는:
opts = JSON.load_default_options
opts # => {:max_nesting=>false, :allow_nan=>true, :allow_blank=>true, :create_additions=>true}
parser [R]
JSON이 사용하는 JSON 파서 클래스를 돌려줘요. 이것은 JSON::Ext::Parser 또는 JSON::Pure::Parser예요.
JSON.parser # => JSON::Ext::Parser
state [RW]
JSON이 사용하는 JSON 생성기 상태 클래스를 설정하거나 돌려줘요. 이것은 JSON::Ext::Generator::State 또는 JSON::Pure::Generator::State예요.
JSON.state # => JSON::Ext::Generator::State
Public Class Methods
JSON[object] → new_array or new_string
object가 String이면 object와 opts로 JSON.parse를 호출해요 (parse 메서드 참고).
json = '[0, 1, null]'
JSON[json]# => [0, 1, nil]
그 외에는 object와 opts로 JSON.generate를 호출해요 (generate 메서드 참고).
ruby = [0, 1, nil]
JSON[ruby] # => '[0,1,null]'
create_fast_state ()
create_id ()
현재 create 식별자를 돌려줘요. JSON.create_id=도 참고하세요.
create_id= (new_value)
create 식별자를 설정해요. 이것은 클래스의 json_create 훅을 호출할지 결정하는 데 쓰여요. 초기값은 json_class예요.
JSON.create_id # => 'json_class'
create_pretty_state ()
iconv (to, from, string)
String.encode를 사용해 문자열을 인코딩해요.
restore
Public Instance Methods
dump(obj, io = nil, limit = nil)
obj를 JSON 문자열로 덤프해요. 즉 객체에 generate를 호출하고 그 결과를 돌려줘요.
기본 옵션은 JSON.dump_default_options 메서드로 바꿀 수 있어요.
- 인자
io가 주어지면write메서드에 응답해야 해요. JSON String이io에 쓰여지고io가 돌려져요.io가 주어지지 않으면 JSON String이 돌려져요. - 인자
limit이 주어지면 옵션max_nesting으로JSON.generate에 전달돼요.
인자 io가 주어지지 않으면 obj에서 생성된 JSON String을 돌려줘요.
obj = {foo: [0, 1], bar: {baz: 2, bat: 3}, bam: :bad}
json = JSON.dump(obj)
json # => "{\"foo\":[0,1],\"bar\":{\"baz\":2,\"bat\":3},\"bam\":\"bad\"}"
인자 io가 주어지면 JSON String을 io에 쓰고 io를 돌려줘요.
path = 't.json'
File.open(path, 'w') do |file|
JSON.dump(obj, file)
end # => #<File:t.json (closed)>
puts File.read(path)
출력:
{"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
fast_generate(obj, opts) → new_string
여기의 인자 obj와 opts는 JSON.generate의 인자 obj와 opts와 같아요.
기본적으로 obj의 순환 참조(circular reference)를 검사하지 않고 JSON 데이터를 생성해요 (옵션 max_nesting이 false로 설정됨, 비활성화).
obj가 순환 참조를 담고 있으면 예외를 발생시켜요.
a = []; b = []; a.push(b); b.push(a)
# Raises SystemStackError (stack level too deep):
JSON.fast_generate(a)
generate(obj, opts = nil) → new_string
생성된 JSON 데이터를 담은 String을 돌려줘요. JSON.fast_generate, JSON.pretty_generate도 참고하세요.
인자 obj는 JSON으로 변환할 Ruby 객체예요. 인자 opts는 주어지면 생성을 위한 옵션의 Hash를 담아요. "생성 옵션 (Generating Options)" 참고.
obj가 Array이면 JSON 배열을 담은 String을 돌려줘요.
obj = ["foo", 1.0, true, false, nil]
json = JSON.generate(obj)
json # => '["foo",1.0,true,false,null]'
obj가 Hash이면 JSON 객체를 담은 String을 돌려줘요.
obj = {foo: 0, bar: 's', baz: :bat}
json = JSON.generate(obj)
json # => '{"foo":0,"bar":"s","baz":"bat"}'
다른 Ruby 객체에서 생성하는 예시는 "다른 객체에서 JSON 생성 (Generating JSON from Other Objects)" 참고.
어떤 형식 옵션이 String이 아니면 예외를 발생시켜요. obj가 순환 참조를 담고 있으면 예외를 발생시켜요.
a = []; b = []; a.push(b); b.push(a)
# Raises JSON::NestingError (nesting of 100 is too deep):
JSON.generate(a)
load(source, proc = nil, options = {}) → object
주어진 source를 파싱해서 만들어진 Ruby 객체들을 돌려줘요.
- 인자
source는 String이거나 String으로 변환 가능해야 해요.source가 인스턴스 메서드to_str에 응답하면 source가source.to_str가 돼요.to_io에 응답하면source.to_io.read가 source가 돼요.read에 응답하면source.read가 source가 돼요. 다음 두 가지 모두 참이면 source가 String'null'이 돼요: 옵션allow_blank가 truthy 값을 지정하고, 위에서 정의한 source가nil이거나 빈 String''. 그 외에는 source가 그대로 남아요. - 인자
proc이 주어지면 한 인자를 받는 Proc이어야 해요. 각 결과와 함께 (depth-first 순서로) 재귀적으로 호출돼요. 아래 자세한 내용 참고. 주의: 이 메서드는 신뢰할 수 있는 사용자 입력(자신의 데이터베이스 서버나 제어하는 클라이언트 같은)의 데이터를 직렬화하기 위한 거예요. 신뢰할 수 없는 사용자가 JSON source를 전달하게 하는 건 위험할 수 있어요. - 인자
opts가 주어지면 파싱을 위한 옵션의 Hash를 담아요. "파싱 옵션 (Parsing Options)" 참고. 기본 옵션은JSON.load_default_options=메서드로 바꿀 수 있어요.
proc이 주어지지 않으면 위처럼 source를 수정하고 parse(source, opts)의 결과를 돌려줘요. parse 참고.
다음 예시를 위한 source:
source = <<-EOT
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
EOT
String 로드:
ruby = JSON.load(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
IO 객체 로드:
require 'stringio'
object = JSON.load(StringIO.new(source))
object # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
File 객체 로드:
path = 't.json'
File.write(path, source)
File.open(path) do |file|
JSON.load(file)
end # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
proc이 주어지면:
- 위처럼 source를 수정해요.
parse(source, opts)호출에서 결과를 얻어요.proc(result)를 재귀적으로 호출해요.- 최종 결과를 돌려줘요.
예시:
require 'json'
# Some classes for the example.
class Base
def initialize(attributes)
@attributes = attributes
end
end
class User < Base; end
class Account < Base; end
class Admin < Base; end
# The JSON source.
json = <<-EOF
{
"users": [
{"type": "User", "username": "jane", "email": "[email protected]"},
{"type": "User", "username": "john", "email": "[email protected]"}
],
"accounts": [
{"account": {"type": "Account", "paid": true, "account_id": "1234"}},
{"account": {"type": "Account", "paid": false, "account_id": "1235"}}
],
"admins": {"type": "Admin", "password": "0wn3d"}
}
EOF
# Deserializer method.
def deserialize_obj(obj, safe_types = %w(User Account Admin))
type = obj.is_a?(Hash) && obj["type"]
safe_types.include?(type) ? Object.const_get(type).new(obj) : obj
end
# Call to JSON.load
ruby = JSON.load(json, proc {|obj|
case obj
when Hash
obj.each {|k, v| obj[k] = deserialize_obj v }
when Array
obj.map! {|v| deserialize_obj v }
end
})
pp ruby
출력:
{"users"=>
[#<User:0x00000000064c4c98
@attributes=
{"type"=>"User", "username"=>"jane", "email"=>"[email protected]"}>,
#<User:0x00000000064c4bd0
@attributes=
{"type"=>"User", "username"=>"john", "email"=>"[email protected]"}>],
"accounts"=>
[{"account"=>
#<Account:0x00000000064c4928
@attributes={"type"=>"Account", "paid"=>true, "account_id"=>"1234"}>},
{"account"=>
#<Account:0x00000000064c4680
@attributes={"type"=>"Account", "paid"=>false, "account_id"=>"1235"}>}],
"admins"=>
#<Admin:0x00000000064c41f8
@attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
load_file(path, opts={}) → object
다음을 호출해요.
parse(File.read(path), opts)
parse 메서드 참고.
load_file!(path, opts = {})
다음을 호출해요.
JSON.parse!(File.read(path, opts))
parse! 메서드 참고.
merge_dump_options (opts, strict: NOT_SET)
parse(source, opts) → object
주어진 source를 파싱해서 만들어진 Ruby 객체들을 돌려줘요.
인자 source는 파싱할 String을 담아요. 인자 opts가 주어지면 파싱을 위한 옵션의 Hash를 담아요. "파싱 옵션 (Parsing Options)" 참고.
source가 JSON 배열이면 Ruby Array를 돌려줘요.
source = '["foo", 1.0, true, false, null]'
ruby = JSON.parse(source)
ruby # => ["foo", 1.0, true, false, nil]
ruby.class # => Array
source가 JSON 객체이면 Ruby Hash를 돌려줘요.
source = '{"a": "foo", "b": 1.0, "c": true, "d": false, "e": null}'
ruby = JSON.parse(source)
ruby # => {"a"=>"foo", "b"=>1.0, "c"=>true, "d"=>false, "e"=>nil}
ruby.class # => Hash
모든 JSON 데이터 타입의 파싱 예시는 "JSON 파싱 (Parsing JSON)" 참고. 중첩된 JSON 객체를 파싱해요.
source = <<-EOT
{
"name": "Dave",
"age" :40,
"hats": [
"Cattleman's",
"Panama",
"Tophat"
]
}
EOT
ruby = JSON.parse(source)
ruby # => {"name"=>"Dave", "age"=>40, "hats"=>["Cattleman's", "Panama", "Tophat"]}
source가 유효한 JSON이 아니면 예외를 발생시켜요.
# Raises JSON::ParserError (783: unexpected token at ''):
JSON.parse('')
parse!(source, opts) → object
source와 (어쩌면 수정된) opts로 다음을 호출해요.
parse(source, opts)
JSON.parse와의 차이점:
- 옵션
max_nesting이 주어지지 않으면 기본값이false여서 중첩 깊이 검사를 비활성화해요. - 옵션
allow_nan이 주어지지 않으면 기본값이true예요.
pretty_generate(obj, opts = nil) → new_string
여기의 인자 obj와 opts는 JSON.generate의 인자 obj와 opts와 같아요.
기본 옵션:
{
indent: ' ', # Two spaces
space: ' ', # One space
array_nl: "\n", # Newline
object_nl: "\n" # Newline
}
예시:
obj = {foo: [:bar, :baz], bat: {bam: 0, bad: 1}}
json = JSON.pretty_generate(obj)
puts json
출력:
{
"foo": [
"bar",
"baz"
],
"bat": {
"bam": 0,
"bad": 1
}
}