pubid 2.0.1 → 2.0.2

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/data/parg/adobe.json +1 -1
  3. data/data/parg/amca.json +1 -1
  4. data/data/parg/ansi.json +1 -1
  5. data/data/parg/api.json +1 -1
  6. data/data/parg/ashrae.json +1 -1
  7. data/data/parg/asme.json +1 -1
  8. data/data/parg/astm.json +1 -1
  9. data/data/parg/bipm.json +1 -1
  10. data/data/parg/bsi.json +1 -1
  11. data/data/parg/ccsds.json +1 -1
  12. data/data/parg/cen_cenelec.json +1 -1
  13. data/data/parg/cie.json +1 -1
  14. data/data/parg/csa.json +1 -1
  15. data/data/parg/ecma.json +1 -1
  16. data/data/parg/etsi.json +1 -1
  17. data/data/parg/evs.json +1 -1
  18. data/data/parg/gost.json +1 -1
  19. data/data/parg/iana.json +1 -1
  20. data/data/parg/idf.json +1 -1
  21. data/data/parg/iec.json +1 -1
  22. data/data/parg/iho.json +1 -0
  23. data/data/parg/isbn.json +1 -1
  24. data/data/parg/itu.json +1 -1
  25. data/data/parg/jcgm.json +1 -1
  26. data/data/parg/jis.json +1 -1
  27. data/data/parg/nist.json +1 -1
  28. data/data/parg/oiml.json +1 -1
  29. data/data/parg/omg.json +1 -1
  30. data/data/parg/plateau.json +1 -1
  31. data/data/parg/tgpp.json +1 -1
  32. data/data/parg/un.json +1 -1
  33. data/lib/pubid/adobe/identifier.rb +1 -1
  34. data/lib/pubid/adobe/parser.rb +2 -113
  35. data/lib/pubid/amca/identifiers/base.rb +1 -1
  36. data/lib/pubid/amca/parser.rb +1 -145
  37. data/lib/pubid/ansi/identifier.rb +1 -1
  38. data/lib/pubid/ansi/parser.rb +1 -82
  39. data/lib/pubid/api/builder.rb +32 -1
  40. data/lib/pubid/api/identifier.rb +1 -1
  41. data/lib/pubid/api/parser.rb +1 -131
  42. data/lib/pubid/ashrae/identifiers/base.rb +1 -1
  43. data/lib/pubid/ashrae/parser.rb +3 -710
  44. data/lib/pubid/asme/builder.rb +6 -4
  45. data/lib/pubid/asme/identifier.rb +1 -2
  46. data/lib/pubid/asme/parser.rb +1 -328
  47. data/lib/pubid/astm/builder.rb +12 -3
  48. data/lib/pubid/astm/identifier.rb +1 -2
  49. data/lib/pubid/astm/parser.rb +1 -227
  50. data/lib/pubid/bipm/identifier.rb +8 -1
  51. data/lib/pubid/bipm/parser.rb +2 -224
  52. data/lib/pubid/bsi/builder.rb +2 -4
  53. data/lib/pubid/bsi/parser.rb +1 -666
  54. data/lib/pubid/bsi/single_identifier.rb +38 -1
  55. data/lib/pubid/calconnect/parser.rb +2 -40
  56. data/lib/pubid/ccsds/identifier.rb +1 -1
  57. data/lib/pubid/ccsds/parser.rb +1 -66
  58. data/lib/pubid/cen_cenelec/identifier.rb +16 -1
  59. data/lib/pubid/cen_cenelec/parser.rb +3 -136
  60. data/lib/pubid/cie/identifier.rb +1 -1
  61. data/lib/pubid/cie/parser.rb +3 -378
  62. data/lib/pubid/conformance.rb +1 -1
  63. data/lib/pubid/csa/builder.rb +41 -18
  64. data/lib/pubid/csa/identifier.rb +12 -4
  65. data/lib/pubid/csa/identifiers/amendment.rb +28 -0
  66. data/lib/pubid/csa/identifiers.rb +1 -0
  67. data/lib/pubid/csa/parser.rb +16 -397
  68. data/lib/pubid/doi/parser.rb +2 -37
  69. data/lib/pubid/easc/builder.rb +1 -1
  70. data/lib/pubid/easc/parser.rb +2 -70
  71. data/lib/pubid/ecma/CLAUDE.md +8 -1
  72. data/lib/pubid/ecma/identifier.rb +13 -8
  73. data/lib/pubid/ecma/parser.rb +2 -54
  74. data/lib/pubid/ecma/renderer.rb +3 -7
  75. data/lib/pubid/errors.rb +18 -13
  76. data/lib/pubid/etsi/builder.rb +8 -5
  77. data/lib/pubid/etsi/identifiers/base.rb +1 -1
  78. data/lib/pubid/etsi/parser.rb +1 -132
  79. data/lib/pubid/evs/identifier.rb +7 -0
  80. data/lib/pubid/evs/parser.rb +1 -8
  81. data/lib/pubid/evs.rb +1 -1
  82. data/lib/pubid/gb/identifier.rb +6 -0
  83. data/lib/pubid/gb/parser.rb +2 -51
  84. data/lib/pubid/gost/identifier.rb +9 -1
  85. data/lib/pubid/gost/parser.rb +4 -81
  86. data/lib/pubid/iala/parser.rb +2 -121
  87. data/lib/pubid/iana/identifier.rb +1 -1
  88. data/lib/pubid/iana/parser.rb +2 -24
  89. data/lib/pubid/identifier.rb +78 -1
  90. data/lib/pubid/idf/builder.rb +42 -0
  91. data/lib/pubid/idf/identifier.rb +1 -1
  92. data/lib/pubid/idf/parser.rb +1 -137
  93. data/lib/pubid/idf.rb +1 -2
  94. data/lib/pubid/iec/builder.rb +158 -50
  95. data/lib/pubid/iec/identifier.rb +1 -1
  96. data/lib/pubid/iec/parser.rb +3 -430
  97. data/lib/pubid/ieee/aiee/identifier.rb +2 -1
  98. data/lib/pubid/ieee/aiee.rb +0 -1
  99. data/lib/pubid/ieee/builder.rb +2 -2
  100. data/lib/pubid/ieee/identifiers/base.rb +1 -1
  101. data/lib/pubid/ieee/ire/identifier.rb +2 -1
  102. data/lib/pubid/ieee/ire.rb +0 -1
  103. data/lib/pubid/ieee/nesc.rb +0 -1
  104. data/lib/pubid/ieee/parser.rb +1 -1257
  105. data/lib/pubid/ietf/identifiers/base.rb +17 -1
  106. data/lib/pubid/ietf/parser.rb +2 -47
  107. data/lib/pubid/ietf/renderer.rb +17 -2
  108. data/lib/pubid/iho/CLAUDE.md +89 -0
  109. data/lib/pubid/iho/builder.rb +4 -1
  110. data/lib/pubid/iho/identifiers/base.rb +28 -2
  111. data/lib/pubid/iho/renderer.rb +8 -0
  112. data/lib/pubid/iho/urn_generator.rb +11 -1
  113. data/lib/pubid/iho/urn_parser.rb +21 -11
  114. data/lib/pubid/iho.rb +0 -1
  115. data/lib/pubid/isbn/identifier.rb +1 -1
  116. data/lib/pubid/isbn/parser.rb +2 -31
  117. data/lib/pubid/iso/builder.rb +1 -1
  118. data/lib/pubid/iso/identifiers/directives.rb +6 -3
  119. data/lib/pubid/iso/identifiers/guide.rb +6 -3
  120. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
  121. data/lib/pubid/iso/normalizer.rb +1 -1
  122. data/lib/pubid/iso/parser.rb +1 -539
  123. data/lib/pubid/iso/supplement_identifier.rb +6 -3
  124. data/lib/pubid/iso/utilities.rb +4 -5
  125. data/lib/pubid/iso.rb +1 -19
  126. data/lib/pubid/itu/builder.rb +36 -20
  127. data/lib/pubid/itu/identifiers/base.rb +15 -2
  128. data/lib/pubid/itu/parser.rb +1 -775
  129. data/lib/pubid/jcgm/builder.rb +35 -0
  130. data/lib/pubid/jcgm/parser.rb +1 -151
  131. data/lib/pubid/jcgm.rb +1 -2
  132. data/lib/pubid/jis/builder.rb +18 -29
  133. data/lib/pubid/jis/identifier.rb +1 -1
  134. data/lib/pubid/jis/parser.rb +1 -128
  135. data/lib/pubid/nist/builder.rb +5 -1
  136. data/lib/pubid/nist/caster.rb +13 -3
  137. data/lib/pubid/nist/identifiers/base.rb +37 -2
  138. data/lib/pubid/nist/identifiers/circular.rb +2 -2
  139. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
  140. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
  141. data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
  142. data/lib/pubid/nist/identifiers/handbook.rb +2 -2
  143. data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
  144. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
  145. data/lib/pubid/nist/identifiers/monograph.rb +2 -2
  146. data/lib/pubid/nist/identifiers/report.rb +2 -2
  147. data/lib/pubid/nist/parser.rb +19 -775
  148. data/lib/pubid/nist/router.rb +4 -1
  149. data/lib/pubid/nist/supplement_identifier.rb +2 -2
  150. data/lib/pubid/oasis/parser.rb +2 -16
  151. data/lib/pubid/ogc/parser.rb +2 -26
  152. data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
  153. data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
  154. data/lib/pubid/oiml/parser.rb +1 -303
  155. data/lib/pubid/oiml.rb +1 -2
  156. data/lib/pubid/omg/identifier.rb +6 -1
  157. data/lib/pubid/omg/parser.rb +2 -76
  158. data/lib/pubid/parser.rb +5 -4
  159. data/lib/pubid/parsers/mr_string.rb +1 -1
  160. data/lib/pubid/plateau/parser.rb +1 -66
  161. data/lib/pubid/plateau.rb +1 -2
  162. data/lib/pubid/renderers/directives_renderer.rb +1 -1
  163. data/lib/pubid/renderers/iwa_renderer.rb +1 -1
  164. data/lib/pubid/renderers/publisher_stripper.rb +82 -0
  165. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  166. data/lib/pubid/renderers.rb +1 -0
  167. data/lib/pubid/sae/parser.rb +1 -48
  168. data/lib/pubid/tgpp/identifier.rb +1 -1
  169. data/lib/pubid/tgpp/parser.rb +2 -59
  170. data/lib/pubid/un/identifier.rb +1 -1
  171. data/lib/pubid/un/parser.rb +1 -18
  172. data/lib/pubid/version.rb +1 -1
  173. data/lib/pubid/w3c/parser.rb +2 -27
  174. data/lib/pubid/xsf/identifier.rb +10 -6
  175. data/lib/pubid/xsf/parser.rb +3 -31
  176. data/lib/pubid/xsf/renderer.rb +2 -4
  177. data/lib/pubid.rb +8 -9
  178. metadata +6 -23
  179. data/lib/pubid/ieee/aiee/parser.rb +0 -130
  180. data/lib/pubid/ieee/ire/parser.rb +0 -109
  181. data/lib/pubid/ieee/nesc/parser.rb +0 -155
  182. data/lib/pubid/iho/parser.rb +0 -68
  183. data/lib/pubid/parser/common_parse_methods.rb +0 -13
  184. data/lib/pubid/parser/common_parse_rules.rb +0 -56
  185. data/lib/pubid/parser/grammar.rb +0 -96
