pbcore 0.2.0 → 0.3.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pbcore-2.1.xsd +1902 -0
  3. data/lib/pbcore.rb +17 -0
  4. data/lib/pbcore/annotation.rb +1 -1
  5. data/lib/pbcore/asset_date.rb +1 -1
  6. data/lib/pbcore/asset_type.rb +1 -1
  7. data/lib/pbcore/audience_level.rb +1 -1
  8. data/lib/pbcore/audience_rating.rb +1 -1
  9. data/lib/pbcore/content_element.rb +11 -0
  10. data/lib/pbcore/contributor/contributor.rb +1 -1
  11. data/lib/pbcore/contributor/role.rb +1 -1
  12. data/lib/pbcore/coverage/coverage.rb +1 -1
  13. data/lib/pbcore/creator/creator.rb +1 -1
  14. data/lib/pbcore/creator/role.rb +1 -1
  15. data/lib/pbcore/description.rb +1 -1
  16. data/lib/pbcore/element.rb +17 -61
  17. data/lib/pbcore/extension.rb +11 -2
  18. data/lib/pbcore/extension/embedded.rb +14 -7
  19. data/lib/pbcore/factories.rb +2 -4
  20. data/lib/pbcore/genre.rb +1 -1
  21. data/lib/pbcore/identifier.rb +1 -1
  22. data/lib/pbcore/instantiation.rb +2 -2
  23. data/lib/pbcore/instantiation/alternative_modes.rb +1 -1
  24. data/lib/pbcore/instantiation/annotation.rb +1 -1
  25. data/lib/pbcore/instantiation/channel_configuration.rb +1 -1
  26. data/lib/pbcore/instantiation/colors.rb +1 -1
  27. data/lib/pbcore/instantiation/data_rate.rb +1 -1
  28. data/lib/pbcore/instantiation/date.rb +1 -1
  29. data/lib/pbcore/instantiation/digital.rb +1 -1
  30. data/lib/pbcore/instantiation/dimensions.rb +1 -1
  31. data/lib/pbcore/instantiation/duration.rb +1 -1
  32. data/lib/pbcore/instantiation/essence_track/annotation.rb +1 -1
  33. data/lib/pbcore/instantiation/essence_track/aspect_ratio.rb +1 -1
  34. data/lib/pbcore/instantiation/essence_track/bit_depth.rb +1 -1
  35. data/lib/pbcore/instantiation/essence_track/data_rate.rb +1 -1
  36. data/lib/pbcore/instantiation/essence_track/duration.rb +1 -1
  37. data/lib/pbcore/instantiation/essence_track/encoding.rb +1 -1
  38. data/lib/pbcore/instantiation/essence_track/frame_rate.rb +1 -1
  39. data/lib/pbcore/instantiation/essence_track/frame_size.rb +1 -1
  40. data/lib/pbcore/instantiation/essence_track/identifier.rb +1 -1
  41. data/lib/pbcore/instantiation/essence_track/language.rb +1 -1
  42. data/lib/pbcore/instantiation/essence_track/playback_speed.rb +1 -1
  43. data/lib/pbcore/instantiation/essence_track/sampling_rate.rb +1 -1
  44. data/lib/pbcore/instantiation/essence_track/standard.rb +1 -1
  45. data/lib/pbcore/instantiation/essence_track/time_start.rb +1 -1
  46. data/lib/pbcore/instantiation/essence_track/type.rb +1 -1
  47. data/lib/pbcore/instantiation/extension.rb +16 -7
  48. data/lib/pbcore/instantiation/file_size.rb +1 -1
  49. data/lib/pbcore/instantiation/generations.rb +1 -1
  50. data/lib/pbcore/instantiation/identifier.rb +1 -1
  51. data/lib/pbcore/instantiation/language.rb +1 -1
  52. data/lib/pbcore/instantiation/location.rb +1 -1
  53. data/lib/pbcore/instantiation/media_type.rb +1 -1
  54. data/lib/pbcore/instantiation/physical.rb +1 -1
  55. data/lib/pbcore/instantiation/relation/identifier.rb +1 -1
  56. data/lib/pbcore/instantiation/relation/type.rb +1 -1
  57. data/lib/pbcore/instantiation/rights.rb +0 -1
  58. data/lib/pbcore/instantiation/rights/link.rb +1 -1
  59. data/lib/pbcore/instantiation/rights/summary.rb +1 -1
  60. data/lib/pbcore/instantiation/standard.rb +1 -1
  61. data/lib/pbcore/instantiation/time_start.rb +1 -1
  62. data/lib/pbcore/instantiation/tracks.rb +1 -1
  63. data/lib/pbcore/instantiation_document.rb +2 -2
  64. data/lib/pbcore/publisher/publisher.rb +1 -1
  65. data/lib/pbcore/publisher/role.rb +1 -1
  66. data/lib/pbcore/relation/identifier.rb +1 -1
  67. data/lib/pbcore/relation/type.rb +1 -1
  68. data/lib/pbcore/rights_summary/link.rb +1 -1
  69. data/lib/pbcore/rights_summary/summary.rb +1 -1
  70. data/lib/pbcore/subject.rb +1 -1
  71. data/lib/pbcore/title.rb +1 -1
  72. data/lib/pbcore/version.rb +1 -1
  73. data/lib/pbcore/vocab.rb +6 -0
  74. metadata +5 -4
