These are chat archives for dry-rb/chat

29th
Jun 2016
garrettlancaster
@garrettlancaster
Jun 29 2016 00:23 UTC
Hi @timriley , I just finished your series of blog posts on dry/roda/rom and really enjoyed them. I'm looking forward to their continuation :)
Tim Riley
@timriley
Jun 29 2016 00:26 UTC
@garrettlancaster thanks! I had a wee break because of RedDotRubyConf but I’ll be back on the blog train again next week.
@garrettlancaster if there’s anything in particular you’d like to see, let me know and I’ll add it to the list.
garrettlancaster
@garrettlancaster
Jun 29 2016 00:31 UTC

Glad to hear it!

As far as things I'd like to see, I've always found permissions/access to be poorly organized in most applications. I've often thought about using the container concept to inject validations and access policies dynamically on a per-request basis, but I would be curious what strategies you've found for appropriately isolating those concerns in an extendable way.

Tim Riley
@timriley
Jun 29 2016 00:31 UTC
That’s actually something I’m yet to do in any serious way. But as soon as we encounter such a requirement in one of our apps, I’ll share our approach.
I’d imagine the injection approach would allow for it to be handled quite cleanly.
garrettlancaster
@garrettlancaster
Jun 29 2016 00:33 UTC
My impression was that dry-containers are set up statically at boot time, is there room for that approach here?
Tim Riley
@timriley
Jun 29 2016 00:35 UTC
how would you see this dynamic-at-request-time thing working?
Andy Holland
@AMHOL
Jun 29 2016 00:36 UTC
@garrettlancaster my original intention was for dry-container to register the request with the container and manipulate it in custom classes in Roda
But it didn't work out, it's better to keep any stateful objects out of the container, so that's why the currying was added when you register using a block with arguments
It simplifies things a lot
So static setup during boot is the best option IMO
@garrettlancaster I was messing about with policies a while ago https://gist.github.com/AMHOL/b0f3e3c3e7b34c155acdddda3eee6f2a
garrettlancaster
@garrettlancaster
Jun 29 2016 00:40 UTC
@timriley Going by a typical "roles & permissions" paradigm: after authorizing the user, a role-specific container would be used for the remainder of the request. If user-level permissions were present, I suppose that might affect the specific injections provided in that container.
@AMHOL interesting, will need to dig into that a bit
Tim Riley
@timriley
Jun 29 2016 00:44 UTC
@garrettlancaster ahh, interesting take. Perhaps rather than providing different containers, what might work instead Is providing a "resolver" for a specific role that returns a bunch of role-specific objects to use...
Andy Holland
@AMHOL
Jun 29 2016 00:50 UTC
You end up with race conditions when you put request state into the container
i.e.
# request 1
container.register(:request, request)
# request 2
container.register(:request, request)
# request 1
container[:request].redirect '/home' # request 2 user gets redirect
I started trying to solve it by having a detach method on the container, but I found the best option is just not to do that :p
Functional objects in the container with simple input => output is the way to go
garrettlancaster
@garrettlancaster
Jun 29 2016 00:55 UTC

@timriley could you be more specific about which "objects" you are thinking about?

@AMHOL you're right, it would be unfortunate to depend on the full build-up and tear-down of the entire world on each request

Tim Riley
@timriley
Jun 29 2016 01:01 UTC
@garrettlancaster any objects in your system that you wanted to vary by role
@garrettlancaster you were talking about having whole role-specific containers, which I presume would be filled with objects that are for that role
garrettlancaster
@garrettlancaster
Jun 29 2016 01:11 UTC
@timriley Sorry, my thinking is a bit unclear as this is unfamiliar territory. So are you suggesting that rather than injecting e.g. MyContainer['validate_article'] I would inject MyArticleValidationResolver.new into any operations that needed it?
@timriley and then the operation itself would do something like validator = validator_resolver.(params); validator.(params)
garrettlancaster
@garrettlancaster
Jun 29 2016 01:21 UTC
Dinner time, gotta run but will check back later. Thanks again for all the great work you guys are doing, it's the first hint of a practical feeling solution to all of the Rails woes we're all too familiar with.
Daniel Sandbecker
@daniels
Jun 29 2016 07:08 UTC
The other day someone answered a question on "inheriting" a base validation schema and adding additional rules. Now I want to do that too, but I can't find the answer again (gitter search is terrible!). Anyone who can help me out? (What I actually want to do is have a base "AddressSchema" and then a "TemporaryAddressSchema" with the same rules but also require a start and a stop date.)
Tim Riley
@timriley
Jun 29 2016 07:49 UTC
Would it be the first argument to Dry::Validation.Schema?
    def self.Schema(base = Schema, **options, &block)
