Ruby处理YAML
Ruby的标准库YAML基于Psych:https://ruby-doc.org/stdlib-2.6.2/libdoc/psych/rdoc/Psych.html
例如:
1 | require 'yaml' |
得到:
1 | "--- hello world\n" |
也可以使用YAML.dump()
方法实现和to_yaml相同的功能,它还可以写入文件。
1 | users = [{name: 'Bob', permissions: ['Read']}, |
查看文件:
1 | --- |
使用YAML.load()从YAML中读取数据:
1 | require 'yaml' |
得到:
1 | {"mysql"=> |
如果想让hash的key是符号而非字符串,可以设置选项symbolize_names: true
:
1 | pp YAML.load(DATA, symbolize_names: true) |
需要注意,YAML可以将对象进行序列化,所以有几方面注意事项:
- 在反序列化的时候需要也require涉及到的文件,例如对Set类型序列化后,在反序列化时如不
require 'set'
则无法还原对象 - 有些底层对象不能序列化,包括IO流、Ruby代码对象Proc、Binding等
- 不要反序列化不被信任的数据对象(比如用户输入的数据),此时可使用safe_load(),它默认只允许加载以下几种类型的数据:
- TrueClass
- FalseClass
- NilClass
- Numeric
- String
- Array
- Hash
- 如果确实想要加载额外的数据类型,可以在safe_load()中指定参数permitted_classes: []或permitted_symbols: []
Ruby处理Json数据
转为json格式字符串
使用JSON.generate()可以将对象或数组转换为JSON格式的数据:
1 | require 'json' |
得到:
1 | "\"abc\"" |
当require 'json'
后,很多ruby类型都具备了一个to_json的方法,可以直接将该类型的数据转换为json数据:
1 | p ({name: "junmajinlong", age: 23}).to_json |
得到:
1 | "{\"name\":\"junmajinlong\",\"age\":23}" |
此外,JSON.dump()也可以将对象转换为JSON格式的字符串,而且它还支持写入文件:
1 | hsh = {name: "junmajinlong", age: 23} |
json格式字符串转为Ruby对象
要从json格式字符串转为ruby对象,有一些选项可设置,参考https://ruby-doc.org/stdlib-2.7.1/libdoc/json/rdoc/JSON.html#method-i-parse>,比如*symbolize_names*选项表示是否将json object中的key解析为符号类型的key,如果设置为false,则解析为字符串的key。
要将json格式的字符串解析为Ruby数据类型(Hash),使用JSON.parse(),
1 | require 'json' |
注意,上面的json字符串必须是合理的json数据,比如key必须使用双引号包围而不能使用单引号,字符串必须使用双引号包围,等等。比如"{'name': 'junmajinlong', 'age': 23}"
就不是合理的json字符串。
要从json文件中读取json数据并转换为Ruby数据,使用load():
1 | data = File.open("/tmp/a.json") do |f| |
自定义对象的转换方式
json支持的数据类型有:
- 字符串
- 数值
- 对象
- 数组
- 布尔
- Null
从一种语言的数据转换为Json数据时,如果数据类型也是JSON所支持的,可直接转换,但如果包含了JSON不支持的类型,则可能报错,也可能以一种对象字符串的方式保存,这取决于对应的实现。
可以在对象中定义as_json
实例方法来决定对象如何转换为json字符串,再定义类方法from_json()
来决定如何从json字符串中恢复为一个对象。
例如,
1 | require 'json' |
查看保存的json数据:
1 | $ cat /tmp/p.json |
定义as_json
和frmo_json
:
1 | require 'json' |
之后要序列化、反序列化该对象,可:
1 | data = Person.new("junmajinlong", "1999-10-11").as_json |
如果是读写json文件,可:
1 | person1 = Person.new("junmajinlong", "1999-10-11") |