vast 0.2 → 1.0

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.
@@ -1,11 +1,13 @@
1
1
  = VAST
2
2
 
3
- A library for parsing Digital Video Ad Serving Template (VAST) documents, as outlined by the Interactive Advertising Bureau at
4
- http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast. This library strives to be as true to the
5
- standard as possible, while presenting a Ruby-friendly interface.
3
+ A library for parsing Digital Video Ad Serving Template (VAST) 2.0 XML documents, as outlined by the Interactive Advertising Bureau at
4
+ http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast. VAST outlines a standard document format for communication between digital video players and ad servers, including support for
5
+ multiple forms of creative and tracking support that conforms to the latest IAB standards.
6
6
 
7
- VAST outlines a standard document format for communication between digital video players and ad servers, including support for
8
- multiple forms of creative and tracking support that conforms to the latest IAB standards.
7
+ It's recommended that you review the resources made available for the IAB. Whenever possible the documentation in this library has been
8
+ pulled directly from those resources.
9
+
10
+ This library strives to be as true to the standard as possible, while presenting a Ruby-friendly interface.
9
11
 
10
12
  == Installation
11
13
 
@@ -15,10 +17,16 @@ VAST is available as a RubyGem.
15
17
 
16
18
  == Usage
17
19
 
18
- Parse a VAST document and access it's contents easily. See the documentation for the individual classes for an overview of
19
- what information available for each class.
20
+ Parse a VAST document and access its contents using an easy-to-understand model. For example:
20
21
 
21
22
  document = VAST::Document.parse(File.read("vast_document.xml"))
23
+ inline_ad = document.inline_ads.first
24
+ puts document.linear_creative.mediafile.type
25
+ => "video/x-flv"
26
+ puts document.linear_creative.mediafile.url
27
+ => #<URI::HTTP:0x1015ad5f0 URL:http://creativeurl.ca/mediafile>
28
+
29
+ See the documentation for the individual classes for an overview of what information available for each class.
22
30
 
23
31
  == Documentation
24
32
 
@@ -1,10 +1,14 @@
1
1
  require 'vast/document'
2
+ require 'vast/element'
2
3
  require 'vast/ad'
3
4
  require 'vast/inline_ad'
5
+ require 'vast/wrapper_ad'
4
6
  require 'vast/creative'
5
7
  require 'vast/linear_creative'
6
8
  require 'vast/mediafile'
7
9
  require 'vast/companion_creative'
10
+ require 'vast/non_linear_creative'
11
+ require 'vast/extension'
8
12
 
9
13
  # This module wraps VAST documents, as outlined by the IAB at http://www.iab.net/media/file/VAST-2_0-FINAL.pdf
10
14
  module VAST
@@ -1,10 +1,21 @@
1
1
  module VAST
2
- class Ad
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ # Contains some combination of video, companions, and non-linear units for a single advertiser.
3
+ #
4
+ # A single VAST response may include multiple Ads from multiple advertisers. It will be up to
5
+ # the Video Player to determine the order, timing, placement, etc for the multiple ads. However,
6
+ # the player should generally respect the sequential order of the Ad elements within a VAST response.
7
+ #
8
+ # The VAST response does not contain information on the placement or timing of each ad. It is up
9
+ # to the Video Player to determine the optimal inclusion points of the ads.
10
+ #
11
+ # Can either be of type InlineAd, meaning it contains all the elements necessary to display the
12
+ # visual experience, or of type WrapperAd, which points to a downstream VAST document that must be
13
+ # requested from another server.
14
+ #
15
+ # An Ad may include one or more pieces of creative that are part of a single execution. For example, an Ad
16
+ # may include a linear video element with a set of companion banners; this would be reflected by two Creative
17
+ # elements, one LinearCreative and one CompanionCreative.
18
+ class Ad < Element
8
19
 
9
20
  # Create proper ad type
10
21
  def self.create(node)
@@ -19,12 +30,12 @@ module VAST
19
30
 
20
31
  # Ad id, if indicated
21
32
  def id
22
- @source_node[:id]
33
+ source_node[:id]
23
34
  end
24
35
 
25
36
  # Name of source ad server
26
37
  def ad_system
27
- ad_system_node = @source_node.at("AdSystem")
38
+ ad_system_node = source_node.at("AdSystem")
28
39
  if ad_system_node
29
40
  ad_system_node.content
30
41
  else
@@ -34,45 +45,55 @@ module VAST
34
45
 
35
46
  # URI to request if ad does not play due to error
36
47
  def error_url
