These are chat archives for dry-rb/chat

12th
Apr 2016
Joe Van Dyk
@joevandyk
Apr 12 2016 00:59
@solnic submitting issue. should that code work in the first place?
Ngan Pham
@ngan
Apr 12 2016 05:16
Hi, is there a way to validate that an attribute is of a certain class? (using dry-validation). I tried doing key(:user).required(type?: User) and it works, but as soon as I add config.input_processor = :sanitizer to the config block, I get this error: Dry::Container::Error: Nothing registered with the key "user"
Sorry, just to be clear: "of a certain class", meaning "is an instance of a certain class"
Piotr Solnica
@solnic
Apr 12 2016 09:20
@ngan at the moment type?: Foo requires a corresponding dry type because we use it for potential coercions. We could make it skip it gracefuly though when a type is not found
@sled could you clarify? you can set up a base schema with rules and infer Form and JSON schemas from it w/o duplication of rule definitions
Simon Schmid
@sled
Apr 12 2016 09:35
ah cool
@solnic like defining the rules once, and use a different pre-processor when needed
stigchristian
@stigchristian
Apr 12 2016 09:36
  article_schema_base = -> {
    key(:id).required(:str?)
    key(:proquint).required(:str?)
    key(:_links).schema do
      key(:self).schema do
        key(:href).required(:str?)
      end
    end
    key(:type).required(:str?)
    key(:sub_type).required(:str?)
    key(:title).required(:str?)
    key(:byline).required(:str?)
    key(:live_from).required(:date_time?)
    key(:live_to).required(:date_time?)
    key(:featured_image).required(:str?)
  }

  ArticleSchema = Dry::Validation.JSON do
    instance_exec(&article_schema_base)
    key(:text).required(:str?)
    key(:published).required(:bool?)
    key(:created_at).required(:date_time?)
    key(:updated_at).required(:date_time?)
    key(:last_saved_by).required(:hash?)
  end

  ArticleSchemaWithStack = Dry::Validation.JSON do
    instance_exec(&article_schema_base)
    key(:stack).required(:array?)
    key(:text_text).required(:str?)
    key(:text_ale).each(:hash?)
  end
Is there a better way of doing this?
Artem Pyankov
@iBublik
Apr 12 2016 09:39
@stigchristian try this one
  ArticleSchemaBase = Dry::Validation.JSON do
    key(:id).required(:str?)
    key(:proquint).required(:str?)
    key(:_links).schema do
      key(:self).schema do
        key(:href).required(:str?)
      end
    end
    key(:type).required(:str?)
    key(:sub_type).required(:str?)
    key(:title).required(:str?)
    key(:byline).required(:str?)
    key(:live_from).required(:date_time?)
    key(:live_to).required(:date_time?)
    key(:featured_image).required(:str?)
  end

  ArticleSchema = Dry::Validation.Schema(ArticleSchemaBase) do
    key(:text).required(:str?)
    key(:published).required(:bool?)
    key(:created_at).required(:date_time?)
    key(:updated_at).required(:date_time?)
    key(:last_saved_by).required(:hash?)
  end

  ArticleSchemaWithStack = Dry::Validation.Schema(ArticleSchemaBase) do
    key(:stack).required(:array?)
    key(:text_text).required(:str?)
    key(:text_ale).each(:hash?)
  end
