Class: ActionWebService::Casting::BaseCaster

Inherits:
Object
  • Object
show all
Extended by:
SignatureTypes
Defined in:
lib/action_web_service/casting.rb

Overview

Performs casting of arbitrary values into the correct types for the signature

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SignatureTypes

canonical_signature, canonical_signature_entry, canonical_type, canonical_type_class, canonical_type_name, class_to_type_name, derived_from?, symbol_name, type_name_to_class

Constructor Details

#initialize(api_method) ⇒ BaseCaster

:nodoc:



13
14
15
# File 'lib/action_web_service/casting.rb', line 13

def initialize(api_method)
  @api_method = api_method
end

Class Method Details

.cast(value, signature_type) ⇒ Object

:nodoc:



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
# File 'lib/action_web_service/casting.rb', line 46

def cast(value, signature_type) # :nodoc:
  return value if signature_type.nil? # signature.length != params.length
  return nil if value.nil?
  # XMLRPC protocol doesn't support nil values. It uses false instead.
  # It should never happen for SOAP.
  if signature_type.structured? && value.equal?(false)
    return nil
  end
  unless signature_type.array? || signature_type.structured?
    return value if canonical_type(value.class) == signature_type.type
  end
  if signature_type.array?
    unless value.respond_to?(:entries) && !value.is_a?(String)
      raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
    end
    value.entries.map do |entry|
      cast(entry, signature_type.element_type)
    end
  elsif signature_type.simple?
    return value
  elsif signature_type.structured?
    cast_to_structured_type(value, signature_type)
  elsif !signature_type.custom?
    cast_base_type(value, signature_type)
  end
end

.cast_base_type(value, signature_type) ⇒ Object

:nodoc:



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
130
131
# File 'lib/action_web_service/casting.rb', line 73

def cast_base_type(value, signature_type) # :nodoc:
  # This is a work-around for the fact that XML-RPC special-cases DateTime values into its own DateTime type
  # in order to support iso8601 dates. This doesn't work too well for us, so we'll convert it into a Time,
  # with the caveat that we won't be able to handle pre-1970 dates that are sent to us.
  # 
  # See http://dev.rubyonrails.com/ticket/2516
  value = value.to_time if value.is_a?(XMLRPC::DateTime)

  case signature_type.type
  when :int
    Integer(value)
  when :string
    value.to_s
  when :base64
    if value.is_a?(ActionWebService::Base64)
      value
    else
      ActionWebService::Base64.new(value.to_s)
    end
  when :bool
    return false if value.nil?
    return value if value == true || value == false
    case value.to_s.downcase
    when '1', 'true', 'y', 'yes'
      true
    when '0', 'false', 'n', 'no'
      false
    else
      raise CastingError, "Don't know how to cast #{value.class} into Boolean"
    end
  when :float
    Float(value)
  when :decimal
    BigDecimal(value.to_s)
  when :time
    if value.kind_of?(Hash)
      value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6])
      Time.respond_to?(:strptime) ? Time.strptime(value.to_s, "%m/%d/%Y %H:%M:%S") : Time.parse(value.to_s)
    elsif value.kind_of?(Time) 
      value
    elsif value.kind_of?(DateTime)
      value.to_time
    else
      Time.parse(value.to_s)
    end
  when :date
    if value.kind_of?(Hash)
      value = "%s/%s/%s" % value.values_at(*%w[2 3 1])
      return Date.strptime(value.to_s,"%m/%d/%Y")
    end
    value.kind_of?(Date) ? value : Date.parse(value.to_s)
  when :datetime
    if value.kind_of?(Hash)
      value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6])
      return DateTime.strptime(value.to_s,"%m/%d/%Y %H:%M:%S")
    end
    value.kind_of?(DateTime) ? value : DateTime.parse(value.to_s)
  end
end

.cast_expects(api_method, params) ⇒ Object

:nodoc:



32
33
34
35
36
37
38
39
# File 'lib/action_web_service/casting.rb', line 32

def cast_expects(api_method, params) # :nodoc:
  return [] if api_method.expects.nil?
  if params.is_a?(Array)
      api_method.expects.zip(params).map{ |type, param| cast(param, type) }
  elsif params.is_a?(Hash)
      api_method.expects.map {|type| cast(params[type.name.to_s], type) }
  end
end

.cast_returns(api_method, return_value) ⇒ Object

:nodoc:



41
42
43
44
# File 'lib/action_web_service/casting.rb', line 41

def cast_returns(api_method, return_value) # :nodoc:
  return nil if api_method.returns.nil?
  cast(return_value, api_method.returns[0])
end

.cast_to_structured_type(value, signature_type) ⇒ Object

:nodoc:



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/action_web_service/casting.rb', line 133

def cast_to_structured_type(value, signature_type) # :nodoc:
  obj = nil
  # if the canonical classes are the same or if the given value is of 
  # a type that is derived from the signature_type do not attempt to 
  # "cast" the value into the signature_type as it's already good to go
  obj = (
    canonical_type(value.class) == canonical_type(signature_type.type) or 
    derived_from?(signature_type.type, value.class)
  ) ? value : signature_type.type_class.new
  if value.respond_to?(:each_pair)
    klass = signature_type.type_class
    value.each_pair do |name, val|
      type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
      val = cast(val, type) if type
      # See http://dev.rubyonrails.com/ticket/3567
      val = val.to_time if val.is_a?(XMLRPC::DateTime)
      obj.__send__("#{name}=", val) if obj.respond_to?(name)
    end
  elsif value.respond_to?(:attributes)
    signature_type.each_member do |name, type|
      val = value.__send__(name)
      obj.__send__("#{name}=", cast(val, type)) if obj.respond_to?(name)
    end
  else
    raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
  end
  obj
end

Instance Method Details

#cast_expects(params) ⇒ Object

Coerces the parameters in params (an Enumerable) into the types this method expects



19
20
21
# File 'lib/action_web_service/casting.rb', line 19

def cast_expects(params)
  self.class.cast_expects(@api_method, params)
end

#cast_returns(return_value) ⇒ Object

Coerces the given return_value into the type returned by this method



25
26
27
# File 'lib/action_web_service/casting.rb', line 25

def cast_returns(return_value)
  self.class.cast_returns(@api_method, return_value)
end