ChanServ changed the topic of #crystal-lang to: The Crystal programming language | http://crystal-lang.org | Crystal 0.29.0 | Fund Crystal's development: http://is.gd/X7PRtI | GH: https://github.com/crystal-lang/crystal | Docs: http://crystal-lang.org/docs/ | API: http://crystal-lang.org/api/ | Gitter: https://gitter.im/crystal-lang/crystal
<FromGitter> <Blacksmoke16> similar concepts yea
<FromGitter> <Blacksmoke16> im prob biased but i like my implementation is a bit simpler/feature complete
<FromGitter> <Blacksmoke16> but as a whole, agreeing on some implementation that supports additional features, like formatters/handlers/processors etc would be quite beneficial to every project
<FromGitter> <ezrast_gitlab> There's room for improvement for sure - I'll take a closer look at Crylog sometime.
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d12b92123e3ac2c55611b9e]
<FromGitter> <Blacksmoke16> are the core concepts
sagax has joined #crystal-lang
<FromGitter> <mwlang> oh, boy. I have an array of array of mixed values to serialize from JSON api now... ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d12bb4805ea9473a678362a]
<FromGitter> <Blacksmoke16> gross
<FromGitter> <mwlang> tell me about it.
<FromGitter> <mwlang> if nothing else, it's definitely forcing me to learn Crystal at a deeper level.
<FromGitter> <mwlang> but geez. get consistent with the API responses already!
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> yea, pretty shitty they dont use objects like a sane person
<FromGitter> <Blacksmoke16> numbers as strings makes sense, but 2d array as an api :eww:
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
<FromGitter> <naqvis> Trying to convert decimal to octal is raising *ArgumentError*. Not sure if there is any other way of doing the conversion? ⏎ ⏎ ```p 0o123.to_s.to_i(base: 8)``` ⏎ ⏎ Conversion works for Decimal & Hexadecimal [https://gitter.im/crystal-lang/crystal?at=5d12ffc8501ea60f1246ca95]
<FromGitter> <watzon> ```p 0o123.to_s(8).to_i```
<FromGitter> <watzon> @naqvis
<FromGitter> <naqvis> Thank you @watzon. Didn’t realize there is base param for `to_s` method as well. 👏
<FromGitter> <watzon> Yup. It would be hard to do base16 conversion without it
<FromGitter> <naqvis> thanks again and much appreciated
<FromGitter> <watzon> In other news, I was able to use the web scraping framework I'm working on to generate a full sitemap of crystal-lang.org
<FromGitter> <naqvis> @watzon 👏 👏
<FromGitter> <mistergibson> nice
alex`` has joined #crystal-lang
DTZUZO has quit [Ping timeout: 248 seconds]
DTZUZU has quit [Ping timeout: 244 seconds]
<FromGitter> <girng> hello
<FromGitter> <watzon> Nihao
<FromGitter> <girng> i use a logging system
<FromGitter> <girng> `puts` LOOOOOOOL
<FromGitter> <girng> blacksmoke not gonnalike me when he sees that message ;p
<FromGitter> <watzon> Lol. `puts` works sometimes, but try disabling it or making it so people that use your library or client can disable logs or enable more verbose logging
<FromGitter> <watzon> Gahh I want Crystal to have its own GC already
<FromGitter> <watzon> Having to install BOEHM is annoying
<FromGitter> <watzon> At least it's not as bad as building LLVM though
<FromGitter> <girng> is it really
<FromGitter> <girng> i've never compiled from source with crystal before
<FromGitter> <girng> does it produce errors, etc?
<FromGitter> <girng> or just slow
<FromGitter> <watzon> It's just a pain in the ass
<FromGitter> <girng> luckily i've never had to compile from source
<FromGitter> <girng> i had with godot before, and it's a pita
<FromGitter> <girng> getting all linkers setup n shit
<FromGitter> <girng> i think there is an issue in the programming community in general
<FromGitter> <girng> that's a snake, and ruining lives
<FromGitter> <girng> and not only ruining lives, but wasting valuable time
<FromGitter> <girng> want to hear what it is?
devil_tux has joined #crystal-lang
<FromGitter> <watzon> Here we go #7925
<FromGitter> <watzon> And what?
<DeBot> https://github.com/crystal-lang/crystal/pull/7925 (Proper handling of max-age and expires for cookies)
devil_tux has quit [Ping timeout: 245 seconds]
DTZUZU has joined #crystal-lang
devil_tux has joined #crystal-lang
<Flipez> Hi guys, I want to validate a k8s deployment file which is a deeply nested yaml file. The solution I found is to define the structure as a yaml mapping and check if it matches file. Are there better ways?
<FromGitter> <j8r> You are in the wrong channel for this question Flipez
<FromGitter> <j8r> after a quick search, perhaps https://github.com/instrumenta/kubeval
<Flipez> It is quite the right channel because the validation is part of a crystal tool. But using and existing one might be not the worst idea. Thanks! :)
<FromGitter> <watzon> Well it's public https://github.com/watzon/arachnid
<FromGitter> <watzon> Still have a lot of work to do, but it's well on its way
devil_tux has quit [Ping timeout: 245 seconds]
devil_tux has joined #crystal-lang
<FromGitter> <j8r> Validating YAML is a thing, but validating a YAML file conformance to Kubernetes spec is even better.
rohitpaulk has joined #crystal-lang
rohitpaulk has quit [Ping timeout: 245 seconds]
rohitpaulk has joined #crystal-lang
devil_tux has quit [Ping timeout: 245 seconds]
<alex``> How about doubling for escaping?
<alex``> puts "foo""bar"
<alex``> > foo"bar
robacarp has quit [Ping timeout: 246 seconds]
<FromGitter> <Blacksmoke16> @girng using puts is fine as long as you only ever want to log to STDOUT and have limited control over when/how/what happens with those messages
robacarp has joined #crystal-lang
<FromGitter> <Blacksmoke16> benefit of crylog and/or the other logging frameworks is that you could define like a "pipeline" of what should happen to each logged message.
<FromGitter> <Blacksmoke16> could get printed to STDOUT, then to a file, or sent to https://github.com/Sija/raven.cr if its an error
<FromGitter> <mistergibson> I'm partial to a log-ring configuration where several loggers are 'tuned in' to the logging message chain.
<FromGitter> <Blacksmoke16> just adds flexibility
<FromGitter> <mistergibson> then what I do is set various logger instances to diff. levels and output directives
devil_tux has joined #crystal-lang
<FromGitter> <Blacksmoke16> thats essentially what mine and @watzon's things do
<FromGitter> <Blacksmoke16> each handler has a min level it will act on
duane has quit [Ping timeout: 252 seconds]
<FromGitter> <mistergibson> cool
<FromGitter> <mistergibson> I like doing it that way because I can have a db-based event logger, a text-file output logger and console etc
<FromGitter> <Blacksmoke16> exactly thats what it does.
<FromGitter> <mistergibson> yeah, much more flexible
<FromGitter> <Blacksmoke16> each of those would just be a handler
<FromGitter> <mistergibson> yup
<FromGitter> <Blacksmoke16> mhm
<FromGitter> <Blacksmoke16> also have processors that allows you to do something like ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d136371501ea60f124a98c9]
<FromGitter> <Blacksmoke16> which when registered to each channel, when you do like `Crylog.logger.info "Some event"
<FromGitter> <Blacksmoke16> it just magically also has the id of the user related to that event
<FromGitter> <mistergibson> nice
DeBot has quit [Ping timeout: 258 seconds]
jhass has quit [Ping timeout: 245 seconds]
asterite has quit [Ping timeout: 252 seconds]
DeBot has joined #crystal-lang
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
<FromGitter> <girng> @Blacksmoke16 yeah it's cool
duane has joined #crystal-lang
rohitpaulk has quit [Ping timeout: 244 seconds]
gangstacat has quit [Ping timeout: 252 seconds]
<FromGitter> <girng> @mwlang looks like Int64, String, and Float64?
<FromGitter> <girng> I wonder if a Union would work here
<FromGitter> <girng> That's a good example usecase of it, right?
<FromGitter> <Blacksmoke16> https://forum.crystal-lang.org/t/statically-parse-csv-to-hash/882/9?u=blacksmoke16 this is what already happens when you use json mapping
<FromGitter> <Blacksmoke16> did you go full circle :P
<FromGitter> <girng> probably
<FromGitter> <girng> let me re-read
<FromGitter> <Blacksmoke16> `JSON.mapping({name: String, min_value: Int32, max_value: Int32, mod_type: String})`
<FromGitter> <Blacksmoke16> `MyClass.from_json`
<FromGitter> <girng> Yeah I guess the mapping would be the same
<FromGitter> <girng> now for JSON.parse, I still think it could be made even better
<FromGitter> <Blacksmoke16> but you would still need a mapping to tell what types each thing is
<FromGitter> <Blacksmoke16> which at that point, you're doing JSON.mapping
<FromGitter> <girng> especially since macros allow you to read data at compile time, it should be possible to detect if a value is a string and int32, or w/e and statically type them
<FromGitter> <Blacksmoke16> but you cant tho
<FromGitter> <girng> this way, there is no need for method invocation calls to be used
<FromGitter> <girng> there is an example remember that lets you read file in macro
<FromGitter> <Blacksmoke16> you can read a file at compile time with a macro, but it would just be a string
<FromGitter> <Blacksmoke16> the parsing of the json would still happen at runtime
<FromGitter> <Blacksmoke16> it would just be like embedding the contents of the file in the binary at compile time
<FromGitter> <Blacksmoke16> vs actually *doing* the parsing at compile time
<FromGitter> <girng> but if that string starts with " it'll be a string, if it starts with a number, int32 or int64, if it contains a `.`, most likely a float, etc
<FromGitter> <girng> since JSON.parse makes the process so easy to parse dynamic data, it should do that to make it even more powerful
<FromGitter> <girng> now, this removes the need for method invocation calls all over
<FromGitter> <Blacksmoke16> let me know when you have a working example :p
<FromGitter> <girng> since it's statically typed now
<FromGitter> <Blacksmoke16> imo you shouldnt be using the data from `JSON.parse` throughout your app
<FromGitter> <Blacksmoke16> should convert it into objects asap
<FromGitter> <tenebrousedge> I would agree with this
<FromGitter> <girng> but, if it's statically typed.. why not?
<FromGitter> <Blacksmoke16> because that doesnt exist atm
<FromGitter> <girng> well, what if i can get this to work
<FromGitter> <Blacksmoke16> or ever will tbh
<FromGitter> <Blacksmoke16> i would be impressed :P
<FromGitter> <Blacksmoke16> would be a cool feature
<FromGitter> <girng> i'm telling you there has to be way
<FromGitter> <girng> believe me
<FromGitter> <girng> from what i've seen with your initializer trick
<FromGitter> <Blacksmoke16> i think it could work in small examples, but for it to be robust enough for real usage, prob not
<FromGitter> <girng> and bcardiff's example, it's def possible
<FromGitter> <kinxer> @girng Are you thinking of statically-typing data that you read once at compile-time or statically-typing data that you read at runtime?
<FromGitter> <girng> compile-time
<FromGitter> <girng> or runtime, if you use a trick
<FromGitter> <girng> blacksmoke's initializer trick might work, but i don't know
asterite has joined #crystal-lang
<FromGitter> <Blacksmoke16> imo only reason his thing works is because its CSV
<FromGitter> <Blacksmoke16> i.e. flat
gangstacat has joined #crystal-lang
<FromGitter> <Blacksmoke16> and he manually told it what each value should be
<FromGitter> <kinxer> I think you could do it at compile-time. I don't think you could statically-type JSON data in a generic `.parse` method at runtime.
jhass has joined #crystal-lang
<FromGitter> <girng> What I'm saying is: If you can use if statement in a macro, you should be able to statically type strings dependent on their value. And use a certain ruleset. ⏎ For example: if a string starts with a ", it's a string. If it starts with a number, it's going to be either Int64, Int32 or a float. If it contains a `.`, it's most likely a float. If it starts with a "{" or "[", it's going to be an object, or an
<FromGitter> ... array respectively. ⏎ ⏎ These certain rules should be able to be coded in macro land, while parsing JSON, and make the values statically typed. [https://gitter.im/crystal-lang/crystal?at=5d1381416fb02f5f6935d4e8]
<FromGitter> <Blacksmoke16> ☝️ June 26, 2019 10:25 AM (https://gitter.im/crystal-lang/crystal?at=5d13805f0a60964f8a904015)
<FromGitter> <bararchy> @Blacksmoke16 So... we made that happen in NeuraLegion 😁
<FromGitter> <Blacksmoke16> im not saying its a bad thing, but for what @girng is saying, thats a lot harder
<FromGitter> <bararchy> we have a class that huristiclly traverse JSON dynamiclly and build objects areound it XD
<FromGitter> <girng> Basically, this ruleset, but in a macro before parsing
<FromGitter> <kinxer> If you managed that, it would be *much* slower than using `JSON::Serializable`. And you would still need to access it somehow in a statically-typed way, which seems like it would be hard.
<FromGitter> <girng> Well yeah JSON.parse is inherently slow already
<FromGitter> <girng> slower*
<FromGitter> <girng> But this makes it a lot easier to use
<FromGitter> <girng> why not make it even easier for thed eveloper?
<FromGitter> <Blacksmoke16> i mean its not tho
<FromGitter> <Blacksmoke16> sec
<FromGitter> <bararchy> @girng for API and communication it's much better to define objects beforehand, also for security reasons and for flow. ⏎ This way there are no suprises
<FromGitter> <Blacksmoke16> i already proved this a while ago
<FromGitter> <girng> if the developer doesn't litter their code with to_i, as_i, etc, it's already innately better.
<FromGitter> <Blacksmoke16> which you would get if you used JSON.mapping or the serializable stuff
<FromGitter> <kinxer> ^
<FromGitter> <bararchy> ^ yeha
<FromGitter> <girng> i'm taling about json.parse
<FromGitter> <girng> yes, i know JSON.mapping is better
<FromGitter> <girng> i'm just saying, why not make JSON.parse even better than the current functionality of JSON.parse
<FromGitter> <Blacksmoke16> make a PR :p
<FromGitter> <girng> i'm trying to brainstorm
<FromGitter> <bararchy> JSON.parse should ONLY be used when there is NO way of knowing what data will be coming
<FromGitter> <Blacksmoke16> is what it should be used for
<FromGitter> <girng> omg lol
<FromGitter> <bararchy> Maybe I didn't get what you meant @girng , sorry if the vibe is "DO THISE!!!!"
<FromGitter> <bararchy> lol
<jokke> :)
<jokke> barachy: i have one problem with json serializable: what if you have a sort of "discriminator"? Like a "type" key in the json object, which determines what class it should be deserialized into.
<FromGitter> <Blacksmoke16> doesnt exist
<FromGitter> <Blacksmoke16> not really an easy way to do that atm
<jokke> yeah
<jokke> which is sad, because many json api standards have this
<FromGitter> <girng> i mean
<FromGitter> <bararchy> jokke you use the "alias" like option
<jokke> barachy: hm?
<FromGitter> <girng> why is JSON.parse even in the language then if crystal is statically typed?
<FromGitter> <bararchy> "which determines what class it should be deserialized into." ⏎ Sorry, I thought you meant regarding key name that might collide
<FromGitter> <Blacksmoke16> so you can consume JSON that you dont know the structure to before hand
<FromGitter> <girng> write a schema
<FromGitter> <Blacksmoke16> but are some legitimate cases where you cant do that
<FromGitter> <Blacksmoke16> example being, my latest project with the JQ wrapper
<FromGitter> <Blacksmoke16> more related to `YAML.parse` but same idea
<FromGitter> <Blacksmoke16> since its a CLI tool, the user can give it any yaml, so i have to use yaml.parse
<jokke> Blacksmoke16: why can't you parse it into Hash?
<FromGitter> <girng> well, if a developer doesn't know incoming json beforehand they shouldn't be using a statically typed language
<FromGitter> <kinxer> @jokke I use abstract superclasses with custom `self.new` and `self.from_json`, but it might just be that my approach happens to work for GeoJSON.
<FromGitter> <girng> am i right?
<FromGitter> <Blacksmoke16> im just converting it into json, so like `YAML.parse(STDIN).to_json`
<FromGitter> <kinxer> No, I don't think you're right, @girng.
<FromGitter> <girng> why not?
<FromGitter> <girng> statically typed language implies you write out the types for values
<FromGitter> <kinxer> You should be able to handle unexpected JSON in any language.
<FromGitter> <kinxer> More or less.
<FromGitter> <girng> how can a statically typed language
<FromGitter> <Blacksmoke16> that gets passed to jq for processing
<FromGitter> <girng> know "unexepected json" and convert them to types
<FromGitter> <girng> that makes no sense
<FromGitter> <Blacksmoke16> it cant, hence the need for `JSON.parse`
<FromGitter> <kinxer> If you were determined and had enough time, you could write something to handle unexpected JSON in assembly.
<FromGitter> <Blacksmoke16> technically .parse is still statically typed, its just a union of all possible types
<FromGitter> <kinxer> You have to use runtime tests to assign things to statically-typed variables.
<FromGitter> <girng> so, JSON.parse was added, so the developer can now use an object like how they would in a dynamically typed language/
<FromGitter> <girng> see where i'm going
<FromGitter> <girng> why mix and match?
<FromGitter> <girng> statically typed values or bust
<FromGitter> <Blacksmoke16> *which is the developer's responsibility to use correct*. i.e. use `JSON.mapping/Serializable` for known schemas, and `JSON.parse` for unknown
<FromGitter> <kinxer> Right, but you still get the benefit of being able to then create statically-typed data using that dynamic data.
<FromGitter> <Blacksmoke16> ^
<FromGitter> <girng> how?
<FromGitter> <girng> isnt' that my thread was all about
<FromGitter> <kinxer> Also, you get the benefits of the speed from a compiled language and only having one program rather than having to deal with communication between different programs.
<FromGitter> <Blacksmoke16> manually new up objects, casting each key/value to proper types
<FromGitter> <Blacksmoke16> like i did in your csv thing
<FromGitter> <girng> > being able to then create statically-typed data using that dynamic data.
<FromGitter> <girng> should be doen automatically, by JSON.parse then
<FromGitter> <girng> by that logic
<FromGitter> <girng> but it does not
<FromGitter> <j8r> no
<FromGitter> <Blacksmoke16> we're not saying it wouldnt be nice to have. im saying at least i dont think you could do it easily
<FromGitter> <j8r> It should be done automatically with an object
<FromGitter> <j8r> like `MyStruct.from_json`
<FromGitter> <j8r> which populates the struct
<FromGitter> <girng> yeah that's nice
<FromGitter> <j8r> like in Go
<FromGitter> <j8r> I had a draft, but didn't have the time to progress on it :/
<FromGitter> <girng> @j8r but in the context of json.parse usage
<FromGitter> <girng> is what i mean
<FromGitter> <j8r> Anyway somehow @girng a mapping has to be provided, whatever the aspect is
<FromGitter> <naqvis> Strange enough that `Int64` is unable to take octal value of `Int64::MAX` ⏎ ⏎ ```Int64::MAX.to_s(8).to_i64 #=> Invalid Int64: 777777777777777777777``` ⏎ ⏎ While I believe Int64 should be sufficient enough to store such value [https://gitter.im/crystal-lang/crystal?at=5d138637e6ae0b757c67c392]
<FromGitter> <j8r> that's the main point of static, the mapping won't change
<FromGitter> <girng> @j8r but the thing is, a mapping doesn't need to be provided to json.parse
<FromGitter> <j8r> yes, that's why it's dynamic
<FromGitter> <j8r> we have to do checks
<FromGitter> <girng> it basically makes you use a method dynamically, in a statically typed languages
<FromGitter> <j8r> yes exactly
<FromGitter> <girng> but crystal is statically typed...
<FromGitter> <girng> so how is that even a thing
<FromGitter> <Blacksmoke16> ☝️ June 26, 2019 10:43 AM (https://gitter.im/crystal-lang/crystal?at=5d1384a2f040bc5fb6cb87f8)
<FromGitter> <j8r> yep thanks to unions
<FromGitter> <girng> @Blacksmoke16 ic, so it's statically typed as a union
<FromGitter> <Blacksmoke16> right
<FromGitter> <girng> that's why the method invocation is required
<FromGitter> <Blacksmoke16> right
<FromGitter> <j8r> I guess there are internal type checks (null) we don't see
<FromGitter> <Blacksmoke16> to get rid of the union and narrow the type down to a specific thing
<FromGitter> <girng> i don't know how i feel about that, but i mean yeah it's nice if the dev doesn't know the json data in advance
<FromGitter> <girng> but IMO it seems like it doesn't fit "statically typed", but then again, it kinda does, since it's a union
<FromGitter> <girng> so nvm i don't know anymore
<FromGitter> <j8r> objects can be created at runtime
<FromGitter> <kinxer> That's an example of what it seemed like you were suggesting, @girng, and why I think there would still be typing issues.
<FromGitter> <j8r> Hash and Array are classes, so heap, so runtime, so recursiveness is allowed - or am i wrong?
<FromGitter> <j8r> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d13880a6fb02f5f69360c46]
<FromGitter> <watzon> @naqvis `Int64::MAX = 9223372036854775807` but the Octal version is `777777777777777777777` which is much larger in base 10
<FromGitter> <watzon> And then there's the binary version `111111111111111111111111111111111111111111111111111111111111111`
<FromGitter> <watzon> The smaller the base the more characters it's going to have
sz0 has quit [Quit: Connection closed for inactivity]
<FromGitter> <naqvis> @watzon yeah I understand the fact, but my question was shouldn’t the 64bits enough to store such number? Other languages does allow to store octal version of Int64::MAX under same type.
<FromGitter> <watzon> It shouldn't be, the reason being that the base10 version of the octal version of `Int64::MAX` is larger than the maximum size of `Int64`
<rkeene> Wut ?
<rkeene> The base is a representation when converted to some kind of text form -- the storage required is actually based on how the computer stores chunks of information so internally it will be stored as 1 single value (you can think of this as base 2^64 if you want)
<FromGitter> <watzon> The octal version of `Int64::MAX` has 4 more characters
<FromGitter> <watzon> When you try to convert it back into an integer it is too big
<rkeene> Are you talking about the number of bytes that's required to store it as a string (i.e., render the numeric value as text) ?
<FromGitter> <watzon> No
<rkeene> Then you are misunderstanding something fundamental
<FromGitter> <naqvis> for example below snippet from GoLang would work without any error ⏎ ⏎ ```var a int64 = 0777777777777777777777``` ⏎ ⏎ btw that’s octal representation of `Int64::MAX` [https://gitter.im/crystal-lang/crystal?at=5d1390cf6e07c2047066caa1]
alex`` has quit [Quit: WeeChat 2.5]
<FromGitter> <watzon> I'm talking about why the octal version has more characters and thereby can't fit into a `Int64` when in base10
<rkeene> Int64 is *NOT* base 10
<FromGitter> <naqvis> aha
<FromGitter> <watzon> 9223372036854775807 is base 10
<rkeene> Sure, if you want to pick an arbitrary base
<FromGitter> <naqvis> yeah
rohitpaulk has joined #crystal-lang
<FromGitter> <watzon> `"777777777777777777777"` is what you get when you convert `Int64::MAX` to an octal using `Int64::MAX.to_s(8)`
<FromGitter> <watzon> Trying to convert it back into an Int64 overflows because `to_i64` doesn't know the base
<FromGitter> <naqvis> i’m working on some binary format, where data internally is stored in Octal representation, so I figured this out during my test spec, where I try to test the functionality against multiple scenarios
<rkeene> 0777777777777777777777 === 2^63-1 === 9223372036854775807
<FromGitter> <watzon> `to_i64(8)` works though
<FromGitter> <watzon> In crystal it's `0o777777777777777777777`, but yes I know
<FromGitter> <watzon> I was trying to explain to him why this `Int64::MAX.to_s(8).to_i64` doesn't work
<FromGitter> <watzon> This `Int64::MAX.to_s(8).to_i64(8)` would though
<FromGitter> <naqvis> and I got your point @watzon, thanks for clarification. I thought of it might be some compiler or related conversion issue or tirgger for some overflow check, so thought of bringing it here for discussion and clarification
<FromGitter> <watzon> Yeah it's expected behavior since `to_i64` uses base10 by default
<FromGitter> <naqvis> thanks @watzon
<FromGitter> <watzon> No problem
<FromGitter> <kinxer> @girng An example of creating statically-typed data from dynamic data: https://play.crystal-lang.org/#/r/74xp (in a real application there would be error checking for if certain keys aren't present or values aren't the right "types")
<FromGitter> <watzon> Hey @RX14, why was https://github.com/RX14/parallel.cr archived? Is there something wrong with it?
duane has quit [Ping timeout: 244 seconds]
sagax has quit [Ping timeout: 252 seconds]
<FromGitter> <girng> @kinxer yeah that's interesting to me
<FromGitter> <girng> statically typed language, but the ability to be dynamic as well. and the ability to convert dynamic data to statically typed values at runtime
<FromGitter> <girng> i guess i'm going to just think of it as a feature
<FromGitter> <girng> if it doesn't hurt my gameserver code, i'm fine with it ;D
sagax has joined #crystal-lang
rohitpaulk has quit [Ping timeout: 252 seconds]
<FromGitter> <Blacksmoke16> i mean its not dynamic
<FromGitter> <Blacksmoke16> its just a union
<FromGitter> <Blacksmoke16> so would still have compile time safety, as it would throw like `undefined method '+' for JSON::Any`
<FromGitter> <girng> but you have to invoke methods on it everywhere you use it (json.parse), so it's not really statically typed either
<FromGitter> <j8r> I guess there are runtime conditions where there is an union?
<FromGitter> <girng> it's like in the middle
<FromGitter> <Blacksmoke16> those methods you invoke on it are making the value a single type
<FromGitter> <Blacksmoke16> i.e. removing the others from the union
<FromGitter> <girng> why does it have to be done every single time instead of just once at runtime
<FromGitter> <Blacksmoke16> because its not changing the values in the hash generated from parse
<FromGitter> <girng> i guess it boils down to
<FromGitter> <girng> if the dev thinks union is dynamic or statically typed
<FromGitter> <j8r> the union is known at compile time
<FromGitter> <girng> how can a union be statically typed to a certain value, if it can hold a plethora of types
<FromGitter> <Blacksmoke16> its in itself a static type
<FromGitter> <girng> but on the other hand, it's technically statically typed
<FromGitter> <j8r> but the values of the types inside an union, not necessarily
<FromGitter> <Blacksmoke16> just not a helpful one
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/74y1
rohitpaulk has joined #crystal-lang
<FromGitter> <Blacksmoke16> the method calls tell it that value should be of the respective type
<FromGitter> <Blacksmoke16> removing the other types from the union
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/74y5 like this wont compile since the type each those values is `JSON::Any` where the the initializer is expecting a `String` and a `Float64`
<FromGitter> <j8r> An Union is in fact a generic struct, `String | Int32 == Union(String, Int32)`
<FromGitter> <girng> i wonder if.. the developer can permanently alter the unions internally from json.parse so method invocation don't need to happen everytime you access a key
<FromGitter> <Blacksmoke16> why dont you just drop the `JSON.parse` and use objects?
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/74y7
<FromGitter> <watzon> ^ this
devil_tux has quit [Ping timeout: 246 seconds]
<FromGitter> <Blacksmoke16> whether that be newing up objects after casting their types like in that playground link, or using `JSON.mapping` or `JSON::Serializable`
<FromGitter> <watzon> If there's one thing @Blacksmoke16 knows it's JSON (de)serialization
<FromGitter> <Blacksmoke16> it would be soo much easier for you
<FromGitter> <Blacksmoke16> and prob make your thing much much faster
<FromGitter> <Blacksmoke16> based on the benchmarks i linked earlier
<FromGitter> <girng> i have over 73~ game functions that use method invocation from json.parse, odn't feel like re-writing everything to use a class
<FromGitter> <kinxer> Will you maintain this game after you make it available to people?
<FromGitter> <kinxer> Add features, fix bugs, etc.?
<FromGitter> <Blacksmoke16> because thats going to be a nightmare
<FromGitter> <girng> hell yeah
<FromGitter> <girng> nah i catch everything in all the methods
<FromGitter> <girng> rescue*
<FromGitter> <Blacksmoke16> 😐
<FromGitter> <Blacksmoke16> im scared to see the source :P
<FromGitter> <girng> if there is an error or server crash
<FromGitter> <kinxer> It's going to save a lot of time in the long run if you take the time now to convert to objects instead of using `JSON.parse`.
<FromGitter> <girng> it's logged and ic an find where it happened
<FromGitter> <Blacksmoke16> so much code could prob be shared/simplified
<FromGitter> <kinxer> Okay, but what if the bug doesn't cause an exception?
<FromGitter> <girng> never experienced that yet
<FromGitter> <girng> i hope it does
<FromGitter> <kinxer> The hardest to find bugs are the ones that don't cause code failures but just cause wrong behavior.
<FromGitter> <girng> i have faith in crystal
<FromGitter> <Blacksmoke16> would help if he wrote tests too :P
<FromGitter> <girng> error reporting is quite nice
<FromGitter> <kinxer> It's not a Crystal issue.
<FromGitter> <Blacksmoke16> its going to be a nightmare for people to contribute to your game without tests
<FromGitter> <girng> if there is a bug like a game bug (dupe), then that's my fault
<FromGitter> <Blacksmoke16> there's no way to manually test an entire game after every change
<FromGitter> <tenebrousedge> ^
<FromGitter> <kinxer> No programming language is gonna fix semantic bugs (kinda like most spell checkers won't catch a misspelled word that's also a word, like if you accidentally typed `rime` when you meant `time`).
<FromGitter> <girng> crystal will error on that
<FromGitter> <girng> when i compile tho
<FromGitter> <girng> so i'm fine
<FromGitter> <Blacksmoke16> assumings its a local variable and not `["rime"]`
<FromGitter> <Blacksmoke16> which be runtime since you're using `JSON.parse`
<FromGitter> <girng> it's really simple. if crystal compiles, and you rescue everything and right good code, your gonna be ok
<FromGitter> <kinxer> The spell checker bit was an analogy. I wasn't actually talking about typos like that in your code.
<FromGitter> <girng> trust me
<FromGitter> <Blacksmoke16> 😕
<FromGitter> <girng> write*
<FromGitter> <Blacksmoke16> i disagree but ok
<FromGitter> <Blacksmoke16> in a perfect world you wouldnt have to rescue much since the architecture of your system wouldnt require every method to have a rescue block
<FromGitter> <girng> true, but i rescue everything just in case that player's fiber'd connection crashes
<FromGitter> <girng> so it doesn't crash the entire server
<FromGitter> <Blacksmoke16> which would be tested to assert changes to the system dont break functionality without manually testing everything
<FromGitter> <girng> just their connection, it's nice
<FromGitter> <tenebrousedge> "If it compiles, ship it" is supposed to be a parody
<FromGitter> <girng> "and write good code"
<FromGitter> <girng> don't forget that part
<FromGitter> <kinxer> The thing is, nobody writes 100% good code.
<FromGitter> <tenebrousedge> no one writes perfect code consistently
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
<FromGitter> <girng> that's why the compiler errors for you
<FromGitter> <Blacksmoke16> cant catch everything
<FromGitter> <tenebrousedge> unless it doesn't
<FromGitter> <girng> and catching raises exist
<FromGitter> <girng> then thed eveloper is writing bad code
<FromGitter> <tenebrousedge> no
<FromGitter> <tenebrousedge> things happen
<FromGitter> <girng> LOL
<FromGitter> <girng> developer still at fault tho
<FromGitter> <tenebrousedge> we have had catches and compilers for decades, and we still have tests
<FromGitter> <tenebrousedge> this isn't about fault
<FromGitter> <girng> tests don't work for everything
<FromGitter> <girng> and are overrated
<FromGitter> <Blacksmoke16> 😐
<FromGitter> <Blacksmoke16> i disagree but you do you
<FromGitter> <Blacksmoke16> let me know how things are going a year from now
<FromGitter> <girng> if i had to write tests for all my code, and how it's based on dynamic action from players, i wouldn't even be anywhere close to where i'm at now in terms of the amount of code i have written
<FromGitter> <girng> sure, testing stuff every now and then is good
<FromGitter> <Blacksmoke16> but you would be more confident in the code you did have
<FromGitter> <girng> but writing a test for every single method is a waste of time
<FromGitter> <Blacksmoke16> so as you add/refactor you know it still works
<FromGitter> <Blacksmoke16> i disagree
<FromGitter> <Blacksmoke16> saves time in the long run
<FromGitter> <Blacksmoke16> when you add a new feature, run tests, everything passes, good to go
<FromGitter> <tenebrousedge> tests may not catch everything, and may be overrated, but that's not an argument against tests any more than illegal activity is an argument against laws
<FromGitter> <Blacksmoke16> if a new bug comes up you add a new test that would catch it so it wont happen again
<FromGitter> <girng> yeah cause my new test is going to find out that bug
<FromGitter> <tenebrousedge> tests are really more for catching regressions than bugs, in my experience
<FromGitter> <girng> when the interaction of the method is done dynamically based on a multitude of different variables
<FromGitter> <girng> tests don't always work
<FromGitter> <Blacksmoke16> this is why objects are useful
laaron has joined #crystal-lang
<FromGitter> <tenebrousedge> write code so that you can test it easily
<FromGitter> <Blacksmoke16> then you could test each object's methods in isolation
<FromGitter> <tenebrousedge> ^
<FromGitter> <Blacksmoke16> vs having to run a whole game just to assert 1 + 1 +2
<FromGitter> <Blacksmoke16> then you dont *have* to test your game 100%
<FromGitter> <Blacksmoke16> maybe have a few end to end tests for the critical parts
<FromGitter> <kinxer> @girng Fix the bug. It compiles. https://play.crystal-lang.org/#/r/74yb
<FromGitter> <kinxer> Also, that's an example of a real bug that I run into fairly frequently in Crystal.
<FromGitter> <kinxer> Nicely done.
<FromGitter> <girng> now what's the catch lol
<FromGitter> <girng> cause local variable
<FromGitter> <girng> thought it was modifying it?
<FromGitter> <kinxer> My point is that bugs like that can be subtle, and compilation doesn't catch everything.
<FromGitter> <girng> yeah that's true
<FromGitter> <girng> i agree
<FromGitter> <tenebrousedge> but a unit test that checked whether the value changed would make sure that code keeps working, no matter how you change the implementation
<FromGitter> <girng> i mean it's a game there will always be bugs
<FromGitter> <kinxer> I'm not sure I have time to write out a harder example, but testing really is as useful as people say it is, especially if you're writing tests before you implement stuff.
<FromGitter> <kinxer> Does Pong have bugs?
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/74yp
<FromGitter> <kinxer> That's a really good spec example, @Blacksmoke16
<FromGitter> <tenebrousedge> writing tests beforehand is not something I'm very sold on
<FromGitter> <kinxer> I only use it sometimes.
<FromGitter> <girng> if a crystal developer doesn't use @ to modify the instance variable
<FromGitter> <Blacksmoke16> is nice when you're refactoring old code that didnt have tests before
<FromGitter> <girng> sounds like they deserve that bug
<FromGitter> <Blacksmoke16> can write the tests, refactor the code, and make sure tests still pass
<FromGitter> <Blacksmoke16> not exactly the same, but still useful
<FromGitter> <tenebrousedge> it could be argued that not using the `@` is best practice
<FromGitter> <girng> the more you understand crystal code and the more confident you are, even less motivation to write tests
<FromGitter> <Blacksmoke16> i disagree
<FromGitter> <Blacksmoke16> i always want to write as many tests as i can, so when i come back to something, or change something i have full confidence everything still works
<FromGitter> <Blacksmoke16> (prob too many in some cases)
<FromGitter> <Blacksmoke16> depends on the project ofc, something i have open sourced like athena, yes. Some random thing i made for myself, no i prob wouldnt bother
<FromGitter> <girng> i like that and think it's prob a good idea, but just not 4 me
<FromGitter> <kinxer> Also, we're programmers. We automate things so certain tasks are easier and more consistently correct. If we can do that with the actual process of programming (using tests) so that we don't have to hunt through everything when we make a change and something breaks, then it makes sense for us to do so.
<FromGitter> <Blacksmoke16> mhm, gets kinda fun to see all the green dots :P
<FromGitter> <kinxer> It really is. :P
<FromGitter> <girng> i have wrote thousands of crystal code. the only time a bug like that example got me, that wasn't caught was that array issue @dscottboggs_gitlab or @Blacksmoke16 helped me with. where the instance variable of an array was shared across all instances of a class. cause i had it referenced to a Const Array.
<FromGitter> <girng> That was the instance variable for the character's image array (itemids of what items are equipped). So that would have been a very nasty bug
<FromGitter> <Blacksmoke16> but what about 6 months from now when it may not be as fresh in your memory
<FromGitter> <Blacksmoke16> or when other people want to contribute to it
<FromGitter> <girng> One player changes their equipment, and al players on that game instance are updated as well lol
<FromGitter> <tenebrousedge> I just like having a better handle on where things break. You start your app, it renders, but the FooBox is blank. What layer of the app caused that?
<FromGitter> <girng> that's actually a good example of what @kinxer 's example was. a bug like that is not caught by an exception
<FromGitter> <girng> caught by players reporting issues, which will take up even more time
<FromGitter> <girng> and harder to track
<FromGitter> <girng> but that was me writing bad code, but i got help from the community so it's all good
<FromGitter> <girng> i want to reproduce that bug in a playground link cause i find it fascinating
<FromGitter> <tenebrousedge> everyone writes bad code all the time. Even if it's correct today, the requirements will change tomorrow
<FromGitter> <kinxer> If that's the only non-exception bug that you have in your game server at this point, you're very lucky.
<rkeene> tenebrousedge, That's why I only write code that I'm the only user of -- it's the only way to be sure
<FromGitter> <girng> @kinxer look at how much i get help with gitter lol it helps
<FromGitter> <tenebrousedge> @rkeene I don't even trust *myself* that much
<FromGitter> <girng> BOOM
<FromGitter> <kinxer> @girng And that's good, and I at least am happy to help. But the debugging process is a lot easier with tests. If you continue programming, particularly in Crystal, which has such an easy testing framework, I suspect you will come around to it at some point. Maybe not, though.
<FromGitter> <girng> nastiest bug ever LOLOL
<FromGitter> <girng> solution was to use .dup or just do an inline explicit https://play.crystal-lang.org/#/r/74z9
<FromGitter> <girng> @kinxer i understand and appreciate it
laaron has quit [Remote host closed the connection]
rohitpaulk has quit [Ping timeout: 245 seconds]
<FromGitter> <tenebrousedge> tests encourage other more subtle best practices, like DI, loose coupling, and strong scope boundaries
<FromGitter> <Blacksmoke16> DI is cool
<FromGitter> <girng> what is a dependency injection example in crystal look like?
<FromGitter> <Blacksmoke16> sec
<FromGitter> <tenebrousedge> so your app uses a logging framework, which normally logs to syslog or something
<FromGitter> <Blacksmoke16> the `Testing` point at the bottom is most relevant
<FromGitter> <Blacksmoke16> `Since the type restrictions of the initializer arguments can be set to "interfaces", this can be utilized to mock out classes to pass to the service. The main use of this would be for unit testing the services; allowing the service to use mocked instances as to not depend on external dependencies. This could either be a new class that inherits from the actual one, or a new class that inherits/includes a
<FromGitter> ... class/module of that type.`
<FromGitter> <tenebrousedge> instead of accessing it as `logger = Logger.new()`, you basically do anything other than that
<FromGitter> <girng> this sounds extremely convoluted
<FromGitter> <Blacksmoke16> let me make a simple example
<FromGitter> <tenebrousedge> you can just do `def my_method(logger = Logger.new)`
<FromGitter> <girng> so it's like allowing another method access to another class?
<FromGitter> <tenebrousedge> you want all the things that a method uses to be passed in
<FromGitter> <girng> isn't this just pass by reference
<FromGitter> <tenebrousedge> you could also use a `getLogger` method, or a DI container (`DI.get("Logger")`)
rohitpaulk has joined #crystal-lang
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/74zj
<FromGitter> <Blacksmoke16> its kinda a contrived example, but you should get the idea
<FromGitter> <Blacksmoke16> basically allows a class to have "plug and play" elements, as long as they implement the same "interface"
<FromGitter> <Blacksmoke16> which makes testings much easier as you can mock out those services, so you can test *ONLY* the class you want
<FromGitter> <Blacksmoke16> vs having to deal with those other dependencies
<FromGitter> <tenebrousedge> so among other things you're forcing yourself to develop code in small (easily independently testable) chunks
<FromGitter> <Blacksmoke16> its best combined with a service container
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d13abecddc34e0f13ebb49f]
<FromGitter> <Blacksmoke16> i think i messed up this example
<FromGitter> <Blacksmoke16> `a_class.a_service.store.name` and should be a `getter store : Store` in `AService`
<FromGitter> <Blacksmoke16> ill fix that in my docs
<FromGitter> <Blacksmoke16> there isnt really an equivalent thing in crystal atm to easily test the external services, without mocking them out manually
<FromGitter> <tenebrousedge> huh
<FromGitter> <Blacksmoke16> like at work, using PHP Mockery
<FromGitter> <tenebrousedge> what would you want instead?
<FromGitter> <Blacksmoke16> sec
<FromGitter> <Blacksmoke16> ill make an example of what Mockery does
lucasb has joined #crystal-lang
<FromGitter> <tenebrousedge> I think I've used it before, but it was probably a lifetime ago -- last year maybe
<FromGitter> <Blacksmoke16> https://paste.ee/p/w5zc1
<FromGitter> <Blacksmoke16> assuming there is a DI container injecting the apiClient in `SomeClass`
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5d13ae786e07c2047067db2c]
<FromGitter> <Blacksmoke16> is the part i like
<FromGitter> <Blacksmoke16> prob doable in crystal, i just dont think it exists atm
<FromGitter> <Blacksmoke16> under the hood afaik when you do like `m::Mock(ApiClient::class)`, it creates a new class that inherits from that one, so its allowed when typed to `ApiClient`
<FromGitter> <Blacksmoke16> and prob keeps track of method execution/args to assert against your expectations
<FromGitter> <tenebrousedge> sounds like a macro
<FromGitter> <Blacksmoke16> yea https://play.crystal-lang.org/#/r/74zn something like that
<FromGitter> <Blacksmoke16> well you would want to get an instance of it back, but im sure its doable, just needs created afaik
rohitpaulk has quit [Ping timeout: 252 seconds]
<FromGitter> <Blacksmoke16> id love to have something like that tho
<FromGitter> <Blacksmoke16> would make testing with DI much easier/cleaner
rkeene_ has joined #crystal-lang
rkeene has quit [Ping timeout: 258 seconds]
rkeene_ is now known as rkeene
duane has joined #crystal-lang
alex`` has joined #crystal-lang
sz0 has joined #crystal-lang
<jokke> any ideas why i might be getting an error: Invalid encoding: utf-8 (ArgumentError) in a alpine built crystal program?
<jokke> here's my dockerfile: https://p.jokke.space/18a/
<FromGitter> <tenebrousedge> from lib/fogtrack/src/fogtrack/working_on_api.cr:24:9 in '???' <-- doesn't like your input
<FromGitter> <Blacksmoke16> i like the name
<FromGitter> <watzon> Thanks :)
davic has quit [Ping timeout: 250 seconds]
davic has joined #crystal-lang
mps has quit [Ping timeout: 252 seconds]
<FromGitter> <watzon> Now to figure out how to make it faster
<FromGitter> <watzon> A thread pool would be nice
<FromGitter> <watzon> Or having the option to use redis and spawn multiple instances of the crawler
<FromGitter> <Blacksmoke16> `Process.fork`?
mps has joined #crystal-lang
<FromGitter> <watzon> Basically the idea. It would be a major overhaul though.
<FromGitter> <PlayLights_twitter> Great work @watzon :)
<FromGitter> <watzon> Thanks @PlayLights_twitter
<FromGitter> <watzon> With just a small block of code though I was able to generate this sitemap for https://crystal-lang.org in a couple minutes
<FromGitter> <wontruefree> @watzon I love arachnid
<FromGitter> <wontruefree> I have written a few smaller things for a project but this is way more flushed out
<FromGitter> <wontruefree> I see some commented out code https://github.com/watzon/arachnid/blob/master/src/arachnid/agent/robots.cr#L9
<FromGitter> <wontruefree> is there a list of features not working?
<FromGitter> <watzon> Yeah I have a lot of cleanup to do and the robots.txt handling isn't working quite yet
<FromGitter> <watzon> robots.cr is a full robots.txt parser and it works, I just have to make it work with the crawler
<FromGitter> <wontruefree> awesome
<FromGitter> <girng> o_O a web scraper
<FromGitter> <girng> gonna look into that ty
<FromGitter> <watzon> It's still very beta, and may run into issues parsing some cookies until #7925 gets merged
<FromGitter> <girng> damn, nice usage of fibers
<FromGitter> <watzon> But it is working :)
<FromGitter> <girng> for the batch image dling
<FromGitter> <watzon> I'm hoping I can add an actual thread pool soon to make it even faster
<FromGitter> <watzon> But we're going to be a little constrained on speed until Crystal supports parallel processing
<FromGitter> <girng> yeah still tho, it's prob hella fast tho lol
<FromGitter> <watzon> Idk about hella, but it's alright :)
<FromGitter> <girng> unless the image is insanely big and they got slow internet it's prob real slow
<FromGitter> <girng> i don't think crystal will be the bottleneck there it might
<FromGitter> <watzon> Yeah the image downloading is pretty cool, and it works for videos and anything else too
<FromGitter> <girng> oh really
<FromGitter> <girng> that's cool
<FromGitter> <watzon> Right now you have to ability to iterate over every link it finds, including css, js, zip files, images, videos, atom and rss feeds, etc
<DeBot> https://github.com/crystal-lang/crystal/pull/7925 (Proper handling of max-age and expires for cookies)
hightower2 has joined #crystal-lang
<FromGitter> <wontruefree> I am curious why build on Halite instead of the crystal http client in the stdlib?
<FromGitter> <watzon> Because I prefer halite, and it will have proxy support soon which I plan to integrate
<FromGitter> <wontruefree> I like it compared to the default client
<FromGitter> <wontruefree> I dont know if a feature like proxies would be added to the stdlib
<FromGitter> <watzon> I doubt it, although I would be very happy if they did
<FromGitter> <watzon> In built support for SOCKS would be nice too
<FromGitter> <wontruefree> I have a socks proxy in crystal still running
<FromGitter> <wontruefree> I have not checked the server for a while but the service is still working
<FromGitter> <wontruefree> https://github.com/wontruefree/socks
<FromGitter> <watzon> Yeah I saw that, starred it a few minutes ago
<FromGitter> <watzon> Great work
<FromGitter> <Daniel-Worrall> Has advanced pattern matching been addressed or discussed before? As here. Being able to check multiple properties on an object in a case https://github.com/tc39/proposal-pattern-matching
<FromGitter> <watzon> Hahaha https://www.yelp.com/robots.txt
<FromGitter> <wontruefree> Thanks !
<FromGitter> <Blacksmoke16> i feel like most of that could be done with the current case
<FromGitter> <Daniel-Worrall> *in a switch
<FromGitter> <Blacksmoke16> you can override `===(other)` in your class to alter the behavior of the case
<FromGitter> <Blacksmoke16> i.e.
<FromGitter> <Blacksmoke16> ```case response ⏎ when 200 then puts "success" ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5d13d899d65dae046f950a71]
<FromGitter> <watzon> It could, but I like the pattern matching syntax
<FromGitter> <Blacksmoke16> which you could have `===` in your `Response` obj be whatever you want
<FromGitter> <Daniel-Worrall> Yeah I like the pattern matching syntax. Looks very intuitive
devil_tux has joined #crystal-lang
<FromGitter> <watzon> I think I need to take a break
rohitpaulk has joined #crystal-lang
rohitpaulk has quit [Ping timeout: 272 seconds]
devil_tux has quit [Ping timeout: 245 seconds]
devil_tux has joined #crystal-lang
devil_tux has quit [Ping timeout: 248 seconds]
<FromGitter> <PlayLights_twitter> Hello, does anybody use granite or is part of the team? I would to know you do some kind of sanitize ?
<FromGitter> <PlayLights_twitter> to avoid SQL injection
<FromGitter> <Blacksmoke16> `Post.all("WHERE name LIKE ?", ["Joe%"])`
<FromGitter> <PlayLights_twitter> Yes im using that feature so I wanted to make sure
<FromGitter> <PlayLights_twitter> is that ok?
<FromGitter> <Blacksmoke16> you can pass them as an array, assuming you're using `.all`, otherwise when using like `find` or `find_by`, they're all sanitized by granite
<FromGitter> <Blacksmoke16> yes, thats the proper way of doing it
<FromGitter> <PlayLights_twitter> cool, thanks so much
alex`` has quit [Ping timeout: 248 seconds]
<FromGitter> <Blacksmoke16> np
<FromGitter> <Blacksmoke16> ofc doing like ``Post.all("WHERE name = #{name}")` is bad
alex`` has joined #crystal-lang