Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implement new validators #27

Merged
merged 12 commits into from
Feb 28, 2023
8 changes: 8 additions & 0 deletions lib/goo/validators/enforce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def enforce(inst,attr,value)
check Goo::Validators::DataType, inst, attr, value, opt, DateTime
when :float, Float
check Goo::Validators::DataType, inst, attr, value, opt, Float
when :symmetric
check Goo::Validators::Symmetric, inst, attr, value, opt
when /^distinct_of_/
check Goo::Validators::DistinctOf, inst, attr, value, opt, opt
when /^superior_equal_to_/
check Goo::Validators::SuperiorEqualTo, inst, attr, value, opt, opt
when /^inverse_of_/
check Goo::Validators::InverseOf, inst, attr, value, opt, opt
when Proc
call_proc(opt, inst, attr)
when /^max_/, /^min_/
Expand Down
10 changes: 5 additions & 5 deletions lib/goo/validators/implementations/data_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class DataType < ValidatorBase
}

validity_check -> (obj) do
self.class.enforce_type(@type, @value)
self.enforce_type(@type, @value)
end

def initialize(inst, attr, value, type)
Expand All @@ -25,7 +25,7 @@ def initialize(inst, attr, value, type)



def self.enforce_type(type, value)
def enforce_type(type, value)
return true if value.nil?

if type == :boolean
Expand All @@ -44,21 +44,21 @@ def self.enforce_type(type, value)

end

def self.enforce_type_uri(value)
def enforce_type_uri(value)
return true if value.nil?

value.is_a?(RDF::URI) && value.valid?
end

def self.enforce_type_boolean(value)
def enforce_type_boolean(value)
if value.kind_of? Array
return value.select { |x| !is_a_boolean?(x) }.empty?
else
return is_a_boolean?(value)
end
end

def self.is_a_boolean?(value)
def is_a_boolean?(value)
return (value.class == TrueClass) || (value.class == FalseClass)
end
end
Expand Down
34 changes: 34 additions & 0 deletions lib/goo/validators/implementations/distinct_of.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module Goo
module Validators
class DistinctOf < ValidatorBase
include Validator

key :distinct_of_

error_message ->(obj) { "`#{@attr}` must be distinct of `#{@property}`"}

validity_check -> (obj) do
return true if self.class.empty_value?(@value)

self.distinct?(@inst, @property, @value)
end

def initialize(inst, attr, value, key)
super(inst, attr, value)
@property = self.class.property(key)
end



def distinct?(inst, property, value)
target_values = self.class.attr_value(property, inst)
current_values = Array(value)

!current_values.any?{ |x| self.find_any?(target_values, x)}
end
def find_any?(array, value)
array.any?{ |x| self.class.equivalent_value?(value, x)}
end
end
end
end
15 changes: 1 addition & 14 deletions lib/goo/validators/implementations/existence.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,10 @@ class Existence < ValidatorBase
error_message ->(obj) { "`#{@value}` value cannot be nil"}

validity_check -> (obj) do
not (@value.nil? || self.class.empty?(@value) || self.class.empty_array?(@value))
not self.class.empty_value?(@value)
end

def self.empty?(value)
empty_string?(value) || empty_to_s?(value)
end
def self.empty_string?(string)
string.is_a?(String) && string.strip.empty?
end

def self.empty_to_s?(object)
object && object.to_s&.strip.empty?
end

def self.empty_array?(array)
array.is_a?(Array) && array && array.reject{|x| x.nil? || empty?(x)}.empty?
end
end
end
end
35 changes: 35 additions & 0 deletions lib/goo/validators/implementations/inverse_of.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Goo
module Validators
class InverseOf < ValidatorBase
include Validator

key :inverse_of_

error_message ->(obj) {
"`#{@attr}` must be the inverse of ``#{@property}``"
}

validity_check -> (obj) do
return true if self.class.empty_value?(@value)

return Array(@value).select{|x| not inverse?(@property,x, @inst)}.empty?
end

def initialize(inst, attr, value, key)
super(inst, attr, value)
@property = self.class.property(key)
end

def inverse?(attr, value, source_object)
if self.class.respond_to?(attr, value)
target_values = self.class.attr_value(attr, value)
return target_values.any?{ |target_object| self.class.equivalent_value?(target_object, source_object)}
end

false
end


end
end
end
8 changes: 4 additions & 4 deletions lib/goo/validators/implementations/object_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ class ObjectType < ValidatorBase
validity_check -> (obj) do
values = Array(@value)

unless values.select { |v| !self.class.is_a_model?(v, @model_range) }.empty?
unless values.select { |v| !self.is_a_model?(v, @model_range) }.empty?
@error = :no_range
return false
end

