exact-target 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|