@@ -2,7 +2,11 @@ require "pbcore/version"
2
2
  require "pbcore/errors"
3
3
 
4
4
  module PBCore
5
+
6
+ GEM_ROOT = File.dirname(File.dirname(__FILE__))
7
+
5
8
  autoload :Element, 'pbcore/element'
9
+ autoload :ContentElement, 'pbcore/content_element'
6
10
  autoload :Attributes, 'pbcore/attributes'
7
11
  autoload :DescriptionDocument, 'pbcore/description_document'
8
12
  autoload :AssetType, 'pbcore/asset_type'
@@ -25,4 +29,17 @@ module PBCore
25
29
  autoload :Instantiation, 'pbcore/instantiation'
26
30
  autoload :InstantiationDocument, 'pbcore/instantiation_document'
27
31
  autoload :Vocab, 'pbcore/vocab'
32
+
33
+ class << self
34
+ def xsd
35
+ File.read(File.join(GEM_ROOT, 'lib', 'pbcore-2.1.xsd'))
36
+ end
37
+
38
+ def validate(xml)
39
+ errors = Nokogiri::XML::Schema(xsd).validate(Nokogiri::XML(xml))
40
+ raise ValidationError, "#{errors.count} errors:\n#{errors.join("\n")}" unless errors.empty?
41
+ end
42
+ end
43
+
44
+ class ValidationError < StandardError; end
28
45
  end
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Annotation < Element
4
+ class Annotation < ContentElement
5
5
  element :pbcoreAnnotation, as: :value
6
6
  attribute :annotationType, as: :type
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class AssetDate < Element
4
+ class AssetDate < ContentElement
5
5
  element :pbcoreAssetDate, as: :value
6
6
  attribute :dateType, as: :type
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class AssetType < Element
4
+ class AssetType < ContentElement
5
5
  element :pbcoreAssetType, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class AudienceLevel < Element
4
+ class AudienceLevel < ContentElement
5
5
  element :pbcoreAudienceLevel, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class AudienceRating < Element
4
+ class AudienceRating < ContentElement
5
5
  element :pbcoreAudienceRating, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -0,0 +1,11 @@
1
+ module PBCore
2
+ class ContentElement < Element
3
+ # Defind attributes common to all PBCore "content elements", which is a term
4
+ # we're using to refer to elements that contain text instead of subelements.
5
+ # In PBCore you can either contain text or subelements, but not both.
6
+ attribute :source
7
+ attribute :ref
8
+ attribute :annotation
9
+ attribute :version
10
+ end
11
+ end
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Contributor::Contributor < Element
4
+ class Contributor::Contributor < ContentElement
5
5
  element :contributor, as: :value
6
6
  attribute :affiliation, as: :affiliation
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Contributor::Role < Element
4
+ class Contributor::Role < ContentElement
5
5
  element :contributorRole, as: :value
6
6
  attribute :portrayal, as: :portrayal
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Coverage::Coverage < Element
4
+ class Coverage::Coverage < ContentElement
5
5
  element :coverage, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Creator::Creator < Element
4
+ class Creator::Creator < ContentElement
5
5
  element :creator, as: :value
