Open anoam opened 8 years ago
This is correct behaviour, how would you coerce "baz" to a Integer?
You can filter it yourself
foo.int_array.select { |k,v| v.is_a? Integer }
@zenry no it's not and it never will be. If a user asks for an integer array and a non-integer is given it should throw at minimum or reject at the extreme... that is correct behavior.
Well I have strict mode on so in my case it will fail loudly. That said I would not like Virtus or any library for that matter to just discard elements in my array. Coerce in non strict mode means to me that it will try to coerce it into the proper type and leave the rest as is.
What you guys want sounds more like a filter.
I don't think it should coerce that's for sure, I think it should throw though.
Agreed, but I also like that fact that you can turn that option on and off (strict mode)
Hi!
Sorry for my late reply.
First of all, I want to say that coercing array elements ignores nulify_blank: true
.
In my example even ""
was casted as ""
, not nil
.
Second, default coersions are unexpectable.
When result of coercing "baz"
to Integer
is "baz"
also looks little bit weird.
I expected to see 0
or `nil.
Using strict can be useful. But does not raising-catching exceptions means bad performance?
Ofcourse, I can resolve it with custom coercion.
But coercing arrays is problem for me. Is there any ways to customize it? I want something like this:
class MyInteger < Virtus::Attribute
primitive Integer
def coerce(input)
res = super
res.is_a?(Integer) ? res : nil
end
end
class MyArray < Virtus::Attribute::Array
def coerce
super.uniq.compact
end
end
class Foo
include Virtus.model(nulify_blank: true)
attribute :int_array, MyArray[MyInteger]
end
So, behaviour I look for, could be like this:
Foo.new(int_array: ["", "1", 2, "1bar", "baz"]).int_array #=> [1, 2]
In sources I found Collection
class. It looks like what i need. But it's documentation is poor. I can't understand how to use it.
Also I could override getter like this.
class Foo::ArrayCoercer
def initialize(array)
@array = array
end
def to_a
@array.uniq.compact
end
end
class Foo
include Virtus.model(nulify_blank: true)
attribute :int_array, Array[Integer]
def int_array
ArrayCoercer.new(super)
end
end
I'm facing a similar issue. I want a custom Array attribute, that ignores nil
entries:
class CompactedArray < Virtus::Attribute::Array
def coerce(value)
super&.compact
end
end
class Foo
include Virtus.mode
attribute :bars, CompactedArray[Bar]
end
But coerce
never gets called. It does work if I replace Virtus::Attribute::Array
with Virtus::Attribute
, but then it will complain about other methods that need to be implemented in my CompactedArray
. Any ideas on how to implement it?
Hi! It doesn't seems like bug or something. But it's look pretty weird for me. Here is my code:
Is there ways to drop attributes that wasn't converted to integer?