These are chat archives for dry-rb/chat

21st
Jun 2016
Nick Sutterer
@apotonick
Jun 21 2016 01:01
hey guys, does dry-v come with EMAIL_REGEX predefined somewhere?
BTW i am LOVING dry-v
with reform, it's fantastic
Tim Riley
@timriley
Jun 21 2016 01:01
@apotonick Hi :) It doesn’t have anything like that, no.
Nick Sutterer
@apotonick
Jun 21 2016 01:03
and not planned?
thanks @timriley
Tim Riley
@timriley
Jun 21 2016 01:04
It’s never been talked about, so yeah, I would say there’s nothing planned for it.
It feels like the kind of thing that’s more specific to whatever domain you might choose to use dry-v inside.
Nick Sutterer
@apotonick
Jun 21 2016 01:09
because email's always change? haha
:P
Tim Riley
@timriley
Jun 21 2016 01:10
Heh.
If someone wanted to publish an email-regex ruby gem, I’d totally use it.
Nick Sutterer
@apotonick
Jun 21 2016 01:12
love it already!
Tim Riley
@timriley
Jun 21 2016 01:15
Related, and actually part of the stdlib: http://til.icelab.com.au/uri-regex-ruby/
Andy Nicholson
@anicholson
Jun 21 2016 06:11
hi!
I'm using dry-validations and I want to create a custom predicate that takes a parameter (a la gt?:. What signature should my method have? I'm using the configure do..end style
Tim Riley
@timriley
Jun 21 2016 06:30
@anicholson something like this inside your configure:
          def not_eql?(input, value)
            !input.eql?(value)
          end
i.e. the input data is the first arg, the args that are supplied to the predicate in the schema go after
Andy Nicholson
@anicholson
Jun 21 2016 06:46

@timriley replaying back, just to make sure I understand correctly:

if I used your example:

key(:some_key) { :not_eql?(5) }

the 5 would be mapped to input?

Tim Riley
@timriley
Jun 21 2016 06:47
no, the input data would be:
my_schema.(some_key: 123)
^ 123 would be input. 5 would be value
you could also confirm this just by playing around :)
Andy Nicholson
@anicholson
Jun 21 2016 06:48
well I thought I had it right before asking, @timriley, but you've just told me they were around the wrong way (and so my comparison operators were too :P )
Piotr Solnica
@solnic
Jun 21 2016 09:24
@anicholson the sig should be not_eql?(value, input) actually, the input is always the last argument, as predicates are being curried with their args which you pass in the DSL, then fully applied with the input
Piotr Solnica
@solnic
Jun 21 2016 09:31
@backus proposal looks good except :permissive which shouldn’t use defaults, so I just want it to work exactly the same as current :strict - this is really important for the common case of building structs from db data that you expect to be valid
@backus if you could introduce these new constructors and update Struct to use them we’d have a release ready :)
Andy Nicholson
@anicholson
Jun 21 2016 09:41

the sig should be (value, input)

@timriley this is why I ask clarifying questions ;)

Piotr Solnica
@solnic
Jun 21 2016 09:41
another case where our dry stuff is very similar to a clojure lib: https://github.com/plumatic/schema

Schema also supports schema-driven data transformations, with coercion being the main application fleshed out thus far. Coercion is like validation, except a schema-dependent transformation can be applied to the input data before validation.

An example application of coercion is converting parsed JSON (e.g., from an HTTP post request) to a domain object with a richer set of types (e.g., Keywords).

^^ yeah this is the next step for me :) type-safe data coercion/transformation

we have building blocks in place so I “just” need to figure out how to approach this
Tim Riley
@timriley
Jun 21 2016 10:06
@anicholson sorry for the bum steer earlier. @solnic did the ordering of these params change at some point?
Piotr Solnica
@solnic
Jun 21 2016 10:06
no it was always like that :)
maybe you confused this with transproc, where ordering is different :)
timriley @timriley hangs head in shame
Andy Nicholson
@anicholson
Jun 21 2016 10:09
all good!
we've all done it :)
Maciej Mensfeld
@mensfeld
Jun 21 2016 11:02
Hello @solnic , how can I stub a schema? :D
        expect(Enjin::Schemas::Result)
          .to receive(:call)
          .with(results)