6
6
  attribute :affiliation, as: :affiliation
7
7
  attribute :affiliationSource, as: :affiliation_source
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Creator::Role < Element
4
+ class Creator::Role < ContentElement
5
5
  element :creatorRole, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Description < Element
4
+ class Description < ContentElement
5
5
  element :pbcoreDescription, as: :value
6
6
  attribute :descriptionType, as: :type
7
7
  attribute :descriptionTypeRef, as: :type_ref
@@ -8,7 +8,6 @@ module PBCore
8
8
  # TODO: decouple XML building behavior from schema-related declarations.
9
9
  class Element
10
10
  include SAXMachine
11
- include PBCore::Attributes::Common
12
11
 
13
12
  # Defines which accessor is used to get the value within an element.
14
13
  # Here we defined it be simply :value.
@@ -16,15 +15,9 @@ module PBCore
16
15
  val == :no_buffer ? nil : val
17
16
  end
18
17
 
19
- # Defind attributes common to all PBCore elements.
20
- # attribute :source
21
- # attribute :ref
22
- # attribute :annotation
23
- # attribute :version
24
-
25
18
  # Returns a hash of child element instances.
26
19
  def elements(key_by_xml_name: false)
27
- key_value_pairs_array = self.class.element_config_all.map do |name, element_configs|
20
+ key_value_pairs_array = self.class.all_element_config.map do |name, element_configs|
28
21
  # SAXMachine allows you to declare multiple elements with the same name
29
22
  # but we don't do tha with PBCore, so just grab the first and only one.
30
23
  element_config = element_configs.first
@@ -84,43 +77,18 @@ module PBCore
84
77
  @build_block = block
85
78
  end
86
79
 
87
- # Returns true if the element is configured to contain a single instance
88
- # of a child element that matches the name and opts parameters.
89
- def has_one?(name, opts={})
90
- element_config_has_one.any? do |element_config|
91
- opts.all? do |key, val|
92
- # In SAXMachine::SaxConfig::ElementConfig, the :class config option
93
- # maps to instance variable @data_class.
94
- key = :data_class if key == :class
95
- val == element_config.instance_variable_get(:"@#{key}")
96
- end
97
- end
98
- end
99
-
100
- # Returns true if the element is configured to contain many instances of
101
- # a child element that matches the name and opts parameters.
102
- def has_many?(name, opts={})
103
- element_config_has_many.any? do |element_config|
104
- opts.all? do |key, val|
105
- val == element_config.instance_variable_get(:"@#{key}")
106
- end
107
- end
80
+ def attribute_config
81
+ sax_config.top_level_attributes
108
82
  end
109
83
 
110
84
  # Returns true if the element is configured to contain a value.
111
85
  def has_a_value?
112
- !element_config_for_value.nil?
113
- end
114
-
115
- def attribute_config
116
- sax_config.top_level_attributes
86
+ !sax_config.top_level_element_value.nil?
117
87
  end
118
88
 
119
89
  # Returns the SAXMachine::SaxConfig::ElementConfig instances that allow
120
90
  # for a single instance of another element.
121
- # NOTE: We use the "has_one" and "has_many" terminoolgy for child elements
122
- # because it seems to be the most readable option.
123
- def element_config_has_one
91
+ def top_level_element_config
124
92
  sax_config.top_level_elements.reject do |_name, element_configs|
125
93
  element_configs.detect do |element_config|
126
94
  element_config.instance_variable_get(:@as) == :value
@@ -128,33 +96,18 @@ module PBCore
128
96
  end
129
97
  end
130
98
 
131
- # Returns the SAXMachine::SaxConfig::ElementConfig instance for the
132
- # element that represents the value (i.e. text that is one or more
133
- # child elements). This is essentially the inverse of
134
- # element_config_has_one.
135
- def element_config_for_value
136
- sax_config.top_level_elements.detect do |_name, element_configs|
137
- element_configs.detect do |element_config|
138
- element_config.instance_variable_get(:@as) == :value
139
- end
140
- end
141
- end
142
-
143
99
  # Returns the SAXMachine::SaxConfig::ElementConfig that allow for
