Module: Metanorma::Standoc::Refs

Includes:
Regex
Included in:
Converter
Defined in:
lib/metanorma/converter/ref.rb,
lib/metanorma/converter/ref_queue.rb,
lib/metanorma/converter/ref_utility.rb

Constant Summary collapse

JOINT_REFS =
%i(merge dual).freeze

Constants included from Regex

Metanorma::Standoc::Regex::CONN_REGEX_STR, Metanorma::Standoc::Regex::ISO_REF, Metanorma::Standoc::Regex::ISO_REF_ALL_PARTS, Metanorma::Standoc::Regex::ISO_REF_NO_YEAR, Metanorma::Standoc::Regex::LOCALITIES, Metanorma::Standoc::Regex::LOCALITY_REGEX_STR, Metanorma::Standoc::Regex::LOCALITY_REGEX_STR_TRIPLEDASH, Metanorma::Standoc::Regex::LOCALITY_REGEX_VALUE_ONLY_STR, Metanorma::Standoc::Regex::NON_ISO_REF, Metanorma::Standoc::Regex::NON_ISO_REF1, Metanorma::Standoc::Regex::NUMERIC_REGEX, Metanorma::Standoc::Regex::TERM_REFERENCE_RE, Metanorma::Standoc::Regex::TERM_REFERENCE_RE_STR

Instance Method Summary collapse

Methods included from Regex

#to_regex

Instance Method Details

#analyse_ref_code(code) ⇒ Object



96
97
98
99
100
101
# File 'lib/metanorma/converter/ref_utility.rb', line 96

def analyse_ref_code(code)
  ret = { id: code }
  code.nil? || code.empty? and return ret
  analyse_ref_code_csv(ret) ||
    analyse_ref_code_nested(ret)
end

#analyse_ref_code_csv(ret) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/metanorma/converter/ref_utility.rb', line 103

def analyse_ref_code_csv(ret)
  ret[:id].include?("=") or return nil
  line = CSV.parse_line(ret[:id], liberal_parsing: true) or return nil
  a = analyse_ref_code_csv_breakup(line)
  analyse_ref_code_csv_map(a)
rescue StandardError
  nil
end

#analyse_ref_code_csv_breakup(line) ⇒ Object



112
113
114
115
116
117
118
119
# File 'lib/metanorma/converter/ref_utility.rb', line 112

def analyse_ref_code_csv_breakup(line)
  line.each_with_object({}) do |x, m|
    kv = x.split("=", 2)
    kv.size == 1 and kv = ["code", kv.first]
    m[kv[0].to_sym] = kv[1].delete_prefix('"').delete_suffix('"')
      .delete_prefix("'").delete_suffix("'")
  end
end

#analyse_ref_code_csv_map(source) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/metanorma/converter/ref_utility.rb', line 121

def analyse_ref_code_csv_map(source)
  source.each_with_object({}) do |(k, v), ret|
    case k
    when :dropid, :hidden, :nofetch
      ret[k] = v == "true"
    when :repo, :path, :attachment
      ret[:type] = k.to_s
      ret[:key] = v
      ret[:nofetch] = true
      source[:code] or
        ret[:id] = v == :attachment ? nil : v.sub(%r{^[^/]+/}, "")
    when :"local-file"
      ret[:localfile] = v
    when :number
      if source[:code] then ret[:usrlabel] = "(#{v})"
      else ret[:numeric] = true
      end
    when :usrlabel
      ret[:usrlabel] = "(#{v})"
    when :code then ret[:id] = v
    end
  end
end

#analyse_ref_code_nested(ret) ⇒ Object



145
146
147
148
149
150
151
152
# File 'lib/metanorma/converter/ref_utility.rb', line 145

def analyse_ref_code_nested(ret)
  opts, id = parse_ref_code_nested({}, ret[:id])
  ret[:id] = id
  ret.merge!(opts)
  analyse_ref_numeric(ret)
  analyse_ref_repo_path(ret)
  ret
end

#analyse_ref_numeric(ret) ⇒ Object



91
92
93
94
# File 'lib/metanorma/converter/ref_utility.rb', line 91

def analyse_ref_numeric(ret)
  /^\d+$/.match?(ret[:id]) or return ret
  ret.merge(numeric: true)
end

#analyse_ref_repo_path(ret) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/metanorma/converter/ref_utility.rb', line 77

