episodic-platform 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +35 -0
  3. data/PostInstall.txt +7 -0
  4. data/README.rdoc +86 -0
  5. data/Rakefile +45 -0
  6. data/lib/episodic/platform.rb +82 -0
  7. data/lib/episodic/platform/analytics_methods.rb +190 -0
  8. data/lib/episodic/platform/base.rb +64 -0
  9. data/lib/episodic/platform/collection_response.rb +45 -0
  10. data/lib/episodic/platform/connection.rb +305 -0
  11. data/lib/episodic/platform/exceptions.rb +105 -0
  12. data/lib/episodic/platform/query_methods.rb +721 -0
  13. data/lib/episodic/platform/response.rb +94 -0
  14. data/lib/episodic/platform/write_methods.rb +446 -0
  15. data/script/console +10 -0
  16. data/script/destroy +14 -0
  17. data/script/generate +14 -0
  18. data/test/fixtures/1-0.mp4 +0 -0
  19. data/test/fixtures/create-episode-response-s3.xml +15 -0
  20. data/test/fixtures/create-episode-response.xml +3 -0
  21. data/test/fixtures/episodes-response.xml +408 -0
  22. data/test/fixtures/episodes-summary-report-response.xml +4 -0
  23. data/test/fixtures/invalid-param-response-multiple.xml +8 -0
  24. data/test/fixtures/invalid-param-response-single.xml +9 -0
  25. data/test/fixtures/playlists-response.xml +611 -0
  26. data/test/fixtures/shows-response.xml +26 -0
  27. data/test/test_analytics_requests.rb +42 -0
  28. data/test/test_analytics_responses.rb +14 -0
  29. data/test/test_connection.rb +31 -0
  30. data/test/test_error_responses.rb +29 -0
  31. data/test/test_helper.rb +8 -0
  32. data/test/test_query_requests.rb +62 -0
  33. data/test/test_query_responses.rb +165 -0
  34. data/test/test_write_requests.rb +56 -0
  35. data/test/test_write_responses.rb +24 -0
  36. metadata +135 -0