144
- # multiple instances of other elements.
145
- # NOTE: SAXMachine uses the term "collection" elements, but that's very
146
- # confusing since PBCoreCollection is a thing, so we change it to the
147
- # has_many terminology (and has_one for the singular element config for
148
- # consistency).
149
- def element_config_has_many
100
+ # multiple instances of other elements, i.e. "collection" elements which
101
+ # is not to be confused with <pbcoreCollection>.
102
+ def collection_element_config
150
103
  sax_config.collection_elements.reject do |element_config|
151
104
  element_config.instance_variable_get(:@as) == :value
152
105
  end
153
106
  end
154
107
 
155
- def element_config_all
156
- element_config_has_one.merge(element_config_has_many) do |name, config_has_one, config_has_many|
157
- config_has_many.present? ? config_has_many : config_has_one
108
+ def all_element_config
109
+ top_level_element_config.merge(collection_element_config) do |name, top_level_element_cfg, coll_element_cfg|
110
+ coll_element_cfg.present? ? coll_element_cfg : top_level_element_cfg
158
111
  end
159
112
  end
160
113
 
@@ -173,6 +126,9 @@ module PBCore
173
126
  def has_sax_machine_top_level_element?(name, opts={})
174
127
  Array(sax_config.top_level_elements.fetch(name.to_s, nil)).any? do |element_config|
175
128
  opts.all? do |key, val|
129
+ # This is a quirk of SAXMachine: when you declare a top-level
130
+ # element with the .element class method, it takes your :class
131
+ # option and puts it into an instance var called @data_class.
176
132
  key = :data_class if key == :class
177
133
  val == element_config.instance_variable_get("@#{key}".to_sym)
178
134
  end
@@ -180,9 +136,9 @@ module PBCore
180
136
  end
181
137
 
182
138
  def has_sax_machine_collection_element?(name, opts={})
183
- # NOTE: Accessing collection_element configs with squarey brackets has
184
- # the unwanted side affect of creating an entry in the
185
- # collection_elements, which we don't want. So we use #fetch here
139
+ # NOTE: Accessing #collection_elements with square brackets has the
140
+ # unwanted side affect of creating an entry in the collection_elements,
141
+ # which we don't want. So we use #fetch here
186
142
  Array(sax_config.collection_elements.fetch(name.to_s, nil)).any? do |element_config|
187
143
  opts.all? do |key, val|
188
144
  # This is a quirk of SAXMachine; for some reason it converts the
@@ -11,8 +11,17 @@ module PBCore
11
11
 
12
12
  build_xml do |xml|
13
13
  xml.pbcoreExtension(xml_attributes.compact) do |xml|
14
- wrap.build(xml) if wrap
15
- embedded.build(xml) if embedded
14
+ # <extensionWrap> and <extensionEmbedded> are mutually exclusive. Wrap
15
+ # takes precedence, so if you want to output <extensionEmbedded> make
16
+ # sure #wrap is set to nil.
17
+ # NOTE: Using #embedded will not produce round-trippable XML (i.e. XML
18
+ # that can be reparsed by the pbcore gem models.
19
+ # (See lib/pbcore/extension/embedded.rb)
20
+ if wrap
21
+ wrap.build(xml)
22
+ elsif embedded
23
+ embedded.build(xml)
24
+ end
16
25
  end
17
26
  end
18
27
  end
@@ -1,15 +1,22 @@
1
- # NOTE: This class doesn't actually work like you might expect it to.
2
- # The <extensionEmbedded> element is supposed to contain XML from a different
3
- # (non-PBCore) schema. However, currently the SAXMachine parser will proceed
4
- # to parse the embedded XML rather than capture it and provide an accessor to
5
- # it, which is what we want to happen.
1
+ # NOTE: The <extensionEmbedded> element is supposed to contain XML from a
2
+ # different (non-PBCore) schema. However, due to the declarative nature of
3
+ # SAXMachine parsing, we need to know what we're parsing before we're parsing
4
+ # it, so PBCore::Extension::Embedded cannot be used for parsing arbitrary
5
+ # embedded XML. You can, however, still use the class to set some embedded
6
+ # XML and output it with #to_xml. It just won't be re-parsable using this same
7
+ # class. There might be a fix for this by overriding the .parse class method
8
+ # but there's not enough demand for that work at this time. Until then, our
9
+ # specs just do not include PBCore::Extension::Embedded in our test for
10
+ # round-trippability.
6
11
  require 'pbcore/element'
