Ruby-Objekte und JSON-Serialisierung (ohne Rails)


70

Ich versuche, die JSON-Serialisierungslandschaft in Ruby zu verstehen. Ich bin neu bei Ruby.

Gibt es gute JSON-Serialisierungsoptionen, wenn Sie nicht mit Rails arbeiten?

Dort scheint diese Antwort zu lauten (auf Rails). So konvertieren Sie ein Ruby-Objekt in JSON

Das json-Juwel scheint es so aussehen zu lassen, als müssten Sie Ihre eigene to_json-Methode schreiben. Ich konnte to_json nicht dazu bringen, mit Arrays und Hashes zu arbeiten (Dokumentation besagt, dass es mit diesen funktioniert). Gibt es einen Grund, warum das json-Juwel nicht nur über das Objekt reflektiert und eine Standard-Serialisierungsstrategie verwendet? Funktioniert to_yaml nicht so (hier raten)


2
Hört sich vielleicht dumm an, aber hast du es tatsächlich getan require 'json'? Ich habe mit den JSON-Edelsteinen gearbeitet und sie haben wie ein Zauber funktioniert.
DarkDust

Antworten:


111

Damit die JSON-Bibliothek verfügbar ist, müssen Sie sie möglicherweise libjson-rubyvon Ihrem Paketmanager installieren .

So verwenden Sie die 'json'-Bibliothek:

require 'json'

So konvertieren Sie ein Objekt in JSON (diese drei Möglichkeiten sind gleichwertig):

JSON.dump object #returns a JSON string
JSON.generate object #returns a JSON string
object.to_json #returns a JSON string

So konvertieren Sie JSON-Text in ein Objekt (diese beiden Möglichkeiten sind gleichwertig):

JSON.load string #returns an object
JSON.parse string #returns an object

Für Objekte aus Ihren eigenen Klassen wird es etwas schwieriger. Für die folgende Klasse erzeugt to_json so etwas wie "\"#<A:0xb76e5728>\"".

class A
    def initialize a=[1,2,3], b='hello'
        @a = a
        @b = b
    end
end

Dies ist wahrscheinlich nicht wünschenswert. Um Ihr Objekt effektiv als JSON zu serialisieren, sollten Sie Ihre eigene to_json-Methode erstellen. Zu diesem Zweck wäre eine from_json-Klassenmethode hilfreich. Sie können Ihre Klasse folgendermaßen erweitern:

class A
    def to_json
        {'a' => @a, 'b' => @b}.to_json
    end
    def self.from_json string
        data = JSON.load string
        self.new data['a'], data['b']
    end
end

Sie können dies automatisieren, indem Sie von einer 'JSONable'-Klasse erben:

class JSONable
    def to_json
        hash = {}
        self.instance_variables.each do |var|
            hash[var] = self.instance_variable_get var
        end
        hash.to_json
    end
    def from_json! string
        JSON.load(string).each do |var, val|
            self.instance_variable_set var, val
        end
    end
end

Anschließend können Sie object.to_jsonin JSON serialisieren und object.from_json! stringden gespeicherten Status, der als JSON-Zeichenfolge gespeichert wurde, in das Objekt kopieren.


4
Ich suchte nach einer Bibliothek, in der Sie die to_json-Methode nicht für Klassen schreiben mussten. Gibt es eine Klasse, die Sie erben können und die Ihnen dies durch Reflexion gibt? und arbeitet an komplexen Objekten?
BuddyJoe

1
Seid ihr euch sicher, dass es keinen einfacheren Weg gibt?
jj_

4
So entfernen Sie das @ aus dem Eigenschaftsnamen: hash [var.to_s.delete "@"]
epzee