Piotr Solnica
@solnic
Apr 12 2016 09:48
yes, what @iBublik said ^
Simon Schmid
@sled
Apr 12 2016 09:55
@solnic How can I infer a JSON schema from an existing (plain) schema? :)
like Dry::Validation.JSON(plain_schema)
ah I got it thanks :D
Artem Pyankov
@iBublik
Apr 12 2016 10:05
@sled as far as I know this won't work, cause Form ans JSON method doesn't accept constant (class) as paramater (look at https://github.com/dry-rb/dry-validation/blob/master/lib/dry/validation.rb#L45-L47). But you can use Schema method and specify config.input_processor = :json in configure block.
Piotr Solnica
@solnic
Apr 12 2016 10:08
gimme a sec
require 'dry-validation'

base = Dry::Validation.Schema do
  key(:name).required
  key(:email).required
end

json = Dry::Validation.Schema(base) do
  configure { config.input_processor = :json }
end

form = Dry::Validation.Schema(base) do
  configure { config.input_processor = :form }
end
Piotr Solnica
@solnic
Apr 12 2016 10:13
@sled ^^ this will work
but I gotta say just using Dry::Validation.Form|JSON should work too, something to improve…
Simon Schmid
@sled
Apr 12 2016 10:30
@solnic, yes I'm building a service object, and this can be fed from either form input or an API call (JSON)
so I'm basically injecting the input processor from the outside :)
stigchristian
@stigchristian
Apr 12 2016 10:37
thanks @iBublik
Simon Schmid
@sled
Apr 12 2016 11:19
I'm using dry-types + dry-validation as replacement for virtus to model JSON documents, is it overkill to both use dry-type and dry-validation?
I'm feeling like I'm writting a lot of things twice
e.g an Address type + a Schema for the address
Andy Holland
@AMHOL
Apr 12 2016 11:23
@sled personally I think there's value in keeping coercion/type-safety logic separate from validation logic, having said that, Dry::Validation::Schema::JSON landed in dry-validation master branch recently, which uses a json input processor to infer coercions in the same way Dry::Validation::Schema::Form works
Piotr Solnica
@solnic
Apr 12 2016 11:25
@sled how exactly do you use dry-types?
Simon Schmid
@sled
Apr 12 2016 11:26
mh basically what our app does is porting paper forms to "digital" forms
so I want to use dry-types to describe the structure of these forms/documents
I just got confused whether I should use Types::Form::Int, Types::Coercible::Int in my document type definition
because the validation also does some coercion right?
Piotr Solnica
@solnic
Apr 12 2016 11:29
no, you should not. your ‘models’ should not do any coercions
Simon Schmid
@sled
Apr 12 2016 11:29
okay so I keep the models "pure and strict" types
Piotr Solnica
@solnic
Apr 12 2016 11:30
yes, that’s the intention of structs in dry-types
should be as simple as possible
Simon Schmid
@sled
Apr 12 2016 11:30
got it, thanks a lot! :)
Piotr Solnica
@solnic
Apr 12 2016 11:31
JSON schemas are available in latest release btw
Simon Schmid
@sled
Apr 12 2016 11:32
another dumb question why isn't there a Types::Maybe::Int ?
I see Types::Maybe::Strict::Int and Types::Maybe::Coercible::Int in the docs
Piotr Solnica
@solnic
Apr 12 2016 11:33
because reasons :laughing:
I honestly don’t know, I probably didn’t have a use case for them yet so I didn’t add them
Simon Schmid
@sled
Apr 12 2016 11:33
ah so Types::Int.optional would be equivalent to Types::Maybe::Int ?
Piotr Solnica
@solnic
Apr 12 2016 11:33
btw Types::Int.optional would do it
yes
Simon Schmid
@sled
Apr 12 2016 11:34
cool! :)
Piotr Solnica
@solnic
Apr 12 2016 11:34
it’s basically Types::Strict::Nil | Types::Int
Simon Schmid
@sled
Apr 12 2016 11:35
I'm really enjoying the dry-rb repository :)
Piotr Solnica
@solnic
Apr 12 2016 11:35
awesome :)
Simon Schmid
@sled
Apr 12 2016 11:37
have you ever tried to mixin schemas? :)
Like class House < Dry::Types::Struct; include Addressable; .... end
Piotr Solnica
@solnic
Apr 12 2016 11:39
nope, I don’t use mixins in structs at all
Simon Schmid
@sled
Apr 12 2016 11:40
how do you handle commonly repeating subsets of fields then? :)
Piotr Solnica
@solnic
Apr 12 2016 11:41
class inheritance
Simon Schmid
@sled
Apr 12 2016 12:27
are incomplete types possible e.g if I set some attributes as optional with a default, do I have to pass the key in the initializer e.g ModelType.new({optional_field: nil}) vs ModelType.new
Piotr Solnica
@solnic
Apr 12 2016 12:34
@sled it’s being discussed how structs should work wrt optional attrs dry-rb/dry-types#72
currently you need constructor_type(:schema) to be set for optional types with default values to be set when sth is missing
Simon Schmid
@sled
Apr 12 2016 12:49
thx! now I just have to bend rails to re-load my types correctly :D
Piotr Solnica
@solnic
Apr 12 2016 12:55
@sled see dry-types-rails
Simon Schmid
@sled
Apr 12 2016 12:55
yes but this seems broken
just read the conversation here in gitter
Piotr Solnica
@solnic
Apr 12 2016 12:55
ah damn
Simon Schmid
@sled
Apr 12 2016 12:59
yep, not the first time rails breaks my balls ;)
I think the issue is the "registry" of the container is not re-loaded properly
Piotr Solnica
@solnic
Apr 12 2016 13:00
could be it
I don’t use rails at the moment so I’m not looking into it
Simon Schmid
@sled
Apr 12 2016 13:01
sure I'm trying to fix it on my own
after reloading it tells me Dry::Container::Error: There is already an item registered with the key "customer.types.address"
Andy Holland
@AMHOL
Apr 12 2016 13:18
@sled can you post your dry-types related code in a gist?
Simon Schmid
@sled
Apr 12 2016 13:20
@AMHOL uhm for the reloading?
Andy Holland
@AMHOL
Apr 12 2016 13:33
Nah just interested in how you're using it