def analyse_ref_repo_path(ret)
  %i(repo path attachment).each do |type|
    ret[type] or next
    id = if ret[:id].empty?
           if type == :attachment then "(#{ret[type]})"
           else ret[type].sub(%r{^[^/]+/}, "")
           end
         else ret[:id]
         end
    ret.merge!(id: id, type: type.to_s, key: ret[type], nofetch: true)
  end
  ret
end

#conditional_date(bib, match, noyr) ⇒ Object



26
27
28
29
30
31
32
# File 'lib/metanorma/converter/ref_utility.rb', line 26

def conditional_date(bib, match, noyr)
  if match.names.include?("year") && !match[:year].nil?
    bib.date(type: "published") do |d|
      (noyr and d.on "--") or set_date_range(d, norm_year(match[:year]))
    end
  end
end

#docid(bib, code, codetype = nil) ⇒ Object



44
45
46
47
48
49
50
51
52
53
# File 'lib/metanorma/converter/ref_utility.rb', line 44

def docid(bib, code, codetype = nil)
  type, code1 = if /^\[\d+\]$|^\(.+\).*$/.match?(code)
                  ["metanorma", mn_code(code)]
                elsif docid_untyped?(code, codetype)
                  [nil, code]
                else @bibdb&.docid_type(code) || [nil, code]
                end
  code1.sub!(/^nofetch\((.+)\)$/, "\\1")
  add_noko_elem(bib, "docidentifier", code1, type: type)
end

#docid_untyped?(code, codetype) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
58
# File 'lib/metanorma/converter/ref_utility.rb', line 55

def docid_untyped?(code, codetype)
  %w(attachment repo path).include?(codetype) ||
    code.strip.empty? || /^\d+$/.match?(code)
end

#docnumber(bib, code) ⇒ Object



60
61
62
63
# File 'lib/metanorma/converter/ref_utility.rb', line 60

def docnumber(bib, code)
  code or return
  add_noko_elem(bib, "docnumber", @c.decode(code).sub(/^[^\d]*/, ""))
end

#docrelation_insert(base) ⇒ Object



106
107
108
109
110
111
# File 'lib/metanorma/converter/ref_queue.rb', line 106

def docrelation_insert(base)
  %w(relation copyright status abstract locale language note version
     edition contributor date docnumber docidentifier).each do |v|
    r = base.at("//#{v}[last()]") and return r
  end
end

#dual_entries(base, add) ⇒ Object



101
102
103
104
# File 'lib/metanorma/converter/ref_queue.rb', line 101

def dual_entries(base, add)
  ins = docrelation_insert(base)
  ins.next = "<relation type='hasReproduction'>#{to_xml(add)}</relation>"
end

#fetch_ref(xml, code, year, **opts) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/metanorma/converter/ref_queue.rb', line 137

def fetch_ref(xml, code, year, **opts)
  opts[:no_year] and return nil
  _, code = extract_balanced_parentheses(code)
  hit = fetch_ref1(code, year, opts) or return nil
  xml.parent.add_child(smart_render_xml(hit, code, opts))
  xml
rescue Relaton::RequestError
  @log.add("STANDOC_40", nil, params: [code])
  nil
end

#fetch_ref1(code, year, opts) ⇒ Object



152
153
154
155
156
157
158
# File 'lib/metanorma/converter/ref_queue.rb', line 152

def fetch_ref1(code, year, opts)
  code = supply_ref_prefix(code)
  if opts[:localfile]
    @local_bibdb.get(code, opts[:localfile])
  else @bibdb&.fetch(code, year, opts)
  end
end

#fetch_ref_async(ref, idx, res) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/metanorma/converter/ref_queue.rb', line 166

def fetch_ref_async(ref, idx, res)
  ref[:code] &&= supply_ref_prefix(ref[:code])
  if unfetchable_ref_code?(ref)
    res << [ref, idx, nil]
    idx += 1
  elsif ref[:localfile]
    res << [ref, idx, @local_bibdb.get(ref[:code], ref[:localfile])]
    idx += 1
  else idx = fetch_ref_async1(ref, idx, res)
  end
  idx
end

#fetch_ref_async1(ref, idx, res) ⇒ Object



179
180
181
182
183
184
# File 'lib/metanorma/converter/ref_queue.rb', line 179

def fetch_ref_async1(ref, idx, res)
  @bibdb.fetch_async(ref[:code], ref[:year], ref) do |doc|
    res << [ref, idx, doc]
  end
  fetch_ref_async_dual(ref, idx, idx + 1, res)
end

#fetch_ref_async_dual(ref, orig, idx, res) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/metanorma/converter/ref_queue.rb', line 186