37
- error_url_node = @source_node.at("Error")
48
+ error_url_node = source_node.at("Error")
38
49
  URI.parse(error_url_node.content) if error_url_node
39
50
  end
40
51
 
41
52
  # Returns an array containing all linear creatives
42
53
  def linear_creatives
43
- @source_node.xpath('.//Creative/Linear').to_a.collect do |node|
54
+ source_node.xpath('.//Creative/Linear').to_a.collect do |node|
44
55
  LinearCreative.new(node)
45
56
  end
46
57
  end
47
58
 
59
+ # It's common for an ad to contain only one piece of linear creative. This is a
60
+ # convenience method for when only the first piece of linear creative is needed.
61
+ def linear_creative
62
+ linear_creatives.first
63
+ end
64
+
48
65
  # Returns an array containing all non linear creatives
49
66
  def non_linear_creatives
50
- @source_node.xpath('.//Creative/NonLinearAds/NonLinear').to_a.collect do |node|
67
+ source_node.xpath('.//Creative/NonLinearAds/NonLinear').to_a.collect do |node|
51
68
  NonLinearCreative.new(node)
52
69
  end
53
70
  end
54
71
 
55
72
  # Returns an array containing all companion creatives
56
73
  def companion_creatives
57
- @source_node.xpath('.//Creative/CompanionAds/Companion').to_a.collect do |node|
74
+ source_node.xpath('.//Creative/CompanionAds/Companion').to_a.collect do |node|
58
75
  CompanionCreative.new(node)
59
76
  end
60
77
  end
61
78
 
62
- # Each Ad should contain at least one impression.
79
+ # Each Ad must contain at least one impression.
63
80
  def impression
64
- URI.parse(@source_node.at('Impression').content)
81
+ URI.parse(source_node.at('Impression').content)
65
82
  end
66
83
 
67
84
  # Array of all impressions available for this ad, excluding those specific
68
85
  # to a particular creative.
69
86
  def impressions
70
- @source_node.xpath('.//Impression').to_a.collect do |node|
87
+ source_node.xpath('.//Impression').to_a.collect do |node|
71
88
  URI.parse(node)
72
89
  end
73
90
  end
74
91
 
92
+ # Extensions included in the
93
+ def extensions
94
+ source_node.xpath('.//Extension').to_a.collect do |node|
95
+ Extension.new(node)
96
+ end
97
+ end
75
98
  end
76
-
77
- class WrapperAd < Ad; end
78
99
  end
@@ -1,48 +1,55 @@
1
1
  module VAST
2
+ # Commonly text, display ads, rich media, or skins that wrap around the video experience. These ads come
3
+ # in a number of sizes and shapes and typically run alongside or surrounding the video player.
2
4
  class CompanionCreative < Creative
3
5
 
4
6
  def id
5
- @source_node[:id]
7
+ source_node[:id]
6
8
  end
7
9
 
8
10
  # Width in pixels of companion
9
11
  def width
10
- @source_node[:width].to_i
12
+ source_node[:width].to_i
11
13
  end
12
14
 
13
15
  # Height in pixels of companion
14
16
  def height
15
- @source_node[:height].to_i
17
+ source_node[:height].to_i
16
18
  end
17
19
 
18
20
  # Width in pixels of expanding companion ad when in expanded state
19
21
  def expanded_width
20
- @source_node[:expandedWidth].to_i
22
+ source_node[:expandedWidth].to_i
21
23
  end
22
24
 
23
25
  # Height in pixels of expanding companion ad when in expanded state
24
26
  def expanded_height
25
- @source_node[:expandedHeight].to_i
27
+ source_node[:expandedHeight].to_i
28
+ end
29
+
30
+ # Defines the method to use for communication with the companion
31
+ def api_framework
32
+ source_node[:apiFramework]
26
33
  end
27
34
 
28
35
  # URI to open as destination page when user clicks on the video
29
36
  def click_through_url
30
- URI.parse @source_node.at('CompanionClickThrough').content
37
+ URI.parse source_node.at('CompanionClickThrough').content
31
38
  end
32
39
 
33
40
  # Alternate text to be displayed when companion is rendered in HTML environment.
34
41
  def alt_text
35
- node = @source_node.at('AltText')
42
+ node = source_node.at('AltText')
36
43
  node.nil? ? nil : node.content
37
44
  end
38
45
 
39
46
  # Type of companion resource, returned as a symbol. Either :static, :iframe, or :html.
40
47
  def resource_type
41
- if @source_node.at('StaticResource')
48
+ if source_node.at('StaticResource')
42
49
  :static
43
- elsif @source_node.at('IFrameResource')
50
+ elsif source_node.at('IFrameResource')
44
51
  :iframe