won't work since schema is frozen
or how can I stub that
Piotr Solnica
@solnic
Jun 21 2016 11:51
use a mock, don’t stub anything like that
Maciej Mensfeld
@mensfeld
Jun 21 2016 11:52
Yeah this is what I did in the end
thx
Piotr Solnica
@solnic
Jun 21 2016 12:09
ok folks hints will be much better in 0.8.0 dry-rb/dry-validation#195 :tada: :tada: :tada: /cc @fran-worley
also dis:
dry-rb/dry-validation (master«) % be ruby tmp/benchmark_form.rb
Warming up --------------------------------------
ActiveModel::Validations
                       178.000  i/100ms
dry-validation / schema
                       617.000  i/100ms
dry-validation / form
                       417.000  i/100ms
Calculating -------------------------------------
ActiveModel::Validations
                          1.816k (± 2.9%) i/s -      9.078k in   5.003400s
dry-validation / schema
                          6.252k (± 3.6%) i/s -     31.467k in   5.040177s
dry-validation / form
                          4.122k (± 6.6%) i/s -     20.850k in   5.089475s

Comparison:
dry-validation / schema:     6251.5 i/s
dry-validation / form:     4121.6 i/s - 1.52x slower
ActiveModel::Validations:     1816.0 i/s - 3.44x slower
meaning, plain schema with no coercions is ~3.5x faster than AM::V with no coercions, and form with coercions is ~2.2x faster than AM::V with no coercions #winning
this also adds a Message concept but for now it’s only an IM representation used to figure out failure msg vs hint dillema, then it’s dumped into string but we may consider returning message objects instead of strings in 0.9.0
Piotr Solnica
@solnic
Jun 21 2016 12:16
oh and once I finalize this PR we should be ready to go with 0.8.0 release
Hannes Nevalainen
@kwando
Jun 21 2016 12:17
There is so much <3 in master, can't wait for it =)
Piotr Solnica
@solnic
Jun 21 2016 12:22
and sweat, and tears ;)
Hannes Nevalainen
@kwando
Jun 21 2016 12:22
ofc >.<
Piotr Solnica
@solnic
Jun 21 2016 12:23
@flash-gordon looks like jruby is giving us issues again :(
Peter Leitzen
@splattael
Jun 21 2016 12:32
@solnic can I see your tmp/benchmark_form.rb from above? :D
Piotr Solnica
@solnic
Jun 21 2016 12:32
I’ll push benchmarks to master tomorrow, it’s nothing fancy
just a schema with a couple of fields
and an AM::V model with custom initialize which just sets attributes
Peter Leitzen
@splattael
Jun 21 2016 12:34
@solnic ok, thank you :-)
Nikita Shilnikov
@flash-gordon
Jun 21 2016 12:40
@solnic OK, I'll have a look later today
Piotr Solnica
@solnic
Jun 21 2016 12:41
@flash-gordon I’m taking a look already
it’s intriguing, as always
Nikita Shilnikov
@flash-gordon
Jun 21 2016 12:41
no doubt
Peter Leitzen
@splattael
Jun 21 2016 12:42
@solnic FYI, I'd like to boost dry-v's perf even more so more realistic benchmarks would be great :)
Piotr Solnica
@solnic
Jun 21 2016 12:42
haha…it was a bug IN MRI that made my specs pass…lol
FYI: arr.uniq!(&:some_invalid_method) works in MRI
and properly crashes under jruby
check dis out:
(byebug) all_msgs
["is missing"]
(byebug) all_msgs
["is missing"]
(byebug) all_msgs.uniq!(&:signature)
nil
(byebug) all_msgs
[“is missing"]
basically a string doesn’t implement :signature yet MRI doesn’t crash
Piotr Solnica
@solnic
Jun 21 2016 12:48
@flash-gordon ^^ FYI :)
@splattael oh that motivates me more to push these benchmarks NAU
Peter Leitzen
@splattael
Jun 21 2016 12:48
:green_heart: YES!!
Nikita Shilnikov
@flash-gordon
Jun 21 2016 12:50
@solnic that's why running specs with several interpreters is a good thing ;)
Piotr Solnica
@solnic
Jun 21 2016 12:50
yep
good that it happened, as I moved dumping messages to result object (which fixed the issue at the same time) and we have the doors open to adding an option to schema to return either strings or messages objects in error hash
so ie schema.(input).messages(as_strings: true) or sutin
Nikita Shilnikov
@flash-gordon
Jun 21 2016 12:53
sweet
Piotr Solnica
@solnic
Jun 21 2016 13:02
there are lots of perf improvements that can be done on dry-logic side, but it requires some bigger internal changes, so I postponed it for now
ie we evaluate input twice, first time to apply a predicate and then the second time when we provide the input to a result object
we could also do a better job in dry-v when defining rules, ie rather than having multiple :key rules, we could have a single :key rule with its predicate set as a conjunction of multiple :val rules, this way we’d extract value only once when applying rules for a given key
Peter Leitzen
@splattael
Jun 21 2016 13:12
@solnic nod
Piotr Solnica
@solnic
Jun 21 2016 13:12
so ie
# instead of dis:
[:and, [[:key, [:age, [:predicate, [:filled?, [[:input, undefined]]]]]], [:key, [:age, [:predicate, [:int?, [[:input, undefined]]]]]]]]

