TL;DR
Bei der Konvertierung in json in Ruby verwenden Sie häufig to_json
.
Wenn Sie von einem Objekt vom Typ "Hash" oder "Array" konvertieren, schreiben Sie den folgenden Code. Wenn Sie jedoch nicht "require'json" ausführen, tritt bei "NoMethodError" ein Fehler auf.
--require'json'
nicht
Fehler tritt auf
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'
Es tritt kein Fehler auf
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}"
Ich fand es ungewöhnlich, später Instanzmethoden zur integrierten Klasse hinzuzufügen, daher werde ich der internen Implementierung folgen.
Laut der Ruby-Dokumentation scheint es ein Modul namens "JSON :: Generator :: GeneratorMethods :: Hash" zu geben.
https://docs.ruby-lang.org/ja/latest/class/JSON=3a=3aGenerator=3a=3aGeneratorMethods=3a=3aHash.html
Wenn Sie den relevanten Teil des Ruby-Quellcodes durchsuchen, rufen Sie wahrscheinlich jede Generatorklasse (json / ext / generator
) von hier aus auf.
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
Wenn Sie Folgendes überprüfen, können Sie außerdem sehen, dass "json / ext / generator" als Erweiterungsbibliothek aus der Sprache c anstelle von ".rb" kompiliert wird.
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'
Als ich die entsprechende c-Sprachdatei überprüfte, stellte ich fest, dass die Methode "to_json" registriert war und das Modul von "rb_define_method" für die Klasse "Hash" registriert wurde.
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);
Und es scheint, dass das obige Modul später eine Instanzmethode hinzufügt, indem es unten gemischt wird.
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
Ich fand heraus, dass dies daran lag, dass ich beim Lesen des json-Moduls die Erweiterungsmethode der C-Sprache aufgerufen, die Funktion hinzugefügt und das Modul hinzugefügt und später in die integrierte Klasse gemischt habe.
Es war ein wenig erfrischend, da einige Sprachen (wie Python) das Hinzufügen von Methoden zu integrierten Klassen nicht zulassen. Sie können flexibel in integrierte Klassen injizieren, zum Guten oder zum Schlechten. Ich würde gerne weiter studieren.