require 'amsi/attribute_parser' require_relative 'base/attribute_store' module Amsi module Model # Base class for models, which are the return values from Requests class Base class << self attr_accessor :attribute_store end # Create a DSL to define the models attributes and their data types. This # bit of meta-programming will create a class method for each data type # to define the model's attributes of the type, e.g. # # class LostAndFound < Base # date_attr :found_date, :lost_date # end # # When a new LostAndFound is initialized (from an AMSI response hash, # that may have the keys 'founddate' and 'lostdate'), it will create # attribute readers for #found_date and #lost_date that return Date # instances. # # Boolean attributes will have the existential '?', e.g. # # class LostAndFound < Base # boolean_attr :found # end # # lost_and_found = LostAndFound.new('foundbit' => '1') # lost_and_found.found? # # => true %i[ boolean date date_time decimal integer object string phone ].each do |data_type| define_singleton_method "#{data_type}_attrs" do |*attrs| self.attribute_store ||= AttributeStore.new(self) attribute_store.add(data_type, attrs).each do |attribute| define_method attribute.accessor_name do instance_variable_get("@#{attribute.name}") end end end end # Initialize a new model with the response hash from AMSI. Attribute # values are parsed into their configured data types. # # @param attrs [Hash] the response hash from AMSI. # Attribute keys are case insensitive. def initialize(attrs = {}) attrs.each do |attr, value| attribute = self.class.attribute_store.find(attr) next unless attribute parser = AttributeParser.new(value: value, type: attribute.type) instance_variable_set("@#{attribute.name}", parser.parse) end end end private_constant :Base end end