Class: PBCore::Element

Inherits:
Object
  • Object
show all
Includes:
SAXMachine
Defined in:
lib/pbcore/element.rb

Overview

TODO: decouple XML building behavior from schema-related declarations.

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.build_blockObject (readonly)

Returns the value of attribute build_block.



72
73
74
# File 'lib/pbcore/element.rb', line 72

def build_block
  @build_block
end

Class Method Details

.all_element_configObject



109
110
111
112
113
# File 'lib/pbcore/element.rb', line 109

def all_element_config
  top_level_element_config.merge(collection_element_config) do |name, top_level_element_cfg, coll_element_cfg|
    coll_element_cfg.present? ? coll_element_cfg : top_level_element_cfg
  end
end

.attribute_configObject



81
82
83
# File 'lib/pbcore/element.rb', line 81

def attribute_config
  sax_config.top_level_attributes
end

.build_xml(&block) ⇒ Object

Class method to allow extended classes to declaratively the logic used to build XML using Nokogiri::XML::Builder.

Raises:

  • (ArgumentError)


76
77
78
79
# File 'lib/pbcore/element.rb', line 76

def build_xml(&block)
  raise ArgumentError, "#{self.class}.build_xml requires a block with one parameter" unless block_given? && block.arity == 1
  @build_block = block
end

.collection_element_configObject

Returns the SAXMachine::SaxConfig::ElementConfig that allow for multiple instances of other elements, i.e. “collection” elements which is not to be confused with <pbcoreCollection>.



103
104
105
106
107
# File 'lib/pbcore/element.rb', line 103

def collection_element_config
  sax_config.collection_elements.reject do |element_config|
    element_config.instance_variable_get(:@as) == :value
  end
end

.has_a_value?Boolean

Returns true if the element is configured to contain a value.

Returns:

  • (Boolean)


86
87
88
# File 'lib/pbcore/element.rb', line 86

def has_a_value?
  !sax_config.top_level_element_value.nil?
end

.has_sax_machine_attribute?(name, opts = {}) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
118
119
120
121
# File 'lib/pbcore/element.rb', line 115

def has_sax_machine_attribute?(name, opts={})
  sax_config.top_level_attributes.any? do |attr_config|
    opts.all? do |key, val|
      val == attr_config.instance_variable_get("@#{key}".to_sym)
    end
  end
end

.has_sax_machine_collection_element?(name, opts = {}) ⇒ Boolean

Returns:

  • (Boolean)


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/pbcore/element.rb', line 139

def has_sax_machine_collection_element?(name, opts={})
  # NOTE: Accessing #collection_elements with square brackets has the
  # unwanted side affect of creating an entry in the collection_elements,
  # which we don't want. So we use #fetch here
  Array(sax_config.collection_elements.fetch(name.to_s, nil)).any? do |element_config|
    opts.all? do |key, val|
      # This is a quirk of SAXMachine; for some reason it converts the
      # config option :as to a string when assigning it to the
      # ConfigElement instance, so we need to convert opts[:as] param to
      # string in order to compare them accurately.
      val = val.to_s if key == :as
      val == element_config.instance_variable_get(:"@#{key}")
    end
  end
end

.has_sax_machine_top_level_element?(name, opts = {}) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
# File 'lib/pbcore/element.rb', line 127

def has_sax_machine_top_level_element?(name, opts={})
  Array(sax_config.top_level_elements.fetch(name.to_s, nil)).any? do |element_config|
    opts.all? do |key, val|
      # This is a quirk of SAXMachine: when you declare a top-level
      # element with the .element class method, it takes your :class
      # option and puts it into an instance var called @data_class.
      key = :data_class if key == :class
      val == element_config.instance_variable_get("@#{key}".to_sym)
    end
  end
end

.has_sax_machine_value_element?Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/pbcore/element.rb', line 123

def has_sax_machine_value_element?
  !sax_config.top_level_element_value.empty?
end

.top_level_element_configObject

Returns the SAXMachine::SaxConfig::ElementConfig instances that allow for a single instance of another element.



92
93
94
95
96
97
98
# File 'lib/pbcore/element.rb', line 92

def top_level_element_config
  sax_config.top_level_elements.reject do |_name, element_configs|
    element_configs.detect do |element_config|
      element_config.instance_variable_get(:@as) == :value
    end
  end
end

Instance Method Details

#attributes(key_by_xml_name: false) ⇒ Object

Returns a hash of attrubutes as the should appear in the XML.



42
43
44
45
46
47
48
49
50
51
# File 'lib/pbcore/element.rb', line 42

def attributes(key_by_xml_name: false)
  xml_attrs = Hash[
    self.class.sax_config.top_level_attributes.map do |attr|
      accessor = attr.instance_variable_get(:@as)
      key = key_by_xml_name ? attr.name : accessor
      [ key, send(accessor) ]
    end
  ]
  xml_attrs
end

#build(builder = nil) ⇒ Object

Executes the block defined with the class method ‘build_xml`. Uses a Nokogiri::XML::Builder instance (either passed in or instantiated) to build the XML, and then returns the builder instance.

Raises:

  • (ArgumentError)


56
57
58
59
60
61
62
# File 'lib/pbcore/element.rb', line 56

def build(builder=nil)
  raise ArgumentError, "#{self.class}#build expects a Nokogiri::XML::Builder class, but #{builder.class} was given" unless builder.nil? || builder.is_a?(Nokogiri::XML::Builder)
  PBCore.fail_if_missing_build_xml_block(element_class: self.class)
  builder ||= Nokogiri::XML::Builder.new
  instance_exec builder, &self.class.build_block
  builder
end

#elements(key_by_xml_name: false) ⇒ Object

Returns a hash of child element instances.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/pbcore/element.rb', line 20

def elements(key_by_xml_name: false)
  key_value_pairs_array = self.class.all_element_config.map do |name, element_configs|
    # SAXMachine allows you to declare multiple elements with the same name
    # but we don't do tha with PBCore, so just grab the first and only one.
    element_config = element_configs.first
    # get the accessor name by which to get the value
    accessor = element_config.instance_variable_get(:@as)

    # fetch the value by calling the accessor
    value = send(accessor)
    # create the key, value pair that will go into the Hash[] construct.
    key = key_by_xml_name ? name : accessor
    [ key,  value ]
  end

  Hash[ key_value_pairs_array ]
end

#to_xmlObject

Builds the xml using #build with a new instance of Nokogiri::XML::Builder and immediately calls to_xml on it.



66
67
68
# File 'lib/pbcore/element.rb', line 66

def to_xml
  build.to_xml
end

#xml_attributesObject

Shortcut for getting xml attributes.



39
# File 'lib/pbcore/element.rb', line 39

def xml_attributes; attributes(key_by_xml_name: true); end