7
12
 
8
13
  module PBCore
9
- class Extension::Embedded < Element
14
+ class Extension::Embedded < ContentElement
10
15
  element :extensionEmbedded, as: :value
11
16
  build_xml do |xml|
12
- xml.extensionEmbedded(value, xml_attributes.compact)
17
+ xml.extensionEmbedded('', xml_attributes.compact) do |xml|
18
+ xml << value
19
+ end
13
20
  end
14
21
  end
15
22
  end
@@ -1,6 +1,4 @@
1
1
  require 'factory_bot'
2
2
 
3
- GEM_ROOT = File.dirname(File.dirname(File.dirname(__FILE__)))
4
-
5
- require File.join(GEM_ROOT, 'spec', 'support', 'date_time_helpers')
6
- Dir.glob(File.join(GEM_ROOT, 'spec', 'factories', '**', '*.rb')).each { |file| require(file) }
3
+ require File.join(PBCore::GEM_ROOT, 'spec', 'support', 'date_time_helpers.rb')
4
+ Dir.glob(File.join(PBCore::GEM_ROOT, 'spec', 'factories', '**', '*.rb')).each { |file| require(file) }
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Genre < Element
4
+ class Genre < ContentElement
5
5
  element :pbcoreGenre, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Identifier < Element
4
+ class Identifier < ContentElement
5
5
  element :pbcoreIdentifier, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -36,7 +36,7 @@ module PBCore
36
36
  element :instantiationLocation, as: :location, class: PBCore::Instantiation::Location
37
37
  element :instantiationMediaType, as: :media_type, class: PBCore::Instantiation::MediaType
38
38
  elements :instantiationGenerations, as: :generations, class: PBCore::Instantiation::Generations
39
- elements :instantiationTimeStart, as: :time_starts, class: PBCore::Instantiation::TimeStart
39
+ element :instantiationTimeStart, as: :time_start, class: PBCore::Instantiation::TimeStart
40
40
  element :instantiationFileSize, as: :file_size, class: PBCore::Instantiation::FileSize
41
41
  element :instantiationDuration, as: :duration, class: PBCore::Instantiation::Duration
42
42
  element :instantiationDataRate, as: :data_rate, class: PBCore::Instantiation::DataRate
@@ -65,7 +65,7 @@ module PBCore
65
65
  media_type.build(xml) if media_type
66
66
  generations.each { |generations_element| generations_element.build(xml) }
67
67
  file_size.build(xml) if file_size
68
- time_starts.each { |time_start| time_start.build(xml) }
68
+ time_start.build(xml) if time_start
69
69
  duration.build(xml) if duration
70
70
  data_rate.build(xml) if data_rate
71
71
  colors.build(xml) if colors
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::AlternativeModes < Element
4
+ class Instantiation::AlternativeModes < ContentElement
5
5
  element :instantiationAlternativeModes, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::Annotation < Element
4
+ class Instantiation::Annotation < ContentElement
5
5
  element :instantiationAnnotation, as: :value
6
6
  attribute :annotationType, as: :type
7
7
 
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::ChannelConfiguration < Element
4
+ class Instantiation::ChannelConfiguration < ContentElement
5
5
  element :instantiationChannelConfiguration, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::Colors < Element
4
+ class Instantiation::Colors < ContentElement
5
5
  element :instantiationColors, as: :value
6
6
 
7
7
  build_xml do |xml|
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::DataRate < Element
4
+ class Instantiation::DataRate < ContentElement
5
5
  element :instantiationDataRate, as: :value
6
6
 
7
7
  attribute :unitsOfMeasure, as: :units_of_measure
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::Date < Element
4
+ class Instantiation::Date < ContentElement
5
5
  element :instantiationDate, as: :value
6
6
 
7
7
  attribute :dateType, as: :type
@@ -1,7 +1,7 @@
1
1
  require 'pbcore/element'
2
2
 
3
3
  module PBCore
4
- class Instantiation::Digital < Element
4
+ class Instantiation::Digital < ContentElement
5
5
  element :instantiationDigital, as: :value
6
6
 
7
7
  build_xml do |xml|