unless values.select { |v| !self.class.persistent?(v) }.empty?
unless values.select { |v| !self.persistent?(v) }.empty?
@error = :persistence
return false
end
Expand All @@ -34,11 +34,11 @@ def initialize(inst, attr, value, model_range)
@model_range = model_range
end

def self.is_a_model?(value, model_range)
def is_a_model?(value, model_range)
value.is_a?(model_range) || (value.respond_to?(:klass) && value[:klass] == model_range)
end

def self.persistent?(value)
def persistent?(value)
value.respond_to?(:klass) || value.persistent?
end
end
Expand Down
26 changes: 26 additions & 0 deletions lib/goo/validators/implementations/superior_equal_to.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Goo
module Validators
class SuperiorEqualTo < ValidatorBase
include Validator

key :superior_equal_to_

error_message ->(obj) {
"`#{@attr}` must be superior or equal to `#{@property}`"
}

validity_check -> (obj) do
target_values = self.class.attr_value(@property, @inst)

return true if target_values.empty?

return @value >= target_values.first
end

def initialize(inst, attr, value, key)
super(inst, attr, value)
@property = self.class.property(key)
end
end
end
end
33 changes: 33 additions & 0 deletions lib/goo/validators/implementations/symmetric.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Goo
module Validators
class Symmetric < ValidatorBase
include Validator

key :symmetric

error_message ->(obj) {
"`#{@attr}` must be symmetric"
}

validity_check -> (obj) do
return true if self.class.empty_value?(@value)

return Array(@value).select{|x| not symmetric?(@attr,x, @inst)}.empty?
end

def symmetric?(attr, value, source_object)
if respond_to?(attr, value)
target_values = self.class.attr_value(attr, value)
return target_values.any?{ |target_object| self.class.equivalent_value?(target_object, source_object)}
end

return false
end

def respond_to?(attr, object)
object && object.respond_to?(attr)
end

end
end
end
12 changes: 6 additions & 6 deletions lib/goo/validators/implementations/value_range.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ValueRange < ValidatorBase
keys [:min_, :max_]

error_message ->(obj) {
value = self.class.value_length(@value)
value = self.value_length(@value)
if @type == :min
"#{@attr} value has length `#{value}` and the min length is `#{@range}`"
else
Expand All @@ -15,27 +15,27 @@ class ValueRange < ValidatorBase
}

validity_check -> (obj) do
self.class.enforce_range_length(@type, @range, @value)
self.enforce_range_length(@type, @range, @value)
end

def initialize(inst, attr, value, type)
super(inst, attr, value)
@type = type.index("max_") ? :max : :min
@range = self.class.range(type)
@range = self.range(type)
end

def self.enforce_range_length(type_range, range, value)
def enforce_range_length(type_range, range, value)
return false if value.nil?
value_length = self.value_length(value)

(type_range.eql?(:min) && (value_length >= range)) || (type_range.eql?(:max) && (value_length <= range))
end

def self.range(opt)
def range(opt)
opt[4..opt.length].to_i
end

def self.value_length(value)
def value_length(value)
return 0 if value.nil?

if value.is_a?(String) || value.is_a?(Array)
Expand Down
45 changes: 45 additions & 0 deletions lib/goo/validators/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,55 @@ def error_message(message)
def validator_settings
@validator_settings ||= {}
end

def ids
Array(validator_settings[:id])
end

def property(key)
key[ids.first.size..key.size].to_sym
end

def respond_to?(attr, object)
object && object.respond_to?(attr)
end


def equivalent_value?(object1, object2)
if object1.respond_to?(:id) && object2.respond_to?(:id)
object1.id.eql?(object2.id)
else
object2 == object1
end
end

def attr_value(attr, object)
Array(object.send(attr))
end

def empty_value?(value)
value.nil? || empty?(value) || empty_array?(value)
end
def empty?(value)
empty_string?(value) || empty_to_s?(value)
end
def empty_string?(string)
string.is_a?(String) && string.strip.empty?
end

def empty_to_s?(object)
object && object.to_s&.strip.empty?
end

def empty_array?(array)
array.is_a?(Array) && array && array.reject{|x| x.nil? || empty?(x)}.empty?
end
end





end
end
end
Expand Down
5 changes: 4 additions & 1 deletion test/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ def self.create_test_case_data
end

def self.delete_test_case_data
objects = [Student, University, Program, Category, Address]
delete_all [Student, University, Program, Category, Address]
end

def self.delete_all(objects)
objects.each do |obj|
obj.where.include(obj.attributes).each do |i|
i.delete
Expand Down
Loading