How to set default value for Dry::Validation.Params scheme? - ruby

I have next scheme
Dry::Validation.Params do
optional(:per_page).filled(:int?, lteq?: 1000)
optional(:page).filled(:int?)
end
If I pass empty hash for validation I get empty output but I want to set default values for my data.
I tried Dry::Types.default but it does not add default values in output. That's what I tried.
Dry::Validation.Params do
optional(:per_page).filled(Dry::Types['strict.integer'].default(10), lteq?: 1000)
optional(:page).filled(:int?)
end
Is it possible to do what I want?

The Dry::Validation has not this purpose.
I recommend you to use dry-initializer on your params before pass it to the validation.

You can do something like this:
optional(:per_page).filled(Types::Integer.constructor { _1 || 10 })
Or define your own fallback strategy as here https://github.com/dry-rb/dry-types/pull/410
optional(:per_page).filled(Types::Integer.constructor { |input, type| type.(input) { 10 } })

Related

How to make Ruby Mocha mock only check about one parameter

I want to mock this function:
def self.set_segment_info(segment_info, history_record)
history_record.segment_info = segment_info
end
In my test, I want a mock that only confirms that I called set_segment_info with an expected value. I don't care about what I pass in for history_record.
How would I do this? I tried
SegmentHistoryRecord.expects(:set_segment_info).with(:segment_info => expected_segment_info, :history_record => anything)
But that doesn't work.
I ran into this today and ended up doing something like:
SegmentHistoryRecord.expects(:set_segment_info).with(
expected_segment_info,
anything
)
I find it more readable that the do version and it helped me avoid a rubocop issue with too many parameters.
Here's an implementation where, if your function takes a lot of parameters, it's more convenient to specify a value for just the one you care about, instead of for all of them:
expected_segment_info = # ...
SegmentHistoryRecord.expects(:set_segment_info).with() { |actual_parameters| actual_parameters[:segment_info] == expected_segment_info }
(Where, as in the original question, set_segment_info is the function being mocked, and segment_info is the parameter whose value you want to match. Note that the history_record parameter -- and any others that might be present -- don't need to be included.)
SegmentHistoryRecord.expects(:set_segment_info).with() do |param1, param2|
# change below to your verification for :segment_info
# and leave param2 doing nothing, the expectation will ignore param2
param1 == expected_segment_info
end

Alternative to logical OR, where false is treated as truthy?

So I have some code that gets values from a couple sources in a fixed priority order. It looks like this:
{ foo: true
bar: 42
}.each_pair do |attrib,default|
instance_variable_set :"##{attrib}",data[attrib] || template[attrib] || otherdata[attrib] || default
end
As you can probably tell, trying to override a true default with false won't work. How would I fix this without creating a horrible mess? (I do know how to fix it with a horrible mess, but I'm fairly certain there is something nice in the standard library for this exact situation, I just don't remember what it is called and can't think of a good search term)
If you're looking for the first non-nil value:
instance_variable_set :"##{attrib}", [ data[attrib], template[attrib], otherdata[attrib], default ].compact.first
Not the most efficient method, but gets the job done and works well if not exercised aggressively.
A slightly more forgiving version:
instance_variable_set :"##{attrib}", [ data[attrib], template[attrib], otherdata[attrib], default ].find { |v| !v.nil? }
This scans for the first non-nil value and returns that. It doesn't produce an intermediate array like compact does.
What you really want is a more forgiving method:
def instance_variable_set_from(attrib, *sources)
instance_variable_set(:"##{attrib}", sources.find { |v| !v.nil? }
end
Which is more self-explanatory when used:
instance_variable_set_from(attrib, data[attrib], template[attrib], otherdata[attrib], default)
Assuming that data, template and otherdata are all hashes, you could use fetch. It returns the value if it is contained in the hash, or the block's result otherwise:
value = data.fetch(attrib) { template.fetch(attrib) { otherdata.fetch(attrib, default) } }
instance_variable_set :"##{attrib}", value
or alternatively find the first hash containing the key and fetch its result, falling back to default:
value = [data, template, other_data].find { |h| h.key?(attrib) }.fetch(attrib, default)
Note that this would also allow nil values.

Return defaul value of hash ruby

I am making a hash like this:
enum_gender={:male=>1,:female=>2, :default_when_fail=>3}
but I need that when I access
enum_gender[:somekey]
It return 3 by default or some value specified
:some_key could be any other :assd, :asf, :asdf
how do I do this ?
You can use fetch:
enum_gender={:male=>1,:female=>2}
enum_gender.fetch(key, 3)
enum_gender.fetch('a_non_key', 3) #=> 3
You can do this
enum_gender = Hash.new(3).merge({:male=>1,:female=>2})
=> {:male=>1, :female=>2}
enum_gender[:somekey]
=> 3
I suggest writing some kind of conditional. You could write it as its own function, an if/else/end block, or a ternary as you like.
Example:
if enum_gender.has_key?(key)
return enum_gender[key]
else
return <default value>
end

How to use .contains with array?

I have an array in a document that contains a list of user ids.
I'd like to find all documents that have this list of user ids.
I know I can do something like:
r.db('unicorn')
.table('rooms').filter(function(doc){
return doc('people').contains(
"id-one","id-two"
)
})
I know this will work great, but I have to hardcode things. How do I pass the contains function an array of values to match against?
After a little digging, The simplest solution was to use args. Was a bit non-obvious from the examples. This way I can pass in dynamic values and run commands with them.
r.db('unicorn')
.table('rooms').filter(function(doc){
return doc('people').contains(
r.args(["id-one","id-two"])
)
})
You can use setIntersection and pass array:
r.db('unicorn')
.table('rooms').filter(function(doc){
return doc('people').default([]).setIntersection(
["id-one","id-two"]
).count().eq(2)
})
So, if you have array:
var myArr = ["id-one","id-two"];
You can write query like this:
r.db('unicorn')
.table('rooms').filter(function(doc){
return doc('people').default([]).setIntersection(myArr).count().eq(myArr.length)
})

More concise way of writing this array inclusion / default fallback code?

I find that I've been doing this a fair enough number of times in my Rails controllers that I'm interested in finding a better way of writing it out (if possible). Essentially, I'm validating the input to a few options, and falling back on a default value if the input doesn't match any of the options.
valid_options = %w(most_active most_recent most_popular)
#my_param = valid_options.include?(params[:my_param]) ? params[:my_param] : 'most_recent'
If you use a hash instead of an array, it would be faster and cleaner. And, since your default is "most_recent", having "most_recent" in valid_options is redundant. You better remove it.
filter_options =
Hash.new("most_recent")
.merge("most_popular" => "most_popular", "most_active" => "most_active")
#my_param = filter_options[params[:my_param]]
I too would go the Hash route.
This could be imaginable:
Hash[valid_options.zip valid_options].fetch(params[:my_param], "most_recent")
A bit farfetched.
valid_options = %w(most_active most_recent most_popular)
(valid_options & [params[:my_param]]).first || 'most_recent'
How is the below:
valid_options = %w(most_active most_recent most_popular)
valid_options.detect(proc{'default_value'}){|i| i == params[:my_param] }
Another one:
valid_options = %w(most_active most_recent most_popular)
valid_options.dup.delete(params[:my_param]) { "default" }

Resources