class Foraneus
Foraneus
base class used to declare a data set, aka ‘form’.
Constants
- Error
Public Class Methods
Return the names of data and error accessors
Returned hash contains the keys :data and :errors, where values are the proper accesor names
@return [Hash]
# File lib/foraneus.rb, line 122 def self.accessors @accessors ||= { :data => :data, :errors => :errors } end
Declares a boolean field.
@param [Symbol] name The name of the field.
# File lib/foraneus.rb, line 31 def self.boolean(name, *args) converter = Foraneus::Converters::Boolean.new(*args) field(name, converter) end
Create a new instance while setting up data and error accessors
@return [Foraneus]
# File lib/foraneus.rb, line 132 def self.create_instance instance = self.new Utils.singleton_attr_accessor(instance, :data, {}) Utils.singleton_attr_accessor(instance, :errors, {}) instance end
Declares a date field.
@param [Symbol] name The name of the field. @param (see Foraneus::Converters::Date#initialize)
# File lib/foraneus.rb, line 40 def self.date(name, *args) converter = Foraneus::Converters::Date.new(*args) field(name, converter) end
Declares a decimal field.
@param [Symbol] name The name of the field. @param (see Foraneus::Converters::Decimal#initialize)
# File lib/foraneus.rb, line 49 def self.decimal(name, *args) converter = Foraneus::Converters::Decimal.new(*args) field(name, converter) end
Declares a field.
When no converter is given, noop is assigned.
@param [Symbol] name The name of the field. @param [#parse, raw] converter The converter.
# File lib/foraneus.rb, line 103 def self.field(name, converter = nil) converter ||= Foraneus::Converters::Noop.new fields[name.to_s] = converter self.send(:attr_accessor, name) end
Map of fields and their corresponding converters.
@return [Hash<String, Converter>]
# File lib/foraneus.rb, line 113 def self.fields @fields ||= {} end
Declares a float field.
@param [Symbol] name The name of the field. @param (see Foraneus::Converters::Float#initialize)
# File lib/foraneus.rb, line 58 def self.float(name, *args) converter = Foraneus::Converters::Float.new(*args) field(name, converter) end
Declares a nested form field
@param [Symbol] name The name of the field. @yield Yields to a nested foraneus spec.
# File lib/foraneus.rb, line 67 def self.form(name, &block) converter = Class.new(Foraneus::Converters::Nested, &block) field(name, converter) end
Declares an integer field.
@param [Symbol] name The name of the field. @param (see Foraneus::Converters::Integer#initialize)
# File lib/foraneus.rb, line 76 def self.integer(name, *args) converter = Foraneus::Converters::Integer.new(*args) field(name, converter) end
@api private
# File lib/foraneus.rb, line 24 def initialize @_ = {} # Hash that holds external representation data end
Declares a noop field.
@param [Symbol] name The name of the field.
# File lib/foraneus.rb, line 84 def self.noop(name, *args) converter = Foraneus::Converters::Noop.new(*args) field(name, converter) end
Parses data coming from an external source.
@param [Hash<Symbol, String>] data External data.
@return [Foraneus] An instance of a form.
# File lib/foraneus.rb, line 146 def self.parse(data = {}) instance = self.create_instance data = data.dup instance.instance_variable_set(:@_, data.dup) fields.each do |field, converter| __parse_field(data, field, converter, instance) end instance end
Converts data into an external representation.
@param [Hash<Symbol, Object>] data
@return [Foraneus] An instance of a form.
# File lib/foraneus.rb, line 164 def self.raw(data = {}) instance = self.create_instance data = data.dup instance.send("#{self.accessors[:data]}=", data) fields.each do |field, converter| __raw_field(data, field, converter, instance) end instance end
Declares a string field.
@param [Symbol] name The name of the field.
# File lib/foraneus.rb, line 92 def self.string(name, *args) converter = Foraneus::Converters::String.new(*args) field(name, converter) end
Private Class Methods
# File lib/foraneus.rb, line 205 def self.__parse_field(data, field, converter, instance) s, is_present = Utils.fetch(data, field) v, error = Utils.parse_datum(field, s, converter) if error.nil? && !v.nil? && Foraneus::Utils.nested_converter?(converter) instance.send(self.accessors[:data])[field.to_sym] = v.data if is_present instance.send("#{field}=", v) unless v.valid? error = Foraneus::Error.new('NestedFormError', "Invalid nested form: #{field}") instance.send(self.accessors[:errors])[field.to_sym] = error end elsif error.nil? instance.send("#{field}=", v) instance.send(self.accessors[:data])[field.to_sym] = v if is_present || converter.opts.include?(:default) else if Foraneus::Utils.nested_converter?(converter) error = Foraneus::Error.new('NestedFormError', "Invalid nested form: #{field}") instance.send(self.accessors[:errors])[field.to_sym] = error else instance.send(self.accessors[:errors])[field.to_sym] = error if error end end end
# File lib/foraneus.rb, line 232 def self.__raw_field(data, field, converter, instance) v, is_present = Utils.fetch(data, field) instance.send("#{field}=", v) if v.nil? v = converter.opts[:default] end s = Utils.raw_datum(v, converter) if Foraneus::Utils.nested_converter?(converter) instance.send("#{field}=", s) end if is_present || converter.opts.include?(:default) if Foraneus::Utils.nested_converter?(converter) && !s.nil? instance[field.to_sym] = s[] else instance[field.to_sym] = s end end end
Public Instance Methods
@return [Hash] raw data when m == nil. @return [Array<Error>] errors when m == :errors. @return [String] raw data value for the field m.
# File lib/foraneus.rb, line 180 def [](m = nil) if m.nil? @_ else @_.fetch(m.to_s) do @_[m.to_sym] end end end
@api private
Sets a raw value.
@param [Symbol] k Field name. @param [String] v Raw value.
# File lib/foraneus.rb, line 196 def []=(k, v) @_[k] = v end
Returns true if no conversion errors occurred. false otherwise.
# File lib/foraneus.rb, line 201 def valid? @errors.empty? end