TL;DR
Lors de la conversion en json en Ruby, je pense que vous utilisez souvent to_json
.
Lors de la conversion à partir d'un objet de type Hash
ou ʻArray, écrivez le code suivant, mais si vous ne faites pas
require'json', une erreur se produira avec
NoMethodError`.
--require'json'
pas
Erreur se produit
irb(main):002:0> some_hash = {a: 1,b: 2}
irb(main):004:0> some_hash.to_json()
Traceback (most recent call last):
5: from /usr/local/opt/ruby/bin/irb:23:in `<main>'
4: from /usr/local/opt/ruby/bin/irb:23:in `load'
3: from /usr/local/Cellar/ruby/2.7.1_2/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
2: from (irb):3
1: from (irb):4:in `rescue in irb_binding'
NoMethodError (undefined method `to_json' for {:a=>1, :b=>2}:Hash)
Did you mean? to_s
--require'json'
Aucune erreur ne se produit
irb(main):005:0> require 'json'
=> true
irb(main):002:0> some_hash = {a: 1,b: 2}
irb(main):006:0> some_hash.to_json()
=> "{\"a\":1,\"b\":2}"
J'ai trouvé inhabituel d'ajouter des méthodes d'instance à la classe intégrée plus tard, je vais donc suivre l'implémentation interne.
D'après la documentation Ruby, il semble y avoir un module appelé JSON :: Generator :: GeneratorMethods :: Hash
.
https://docs.ruby-lang.org/ja/latest/class/JSON=3a=3aGenerator=3a=3aGeneratorMethods=3a=3aHash.html
Si vous recherchez la partie appropriée du code source de Ruby, il semble que vous appelez probablement chaque classe de générateur (json / ext / generator
) à partir d'ici.
https://github.com/ruby/ruby/blob/v2_7_1/ext/json/lib/json/ext.rb#L8
ext.rb
module Ext
require 'json/ext/parser'
require 'json/ext/generator'
$DEBUG and warn "Using Ext extension for JSON."
JSON.parser = Parser
JSON.generator = Generator
end
De plus, si vous vérifiez ce qui suit, vous pouvez voir que json / ext / generator
est compilé comme une bibliothèque d'extension à partir du langage c au lieu de .rb
.
https://github.com/ruby/ruby/blob/v2_7_1/ext/json/generator/extconf.rb#L4
extconf.rb
require 'mkmf'
$defs << "-DJSON_GENERATOR"
create_makefile 'json/ext/generator'
Quand j'ai vérifié le fichier de langage c correspondant, j'ai trouvé que la méthode to_json
était enregistrée et que le module était enregistré pour la classe Hash
par rb_define_method
.
https://github.com/ruby/ruby/blob/68d7e93b3baf91ac7d7cc100b75bab81ba7dee76/ext/json/generator/generator.c#L1511
mHash = rb_define_module_under(mGeneratorMethods, "Hash");
rb_define_method(mHash, "to_json", mHash_to_json, -1);
Et il semble que le module ci-dessus ajoute une méthode d'instance plus tard en la mélangeant ci-dessous.
https://github.com/ruby/ruby/blob/68d7e93b3baf91ac7d7cc100b75bab81ba7dee76/ext/json/lib/json/common.rb#L67
klass.class_eval do
instance_methods(false).each do |m|
m.to_s == 'to_json' and remove_method m
end
include modul
end
J'ai découvert que c'était parce que j'avais appelé la méthode d'extension du langage C lors de la lecture du module json, ajouté la fonction et ajouté le module, puis l'ai mélangé dans la classe intégrée.
C'était un peu rafraîchissant car certains langages (comme Python) ne permettent pas l'ajout de méthodes aux classes intégrées. Vous pouvez injecter de manière flexible dans les classes intégrées, pour le meilleur ou pour le pire. J'aimerais continuer à étudier.