quinnj / JSON3.jl

Other
214 stars 47 forks source link

provide JSONText in analogy to JSON.jl #168

Open hhaensel opened 3 years ago

hhaensel commented 3 years ago

What I am missing from JSON.jl is the ability to render plain text, e.g. for the construction of function objects, which are not directly supported by the JSON interface. Therefore I propose to define the following:

struct JSONText
    s::AbstractString
end

@inline StructTypes.StructType(::Type{JSONText}) = JSON3.RawType()
@inline StructTypes.construct(::Type{JSONText}, x::JSON3.RawValue) = JSONText(string(x))
@inline JSON3.rawbytes(x::JSONText) = x.s

which would allow us to write

julia> using JSON3

julia> JSON3.write(JSONText("Hello World"))
"Hello World"

@quinnj If you like this idea, I'd happily provide a PR.

EDIT:

hhaensel commented 3 years ago

After re-reading the docs, I realised that my constructor was not correctly written. If I understand it right now, the constructor is only necessary for reading, which was not my primary goal.

To allow for reading JSON3.read() would need to support reading of raw data without checking of JSON syntax. But if I do

a JSON3.read("test", JSONText) I receive an parsing error

ERROR: ArgumentError: invalid JSON at byte position 1 while parsing type JSON3.False: InvalidChar

I could go for

function StructTypes.construct(::Type{JSONText}, x::JSON3.RawValue) 
    s = unsafe_string(pointer(x.bytes, x.pos), x.len)
    JSONText(s[2:prevind(s, lastindex(s))])
end

to read quoted strings into a JSONText like

julia> JSON3.read("\"test 2π\"", JSONText)
JSONText("test 2π")

but this doesn't make much sense to me. So maybe we could live without a constructor ...?

EDIT: We could also go for a different name, e.g. RawString

quinnj commented 3 years ago

Hmmmm.....I don't love the idea of a JSONText thing, since it's like, why are you calling JSON3.write anyway if it's just raw text? If there's a question of supporting functions, then I'd be open to supporting them natively in JSON3; we actually supported them in JSON2.jl (https://github.com/quinnj/JSON2.jl/blob/0bdd11058ceb6495a8987d6a3d441ec0397b0e27/src/read.jl#L182), but I wasn't sure anyone ever needed/used it, so I didn't port it over when writing JSON3.jl.

hhaensel commented 3 years ago

Well, if you have a dict or struct that contains mainly standard JSON, but some of the objects are not covered by the strict JSON definition, then JSONText comes in very handy. In Stipple.jl, we use it to define mxins and functions, e.g. to define the code

var Example = new Vue({
    "el": "#Example",
    "mixins": [watcherMixin, reviveMixin],
    "data": {
        "f": function() {
            alert("The value of n is: " + this.n);
            return this.n + 1
        },
        "s": "...",
        "a": [3, 2, 1],
        "n": 1
    }
});

We use (slightly modified)

Dict(:el => Elements.elem(app), :mixins => JSONText("[watcherMixin, reviveMixin]"), :data => Example())

where Example defines the model data to be shared between frontend and backend.

Stipple.@kwdef mutable struct Example <: ReactiveModel
  s::R{String} = "..."
  a::R{Array} = [3, 2, 1], PUBLIC
  n::R{Int} = 1, READONLY
  i::R{Int} = 1, PRIVATE
  f::R{JSONText} = JSONText("function() { return Example.n + 1 }"), JSFUNCTION
end

But I'm also fine without official JSONText support, as your API gives me all the freedom to define what I need 😄 👍 Thanks for commenting!

hhaensel commented 3 years ago

@quinnj Feel free to close this when you are not going to implement JSONText. You might include a remark in the docs? I could support, if you like.

hhaensel commented 2 years ago

Shall we close this, and rather include it in the docs than in the module?