6
Dies funktioniert nicht:in `to_json': wrong number of arguments (1 for 0) (ArgumentError)
redolent

2
@redolent - dass eine Schiene Sache anscheinend. verwenden to_json(options={}), um zu beheben. siehe stackoverflow.com/questions/11599610/…
Randall

11

Schauen Sie sich Oj . Es gibt Fallstricke, wenn es darum geht, ein altes Objekt in JSON zu konvertieren, aber Oj kann es.

require 'oj'

class A
    def initialize a=[1,2,3], b='hello'
        @a = a
        @b = b
    end
end

a = A.new
puts Oj::dump a, :indent => 2

Dies gibt aus:

{
  "^o":"A",
  "a":[
    1,
    2,
    3
  ],
 "b":"hello"
}

Beachten Sie, dass dies ^ozur Bezeichnung der Objektklasse und zur Unterstützung der Deserialisierung verwendet wird. ^oVerwenden Sie zum Auslassen den :compatModus:

puts Oj::dump a, :indent => 2, :mode => :compat

Ausgabe:

{
  "a":[
    1,
    2,
    3
  ],
  "b":"hello"
}

Ojbietet eine hervorragende Kompatibilität zum Ändern und Deserialisieren von Klassen ohne zusätzliche Fehler. +1
Asche999

1
Wie entferne ich diesen "^ oj" -Wert?
neustart47

1
@ neustart47: Ich habe meine Antwort bearbeitet, um zu zeigen, wie dies im :compatModus möglich ist.
Jimothy

8

Wenn die Renderleistung von entscheidender Bedeutung ist, sollten Sie sich auch yajl-ruby ansehen , eine Bindung an die C yajl- Bibliothek. Die Serialisierungs-API für diese sieht folgendermaßen aus:

require 'yajl'
Yajl::Encoder.encode({"foo" => "bar"}) #=> "{\"foo\":\"bar\"}"

Da ich in meinem nächsten Projekt mit vielen JSON-Daten arbeiten muss, kann dies mein Lebensretter sein. +1
Ernest

7

Welche Version von Ruby verwenden Sie? ruby -vwerde es dir sagen.

Wenn es 1.9.2 ist, ist JSON in der Standardbibliothek enthalten .

Wenn Sie auf 1.8.something sind, dann tun Sie gem install jsonund es wird installiert. Dann tun Sie in Ihrem Code:

require 'rubygems'
require 'json'

Dann to_jsonan ein Objekt anhängen und los geht's:

asdf = {'a' => 'b'} #=> {"a"=>"b"}
asdf.to_json #=> "{"a":"b"}"

Wird es schneller sein als yajl?
Ernest

Das müssen Sie bestimmen, Benchmarknicht wahr?
der Blechmann

1
Ich dachte du weißt das vielleicht. Benchmarking und es ist langsamer: P Besonders beim Codieren.
Ernest

7

Da ich selbst viel gesucht habe, um ein Ruby-Objekt für json zu serialisieren:

require 'json'

class User
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def as_json(options={})
    {
      name: @name,
      age: @age
    }
  end

  def to_json(*options)
    as_json(*options).to_json(*options)
  end
end

user = User.new("Foo Bar", 42)
puts user.to_json #=> {"name":"Foo Bar","age":42}

1
Ich habe dies in eine Ruby-Datei kopiert / eingefügt und es wurde problemlos ausgeführt. Es könnte hilfreich sein, Ihre Antwort so zu aktualisieren, dass sie die Ausgabe enthält: {"name": "Foo Bar", "age": 42}
Matthew Kraus


1

Wenn Sie 1.9.2 oder höher verwenden, können Sie Hashes und Arrays mit to_json in verschachtelte JSON-Objekte konvertieren.

{a: [1,2,3], b: 4}.to_json

In Rails können Sie to_json für Active Record-Objekte aufrufen. Sie können folgende Parameter übergeben: include und: only, um die Ausgabe zu steuern:

@user.to_json only: [:name, :email]

Sie können to_json auch für AR-Beziehungen aufrufen, wie folgt:

User.order("id DESC").limit(10).to_json

Sie müssen nichts importieren und alles funktioniert genau so, wie Sie es sich erhoffen.


1

Um die Build - in - Klassen (wie Array und Hash) zu erhalten , um Unterstützung as_jsonund to_jsonSie müssen require 'json/add/core'(siehe Readme für weitere Details)


1

Jbuilder ist ein Juwel, das von der Rails Community gebaut wurde. Aber es funktioniert gut in Umgebungen ohne Schienen und verfügt über coole Funktionen.

# suppose we have a sample object as below
sampleObj.name #=> foo
sampleObj.last_name #=> bar

# using jbuilder we can convert it to json:
Jbuilder.encode do |json|
  json.name sampleObj.name
  json.last_name sampleObj.last_name
end #=> "{:\"name\" => \"foo\", :\"last_name\" => \"bar\"}"

0

Tatsächlich gibt es ein Juwel namens Jsonable, https://github.com/treeder/jsonable . Es ist ziemlich süß.


Jsonable scheint nicht mehr vorhanden zu sein: Zuletzt aktualisiert im Jahr 2012, und der Beispielcode schlägt fehl - JSON.parsegibt json zurück, kein Objekt.
Asche999

Ich weiß nichts über die Beispiele, aber ich fand Jsonable perfekt für meinen Anwendungsfall: feedjira.herokuapp.com github.com/dentarg/feedjira.herokuapp.com/blob/… github.com/dentarg/feedjira.herokuapp.com/
blob

Vielleicht hängt es von Rails oder etwas anderem ab. Ich benutze gerade Ruby.
Asche999

Ich auch, ohne Rails.
Dentarg

0

Ich habe es früher getan virtus. Wirklich leistungsfähiges Tool, mit dem Sie eine dynamische Ruby-Strukturstruktur basierend auf Ihren angegebenen Klassen erstellen können. Einfaches DSL, möglich zum Erstellen von Objekten aus Ruby-Hashes, es gibt einen strengen Modus. Schau es dir an.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.