[Ruby] Warum "json" erforderlich ist, wird "json" zulassen

TL;DR

Frage

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.

Quellcodeprüfung

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

Zusammenfassung

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.

Recommended Posts

[Ruby] Warum "json" erforderlich ist, wird "json" zulassen
Warum Schulen Ruby lernen
Teilen Sie durch Ruby! Warum ist es 0?