These are chat archives for dry-rb/chat

9th
May 2016
Jeff Dickey
@jdickey
May 09 2016 08:17 UTC
In dry-types, is there an analogue to the Virtus "private setter" idiom, so that one can define an "attribute" with a default (fixed) value?
Tim Riley
@timriley
May 09 2016 09:22 UTC
@jdickey I guess one question I'd ask first is what you want to do with that attribute once it's there? How is this not, for example, solved by def my_attr; "static value"; end?
Jeff Dickey
@jdickey
May 09 2016 09:25 UTC
@timriley I'd like to be able to hand the value object that I'm defining to a repository instance that treats it as a Hash. We're developing code that, for now, will always have that fixed value for that attribute. That's going to change in reasonably short order, and we'd rather not have to update the repo class (or other classes that don't need to care) when it does.
Tim Riley
@timriley
May 09 2016 09:26 UTC
@jdickey right, that makes sense. Could you get away with def to_h; super.merge(my_attr: “hi”); end for now?
I don’t think there’s a “feature” for what you describe, but there are certainly lots of ways to handle it.
Jeff Dickey
@jdickey
May 09 2016 10:06 UTC
@timriley Yeah, that's the approach I'm taking. I just remember thinking that was Useful in Virtus, and missed it after making the switch. Thanks again
Jeff Dickey
@jdickey
May 09 2016 11:00 UTC
one more shout into the aether: has anyone spun up a Dry::Types definition for a UUID, which would let me write clearer code than
        attribute :identifier, Types::Strict::String.default { UUID.generate }.
                  constrained(format: /\A\h{8}(-\h{4}){3}\-\h{12}\z/ )
Tim Riley
@timriley
May 09 2016 11:01 UTC
If I were doing this, I’d save that type in my Types module
module Types
  UUID = Types::Strict::String.defaults { UUID.generate }.constrained(…)
end
Then you can just reuse it by name :)
Jeff Dickey
@jdickey
May 09 2016 11:02 UTC
d'oh; no idea why that didn't spring to mind with the correct syntax_ the first _n times. Thanks again
Luca Guidi
@jodosha
May 09 2016 12:40 UTC
There we go: dry-rb/dry-validation#147
Tim Riley
@timriley
May 09 2016 12:40 UTC
Awesome, @jodosha, I’ll take a look in my morning (just finishing up a blog draft and going to bed soon).
Luca Guidi
@jodosha
May 09 2016 12:41 UTC
@timriley great! thanks!
Andy Holland
@AMHOL
May 09 2016 12:48 UTC
Thanks @jodosha, LGTM :+1:
@timriley is it the next in series for the Icelab articles?
Tim Riley
@timriley
May 09 2016 12:55 UTC
@AMHOL yep - will link you a draft shortly!
Andy Holland
@AMHOL
May 09 2016 12:55 UTC
Cool, thanks :heart:
“Better code with an inversion of control container”
@AMHOL more on the container, so I’d love your feedback :)
Andy Holland
@AMHOL
May 09 2016 13:51 UTC
:+1: I'll have a read
Andy Holland
@AMHOL
May 09 2016 14:00 UTC
@timriley nice, all seems good, the only thing that could be done is to make it more obvious about the #call interface, perhaps an example of actually switching out a dependency to show that as long as we adhere to the same interface the only code we need to change is registering the object?
Tim Riley
@timriley
May 09 2016 14:00 UTC
like CreateArticle.new(something_else_entirely, nil)?
Andy Holland
@AMHOL
May 09 2016 14:01 UTC
Nah, I mean actually showing the whole cycle of registering with the container, importing with auto-inject, then switching out with a new dependency
Might be a bit OTT for code examples tho
Tim Riley
@timriley
May 09 2016 14:02 UTC
Yeah, I did a lot of the step-by-step setup last week
what would “switching” look like to you?
Andy Holland
@AMHOL
May 09 2016 14:04 UTC
Just changing the call to register, i.e.
register(:user_validator) { Users::Validator.new }
register(:user_validator) { Some::Other::Validator.new }
Tim Riley
@timriley
May 09 2016 14:04 UTC
right, I get you
Andy Holland
@AMHOL
May 09 2016 14:05 UTC
And mentioning that as long as both respond to #call(hash) we're golden
Or that the implied interface is like ResultObject #call(hash)
Hard to express in Ruby I guess
Tim Riley
@timriley
May 09 2016 14:07 UTC
yeah
Andy Holland
@AMHOL
May 09 2016 14:10 UTC
My main concern is that Any implementation that wants to behave as low-level “article validator” or “article persister” module must now adhere to the interface expectations set here in this high-level module. explains the problem away, but might not be immediately obvious to less experienced programmers
Tim Riley
@timriley
May 09 2016 14:10 UTC
Yeah. I hear you.
Trying a paragraph of words first...
Andy Holland
@AMHOL
May 09 2016 14:11 UTC
Cool, also the use of the word module could confuse people there
Tim Riley
@timriley
May 09 2016 14:11 UTC
yeah. What else though? “component?” “object?"
I just use it because it’s stated in the principle’s text
Andy Holland
@AMHOL
May 09 2016 14:12 UTC
Object works, but not as well as module :p
Probably better to just leave it as is
Tim Riley
@timriley
May 09 2016 14:14 UTC
For example, we might decide that our original validator implementation is no longer what we need, and we now want to validate each article by submitting it to a web service for bad pun detection. We can create a BadPunValidator that responds to #call, register it with the container as validate_article, and now we have a completely different validation approach that continues to work with the high-level code.
Andy Holland
@AMHOL
May 09 2016 14:14 UTC
:+1:
Tim Riley
@timriley
May 09 2016 14:14 UTC
Does that explain the “switching” bit a little better, without going so far as to demonstrate in code?
Updated the draft
Andy Holland
@AMHOL
May 09 2016 14:17 UTC
Cool
Also, I don't know how draftin works, but I submitted a typo edit for Our higher-level modules are now more reusable because they’re no longer couple => Our higher-level modules are now more reusable because they’re no longer coupled
Tim Riley
@timriley
May 09 2016 14:17 UTC
Hmm, I haven’t received that edit yet.
fixed it :)
Thanks! That was really helpful feedback. If you think of anything else, let me know. I’m gonna sleep now.
Andy Holland
@AMHOL
May 09 2016 14:18 UTC
:+1:
Only other thing is I'd link dependency inversion principle to http://martinfowler.com/articles/dipInTheWild.html
And night :moon:
Tim Riley
@timriley
May 09 2016 14:19 UTC
ah yes!
Got your edit now, haha
Andy Holland
@AMHOL
May 09 2016 14:22 UTC
:P
Tim Riley
@timriley
May 09 2016 14:28 UTC
Ok. Put the computer away and now I think that article needs a few more hundred words: a section on how SRP becomes easier, and then how working with functional objects makes the injection like a simple function import.
Otherwise it's not really a full picture of how the container helps.
Andy Holland
@AMHOL
May 09 2016 14:31 UTC
Yeah, that sounds good, also maybe the implications of SRP and functional objects on ease of testing
Tim Riley
@timriley
May 09 2016 14:32 UTC
Yeah. I'll add them in 6 hours :p
Andy Holland
@AMHOL
May 09 2016 14:32 UTC
Damn, you don't sleep much eh
Tim Riley
@timriley
May 09 2016 14:33 UTC
Well not when I've stayed up too late.
Aditya Tiwari
@aditya01933
May 09 2016 18:22 UTC
This message was deleted
This message was deleted