45
- elsif @source_node.at('HTMLResource')
52
+ elsif source_node.at('HTMLResource')
46
53
  :html
47
54
  end
48
55
  end
@@ -50,7 +57,7 @@ module VAST
50
57
  # Returns MIME type of static creative
51
58
  def creative_type
52
59
  if resource_type == :static
53
- @source_node.at('StaticResource')[:creativeType]
60
+ source_node.at('StaticResource')[:creativeType]
54
61
  end
55
62
  end
56
63
 
@@ -58,16 +65,16 @@ module VAST
58
65
  def resource_url
59
66
  case resource_type
60
67
  when :static
61
- URI.parse @source_node.at('StaticResource').content
68
+ URI.parse source_node.at('StaticResource').content
62
69
  when :iframe
63
- URI.parse @source_node.at('IFrameResource').content
70
+ URI.parse source_node.at('IFrameResource').content
64
71
  end
65
72
  end
66
73
 
67
74
  # Returns HTML text for html resource
68
75
  def resource_html
69
76
  if resource_type == :html
70
- @source_node.at('HTMLResource').content
77
+ source_node.at('HTMLResource').content
71
78
  end
72
79
  end
73
80
  end
@@ -1,13 +1,14 @@
1
1
  module VAST
2
- class Creative
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ # Contains the information related to a piece of creative.
3
+ #
4
+ # === Sequence
5
+ # The Creative element takes an optional “sequence” attribute that indicates the suggested order in which the
6
+ # Creatives should be displayed. If two Creative elements are intended to be shown at the same time they should
7
+ # share the same sequence number.
8
+ class Creative < Element
8
9
 
9
10
  def ad
10
- Ad.create @source_node.ancestors('Ad').first
11
+ Ad.create source_node.ancestors('Ad').first
11
12
  end
12
13
 
13
14
  def id
@@ -25,14 +26,19 @@ module VAST
25
26
 
26
27
  # Data to be passed into the video ad.
27
28
  def ad_parameters
28
- @source_node.at('AdParameters').content
29
+ source_node.at('AdParameters').content
29
30
  end
30
31
 
32
+ # Returns a hash, keyed by event name, containing an array of URIs to be called for each event.
31
33
  def tracking_urls
32
34
  tracking_urls = {}
33
- @source_node.xpath('.//Tracking').to_a.collect do |node|
35
+ source_node.xpath('.//Tracking').to_a.collect do |node|
34
36
  underscored_name = underscore(node[:event])
35
- tracking_urls[underscored_name.to_sym] = URI.parse(node.content)
37
+ if tracking_urls[underscored_name.to_sym]
38
+ tracking_urls[underscored_name.to_sym] << URI.parse(node.content)
39
+ else
40
+ tracking_urls[underscored_name.to_sym] = [URI.parse(node.content)]
41
+ end
36
42
  end
37
43
  tracking_urls
38
44
  end
@@ -50,9 +56,7 @@ module VAST
50
56
  private
51
57
 
52
58
  def creative_node
53
- @source_node.ancestors('Creative').first
59
+ source_node.ancestors('Creative').first
54
60
  end
55
61
  end
56
-
57
- class NonLinearCreative < Creative; end
58
62
  end
@@ -20,7 +20,8 @@ module VAST
20
20
  xsd.valid?(self)
21
21
  end
22
22
 
23
- # All ads in the document
23
+ # All ads in the document If no ads of any type are available, it should ould be indicated
24
+ # by the absence of any Ads.
24
25
  def ads
25
26
  self.root.xpath('.//Ad').to_a.collect do |node|
26
27
  Ad.create(node)
@@ -0,0 +1,9 @@
1
+ module VAST
2
+ class Element
3
+ attr_reader :source_node
4
+
5
+ def initialize(node)
6
+ @source_node = node
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module VAST
2
+ class Extension < Element
3
+
4
+ # Extension type
5
+ def type
6
+ source_node[:type]
7
+ end
8
+
9
+ # Access to the XML contents of this extension, as a Nokogiri::XML::Node
10
+ # http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Node.html. Alias of
11
+ # Extension#source_node
12
+ def xml
13
+ source_node
14
+ end
15
+ end
16
+ end
@@ -1,15 +1,17 @@
1
1
  module VAST
2
+ # Contains all the information necessary to display the visual experience of one complete ad.
2
3
  class InlineAd < Ad
3
4
 
4
5
  # URI of request to survey vendor
5
6
  def survey_url
6
- URI.parse @source_node.at('Survey').content
7
+ URI.parse source_node.at('Survey').content
7
8
  end