I think calling

module Types
  include Dry::Types.module
end

in an initializer

Then defining your custom types somewhere in the app/lib directory should stop the problem from happening
Simon Schmid
@sled
Apr 12 2016 13:38
I'll try right away :)
I also noticed there are no setters, do you have any best practices on how to modify certain attributes easily?
the one I came up with is Hypo::Types::Location.new(original.to_h.merge(phone_number: '123456'))
Andy Holland
@AMHOL
Apr 12 2016 13:44
Yeah, mutable structs won't be added to dry-types core
Piotr Solnica
@solnic
Apr 12 2016 13:44
we deliberately fight with mutability
(so dramatic)
Simon Schmid
@sled
Apr 12 2016 13:51
@solnic, I totally support that - however it's still nice to have an easy way of creating a copy with the modifications
might be a cool case for keyword arguments
Simon Schmid
@sled
Apr 12 2016 14:01
@AMHOL just tried with the initializer and putting custom types into app/lib, however if I auto-load these paths it fails with the same error
Andy Holland
@AMHOL
Apr 12 2016 14:02
Ahh shit, yeah
Forgot types get registered automatically when you inherit from Struct
Simon Schmid
@sled
Apr 12 2016 14:03
yep I think I need to "reset" the container's registry somehow
Piotr Solnica
@solnic
Apr 12 2016 14:11
Screen Shot 2016-04-12 at 16.10.02.png
related ^^
that’s from Programming Clojure book but it’s a universal truth
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:31
I have Product and Category, both are Types::Struct
Product has a field with Category type. How can we make that field nullable so that I don't have to join/query categories table?
Simon Schmid
@sled
Apr 12 2016 15:31
attribute :category, Category.optional :D
just learned today
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:33
thanks but I get error 'NoMethodError: undefined method `optional' for Category:Class' :D
Simon Schmid
@sled
Apr 12 2016 15:33
is your category a type?
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:33
class Category < Dry::Types::Struct; end
class Product < Dry::Types::Struct
attribute :category, Category.optional
end
is that correct?
Simon Schmid
@sled
Apr 12 2016 15:36
mh... another guess: attribute :category, Types::Strict::Nil | Category
(I'm still learning too)
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:38
still not work, I will learn more :D
thanks @sled
Simon Schmid
@sled
Apr 12 2016 15:39
@mmeeoorroo actually the one with | works for me
ah nope
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:41
the | works with this trick: Product.new({id: 1}.merge(category: nil))
Piotr Solnica
@solnic
Apr 12 2016 15:42
@sled I use separate struct classes, one with a category and one w/o a category
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:42
magic :D
Piotr Solnica
@solnic
Apr 12 2016 15:42
a product with category would be a separate concept in my app
vs a product w/o a category
Simon Schmid
@sled
Apr 12 2016 15:42

`a_type = Hypo::Types::Strict::Nil | Hyp::Types::Address

a_type[nil] => nil

a_type[Hypo::Types::Address.new] => TypeError: #<Hypo::Types::Address address_line1=nil, ...> is not a symbol nor a string`

Piotr Solnica
@solnic
Apr 12 2016 15:42
if you want dynamic behavior just don’t use explicit classes and rely on auto-generated rom structs
this won’t work, struct classes are not types
Hyp::Types[“address”].optional should work but I wouldn’t recommend it
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:44
what's wrong with it?
Piotr Solnica
@solnic
Apr 12 2016 15:45
because nil is evil, mostly. your system will start relying on a product-with-or-without-a-category
Simon Schmid
@sled
Apr 12 2016 15:46
@solnic but how to handle these permutations? If I have a struct with 3-4 optionals, I'd have to create 4! different variations
also a common scenario is to save "incomplete" forms (e.g auto-saving)
Piotr Solnica
@solnic
Apr 12 2016 15:48
I don’t use structs along with forms
I use structs to represent specific concepts in a system, and treat them as values
Simon Schmid
@sled
Apr 12 2016 15:50
do you have an example what is meant by a "concept" ? :)
Piotr Solnica
@solnic
Apr 12 2016 15:50
a product, a user, a product with a category, a list of products etc
Dung Nguyen
@mmeeoorroo
Apr 12 2016 15:52
I have a scenario where I need optional types. When a user delete a product, the app just marks the product as deleted, and tracks that user with attribute :deleted_by, User. That field is nil until the product is deleted
could you give a suggestion on that case?
Simon Schmid
@sled
Apr 12 2016 15:54
this is where the permutation starts, i.e Product, ProductWithCategory, DeletedProduct, DeletedProductWithCategory
Piotr Solnica
@solnic
Apr 12 2016 15:56
I don’t have a generic answer or suggestion, because it depends on the application domain. I would definitely not used names like FooWithoutBar though.
you need to look at what your application is doing and in which contexts things are needed, these should give you good hints how to name things
if you have contexts where you have all products, including deleted ones, then you can have optional deleted_by I suppose
Simon Schmid
@sled
Apr 12 2016 15:58
mh so this gets me thinking, we have a document which can be in a "draft" mode, i.e a lot of optionals, no requirements - just type checking
and then the document is validated and put in a "validated" mode, same fields but with a lot of required attributes
Piotr Solnica
@solnic
Apr 12 2016 16:31
sounds like a good use case for sub-types then
John Backus
@backus
Apr 12 2016 19:27
So is this Kleisli gem dead? Doesn't seem like the maintainer is interested in it anymore
Piotr Solnica
@solnic
Apr 12 2016 19:28
Probably. I dunno
Nikita Shilnikov
@flash-gordon
Apr 12 2016 19:42
@backus I think you can ping author on Twitter or via email
Mb someone should fork the repo and republish it as a new gem
Ngan Pham
@ngan
Apr 12 2016 19:44
@solnic I'm trying to create a service objects with good validation for input. And I think being able to check the type of a variable (beyond primitive types) would be nice
John Backus
@backus
Apr 12 2016 19:53
Eh I'm not that interested in it. I just want to get it updated so that it doesn't monkey patch my ruby environment when I require dry-types :P
I do think dry-rb should fork it though
and reduce it down to the useful functionality without all of the haskell-wannabe syntax
Piotr Solnica
@solnic
Apr 12 2016 19:54
We thought about it already
Piotr Solnica
@solnic
Apr 12 2016 19:59
Either is fantastic but the rest is meh
dry-monads? :P
I actually thought about dry-fp project with some common abstractions that we use in many places
John Backus
@backus
Apr 12 2016 20:01
Nice
dry-monad seems pretty good to me
I really think they will be more useful if the syntactic sugar is ditched
Piotr Solnica
@solnic
Apr 12 2016 20:04
Me too
Even Either could be a bit simpler to use. >-> and fmap confused me more then once
John Backus
@backus
Apr 12 2016 20:06
mhm

Could their >-> example

result = Right(3) >-> value {
  if value > 1
    Right(value + 3)
  else
    Left("value was less or equal than 1")
  end
} >-> value {
  if value % 2 == 0
    Right(value * 2)
  else
    Left("value was not even")
  end
}

just be re-written such that Right and Left provided the method #bind like so?

Right(3).bind do |value|
  if value > 1
    Right(value + 3)
  else
    Left("value was less or equal than 1")
  end
end.bind do |value|
  if value % 2 == 0
    Right(value * 2)
  else
    Left("value was not even")
  end
end
Tim Riley
@timriley
Apr 12 2016 22:42
I’d be up for us having a small set of useful things in either dry-fp or dry-monads
I’m really not the biggest fan of kleisli’s >-> trickery. It makes chaining hard in a lot of cases, I’ve found.
John Backus
@backus
Apr 12 2016 23:28
Alright so I can define a dry-validation rule that depends on other values
I can also define a schema that works with arrays as input
But can I define a rule for a value in an array which is dependent on the entire array
For example, can I write a validation that says that a value is not repeated in an array