Module: Structish::Validations::InstanceMethods
- Defined in:
- lib/structish/validations.rb
Instance Method Summary collapse
- #[]=(key, value) ⇒ Object
- #apply_defaults(constructor) ⇒ Object
- #attribute_values ⇒ Object
- #cast_single(value, klass) ⇒ Object
- #cast_values(constructor) ⇒ Object
- #define_accessor_methods(constructor) ⇒ Object
- #define_delegated_methods ⇒ Object
- #global_attributes_for(constructor) ⇒ Object
- #global_attributes_hash ⇒ Object
- #global_validations ⇒ Object
- #keys_for(constructor) ⇒ Object
- #parent_attributes(klass) ⇒ Object
- #parent_global_validations(klass) ⇒ Object
- #validate_class(attribute, value) ⇒ Object
- #validate_constructor(constructor) ⇒ Object
- #validate_custom(attribute, value, constructor) ⇒ Object
- #validate_key_restriction(constructor) ⇒ Object
- #validate_one_of(attribute, value) ⇒ Object
- #validate_presence(attribute, value) ⇒ Object
- #validate_structish(constructor) ⇒ Object
- #validations ⇒ Object
Instance Method Details
#[]=(key, value) ⇒ Object
137 138 139 140 |
# File 'lib/structish/validations.rb', line 137 def []=(key, value) super(key, value) validate_structish(self) end |
#apply_defaults(constructor) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/structish/validations.rb', line 34 def apply_defaults(constructor) validations.select { |v| v[:optional] }.each do |attribute| key = attribute[:key] default_value = if attribute[:default].is_a?(::Array) && attribute[:default].first == :other_attribute constructor[attribute[:default][1]] else attribute[:default] end constructor[key] = default_value if constructor[key].nil? end end |
#attribute_values ⇒ Object
166 167 168 169 170 171 172 |
# File 'lib/structish/validations.rb', line 166 def attribute_values if self.class < Array self.to_a.values_at(*self.class.attribute_keys) elsif self.class < Hash self.to_h.slice(*self.class.attribute_keys) end end |
#cast_single(value, klass) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/structish/validations.rb', line 62 def cast_single(value, klass) if value.is_a?(klass) value else if cast_method = Structish::CAST_METHODS[klass.to_s] value.send(cast_method) else klass.new(value) end end end |
#cast_values(constructor) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/structish/validations.rb', line 46 def cast_values(constructor) (validations + global_attributes_for(constructor)).each do |attribute| key = attribute[:key] if attribute[:cast] && constructor[key] if attribute[:klass] == ::Array && attribute[:of] unless constructor[key].class <= ::Array raise(Structish::ValidationError.new("Class mismatch for #{attribute[:key]} -> #{constructor[key].class}. Should be a Array", self.class)) end constructor[key] = constructor[key].map { |v| cast_single(v, attribute[:of]) } else constructor[key] = cast_single(constructor[key], attribute[:klass]) end end end end |
#define_accessor_methods(constructor) ⇒ Object
74 75 76 77 78 79 80 81 |
# File 'lib/structish/validations.rb', line 74 def define_accessor_methods(constructor) validations.each do |attribute| if accessor = attribute[:accessor] value = attribute[:proc] ? attribute[:proc].call(constructor[attribute[:key]]) : constructor[attribute[:key]] instance_variable_set "@#{accessor}", value end end end |
#define_delegated_methods ⇒ Object
20 21 22 23 24 |
# File 'lib/structish/validations.rb', line 20 def define_delegated_methods self.class.delegations.each do |function, object| define_singleton_method(function.to_s) { self.send(object.to_sym)&.send(function.to_sym) } end end |
#global_attributes_for(constructor) ⇒ Object
97 98 99 100 101 102 103 104 |
# File 'lib/structish/validations.rb', line 97 def global_attributes_for(constructor) global_attributes_hash[constructor] = begin constructor_keys = keys_for(constructor) global_validations.each_with_object([]) do |validation, arr| constructor_keys.each { |key| arr << validation.merge(key: key) } end end end |
#global_attributes_hash ⇒ Object
142 143 144 |
# File 'lib/structish/validations.rb', line 142 def global_attributes_hash @global_attributes_hash ||= {} end |
#global_validations ⇒ Object
150 151 152 |
# File 'lib/structish/validations.rb', line 150 def global_validations @global_validations ||= self.class.global_validations + parent_global_validations(self.class) end |
#keys_for(constructor) ⇒ Object
174 175 176 177 178 179 180 |
# File 'lib/structish/validations.rb', line 174 def keys_for(constructor) if constructor.class <= ::Array [*0..constructor.size-1] elsif constructor.class <= ::Hash constructor.keys end end |
#parent_attributes(klass) ⇒ Object
154 155 156 157 158 |
# File 'lib/structish/validations.rb', line 154 def parent_attributes(klass) if klass.superclass.respond_to?(:structish?) && klass.superclass.structish? klass.superclass.attributes + parent_attributes(klass.superclass) end || [] end |
#parent_global_validations(klass) ⇒ Object
160 161 162 163 164 |
# File 'lib/structish/validations.rb', line 160 def parent_global_validations(klass) if klass.superclass.respond_to?(:structish?) && klass.superclass.structish? klass.superclass.global_validations + parent_global_validations(klass.superclass) end || [] end |
#validate_class(attribute, value) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/structish/validations.rb', line 110 def validate_class(attribute, value) if attribute[:klass].nil? return elsif attribute[:of] valid = if attribute[:klass] <= ::Array value.class <= ::Array && value.all? { |v| v.class <= attribute[:of] } elsif attribute[:klass] <= ::Hash value.class <= ::Hash && value.values.all? { |v| v.class <= attribute[:of] } end raise(Structish::ValidationError.new("Class mismatch for #{attribute[:key]}. All values should be of type #{attribute[:of].to_s}", self.class)) unless valid else valid_klasses = [attribute[:klass]].flatten.compact valid = valid_klasses.any? { |klass| value.class <= klass } raise(Structish::ValidationError.new("Class mismatch for #{attribute[:key]} -> #{value.class}. Should be a #{valid_klasses.join(", ")}", self.class)) unless valid end end |
#validate_constructor(constructor) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/structish/validations.rb', line 83 def validate_constructor(constructor) (validations + global_attributes_for(constructor)).each do |attribute| value = constructor[attribute[:key]] if attribute[:optional] && value.nil? true else validate_presence(attribute, value) validate_class(attribute, value) validate_one_of(attribute, value) validate_custom(attribute, value, constructor) end end end |
#validate_custom(attribute, value, constructor) ⇒ Object
132 133 134 135 |
# File 'lib/structish/validations.rb', line 132 def validate_custom(attribute, value, constructor) valid = attribute[:validation] ? attribute[:validation].new(value, attribute, constructor).validate : true raise(Structish::ValidationError.new("Custom validation #{attribute[:validation].to_s} not met", self.class)) unless valid end |
#validate_key_restriction(constructor) ⇒ Object
26 27 28 29 30 31 32 |
# File 'lib/structish/validations.rb', line 26 def validate_key_restriction(constructor) if self.class.restrict? allowed_keys = validations.map { |attribute| attribute[:key] } valid = (keys_for(constructor) - allowed_keys).empty? raise(Structish::ValidationError.new("Keys are restricted to #{allowed_keys.join(", ")}", self.class)) unless valid end end |
#validate_one_of(attribute, value) ⇒ Object
127 128 129 130 |
# File 'lib/structish/validations.rb', line 127 def validate_one_of(attribute, value) valid = attribute[:one_of] ? attribute[:one_of].include?(value) : true raise(Structish::ValidationError.new("Value not one of #{attribute[:one_of].join(", ")}", self.class)) unless valid end |
#validate_presence(attribute, value) ⇒ Object
106 107 108 |
# File 'lib/structish/validations.rb', line 106 def validate_presence(attribute, value) raise(Structish::ValidationError.new("Required value #{attribute[:key]} not present", self.class)) unless !value.nil? end |
#validate_structish(constructor) ⇒ Object
11 12 13 14 15 16 17 18 |
# File 'lib/structish/validations.rb', line 11 def validate_structish(constructor) validate_key_restriction(constructor) apply_defaults(constructor) cast_values(constructor) validate_constructor(constructor) define_accessor_methods(constructor) define_delegated_methods end |
#validations ⇒ Object
146 147 148 |
# File 'lib/structish/validations.rb', line 146 def validations @validations ||= self.class.attributes + parent_attributes(self.class) end |