# we could have dis:
[:key, [:age, [:and, [[:val, [:predicate, [:filled?, [[:input, undefined]]]]], [:val, [:predicate, [:int?, [[:input, undefined]]]]]]]]]
this way the rule would only access :age key once
Peter Leitzen
@splattael
Jun 21 2016 13:16
gotcha, I have to dig deeper into dry-v before tweaking this I guess :-)
low-hanging fruits first I hope :D
Piotr Solnica
@solnic
Jun 21 2016 13:19
lol forget what I just said, I just measured the difference, the way it is now is faster due to result processing :laughing:
Warming up --------------------------------------
      1 x key access     4.36k i/00ms
      4 x key access     6.32k i/00ms
Calculating -------------------------------------
      1 x key access     39.98k (± 9.2%) i/s -    198.28k in   5.26771s
      4 x key access     60.66k (± 3.1%) i/s -    307.32k in   5.67581s

Comparison:
      4 x key access:    60766.3 i/s
      1 x key access:    39897.9 i/s - 1.2x slower
ok moving on ;)
I was hoping to simplify error compiler a lot now that we have access to all arguments from predicates (thanks @fran-worley !) but it’d be a bigger refactor so I’ll do it for 0.8.1
this should make dry-v as fast as it was around 0.4 version (~5-6x faster than AM::V)
not to mention the code will be much simpler in error-compiler
I wouldn’t call it a low hanging fruit but it’s not a huge deal either :)
Peter Leitzen
@splattael
Jun 21 2016 13:34
@solnic Even after dry-rb/dry-validation@391a99a I see huge amount of calls to uncached HintCompiler#hash
Piotr Solnica
@solnic
Jun 21 2016 13:35
yeah, no way around that
Peter Leitzen
@splattael
Jun 21 2016 13:35
so caching the hash in @hash kind of useless :-(
I'm referring to this BTW:
require 'benchmark/ips'
require 'dry-validation'

schema = Dry::Validation.Schema do
  required(:address).schema do
    required(:city).filled(min_size?: 3)

    required(:street).filled

    required(:country).schema do
      required(:name).filled
      required(:code).filled
    end
  end
end

INPUT = { address: { city: 'NYC' } }.freeze

errors = schema.call({}).messages

puts errors.inspect

Benchmark.ips do |x|
  x.report do
    schema.call(INPUT).messages
  end
end
Peter Leitzen
@splattael
Jun 21 2016 13:43
Mhh, can we just return self when new_options is empty for HintCompiler#with? :D
diff --git a/lib/dry/validation/hint_compiler.rb b/lib/dry/validation/hint_compiler.rb
index b6a2f66..28a8f60 100644
--- a/lib/dry/validation/hint_compiler.rb
+++ b/lib/dry/validation/hint_compiler.rb
@@ -40,6 +40,7 @@ module Dry
       end

       def with(new_options)
+        return self if new_options.empty?
         super(new_options.merge(rules: rules))
       end
Piotr Solnica
@solnic
Jun 21 2016 13:57
@splattael yeah we should do that
nice catch Peter <3
Piotr Solnica
@solnic
Jun 21 2016 14:21
@splattael just push it to master
Peter Leitzen
@splattael
Jun 21 2016 14:29
I do have +x for dry-v?
(TBH, I tried and I failed ;)) -> dry-rb/dry-validation#196
Piotr Solnica
@solnic
Jun 21 2016 14:44
dry-rb/dry-validation@714979e <= @splattael
@splattael you made it ~4.85x faster btw
I love you man :laughing:
Peter Leitzen
@splattael
Jun 21 2016 14:45
WTF! Really?
Piotr Solnica
@solnic
Jun 21 2016 14:45
we went from ~3.5x to ~4.85
Peter Leitzen
@splattael
Jun 21 2016 14:45
Nice :D
Piotr Solnica
@solnic
Jun 21 2016 14:45
yeah, this part is an extreme bottleneck
so reducing object allocation there makes big difference
Peter Leitzen
@splattael
Jun 21 2016 14:46
dry-v.png
my current status :D
Piotr Solnica
@solnic
Jun 21 2016 14:46
if we could somehow come up with a faster algo for generating unique object identifiers…;)
Peter Leitzen
@splattael
Jun 21 2016 14:46
:D
Piotr Solnica
@solnic
Jun 21 2016 14:47
yeah so define_hash_method is actually defining a method inside of it so this really means it’s the hash method being so slow
it’s from dry-equalizer
Peter Leitzen
@splattael
Jun 21 2016 14:48
yes, I hoped to speed it up there but I failed. It's fast enough I fear
(even class_eval magic did not work there) ;)
Piotr Solnica
@solnic
Jun 21 2016 14:48
we should have an interface in equalizer that would allow us to say “this stuff does not change, memoize #hash, kthxbye”
Peter Leitzen
@splattael
Jun 21 2016 14:48
yes! this helped but I broke tests :D
Piotr Solnica
@solnic
Jun 21 2016 14:49
oh damn, that’s bad
I would expect it to work, we don’t mutate anything…:/
btw you could experiment with caching Message objects
Peter Leitzen
@splattael
Jun 21 2016 14:49
yeah, but it would break things for all users of dry-e too :/
Piotr Solnica
@solnic
Jun 21 2016 14:49
these are immutable structs, their state is basically a couple of arrays, constants and a message string
so it is safe to cache them
errr, I should say “Message objects for hint compiler”
Peter Leitzen
@splattael
Jun 21 2016 14:51
yeah
Piotr Solnica
@solnic
Jun 21 2016 14:51
error compiler produces messages which are variables, so it can’t be cached there
otoh we cache ALL HINTS already so that might not make a difference
Peter Leitzen
@splattael
Jun 21 2016 14:52
btw, caching hash in dry-e: 2268 examples, 2 failures, 33 pending in dry-v
BUT:
Warming up --------------------------------------
                       392.000  i/100ms
