pubid 2.0.0 → 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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/data/parg/adobe.json +1 -1
  3. data/data/parg/aiee.json +1 -1
  4. data/data/parg/amca.json +1 -1
  5. data/data/parg/ansi.json +1 -1
  6. data/data/parg/api.json +1 -1
  7. data/data/parg/ashrae.json +1 -1
  8. data/data/parg/asme.json +1 -1
  9. data/data/parg/astm.json +1 -1
  10. data/data/parg/bipm.json +1 -1
  11. data/data/parg/bsi.json +1 -1
  12. data/data/parg/calconnect.json +1 -1
  13. data/data/parg/ccsds.json +1 -1
  14. data/data/parg/cen_cenelec.json +1 -1
  15. data/data/parg/cie.json +1 -1
  16. data/data/parg/csa.json +1 -1
  17. data/data/parg/doi.json +1 -1
  18. data/data/parg/easc.json +1 -1
  19. data/data/parg/ecma.json +1 -1
  20. data/data/parg/etsi.json +1 -1
  21. data/data/parg/evs.json +1 -1
  22. data/data/parg/gb.json +1 -1
  23. data/data/parg/gost.json +1 -1
  24. data/data/parg/iala.json +1 -1
  25. data/data/parg/iana.json +1 -1
  26. data/data/parg/idf.json +1 -1
  27. data/data/parg/iec.json +1 -1
  28. data/data/parg/ieee.json +1 -29571
  29. data/data/parg/ietf.json +1 -1
  30. data/data/parg/iho.json +1 -0
  31. data/data/parg/ire.json +1 -1
  32. data/data/parg/isbn.json +1 -1
  33. data/data/parg/iso.json +1 -8510
  34. data/data/parg/itu.json +1 -1
  35. data/data/parg/jcgm.json +1 -1
  36. data/data/parg/jis.json +1 -1
  37. data/data/parg/nesc.json +1 -1
  38. data/data/parg/nist.json +1 -9588
  39. data/data/parg/oasis.json +1 -1
  40. data/data/parg/ogc.json +1 -1
  41. data/data/parg/oiml.json +1 -1
  42. data/data/parg/omg.json +1 -1
  43. data/data/parg/parg.json +1 -1
  44. data/data/parg/plateau.json +1 -1
  45. data/data/parg/sae.json +1 -1
  46. data/data/parg/tables/typed_stages.yaml +1 -0
  47. data/data/parg/tgpp.json +1 -1
  48. data/data/parg/un.json +1 -1
  49. data/data/parg/w3c.json +1 -1
  50. data/data/parg/xsf.json +1 -1
  51. data/lib/pubid/adobe/identifier.rb +1 -1
  52. data/lib/pubid/adobe/parser.rb +2 -113
  53. data/lib/pubid/amca/identifiers/base.rb +1 -1
  54. data/lib/pubid/amca/parser.rb +1 -145
  55. data/lib/pubid/ansi/identifier.rb +1 -1
  56. data/lib/pubid/ansi/parser.rb +1 -82
  57. data/lib/pubid/api/builder.rb +32 -1
  58. data/lib/pubid/api/identifier.rb +1 -1
  59. data/lib/pubid/api/parser.rb +1 -131
  60. data/lib/pubid/ashrae/identifiers/base.rb +1 -1
  61. data/lib/pubid/ashrae/parser.rb +3 -710
  62. data/lib/pubid/asme/builder.rb +6 -4
  63. data/lib/pubid/asme/identifier.rb +1 -2
  64. data/lib/pubid/asme/parser.rb +1 -328
  65. data/lib/pubid/astm/builder.rb +12 -3
  66. data/lib/pubid/astm/identifier.rb +1 -2
  67. data/lib/pubid/astm/parser.rb +1 -227
  68. data/lib/pubid/bipm/identifier.rb +8 -1
  69. data/lib/pubid/bipm/parser.rb +2 -224
  70. data/lib/pubid/bsi/builder.rb +2 -4
  71. data/lib/pubid/bsi/parser.rb +1 -666
  72. data/lib/pubid/bsi/single_identifier.rb +38 -1
  73. data/lib/pubid/calconnect/identifier.rb +1 -1
  74. data/lib/pubid/calconnect/parser.rb +2 -40
  75. data/lib/pubid/ccsds/identifier.rb +1 -1
  76. data/lib/pubid/ccsds/parser.rb +1 -66
  77. data/lib/pubid/cen_cenelec/identifier.rb +16 -1
  78. data/lib/pubid/cen_cenelec/parser.rb +3 -136
  79. data/lib/pubid/cie/identifier.rb +1 -1
  80. data/lib/pubid/cie/parser.rb +3 -378
  81. data/lib/pubid/conformance.rb +1 -1
  82. data/lib/pubid/csa/builder.rb +41 -18
  83. data/lib/pubid/csa/identifier.rb +12 -4
  84. data/lib/pubid/csa/identifiers/amendment.rb +28 -0
  85. data/lib/pubid/csa/identifiers.rb +1 -0
  86. data/lib/pubid/csa/parser.rb +16 -397
  87. data/lib/pubid/doi/identifier.rb +1 -1
  88. data/lib/pubid/doi/parser.rb +2 -37
  89. data/lib/pubid/easc/builder.rb +1 -1
  90. data/lib/pubid/easc/identifier.rb +1 -1
  91. data/lib/pubid/easc/parser.rb +2 -70
  92. data/lib/pubid/ecma/CLAUDE.md +8 -1
  93. data/lib/pubid/ecma/identifier.rb +13 -8
  94. data/lib/pubid/ecma/parser.rb +2 -54
  95. data/lib/pubid/ecma/renderer.rb +3 -7
  96. data/lib/pubid/errors.rb +18 -13
  97. data/lib/pubid/etsi/builder.rb +8 -5
  98. data/lib/pubid/etsi/identifiers/base.rb +1 -1
  99. data/lib/pubid/etsi/parser.rb +1 -132
  100. data/lib/pubid/evs/identifier.rb +7 -0
  101. data/lib/pubid/evs/parser.rb +1 -8
  102. data/lib/pubid/evs.rb +1 -1
  103. data/lib/pubid/gb/identifier.rb +7 -1
  104. data/lib/pubid/gb/parser.rb +2 -51
  105. data/lib/pubid/gost/identifier.rb +9 -1
  106. data/lib/pubid/gost/parser.rb +4 -81
  107. data/lib/pubid/iala/parser.rb +2 -121
  108. data/lib/pubid/iana/identifier.rb +1 -1
  109. data/lib/pubid/iana/parser.rb +2 -24
  110. data/lib/pubid/identifier.rb +78 -1
  111. data/lib/pubid/idf/builder.rb +42 -0
  112. data/lib/pubid/idf/identifier.rb +1 -1
  113. data/lib/pubid/idf/parser.rb +1 -137
  114. data/lib/pubid/idf.rb +1 -2
  115. data/lib/pubid/iec/builder.rb +158 -50
  116. data/lib/pubid/iec/identifier.rb +1 -1
  117. data/lib/pubid/iec/parser.rb +3 -430
  118. data/lib/pubid/ieee/aiee/identifier.rb +2 -1
  119. data/lib/pubid/ieee/aiee.rb +0 -1
  120. data/lib/pubid/ieee/builder.rb +2 -2
  121. data/lib/pubid/ieee/identifiers/base.rb +1 -1
  122. data/lib/pubid/ieee/ire/identifier.rb +2 -1
  123. data/lib/pubid/ieee/ire.rb +0 -1
  124. data/lib/pubid/ieee/nesc.rb +0 -1
  125. data/lib/pubid/ieee/parser.rb +1 -1257
  126. data/lib/pubid/ietf/identifiers/base.rb +17 -1
  127. data/lib/pubid/ietf/parser.rb +2 -47
  128. data/lib/pubid/ietf/renderer.rb +17 -2
  129. data/lib/pubid/iho/CLAUDE.md +89 -0
  130. data/lib/pubid/iho/builder.rb +4 -1
  131. data/lib/pubid/iho/identifiers/base.rb +28 -2
  132. data/lib/pubid/iho/renderer.rb +8 -0
  133. data/lib/pubid/iho/urn_generator.rb +11 -1
  134. data/lib/pubid/iho/urn_parser.rb +21 -11
  135. data/lib/pubid/iho.rb +0 -1
  136. data/lib/pubid/isbn/identifier.rb +1 -1
  137. data/lib/pubid/isbn/parser.rb +2 -31
  138. data/lib/pubid/iso/builder.rb +1 -1
  139. data/lib/pubid/iso/identifiers/directives.rb +6 -3
  140. data/lib/pubid/iso/identifiers/guide.rb +6 -3
  141. data/lib/pubid/iso/identifiers/international_standard.rb +3 -1
  142. data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
  143. data/lib/pubid/iso/normalizer.rb +1 -1
  144. data/lib/pubid/iso/parser.rb +1 -539
  145. data/lib/pubid/iso/supplement_identifier.rb +6 -3
  146. data/lib/pubid/iso/utilities.rb +4 -5
  147. data/lib/pubid/iso.rb +1 -19
  148. data/lib/pubid/itu/builder.rb +36 -20
  149. data/lib/pubid/itu/identifiers/base.rb +15 -2
  150. data/lib/pubid/itu/parser.rb +1 -775
  151. data/lib/pubid/jcgm/builder.rb +35 -0
  152. data/lib/pubid/jcgm/parser.rb +1 -151
  153. data/lib/pubid/jcgm.rb +1 -2
  154. data/lib/pubid/jis/builder.rb +18 -29
  155. data/lib/pubid/jis/identifier.rb +1 -1
  156. data/lib/pubid/jis/parser.rb +1 -128
  157. data/lib/pubid/nist/builder.rb +5 -1
  158. data/lib/pubid/nist/caster.rb +13 -3
  159. data/lib/pubid/nist/identifiers/base.rb +37 -2
  160. data/lib/pubid/nist/identifiers/circular.rb +2 -2
  161. data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
  162. data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
  163. data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
  164. data/lib/pubid/nist/identifiers/handbook.rb +2 -2
  165. data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
  166. data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
  167. data/lib/pubid/nist/identifiers/monograph.rb +2 -2
  168. data/lib/pubid/nist/identifiers/report.rb +2 -2
  169. data/lib/pubid/nist/parser.rb +19 -775
  170. data/lib/pubid/nist/router.rb +4 -1
  171. data/lib/pubid/nist/supplement_identifier.rb +2 -2
  172. data/lib/pubid/oasis/identifier.rb +1 -1
  173. data/lib/pubid/oasis/parser.rb +2 -16
  174. data/lib/pubid/ogc/identifier.rb +1 -1
  175. data/lib/pubid/ogc/parser.rb +2 -26
  176. data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
  177. data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
  178. data/lib/pubid/oiml/parser.rb +1 -303
  179. data/lib/pubid/oiml.rb +1 -2
  180. data/lib/pubid/omg/identifier.rb +6 -1
  181. data/lib/pubid/omg/parser.rb +2 -76
  182. data/lib/pubid/parg/artifact.rb +22 -3
  183. data/lib/pubid/parg/model.rb +98 -0
  184. data/lib/pubid/parg.rb +1 -0
  185. data/lib/pubid/parser.rb +5 -4
  186. data/lib/pubid/parsers/mr_string.rb +1 -1
  187. data/lib/pubid/plateau/parser.rb +1 -66
  188. data/lib/pubid/plateau.rb +1 -2
  189. data/lib/pubid/renderers/directives_renderer.rb +1 -1
  190. data/lib/pubid/renderers/iwa_renderer.rb +1 -1
  191. data/lib/pubid/renderers/publisher_stripper.rb +82 -0
  192. data/lib/pubid/renderers/supplement_renderer.rb +1 -1
  193. data/lib/pubid/renderers.rb +1 -0
  194. data/lib/pubid/sae/identifiers/base.rb +1 -1
  195. data/lib/pubid/sae/parser.rb +1 -48
  196. data/lib/pubid/tgpp/identifier.rb +1 -1
  197. data/lib/pubid/tgpp/parser.rb +2 -59
  198. data/lib/pubid/un/identifier.rb +1 -1
  199. data/lib/pubid/un/parser.rb +1 -18
  200. data/lib/pubid/version.rb +1 -1
  201. data/lib/pubid/w3c/identifier.rb +1 -1
  202. data/lib/pubid/w3c/parser.rb +2 -27
  203. data/lib/pubid/xsf/identifier.rb +11 -7
  204. data/lib/pubid/xsf/parser.rb +3 -31
  205. data/lib/pubid/xsf/renderer.rb +2 -4
  206. data/lib/pubid.rb +8 -9
  207. metadata +15 -25
  208. data/lib/pubid/ieee/aiee/parser.rb +0 -130
  209. data/lib/pubid/ieee/ire/parser.rb +0 -109
  210. data/lib/pubid/ieee/nesc/parser.rb +0 -155
  211. data/lib/pubid/iho/parser.rb +0 -68
  212. data/lib/pubid/parser/common_parse_methods.rb +0 -13
  213. data/lib/pubid/parser/common_parse_rules.rb +0 -56
  214. data/lib/pubid/parser/grammar.rb +0 -96
