module OrangeData::GeneratedAttributes

Public Class Methods

from_schema(klass, schema) click to toggle source
# File lib/orange_data/generated_attributes.rb, line 25
def self.from_schema(klass, schema)
  klass.class_eval{
    extend GeneratedAttributes
    generate_accessors_from_schema(schema)
  }
end

Protected Instance Methods

generate_accessors_from_schema(schema) click to toggle source
# File lib/orange_data/generated_attributes.rb, line 34
def generate_accessors_from_schema(schema)
  plain_types = %w[integer string number]
  schema["properties"].each_pair do |property, info|
    property_name = info["x-name"] || property.underscore

    if plain_types.include?(info["type"]) ||
       info["type"].is_a?(Array) && plain_types.include?(info["type"].first) &&
       info["type"].last == "null" && info["type"].size == 2
      if info["x-enum"]
        inverse_map = info["x-enum"].map{|k, v| [v['val'], k.to_sym] }.to_h

        define_method(property_name){
          return nil if @payload[property].nil?

          inverse_map[@payload[property]] ||
            raise("unknown value #{@payload[property].inspect} for field #{property}")
        }
        define_method(:"#{property_name}="){|val|
          unless val.nil?
            val = (
              info["x-enum"][val.to_s] ||
              raise(ArgumentError, "unknown value #{val.inspect} for property #{property}")
            )["val"]
          end

          @payload[property] = val
        }

      elsif info["x-bitfield"]
        bitmap = info["x-bitfield"].map{|k, v| [k.to_sym, 1 << v['bit']] }.to_h
        # TODO: return wrapper so that :<< etc will work
        define_method(property_name){
          return nil if @payload[property].nil?

          data = @payload[property].to_i
          # FIXME: unknown bits will be silently lost
          bitmap.reject{|_, v| (data & v).zero? }.map(&:first)
        }
        define_method(:"#{property_name}="){|val|
          unless val.nil?
            val = [val] unless val.is_a?(Array)
            val = val.map{|v|
              bitmap[v] || raise(ArgumentError, "unknown value #{v.inspect} for property #{property}")
            }.reduce(:|)
          end
          @payload[property] = val
        }
      else
        # primitive
        define_method(property_name){ @payload[property] }
        define_method(:"#{property_name}="){|val| @payload[property] = val }
      end
    elsif info["type"] == 'array'
      if info["items"] && plain_types.include?(info["items"]["type"])
        define_method(property_name){ @payload[property] }
        define_method(:"#{property_name}="){|val|
          val = [val] unless val.is_a?(Array)
          @payload[property] = val
        }
        # else
        # ref?
      end

      # else

    end

    if info["x-alias"]
      alias_method info['x-alias'].to_s, property_name
      alias_method "#{info['x-alias']}=", "#{property_name}="
    end
  end
end