Daniel Sandbecker
@daniels
Jun 29 2016 07:51 UTC
Forget that, found the spec and it was super simple. :smile:
Tim Riley
@timriley
Jun 29 2016 07:51 UTC
Great!
Daniel Sandbecker
@daniels
Jun 29 2016 08:08 UTC
@timriley I didn't see your answer before posting! Didn't intend to dismiss it - it was exactly what I needed even if I figured it out almost exactly at the same time! So thanks!
Chris Richards
@cmrichards
Jun 29 2016 11:25 UTC

Instead of :

time_op = TimeMath().ceil(:week).advance(:hour, 10)

What about :

T=TimeMath()

T().next_week + T(10).hours

Piotr Solnica
@solnic
Jun 29 2016 11:31 UTC
@cmrichards the downside is that you create objects too many times instead of just defining your calculation once and calling it many times at run-time
Chris Richards
@cmrichards
Jun 29 2016 11:33 UTC
The upside is that it doesn't pollute core objects and feels more intuitive (to me) to use
Piotr Solnica
@solnic
Jun 29 2016 11:36 UTC
yes that would be an improvement
as in lack of global TimeMath method
you could report an issue and ask about that
it’s an alpha-stage lib
Chris Richards
@cmrichards
Jun 29 2016 14:11 UTC
So a monad is basically an object that wraps a returned object from a method and adds additional state that relates to the success or failure of that method?
Piotr Solnica
@solnic
Jun 29 2016 14:16 UTC
@cmrichards Either monad, yes
great primer about monads in ruby right there ^
Chris Richards
@cmrichards
Jun 29 2016 14:17 UTC
thanks, i'll check it out
Chris Richards
@cmrichards
Jun 29 2016 15:26 UTC
How come you didn't use Wrong() instead of Left() ?
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:32 UTC
@cmrichards this was taken from kleisly gem, but the name Left is more ... uhm canonical anyway. You don't have to think about Left as something wrong actually, it's just a common case
so we added helpers #success? and #failure? for that
Chris Richards
@cmrichards
Jun 29 2016 15:33 UTC
Where Left == failure ?
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:33 UTC
yep
Andy Holland
@AMHOL
Jun 29 2016 15:33 UTC
I always thought of it like a flow diagram
Go right for happy path, left for bad path
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:33 UTC
@cmrichards but it's an alias for #left? after all
Chris Richards
@cmrichards
Jun 29 2016 15:34 UTC
For a programmer who doesn't know monads, looking at Left() won't mean anything. It seems a bit arbitrary
Jeff Dickey
@jdickey
Jun 29 2016 15:36 UTC
this; that was my single biggest problem with the video
Piotr Solnica
@solnic
Jun 29 2016 15:36 UTC
@cmrichards this ain’t random, it’s from Haskell https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Either.html
Jeff Dickey
@jdickey
Jun 29 2016 15:37 UTC
speaking for myself, that's what I gathered, but are we expecting people to be comfortable with Haskell idioms to use this Ruby library?
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:38 UTC
I think it's better to call the things with their common names, otherwise those who know about monads will come and ask us why?
Piotr Solnica
@solnic
Jun 29 2016 15:38 UTC
yes I think it’s a good idea to use existing idioms
Chris Richards
@cmrichards
Jun 29 2016 15:38 UTC
But there's also a case for being consistent wth existing ideas
Piotr Solnica
@solnic
Jun 29 2016 15:38 UTC
there’s no equivalent in Ruby anyway
and Success/Failure is for Try monad so there’s that too
Jeff Dickey
@jdickey
Jun 29 2016 15:40 UTC
but that has a bit more implicit knowledge to most Rubyists, I think; methods by those names are used in other libraries and carry plain-English connotations for the meaning of "success" and "failure". Left and right are navigational terms, not logical terms
mixing metaphors
Harry Maclean
@hmac
Jun 29 2016 15:41 UTC
It's maybe worth noting that Rust's equivalents use Ok/Err and Some/None
Piotr Solnica
@solnic
Jun 29 2016 15:42 UTC
not sure about Some/None, it’s for maybe values, not control flow
Left/Right is great for control flow, and I think these names fit prefectly, like Andy said, it’s like going down the execution path and deciding where to go, left when it’s bad, right when it’s good
Jeff Dickey
@jdickey
Jun 29 2016 15:43 UTC
agreed; but I see on RubyGems that over half of Kleisli's downloads to date are from the current version, and I'd bet that a very large subset of those are thanks to dry-rb's use of it
that's fine if you happen to be right-handed :P
but I get it now; I didn't when I first read up on Kleisli
Piotr Solnica
@solnic
Jun 29 2016 15:43 UTC
well, we use it for control flow in dry-transaction, it’s a great pattern, I don’t think monads will ever become a standard way of writing ruby all-the-time so…there’ that
Jeff Dickey
@jdickey
Jun 29 2016 15:44 UTC
true. And, given that I don't have a better idea sitting here at the moment, fine :)
Piotr Solnica
@solnic
Jun 29 2016 15:45 UTC
well, it’s a pretty standard naming…
diverging from that would be rather bad
Jeff Dickey
@jdickey
Jun 29 2016 15:46 UTC
I understand the argument you're making, and I recognise that introducing a new idiom into an existing, highly idiomatic language is always fraught, so yeah; I'll go with the left/right flow here
Piotr Solnica
@solnic
Jun 29 2016 15:47 UTC
:+1: :)
Chris Richards
@cmrichards
Jun 29 2016 15:48 UTC
Seems like it's only the convention that Right is success and Left is failure. Really, Either just means that there are two possibilities, so Left and Right seem fine for that.
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:48 UTC
correct
Piotr Solnica
@solnic
Jun 29 2016 15:49 UTC
we could have Whoops and Pheew aliases too
Jeff Dickey
@jdickey
Jun 29 2016 15:49 UTC
WhenSuccess and NotSuccess, maybe?
Chris Richards
@cmrichards
Jun 29 2016 15:49 UTC
or ThisShouldNeverHappen
Piotr Solnica
@solnic
Jun 29 2016 15:49 UTC
OhNoez Yeah!
jdickey @jdickey crawls back under rock; makes more popcorn
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:52 UTC
I suggest to create dry-burritos gem that will hold all of them :) I mean we need to wrap this scary monad word with sutin more usual
jdickey @jdickey throws hot popcorn at @flash-gordon
Jeff Dickey
@jdickey
Jun 29 2016 15:55 UTC
yeah, fine, how about this; we keep Left and Right as loanwords from Haskell until/unless someone comes up with lower-friction synonyms/aliases for same. Who knows, they might actually catch on
Chris Richards
@cmrichards
Jun 29 2016 15:55 UTC
Right
Jeff Dickey
@jdickey
Jun 29 2016 15:55 UTC
maybe even open that as an issue for further comment along the line
Nikita Shilnikov
@flash-gordon
Jun 29 2016 15:56 UTC
@jdickey I don't remember really where I found it, but that's the old joke, not mine :) Along with "A monad is just a monoid in the category of endofunctors, what's the issue?" :)
Jeff Dickey
@jdickey
Jun 29 2016 15:56 UTC
no. don't. go. there. I just finished cleaning up the grue from the last time my head exploded on a project discussion :P
not to mention that the actual event is painful as hell
Andy Holland
@AMHOL
Jun 29 2016 16:09 UTC
I've had the same thoughts RE Left/Right, I think Success/Failure is the obvious alternative
Piotr Solnica
@solnic
Jun 29 2016 17:34 UTC
@AMHOL they are not, Success/Failure is for handling exceptions
Andy Holland
@AMHOL
Jun 29 2016 17:34 UTC
Ahh OK
Piotr Solnica
@solnic
Jun 29 2016 17:35 UTC
and basicaly Success acts like Right, and Failure as Left, since the monad interface is common
which is what makes it so great
Andy Holland
@AMHOL
Jun 29 2016 17:35 UTC
Nice, I've had very little exposure to monads
Don Morrison
@elskwid
Jun 29 2016 18:08 UTC
There’s real value is using the right terms for concepts/structures/etc. i.e. map, fold, reduce, etc.
Even if we have to go learn. :wink:
Jeff Dickey
@jdickey
Jun 29 2016 18:09 UTC
absolutely
of course, "the right terms" are context-dependent :P
Don Morrison
@elskwid
Jun 29 2016 18:09 UTC
And I know you know that @jdickey.
I just felt like saying something...
wanted it to sound deep
did it work?
Jeff Dickey
@jdickey
Jun 29 2016 18:09 UTC
well, the stone you dropped hasn't hit water yet, so…
Don Morrison
@elskwid
Jun 29 2016 18:10 UTC
oh...
elskwid @elskwid waits
Jeff Dickey
@jdickey
Jun 29 2016 18:10 UTC
there might just be an Ugly Bug Monster sitting at the bottom of the chasm feeding on our flailing :D
Aditya Tiwari
@aditya01933
Jun 29 2016 18:33 UTC
i am using dry validation for accepting params in place of rails strong params. How can i use it to accept nested attributes ?
found it ..
Thanks :)
If I get a response from an api that returns something like this {data: [{_type: 'user', ...}, {_type: 'group', ...}]} is there a way to get dry-types to pickup on the _type property for each returned entity and properly deserialize the json into the correct objects?
Piotr Solnica
@solnic
Jun 29 2016 20:23 UTC
@dnd not yet, you gotta handle it yourself for now
@solnic so I would basically need to remove the data attribute from the json hash, and then manually iterate, and add those to the main response object?
Wilson Silva
@wilsonsilva
Jun 29 2016 20:49 UTC
Using dry-result_matcher and dry-monads, how would you handle two different failure scenarios? For example, say that you are updating a record and you need to retrieve the record from the DB before updating it. If the record is not found you want to return a 404 status code and if the update is not successful, you want to return the status code 422 + error payload.
put '/people/:id' do
  UpdatePerson.new(declared(params, include_missing: false)) do |m|
    m.success do |person|
      person
    end

    m.failure do |errors|
      # check the content of Left and decide?
      status 422
      errors
    end

    # code another block to handle 404?
  end