8
9
 
9
10
  # Common name of ad
10
11
  def ad_title
11
- @source_node.at('AdTitle').content
12
+ source_node.at('AdTitle').content
12
13
  end
14
+
13
15
  end
14
16
  end
15
17
 
@@ -1,19 +1,21 @@
1
1
  module VAST
2
+ # LinearCreative is presented before, in the middle of, or after the video content is consumed by the user,
3
+ # in very much the same way a TV commercial can play before, during or after the chosen program.
2
4
  class LinearCreative < Creative
3
5
 
4
6
  # Duration of creative
5
7
  def duration
6
- @source_node.at('Duration').content
8
+ source_node.at('Duration').content
7
9
  end
8
10
 
9
11
  # URI to open as destination page when user clicks on the video
10
12
  def click_through_url
11
- URI.parse @source_node.at('ClickThrough').content
13
+ URI.parse source_node.at('ClickThrough').content
12
14
  end
13
15
 
14
16
  # An array of URIs to request for tracking purposes when user clicks on the video
15
17
  def click_tracking_urls
16
- @source_node.xpath('.//ClickTracking').to_a.collect do |node|
18
+ source_node.xpath('.//ClickTracking').to_a.collect do |node|
17
19
  URI.parse node.content
18
20
  end
19
21
  end
@@ -23,7 +25,7 @@ module VAST
23
25
  # used as the key for this hash
24
26
  def custom_click_urls
25
27
  custom_click_urls = {}
26
- @source_node.xpath('.//CustomClick').to_a.collect do |node|
28
+ source_node.xpath('.//CustomClick').to_a.collect do |node|
27
29
  key = underscore(node[:id]).to_sym
28
30
  custom_click_urls[key] = URI.parse(node.content)
29
31
  end
@@ -31,7 +33,7 @@ module VAST
31
33
  end
32
34
 
33
35
  def mediafiles
34
- @source_node.xpath('.//MediaFile').to_a.collect do |node|
36
+ source_node.xpath('.//MediaFile').to_a.collect do |node|
35
37
  Mediafile.new(node)
36
38
  end
37
39
  end
@@ -1,54 +1,54 @@
1
1
  module VAST
2
- class Mediafile
3
- attr_reader :source_node
4
-
5
- def initialize(node)
6
- @source_node = node
7
- end
2
+ class Mediafile < Element
8
3
 
9
4
  # Location of linear file
10
5
  def url
11
- URI.parse @source_node.content
6
+ URI.parse source_node.content
12
7
  end
13
8
 
14
9
  def id
15
- @source_node[:id]
10
+ source_node[:id]
16
11
  end
17
12
 
18
13
  # Method of delivery of ad, either "streaming" or "progressive"
19
14
  def delivery
20
- @source_node[:delivery]
15
+ source_node[:delivery]
21
16
  end
22
17
 
23
18
  # MIME type. Popular MIME types include, but are not limited to “video/x-ms-wmv” for
24
19
  # Windows Media, and “video/x-flv” for Flash Video.
25
20
  def type
26
- @source_node[:type]
21
+ source_node[:type]
27
22
  end
28
23
 
29
24
  # Bitrate of encoded video in Kbps
30
25
  def bitrate
31
- @source_node[:bitrate].to_i
26
+ source_node[:bitrate].to_i
32
27
  end
33
28
 
34
29
  # Pixel dimensions of video width
35
30
  def width
36
- @source_node[:width].to_i
31
+ source_node[:width].to_i
37
32
  end
38
33
 
39
34
  # Pixel dimensions of video height
40
35
  def height
41
- @source_node[:height].to_i
36
+ source_node[:height].to_i
37
+ end
38
+
39
+ # Defines the method to use for communication with the companion
40
+ def api_framework
41
+ source_node[:apiFramework]
42
42
  end
43
43
 
44
- # Whether it is acceptable to scale the image.
44
+ # Whether it is acceptable to scale the mediafile.
45
45
  def scalable?
46
- @source_node[:scalable]=="true"
46
+ source_node[:scalable]=="true"
47
47
  end
48
48
 
49
- # Whether the ad must have its aspect ratio maintained when scaled
49
+ # Whether the mediafile must have its aspect ratio maintained when scaled
50
50
  def maintain_aspect_ratio?
51
- @source_node[:maintainAspectRatio]=="true"
51
+ source_node[:maintainAspectRatio]=="true"
52
52
  end
53
53
  end
54
54
  end