Calculating -------------------------------------
                          3.974k (± 1.3%) i/s -     19.992k in   5.031927s
remember before:
Warming up --------------------------------------
                       257.000  i/100ms
Calculating -------------------------------------
                          2.573k (± 2.8%) i/s -     13.107k in   5.098857s
HUUUUGE win :D
diff in dry-e:
diff --git a/lib/dry/equalizer.rb b/lib/dry/equalizer.rb
index 099900f..c46966d 100644
--- a/lib/dry/equalizer.rb
+++ b/lib/dry/equalizer.rb
@@ -75,7 +75,7 @@ module Dry
     def define_hash_method
       keys = @keys
       define_method(:hash) do | |
-        keys.map(&method(:send)).push(self.class).hash
+        @__hash__ ||= keys.map(&method(:send)).push(self.class).hash
       end
     end
dropsmic :microphone:
so, yes. We need “this stuff does not change, memoize #hash, kthxbye”
gotta run :runner:
will try your benchmarks later during the hopefully boring football matches ;)
cheść
Piotr Solnica
@solnic
Jun 21 2016 14:58
ZOMG we gotta make this work!!!111111111111oneoneone
cheers Peter :wave:
Nikita Shilnikov
@flash-gordon
Jun 21 2016 15:04
interesting, this is a special kind of equalizer for objects that don't have mutable variables
Piotr Solnica
@solnic
Jun 21 2016 15:12
I would expect all specs to pass with memoization, so it’s either a bug in dry-v or we do sth funky in these 3 failing specs
John Backus
@backus
Jun 21 2016 17:46
Are dry-equalizer objects guaranteed to be immutable though?
Seems precarious to cache their object identity if they aren't
Piotr Solnica
@solnic
Jun 21 2016 17:47
nope they are not, that’s why I said “this stuff does not change, memoize #hash, kthxbye” as in “add an option to dry-equalizer so that hash will be memoized”
John Backus
@backus
Jun 21 2016 17:48
Ah ok
Piotr Solnica
@solnic
Jun 21 2016 17:56
@backus so ie sutin like dis: include Dry::Equalizer(:foo, :bar, memoizable: true)
John Backus
@backus
Jun 21 2016 17:59
heh
Need a Dry::Adamantium
Piotr Solnica
@solnic
Jun 21 2016 18:03
adamantium/ice_nine work just fine :)
John Backus
@backus
Jun 21 2016 18:45