end
Wilson Silva
@wilsonsilva
Jun 29 2016 21:02 UTC
I see that you have already discussed it here dry-rb/dry-result_matcher#3
Piotr Solnica
@solnic
Jun 29 2016 21:07 UTC
@wilsonsilva yes it's gonna be a new feature in the next release :) Tim is wrapping it up
@dnd ok I guess I didn't get what you want to do :) wdym by pick up on the _type property
@solnic if while deserializing data it came across {_type: 'user', name: 'bob'} it would create an a new instance of User, basically doing User.new({_type:'user', name: 'bob'})
Wilson Silva
@wilsonsilva
Jun 29 2016 21:14 UTC
@solnic Awesome! I'm a big fan of your work.
Piotr Solnica
@solnic
Jun 29 2016 21:15 UTC
@wilsonsilva thank you :) although technically speaking dry-result_matcher and dry-monads were created by Tim and Nikita, respectively :D
Wilson Silva
@wilsonsilva
Jun 29 2016 21:16 UTC
I meant fan of the whole dry-rb and ROM team
Piotr Solnica
@solnic
Jun 29 2016 21:18 UTC
cool, really happy to know that :)
@wilsonsilva iirc Tim is going to push new matcher stuff ~tomorrow so stay tuned!
Tim Riley
@timriley
Jun 29 2016 22:29 UTC
@wilsonsilva @solnic yep, I’ll try for the next couple of hours!
Tim Riley
@timriley
Jun 29 2016 22:46 UTC
Code’s ready. I’m going to rename it to dry-matcher now, then do docs.
Piotr Solnica
@solnic
Jun 29 2016 23:11 UTC
Wooohaaaa
Tim Riley
@timriley
Jun 29 2016 23:18 UTC
@solnic thanks for your contributions to the reddit comments for my RDRC talk :pray:
Piotr Solnica
@solnic
Jun 29 2016 23:29 UTC
@timriley n/p :)
Tim Riley
@timriley
Jun 29 2016 23:30 UTC
Now that I think about it, feels like we could build a solid FAQ section based on responses like yours that you’ve had to write!
Hector Sansores
@hectorsq
Jun 29 2016 23:40 UTC

I want to validate the following yaml file using dry-validation 0.7

remote_printer:
  pusher:
    secret: 'xxx'
    key: 'yyy'
    pid: '1'
    presence: 'zzz'
  labels_printer:
    name: 'ZEBRA'
    port: 'COM4'
  receipts_printer:
    name: 'BIXOLON'
    port: 'COM5'

labels_printer and receipts_printer are optional, but when any of them is present I need to validate that name and port are present too. Any hints?

Piotr Solnica
@solnic
Jun 29 2016 23:45 UTC
@hectorsq optional(:labels_printer).schema { key(:name).filled(:str?); key(:port).filled(:str?) }
you could also pull that out into a re-usable schema and just do optional(:labels_printer).schema(PrinterSchema)
Hector Sansores
@hectorsq
Jun 29 2016 23:48 UTC
@solnic Great! It worked fine. Thank you.
Piotr Solnica
@solnic
Jun 29 2016 23:48 UTC
awesome :)
Tim Riley
@timriley
Jun 29 2016 23:54 UTC
Amazing what a flexible validation library can do!