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:



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

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:



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

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

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

.cast_returns(api_method, return_value) ⇒ Object

:nodoc:



37
38
39
40
# File 'lib/action_web_service/casting.rb', line 37

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:



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

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