@@ -0,0 +1,93 @@
1
+ module VAST
2
+ # NonLinearCreative runs concurrently with the video content so the users see the ad while viewing
3
+ # the content. Non-linear video ads can be delivered as text, graphical ads, or as video overlays.
4
+ class NonLinearCreative < Creative
5
+
6
+ def id
7
+ source_node[:id]
8
+ end
9
+
10
+ # Width in pixels
11
+ def width
12
+ source_node[:width].to_i
13
+ end
14
+
15
+ # Height in pixels
16
+ def height
17
+ source_node[:height].to_i
18
+ end
19
+
20
+ # Width in pixels when in expanded state
21
+ def expanded_width
22
+ source_node[:expandedWidth].to_i
23
+ end
24
+
25
+ # Height in pixels when in expanded state
26
+ def expanded_height
27
+ source_node[:expandedHeight].to_i
28
+ end
29
+
30
+ # Defines the method to use for communication with the companion
31
+ def api_framework
32
+ source_node[:apiFramework]
33
+ end
34
+
35
+ # URI to open as destination page when user clicks on creative
36
+ def click_through_url
37
+ URI.parse source_node.at('NonLinearClickThrough').content
38
+ end
39
+
40
+ # Whether it is acceptable to scale the mediafile.
41
+ def scalable?
42
+ source_node[:scalable]=="true"
43
+ end
44
+
45
+ # Whether the mediafile must have its aspect ratio maintained when scaled
46
+ def maintain_aspect_ratio?
47
+ source_node[:maintainAspectRatio]=="true"
48
+ end
49
+
50
+ # Suggested duration to display non-linear ad, typically for animation to complete.
51
+ # Expressed in standard time format hh:mm:ss
52
+ def min_suggested_duration
53
+ source_node[:minSuggestedDuration]
54
+ end
55
+
56
+
57
+ # Type of non-linear resource, returned as a symbol. Either :static, :iframe, or :html.
58
+ def resource_type
59
+ if source_node.at('StaticResource')
60
+ :static
61
+ elsif source_node.at('IFrameResource')
62
+ :iframe
63
+ elsif source_node.at('HTMLResource')
64
+ :html
65
+ end
66
+ end
67
+
68
+ # Returns MIME type of static creative
69
+ def creative_type
70
+ if resource_type == :static
71
+ source_node.at('StaticResource')[:creativeType]
72
+ end
73
+ end
74
+
75
+ # Returns URI for static or iframe resource
76
+ def resource_url
77
+ case resource_type
78
+ when :static
79
+ URI.parse source_node.at('StaticResource').content
80
+ when :iframe
81
+ URI.parse source_node.at('IFrameResource').content
82
+ end
83
+ end
84
+
85
+ # Returns HTML text for html resource
86
+ def resource_html
87
+ if resource_type == :html
88
+ source_node.at('HTMLResource').content
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,19 @@
1
+ module VAST
2
+ # Points to another VAST document on a different server.
3
+ #
4
+ # WrapperAds may include any number of tracking urls to allow CompanionCreatives to be served
5
+ # from an InlineAd response but tracked separately from the Impression. It may also include
6
+ # tracking elements for separately tracking LinearCreative or NonLinearCreative views or events.
7
+ #
8
+ # The server providing the WrapperAd may not know exactly which creative elements are to be
9
+ # delivered downline in inline ads; in that case the WrapperAd should include placeholders for
10
+ # the maximum set of Creatives that could be played within the Video Player.
11
+ class WrapperAd < Ad
12
+
13
+ # URI of ad tag of downstream Secondary Ad Server
14
+ def ad_tag_url
15
+ URI.parse source_node.at('VASTAdTagURI').content
16
+ end
17
+
18
+ end
19
+ end
@@ -60,12 +60,20 @@ class AdTest < Test::Unit::TestCase
60
60
  end
61
61
  end
62
62
 
63
+ def test_ad_should_know_first_linear_creative
64
+ document_file = example_file('document_with_one_inline_ad.xml')
65
+ document = VAST::Document.parse!(document_file)
66
+ ad = document.inline_ads.first
67
+
68
+ assert_equal ad.linear_creative.id, ad.linear_creatives.first.id
69
+ end
70
+
63
71
  def test_ad_should_know_non_linear_creatives
64
72
  document_file = example_file('document_with_one_inline_ad.xml')
65
73
  document = VAST::Document.parse!(document_file)
66
74
  ad = document.inline_ads.first
67
75
 
68
- assert_equal 1, ad.non_linear_creatives.count
76
+ assert_equal 2, ad.non_linear_creatives.count
69
77
  ad.non_linear_creatives.each do |creative|
70
78
  assert creative.kind_of?(VAST::NonLinearCreative)
