signature_types.rb 4.3 KB
Newer Older
1 2 3 4
module ActionWebService # :nodoc:
  module SignatureTypes # :nodoc:
    def canonical_signature(signature)
      return nil if signature.nil?
5 6 7
      unless signature.is_a?(Array)
        raise(ActionWebServiceError, "Expected signature to be an Array")
      end
8 9 10 11 12
      i = -1
      signature.map{ |spec| canonical_signature_entry(spec, i += 1) }
    end

    def canonical_signature_entry(spec, i)
13
      orig_spec = spec
14 15
      name = "param#{i}"
      if spec.is_a?(Hash)
16
        name, spec = spec.keys.first, spec.values.first
17
      end
18
      type = spec
19
      if spec.is_a?(Array)
20
        ArrayType.new(orig_spec, canonical_signature_entry(spec[0], 0), name)
21 22 23
      else
        type = canonical_type(type)
        if type.is_a?(Symbol)
24
          BaseType.new(orig_spec, type, name)
25
        else
26
          StructuredType.new(orig_spec, type, name)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
        end
      end
    end

    def canonical_type(type)
      type_name = symbol_name(type) || class_to_type_name(type)
      type = type_name || type
      return canonical_type_name(type) if type.is_a?(Symbol)
      type
    end

    def canonical_type_name(name)
      name = name.to_sym
      case name
        when :int, :integer, :fixnum, :bignum
          :int
        when :string, :base64
          :string
        when :bool, :boolean
          :bool
        when :float, :double
          :float
        when :time, :timestamp
          :time
        when :datetime
          :datetime
        when :date
          :date
        else
          raise(TypeError, "#{name} is not a valid base type")
      end
    end

    def canonical_type_class(type)
      type = canonical_type(type)
      type.is_a?(Symbol) ? type_name_to_class(type) : type
    end

    def symbol_name(name)
      return name.to_sym if name.is_a?(Symbol) || name.is_a?(String)
      nil
    end

    def class_to_type_name(klass)
      klass = klass.class unless klass.is_a?(Class)
      if derived_from?(Integer, klass) || derived_from?(Fixnum, klass) || derived_from?(Bignum, klass)
        :int
      elsif klass == String
        :string
      elsif klass == TrueClass || klass == FalseClass
        :bool
      elsif derived_from?(Float, klass) || derived_from?(Precision, klass) || derived_from?(Numeric, klass)
        :float
      elsif klass == Time
        :time
      elsif klass == DateTime
        :datetime
      elsif klass == Date
        :date
      else
        nil
      end
    end

    def type_name_to_class(name)
      case canonical_type_name(name)
      when :int
        Integer
      when :string
        String
      when :bool
        TrueClass
      when :float
        Float
      when :time
        Time
      when :date
        Date
      when :datetime
        DateTime
      else
        nil
      end
    end

    def derived_from?(ancestor, child)
      child.ancestors.include?(ancestor)
    end

    module_function :type_name_to_class
    module_function :class_to_type_name
    module_function :symbol_name
    module_function :canonical_type_class
    module_function :canonical_type_name
    module_function :canonical_type
    module_function :canonical_signature_entry
    module_function :canonical_signature
    module_function :derived_from?
  end

  class BaseType # :nodoc:
    include SignatureTypes

130
    attr :spec
131 132 133 134
    attr :type
    attr :type_class
    attr :name

135 136
    def initialize(spec, type, name)
      @spec = spec
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
      @type = canonical_type(type)
      @type_class = canonical_type_class(@type)
      @name = name
    end

    def custom?
      false
    end

    def array?
      false
    end

    def structured?
      false
    end
  end

  class ArrayType < BaseType # :nodoc:
    attr :element_type

158 159
    def initialize(spec, element_type, name)
      super(spec, Array, name)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
      @element_type = element_type
    end

    def custom?
      true
    end

    def array?
      true
    end
  end

  class StructuredType < BaseType # :nodoc:
    def each_member
      if @type_class.respond_to?(:members)
        @type_class.members.each do |name, type|
          yield name, type
        end
      elsif @type_class.respond_to?(:columns)
179
        i = -1
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        @type_class.columns.each do |column|
          yield column.name, canonical_signature_entry(column.klass, i += 1)
        end
      end
    end

    def custom?
      true
    end

    def structured?
      true
    end
  end
end