@backus proposal looks good except :permissive which shouldn’t use defaults, so I just want it to work exactly the same as current :strict - this is really important for the common case of building structs from db data that you expect to be valid
@backus if you could introduce these new constructors and update Struct to use them we’d have a release ready :)

@solnic :thumbsup:. Might not be able to get to it until this weekend. We'll see. Feel free to ping me as a reminder if more time passes than that

Steve
@dnd
Jun 21 2016 21:31
Is there a way with dry-types to define an attribute as either an Array, with members of a specific class, or just a single object of a specific class?
I'm trying to define objects for an api, and the data key can either be an an array of objects, a single object, or null
Nikita Shilnikov
@flash-gordon
Jun 21 2016 21:41
@dnd try dis Types::Strict::Nil | Types::Strict::Array.member(YourStruct) | YourStruct or maybe Types::Strict::Nil | Types::Strict::Array.member(Dry::Types[YourStruct]) | Dry::Types[YourStruct]
should work fine
Steve
@dnd
Jun 21 2016 21:46
@flash-gordon thanks, I'll give that a try
Piotr Solnica
@solnic
Jun 21 2016 22:17
huh yeah we really should add Struct.|
Andy Holland
@AMHOL
Jun 21 2016 22:43
Is there any reason Struct isn't just a normal type?
Piotr Solnica
@solnic
Jun 21 2016 22:46
@AMHOL type is an interface in dry-types, Struct class doesn't implement it
it probably should
Andy Holland
@AMHOL
Jun 21 2016 22:58
:+1:
Piotr Solnica
@solnic
Jun 21 2016 23:03
it's | optional default and enum
oh and #[]
Nikita Shilnikov
@flash-gordon
Jun 21 2016 23:04
extend Dry::Types::Builder + singleton_class.alias_method :[], :new ?
Piotr Solnica
@solnic
Jun 21 2016 23:11
IIRC | is not there
so this one would have to be implement on the struct class