71
79
  end
@@ -100,4 +108,15 @@ class AdTest < Test::Unit::TestCase
100
108
  assert_equal "http://myTrackingURL/impression", ad.impressions.first.to_s
101
109
  assert_equal "http://myTrackingURL/anotherImpression", ad.impressions.last.to_s
102
110
  end
111
+
112
+ def test_extensions
113
+ document_file = example_file('document_with_one_inline_ad.xml')
114
+ document = VAST::Document.parse!(document_file)
115
+ ad = document.inline_ads.first
116
+
117
+ assert_equal 2, ad.extensions.count
118
+ ad.extensions.each do |extension|
119
+ assert extension.kind_of?(VAST::Extension)
120
+ end
121
+ end
103
122
  end
@@ -14,6 +14,7 @@ class CompanionCreativeTest < Test::Unit::TestCase
14
14
  assert_equal 500, creative.expanded_height
15
15
  assert_equal "http://www.tremormedia.com", creative.click_through_url.to_s
16
16
  assert_equal "Display this instead of the ad", creative.alt_text
17
+ assert_equal "VPAID", creative.api_framework
17
18
  end
18
19
 
19
20
  def test_should_know_static_resource
@@ -27,8 +27,8 @@ class CreativeTest < Test::Unit::TestCase
27
27
  document = VAST::Document.parse!(document_with_creative)
28
28
  creative = document.ads.first.linear_creatives.first
29
29
 
30
- assert_equal "http://myTrackingURL/creativeView", creative.tracking_urls[:creative_view].to_s
31
- assert_equal "http://myTrackingURL/start", creative.tracking_urls[:start].to_s
30
+ assert_equal ["http://myTrackingURL/creativeView"], creative.tracking_urls[:creative_view].collect{ |url| url.to_s }
31
+ assert_equal ["http://myTrackingURL/start1", "http://myTrackingURL/start2"], creative.tracking_urls[:start].collect{ |url| url.to_s }
32
32
  ## There are more tracking urls, refer to spec for complete list
33
33
  end
34
34
 
@@ -18,7 +18,8 @@
18
18
  <TrackingEvents>