I have this module

module UniquePredicate
include Dry::Logic::Predicates
predicate(:unique?) do |value,input|
find_by(input => value)
end
end

and this validation

require 'json'
require 'dry-validation'
include UniquePredicate
UserSchema = Dry::Validation.JSON do
configure { config.messages_file = 'config/validations/errors.yml' }
key(:username).required(:unique?)
key(:name).required
configure do
config.predicates = UniquePredicate
end
end

but config.predicates = UniquePredicate not working ...
Andy Holland
@AMHOL
May 09 2016 18:45 UTC
@aditya01933 How come you include UniquePredicate?
Also, you should only use one configure block
Aditya Tiwari
@aditya01933
May 09 2016 18:45 UTC
ohh sorry .. that was trial and run
that should not be here
Andy Holland
@AMHOL
May 09 2016 18:46 UTC
And it doesn't iook like find_by is implemented by anything
Also you can use markdown for code blocks here
Aditya Tiwari
@aditya01933
May 09 2016 18:46 UTC
UniquePredicate module is in separate file
and that is not accessible in user_schema.rb i/e config block
Andy Holland
@AMHOL
May 09 2016 18:48 UTC
You need to load the file then
Aditya Tiwari
@aditya01933
May 09 2016 18:48 UTC
yeah trying that only
Andy Holland
@AMHOL
May 09 2016 19:08 UTC
@aditya01933 you can do something like:
require 'dry-validation'

User = Struct.new(:username, :name)

class UserRepository
  USERS = []

  def create(attributes)
    USERS << User.new(*attributes.values_at(:username, :name))
  end

  def find_by_username(username)
    USERS.find { |user| user.username == username }
  end
end

UserSchema = Dry::Validation.JSON do
  configure do
    option :finder

    config.messages_file = 'config/validations/errors.yml'

    def unique?(username)
      finder.call(username).nil?
    end
  end

  required(:username).required(:unique?)
  required(:name).required
end

user_repo = UserRepository.new
user_repo.create(username: 'john', name: 'John')

UserSchema.with(finder: user_repo.method(:find_by_username)).call(
  username: 'john',
  name: 'John'
)
UserSchema.with(finder: user_repo.method(:find_by_username)).call(
  username: 'jill',
  name: 'Jill'
)
=> #<Dry::Validation::Result output={:username=>"john", :name=>"John"} messages={:username=>["must be unique"]}>
=> #<Dry::Validation::Result output={:username=>"jill", :name=>"Jill"} messages={}>
Thinking that custom predicates should be evaluated in the context of the validator
That way your custom predicates method would work
Phil Schalm
@pnomolos
May 09 2016 23:30 UTC
@timriley The docs on http://dry-rb.org/gems/dry-types/default-values/ mention Types::Form::String but that doesn’t appear to exist anymore
Tim Riley
@timriley
May 09 2016 23:31 UTC
@pnomolos thanks, I think that’s actually a bug. AFAIK there’s no Form::String type because forms are already posting everything as strings in the first place, so no special coercion is needed.
I think that should probably just be Strict::String
Would you mind making the change in a PR?
Phil Schalm
@pnomolos
May 09 2016 23:31 UTC
@timriley The coercion (according to that page) is that “” becomes nil
Tim Riley
@timriley
May 09 2016 23:32 UTC
ah, hmm
I’m not sure off the top of my head what the situation is here. Perhaps you could file a bug with a question?
Phil Schalm
@pnomolos
May 09 2016 23:36 UTC
Will do :)
Tim Riley
@timriley
May 09 2016 23:36 UTC
Thanks!
Phil Schalm
@pnomolos
May 09 2016 23:40 UTC
Created! :)