Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
Oskar Szrajer
@gotar
sound good
Jonah
@jonahx
best practice question, not specifically related to the dry gems but input from regulars here would be appreciated. say you have a class that raises specific domain errors, related to that class. Do you:
  1. Define the custom error classes inside the domain class and access them like MyClass::MyError?
  2. Define the custome error classes in the same file as the domain class but outside of it, so client code can directly access MyError?
  3. Something else?
Andy Holland
@AMHOL
I'd namespace it, MyClass::MyError
Jonah
@jonahx

I want a type to represent a non empty string, is there a builtin for this or should I just do:

NonEmptyString = Types::Strict::String.constrained(
  format: /\S+/
)

?

Nikita Shilnikov
@flash-gordon
there's no predefined type for this
Daniel Sandbecker
@daniels

In Dry::Validation, is there a way to define a custom error message for a rule block, that isn't composed of messages from the individual predicates used in the block? I have a form where I want to enforce a checkbox only if the birthdate given in another field is for a person under 18:

rule(acknowledge_age_if_young: [:acknowledge_age, :birth_date]) do |acknowledge_age, birth_date|
  birth_date.older?(18) | acknowledge_age.true?
end

But the automatic error message is a join of the older?-message and the true?-message, with " or " as the delimiter: "must be older than 18 or must be true". I can customize each of these messages, but I don't see how/if I can use a message without an " or ". Basically I just wan't to say "You need to check this box if you're not 18".

Daniel Sandbecker
@daniels
Ok, after searching and testing for hours I found an answer in the forum right after I posted here: https://discourse.dry-rb.org/t/difficulty-creating-error-messages-for-high-level-rules/238/2
Jonah
@jonahx

Could someone clarify for me the purpose of Types.Constructor:

user_type = Types.Constructor(User)

# It is equivalent to User.new(name: 'John')
user_type[name: 'John’]

What is the differentce between User and user_type — other than that you can construct with []rather than new? Types.Instance makes sense to me, since we’re checking that the value passed is an instance of a certain class. But what are we checking with a constructor type?

Piotr Solnica
@solnic
@jonahx just a shortcut for Types::Definition.new(User).constructor(&User.method(:new))
Jonah
@jonahx
@solnic what is the typical use case for this kind of type?
Piotr Solnica
@solnic
@jonahx ie type annotation in dry/rom structs
in general, dry-types provide type definitions (as in, they define the primitive class), with optional constructors, constraints and arbitrary meta-information, there are tons of use cases for them
Jonah
@jonahx
@solnic thanks, yeah, i knew that part. i use and love Dry::Struct. By use case I meant, an example of a dry struct that would need an attribute with a contructor type. I’m having trouble connecting the idea to something that would come up in my work.
Jonah
@jonahx

separate question: Is there a better (more concise) way to achieve the equivalent of the following using dry::struct or dry::types:

class Webservices
  include Enumerable
  extend Forwardable

  TYPE = Types.Array(Types.Instance(Webservice))

  def initialize(arr)
    @arr = TYPE[arr]
  end
  def_delegators :@arr, :each
end

Note: I want to be able to construct using a single, unnamed parameter as in Webservices.new([service1, service2]).
Essentially, I want a typed array constructible using Webservices.new.

Pavel Argentov
@argent-smith
Hi ppl. How to package a Klass::ActiveRecord_Associations_CollectionProxy into a dry-struct (via dry-types)?
Specifically, I want to declare a certain model's scope as a struct member
Nikita Shilnikov
@flash-gordon
@argent-smith you can use Types::Any in comlex cases
Pavel Argentov
@argent-smith
thnx
I've tried Types.Definition() as well: it works
Nikita Shilnikov
@flash-gordon
hm, yeah, though Definition doesn't do a type check actually, .Instance() does, or its alias, .Strict()
Jonah
@jonahx
@solnic @timriley friendly poke re: question above ^^
Also separate question for today: I have an Dry::Struct with an attribute with a Class type constraint. When using rspec, I want to pass in a double for the object. But an rspec double does not have type class. Have you ever run into this? What was your workaround?
Tim Riley
@timriley
@jonahx What you have in that code example above seems fine. There’s not any kind of first-class support for something like that.
Jonah
@jonahx
@timriley thanks
Tim Riley
@timriley
@jonahx Alternatively, you could just use the type definition directly whenever you need it?
Webservices = Types::Strict::Array(Types::Instance(Webservice))
services = Types::Webservices[some_array]
Jonah
@jonahx
@timriley yeah, in this case i felt there was benefit in explictily naming the concept. Also, the real object has a from_string ctor so there’s a bit more reason to have it
Tim Riley
@timriley
Right, that makes sense then.
Jonah
@jonahx
any advice on the rspec question?
Tim Riley
@timriley
Mind repeating it?
Jonah
@jonahx
Also separate question for today: I have an Dry::Struct with an attribute with a Class type constraint. When using rspec, I want to pass in a double for the object. But an rspec double does not have type class. Have you ever run into this? What was your workaround?
Tim Riley
@timriley
I’d just construct an object of the actual class :)
Jonah
@jonahx
ha, you’re not as lazy as me. thanks :)
Tim Riley
@timriley
Code should inform tests :)
(and if it makes testing too hard, well, that’s a code problem)
Jonah
@jonahx
@timriley, well, the test is perfectly easy. it’s just that rspec double’s aren’t designed with type checking in mind, which is fair enough given how atypcal it is in ruby. imo dry::struct types bring a certain sanity to ruby that should be there, but the fact remains it’s still an addon to the language, so to speak.
Tim Riley
@timriley
Yeah. I’d only use doubles where duck-typing matters more than the actual strict class check
Jonah
@jonahx
@timriley which is indeed the case here. i sort of added the class constraint just as a way of enforcing the interface, but now that you mention it i think that’s where my mistake was — the contract really is just an interface and not a particular class. and removing the type constraint which i’ve what i did to fix the issue was probably the correct move anyway and not just a hack as i’ve been viewing it
Tim Riley
@timriley
Cool :)
Alexander Chernik
@achernik
Hello!
I have a question regarding dry-validation usage. Is it possible to "filter out" invalid parts instead of flat out rejecting entire hash?
I could use result.errors to filter result.output manually, but maybe there is another way?
Jonah
@jonahx
How can I get an attribute that is both optional and default? I want to be able to leave it out, and when I do, it should have a default value.
Nikita Shilnikov
@flash-gordon
@jonahx I think it's what dry-types/dry-struct does in master, check out the changelogs
Tiago Moraes
@tiagoefmoraes

Hello,
when defining an enum without 0 as a valid value:

subject(:enum) { Dry::Types['integer'].enum(4, 5, 6) }

I expected that it would be invalid

expect(enum.try(0)).to be_failure

but it is actually valid because of inverted_mapping. I found this to be really confusing.
Should't this inverted behavior only happen when the mapping is defined explicitly?

subject(:enum) { Dry::Types['integer'].enum(4 => 0) }

At least when the values are all integers?

Nikita Shilnikov
@flash-gordon
it always worked like that for integers but I think this behavior can be made configurable
well, try didn't work in prev version actually but fixed this :)
[] worked
I would say it's better not to have mapping by default