def fetch_ref_async_dual(ref, orig, idx, res)
  JOINT_REFS.each do |m|
    ref.dig(:analyse_code, m)&.each_with_index do |code, i|
      @bibdb.fetch_async(code, nil, ref.merge(ord: idx)) do |doc|
        res << [ref.merge("#{m}_into": orig, merge_order: i, ord: idx),
                idx, doc]
      end
      idx += 1
    end
  end
  idx
end

#flush_bib_caches_force(node) ⇒ Object

‘:flush-caches:` must clear stale cache state regardless of whether `:no-isobib-cache:` disables caching for this compile. When both are set, the `Relaton::Db.init_bib_caches` path no-ops on the flush (because it has no cache paths to flush), leaving any previously cached entries on disk for the next compile that DOES have caching enabled to pick up. Force-flush the conventional cache locations here so the flag does what its name says. Source issue: github.com/relaton/relaton-iso/issues/181



241
242
243
244
245
246
247
248
# File 'lib/metanorma/converter/ref_queue.rb', line 241

def flush_bib_caches_force(node)
  FileUtils.rm_rf "#{Dir.home}/.relaton/cache"
  lcache_name = node.attr("local-cache") || node.attr("local-cache-only")
  if lcache_name
    base = lcache_name.to_s.empty? ? "relaton" : lcache_name
    FileUtils.rm_rf "#{base}/cache"
  end
end

#global_ievcache_nameObject



126
127
128
# File 'lib/metanorma/converter/ref_queue.rb', line 126

def global_ievcache_name
  "#{Dir.home}/.iev/cache"
end

#id_and_year(id, year) ⇒ Object



16
17
18
# File 'lib/metanorma/converter/ref_utility.rb', line 16

def id_and_year(id, year)
  year ? "#{id}:#{year}" : id
end

#init_bib_caches(node) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/metanorma/converter/ref_queue.rb', line 219

def init_bib_caches(node)
  @no_isobib and return
  global = !@no_isobib_cache && !node.attr("local-cache-only")
  local = node.attr("local-cache") || node.attr("local-cache-only")
  local = nil if @no_isobib_cache
  flush_bib_caches_force(node) if node.attr("flush-caches") &&
    @no_isobib_cache
  @bibdb = Relaton::Db.init_bib_caches(
    local_cache: local,
    flush_caches: node.attr("flush-caches"),
    global_cache: global,
  )
end

#init_iev_caches(node) ⇒ Object

Treat empty strings as falsy (they’re set by Asciidoctor for some attributes)



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/metanorma/converter/ref_queue.rb', line 251

def init_iev_caches(node)
  no_cache = @no_isobib_cache && !@no_isobib_cache.empty?
  no_bib = @no_isobib && !@no_isobib.empty?
  unless no_cache || no_bib
    node.attr("local-cache-only") or
      @iev_globalname = global_ievcache_name
    @iev_localname = local_ievcache_name(node.attr("local-cache") ||
                                         node.attr("local-cache-only"))
    if @flush_caches
      FileUtils.rm_f @iev_globalname unless @iev_globalname.nil?
      FileUtils.rm_f @iev_localname unless @iev_localname.nil?
    end
  end
  # @iev = Iev::Db.new(globalname, localname) unless @no_isobib
end

#iso_publisher(bib, code) ⇒ Object



7
8
9
10
11
12
13
14
15
16
# File 'lib/metanorma/converter/ref.rb', line 7

def iso_publisher(bib, code)
  code.sub(/(?<! ) .*$/, "").split("/").each do |abbrev|
    bib.contributor do |c|
      c.role type: "publisher"
      c.organization do |org|
        organization(org, abbrev, nil, true)
      end
    end
  end
end

#isorefmatches2_1(xml, match, code) ⇒ Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/metanorma/converter/ref.rb', line 68

def isorefmatches2_1(xml, match, code)
  xml.bibitem **attr_code(ref_attributes(match)) do |t|
    isorefrender1(t, match, code, "--")
    t.date type: "published" do |d|
      d.on "--"
    end
    iso_publisher(t, match[:code])
    ref_fn(match, t)
  end
end

#isorefmatches2code(match, _item) ⇒ Object



47
48
49
50
51
52
# File 'lib/metanorma/converter/ref.rb', line 47

def isorefmatches2code(match, _item)
  code = analyse_ref_code(match[:code])
  { code: match[:code], no_year: true, lang: @lang || :all,
    note: match[:fn], year: nil, match:, analyse_code: code,
    title: match[:text], usrlbl: match[:usrlbl] || code[:usrlabel] }
end

#isorefmatches2out(item, xml) ⇒ Object



54
55
56
57
58
59
# File 'lib/metanorma/converter/ref.rb', line 54

def isorefmatches2out(item, xml)
  if item[:doc] then use_retrieved_relaton(item, xml)
  else isorefmatches2_1(xml, item[:ref][:match],
                        item[:ref][:analyse_code])
  end
end

#isorefmatches3_1(xml, match, code, year, _hasyr, _ref) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/metanorma/converter/ref.rb', line 98

def isorefmatches3_1(xml, match, code, year, _hasyr, _ref)
  xml.bibitem(**attr_code(ref_attributes(match))) do |t|
    isorefrender1(t, match, code, year, " (all parts)")
    conditional_date(t, match, year == "--")
    iso_publisher(t, match[:code])
    ref_fn(match, t)
    t.extent type: "part" do |e|
      e.referenceFrom "all"
    end
  end
end

#isorefmatches3code(match, _item) ⇒ Object



79
80
81
82
83
84
85
86
87
# File 'lib/metanorma/converter/ref.rb', line 79

def isorefmatches3code(match, _item)
  code = analyse_ref_code(match[:code])
  yr = norm_year(match[:year])
  hasyr = !yr.nil? && yr != "--"
  { code: match[:code], match:, yr:, hasyr:,
    year: hasyr ? yr : nil, lang: @lang || :all,
    all_parts: true, no_year: yr == "--",
    title: match[:text], usrlbl: match[:usrlbl] || code[:usrlabel] }
end

#isorefmatches3out(item, xml) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/metanorma/converter/ref.rb', line 89

def isorefmatches3out(item, xml)
  if item[:doc] then use_retrieved_relaton(item, xml)
  else isorefmatches3_1(
    xml, item[:ref][:match], item[:ref][:analyse_code],
    item[:ref][:yr], item[:ref][:hasyr], item[:doc]
  )
  end
end

#isorefmatchescode(match, _item) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/metanorma/converter/ref.rb', line 27

def isorefmatchescode(match, _item)
  code = analyse_ref_code(match[:code])
  yr = norm_year(match[:year])
  { code: match[:code], year: yr, match:, fn: match[:fn],
    title: match[:text], usrlbl: match[:usrlbl] || code[:usrlabel],
    analyse_code: code, lang: @lang || :all }
end

#isorefmatchesout(item, xml) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/metanorma/converter/ref.rb', line 35

def isorefmatchesout(item, xml)
  item[:doc] and return use_retrieved_relaton(item, xml)
  r = item[:ref]
  xml.bibitem **attr_code(ref_attributes(r[:match])) do |t|
    isorefrender1(t, r[:match], r[:analyse_code], r[:year])
    y = r[:year] and t.date type: "published" do |d|
      set_date_range(d, y)
    end
    iso_publisher(t, r[:match][:code])
  end
end

#isorefrender1(bib, match, code, year, allp = "") ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/metanorma/converter/ref.rb', line 18

def isorefrender1(bib, match, code, year, allp = "")
  bib.title(**plaintxt) { |i| i << ref_normalise(match[:text]) }
  # refitem_render_formattedref(bib, match[:text])
  docid(bib, match[:usrlbl]) if match[:usrlbl]
  docid(bib, code[:usrlabel]) if code && code[:usrlabel]
  docid(bib, id_and_year(match[:code], year) + allp)
  docnumber(bib, match[:code])
end

#joint_entries(out, joint_prep) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/metanorma/converter/ref_queue.rb', line 57

def joint_entries(out, joint_prep)
  joint_prep.each do |k, v|
    v[:merge]&.each do |i|
      merge_entries(out[k], out[i]) and out[i] = nil
    end
    v[:dual]&.each do |i|
      dual_entries(out[k], out[i]) and out[i] = nil
    end
  end
  out
end

#joint_entries_prep(out) ⇒ Object



115
116
117
118
119
120
121
122
123
124
# File 'lib/metanorma/converter/ref_queue.rb', line 115

def joint_entries_prep(out)
  out.each_with_object({}) do |r, m|
    JOINT_REFS.each do |v|
      if i = r&.dig(:ref, :"#{v}_into")
        m[i] ||= { "#{v}": [] }
        m[i][v][r[:ref][:merge_order]] = r[:ref][:ord]
      end
    end
  end
end

#local_ievcache_name(cachename) ⇒ Object



130
131
132
133
134
135
# File 'lib/metanorma/converter/ref_queue.rb', line 130

def local_ievcache_name(cachename)
  cachename.nil? and return nil
  cachename += "_iev" unless cachename.empty?
  cachename = "iev" if cachename.empty?
  "#{cachename}/cache"
end

#merge_docids(base, add) ⇒ Object



83
84
85
86
87
88
89
90
91
92
# File 'lib/metanorma/converter/ref_queue.rb', line 83

def merge_docids(base, add)
  ins = base.at("//docidentifier[last()]")
  [ins, add].each do |v|
    v.at("//docidentifier[@primary = 'true']") or
      v.at("//docidentifier")["primary"] = true
  end
  add.xpath("//docidentifier").reverse_each do |p|
    ins.next = p
  end
end

#merge_entries(base, add) ⇒ Object

append publishers docids of add to base



70
71
72
73
74
# File 'lib/metanorma/converter/ref_queue.rb', line 70

def merge_entries(base, add)
  merge_publishers(base, add)
  merge_docids(base, add)
  merge_urls(base, add)
end

#merge_publishers(base, add) ⇒ Object



76
77
78
79
80
81
# File 'lib/metanorma/converter/ref_queue.rb', line 76

def merge_publishers(base, add)
  ins = base.at("//contributor[last()]") || base.children[-1]
  add.xpath("//contributor[role/@type = 'publisher']").reverse_each do |p|
    ins.next = p
  end
end

#merge_urls(base, add) ⇒ Object



94
95
96
97
98
99
# File 'lib/metanorma/converter/ref_queue.rb', line 94

def merge_urls(base, add)
  ins = base.at("./uri[last()]") || base.at("./title[last()]")
  add.xpath("./uri").reverse_each do |p|
    ins.next = p
  end
end

#mn_code(code) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/metanorma/converter/ref_utility.rb', line 65

def mn_code(code)
  # Handle balanced parentheses at the start of the string
  balance, remainder = extract_balanced_parentheses(code)
  balance and return "[#{balance}]"
  remainder
    .sub(/^dropid\((.+)\)$/, "\\1")
    .sub(/^hidden\((.+)\)$/, "\\1")
    .sub(/^nofetch\((.+)\)$/, "\\1")
    .sub(/^local-file\((.+)\)$/, "\\1")
    .sub(/^amend\((.+)\)$/, "\\1")
end

#no_year_generic_ref(code) ⇒ Object

if no year is supplied, interpret as no_year reference



191
192
193
# File 'lib/metanorma/converter/ref_utility.rb', line 191

def no_year_generic_ref(code)
  /^(BSI|BS)\b/.match?(code)
end

#norm_year(year) ⇒ Object



20
21
22
23
24
# File 'lib/metanorma/converter/ref_utility.rb', line 20

def norm_year(year)
  /^&\#821[12];$/.match(year) and return "--"
  /^\d\d\d\d-\d\d\d\d$/.match(year) and return year
  year&.sub(/^([0-9]+)-.*$/, "\\1")
end

#parse_ref_code_nested(ret, ident) ⇒ Object

ref id = (usrlbl)codeyear code = [? number ]? | ident | nofetch(code) | hidden(code) | dropid(code) | amend(code) | (repo|path|attachment):(key,code) | local-file(source,? key) | merge(code, code) | dual(code, code)



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/metanorma/converter/ref_utility.rb', line 159

def parse_ref_code_nested(ret, ident)
  keys = %w(nofetch hidden dropid local-file repo path attachment merge
            dual amend)
  if (m = /^(?<key>[a-z-]+):?\((?<val>.*)\)$/.match(ident)) &&
      keys.include?(m[:key])
    case m[:key]
    when "nofetch", "hidden", "dropid", "amend"
      ret[m[:key].to_sym] = true
      parse_ref_code_nested(ret, m[:val])
    when "repo", "path", "attachment"
      kv = m[:val].split(",", 2).map(&:strip)
      ret[m[:key].to_sym] = kv[0]
      parse_ref_code_nested(ret, kv.size == 1 ? "" : kv[1])
    when "local-file"
      kv = m[:val].split(",", 2).map(&:strip)
      source = kv.size == 1 ? "default" : kv[0]
      ret[:localfile] = source
      parse_ref_code_nested(ret, kv[-1])
    when "merge", "dual"
      line = CSV.parse_line(m[:val],
                            liberal_parsing: true) or return [ret, ident]
      line.size > 1 or return [ret, ident]
      ret[:id] = line.first
      ret[m[:key].to_sym] = line[1..].map(&:strip)
      [ret, ret[:id]]
    end

  else [ret, ident]
  end
end

#plaintxtObject



195
196
197
# File 'lib/metanorma/converter/ref_utility.rb', line 195

def plaintxt
  { format: "text/plain" }
end

#ref_attributes(match) ⇒ Object



199
200
201
202
203
204
# File 'lib/metanorma/converter/ref_utility.rb', line 199

def ref_attributes(match)
  code = analyse_ref_code(match[:code])
  { anchor: match[:anchor], id: "_#{UUIDTools::UUID.random_create}",
    type: "standard",
    suppress_identifier: code[:dropid] || nil }
end

#ref_fn(match, xml) ⇒ Object



61
62
63
64
65
66
# File 'lib/metanorma/converter/ref.rb', line 61

def ref_fn(match, xml)
  if match.names.include?("fn") && match[:fn]
    add_noko_elem(xml, "note", match[:fn].to_s,
                  **plaintxt.merge(type: "Unpublished-Status"))
  end
end

#ref_normalise(ref) ⇒ Object



206
207
208
# File 'lib/metanorma/converter/ref_utility.rb', line 206

def ref_normalise(ref)
  ref.gsub("&amp;amp;", "&amp;").gsub(%r{^<em>(.*)</em>}, "\\1")
end

#ref_normalise_no_format(ref) ⇒ Object



210
211
212
213
# File 'lib/metanorma/converter/ref_utility.rb', line 210

def ref_normalise_no_format(ref)
  ref.gsub("&amp;amp;", "&amp;")
    .gsub(">\n", "> \n")
end

#reference(node) ⇒ Object



4
5
6
7
8
9
# File 'lib/metanorma/converter/ref_queue.rb', line 4

def reference(node)
  refs = node.items.each_with_object([]) do |b, m|
    m << reference1code(b.text, node)
  end
  reference_populate(reference_normalise(refs))
end

#reference1_matches(item) ⇒ Object



190
191
192
193
194
195
# File 'lib/metanorma/converter/ref.rb', line 190

def reference1_matches(item)
  matched = ISO_REF.match item
  matched2 = ISO_REF_NO_YEAR.match item
  matched3 = ISO_REF_ALL_PARTS.match item
  [matched, matched2, matched3]
end

#reference1code(item, node) ⇒ Object



197
198
199
200
201
202
203
204
# File 'lib/metanorma/converter/ref.rb', line 197

def reference1code(item, node)
  m, m2, m3 = reference1_matches(item)
  m3.nil? && m2.nil? && m.nil? and
    return refitemcode(item, node).merge(process: 0)
  !m.nil? and return isorefmatchescode(m, item).merge(process: 1)
  !m2.nil? and return isorefmatches2code(m2, item).merge(process: 2)
  !m3.nil? and return isorefmatches3code(m3, item).merge(process: 3)
end

#reference1out(item, xml) ⇒ Object



206
207
208
209
210
211
212
213
214
# File 'lib/metanorma/converter/ref.rb', line 206

def reference1out(item, xml)
  item[:ref][:analyse_code] ||= analyse_ref_code(item[:ref][:code])
  case item[:ref][:process]
  when 0 then refitemout(item, xml)
  when 1 then isorefmatchesout(item, xml)
  when 2 then isorefmatches2out(item, xml)
  when 3 then isorefmatches3out(item, xml)
  end
end

#reference_normalise(refs) ⇒ Object



11
12
13
14
15
16
# File 'lib/metanorma/converter/ref_queue.rb', line 11

def reference_normalise(refs)
  refs.each do |r|
    r[:code] = @c.decode(r[:code])
      .gsub("\u2009\u2014\u2009", " -- ").strip
  end
end

#reference_populate(refs) ⇒ Object



18
19
20
21
22
23
24
25
# File 'lib/metanorma/converter/ref_queue.rb', line 18

def reference_populate(refs)
  @biblio_cutoff and
    refs.each { |r| r[:publication_date_before] = @biblio_cutoff }
  ret = reference_queue(*references_fetch(refs))
  joint_prep = joint_entries_prep(ret)
  out = references2xml(ret)
  joint_entries(out, joint_prep).compact.map { |x| to_xml(x) }.join
end

#reference_queue(results, size) ⇒ Object



46
47
48
49
50
51
52
53
54
55
# File 'lib/metanorma/converter/ref_queue.rb', line 46

def reference_queue(results, size)
  (1..size).each.with_object([]) do |_, m|
    ref, i, doc = results.pop
    m[i.to_i] = { ref: }
    if doc.is_a?(Relaton::RequestError)
      @log.add("STANDOC_40", nil, params: [ref[:code]])
    else m[i.to_i][:doc] = doc
    end
  end
end

#references2xml(ret) ⇒ Object



27
28
29
30
31
32
# File 'lib/metanorma/converter/ref_queue.rb', line 27

def references2xml(ret)
  out = ret.map do |b|
    b.nil? ? nil : noko { |xml| reference1out(b, xml) }
  end
  out.map { |x| x.nil? ? nil : Nokogiri::XML(x).root }
end

#references_fetch(refs) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/metanorma/converter/ref_queue.rb', line 34

def references_fetch(refs)
  i = 0
  seen = {}
  ret = refs.each_with_object(Queue.new) do |ref, res|
    idx = ref[:code] + (ref[:match] ? ref[:match][:anchor] : "")
    seen[idx] and next
    i = fetch_ref_async(ref.merge(ord: i), i, res)
    /[A-Za-z]/.match?(idx) and seen[idx] = true
  end
  [ret, i]
end

#refitem1code(_item, match) ⇒ Object



165
166
167
168
169
170
171
172
173
174
# File 'lib/metanorma/converter/ref.rb', line 165

def refitem1code(_item, match)
  code = analyse_ref_code(match[:code])
  ((code[:id] && code[:numeric]) || code[:nofetch]) and
    return { code: nil, match:, analyse_code: code, fn: match[:fn],
             hidden: code[:hidden] }
  { code: code[:id], analyse_code: code, localfile: code[:localfile],
    year: (m = refitem1yr(code[:id])) ? m[:year] : nil,
    title: match[:text], match:, hidden: code[:hidden], fn: match[:fn],
    usrlbl: match[:usrlbl] || code[:usrlabel], lang: @lang || :all }
end

#refitem1yr(code) ⇒ Object



176
177
178
179
180
181
# File 'lib/metanorma/converter/ref.rb', line 176

def refitem1yr(code)
  yr_match = /[:-](?<year>(?:19|20)[0-9][0-9])$/.match(code)
  /[:-](?:19|20)[0-9][0-9].*?[:-](?:19|20)[0-9][0-9]$/.match(code) and
    yr_match = nil
  yr_match
end

#refitem_render(xml, match, code) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/metanorma/converter/ref.rb', line 133

def refitem_render(xml, match, code)
  xml.bibitem(**refitem_render_attrs(match, code)) do |t|
    refitem_render_formattedref(t, match[:text])
    yr_match = refitem1yr(code[:id])
    refitem_render1(match, code, t)
    /^\d+$|^\(.+\)$/.match?(code[:id]) or
      docnumber(t, code[:id]&.sub(/[:-](19|20)[0-9][0-9]$/, ""))
    conditional_date(t, yr_match || match, false)
    ref_fn(match, t)
  end
end

#refitem_render1(match, code, bib) ⇒ Object



110
111
112
113
114
115
116
117
118
# File 'lib/metanorma/converter/ref.rb', line 110

def refitem_render1(match, code, bib)
  refitem_uri(code, bib)
  match[:usrlbl] and docid(bib, match[:usrlbl])
  code[:usrlabel] and docid(bib, code[:usrlabel])
  i = code[:id] and
    docid(bib, /^\d+$/.match?(i) ? "[#{i}]" : i, code[:type])
  code[:type] == "repo" and
    add_noko_elem(bib, "docidentifier", code[:key], type: "repository")
end

#refitem_render_attrs(match, code) ⇒ Object



145
146
147
148
149
# File 'lib/metanorma/converter/ref.rb', line 145

def refitem_render_attrs(match, code)
  attr_code(anchor: match[:anchor], suppress_identifier: code[:dropid],
            amend: code[:amend], hidden: code[:hidden],
            id: "_#{UUIDTools::UUID.random_create}")
end

#refitem_render_formattedref(bibitem, title) ⇒ Object



151
152
153
154
155
# File 'lib/metanorma/converter/ref.rb', line 151

def refitem_render_formattedref(bibitem, title)
  (title.nil? || title.empty?) and title = @i18n.no_information_available
  add_noko_elem(bibitem, "formattedref", ref_normalise_no_format(title),
                format: "application/x-isodoc+xml")
end

#refitem_uri(code, bib) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/metanorma/converter/ref.rb', line 120

def refitem_uri(code, bib)
  if code[:type] == "path"
    add_noko_elem(bib, "uri", code[:key].sub(/\.[a-zA-Z0-9]+$/, ""),
                  type: "URI")
    add_noko_elem(bib, "uri", code[:key].sub(/\.[a-zA-Z0-9]+$/, ""),
                  type: "citation")
  end
  if code[:type] == "attachment"
    add_noko_elem(bib, "uri", code[:key], type: "attachment")
    add_noko_elem(bib, "uri", code[:key], type: "citation")
  end
end

#refitemcode(item, node) ⇒ Object

TODO: alternative where only title is available



158
159
160
161
162
163
# File 'lib/metanorma/converter/ref.rb', line 158

def refitemcode(item, node)
  m = NON_ISO_REF.match(item) and return refitem1code(item, m).compact
  m = NON_ISO_REF1.match(item) and return refitem1code(item, m).compact
  @log.add("STANDOC_43", node, params: [item])
  {}
end

#refitemout(item, xml) ⇒ Object



183
184
185
186
187
188
# File 'lib/metanorma/converter/ref.rb', line 183

def refitemout(item, xml)
  item[:ref][:match].nil? and return nil
  item[:doc] or return refitem_render(xml, item[:ref][:match],
                                      item[:ref][:analyse_code])
  use_retrieved_relaton(item, xml)
end

#set_date_range(date, text) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
# File 'lib/metanorma/converter/ref_utility.rb', line 4

def set_date_range(date, text)
  matched = /^(?<from>[0-9]+)(?:-+(?<to>[0-9]+))?$/.match text
  return unless matched[:from]

  if matched[:to]
    date.from matched[:from]
    date.to matched[:to]
  else
    date.on matched[:from]
  end
end

#skip_docidObject



215
216
217
218
219
# File 'lib/metanorma/converter/ref_utility.rb', line 215

def skip_docid
  <<~XPATH.strip.freeze
    @type = 'DOI' or @type = 'doi' or @type = 'ISSN' or @type = 'issn' or @type = 'ISBN' or @type = 'isbn' or starts-with(@type, 'ISSN.') or starts-with(@type, 'ISBN.') or starts-with(@type, 'issn.') or starts-with(@type, 'isbn.')
  XPATH
end

#smart_render_xml(xml, code, opts) ⇒ Object



199
200
201
202
203
204
205
206
207
208
# File 'lib/metanorma/converter/ref_queue.rb', line 199

def smart_render_xml(xml, code, opts)
  xml.respond_to? :to_xml or return nil
  xml = Nokogiri::XML(xml.to_xml(lang: opts[:lang]))
  emend_biblio(xml, code, opts)
  xml.xpath("//date").each { |d| Metanorma::Utils::endash_date(d) }
  xml.traverse do |n|
    n.text? and n.replace(Metanorma::Utils::smartformat(n.text))
  end
  xml.to_xml.sub(/<\?[^>]+>/, "")
end

#supply_ref_prefix(ret) ⇒ Object



148
149
150
# File 'lib/metanorma/converter/ref_queue.rb', line 148

def supply_ref_prefix(ret)
  ret
end

#unfetchable_ref_code?(ref) ⇒ Boolean

Returns:

  • (Boolean)


160
161
162
163
164
# File 'lib/metanorma/converter/ref_queue.rb', line 160

def unfetchable_ref_code?(ref)
  ref[:code].nil? || ref[:code].empty? || ref[:no_year] ||
    /^\(.+\)$/.match?(ref[:code]) ||
    (@bibdb.nil? && !ref[:localfile])
end

#use_my_anchor(ref, id, opt) ⇒ Object



34
35
36
37
38
39
40
41
42
# File 'lib/metanorma/converter/ref_utility.rb', line 34

def use_my_anchor(ref, id, opt)
  elem = ref.parent.elements.last
  elem["anchor"] = id
  add_id(elem)
  a = opt[:hidden] and elem["hidden"] = a
  a = opt[:amend] and elem["amend"] = a
  a = opt[:dropid] and elem["suppress_identifier"] = a
  ref
end

#use_retrieved_relaton(item, xml) ⇒ Object



210
211
212
213
214
215
216
217
# File 'lib/metanorma/converter/ref_queue.rb', line 210

def use_retrieved_relaton(item, xml)
  xml.parent.add_child(smart_render_xml(item[:doc], item[:ref][:code],
                                        item[:ref]))
  use_my_anchor(xml, item[:ref][:match][:anchor],
                amend: item.dig(:ref, :analyse_code, :amend),
                hidden: item.dig(:ref, :analyse_code, :hidden),
                dropid: item.dig(:ref, :analyse_code, :dropid))
end