exact-target 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +4 -0
- data/LICENSE +481 -0
- data/Manifest +22 -0
- data/README.rdoc +170 -0
- data/Rakefile +40 -0
- data/exact-target.gemspec +32 -0
- data/lib/exact_target.rb +109 -0
- data/lib/exact_target/builder_ext.rb +11 -0
- data/lib/exact_target/configuration.rb +42 -0
- data/lib/exact_target/error.rb +16 -0
- data/lib/exact_target/net_https_hack.rb +8 -0
- data/lib/exact_target/request_builder.rb +284 -0
- data/lib/exact_target/response_class.erb +30 -0
- data/lib/exact_target/response_classes.rb +61 -0
- data/lib/exact_target/response_handler.rb +167 -0
- data/lib/exact_target/string_ext.rb +22 -0
- data/spec/exact_target/net_https_hack_spec.rb +8 -0
- data/spec/exact_target/response_handler_spec.rb +15 -0
- data/spec/exact_target/string_ext_spec.rb +13 -0
- data/spec/exact_target_data.yml +133 -0
- data/spec/exact_target_spec.rb +382 -0
- data/spec/spec.opts +4 -0
- data/spec/subscriber_list_spec.rb +290 -0
- metadata +95 -0
@@ -0,0 +1,284 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
module ExactTarget
|
4
|
+
class RequestBuilder
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def accountinfo_retrieve_attrbs
|
11
|
+
build(:accountinfo, :retrieve_attrbs)
|
12
|
+
end
|
13
|
+
|
14
|
+
def list_add(list_name, list_type=nil)
|
15
|
+
list_type = :public unless %w(public private salesforce).include?(list_type.to_s)
|
16
|
+
build(:list, :add) do |li|
|
17
|
+
li.list_type list_type.to_s
|
18
|
+
li.list_name list_name.to_s
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def list_edit(list_id, new_list_name)
|
23
|
+
build(:list, :edit, :listid, list_id) do |li|
|
24
|
+
li.list_name new_list_name.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_retrieve(id_or_name=nil)
|
29
|
+
if id_or_name.is_a?(Fixnum) or id_or_name =~ /^\d+$/
|
30
|
+
build(:list, :retrieve, :listid, id_or_name.to_i)
|
31
|
+
else
|
32
|
+
build(:list, :retrieve, :listname, id_or_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def list_import(list_id, file_name, file_mapping, options={})
|
37
|
+
options = list_import_default_options(options, file_name)
|
38
|
+
build(:list, :import, :listid, list_id) do |li|
|
39
|
+
li.tags_from_options! options, :file_name, :email_address, :file_type, :column_headings
|
40
|
+
li.file_mapping do |fm|
|
41
|
+
file_mapping.each { |m| fm.field(m) }
|
42
|
+
end
|
43
|
+
li.tags_from_options! options, :import_type, :returnid, :encrypted, :encrypt_format
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def list_importstatus(import_id)
|
48
|
+
build(
|
49
|
+
:list, :import,
|
50
|
+
:sub_action => :importstatus,
|
51
|
+
:search_type => :omit,
|
52
|
+
:search_value => import_id
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def list_retrieve_sub(list_id, status=nil)
|
57
|
+
unless status.nil? or %w(Active Unsubscribed Returned Undeliverable Deleted).include?(status)
|
58
|
+
raise "Invalid status: #{status}"
|
59
|
+
end
|
60
|
+
build(:list, :retrieve_sub, :listid, list_id) do |li|
|
61
|
+
li.search_status status unless status.nil?
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def list_delete(id)
|
66
|
+
build(:list, :delete, :listid, id)
|
67
|
+
end
|
68
|
+
|
69
|
+
def list_retrievegroups
|
70
|
+
build(:list, :retrievegroups, :groups)
|
71
|
+
end
|
72
|
+
|
73
|
+
def list_refresh_group(group_id)
|
74
|
+
build(
|
75
|
+
:list, :refresh_group,
|
76
|
+
:sub_action => nil,
|
77
|
+
:search_type => :omit,
|
78
|
+
:search_value => group_id,
|
79
|
+
:search_value2 => nil
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def batch_inquire(batch_id)
|
84
|
+
build(
|
85
|
+
:batch, :inquire, :batchid, batch_id,
|
86
|
+
:sub_action => nil,
|
87
|
+
:search_value2 => nil
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
###################################################################
|
92
|
+
|
93
|
+
def subscriber_add(list_id, subscriber, options={})
|
94
|
+
subscriber_edit(list_id, nil, subscriber, options)
|
95
|
+
end
|
96
|
+
|
97
|
+
def subscriber_edit(list_id, orig_email, subscriber, options={})
|
98
|
+
options = subscriber_edit_default_options(options)
|
99
|
+
subscriber = subscriber.to_et_hash if subscriber.is_a?(Subscriber)
|
100
|
+
action = orig_email.nil? ? :add : :edit
|
101
|
+
build(:subscriber, action, :listid, list_id, :search_value2 => orig_email) do |sub|
|
102
|
+
sub.values do |vs|
|
103
|
+
subscriber.each do |k, v|
|
104
|
+
vs.tag!(k.to_s, v) unless k.to_s =~ /status/i
|
105
|
+
end
|
106
|
+
vs.status options[:status].to_s
|
107
|
+
vs.reason options[:reason] if options.has_key? :reason
|
108
|
+
vs.ChannelMemberID options[:ChannelMemberID] if options.has_key? :ChannelMemberID
|
109
|
+
end
|
110
|
+
sub.update options[:update] if orig_email.nil?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def subscriber_retrieve(id, email=nil)
|
115
|
+
type = email.blank? ? :subid : :listid
|
116
|
+
build(:subscriber, :retrieve, type, id, :search_value2 => email)
|
117
|
+
end
|
118
|
+
|
119
|
+
def subscriber_delete(id, email=nil)
|
120
|
+
type = email.blank? ? :subid : :listid
|
121
|
+
build(:subscriber, :delete, type, id, :search_value2 => email)
|
122
|
+
end
|
123
|
+
|
124
|
+
def subscriber_masterunsub(*email_addresses)
|
125
|
+
build(:subscriber, :masterunsub, :emailaddress, :search_value => :omit) do |sub|
|
126
|
+
sub.search_value do |sv|
|
127
|
+
email_addresses.flatten.each { |a| sv.emailaddress(a) }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
###################################################################
|
133
|
+
|
134
|
+
def email_retrieve(name=nil, options={})
|
135
|
+
name, options = nil, name if name.is_a?(Hash)
|
136
|
+
start_date, end_date = %w(start_date end_date).map do |n|
|
137
|
+
et_date options[n.to_sym]
|
138
|
+
end
|
139
|
+
type = unless start_date.nil? and end_date.nil?
|
140
|
+
name.nil? ? :daterange : :emailnameanddaterange
|
141
|
+
else
|
142
|
+
name.nil? ? nil : :emailname
|
143
|
+
end
|
144
|
+
build(:email, :retrieve, type, name, :sub_action => :all, :search_value2 => nil) do |em|
|
145
|
+
em.daterange do |r|
|
146
|
+
r.startdate start_date if start_date
|
147
|
+
r.enddate end_date if end_date
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def email_add(name, subject, options)
|
153
|
+
build(:email, :add, :search_type => :omit, :search_value => :omit, :sub_action => 'HTMLPaste') do |em|
|
154
|
+
em.category
|
155
|
+
em.email_name name
|
156
|
+
em.email_subject subject
|
157
|
+
if options.has_key? :body
|
158
|
+
em.email_body { |eb| eb.cdata! options[:body] }
|
159
|
+
elsif options.has_key? :file
|
160
|
+
em.file_name options[:file]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def email_add_text(email_id, options)
|
166
|
+
build(:email, :add, :search_type => :emailid,
|
167
|
+
:search_value => email_id, :sub_action => :text) do |em|
|
168
|
+
if options.has_key? :body
|
169
|
+
em.email_body { |eb| eb.cdata! options[:body] }
|
170
|
+
elsif options.has_key? :file
|
171
|
+
em.file_name options[:file]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def email_retrieve_body(email_id)
|
177
|
+
build(:email, :retrieve, :emailid, email_id, :sub_action => :htmlemail) do |em|
|
178
|
+
em.search_value2
|
179
|
+
em.search_value3
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
###################################################################
|
184
|
+
|
185
|
+
def job_send(email_id, list_ids, options={})
|
186
|
+
options = job_send_default_options(options)
|
187
|
+
|
188
|
+
build(:job, :send, :emailid, email_id) do |job|
|
189
|
+
job.tags_from_options! options, :from_name, :from_email, :additional,
|
190
|
+
:multipart_mime, :track_links,
|
191
|
+
:send_date, :send_time
|
192
|
+
job_send_id_list job, :lists, list_ids
|
193
|
+
job_send_id_list job, :suppress, options[:suppress_ids]
|
194
|
+
job.test_send options[:test_send]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
###################################################################
|
199
|
+
private
|
200
|
+
###################################################################
|
201
|
+
|
202
|
+
def list_import_default_options(options, file_name)
|
203
|
+
options = options.dup
|
204
|
+
options[:file_name] = file_name
|
205
|
+
options[:file_type] ||= (file_name =~ /\.txt$/i ? 'tab' : 'csv')
|
206
|
+
options[:column_headings] ||= true
|
207
|
+
options[:import_type] ||= 0
|
208
|
+
options[:returnid] ||= true
|
209
|
+
options[:encrypted] ||= false
|
210
|
+
options
|
211
|
+
end
|
212
|
+
|
213
|
+
def subscriber_edit_default_options(options)
|
214
|
+
options = options.dup
|
215
|
+
options[:status] = :active unless options[:status].to_s == 'unsub'
|
216
|
+
options[:update] = true unless options[:update] == false
|
217
|
+
options
|
218
|
+
end
|
219
|
+
|
220
|
+
def job_send_default_options(options)
|
221
|
+
options = options.nil? ? {} : options.dup # Don't munge hash passed in
|
222
|
+
options[:multipart_mime] = false unless options.has_key? :multipart_mime
|
223
|
+
options[:track_links] = true unless options.has_key? :track_links
|
224
|
+
options[:test_send] = false unless options.has_key? :test_send
|
225
|
+
options[:send_date] ||= :immediate
|
226
|
+
options[:suppress_ids] ||= []
|
227
|
+
options
|
228
|
+
end
|
229
|
+
|
230
|
+
def job_send_id_list(job, tag, ids)
|
231
|
+
job.tag!(tag.to_s) do |li|
|
232
|
+
[ids].flatten.compact.each { |id| li.list id }
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def et_date(d)
|
237
|
+
d = Date.parse(d) if d.is_a?(String)
|
238
|
+
[d.month, d.day, d.year] * '/' if d
|
239
|
+
end
|
240
|
+
|
241
|
+
def build(system_name, action, search_type=nil, search_value=nil, options=nil, &block)
|
242
|
+
options = parse_options(search_type, search_value, options)
|
243
|
+
xml = Builder::XmlMarkup.new
|
244
|
+
xml.instruct! :xml, :version => "1.0", :encoding => nil
|
245
|
+
xml = xml.exacttarget do |et|
|
246
|
+
et.authorization do |a|
|
247
|
+
a.username @config.username
|
248
|
+
a.password @config.password
|
249
|
+
end
|
250
|
+
et.system do |s|
|
251
|
+
build_system(s, system_name, action, options, &block)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
xml.to_s
|
255
|
+
end
|
256
|
+
|
257
|
+
def parse_options(search_type, search_value, options)
|
258
|
+
options, search_type = search_type, nil if search_type.is_a?(Hash)
|
259
|
+
options, search_value = search_value, nil if search_value.is_a?(Hash)
|
260
|
+
options ||= {}
|
261
|
+
{ :search_type => search_type, :search_value => search_value }.merge(options)
|
262
|
+
end
|
263
|
+
|
264
|
+
def build_system(s, system_name, action, options, &block)
|
265
|
+
s.system_name system_name.to_s
|
266
|
+
s.action action.to_s
|
267
|
+
[:sub_action, :search_type, :search_value, :search_value2].each do |name|
|
268
|
+
build_system_option(s, name, options[name]) if options.has_key? name
|
269
|
+
end
|
270
|
+
yield(s) if block_given?
|
271
|
+
end
|
272
|
+
|
273
|
+
def build_system_option(s, name, value)
|
274
|
+
if name == :search_value and value.is_a?(Array)
|
275
|
+
s.search_values do |ss|
|
276
|
+
value.each { |v| ss.search_value v }
|
277
|
+
end
|
278
|
+
elsif value != :omit
|
279
|
+
s.tag! name.to_s, value.to_s
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
end
|
284
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class <%= name %>
|
2
|
+
|
3
|
+
<% attributes.each do |rb_a, et_a| %>
|
4
|
+
attr_accessor :<%= rb_a %>
|
5
|
+
|
6
|
+
<% if rb_a != et_a %>
|
7
|
+
alias :<%= et_a %> :<%= rb_a %>
|
8
|
+
alias :<%= et_a %>= :<%= rb_a %>=
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
def attributes
|
13
|
+
[<%= attributes.map { |rb_a, et_a| ":#{rb_a}" } * ', ' %>]
|
14
|
+
end
|
15
|
+
|
16
|
+
def et_attributes
|
17
|
+
[<%= attributes.map { |rb_a, et_a| ":#{et_a}" } * ', ' %>]
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
attributes.map { |a| [a, send(a)] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_et_hash
|
25
|
+
et_attributes.map { |a| [a, send(a)] }
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :to_s :<%= attributes.first.first %>
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module ExactTarget
|
4
|
+
#
|
5
|
+
# Response classes for ExactTarget. We'll use these rather
|
6
|
+
# than just stuff it all in a hash as it allows us to more
|
7
|
+
# easily map between ugly ET names (e.g. GroupID) to ruby-friendly
|
8
|
+
# names (e.g. group_id).
|
9
|
+
#
|
10
|
+
module ResponseClasses
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def extended(base)
|
14
|
+
class_from_et_attributes base, :ListProfileAttribute,
|
15
|
+
:name, :description, :default_value, :data_type, :required,
|
16
|
+
:min_size, :max_size, :subscriber_editable, :display, :values
|
17
|
+
|
18
|
+
class_from_et_attributes base, :ListInformation,
|
19
|
+
:list_name, :list_type, :modified, :subscriber_count,
|
20
|
+
:active_total, :held_count, :bounce_count, :unsub_count
|
21
|
+
|
22
|
+
class_from_et_attributes base, :ListGroupInformation,
|
23
|
+
:groupName, :groupID, :parentlistID, :description
|
24
|
+
|
25
|
+
class_from_et_attributes base, :SubscriberInformation,
|
26
|
+
:subid, :listid, :list_name, :subscriber
|
27
|
+
|
28
|
+
class_from_et_attributes base, :EmailInformation,
|
29
|
+
:emailname, :emailid, :emailsubject, :emailcreateddate, :categoryid
|
30
|
+
|
31
|
+
def base.subscriber_class
|
32
|
+
@subscriber_class ||= ResponseClasses.class_from_et_attributes(
|
33
|
+
self, :Subscriber, accountinfo_retrieve_attrbs.map(&:name)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def base.const_missing(name)
|
38
|
+
if name.to_sym == :Subscriber
|
39
|
+
subscriber_class
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def class_from_et_attributes(base, name, *attribute_names)
|
47
|
+
attributes = attribute_names.flatten.map do |a|
|
48
|
+
[a.to_s.underscore.gsub(' ', '_'), a.to_s.gsub(' ', '__')]
|
49
|
+
end
|
50
|
+
class_def = class_template.result(binding)
|
51
|
+
base.module_eval(class_def)
|
52
|
+
base.const_get(name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def class_template
|
56
|
+
@class_template ||= ERB.new File.read(File.expand_path '../response_class.erb', __FILE__)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
module ExactTarget
|
4
|
+
#
|
5
|
+
# This class is responsible for turning parsed ExactTarget response xml
|
6
|
+
# into data that applications can use
|
7
|
+
#
|
8
|
+
class ResponseHandler
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_import_id_result(resp)
|
15
|
+
handle_id_result resp, :import_info, :importid, /is being imported/i
|
16
|
+
end
|
17
|
+
|
18
|
+
%w(email job list subscriber).each do |t|
|
19
|
+
define_method "handle_#{t}_id_result", lambda { |resp|
|
20
|
+
handle_id_result resp, "#{t}_info", "#{t}_description", /success/i
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def accountinfo_retrieve_attrbs(resp)
|
25
|
+
resp.xpath('//attribute').map do |a|
|
26
|
+
create_result(ListProfileAttribute, a) do |child|
|
27
|
+
child.children.map { |v| cast_value(v.text) } if child.name == 'values'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
alias :list_add :handle_list_id_result
|
33
|
+
|
34
|
+
alias :list_edit :handle_list_id_result
|
35
|
+
|
36
|
+
def list_retrieve(resp)
|
37
|
+
if resp.xpath('//list/list_name').size == 1
|
38
|
+
resp.xpath('//list[1]').map do |list|
|
39
|
+
create_result(ListInformation, list)
|
40
|
+
end.first
|
41
|
+
else
|
42
|
+
resp.xpath('//listid').map do |id|
|
43
|
+
id.text.to_i
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
alias :list_import :handle_import_id_result
|
49
|
+
|
50
|
+
def list_importstatus(resp)
|
51
|
+
resp.xpath('//import_info[1]').first.text
|
52
|
+
end
|
53
|
+
|
54
|
+
def list_retrieve_sub(resp)
|
55
|
+
resp.xpath('//subscriber').map do |s|
|
56
|
+
return [] if s.text =~ /no subscribers found/i
|
57
|
+
create_result(Subscriber, s)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
alias :list_delete :handle_list_id_result
|
62
|
+
|
63
|
+
def list_retrievegroups(resp)
|
64
|
+
resp.xpath('//group').map do |group|
|
65
|
+
create_result(ListGroupInformation, group)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def list_refresh_group(resp)
|
70
|
+
resp.xpath('//groupRefresh/groupAsyncID[1]').first.text.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
def batch_inquire(resp)
|
74
|
+
resp.xpath('//Batch/status[1]').first.text
|
75
|
+
end
|
76
|
+
|
77
|
+
###################################################################
|
78
|
+
|
79
|
+
alias :subscriber_add :handle_subscriber_id_result
|
80
|
+
|
81
|
+
alias :subscriber_edit :handle_subscriber_id_result
|
82
|
+
|
83
|
+
def subscriber_retrieve(resp)
|
84
|
+
resp.xpath('//subscriber').map do |s|
|
85
|
+
return [] if s.text =~ /no subscribers found/i
|
86
|
+
sri = create_result(SubscriberInformation, s)
|
87
|
+
sri.subscriber = create_result(Subscriber, s)
|
88
|
+
sri
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
alias :subscriber_delete :handle_subscriber_id_result
|
93
|
+
|
94
|
+
def subscriber_masterunsub(resp)
|
95
|
+
resp = resp.xpath('//subscriberunsub').map do |su|
|
96
|
+
%w(emailaddress status).map { |p| su.xpath(".//#{p}[1]").first.text }
|
97
|
+
end
|
98
|
+
Hash[resp]
|
99
|
+
end
|
100
|
+
|
101
|
+
###################################################################
|
102
|
+
|
103
|
+
def email_retrieve(resp)
|
104
|
+
resp.xpath('//emaillist').map do |el|
|
105
|
+
create_result(EmailInformation, el)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def email_add(resp)
|
110
|
+
resp.xpath('//emailID[1]').first.text.to_i
|
111
|
+
end
|
112
|
+
|
113
|
+
alias :email_add_text :handle_email_id_result
|
114
|
+
|
115
|
+
def email_retrieve_body(resp)
|
116
|
+
resp.xpath('//htmlbody[1]').first.text
|
117
|
+
end
|
118
|
+
|
119
|
+
###################################################################
|
120
|
+
|
121
|
+
alias :job_send :handle_job_id_result
|
122
|
+
|
123
|
+
###################################################################
|
124
|
+
private
|
125
|
+
###################################################################
|
126
|
+
|
127
|
+
def handle_id_result(resp, info_tag, id_tag, success_regex)
|
128
|
+
info = resp.xpath("//#{info_tag}[1]").first
|
129
|
+
if !info.nil? and info.text =~ success_regex
|
130
|
+
id = resp.xpath("//#{id_tag}[1]").first
|
131
|
+
id.nil? ? true : cast_value(id.text)
|
132
|
+
else
|
133
|
+
raise Error.new(0, "Unsupported id result: #{resp.to_s}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def create_result(clazz, node, &block)
|
138
|
+
ret = clazz.new
|
139
|
+
node.children.each do |child|
|
140
|
+
if ret.respond_to? "#{child.name}="
|
141
|
+
val = yield(child) if block_given?
|
142
|
+
val = cast_value(child.text) if val.nil?
|
143
|
+
ret.send "#{child.name}=", val
|
144
|
+
end
|
145
|
+
end
|
146
|
+
ret
|
147
|
+
end
|
148
|
+
|
149
|
+
def cast_value(v)
|
150
|
+
case v
|
151
|
+
when /^[+-]?\d+$/
|
152
|
+
v.to_i
|
153
|
+
when /^([+-]?)(?=\dâ\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
|
154
|
+
v.to_f
|
155
|
+
when /^true$/i
|
156
|
+
true
|
157
|
+
when /^false$/i
|
158
|
+
false
|
159
|
+
when %r{^\d+/\d+/\d+ \d+:\d+:\d+ [AP]M$}i, %r{^\d+/\d+/\d+$}i
|
160
|
+
DateTime.parse(v)
|
161
|
+
else
|
162
|
+
v.strip
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|