@@ -0,0 +1,721 @@
1
+ module Episodic #:nodoc:
2
+
3
+ module Platform
4
+
5
+ #
6
+ # Class for making requests against the Episodic Platform Query API.
7
+ #
8
+ class QueryMethods < Base
9
+
10
+ class << self
11
+
12
+ #
13
+ # Queries for episodes in your network. The options parameter allows you to limit
14
+ # your results. Acceptable options are:
15
+ # show_id - A single id or an Array of show ids. If this param is not provided then
16
+ # all shows in your network are queried.
17
+ # id - A single id or an Array of episode ids. If this param is not provided then
18
+ # all episodes in the your network or specified shows are queried.
19
+ # search_term - This string is used to perform a keywords search against the title,
20
+ # description, tags and custom fields of an episode. Tags should be separated by
21
+ # commas.
22
+ # search_type - The search_type parameter must be one of "tags", "name_description"
23
+ # or "all". The default is "all"
24
+ # tag_mode - The tag_mode parameter can be "any" for an OR combination of tags, or
25
+ # "all" for an AND combination. The default is "any". This parameter is ignored if
26
+ # the search_type is not "tags".
27
+ # status - The status parameter can be used to limit the list of episodes with a
28
+ # certain publishing status. The value must be a comma delimited list of one or more
29
+ # of "off_the_air", "publishing", "on_the_air", "waiting_to_air", "publish_failed"
30
+ # sort_by - The sort_by parameter is optional and specifies a field to sort the results
31
+ # by. The value must be one of "updated_at", "created_at", "air_date" or "name".
32
+ # The default is "created_at".
33
+ # sort_dir - The sort_dir parameter is optional and specifies the sort direction. The
34
+ # value must be one of "asc" or "desc". The default is "asc".
35
+ # include_views - A value that must be one of "true" or "false" to indicate if total
36
+ # views and complete views should be included in the response. The default is "false".
37
+ # NOTE: Setting this to "true" may result in slower response times.
38
+ # page - A value that must be an integer indicating the page number to return the results
39
+ # for. The default is 1.
40
+ # per_page - A value that must be an integer indicating the number of items per page. The
41
+ # default is 20. NOTE: The smaller this value is the better your response times will be.
42
+ # embed_width - An integer value in pixels that specifies the width of the player. The
43
+ # returned embed code width may be larger that this to account for player controls
44
+ # depending on the player you are using. If only the width is provided, the height is
45
+ # determined by maintaining the aspect ratio.
46
+ # embed_height - An integer value in pixels that specifies the height of the player. The
47
+ # embed code height may be larger that this to account for player controls depending on
48
+ # the player you are using. The default height is 360.
49
+ #
50
+ # ==== Parameters
51
+ #
52
+ # options<Hash>:: A hash of optional attributes.
53
+ #
54
+ # ==== Returns
55
+ #
56
+ # ::Episodic::Platform::EpisodesResponse:: The parsed response.
57
+ #
58
+ def episodes options = {}
59
+
60
+ # Clone the options into our params hash
61
+ params = options.clone
62
+
63
+ # Make the request
64
+ response = connection.do_get(construct_url("query", "episodes"), params)
65
+
66
+ # Convert to a hash
67
+ return parse_episodes_response(response)
68
+ end
69
+
70
+ #
71
+ # Third-party applications can register to be notified of changes to episodes and
72
+ # playlists in their network by providing an Modification URL in their network settings.
73
+ # When an episode/playlist is created, modified or deleted the Episodic System when
74
+ # make a POST request to specified URL with an XML representation of the modified object.
75
+ #
76
+ # This method allows the caller to query for all callbacks registered since a specified time.
77
+ # Although, failed callbacks are marked as failed and retried, this method allows the caller
78
+ # to see a history of callbacks to perhaps reprocess them if something went wrong with their
79
+ # initial processing.
80
+ #
81
+ # Acceptable filter options are:
82
+ # pending_only - Set this parameter to 'true' if only unprocessed callbacks should be
83
+ # returned. The default is 'false'.
84
+ # page - A value that must be an integer indicating the page number to return the results
85
+ # for. The default is 1.
86
+ # per_page - A value that must be an integer indicating the number of items per page. The
87
+ # default is 20. NOTE: The smaller this value is the better your response times will be.
88
+ #
89
+ # ==== Parameters
90
+ #
91
+ # since<Time>:: All callbacks registered since the provided date will be included in the
92
+ # response.
93
+ # options<Hash>:: A hash of optional attributes.
94
+ #
95
+ # ==== Returns
96
+ #
97
+ # String:: The XML response from the server.
98
+ #
99
+ def modification_callbacks since, options = {}
100
+
101
+ # Clone the options into our params hash
102
+ params = options.clone
103
+ params[:since] = since
104
+
105
+ # Make the request
106
+ response = connection.do_get(construct_url("query", "modification_callbacks"), params)
107
+
108
+ # Convert to a hash
109
+ return response.body
110
+ end
111
+
112
+ #
113
+ # Queries for playlists in your network. The options parameter allows you to limit
114
+ # your results. Acceptable options are:
115
+ # show_id - A single id or an Array of show ids. If this param is not provided then
116
+ # all shows in your network are queried.
117
+ # id - A single id or an Array of playlist ids. If this param is not provided then
118
+ # all playlists in the your network or specified shows are queried.
119
+ # search_term - This string is used to perform a keywords search against the title,
120
+ # description, and custom fields of a playlist.
121
+ # sort_by - The sort_by parameter is optional and specifies a field to sort the results
122
+ # by. The value must be one of "updated_at", "created_at", "name".
123
+ # The default is "created_at".
124
+ # sort_dir - The sort_dir parameter is optional and specifies the sort direction. The
125
+ # value must be one of "asc" or "desc". The default is "asc".
126
+ # page - A value that must be an integer indicating the page number to return the results
127
+ # for. The default is 1.
128
+ # per_page - A value that must be an integer indicating the number of items per page. The
129
+ # default is 20. NOTE: The smaller this value is the better your response times will be.
130
+ # embed_width - An integer value in pixels that specifies the width of the player. The
131
+ # returned embed code width may be larger that this to account for player controls
132
+ # depending on the player you are using. If only the width is provided, the height is
133
+ # determined by maintaining the aspect ratio.
134
+ # embed_height - An integer value in pixels that specifies the height of the player. The
135
+ # embed code height may be larger that this to account for player controls depending on
136
+ # the player you are using. The default height is 360.
137
+ #
138
+ # ==== Parameters
139
+ #
140
+ # options<Hash>:: A hash of optional attributes.
141
+ #
142
+ # ==== Returns
143
+ #
144
+ # ::Episodic::Platform::PlaylistsResponse:: The parsed response.
145
+ #
146
+ def playlists options = {}
147
+
148
+ # Clone the options into our params hash
149
+ params = options.clone
150
+
151
+ # Make the request
152
+ response = connection.do_get(construct_url("query", "playlists"), params)
153
+
154
+ # Convert to a hash
155
+ return parse_playlists_response(response)
156
+ end
157
+
158
+ #
159
+ # Queries for shows in your network. The options parameter allows you to limit
160
+ # your results. Acceptable options are:
161
+ # id - A single id or an Array of episode ids. If this param is not provided then
162
+ # all shows in the your network or specified shows are queried.
163
+ # sort_by - The sort_by parameter is optional and specifies a field to sort the results
164
+ # by. The value must be one of "updated_at", "created_at" or "name". The
165
+ # default is "created_at".
166
+ # sort_dir - The sort_dir parameter is optional and specifies the sort direction. The
167
+ # value must be one of "asc" or "desc". The default is "asc".
168
+ # page - A value that must be an integer indicating the page number to return the results
169
+ # for. The default is 1.
170
+ # per_page - A value that must be an integer indicating the number of items per page. The
171
+ # default is 20. NOTE: The smaller this value is the better your response times will be.
172
+ #
173
+ # ==== Parameters
174
+ #
175
+ # options<Hash>:: A hash of optional attributes.
176
+ #
177
+ # ==== Returns
178
+ #
179
+ # ::Episodic::Platform::ShowsResponse:: The parsed response.
180
+ #
181
+ def shows options = {}
182
+
183
+ # Clone the options into our params hash
184
+ params = options.clone
185
+
186
+ # Make the request
187
+ response = connection.do_get(construct_url("query", "shows"), params)
188
+
189
+ # Convert to a hash
190
+ return parse_shows_response(response)
191
+ end
192
+
193
+ protected
194
+
195
+ #
196
+ # Method factored out to make unit testing easier. This method simply creates the <tt>::Episodic::Platform::EpisodesResponse</tt>
197
+ # object.
198
+ #
199
+ # ==== Parameters
200
+ #
201
+ # response<Episodic::Platform::HTTPResponse>:: The response from an episodes request
202
+ #
203
+ # ==== Returns
204
+ #
205
+ # ::Episodic::Platform::EpisodesResponse:: The parsed response.
206
+ #
207
+ def parse_episodes_response response
208
+ return ::Episodic::Platform::EpisodesResponse.new(response, {"ForceArray" => ["episode", "thumbnail", "player", "download", "field", "playlist"]})
209
+ end
210
+
211
+ #
212
+ # Method factored out to make unit testing easier. This method simply creates the <tt>::Episodic::Platform::ShowsResponse</tt>
213
+ # object.
214
+ #
215
+ # ==== Parameters
216
+ #
217
+ # response<Episodic::Platform::HTTPResponse>:: The response from a shows request
218
+ #
219
+ # ==== Returns
220
+ #
221
+ # ::Episodic::Platform::EpisodesResponse:: The parsed response.
222
+ #
223
+ def parse_shows_response response
224
+ return ::Episodic::Platform::ShowsResponse.new(response, {"ForceArray" => ["show", "thumbnail", "player"]})
225
+ end
226
+
227
+ #
228
+ # Method factored out to make unit testing easier. This method simply creates the <tt>::Episodic::Platform::PlaylistsResponse</tt>
229
+ # object.
230
+ #
231
+ # ==== Parameters
232
+ #
233
+ # response<Episodic::Platform::HTTPResponse>:: The response from a playlists request
234
+ #
235
+ # ==== Returns
236
+ #
237
+ # ::Episodic::Platform::EpisodesResponse:: The parsed response.
238
+ #
239
+ def parse_playlists_response response
240
+ return ::Episodic::Platform::PlaylistsResponse.new(response, {"ForceArray" => ["playlist", "thumbnail", "player", "field", "episode"]})
241
+ end
242
+
243
+ end
244
+ end
245
+
246
+ #
247
+ # Extends <tt>Episodic::Platform::CollectionResponse</tt> to handle a collection of shows in the response.
248
+ #
249
+ class ShowsResponse < CollectionResponse
250
+
251
+ #
252
+ # Get the list of shows from the response.
253
+ #
254
+ # ==== Returns
255
+ #
256
+ # Array:: An array of <tt>Episodic::Platform::ShowItem</tt> objects.
257
+ #
258
+ def shows
259
+ @show_items ||= @parsed_body["show"].collect {|e| ShowItem.new(e)}
260
+ return @show_items
261
+ end
262
+
263
+ end
264
+
265
+ #
266
+ # Extends <tt>Episodic::Platform::CollectionResponse</tt> to handle a collection of episodes in the response.
267
+ #
268
+ class EpisodesResponse < CollectionResponse
269
+
270
+ #
271
+ # Get the list of episodes from the response.
272
+ #
273
+ # ==== Returns
274
+ #
275
+ # Array:: An array of <tt>Episodic::Platform::EpisodeItem</tt> objects.
276
+ #
277
+ def episodes
278
+ @episode_items ||= @parsed_body["episode"].collect {|e| EpisodeItem.new(e)}
279
+ return @episode_items
280
+ end
281
+
282
+ end
283
+
284
+ #
285
+ # Extends <tt>Episodic::Platform::CollectionResponse</tt> to handle a collection of playlists in the response.
286
+ #
287
+ class PlaylistsResponse < CollectionResponse
288
+
289
+ #
290
+ # Get the list of playlists from the response.
291
+ #
292
+ # ==== Returns
293
+ #
294
+ # Array:: An array of <tt>Episodic::Platform::EpisodeItem</tt> objects.
295
+ #
296
+ def playlists
297
+ @playlist_items ||= @parsed_body["playlist"].collect {|e| PlaylistItem.new(e)}
298
+ return @playlist_items
299
+ end
300
+
301
+ end
302
+
303
+ #
304
+ # Base class for parsed items from a query response.
305
+ #
306
+ class Item
307
+
308
+ #
309
+ # Constructor
310
+ #
311
+ # ==== Parameters
312
+ #
313
+ # item<Hash>:: The parsed item in the response. This may be a show, episode or playlist item.
314
+ #
315
+ def initialize(item)
316
+ super()
317
+ @item = item
318
+ end
319
+
320
+ #
321
+ # Explcitly declare to avoid <tt>warning: Object#id will be deprecated; use Object#object_id</tt>.
322
+ #
323
+ # ==== Parameters
324
+ #
325
+ # String:: The id of the item.
326
+ #
327
+ def id
328
+ return @item["id"]
329
+ end
330
+
331
+ #
332
+ # When requesting specific items in a query it may be the case that the item specified could not
333
+ # be found. In this case the XML returned looks something like the following for the item:
334
+ #
335
+ # <id>adfadsfasdf</id>
336
+ # <error>
337
+ # <code>6</code>
338
+ # <message>Show not found</message>
339
+ # </error>
340
+ #
341
+ # Therefore, this method allows the caller to check if the item actually exists before trying to pull
342
+ # out other properties that will result in an exception. You really only need to use this method when
343
+ # you make a query request with IDs specified.
344
+ #
345
+ # ==== Returns
346
+ #
347
+ # Boolean:: <tt>true</tt> if the item was found and requests for other attributes will succeed.
348
+ #
349
+ def exists?
350
+ return @item["error"].nil?
351
+ end
352
+
353
+ #
354
+ # Gets the list of thumbnails for this item.
355
+ #
356
+ # ==== Returns
357
+ #
358
+ # Array:: An array of <tt>Episodic::Platform::ThumbnailItem</tt> objects.
359
+ #
360
+ def thumbnails
361
+ @thumbnails ||= nested_items("thumbnails", "thumbnail", ThumbnailItem)
362
+ return @thumbnails
363
+ end
364
+
365
+ #
366
+ # Gets the list of players for this item.
367
+ #
368
+ # ==== Returns
369
+ #
370
+ # Array:: An array of <tt>Episodic::Platform::PlayerItem</tt> objects.
371
+ #
372
+ def players
373
+ @players ||= nested_items("players", "player", PlayerItem)
374
+ return @players
375
+ end
376
+
377
+ #
378
+ # Overridden to pull properties from the item.
379
+ #
380
+ def method_missing(method_sym, *arguments, &block)
381
+ method_name = method_sym.to_s
382
+
383
+ value = @item[method_name]
384
+
385
+ # Dates are always in UTC
386
+ if (value && date_fields.include?(method_sym))
387
+ return value.empty? ? nil : Time.parse("#{value} +0000")
388
+ elsif (value && boolean_fields.include?(method_sym))
389
+ return @item[method_sym.to_s] == "true"
390
+ elsif (value && integer_fields.include?(method_sym))
391
+ return value.empty? ? nil : value.to_i
392
+ end
393
+
394
+ return value && value.empty? ? nil : value
395
+ end
396
+
397
+ #
398
+ # Always return <tt>true</tt>.
399
+ #
400
+ def respond_to?(symbol, include_private = false)
401
+ return true
402
+ end
403
+
404
+ protected
405
+
406
+ #
407
+ # Helper method to pull out nested items.
408
+ #
409
+ # ==== Parameters
410
+ #
411
+ # group_name<String>:: This is something like "episodes".
412
+ # element_name<String>:: This is something like "episode".
413
+ # clazz<Class>:: This is the class of the item to create (i.e. EpisodeItem)
414
+ #
415
+ # ==== Returns
416
+ #
417
+ # Array:: An array of items of type <tt>clazz</tt>
418
+ #
419
+ def nested_items group_name, element_name, clazz
420
+ if (@item[group_name] && @item[group_name][element_name])
421
+ return @item[group_name][element_name].collect {|v| clazz.new(v)}
422
+ else
423
+ return []
424
+ end
425
+ end
426
+
427
+ #
428
+ # Should be overridden by subclasses to provide a list of fields that should
429
+ # be converted to a <tt>Time</tt> object.
430
+ #
431
+ # ==== Returns
432
+ #
433
+ # Array:: A list of field names as symbols.
434
+ #
435
+ def date_fields
436
+ return []
437
+ end
438
+
439
+ #
440
+ # Should be overridden by subclasses to provide a list of fields that should
441
+ # be converted to a <tt>Boolean</tt> object.
442
+ #
443
+ # ==== Returns
444
+ #
445
+ # Array:: A list of field names as symbols.
446
+ #
447
+ def boolean_fields
448
+ return []
449
+ end
450
+
451
+ #
452
+ # Should be overridden by subclasses to provide a list of fields that should
453
+ # be converted to a <tt>Integer</tt> object.
454
+ #
455
+ # ==== Returns
456
+ #
457
+ # Array:: A list of field names as symbols.
458
+ #
459
+ def integer_fields
460
+ return []
461
+ end
462
+ end
463
+
464
+ #
465
+ # Represents a show from a list of shows returned from a call to <tt>Episodic::Platform::QueryMethods.shows</tt>.
466
+ #
467
+ class ShowItem < Item
468
+ end
469
+
470
+ #
471
+ # Represents a episode from a list of episodes returned from a call to <tt>Episodic::Platform::QueryMethods.episodes</tt>.
472
+ #
473
+ class EpisodeItem < Item
474
+
475
+ #
476
+ # Gets the list of downloads for this item.
477
+ #
478
+ # ==== Returns
479
+ #
480
+ # Array:: An array of <tt>Episodic::Platform::DownloadItem</tt> objects.
481
+ #
482
+ def downloads
483
+ @downloads ||= nested_items("downloads", "download", DownloadItem)
484
+ return @downloads
485
+ end
486
+
487
+ #
488
+ # Gets the list of custom fields for this item.
489
+ #
490
+ # ==== Returns
491
+ #
492
+ # Array:: An array of <tt>Episodic::Platform::CustomItem</tt> objects.
493
+ #
494
+ def custom_fields
495
+ @custom_fields ||= nested_items("custom_fields", "field", CustomFieldItem)
496
+ return @custom_fields
497
+ end
498
+
499
+ #
500
+ # Gets the list of playlists for this item.
501
+ #
502
+ # ==== Returns
503
+ #
504
+ # Array:: An array of <tt>Episodic::Platform::EpisodePlaylistItem</tt> objects.
505
+ #
506
+ def playlists
507
+ @playlists ||= nested_items("playlists", "playlist", EpisodePlaylistItem)
508
+ return @playlists
509
+ end
510
+
511
+ #
512
+ # Provides a list of fields that are actually dates.
513
+ #
514
+ # ==== Returns
515
+ #
516
+ # Array:: A list of field names as symbols.
517
+ #
518
+ def date_fields
519
+ return [:air_date, :off_air_date]
520
+ end
521
+
522
+ end
523
+
524
+ #
525
+ # Represents a playlist from a list of playlists returned from a call to <tt>Episodic::Platform::QueryMethods.playlists</tt>.
526
+ #
527
+ class PlaylistItem < Item
528
+
529
+ #
530
+ # Gets the list of custom fields for this item.
531
+ #
532
+ # ==== Returns
533
+ #
534
+ # Array:: An array of <tt>Episodic::Platform::CustomItem</tt> objects.
535
+ #
536
+ def custom_fields
537
+ @custom_fields ||= nested_items("custom_fields", "field", CustomFieldItem)
538
+ return @custom_fields
539
+ end
540
+
541
+ #
542
+ # Gets the list of episodes for this item.
543
+ #
544
+ # ==== Returns
545
+ #
546
+ # Array:: An array of <tt>Episodic::Platform::PlaylistEpisodeItem</tt> objects.
547
+ #
548
+ def episodes
549
+ @episodes ||= nested_items("episodes", "episode", PlaylistEpisodeItem)
550
+ return @episodes
551
+ end
552
+
553
+ #
554
+ # Provides a list of fields that are actually dates.
555
+ #
556
+ # ==== Returns
557
+ #
558
+ # Array:: A list of field names as symbols.
559
+ #
560
+ def date_fields
561
+ return [:created_at]
562
+ end
563
+ end
564
+
565
+ #
566
+ # Represents a thumbnail element in a response.
567
+ #
568
+ class ThumbnailItem < Item
569
+
570
+ #
571
+ # Since the URL is stored in the element content we need to explicitly define
572
+ # this method to get the URL for a thumbnail.
573
+ #
574
+ # ==== Returns
575
+ #
576
+ # String:: The URL to the thumbnail.
577
+ #
578
+ def url
579
+ return @item["content"]
580
+ end
581
+
582
+ end
583
+
584
+ #
585
+ # Represents a player element in a response.
586
+ #
587
+ class PlayerItem < Item
588
+
589
+ #
590
+ # Provides a list of fields that are actually dates.
591
+ #
592
+ # ==== Returns
593
+ #
594
+ # Array:: A list of field names as symbols.
595
+ #
596
+ def boolean_fields
597
+ return [:default]
598
+ end
599
+
600
+ end
601
+
602
+ #
603
+ # Represents a download element in a response.
604
+ #
605
+ class DownloadItem < Item
606
+
607
+ #
608
+ # Get the url for the downloadable file.
609
+ #
610
+ # ==== Returns
611
+ #
612
+ # String:: The URL
613
+ #
614
+ def url
615
+ return @item["url"].first
616
+ end
617
+
618
+ end
619
+
620
+ #
621
+ # Represents a playlist element in an episodes response.
622
+ #
623
+ class EpisodePlaylistItem < Item
624
+
625
+ #
626
+ # Provides a list of fields that are actually integers.
627
+ #
628
+ # ==== Returns
629
+ #
630
+ # Array:: A list of field names as symbols.
631
+ #
632
+ def integer_fields
633
+ return [:position]
634
+ end
635
+
636
+ end
637
+
638
+ #
639
+ # Represents an episode element in a playlist response.
640
+ #
641
+ class PlaylistEpisodeItem < Item
642
+
643
+ #
644
+ # Provides a list of fields that are actually integers.
645
+ #
646
+ # ==== Returns
647
+ #
648
+ # Array:: A list of field names as symbols.
649
+ #
650
+ def integer_fields
651
+ return [:position]
652
+ end
653
+
654
+ end
655
+
656
+ #
657
+ # Represents a custom field element returned from an episodes or playlists request.
658
+ #
659
+ class CustomFieldItem < Item
660
+
661
+ #
662
+ # Get the values for this field. Values are always returned as strings except when
663
+ # the type is <tt>external_select</tt> then it is an array or two element arrays with the
664
+ # external id and external value respectively.
665
+ #
666
+ # ==== Returns
667
+ #
668
+ # Array:: In most cases this will be a single element array.
669
+ #
670
+ def values
671
+
672
+ if (@values.nil?)
673
+ @values = []
674
+ _values = @item["value"]
675
+ unless (_values.is_a?(Array))
676
+ _values = [_values]
677
+ end
678
+ _values.compact.each do |v|
679
+ if (v.is_a?(Hash))
680
+ @values << [v["id"].strip, v["content"].strip]
681
+ else
682
+ @values << v.strip
683
+ end
684
+ end
685
+ end
686
+
687
+ return @values
688
+ end
689
+
690
+ #
691
+ # Explicitly declare to avoid <tt>warning: Object#type is deprecated; use Object#class</tt>.
692
+ #
693
+ def type
694
+ return @item["type"]
695
+ end
696
+
697
+ #
698
+ # Provides a list of fields that are actually integers.
699
+ #
700
+ # ==== Returns
701
+ #
702
+ # Array:: A list of field names as symbols.
703
+ #
704
+ def integer_fields
705
+ return [:position]
706
+ end
707
+
708
+ #
709
+ # Provides a list of fields that are actually dates.
710
+ #
711
+ # ==== Returns
712
+ #
713
+ # Array:: A list of field names as symbols.
714
+ #
715
+ def boolean_fields
716
+ return [:required]
717
+ end
718
+ end
719
+ end
720
+
721
+ end