ChanServ changed the topic of #crystal-lang to: The Crystal programming language | | Fund Crystal's development: | GH: | Docs: | Gitter:
scott_tams has joined #crystal-lang
scott_tams has quit [Remote host closed the connection]
tleaf has joined #crystal-lang
tleaf has quit [Quit: nyaa~]
hightower3 has joined #crystal-lang
hightower4 has quit [Ping timeout: 265 seconds]
Peter0x44 has quit [Ping timeout: 252 seconds]
Peter0x44 has joined #crystal-lang
<hightower3> Hey @j8r, even though I use ByteFormat, I also have a use for some simple JSON serialization. How could I make the JSON-serialized content be output on a single line, without inserting \n between variables?
<FromGitter> <> I decided to change the default indent, some languages do it too. ⏎ You can either `Crystalizer::JSON::Serializer.indent = ""` or define it when you do so
<FromGitter> <> Right I just noticed it is not taken into account, fixing that
<hightower3> you da man, thanks
<FromGitter> <> hum no should work? Not sure
<hightower3> Well, i tried setting `Crystalizer::JSON::Serializer.indent = "xx"` and it didn't make any difference. The output still had 1 variable per line and was indented by " "
<hightower3> What's even more interesting, at a quick glance I wasn't able to find \n mentioned anywhere (inside crystalizer's shard), yet it certainly appears in output
<FromGitter> <> I see, that's because it is overriden by the indent defined in the method
<FromGitter> <> that's how the JSON::Builder works
<FromGitter> <> defining an indent make it "\n"
<FromGitter> <> fix pushed, thanks
<hightower3> great, that doesn't include the newline thing right? Looking at builder's code, it emits newlines unconditionally. What one could do though is override its `newline` or `write_indent` methods I guess... or remove newlines after serialization :)
<hightower3> Yeah overriding `newline` worked. I prefer that to removing newlines later
_whitelogger has joined #crystal-lang
<hightower3> yeah, although I'll probably give up on that and just use no-spaces/no-newlines which `indent = ""` gives.
<hightower3> thanks!
<FromGitter> <> 👍️
<FromGitter> <> class vars/properties are hard to test, but sometimes convenient
<hightower3> This library is so convenient... and the out of the box, interchangeable (de)serialization between all formats is amazing
<hightower3> like, (de)serialize to bytes for wire protocol, and to json for visual inspection or logs!
HumanG33k has quit [Quit: WeeChat 3.0]
<FromGitter> <speg> Ha, speaking of indents... I've been trying to format some HTML all morning without much luck. Is this the right approach? ⏎ ⏎ ```code paste, see link``` []
<hightower3> @j8r I have a need to serialize enum members in JSON/YAML to their name instead of numeric value. The change seems like it would be simple. How would you prefer to control when it's a number and when it's a string? An annotation?
<hightower3> (well, simple at least for serialization :-)
<FromGitter> <Blacksmoke16> stdlib has been updated to use strings, might be worth doing the opposite. I.e. make that the default and provide a way to use the numbers
<hightower3> right, great (found before asking because I had it in mind)
<hightower3> mm is there a way to detect if an enum has flags in runtime?
<FromGitter> <> Agreed
<FromGitter> <> Open for PRs to change that behavior
<hightower3> I tried coming up with a PR, wasn't successful so far
<FromGitter> <> The work will only on be serialization
<FromGitter> <> For it, the work should be similar as what you've done with `bytesize`
<hightower3> But deserialization too, no? Yes I'm aware that it's very simple/similar, the issue that got me is that we can read if an object is a flags enum and store that in @annotations. But later when we use say, `if object.is_a?(Enum) && object.annotations[:flags]`, then compiler error shows up that 'enum.each' can only be called on Flags enums. I wasn't sure what to do there
<hightower3> Another issue I'm trying to figure out is that I have a struct which I have deserialized from byte_format, and when I try to serialize it to JSON it prints just {}. But when I try to reproduce minimal case, then it works.
<FromGitter> <> For deserialization, accoding to the type parsed from the pull parser, it creates the enum member accordingly
<FromGitter> <> You issue may be due to the IO/Bytes. You can try to copy it before deserializing to see if it fixes the issue
<hightower3> hm, maybe I don't understand your advice, but if I do it's probably unrelated. I have a working object, the fact that I got it by deserializing from bytes is not particularly relevant.
<hightower3> (I only meant that to say that it's a working/valid crystalizer-capable object)
<hightower3> So once I have it as an object, if I `p` it, I see everything, if I Crystalizer::JSON.serialize it, I get {}
<FromGitter> <> If Bytes are directly used, as-is, they may be freed
<hightower3> no no, no relation to them any more. It's a normal object. I can create one with .new() manually and it's the same
<FromGitter> <> Ok!
<hightower3> I was unable to reproduce so I avoided using json (I needed it for some informational prints anyway), but will get back to it at some point
<FromGitter> <> So can't say before you are able to reproduce :/
<FromGitter> <> but you said with .new the issue still occurs?
HumanG33k has joined #crystal-lang
<FromGitter> <> For enum, it is just about serialization
<FromGitter> <> deserialization will happily take either an int or string
<hightower3> Yes but in case of Flags it will be an array
<hightower3> (of strings)
<hightower3> ouch, my mistake, with .new it works. But I don't understand why really.
<FromGitter> <> ok I see
<FromGitter> <> with `forall` we can get the type, then its annotations
<FromGitter> <> wherever we are, it is not strictly necessary to have to pass around arguments
<hightower3> oh awesome, totally forgot about that
<FromGitter> <> the thing I'm not sure how to is the converter stuff...
<FromGitter> <> I'm not satisfied with how the stdlib do
<hightower3> I think we don't need it at all. With direct access to annotations (thanks to forall) to check for the Flags annotation, and with one annotation which we need to add anyway, like `Crystalizer::Field(values: true/false)`, we have both pieces of info which we need to (de)serialize to values or strings
<FromGitter> <> for this very use case, maybe. But all other cases?
<FromGitter> <> Like, I prefer camelcase, or want Y format date instead of X, etc
<hightower3> in that case the user adds Crystalizer::Type and defines their own method?
<FromGitter> <> That works too, or making a format derived from the standard JSON/YAML
<FromGitter> <> having to make a wrapper may not be ideal though :/
<hightower3> yes but... well, even the current model with Crystalizer::Type I found a bit long-winded... I was dreaming of something like:
<FromGitter> <> I've taken inspiration from serde on this :)
<hightower3> (like, if you remember my case where from the wire I read: <len><string of size 'len'>).. I was hoping that I could deserialize the first field, `len`, in a completely standard/non-custom way
<hightower3> and then for the other, to define something like:
<FromGitter> <> You'd prefer to have it natively?
<hightower3> @[Crystalizer::Field()] { |s| @len }
<FromGitter> <> for deserializing, but what about serializing?
<hightower3> obviously that syntax won't work directly, but something like that...
Peter0x44 has quit [Ping timeout: 265 seconds]
<FromGitter> <> The issue is infinite possiblities. There are format where the type also is defined in a field (discriminator I guess), and other stuff
<hightower3> well, passing a block to an annotation won't work, so if the actual syntax would be via arguments, it could be @[Crystalizer::Field(serialize: {...}, deserialize: {...} )] or something
<hightower3> or it could be a flag passed to the block, indicating which one it is
<FromGitter> <> maybe then a converter is a good idea...
Peter0x44 has joined #crystal-lang
<FromGitter> <> @[Crystalizer::Field(converter: SomeType)]
<FromGitter> <> one thing which can be annoying is to add this annotation for every type we want. For example, I want all my enums with numbers and not strings
<FromGitter> <> *for each type
<FromGitter> <> pros and cons of each approaches
<hightower3> Yeah. personally I'd prefer a model which involves just a block somehow, since that wouldn't require one to create a separate class just to define `to/from_<format>` methods on it
<hightower3> if a separate class/module is involved, then the existing approach with Type works OK too
<FromGitter> <> In any case you'll have to create proper methods. Crystalizer::Type, Converter or a custom format
<FromGitter> <> it also make the code reusable, vs put the logic inside an annotation
<FromGitter> <> One last thing I hesitate: do we keep the happily parsing of either integers or string, or like the stdlib raise if not a string?
<FromGitter> <> I'd rather go with stricter parsing
<hightower3> yeah, probably that'd be easier. to accept only one, depending on the user's setting if they want numbers or strings
<FromGitter> <> and another thing I can do is just calling the stdlib implementation. ⏎ As expected, `require "yaml/pull_parser"` does not work out of the box due to having to requires in :/
<FromGitter> <> *no requires
<FromGitter> <> I'll keep numbers for ByteFormat
<hightower3> that's for sure, yes
<hightower3> jrei: for now you opted for strings being default, without an option to do values? Or the PR is still in development?
<FromGitter> <> Not sure with the numbers being annotation fields
<FromGitter> <> I consider the PR finished. If someone really needs numbers for Enums, I may reconsider the options
<FromGitter> <Blacksmoke16> may be useful if you need to hitup an external api that expects it
<FromGitter> <> APIs may expect lots of things 😆
<FromGitter> <> I prefer to hit actual use cases before doing anything, 'cause: 1. I'm lazy and don't want to spens much time to spend on it afterall. 2. I'd like to keep it as simple & flexible as possible
<FromGitter> <Blacksmoke16> yea no need for premature optimization
<FromGitter> <nanobowers> Can someone advise on a good way to reuse a common setup or variables across multiple tests using `Spec`? I am aware of the before_each / before_suite, but I havent found any examples of defining vars and then reusing them in the tests themselves and things dont seem to work as i'd expect
<FromGitter> <Blacksmoke16> define a method
<FromGitter> <Blacksmoke16> you can use `it` blocks in a method so you can do stuff like `assert_something "input", "output"`
<FromGitter> <Blacksmoke16> but depends on your exact context