lib/rasti/form.rb in rasti-form-3.1.2 vs lib/rasti/form.rb in rasti-form-4.0.0

- old
+ new

@@ -1,172 +1,73 @@ -require 'json' +require 'rasti-model' require 'multi_require' module Rasti - class Form + class Form < Rasti::Model extend MultiRequire require_relative_pattern 'form/*' - require_relative_pattern 'form/types/*' include Validable - class << self + def initialize(attributes={}) + begin + super attributes - def [](attributes) - Class.new(self) do - attributes.each do |name, type, options={}| - attribute name, type, options - end + cast_attributes! + + rescue Rasti::Model::UnexpectedAttributesError => ex + ex.attributes.each do |attr_name| + errors[attr_name] << 'unexpected attribute' end - end - def inherited(subclass) - subclass.instance_variable_set :@attributes, attributes.dup - end + rescue Rasti::Types::CompoundError => ex + ex.errors.each do |key, messages| + errors[key] += messages + end - def attribute(name, type, options={}) - attributes[name.to_sym] = options.merge(type: type) - attr_reader name end - def attributes - @attributes ||= {} - end - - def attribute_names - attributes.keys - end - - def to_s - "#{name || self.superclass.name}[#{attribute_names.map(&:inspect).join(', ')}]" - end - alias_method :inspect, :to_s - - end - - def initialize(attrs={}) - assign_attributes attrs - set_defaults validate! end - def to_s - "#<#{self.class.name || self.class.superclass.name}[#{to_h.map { |n,v| "#{n}: #{v.inspect}" }.join(', ')}]>" + def assigned?(attr_name) + assigned_attribute? attr_name.to_sym end - alias_method :inspect, :to_s - def attributes(options={}) - attributes_filter = {only: assigned_attribute_names, except: []}.merge(options) - (attributes_filter[:only] - attributes_filter[:except]).each_with_object({}) do |name, hash| - hash[name] = serialize(read_attribute(name)) - end - end - - def to_h - attributes - end - - def assigned?(name) - assigned_attribute_names.include? name - end - - def ==(other) - other.kind_of?(self.class) && other.attributes == attributes - end - - def eql?(other) - other.instance_of?(self.class) && other.attributes == attributes - end - - def hash - [self.class, attributes].hash - end - private - def assign_attributes(attrs={}) - attrs.each do |name, value| - attr_name = name.to_sym - begin - if self.class.attributes.key? attr_name - write_attribute attr_name, value - else - errors[attr_name] << 'unexpected attribute' - end - - rescue CastError => error - errors[attr_name] << error.message - - rescue MultiCastError, ValidationError => error - error.errors.each do |inner_name, inner_errors| - inner_errors.each { |message| errors["#{attr_name}.#{inner_name}"] << message } - end - end + def assert_present(attr_name) + if !errors.key?(attr_name) + assert attr_name, assigned?(attr_name) && !public_send(attr_name).nil?, 'not present' end + rescue Types::Error + assert attr_name, false, 'not present' end - def set_defaults - (self.class.attribute_names - attributes.keys).each do |name| - if self.class.attributes[name].key? :default - value = self.class.attributes[name][:default] - write_attribute name, value.is_a?(Proc) ? value.call(self) : value - end - end + def assert_not_present(attr_name) + assert attr_name, !assigned?(attr_name) || public_send(attr_name).nil?, 'is present' + rescue Types::Error + assert attr_name, false, 'is present' end - def assigned_attribute_names - self.class.attribute_names & instance_variables.map { |v| v.to_s[1..-1].to_sym } - end - - def serialize(value) - if value.kind_of? Array - value.map { |v| serialize v } - elsif value.kind_of? Form - value.attributes - else - value + def assert_not_empty(attr_name) + if assert_present attr_name + value = public_send attr_name + assert attr_name, value.is_a?(String) ? !value.strip.empty? : !value.empty?, 'is empty' end end - def read_attribute(name) - instance_variable_get "@#{name}" - end - - def write_attribute(name, value) - typed_value = value.nil? ? nil : self.class.attributes[name][:type].cast(value) - instance_variable_set "@#{name}", typed_value - end - - def fetch(attribute) - attribute.to_s.split('.').inject(self) do |target, attr_name| - target.nil? ? nil : target.public_send(attr_name) + def assert_included_in(attr_name, set) + if assert_present attr_name + assert attr_name, set.include?(public_send(attr_name)), "not included in #{set.map(&:inspect).join(', ')}" end end - def assert_present(attribute) - assert attribute, !fetch(attribute).nil?, 'not present' unless errors.key? attribute - end - - def assert_not_present(attribute) - assert attribute, fetch(attribute).nil?, 'is present' - end - - def assert_not_empty(attribute) - if assert_present attribute - value = fetch attribute - assert attribute, value.is_a?(String) ? !value.strip.empty? : !value.empty?, 'is empty' - end - end - - def assert_time_range(attribute_from, attribute_to) - assert attribute_from, public_send(attribute_from) <= public_send(attribute_to), 'invalid time range' - end - - def assert_included_in(attribute, set) - if assert_present attribute - assert attribute, set.include?(fetch(attribute)), "not included in #{set.map { |e| e.is_a?(::String) ? "'#{e}'" : e.inspect }.join(', ')}" + def assert_range(attr_name_from, attr_name_to) + if assert_present(attr_name_from) && assert_present(attr_name_to) + assert attr_name_from, public_send(attr_name_from) <= public_send(attr_name_to), 'invalid range' end end end end \ No newline at end of file