@@ -1,706 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "parslet"
4
-
5
3
  module Pubid
6
4
  module Ashrae
7
5
  # Parser class for ASHRAE identifiers
8
6
  # Single Responsibility: Parsing ASHRAE identifier syntax
9
- class Parser < ::Pubid::Parser::Grammar
10
- # Basic building blocks
11
- rule(:space) { str(" ") }
12
- rule(:space?) { space.maybe }
13
- rule(:dash) { str("-") }
14
- rule(:dot) { str(".") }
15
- rule(:slash) { str("/") }
16
- rule(:lparen) { str("(") }
17
- rule(:rparen) { str(")") }
18
- rule(:comma) { str(",") }
19
- rule(:colon) { str(":") }
20
-
21
- rule(:digit) { match("[0-9]") }
22
- rule(:digits) { digit.repeat(1) }
23
- rule(:letter) { match("[A-Za-z]") }
24
-
25
- # Year pattern (4 digits starting with 19 or 20)
26
- rule(:year_digits) do
27
- (str("19") | str("20")) >> digit.repeat(2, 2)
28
- end
29
-
30
- # Reaffirmation year (2 or 4 digits)
31
- rule(:reaffirmation_year) do
32
- year_digits | digit.repeat(2, 2)
33
- end
34
-
35
- # Publisher
36
- rule(:publisher) { str("ASHRAE") }
37
-
38
- # Type (Guideline or Standard)
39
- rule(:type) do
40
- str("Guideline") | str("Standard")
41
- end
42
-
43
- # Code pattern (e.g., 15, 90.1, 41.10, 118.1, 90A,B,C)
44
- rule(:code) do
45
- (
46
- digits >> # First part (e.g., 15, 90)
47
- (dot >> digits).repeat(0, 2) >> # Optional dotted parts (e.g., .1, .10)
48
- # Special pattern for codes like "90A,B,C" (letter + comma-separated letters)
49
- (
50
- letter >> # Single letter after digits (e.g., "A" in "90A")
51
- (comma >> letter).repeat(0, 10) # Optional comma-separated letters (e.g., ",B,C")
52
- ).maybe # This entire letter+commas pattern is optional
53
- ).as(:code)
54
- end
55
-
56
- # Code with year pattern (e.g., 34-2024, 62.1-2022, 90A-2010) - used when type is missing
57
- #
58
- # The code portion MUST be captured with `.as(:code)`. Without it the
59
- # digits were matched and then discarded — only the year was named — so
60
- # every identifier reaching this rule lost its document number: 48 corpus
61
- # ids rendered as "ANSI/ASHRAE Addendum a to ASHRAE Standard -2024",
62
- # number gone and a dangling dash left behind. Builder#extract_base_attributes
63
- # already read `code_with_year[:code]`; it was waiting for a value the
64
- # grammar never produced.
65
- rule(:code_with_year) do
66
- (
67
- (
68
- digits >> # First part (e.g., 34, 62)
69
- (dot >> digits).repeat(0, 2) >> # Optional dotted parts (e.g., .1)
70
- # Special pattern for codes like "90A,B,C-2010"
71
- (
72
- letter >> # Single letter after digits
73
- (comma >> letter).repeat(0, 10) # Optional comma-separated letters
74
- ).maybe
75
- ).as(:code) >>
76
- space?.maybe >> dash >>
77
- year_digits.as(:year)
78
- ).as(:code_with_year)
79
- end
80
-
81
- # Suffix (R for revision, P for proposed)
82
- rule(:suffix) do
83
- (str("R") | str("P")).as(:suffix)
84
- end
85
-
86
- # Additional copublisher pattern (e.g., /AMCA 210-99 or (ANSI/AMCA 330-97))
87
- rule(:additional_copublisher) do
88
- (slash >> (letter.repeat(4,
89
- 10) >> space >> (digits >> (dash >> digits).maybe).maybe).as(:additional_copublisher)) |
90
- (lparen >> (str("ANSI") >> slash >> (letter.repeat(2,
91
- 10) >> (slash >> letter.repeat(2, 10)).repeat(0,
92
- 2))).as(:additional_copublisher) >> space >> (digits >> (dash >> digits).maybe).maybe >> rparen)
93
- end
94
-
95
- # Optional suffix in parentheses (PDF), (I-P and SI versions), long descriptions, etc.
96
- rule(:optional_suffix) do
97
- space.maybe >> lparen >> (
98
- str("PDF") | # Special case for PDF
99
- (letter.repeat(1, 20) >> (space | digit | comma | dash | dot | letter | str("–")).repeat(0, 500)) # General case including long descriptions
100
- ) >> rparen
101
- end
102
-
103
- # Reaffirmation pattern (RA YEAR or RA-YEAR)
104
- rule(:reaffirmed) do
105
- (space.maybe >> lparen >> str("RA") >> space? >> reaffirmation_year.as(:reaffirmed) >> rparen) |
106
- (space.maybe >> lparen >> str("RA") >> dash >> reaffirmation_year.as(:reaffirmed) >> rparen) |
107
- (space >> str("RA") >> space >> reaffirmation_year.as(:reaffirmed)) |
108
- (space >> str("RA") >> dash >> reaffirmation_year.as(:reaffirmed))
109
- end
110
-
111
- # Addendum code (single letter, multi-letter, or numeric-prefixed like 62o)
112
- rule(:addendum_code) do
113
- (digits.maybe >> letter.repeat(1, 3)).as(:addendum_code)
114
- end
115
-
116
- # Addendum date pattern (Month Day, Year - e.g., "January 22, 2019")
117
- rule(:month_name) do
118
- str("January") | str("February") | str("March") | str("April") | str("May") |
119
- str("June") | str("July") | str("August") | str("September") | str("October") |
120
- str("November") | str("December")
121
- end
122
-
123
- # The date is what tells two errata of one standard apart, so every part
124
- # of it is named. The leading space is part of the rule: without it the
125
- # date never matched after "Errata", and optional_suffix took it instead.
126
- rule(:errata_date) do
127
- # Full date: (Month Day, Year)
128
- (space.maybe >> lparen >> month_name.as(:month) >> space >>
129
- digit.repeat(1, 2).as(:day) >> comma.maybe >> (space | comma.maybe) >>
130
- year_digits.as(:errata_year) >> rparen).as(:errata_date) |
131
- # Month+day without year: (August 27)
132
- (space.maybe >> lparen >> month_name.as(:month) >> space >>
133
- digit.repeat(1, 2).as(:day) >> rparen).as(:errata_date) |
134
- # Numeric date with dash: (7-17- 2003) or (7-17-2003)
135
- (space.maybe >> lparen >>
136
- (digit.repeat(1, 2) >> dash >> digit.repeat(1, 2) >> dash >>
137
- space.maybe >> year_digits).as(:numeric_date) >>
138
- rparen).as(:errata_date)
139
- end
140
-
141
- # Errata suffix pattern - handles descriptive text like "– Spanish Edition" after "Errata"
142
- rule(:errata_suffix) do
143
- # Regular dash or em dash
144
- (space >> (str("-") | str("–")) >> space >> (letter >> (space | letter | digit | comma).repeat(0, 50))).repeat(
145
- 0, 3
146
- )
147
- end
148
-
149
- # The date and the descriptive suffix after "Errata", in either order. All
150
- # three errata_identifier branches share this rule: the publisher branch had
151
- # only the date-first order, so "Errata – Spanish Edition (June 2, 2010)"
152
- # lost its date to optional_suffix.
153
- rule(:errata_date_and_suffix) do
154
- (errata_suffix >> errata_date) |
155
- (errata_date >> errata_suffix) |
156
- errata_date |
157
- errata_suffix
158
- end
159
-
160
- # Errata suffix on addendum (e.g., "ASHRAE Addendum a to Standard 15-2001 Errata (July 6, 2021)")
161
- rule(:errata_suffix_on_addendum) do
162
- space >> str("Errata").as(:errata_keyword) >>
163
- (
164
- # Full date: (Month Day, Year)
165
- (space >> lparen >> month_name >> space >> digit.repeat(1,
166
- 2) >> comma.maybe >> (space | comma.maybe) >> year_digits >> rparen) |
167
- # Month+day without year: (August 27)
168
- (space >> lparen >> month_name >> space >> digit.repeat(1,
169
- 2) >> rparen) |
170
- # Numeric date with dash: (7-17-2003)
171
- (space >> lparen >> digit.repeat(1,
172
- 2) >> dash >> digit.repeat(1,
173
- 2) >> dash >> space.maybe >> year_digits >> rparen) |
174
- # No date at all
175
- str("")
176
- )
177
- end
178
-
179
- # Errata pattern (base identifier + " Errata (date)")
180
- rule(:errata_identifier) do
181
- # Format with copublisher: ANSI/ASHRAE Standard 105-2014 Errata (May 23, 2014)
182
- ((
183
- (
184
- (str("ANSI") >> dash >> str("ASHRAE")) |
185
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
186
- 0, 10
187
- ))
188
- ).as(:copublisher) >> space >>
189
- type.as(:type) >> space >>
190
- code >>
191
- (space?.maybe >> dash >> year_digits.as(:year)).maybe >>
192
- (space >> additional_copublisher).maybe >>
193
- suffix.maybe >>
194
- reaffirmed.maybe
195
- ).as(:base) >>
196
- space >>
197
- str("Errata").as(:errata_keyword) >>
198
- errata_date_and_suffix.maybe >>
199
- optional_suffix.repeat(0, 2).as(:optional_suffixes)) |
200
- # Format with copublisher, missing type: ANSI/ASHRAE 51-1999 Errata (May 23, 2014)
201
- ((
202
- (
203
- (str("ANSI") >> dash >> str("ASHRAE")) |
204
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
205
- 0, 10
206
- ))
207
- ).as(:copublisher) >> space >>
208
- code_with_year >>
209
- (space >> additional_copublisher).maybe >>
210
- suffix.maybe >>
211
- reaffirmed.maybe
212
- ).as(:base) >>
213
- space >>
214
- str("Errata").as(:errata_keyword) >>
215
- errata_date_and_suffix.maybe >>
216
- optional_suffix.repeat(0, 2).as(:optional_suffixes)) |
217
- # Format with publisher: ASHRAE Guideline 0-2005 Errata (September 28, 2011)
218
- ((
219
- publisher.as(:publisher) >> space >>
220
- type.as(:type) >> space >>
221
- code >>
222
- (space?.maybe >> dash >> year_digits.as(:year)).maybe >>
223
- (space >> additional_copublisher).maybe >>
224
- suffix.maybe >>
225
- reaffirmed.maybe
226
- ).as(:base) >>
227
- space >>
228
- str("Errata").as(:errata_keyword) >>
229
- errata_date_and_suffix.maybe >>
230
- optional_suffix.repeat(0, 2).as(:optional_suffixes))
231
- end
232
-
233
- # Interpretation pattern ("Interpretations for Standard X-YYYY")
234
- #
235
- # The `.as(:interpretation_identifier)` tag is what Builder#build
236
- # dispatches on. Without it the tree is a bare `{base: …}`, the builder
237
- # takes the plain-identifier path, and the interpretation becomes the
238
- # standard it interprets.
239
- rule(:interpretation_identifier) do
240
- (str("Interpretations") >> space >>
241
- str("for") >> space >>
242
- (type.as(:type) >> space >> code >>
243
- (dash >> year_digits.as(:year)).maybe).as(:base))
244
- .as(:interpretation_identifier)
245
- end
246
-
247
- # Combined Addenda pattern (multiple addendums grouped together)
248
- rule(:combined_addenda_identifier) do
249
- # Format 1: ASHRAE Addenda X, Y and Z to Standard/Guideline X-YYYY
250
- (
251
- publisher.as(:publisher) >> space >>
252
- str("Addenda") >> space >>
253
- addendum_code >> # First addendum code
254
- (
255
- (comma >> space >> str("and") >> space >> addendum_code) | # ", and b"
256
- (space >> str("and") >> space >> addendum_code) | # "and b"
257
- (comma >> space >> addendum_code).repeat(1, 50) | # comma-separated: "a, b, c"
258
- (comma >> addendum_code).repeat(1, 50) # comma without space: "a,b,c"
259
- ).repeat(0, 20).as(:additional_codes) >> # Multiple groups of codes
260
- space >>
261
- (str("to") | str("for")) >> space >>
262
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
263
- 0, 10
264
- )).as(:copublisher) >> space).maybe >>
265
- type.as(:type) >> space >>
266
- code >>
267
- (dash >> year_digits.as(:year)).maybe >>
268
- (space >> additional_copublisher).maybe >>
269
- addendum_date_suffix.maybe >>
270
- optional_suffix.repeat(0, 2)
271
- ).as(:combined_addenda) |
272
- # Format 2: ASHRAE Standard X-YYYY: Addenda a, b, c (colon separator)
273
- (
274
- publisher.as(:publisher) >> space >>
275
- type.as(:type) >> space >>
276
- code >>
277
- (dash >> year_digits.as(:year)) >>
278
- ((colon >> space) | space) >>
279
- str("Addenda") >> space >>
280
- addendum_code >> # First addendum code
281
- (
282
- # Just match all comma-separated values (including "and" as a code)
283
- (comma >> space >> addendum_code).repeat(1, 50) |
284
- # Or comma without space
285
- (comma >> addendum_code).repeat(1, 50)
286
- ).as(:additional_codes).maybe >> # Entire additional_codes is optional
287
- optional_suffix.repeat(0, 2)
288
- ).as(:combined_addenda) |
289
- # Format 3: ASHRAE Addenda a, b, c to Standard/Guideline X-YYYY (without publisher at start)
290
- (
291
- str("Addenda") >> space >>
292
- addendum_code >> # First addendum code
293
- (
294
- (comma >> space >> str("and") >> space >> addendum_code) | # ", and b"
295
- (space >> str("and") >> space >> addendum_code) | # "and b"
296
- (comma >> space >> addendum_code).repeat(1, 20) | # comma-separated
297
- (comma >> addendum_code).repeat(1, 20) # comma without space
298
- ).repeat(0, 50).as(:additional_codes) >> # Allow 0 for single addendum
299
- space >>
300
- (str("to") | str("for")) >> space >>
301
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
302
- 0, 10
303
- )).as(:copublisher) >> space).maybe >>
304
- type.as(:type) >> space >>
305
- code >>
306
- (dash >> year_digits.as(:year)).maybe >>
307
- optional_suffix.repeat(0, 2)
308
- ).as(:combined_addenda) |
309
- # Format 4: ASHRAE Addenda to Standard/Guideline X-YYYY (without specific codes)
310
- (
311
- publisher.as(:publisher) >> space >>
312
- str("Addenda") >> space >>
313
- (str("to") | str("for")) >> space >>
314
- type.as(:type) >> space >>
315
- code >>
316
- (dash >> year_digits.as(:year)).maybe >>
317
- optional_suffix.repeat(0, 2)
318
- ).as(:combined_addenda) |
319
- # Format 5: ASHRAE Addenda a, b, c to 105-2007 (missing type keyword)
320
- (
321
- publisher.as(:publisher) >> space >>
322
- str("Addenda") >> space >>
323
- addendum_code >>
324
- (
325
- (comma >> space >> str("and") >> space >> addendum_code) | # ", and b"
326
- (space >> str("and") >> space >> addendum_code) | # "and b"
327
- (comma >> space >> addendum_code).repeat(1, 20) | # comma-separated
328
- (comma >> addendum_code).repeat(1, 20) # comma without space
329
- ).repeat(0, 50).as(:additional_codes) >> # Allow 0 for single addendum
330
- space >>
331
- (str("to") | str("for")) >> space >>
332
- code_with_year >>
333
- optional_suffix.repeat(0, 2)
334
- ).as(:combined_addenda) |
335
- # Format 6: Addenda a, b, c to 105-2007 (without publisher, missing type)
336
- (
337
- str("Addenda") >> space >>
338
- addendum_code >>
339
- (
340
- (comma >> space >> str("and") >> space >> addendum_code) | # ", and b"
341
- (space >> str("and") >> space >> addendum_code) | # "and b"
342
- (comma >> space >> addendum_code).repeat(1, 20) | # comma-separated
343
- (comma >> addendum_code).repeat(1, 20) # comma without space
344
- ).repeat(0, 50).as(:additional_codes) >> # Allow 0 for single addendum
345
- space >>
346
- (str("to") | str("for")) >> space >>
347
- code_with_year >>
348
- optional_suffix.repeat(0, 2)
349
- ).as(:combined_addenda) |
350
- # Format 7: ASHRAE Standard X-YYYY: Addenda a, b, c (colon or space separator)
351
- (
352
- publisher.as(:publisher) >> space >>
353
- type.as(:type) >> space >>
354
- code >>
355
- (dash >> year_digits.as(:year)).maybe >>
356
- ((colon >> space) | space) >>
357
- str("Addenda") >> space >>
358
- addendum_code >> # First addendum code
359
- (
360
- # Range pattern: "a through z"
361
- (space >> str("through") >> space >> addendum_code) |
362
- # Space or comma separated codes (handles typos like "bl bq")
363
- ((space | (comma >> space)) >> addendum_code).repeat(1, 200) |
364
- # Just match all comma-separated values
365
- (comma >> space >> addendum_code).repeat(1, 200) |
366
- # Or comma without space
367
- (comma >> addendum_code).repeat(1, 200)
368
- ).as(:additional_codes).maybe >>
369
- (space >> additional_copublisher).maybe >>
370
- addendum_date_suffix.maybe >>
371
- optional_suffix.repeat(0, 2)
372
- ).as(:combined_addenda)
373
- end
374
-
375
- # Year-first Addenda Package pattern
376
- rule(:year_first_addenda_package_identifier) do
377
- (
378
- year_digits.as(:package_year) >> space >>
379
- (
380
- # Format 1: "YYYY Addenda Supplement Package to Standard X-YYYY"
381
- (str("Addenda") >> space >> str("Supplement") >> (space >> str("Package")).maybe >> space >> str("to") >> space >>
382
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
383
- 0, 10
384
- )).as(:copublisher) >> space).maybe >>
385
- type.as(:type) >> space >> code >> (dash >> year_digits.as(:year)).maybe) |
386
- # Format 2: "YYYY Supplement Addenda a, b, c to Standard X-YYYY"
387
- (str("Supplement") >> space >> str("Addenda") >> space >>
388
- addendum_code >>
389
- (
390
- (comma >> space >> addendum_code).repeat(1, 50) |
391
- (comma >> addendum_code).repeat(1, 50)
392
- ).as(:additional_codes).maybe >>
393
- space >> str("to") >> space >>
394
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
395
- 0, 10
396
- )).as(:copublisher) >> space).maybe >>
397
- type.as(:type) >> space >> code >> (dash >> year_digits.as(:year)).maybe
398
- ) |
399
- # Format 3: "YYYY Addenda Supplement to Standard X-YYYY" (without "Package")
400
- (str("Addenda") >> space >> str("Supplement") >> space >> str("to") >> space >>
401
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
402
- 0, 10
403
- )).as(:copublisher) >> space).maybe >>
404
- type.as(:type) >> space >> code >> (dash >> year_digits.as(:year)).maybe) |
405
- # Format 4: "YYYY Supplement to ANSI/ASHRAE/... Standard X-YYYY Errata (date)"
406
- (str("Supplement") >> space >> str("to") >> space >>
407
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
408
- 0, 10
409
- )).as(:copublisher) >> space).maybe >>
410
- type.as(:type) >> space >> code >> (dash >> year_digits.as(:year)).maybe >>
411
- errata_suffix_on_addendum.maybe)
412
- ) >>
413
- optional_suffix.repeat(0, 2)
414
- ).as(:addenda_package)
415
- end
416
-
417
- # Addenda Package pattern (collection packages)
418
- rule(:addenda_package_identifier) do
419
- # Format with copublisher: ANSI/ASHRAE Standard 34-2013 Addenda Supplement Package (...)
420
- (
421
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
422
- 0, 10
423
- )).as(:copublisher) >> space >>
424
- type.as(:type) >> space >>
425
- code >>
426
- (dash >> year_digits.as(:year)).maybe >>
427
- ((colon >> space) | space) >>
428
- str("Addenda") >> space >>
429
- ((str("Supplement") >> (space >> str("Package")).maybe) | str("Package")).as(:package_description) >>
430
- (space >> str("for") >> space >> year_digits.as(:target_year)).maybe >>
431
- optional_suffix.repeat(0, 3)
432
- ).as(:addenda_package) |
433
- # Format with publisher + comma Addenda YEAR Supplement: ASHRAE Standard 90.1-2010, Addenda 2012 Supplement: Addenda Supplement Package
434
- (
435
- publisher.as(:publisher) >> space >>
436
- type.as(:type) >> space >>
437
- code >>
438
- (dash >> year_digits.as(:year)).maybe >>
439
- comma >> space >> str("Addenda") >> space >> year_digits.as(:package_year) >> space >> str("Supplement") >> colon >> space >>
440
- str("Addenda") >> space >>
441
- ((str("Supplement") >> (space >> str("Package")).maybe) | str("Package")).as(:package_description) >>
442
- optional_suffix.repeat(0, 3)
443
- ).as(:addenda_package) |
444
- # Standard format with publisher: ASHRAE Standard X-YYYY Addenda Supplement Package
445
- (
446
- publisher.as(:publisher) >> space >>
447
- type.as(:type) >> space >>
448
- code >>
449
- (dash >> year_digits.as(:year)).maybe >>
450
- (space >> year_digits.as(:package_year)).maybe >>
451
- additional_copublisher.maybe >>
452
- suffix.maybe >>
453
- reaffirmed.maybe >>
454
- ((colon >> space) | space) >>
455
- str("Addenda") >> space >>
456
- ((str("Supplement") >> (space >> str("Package")).maybe) | str("Package")).as(:package_description) >>
457
- (space >> str("for") >> space >> year_digits.as(:target_year)).maybe >>
458
- optional_suffix.repeat(0, 3)
459
- ).as(:addenda_package)
460
- end
461
-
462
- # Addendum date pattern (Month Day, Year - e.g., "January 22, 2019")
463
- rule(:addendum_date_suffix) do
464
- space >> lparen >> month_name >> space >> digit.repeat(1,
465
- 2) >> comma.maybe >> (space | comma.maybe) >> year_digits >> rparen
466
- end
467
-
468
- # Addendum pattern (multiple formats):
469
- rule(:addendum_identifier) do
470
- # Format: ASHRAE Addendum X to Standard/Guideline X-YYYY
471
- (
472
- publisher.as(:publisher) >> space >>
473
- str("Addendum") >> space >>
474
- addendum_code >>
475
- space >>
476
- (str("to") | str("for")) >> space >>
477
- type.as(:type) >> space >>
478
- code >>
479
- (dash >> year_digits.as(:year)).maybe >>
480
- additional_copublisher.maybe >>
481
- addendum_date_suffix.maybe >>
482
- errata_suffix_on_addendum.maybe >>
483
- optional_suffix.repeat(0, 2)
484
- ).as(:publisher_addendum) |
485
- # Format: ASHRAE Addendum X to ASHRAE Standard/Guideline X-YYYY (same publisher repeated)
486
- (
487
- publisher.as(:publisher) >> space >>
488
- str("Addendum") >> space >>
489
- addendum_code >>
490
- space >>
491
- (str("to") | str("for")) >> space >>
492
- publisher.as(:base_publisher) >> space >>
493
- type.as(:type) >> space >>
494
- code >>
495
- (dash >> year_digits.as(:year)).maybe >>
496
- additional_copublisher.maybe >>
497
- addendum_date_suffix.maybe >>
498
- errata_suffix_on_addendum.maybe >>
499
- optional_suffix.repeat(0, 2)
500
- ).as(:publisher_base_addendum) |
501
- # Format: [ANSI/ASHRAE] Addendum X to/for ASHRAE Standard/Guideline
502
- # X-YYYY (leading copublisher + publisher-led base)
503
- (
504
- (
505
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
506
- 0, 10
507
- )).as(:copublisher) >>
508
- space
509
- ).maybe >>
510
- str("Addendum") >> space >>
511
- addendum_code >>
512
- space >>
513
- (str("to") | str("for")) >> space >>
514
- publisher.as(:base_publisher) >> space >>
515
- type.as(:type) >> space >>
516
- code >>
517
- (dash >> year_digits.as(:year)).maybe >>
518
- additional_copublisher.maybe >>
519
- addendum_date_suffix.maybe >>
520
- errata_suffix_on_addendum.maybe >>
521
- optional_suffix.repeat(0, 2)
522
- ).as(:publisher_base_addendum) |
523
- # Format: ASHRAE Addendum X to ANSI/ASHRAE Standard/Guideline X-YYYY (ASHRAE publisher + copublisher base)
524
- (
525
- publisher.as(:publisher) >> space >>
526
- str("Addendum") >> space >>
527
- addendum_code >>
528
- space >>
529
- (str("to") | str("for")) >> space >>
530
- (
531
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
532
- 0, 10
533
- )).as(:copublisher) >>
534
- space
535
- ) >>
536
- type.as(:type) >> space >>
537
- code >>
538
- (dash >> year_digits.as(:year)).maybe >>
539
- addendum_date_suffix.maybe >>
540
- errata_suffix_on_addendum.maybe >>
541
- optional_suffix.repeat(0, 2)
542
- ).as(:publisher_addendum_copublisher) |
543
- # Format: ASHRAE Addendum X to ANSI/ASHRAE 62.1-2022 (publisher + copublisher, no type)
544
- (
545
- publisher.as(:publisher) >> space >>
546
- str("Addendum") >> space >>
547
- addendum_code >>
548
- space >>
549
- (str("to") | str("for")) >> space >>
550
- (
551
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
552
- 0, 10
553
- )).as(:copublisher) >>
554
- space
555
- ) >>
556
- code_with_year >>
557
- additional_copublisher.maybe >>
558
- addendum_date_suffix.maybe >>
559
- errata_suffix_on_addendum.maybe >>
560
- optional_suffix.repeat(0, 2)
561
- ).as(:publisher_addendum_copublisher_no_type) |
562
- # Format: [ANSI/ASHRAE] Addendum X to/for [ANSI/ASHRAE] 34-2024 (no type)
563
- (
564
- (
565
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
566
- 0, 10
567
- )).as(:copublisher) >>
568
- space
569
- ).maybe >>
570
- str("Addendum") >> space >>
571
- addendum_code >>
572
- space >>
573
- (str("to") | str("for")) >> space >>
574
- (
575
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
576
- 0, 10
577
- )).as(:copublisher) >>
578
- space
579
- ).maybe >> # Make second copublisher optional
580
- code_with_year >>
581
- additional_copublisher.maybe >>
582
- addendum_date_suffix.maybe >>
583
- errata_suffix_on_addendum.maybe >>
584
- optional_suffix.repeat(0, 2)
585
- ).as(:addendum_no_type) |
586
- # Format: [ANSI/ASHRAE] Addendum X to/for [ANSI/ASHRAE] Standard/Guideline X-YYYY
587
- (
588
- (
589
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
590
- 0, 10
591
- )).as(:copublisher) >>
592
- space
593
- ).maybe >>
594
- str("Addendum") >> space >>
595
- addendum_code >>
596
- space >>
597
- (str("to") | str("for")) >> space >>
598
- (
599
- (str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
600
- 0, 10
601
- )).as(:copublisher) >>
602
- space
603
- ).maybe >>
604
- type.as(:type) >> space >>
605
- code >>
606
- (dash >> year_digits.as(:year)).maybe >>
607
- additional_copublisher.maybe >>
608
- addendum_date_suffix.maybe >>
609
- errata_suffix_on_addendum.maybe >>
610
- optional_suffix.repeat(0, 2)
611
- ).as(:addendum) |
612
- # Format: ASHRAE Standard 15-2013 Addendum a
613
- (
614
- publisher.as(:publisher) >> space >>
615
- type.as(:type) >> space >>
616
- code >>
617
- (dash >> year_digits.as(:year)).maybe >>
618
- additional_copublisher.maybe >>
619
- suffix.maybe >>
620
- reaffirmed.maybe >>
621
- ((colon >> space) | space) >>
622
- (str("Addendum") | str("addendum")) >> space >>
623
- addendum_code >>
624
- addendum_date_suffix.maybe >>
625
- errata_suffix_on_addendum.maybe >>
626
- optional_suffix.repeat(0, 2)
627
- ).as(:standard_addendum) |
628
- # Format: ASHRAE Standard 15-2013 Addendum a (with lowercase and space only)
629
- (
630
- publisher.as(:publisher) >> space >>
631
- type.as(:type) >> space >>
632
- code >>
633
- (dash >> year_digits.as(:year)).maybe >>
634
- additional_copublisher.maybe >>
635
- suffix.maybe >>
636
- reaffirmed.maybe >>
637
- space >>
638
- (str("Addendum") | str("addendum")) >> space >>
639
- addendum_code >>
640
- addendum_date_suffix.maybe >>
641
- errata_suffix_on_addendum.maybe >>
642
- optional_suffix.repeat(0, 2)
643
- ).as(:standard_addendum)
644
- end
645
-
646
- # Main identifier pattern
647
- rule(:identifier) do
648
- errata_identifier |
649
- interpretation_identifier |
650
- combined_addenda_identifier |
651
- year_first_addenda_package_identifier |
652
- addenda_package_identifier |
653
- addendum_identifier |
654
- # Standalone copublisher pattern (ANSI/AMCA 210-99, AMCA 210-99).
655
- # The literal "ASHRAE" is excluded here so a bare "ASHRAE <code>-<year>"
656
- # is not swallowed as a copublisher and instead falls through to the
657
- # ASHRAE-publisher branch below.
658
- (((str("ANSI") >> slash).maybe >> (str("ASHRAE").absent? >> letter).repeat(2,
659
- 10)).as(:copublisher) >>
660
- space >>
661
- code_with_year >>
662
- optional_suffix.repeat(0, 2)) |
663
- # Copublished patterns without type (ANSI/ASHRAE 34-2024)
664
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
665
- 0, 10
666
- )).as(:copublisher) >>
667
- space >>
668
- code_with_year >>
669
- (space >> additional_copublisher).maybe >>
670
- suffix.maybe >>
671
- reaffirmed.maybe >>
672
- optional_suffix.repeat(0, 2)) |
673
- # Copublished patterns with type (ANSI/ASHRAE, ANSI/ASHRAE/ACCA, ANSI/ASHRAE/ASHE/ICC, etc.)
674
- ((str("ANSI") >> slash >> str("ASHRAE") >> (slash >> letter.repeat(3, 10)).repeat(
675
- 0, 10
676
- )).as(:copublisher) >>
677
- space >>
678
- type.as(:type).maybe >> space.maybe >>
679
- code >>
680
- (space?.maybe >> dash >> year_digits.as(:year)).maybe >>
681
- (space >> additional_copublisher).maybe >>
682
- suffix.maybe >>
683
- reaffirmed.maybe >>
684
- optional_suffix.repeat(0, 2)) |
685
- # Standard ASHRAE pattern. The type keyword is optional so a bare
686
- # partial reference "ASHRAE <code>" (no "Standard"/"Guideline") parses;
687
- # the builder defaults the absent type to "Standard".
688
- (publisher.as(:publisher) >> space >>
689
- (type.as(:type) >> space).maybe >>
690
- code >>
691
- (space?.maybe >> dash >> year_digits.as(:year)).maybe >>
692
- (space >> additional_copublisher).maybe >>
693
- suffix.maybe >>
694
- reaffirmed.maybe >>
695
- optional_suffix.repeat(0, 2)
696
- ).as(:base)
697
- end
698
-
699
- root(:identifier)
700
-
701
- # Pre-parse ingestion normalizations (R2): every parse path —
702
- # parslet and PG artifact alike — feeds the grammar the same
703
- # normalized string.
7
+ class Parser
8
+ # Pre-parse ingestion normalizations (R2): every parse path feeds
9
+ # the grammar the same normalized string.
704
10
  def self.normalize_input(string)
705
11
  # Strip leading/trailing whitespace
706
12
  cleaned = string.strip
@@ -771,19 +77,6 @@ module Pubid
771
77
 
772
78
  cleaned
773
79
  end
774
-
775
- def self.parse(string)
776
- unless string.is_a?(String)
777
- raise Pubid::Errors::InvalidInputError,
778
- Pubid::INPUT_NOT_A_STRING_MESSAGE
779
- end
780
-
781
- if string.length > Pubid::MAX_INPUT_LENGTH
782
- raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
783
- end
784
-
785
- new.parse(normalize_input(string))
786
- end
787
80
  end
788
81
  end
789
82
  end