@@ -1,237 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parslet"
4
-
5
3
  module Pubid
6
4
  module Bipm
7
- # Parslet grammar for the four BIPM identifier families. The root branches
5
+ # Grammar for the four BIPM identifier families. The root branches
8
6
  # by leading token / shape; each alternative is wrapped in a distinct key
9
7
  # (:committee_short, :meeting_en, …) so the Builder can dispatch on the
10
8
  # matched branch without re-inspecting the string.
11
9
  #
12
10
  # Group and type-word alternations are built from the shared vocabularies on
13
11
  # {Identifier} (sorted longest-first so e.g. "CCTF" is tried before "CCT").
14
- class Parser < ::Pubid::Parser::Grammar
15
- # --- primitives ---
16
- rule(:space) { str(" ") }
17
- rule(:digits) { match["0-9"].repeat(1) }
18
- rule(:alnum) { match["0-9A-Za-z"].repeat(1) }
19
- # Number, preserved as a string: digits with optional hyphenated parts.
20
- rule(:number) do
21
- (digits >> (str("-") >> digits).repeat).as(:number)
22
- end
23
- rule(:year) { match["0-9"].repeat(4, 4).as(:year) }
24
- # "E"/"F" as BIPM prints them, plus the two-letter codes consumer
25
- # references use (longest first, so "EN" is never read as a bare "E").
26
- rule(:lang) do
27
- (str("EN") | str("FR") | match["EF"]).as(:language)
28
- end
29
- # "(YYYY)" or "(YYYY, E)"
30
- rule(:year_paren) do
31
- str("(") >> year >> (str(", ") >> lang).maybe >> str(")")
32
- end
33
- rule(:year_paren_nolang) { str("(") >> year >> str(")") }
34
-
35
- # Longest-first alternation over a list of literal tokens, so a token that
36
- # is a prefix of another (e.g. "CCT" of "CCTF") never shadows it.
37
- def alternation(tokens)
38
- tokens.sort_by { |t| -t.length }.map { |t| str(t) }.reduce(:|)
39
- end
40
-
41
- rule(:group) { alternation(Identifier::PARSEABLE_GROUPS).as(:group) }
42
-
43
- rule(:type_abbrev) do
44
- alternation(Identifier::TYPE_CODES).as(:type_word)
45
- end
46
- rule(:type_name_en) do
47
- names = Identifier::TYPE_NAME_EN.values.uniq + ["Declaration"]
48
- alternation(names).as(:type_word)
49
- end
50
- rule(:type_name_fr) do
51
- names = Identifier::TYPE_NAME_FR.values.uniq + ["Déclaration"]
52
- alternation(names).as(:type_word)
53
- end
54
- rule(:connective) { str("de la") | str("du") }
55
- rule(:ordinal) { str("st") | str("nd") | str("rd") | str("th") }
56
- # The word naming a meeting in French. BIPM prints it lowercase; a
57
- # consumer reference capitalizes it, as relaton's `Id::TYPES` does.
58
- rule(:meeting_word_fr) { str("Réunion") | str("réunion") }
59
-
60
- # --- committee documents ---
61
- # The trailing "(YYYY)" date is optional (`.maybe`) so a partial reference
62
- # that omits it — e.g. "CCTF REC 2" — still parses, leaving :year absent.
63
- rule(:committee_short) do
64
- (group >> space >> type_abbrev >>
65
- (space >> number).maybe >> (space >> year_paren).maybe)
66
- .as(:committee_short)
67
- end
68
- rule(:committee_long_en) do
69
- (group >> space >> type_name_en >>
70
- (space >> number).maybe >> (space >> year_paren_nolang).maybe)
71
- .as(:committee_long_en)
72
- end
73
- rule(:committee_long_fr) do
74
- (type_name_fr >> (space >> number).maybe >> space >>
75
- connective >> space >> group >> (space >> year_paren_nolang).maybe)
76
- .as(:committee_long_fr)
77
- end
78
- # Loose consumer form: a French type name in the English (group-leading)
79
- # word order, e.g. "CIPM Décision 101-1 (2012)". BIPM never prints this,
80
- # so it renders back as the canonical "Décision 101-1 du CIPM (2012)".
81
- # Tried after `committee_long_en`, which is what keeps the words both
82
- # languages share ("Action", "Statement") English.
83
- rule(:committee_group_fr) do
84
- (group >> space >> type_name_fr >>
85
- (space >> number).maybe >> (space >> year_paren_nolang).maybe)
86
- .as(:committee_long_fr)
87
- end
88
-
89
- # Bare MRA-interpretation form: a group directly followed by a document
90
- # number with no type word (e.g. "CIPM 2005-06"). Tried last, so typed
91
- # committee documents and meetings always win; only fires when a digit
92
- # follows the group and the string is fully consumed.
93
- rule(:committee_bare) do
94
- (group >> space >> number >> (space >> year_paren).maybe)
95
- .as(:committee_bare)
96
- end
97
-
98
- # --- meetings ---
99
- # Canonical: "<group> <n><ordinal> Meeting [(YYYY)]". The second branch is
100
- # the loose consumer word order "<group> Meeting <n>", which relaton's
101
- # bespoke grammar accepts; both build the same tree, so the loose form
102
- # renders back in the canonical spelling.
103
- rule(:meeting_en) do
104
- ((group >> space >> number >> ordinal >> space >> str("Meeting") >>
105
- (space >> year_paren).maybe) |
106
- (group >> space >> str("Meeting") >> space >> number >>
107
- (space >> year_paren).maybe)).as(:meeting_en)
108
- end
109
- # Canonical: "<group> <n><sup>e</sup> réunion [(YYYY)]". The second and
110
- # third branches are the loose consumer spellings — the plain "e" ordinal
111
- # and the "<group> Réunion <n>" word order.
112
- rule(:meeting_fr) do
113
- ((group >> space >> number >> str("<sup>e</sup>") >> space >>
114
- str("réunion") >> (space >> year_paren).maybe) |
115
- (group >> space >> number >> str("e") >> space >> meeting_word_fr >>
116
- (space >> year_paren).maybe) |
117
- (group >> space >> meeting_word_fr >> space >> number >>
118
- (space >> year_paren).maybe)).as(:meeting_fr)
119
- end
120
-
121
- # --- Metrologia journal ---
122
- rule(:metrologia) do
123
- (str("Metrologia") >>
124
- (space >> digits.as(:volume) >>
125
- (space >> alnum.as(:issue) >>
126
- (space >> alnum.as(:article)).maybe).maybe).maybe).as(:metrologia)
127
- end
128
-
129
- # --- SI Brochure ---
130
- rule(:edition) { (digits >> str("e")).as(:edition) }
131
- rule(:version) { (str("v") >> match["0-9."].repeat(1)).as(:version) }
132
- rule(:years) { (digits >> (str("/") >> digits).maybe).as(:years) }
133
- # The "BIPM " prefix is optional, as it is on the variant and section
134
- # rules: `si-brochure.yaml` stores the docnumber WITHOUT it, and
135
- # `Relaton::Bipm::Bibliography.search` strips a leading "BIPM " before it
136
- # ever reaches pubid. Either spelling renders back with the prefix.
137
- rule(:si_brochure) do
138
- ((str("BIPM SI Brochure") | str("SI Brochure")) >> space >>
139
- (str("sur le SI") >> space).maybe >>
140
- edition >> space >> version >> space >>
141
- str("(") >> years >> str(", ") >> lang >> str(")")).as(:si_brochure)
142
- end
143
-
144
- # --- SI Brochure appendices / derived products ---
145
- # The full primary-docidentifier content the relaton crawler indexes by,
146
- # e.g. "BIPM SI Brochure Appendix 3" / "…Concise" / "…FAQ". The bare
147
- # "SI Brochure Appendix 3" docnumber form is accepted too (rendered back
148
- # with the "BIPM " prefix, matching the base SI Brochure record).
149
- rule(:brochure_variant) do
150
- ((str("Appendix") >> space >> digits) | str("Concise") | str("FAQ"))
151
- .as(:variant)
152
- end
153
- rule(:si_brochure_variant) do
154
- ((str("BIPM SI Brochure") | str("SI Brochure")) >> space >>
155
- brochure_variant).as(:si_brochure_variant)
156
- end
157
-
158
- # Bare and sectioned SI Brochure references: "SI Brochure",
159
- # "SI Brochure Part 1". Neither names an edition, so both are partial
160
- # references whose `number` stays nil and which wildcard every edition —
161
- # the same reading a date-less "CCTF REC 2" gets. "Part N" points at a
162
- # section INSIDE the brochure, not a separate record, so it rides in the
163
- # shared `part` attribute and stays out of the index key, exactly as the
164
- # MEP/guide "Part N.M" tail does. Listed after the edition and variant
165
- # rules for readability, not for correctness: Parslet threads
166
- # `consume_all` down through an alternation, so an alternative that
167
- # matches only a PREFIX ("SI Brochure" of "SI Brochure Concise") counts
168
- # as a failure and the next one is tried whatever the order. Order only
169
- # decides between two alternatives that BOTH consume the whole input.
170
- rule(:si_brochure_section) do
171
- ((str("BIPM SI Brochure") | str("SI Brochure")) >>
172
- (space >> str("Part") >> space >> digits.as(:part)).maybe)
173
- .as(:si_brochure_section)
174
- end
175
-
176
- # Shared "Appendix N [Annex N] Part N[.M]" tail carried by the full
177
- # docidentifier content of MEPs and CC guides (the "Appendix 2 Part 1.1"
178
- # or "Appendix 2 Annex 2 Part 1" suffix on "BIPM SI MEP …" etc.).
179
- rule(:appendix_part) do
180
- str("Appendix") >> space >> digits.as(:appendix) >>
181
- (space >> str("Annex") >> space >> digits.as(:annex)).maybe >>
182
- space >> str("Part") >> space >>
183
- (digits >> (str(".") >> digits).maybe).as(:part)
184
- end
185
-
186
- # --- Mises en pratique (MEP) ---
187
- # Two index-relevant spellings: the short docnumber ("SI MEP S1",
188
- # "Rapport BIPM-2019/05") and the full "BIPM …" primary-docidentifier
189
- # content the crawler actually keys on ("BIPM SI MEP S1 Appendix 2 Part
190
- # 1.1"). The renderer reproduces whichever the identifier carries.
191
- rule(:mep_code) { match["0-9A-Za-z"].repeat(1).as(:mep_code) }
192
- rule(:report_code) do
193
- (str("BIPM-") >> digits >> str("/") >> digits).as(:report_code)
194
- end
195
- rule(:mep_body) do
196
- (str("SI MEP") >> space >> mep_code) |
197
- (str("Rapport") >> space >> report_code)
198
- end
199
- rule(:mep) do
200
- ((str("BIPM") >> space >> mep_body >> space >> appendix_part) |
201
- mep_body).as(:mep)
202
- end
203
-
204
- # --- Consultative-Committee guides ---
205
- # "<committee>-GD-<kind>-<number>" (e.g. "CCL-GD-MeP-1"), and its full
206
- # "BIPM … Appendix 2 Part 2.2" content form. <kind> is "MeP" (mise en
207
- # pratique) or "RSI" (réalisation du SI). Reuses the shared `group`
208
- # (committee) and `number` (trailing sequence).
209
- rule(:guide_kind) { (str("MeP") | str("RSI")).as(:guide_kind) }
210
- rule(:guide_body) do
211
- group >> str("-GD-") >> guide_kind >> str("-") >> digits.as(:number)
212
- end
213
- rule(:guide) do
214
- ((str("BIPM") >> space >> guide_body >> space >> appendix_part) |
215
- guide_body).as(:guide)
216
- end
217
-
218
- # After a leading group token, the shape after the first space decides:
219
- # a digit → meeting; a type word → committee.
220
- rule(:group_leading) do
221
- meeting_en | meeting_fr | committee_short | committee_long_en |
222
- committee_group_fr | committee_bare
223
- end
224
-
225
- rule(:identifier) do
226
- metrologia | si_brochure | si_brochure_variant | si_brochure_section |
227
- mep | guide | committee_long_fr | group_leading
228
- end
229
-
230
- root(:identifier)
231
-
232
- def self.parse(input)
233
- new.parse(input)
234
- end
12
+ class Parser
235
13
  end
