Module: NEU::MODS::Selectors
- Included in:
- Document
- Defined in:
- lib/neu/mods/selectors.rb
Overview
Node LOCATION over a parsed MODS document. These return live Nokogiri nodes, so they serve BOTH the read path (projection reads their text) AND the write path (Cerberus’s MODSMerge mutates the returned nodes in place). That shared definition is the point: the node an editor changes is provably the node the projection reads. Mixed into Document; operates on ‘doc`.
Instance Method Summary collapse
-
#abstract_nodes ⇒ Object
All top-level <abstract> elements (MODS permits several).
-
#build_corporate_name(name:, role: "Creator") ⇒ Object
Build a plain corporate-creator <name> node: a single namePart + a text roleTerm.
-
#build_node(name, text = nil) ⇒ Object
Build a namespaced MODS element reusing the document’s existing ‘mods:` namespace declaration (so new nodes never re-declare xmlns).
-
#build_personal_name(given:, family:, role: "Creator") ⇒ Object
Build a plain personal-creator <name> node: namePart/[family] + a text roleTerm.
-
#editable_creator_nodes(type) ⇒ Object
The “editable creator” <name> nodes of a given @type (“personal” / “corporate”) that the Advanced form manages: plain names (no authority markers) with a Creator role.
-
#keyword_subjects ⇒ Object
The “keyword” subjects the simple form manages: attribute-free <subject> elements whose element children are all <topic>.
-
#primary_title_info ⇒ Object
Top-level primary titleInfo, falling back to the first top-level titleInfo.
Instance Method Details
#abstract_nodes ⇒ Object
All top-level <abstract> elements (MODS permits several).
20 21 22 |
# File 'lib/neu/mods/selectors.rb', line 20 def abstract_nodes doc.xpath("/mods:mods/mods:abstract", NAMESPACE) end |
#build_corporate_name(name:, role: "Creator") ⇒ Object
Build a plain corporate-creator <name> node: a single namePart + a text roleTerm. No authority/valueURI.
67 68 69 70 71 72 73 |
# File 'lib/neu/mods/selectors.rb', line 67 def build_corporate_name(name:, role: "Creator") node = build_node("name") node["type"] = "corporate" node.add_child(name_part(name)) unless name.to_s.strip.empty? node.add_child(role_node(role)) node end |
#build_node(name, text = nil) ⇒ Object
Build a namespaced MODS element reusing the document’s existing ‘mods:` namespace declaration (so new nodes never re-declare xmlns).
35 36 37 38 39 40 |
# File 'lib/neu/mods/selectors.rb', line 35 def build_node(name, text = nil) node = Nokogiri::XML::Node.new(name, doc) node.namespace = doc.root.namespace_definitions.find { |d| d.prefix == "mods" } node.content = text unless text.nil? node end |
#build_personal_name(given:, family:, role: "Creator") ⇒ Object
Build a plain personal-creator <name> node: namePart/[family] + a text roleTerm. No authority/valueURI (the editable set). ‘role` is parameterised (default “Creator”) so a later role-selectable form is a non-breaking change.
56 57 58 59 60 61 62 63 |
# File 'lib/neu/mods/selectors.rb', line 56 def build_personal_name(given:, family:, role: "Creator") name = build_node("name") name["type"] = "personal" name.add_child(name_part(given, "given")) unless given.to_s.strip.empty? name.add_child(name_part(family, "family")) unless family.to_s.strip.empty? name.add_child(role_node(role)) name end |
#editable_creator_nodes(type) ⇒ Object
The “editable creator” <name> nodes of a given @type (“personal” / “corporate”) that the Advanced form manages: plain names (no authority markers) with a Creator role. The write-path counterpart to the editable_*_creators projections; everything else (authority-bearing or non-Creator) is curated and left untouched. Mirrors keyword_subjects.
47 48 49 50 |
# File 'lib/neu/mods/selectors.rb', line 47 def editable_creator_nodes(type) doc.xpath("/mods:mods/mods:name[@type='#{type}']", NAMESPACE) .select { |n| editable_creator_name?(n) } end |
#keyword_subjects ⇒ Object
The “keyword” subjects the simple form manages: attribute-free <subject> elements whose element children are all <topic>. Anything with an authority/valueURI (or a non-topic child, e.g. a <name> subject) is curated and left untouched. (Distinct from the projection’s #topical_subjects, which harvests every <topic> for the access copy.)
29 30 31 |
# File 'lib/neu/mods/selectors.rb', line 29 def keyword_subjects doc.xpath("/mods:mods/mods:subject", NAMESPACE).select { |s| keyword_subject?(s) } end |
#primary_title_info ⇒ Object
Top-level primary titleInfo, falling back to the first top-level titleInfo. Scoped to direct children of <mods:mods> so a relatedItem’s nested titleInfo (e.g. a series title) is never matched.
14 15 16 17 |
# File 'lib/neu/mods/selectors.rb', line 14 def primary_title_info doc.at_xpath("/mods:mods/mods:titleInfo[@usage='primary']", NAMESPACE) || doc.at_xpath("/mods:mods/mods:titleInfo", NAMESPACE) end |