19
19
  <Tracking event="creativeView"><![CDATA[http://myTrackingURL/creativeView]]></Tracking>
20
20
 
21
- <Tracking event="start"><![CDATA[http://myTrackingURL/start]]></Tracking>
21
+ <Tracking event="start"><![CDATA[http://myTrackingURL/start1]]></Tracking>
22
+ <Tracking event="start"><![CDATA[http://myTrackingURL/start2]]></Tracking>
22
23
  <Tracking event="midpoint"><![CDATA[http://myTrackingURL/midpoint]]></Tracking>
23
24
  <Tracking event="firstQuartile"><![CDATA[http://myTrackingURL/firstQuartile]]></Tracking>
24
25
  <Tracking event="thirdQuartile"><![CDATA[http://myTrackingURL/thirdQuartile]]></Tracking>
@@ -43,13 +44,13 @@
43
44
  <CustomClick id="customTwo"><![CDATA[http://myTrackingURL/custom2]]></CustomClick>
44
45
  </VideoClicks>
45
46
  <MediaFiles>
46
- <MediaFile id="firstFile" delivery="progressive" type="video/x-flv" bitrate="500" width="400" height="300" scalable="true" maintainAspectRatio="true"><![CDATA[http://cdnp.tremormedia.com/video/acudeo/Carrot_400x300_500kb.flv]]></MediaFile>
47
+ <MediaFile id="firstFile" delivery="progressive" type="video/x-flv" bitrate="500" width="400" height="300" scalable="true" maintainAspectRatio="true" apiFramework="VPAID"><![CDATA[http://cdnp.tremormedia.com/video/acudeo/Carrot_400x300_500kb.flv]]></MediaFile>
47
48
  </MediaFiles>
48
49
  </Linear>
49
50
  </Creative>
50
51
  <Creative AdID="601364-Companion">
51
52
  <CompanionAds>
52
- <Companion id="big_box" width="300" height="250" expandedWidth="600" expandedHeight="500">
53
+ <Companion id="big_box" width="300" height="250" expandedWidth="600" expandedHeight="500" apiFramework="VPAID">
53
54
  <StaticResource creativeType="image/jpeg">http://demo.tremormedia.com/proddev/vast/Blistex1.jpg</StaticResource>
54
55
  <TrackingEvents>
55
56
  <Tracking event="creativeView">http://myTrackingURL/firstCompanionCreativeView</Tracking>
@@ -65,13 +66,31 @@
65
66
  </Creative>
66
67
  <Creative AdID="601365">
67
68
  <NonLinearAds>
68
- <NonLinear width="300" height="50">
69
+ <NonLinear id="special_overlay" width="300" height="50" expandedWidth="600" expandedHeight="500" apiFramework="VPAID" scalable="true" maintainAspectRatio="true">
69
70
  <StaticResource creativeType="image/jpeg"><![CDATA[http://cdn.liverail.com/adasset/228/330/overlay.jpg]]></StaticResource>
70
- <NonLinearClickThrough><![CDATA[http://t3.liverail.com/?metric=clickthru&pos=1&pid=1331&coid=135&nid=0&cid=330&kid=228&vid=&amid=&cc=default&pp=&url=&cb=9185&x=&y=&xy=&redirect=http%3A%2F%2Fliverail.com%2F]]></NonLinearClickThrough>
71
- </NonLinear>
71
+ <NonLinearClickThrough><![CDATA[http://t3.liverail.com]]></NonLinearClickThrough>
72
+ </NonLinear>
73
+ <NonLinear width="728" height="90">
74
+ <IFrameResource><![CDATA[http://ad3.liverail.com/util/non_linear.php]]></IFrameResource>
75
+ <NonLinearClickThrough>http://www.tremormedia.com</NonLinearClickThrough>
76
+ </NonLinear>
72
77
  </NonLinearAds>
73
78
  </Creative>
74
79
  </Creatives>
80
+ <Extensions>
81
+ <Extension type="DART">
82
+ <AdServingData>
83
+ <DeliveryData>
84
+ <GeoData><![CDATA[ct=CA&st=ON&ac=905&zp=L6V1X9&bw=0&dma=1&city=1869]]></GeoData>
85
+ </DeliveryData>
86
+ </AdServingData>
87
+ </Extension>
88
+ <Extension type="value">
89
+ <CostPerThousand currency="CAD">
90
+ 125.00
91
+ </CostPerThousand>
92
+ </Extension>
93
+ </Extensions>
75
94
  </InLine>
76
95
  </Ad>
77
96
 
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class ExtensionTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_attributes
6
+ document_file = example_file('document_with_one_inline_ad.xml')
7
+ document = VAST::Document.parse!(document_file)
8
+ extension = VAST::Extension.new(document.at('Extension'))
9
+
10
+ assert_equal "DART", extension.type
11
+ end
12
+
13
+ def test_should_know_attributes
14
+ document_file = example_file('document_with_one_inline_ad.xml')
15
+ document = VAST::Document.parse!(document_file)
16
+ extension = VAST::Extension.new(document.at('Extension'))
17
+
18
+ assert_equal extension.source_node, extension.xml
19
+ end
20
+ end
@@ -13,6 +13,7 @@ class MediafileTest < Test::Unit::TestCase
13
13
  assert_equal 400, mediafile.width
14
14
  assert_equal 300, mediafile.height
15
15
  assert_equal 500, mediafile.bitrate
16
+ assert_equal "VPAID", mediafile.api_framework
16
17
  assert mediafile.scalable?
17
18
  assert mediafile.maintain_aspect_ratio?
18
19
  end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ class NonLinearCreativeTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_attributes
6
+ document_file = example_file('document_with_one_inline_ad.xml')
7
+ document = VAST::Document.parse!(document_file)
8
+ creative = document.inline_ads.first.non_linear_creatives.first
9
+
10
+ assert_equal "special_overlay", creative.id
11
+ assert_equal 300, creative.width
12
+ assert_equal 50, creative.height
13
+ assert_equal 600, creative.expanded_width
14
+ assert_equal 500, creative.expanded_height
15
+ assert_equal "http://t3.liverail.com", creative.click_through_url.to_s
16
+ assert_equal "VPAID", creative.api_framework
17
+ assert creative.scalable?
18
+ assert creative.maintain_aspect_ratio?
19
+ end
20
+
21
+ def test_should_know_static_resource
22
+ document_file = example_file('document_with_one_inline_ad.xml')
23
+ document = VAST::Document.parse!(document_file)
24
+ creative_with_static_resource = document.inline_ads.first.non_linear_creatives.first
25
+
26
+ assert_equal :static, creative_with_static_resource.resource_type
27
+ assert_equal "image/jpeg", creative_with_static_resource.creative_type
28
+ assert_equal "http://cdn.liverail.com/adasset/228/330/overlay.jpg", creative_with_static_resource.resource_url.to_s
29
+ end
30
+
31
+ def test_should_know_iframe_resource
32
+ document_file = example_file('document_with_one_inline_ad.xml')
33
+ document = VAST::Document.parse!(document_file)
34
+ creative_with_iframe_resource = document.inline_ads.first.non_linear_creatives.last
35
+
36
+ assert_equal :iframe, creative_with_iframe_resource.resource_type
37
+ assert_equal "http://ad3.liverail.com/util/non_linear.php", creative_with_iframe_resource.resource_url.to_s
38
+ end
39
+ end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ class WrapperAdTest < Test::Unit::TestCase
4
+
5
+ def test_should_know_ad_tag_url
6
+ document_with_wrapper_ad = example_file('document_with_one_wrapper_ad.xml')
7
+ document = VAST::Document.parse!(document_with_wrapper_ad)
8
+
9
+ ad_node = document.root.xpath('.//Ad').first
10
+ ad = VAST::WrapperAd.new(ad_node)
11
+
12
+ assert ad.ad_tag_url.kind_of?(URI)
13
+ assert_equal "http://demo.tremormedia.com/proddev/vast/vast_inline_linear.xml", ad.ad_tag_url.to_s
14
+ end
15
+
16
+ end
metadata CHANGED
@@ -3,9 +3,9 @@ name: vast
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
+ - 1
6
7
  - 0
7
- - 2
8
- version: "0.2"
8
+ version: "1.0"
9
9
  platform: ruby
10
10
  authors:
11
11
  - Chris Dinn
@@ -46,17 +46,24 @@ files:
46
46
  - lib/vast/companion_creative.rb
47
47
  - lib/vast/creative.rb
48
48
  - lib/vast/document.rb
49
+ - lib/vast/element.rb
50
+ - lib/vast/extension.rb
49
51
  - lib/vast/inline_ad.rb
50
52
  - lib/vast/linear_creative.rb
51
53
  - lib/vast/mediafile.rb
54
+ - lib/vast/non_linear_creative.rb
55
+ - lib/vast/wrapper_ad.rb
52
56
  - test/ad_test.rb
53
57
  - test/companion_creative_test.rb
54
58
  - test/creative_test.rb
55
59
  - test/document_test.rb
60
+ - test/extension_test.rb
56
61
  - test/inline_ad_test.rb
57
62
  - test/linear_creative_test.rb
58
63
  - test/mediafile_test.rb
64
+ - test/non_linear_creative_test.rb
59
65
  - test/test_helper.rb
66
+ - test/wrapper_ad_test.rb
60
67
  - test/examples/document_with_no_ads.xml
61
68
  - test/examples/document_with_one_inline_ad.xml
62
69
  - test/examples/document_with_one_inline_and_one_wrapper_ad.xml
@@ -66,7 +73,6 @@ files:
66
73
  - test/examples/invalid_document_with_missing_ad_type.xml
67
74
  - test/examples/invalid_document_with_missing_creative_type.xml
68
75
  - LICENSE
69
- - README.md
70
76
  - README.rdoc
71
77
  has_rdoc: true
72
78
  homepage: http://github.com/chrisdinn/vast
data/README.md DELETED
@@ -1,45 +0,0 @@
1
- VAST
2
- =====
3
-
4
- A library for parsing Digital Video Ad Serving Template (VAST) documents, as outlined by the Interactive Advertising Bureau at
5
- [http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast]. This library strives to be as true to the
6
- standard as possible, while presenting a Ruby-friendly interface.
7
-
8
- VAST outlines a standard document format for communication between digital video players and ad servers, including support for
9
- multiple forms of creative and tracking support that conforms to the latest IAB standards.
10
-
11
- Installation
12
- ------------
13
-
14
- VAST is available as a RubyGem.
15
-
16
- gem install vast
17
-
18
- Usage
19
- -----
20
-
21
- Parse a VAST document and access it's contents easily. See the documentation for the individual classes for an overview of
22
- what information available for each class.
23
-
24
- document = VAST::Document.parse(File.read("vast_document.xml"))
25
-
26
- Problems/Bugs/Requests
27
- -----------------------------
28
-
29
- Please, file an issue.
30
-
31
- Note on Patches/Pull Requests
32
- -----------------------------
33
-
34
- * Fork the project.
35
- * Make your feature addition or bug fix.
36
- * Add tests for it. This is important so I don't break it in a
37
- future version unintentionally.
38
- * Commit, do not mess with rakefile, version, or history.
39
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
40
- * Send me a pull request. Bonus points for topic branches.
41
-
42
- Copyright
43
- -----------------------------
44
-
45
- © 2010 Chris Dinn. See [LICENSE](http://github.com/chrisdinn/vast/blob/master/LICENSE) for details.