236
14
  end
237
15
  end
@@ -684,8 +684,7 @@ module Pubid
684
684
  # Handle nested hash from parser (when using .as with alternatives)
685
685
  data = data[:supplement_document] if data[:supplement_document].is_a?(Hash)
686
686
 
687
- # Extract values from nested hashes (parser returns {:number => {:number => "1000"}})
688
- number_val = data[:number][:number] if data[:number].is_a?(Hash)
687
+ number_val = data[:number].to_s if data[:number]
689
688
  iteration_val = data[:iteration][:iteration][0][:iteration] if data[:iteration].is_a?(Hash) && data[:iteration][:iteration].is_a?(Array) && data[:iteration][:iteration].any?
690
689
  iteration_val = nil if iteration_val.is_a?(String) && iteration_val.empty?
691
690
  parts_val = data[:parts][:parts] if data[:parts].is_a?(Hash)
@@ -734,8 +733,7 @@ module Pubid
734
733
  end
735
734
 
736
735
  def build_addendum_document(data)
737
- # Extract values from nested hashes (parser returns {:number => {:number => "1000"}})
738
- number_val = data[:number][:number] if data[:number].is_a?(Hash)
736
+ number_val = data[:number].to_s if data[:number]
739
737
  iteration_val = data[:iteration][:iteration][0][:iteration] if data[:iteration].is_a?(Hash) && data[:iteration][:iteration].is_a?(Array) && data[:iteration][:iteration].any?
740
738
  iteration_val = nil if iteration_val.is_a?(String) && iteration_val.empty?
741
739
  parts_val = data[:parts][:parts] if data[:parts].is_a?(Hash)