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.
- checksums.yaml +4 -4
- data/data/parg/adobe.json +1 -1
- data/data/parg/aiee.json +1 -1
- data/data/parg/amca.json +1 -1
- data/data/parg/ansi.json +1 -1
- data/data/parg/api.json +1 -1
- data/data/parg/ashrae.json +1 -1
- data/data/parg/asme.json +1 -1
- data/data/parg/astm.json +1 -1
- data/data/parg/bipm.json +1 -1
- data/data/parg/bsi.json +1 -1
- data/data/parg/calconnect.json +1 -1
- data/data/parg/ccsds.json +1 -1
- data/data/parg/cen_cenelec.json +1 -1
- data/data/parg/cie.json +1 -1
- data/data/parg/csa.json +1 -1
- data/data/parg/doi.json +1 -1
- data/data/parg/easc.json +1 -1
- data/data/parg/ecma.json +1 -1
- data/data/parg/etsi.json +1 -1
- data/data/parg/evs.json +1 -1
- data/data/parg/gb.json +1 -1
- data/data/parg/gost.json +1 -1
- data/data/parg/iala.json +1 -1
- data/data/parg/iana.json +1 -1
- data/data/parg/idf.json +1 -1
- data/data/parg/iec.json +1 -1
- data/data/parg/ieee.json +1 -29571
- data/data/parg/ietf.json +1 -1
- data/data/parg/iho.json +1 -0
- data/data/parg/ire.json +1 -1
- data/data/parg/isbn.json +1 -1
- data/data/parg/iso.json +1 -8510
- data/data/parg/itu.json +1 -1
- data/data/parg/jcgm.json +1 -1
- data/data/parg/jis.json +1 -1
- data/data/parg/nesc.json +1 -1
- data/data/parg/nist.json +1 -9588
- data/data/parg/oasis.json +1 -1
- data/data/parg/ogc.json +1 -1
- data/data/parg/oiml.json +1 -1
- data/data/parg/omg.json +1 -1
- data/data/parg/parg.json +1 -1
- data/data/parg/plateau.json +1 -1
- data/data/parg/sae.json +1 -1
- data/data/parg/tables/typed_stages.yaml +1 -0
- data/data/parg/tgpp.json +1 -1
- data/data/parg/un.json +1 -1
- data/data/parg/w3c.json +1 -1
- data/data/parg/xsf.json +1 -1
- data/lib/pubid/adobe/identifier.rb +1 -1
- data/lib/pubid/adobe/parser.rb +2 -113
- data/lib/pubid/amca/identifiers/base.rb +1 -1
- data/lib/pubid/amca/parser.rb +1 -145
- data/lib/pubid/ansi/identifier.rb +1 -1
- data/lib/pubid/ansi/parser.rb +1 -82
- data/lib/pubid/api/builder.rb +32 -1
- data/lib/pubid/api/identifier.rb +1 -1
- data/lib/pubid/api/parser.rb +1 -131
- data/lib/pubid/ashrae/identifiers/base.rb +1 -1
- data/lib/pubid/ashrae/parser.rb +3 -710
- data/lib/pubid/asme/builder.rb +6 -4
- data/lib/pubid/asme/identifier.rb +1 -2
- data/lib/pubid/asme/parser.rb +1 -328
- data/lib/pubid/astm/builder.rb +12 -3
- data/lib/pubid/astm/identifier.rb +1 -2
- data/lib/pubid/astm/parser.rb +1 -227
- data/lib/pubid/bipm/identifier.rb +8 -1
- data/lib/pubid/bipm/parser.rb +2 -224
- data/lib/pubid/bsi/builder.rb +2 -4
- data/lib/pubid/bsi/parser.rb +1 -666
- data/lib/pubid/bsi/single_identifier.rb +38 -1
- data/lib/pubid/calconnect/identifier.rb +1 -1
- data/lib/pubid/calconnect/parser.rb +2 -40
- data/lib/pubid/ccsds/identifier.rb +1 -1
- data/lib/pubid/ccsds/parser.rb +1 -66
- data/lib/pubid/cen_cenelec/identifier.rb +16 -1
- data/lib/pubid/cen_cenelec/parser.rb +3 -136
- data/lib/pubid/cie/identifier.rb +1 -1
- data/lib/pubid/cie/parser.rb +3 -378
- data/lib/pubid/conformance.rb +1 -1
- data/lib/pubid/csa/builder.rb +41 -18
- data/lib/pubid/csa/identifier.rb +12 -4
- data/lib/pubid/csa/identifiers/amendment.rb +28 -0
- data/lib/pubid/csa/identifiers.rb +1 -0
- data/lib/pubid/csa/parser.rb +16 -397
- data/lib/pubid/doi/identifier.rb +1 -1
- data/lib/pubid/doi/parser.rb +2 -37
- data/lib/pubid/easc/builder.rb +1 -1
- data/lib/pubid/easc/identifier.rb +1 -1
- data/lib/pubid/easc/parser.rb +2 -70
- data/lib/pubid/ecma/CLAUDE.md +8 -1
- data/lib/pubid/ecma/identifier.rb +13 -8
- data/lib/pubid/ecma/parser.rb +2 -54
- data/lib/pubid/ecma/renderer.rb +3 -7
- data/lib/pubid/errors.rb +18 -13
- data/lib/pubid/etsi/builder.rb +8 -5
- data/lib/pubid/etsi/identifiers/base.rb +1 -1
- data/lib/pubid/etsi/parser.rb +1 -132
- data/lib/pubid/evs/identifier.rb +7 -0
- data/lib/pubid/evs/parser.rb +1 -8
- data/lib/pubid/evs.rb +1 -1
- data/lib/pubid/gb/identifier.rb +7 -1
- data/lib/pubid/gb/parser.rb +2 -51
- data/lib/pubid/gost/identifier.rb +9 -1
- data/lib/pubid/gost/parser.rb +4 -81
- data/lib/pubid/iala/parser.rb +2 -121
- data/lib/pubid/iana/identifier.rb +1 -1
- data/lib/pubid/iana/parser.rb +2 -24
- data/lib/pubid/identifier.rb +78 -1
- data/lib/pubid/idf/builder.rb +42 -0
- data/lib/pubid/idf/identifier.rb +1 -1
- data/lib/pubid/idf/parser.rb +1 -137
- data/lib/pubid/idf.rb +1 -2
- data/lib/pubid/iec/builder.rb +158 -50
- data/lib/pubid/iec/identifier.rb +1 -1
- data/lib/pubid/iec/parser.rb +3 -430
- data/lib/pubid/ieee/aiee/identifier.rb +2 -1
- data/lib/pubid/ieee/aiee.rb +0 -1
- data/lib/pubid/ieee/builder.rb +2 -2
- data/lib/pubid/ieee/identifiers/base.rb +1 -1
- data/lib/pubid/ieee/ire/identifier.rb +2 -1
- data/lib/pubid/ieee/ire.rb +0 -1
- data/lib/pubid/ieee/nesc.rb +0 -1
- data/lib/pubid/ieee/parser.rb +1 -1257
- data/lib/pubid/ietf/identifiers/base.rb +17 -1
- data/lib/pubid/ietf/parser.rb +2 -47
- data/lib/pubid/ietf/renderer.rb +17 -2
- data/lib/pubid/iho/CLAUDE.md +89 -0
- data/lib/pubid/iho/builder.rb +4 -1
- data/lib/pubid/iho/identifiers/base.rb +28 -2
- data/lib/pubid/iho/renderer.rb +8 -0
- data/lib/pubid/iho/urn_generator.rb +11 -1
- data/lib/pubid/iho/urn_parser.rb +21 -11
- data/lib/pubid/iho.rb +0 -1
- data/lib/pubid/isbn/identifier.rb +1 -1
- data/lib/pubid/isbn/parser.rb +2 -31
- data/lib/pubid/iso/builder.rb +1 -1
- data/lib/pubid/iso/identifiers/directives.rb +6 -3
- data/lib/pubid/iso/identifiers/guide.rb +6 -3
- data/lib/pubid/iso/identifiers/international_standard.rb +3 -1
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
- data/lib/pubid/iso/normalizer.rb +1 -1
- data/lib/pubid/iso/parser.rb +1 -539
- data/lib/pubid/iso/supplement_identifier.rb +6 -3
- data/lib/pubid/iso/utilities.rb +4 -5
- data/lib/pubid/iso.rb +1 -19
- data/lib/pubid/itu/builder.rb +36 -20
- data/lib/pubid/itu/identifiers/base.rb +15 -2
- data/lib/pubid/itu/parser.rb +1 -775
- data/lib/pubid/jcgm/builder.rb +35 -0
- data/lib/pubid/jcgm/parser.rb +1 -151
- data/lib/pubid/jcgm.rb +1 -2
- data/lib/pubid/jis/builder.rb +18 -29
- data/lib/pubid/jis/identifier.rb +1 -1
- data/lib/pubid/jis/parser.rb +1 -128
- data/lib/pubid/nist/builder.rb +5 -1
- data/lib/pubid/nist/caster.rb +13 -3
- data/lib/pubid/nist/identifiers/base.rb +37 -2
- data/lib/pubid/nist/identifiers/circular.rb +2 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
- data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
- data/lib/pubid/nist/identifiers/handbook.rb +2 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
- data/lib/pubid/nist/identifiers/monograph.rb +2 -2
- data/lib/pubid/nist/identifiers/report.rb +2 -2
- data/lib/pubid/nist/parser.rb +19 -775
- data/lib/pubid/nist/router.rb +4 -1
- data/lib/pubid/nist/supplement_identifier.rb +2 -2
- data/lib/pubid/oasis/identifier.rb +1 -1
- data/lib/pubid/oasis/parser.rb +2 -16
- data/lib/pubid/ogc/identifier.rb +1 -1
- data/lib/pubid/ogc/parser.rb +2 -26
- data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
- data/lib/pubid/oiml/parser.rb +1 -303
- data/lib/pubid/oiml.rb +1 -2
- data/lib/pubid/omg/identifier.rb +6 -1
- data/lib/pubid/omg/parser.rb +2 -76
- data/lib/pubid/parg/artifact.rb +22 -3
- data/lib/pubid/parg/model.rb +98 -0
- data/lib/pubid/parg.rb +1 -0
- data/lib/pubid/parser.rb +5 -4
- data/lib/pubid/parsers/mr_string.rb +1 -1
- data/lib/pubid/plateau/parser.rb +1 -66
- data/lib/pubid/plateau.rb +1 -2
- data/lib/pubid/renderers/directives_renderer.rb +1 -1
- data/lib/pubid/renderers/iwa_renderer.rb +1 -1
- data/lib/pubid/renderers/publisher_stripper.rb +82 -0
- data/lib/pubid/renderers/supplement_renderer.rb +1 -1
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/sae/identifiers/base.rb +1 -1
- data/lib/pubid/sae/parser.rb +1 -48
- data/lib/pubid/tgpp/identifier.rb +1 -1
- data/lib/pubid/tgpp/parser.rb +2 -59
- data/lib/pubid/un/identifier.rb +1 -1
- data/lib/pubid/un/parser.rb +1 -18
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/identifier.rb +1 -1
- data/lib/pubid/w3c/parser.rb +2 -27
- data/lib/pubid/xsf/identifier.rb +11 -7
- data/lib/pubid/xsf/parser.rb +3 -31
- data/lib/pubid/xsf/renderer.rb +2 -4
- data/lib/pubid.rb +8 -9
- metadata +15 -25
- data/lib/pubid/ieee/aiee/parser.rb +0 -130
- data/lib/pubid/ieee/ire/parser.rb +0 -109
- data/lib/pubid/ieee/nesc/parser.rb +0 -155
- data/lib/pubid/iho/parser.rb +0 -68
- data/lib/pubid/parser/common_parse_methods.rb +0 -13
- data/lib/pubid/parser/common_parse_rules.rb +0 -56
- data/lib/pubid/parser/grammar.rb +0 -96
data/lib/pubid/jcgm/builder.rb
CHANGED
|
@@ -24,7 +24,18 @@ module Pubid
|
|
|
24
24
|
Jcgm.locate_type(typed_stage.type_code)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# The bound grammar flattens the old `(base as base)` wrapper (the
|
|
28
|
+
# bindings cannot nest): the base document keeps the canonical
|
|
29
|
+
# number/date captures and the supplement layer captures
|
|
30
|
+
# supp_number/supp_date. Rebuild the nested shape the builder has
|
|
31
|
+
# always consumed — the base fields rename under :base and the
|
|
32
|
+
# supplement layer takes type_with_stage plus its own
|
|
33
|
+
# supp_number/supp_date, which is exactly the tree the
|
|
34
|
+
# amendment/corrigendum rules produced before the flatten.
|
|
35
|
+
SUPPLEMENT_STAGES = %w[Amd Cor Corrigendum].freeze
|
|
36
|
+
|
|
27
37
|
def build(parsed_hash)
|
|
38
|
+
parsed_hash = unflatten_supplement(parsed_hash)
|
|
28
39
|
klass = locate_identifier_klass(parsed_hash)
|
|
29
40
|
|
|
30
41
|
# GUM guides store their part number in the shared `number` attribute
|
|
@@ -52,6 +63,30 @@ module Pubid
|
|
|
52
63
|
|
|
53
64
|
private
|
|
54
65
|
|
|
66
|
+
def unflatten_supplement(parsed_hash)
|
|
67
|
+
stage = parsed_hash[:type_with_stage]
|
|
68
|
+
return parsed_hash if parsed_hash[:base] || stage.nil? ||
|
|
69
|
+
!SUPPLEMENT_STAGES.include?(stage)
|
|
70
|
+
|
|
71
|
+
base_hash = {}
|
|
72
|
+
%i[publisher number gum_number date languages].each do |key|
|
|
73
|
+
base_hash[key] = parsed_hash.delete(key) if parsed_hash[key]
|
|
74
|
+
end
|
|
75
|
+
stage = parsed_hash.delete(:type_with_stage)
|
|
76
|
+
supplement_hash = { type_with_stage: stage }
|
|
77
|
+
if parsed_hash[:supp_number]
|
|
78
|
+
supplement_hash[:number] = parsed_hash.delete(:supp_number)
|
|
79
|
+
end
|
|
80
|
+
if parsed_hash[:supp_date]
|
|
81
|
+
supplement_hash[:date] = parsed_hash.delete(:supp_date)
|
|
82
|
+
end
|
|
83
|
+
# Keep the base as a raw hash: the shared assign_attributes loop
|
|
84
|
+
# routes :base through cast, which recursively builds it — the
|
|
85
|
+
# same path the tree backend's nested subtree took.
|
|
86
|
+
supplement_hash[:base] = base_hash
|
|
87
|
+
parsed_hash.merge(supplement_hash)
|
|
88
|
+
end
|
|
89
|
+
|
|
55
90
|
def default_identifier_class
|
|
56
91
|
Identifiers::Guide
|
|
57
92
|
end
|
data/lib/pubid/jcgm/parser.rb
CHANGED
|
@@ -1,158 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Jcgm
|
|
7
|
-
class Parser
|
|
8
|
-
include ::Pubid::Parser::CommonParseRules
|
|
9
|
-
include ::Pubid::Parser::CommonParseMethods
|
|
10
|
-
|
|
11
|
-
root :identifier
|
|
12
|
-
|
|
13
|
-
rule(:identifier) do
|
|
14
|
-
meeting_identifier | amendment_identifier | corrigendum_identifier |
|
|
15
|
-
numbered_corrigendum_identifier | base | named_guide_identifier
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# "JCGM 200:2008 Corrigendum" — a base guide plus a trailing
|
|
19
|
-
# " Corrigendum" word (no number). Must precede base: Parslet
|
|
20
|
-
# is an ordered PEG that commits to the first matching alternative, so if
|
|
21
|
-
# base ran first it would consume "JCGM 200:2008" and root
|
|
22
|
-
# would fail on the leftover " Corrigendum". Emits type_with_stage so the
|
|
23
|
-
# builder routes it to Corrigendum.
|
|
24
|
-
rule(:corrigendum_identifier) do
|
|
25
|
-
base.as(:base) >> space >>
|
|
26
|
-
str("Corrigendum").as(:type_with_stage)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# "JCGM 101:2008/Cor 1:2009" — a base guide plus a slash-separated
|
|
30
|
-
# numbered corrigendum (mirrors the ISO/IEC supplement form). The
|
|
31
|
-
# trailing :YYYY is optional so "JCGM 101:2008/Cor 1" also parses.
|
|
32
|
-
# Must precede base for the same PEG-commit reason as corrigendum_identifier.
|
|
33
|
-
rule(:numbered_corrigendum_identifier) do
|
|
34
|
-
base.as(:base) >>
|
|
35
|
-
str("/") >> str("Cor").as(:type_with_stage) >>
|
|
36
|
-
supplement_separator >> digits.as(:number) >>
|
|
37
|
-
corrigendum_date.maybe
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# "Amd 1" and the dotted "Amd.1:2026" BIPM prints on its
|
|
41
|
-
# publications page (bipm.org, JCGM 100:2008/Amd.1:2026) are both
|
|
42
|
-
# accepted on input; rendering stays "Amd 1".
|
|
43
|
-
rule(:supplement_separator) do
|
|
44
|
-
space | (str(".") >> space.maybe)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Dateless "named" guides: "JCGM GUM", "JCGM VIM-3" (and future "VIM-N").
|
|
48
|
-
# Last in the alternation — only reached when base fully fails
|
|
49
|
-
# (these have no date, so number_portion/date_portion never match).
|
|
50
|
-
rule(:named_guide_identifier) do
|
|
51
|
-
publisher >> space >> named_number
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
rule(:named_number) do
|
|
55
|
-
(str("GUM") | (str("VIM") >> (str("-") >> digits).maybe)).as(:number)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Committee/meeting record, e.g. "JCGM 17th Meeting (2012)". Diverges
|
|
59
|
-
# from base right after the digits (base wants ":", meeting
|
|
60
|
-
# wants the ordinal suffix), so ordered choice is unambiguous. Emits the
|
|
61
|
-
# same tokens as a guide plus type_with_stage "Meeting", so the generic
|
|
62
|
-
# builder path resolves it to Identifiers::Meeting (like "Amd").
|
|
63
|
-
#
|
|
64
|
-
# The trailing " (YYYY)" group is optional, so the partial reference
|
|
65
|
-
# "JCGM 11st Meeting" parses with `date` left nil. JCGM numbers its
|
|
66
|
-
# meetings in one sequence, so the ordinal alone names the event and the
|
|
67
|
-
# year is redundant detail. The whole group is `.maybe` (not the year
|
|
68
|
-
# inside it), so a dangling "(" or a truncated year still fails —
|
|
69
|
-
# the same shape as `date_portion.maybe` in `rule(:base)`.
|
|
70
|
-
rule(:meeting_identifier) do
|
|
71
|
-
publisher >> space >> digits.as(:number) >> ordinal_suffix >>
|
|
72
|
-
space >> str("Meeting").as(:type_with_stage) >>
|
|
73
|
-
(space >> str("(") >> year_digits.as(:date) >> str(")")).maybe
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
rule(:ordinal_suffix) do
|
|
77
|
-
str("st") | str("nd") | str("rd") | str("th")
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# `date_portion` is optional so a partial reference that omits the
|
|
81
|
-
# trailing `:YYYY` date (e.g. "JCGM 100") parses with `date` left nil,
|
|
82
|
-
# letting relaton match a collection via `matches?(row, ignore: [:date])`.
|
|
83
|
-
# The whole sub-rule is `.maybe` (not the year inside it) so a dangling
|
|
84
|
-
# ":" still fails. Mirrors ETSI (lib/pubid/etsi/parser.rb).
|
|
85
|
-
rule(:base) do
|
|
86
|
-
publisher >> space >> number_portion >>
|
|
87
|
-
date_portion.maybe >> language_portion.maybe
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
rule(:amendment_identifier) do
|
|
91
|
-
base.as(:base) >>
|
|
92
|
-
str("/") >> amendment_type >>
|
|
93
|
-
supplement_separator >> digits.as(:number) >>
|
|
94
|
-
amendment_date.maybe
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
rule(:publisher) do
|
|
98
|
-
str("JCGM").as(:publisher)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# Number can be plain (100, 200) or GUM-prefixed (GUM-1, GUM-6)
|
|
102
|
-
rule(:number_portion) do
|
|
103
|
-
gum_number | standard_number
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
rule(:standard_number) do
|
|
107
|
-
digits.as(:number)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
rule(:gum_number) do
|
|
111
|
-
str("GUM-") >> digits.as(:gum_number)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Date can be YYYY or YYYY-MM-DD
|
|
115
|
-
rule(:date_portion) do
|
|
116
|
-
str(":") >> (full_date | year_only)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
rule(:year_only) do
|
|
120
|
-
year_digits.as(:date)
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
rule(:full_date) do
|
|
124
|
-
(year_digits >> str("-") >> month_digits >> str("-") >> day_digits).as(:date)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# Language: "(E)", "(F)", "(E/F)", "(F/E)"
|
|
128
|
-
rule(:language_portion) do
|
|
129
|
-
str("(") >>
|
|
130
|
-
(
|
|
131
|
-
# Multi-language: E/F, F/E
|
|
132
|
-
(str("E/F") | str("F/E")) |
|
|
133
|
-
# Single language: E, F, R, etc.
|
|
134
|
-
match("[A-Z]")
|
|
135
|
-
).as(:languages) >>
|
|
136
|
-
str(")")
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# Amendment support
|
|
140
|
-
rule(:amendment_type) do
|
|
141
|
-
str("Amd").as(:type_with_stage)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
rule(:amendment_number) do
|
|
145
|
-
digits.as(:number)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
rule(:amendment_date) do
|
|
149
|
-
str(":") >> (full_date | year_only)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# Numbered corrigendum date: same shape as amendment_date.
|
|
153
|
-
rule(:corrigendum_date) do
|
|
154
|
-
str(":") >> (full_date | year_only)
|
|
155
|
-
end
|
|
5
|
+
class Parser
|
|
156
6
|
end
|
|
157
7
|
end
|
|
158
8
|
end
|
data/lib/pubid/jcgm.rb
CHANGED
|
@@ -32,10 +32,9 @@ module Pubid
|
|
|
32
32
|
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
parser = Parser.new
|
|
36
35
|
builder = Builder.new
|
|
37
36
|
|
|
38
|
-
parsed = Pubid::Parg::
|
|
37
|
+
parsed = Pubid::Parg::Model.bound(:jcgm, identifier)
|
|
39
38
|
builder.build(parsed)
|
|
40
39
|
end
|
|
41
40
|
|
data/lib/pubid/jis/builder.rb
CHANGED
|
@@ -9,12 +9,14 @@ module Pubid
|
|
|
9
9
|
|
|
10
10
|
def build(data)
|
|
11
11
|
# Handle supplement case first; the SYMBOL clause (if any) attaches to
|
|
12
|
-
# the outermost identifier, be it the base or the supplement.
|
|
13
|
-
|
|
12
|
+
# the outermost identifier, be it the base or the supplement. The
|
|
13
|
+
# bindings bind the supplement's fields flat (amd_type/amd_number/…),
|
|
14
|
+
# so their presence marks the supplement kind.
|
|
15
|
+
identifier = if data[:amd_type]
|
|
14
16
|
build_amendment(data)
|
|
15
|
-
elsif data[:
|
|
17
|
+
elsif data[:expl_type]
|
|
16
18
|
build_explanation(data)
|
|
17
|
-
elsif data[:
|
|
19
|
+
elsif data[:corr_type]
|
|
18
20
|
build_corrigendum(data)
|
|
19
21
|
else
|
|
20
22
|
build_single_identifier(data)
|
|
@@ -58,49 +60,36 @@ module Pubid
|
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def build_amendment(data)
|
|
61
|
-
|
|
63
|
+
# The bindings carry the supplement's fields at the top level; the
|
|
64
|
+
# base document shares them.
|
|
65
|
+
base = build_single_identifier(data)
|
|
62
66
|
|
|
63
|
-
# Build base document (without supplement)
|
|
64
|
-
base_data = data.except(:amendment)
|
|
65
|
-
base = build_single_identifier(base_data)
|
|
66
|
-
|
|
67
|
-
# Build amendment
|
|
68
67
|
Identifiers::Amendment.new(
|
|
69
68
|
base: base,
|
|
70
|
-
number:
|
|
71
|
-
year:
|
|
72
|
-
reaffirmed: (true if
|
|
69
|
+
number: data[:amd_number].to_i,
|
|
70
|
+
year: data[:amd_year].to_i,
|
|
71
|
+
reaffirmed: (true if data[:amd_reaffirmed]),
|
|
73
72
|
)
|
|
74
73
|
end
|
|
75
74
|
|
|
76
75
|
def build_explanation(data)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# Build base document (without supplement)
|
|
80
|
-
base_data = data.except(:explanation)
|
|
81
|
-
base = build_single_identifier(base_data)
|
|
76
|
+
base = build_single_identifier(data)
|
|
82
77
|
|
|
83
|
-
# Build explanation
|
|
84
78
|
Identifiers::Explanation.new(
|
|
85
79
|
base: base,
|
|
86
|
-
number:
|
|
80
|
+
number: data[:expl_number]&.to_i,
|
|
87
81
|
year: base.year,
|
|
88
82
|
)
|
|
89
83
|
end
|
|
90
84
|
|
|
91
85
|
def build_corrigendum(data)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
# Build base document (without supplement)
|
|
95
|
-
base_data = data.except(:corrigendum)
|
|
96
|
-
base = build_single_identifier(base_data)
|
|
86
|
+
base = build_single_identifier(data)
|
|
97
87
|
|
|
98
|
-
# Build corrigendum
|
|
99
88
|
Identifiers::Corrigendum.new(
|
|
100
89
|
base: base,
|
|
101
|
-
number:
|
|
102
|
-
year:
|
|
103
|
-
reaffirmed: (true if
|
|
90
|
+
number: data[:corr_number].to_i,
|
|
91
|
+
year: data[:corr_year].to_i,
|
|
92
|
+
reaffirmed: (true if data[:corr_reaffirmed]),
|
|
104
93
|
)
|
|
105
94
|
end
|
|
106
95
|
|
data/lib/pubid/jis/identifier.rb
CHANGED
|
@@ -174,7 +174,7 @@ module Pubid
|
|
|
174
174
|
raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
parsed = Pubid::Parg::
|
|
177
|
+
parsed = Pubid::Parg::Model.bound(:jis, identifier)
|
|
178
178
|
Builder.build(parsed)
|
|
179
179
|
end
|
|
180
180
|
end
|
data/lib/pubid/jis/parser.rb
CHANGED
|
@@ -1,135 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Jis
|
|
7
|
-
class Parser
|
|
8
|
-
# Japanese character normalization
|
|
9
|
-
rule(:jp_dash) { str("ー") } # Full-width dash
|
|
10
|
-
rule(:jp_space) { str(" ") } # Full-width space
|
|
11
|
-
rule(:jp_colon) { str(":") } # Full-width colon
|
|
12
|
-
rule(:jp_lparen) { str("(") }
|
|
13
|
-
rule(:jp_rparen) { str(")") }
|
|
14
|
-
|
|
15
|
-
# Normalized separators
|
|
16
|
-
rule(:dash) { (str("-") | jp_dash).as(:dash) }
|
|
17
|
-
rule(:space) { str(" ") | jp_space }
|
|
18
|
-
rule(:colon) { str(":") | jp_colon }
|
|
19
|
-
|
|
20
|
-
# Basic elements
|
|
21
|
-
rule(:digit) { match["0-9"] }
|
|
22
|
-
rule(:digits) { digit.repeat(1) }
|
|
23
|
-
rule(:letter) { match["A-Z"] }
|
|
24
|
-
|
|
25
|
-
# JIS prefix (optional, handles both "JIS " and "JIS/")
|
|
26
|
-
rule(:jis_prefix) { str("JIS") >> (space | str("/")).maybe }
|
|
27
|
-
|
|
28
|
-
# Type prefix (TR or TS, can come with or without slash)
|
|
29
|
-
rule(:type_prefix) do
|
|
30
|
-
(str("TR") | str("TS")).as(:type) >> (space | str("/"))
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Series letter
|
|
34
|
-
rule(:series) { letter.as(:series) }
|
|
35
|
-
|
|
36
|
-
# Number (preserve as string to maintain leading zeros)
|
|
37
|
-
rule(:number) { digits.as(:number) }
|
|
38
|
-
|
|
39
|
-
# Parts (multi-level: -1, -2-1, -3-2-1, etc.)
|
|
40
|
-
rule(:part) do
|
|
41
|
-
dash >> digits.as(:part)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
rule(:parts) { part.repeat(0).as(:parts) }
|
|
45
|
-
|
|
46
|
-
# Reaffirmation marker (再確認): trailing "R" on a year
|
|
47
|
-
rule(:reaffirmed) { str("R").maybe.as(:reaffirmed) }
|
|
48
|
-
|
|
49
|
-
# Year
|
|
50
|
-
rule(:year) do
|
|
51
|
-
colon >> digits.as(:year) >> reaffirmed
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Language code
|
|
55
|
-
rule(:language) do
|
|
56
|
-
(str("(") | jp_lparen) >>
|
|
57
|
-
match["EJ"].as(:language) >>
|
|
58
|
-
(str(")") | jp_rparen)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# All-parts notation (Japanese)
|
|
62
|
-
rule(:all_parts) do
|
|
63
|
-
((jp_lparen >> str("規格群") >> jp_rparen) |
|
|
64
|
-
(str("(") >> str("規格群") >> str(")"))).as(:all_parts)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Amendment supplement
|
|
68
|
-
rule(:amendment) do
|
|
69
|
-
str("/") >>
|
|
70
|
-
(str("AMENDMENT") | str("AMD")).as(:amd_type) >>
|
|
71
|
-
space >>
|
|
72
|
-
digits.as(:amd_number) >>
|
|
73
|
-
colon >>
|
|
74
|
-
digits.as(:amd_year) >>
|
|
75
|
-
str("R").maybe.as(:amd_reaffirmed)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Explanation supplement
|
|
79
|
-
rule(:explanation) do
|
|
80
|
-
str("/") >>
|
|
81
|
-
(str("EXPLANATION") | str("EXPL")).as(:expl_type) >>
|
|
82
|
-
(space >> digits.as(:expl_number)).maybe
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Corrigendum supplement
|
|
86
|
-
rule(:corrigendum) do
|
|
87
|
-
str("/") >>
|
|
88
|
-
(str("CORRIGENDUM") | str("CORR")).as(:corr_type) >>
|
|
89
|
-
space >>
|
|
90
|
-
digits.as(:corr_number) >>
|
|
91
|
-
colon >>
|
|
92
|
-
digits.as(:corr_year) >>
|
|
93
|
-
str("R").maybe.as(:corr_reaffirmed)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Supplements (AMD, EXPL or CORRIGENDUM, only one for JIS)
|
|
97
|
-
rule(:supplement) do
|
|
98
|
-
amendment.as(:amendment) | explanation.as(:explanation) |
|
|
99
|
-
corrigendum.as(:corrigendum)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Graphical-symbol sub-reference (e.g. JIS Z 8210 safety signs):
|
|
103
|
-
# "SYMBOL <id>" where <id> runs to the end of the string and may be a
|
|
104
|
-
# number, an alphanumeric code or a free-text phrase. The keyword may
|
|
105
|
-
# also appear bare with no value.
|
|
106
|
-
rule(:symbol_clause) do
|
|
107
|
-
space >> str("SYMBOL").as(:symbol_present) >>
|
|
108
|
-
(space >> match["^\n"].repeat(1).as(:symbol_value)).maybe
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Main identifier
|
|
112
|
-
rule(:identifier) do
|
|
113
|
-
jis_prefix.maybe >>
|
|
114
|
-
type_prefix.maybe >>
|
|
115
|
-
space.maybe >>
|
|
116
|
-
series >>
|
|
117
|
-
space.maybe >>
|
|
118
|
-
number >>
|
|
119
|
-
parts >>
|
|
120
|
-
year.maybe >>
|
|
121
|
-
language.maybe >>
|
|
122
|
-
all_parts.maybe >>
|
|
123
|
-
supplement.maybe >>
|
|
124
|
-
symbol_clause.maybe
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
rule(:root) { identifier }
|
|
128
|
-
|
|
129
|
-
# Parse and normalize Japanese characters
|
|
130
|
-
def self.parse(input)
|
|
131
|
-
new.parse(input)
|
|
132
|
-
end
|
|
5
|
+
class Parser
|
|
133
6
|
end
|
|
134
7
|
end
|
|
135
8
|
end
|
data/lib/pubid/nist/builder.rb
CHANGED
|
@@ -85,9 +85,13 @@ module Pubid
|
|
|
85
85
|
|
|
86
86
|
# NEW: Check for CIRC supplement pattern
|
|
87
87
|
# Note: :base_portion is lost during parser merge, so check for supplement indicators
|
|
88
|
+
# circ_series routes the bare "NBS.CIRC.sup" form: the edition-2
|
|
89
|
+
# grammar cannot carry the zero-width supplement_empty marker the
|
|
90
|
+
# Parslet tree used, and the series capture marks every circular
|
|
91
|
+
# supplement head.
|
|
88
92
|
if parsed_hash[:supplement_date_range] || parsed_hash[:supplement_slash_year] ||
|
|
89
93
|
parsed_hash[:supplement_month_year] || parsed_hash[:supplement_year] ||
|
|
90
|
-
parsed_hash[:supplement_empty] ||
|
|
94
|
+
parsed_hash[:supplement_empty] || parsed_hash[:circ_series] ||
|
|
91
95
|
parsed_hash[:supplement] || parsed_hash[:base_portion]
|
|
92
96
|
return build_circular_supplement(parsed_hash)
|
|
93
97
|
end
|
data/lib/pubid/nist/caster.rb
CHANGED
|
@@ -128,7 +128,16 @@ module Pubid
|
|
|
128
128
|
id: value[:owmwp_year])
|
|
129
129
|
{ first_number: Components::Code.new(value: number_part), edition: edition_part }
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
# The polymorphic number wrappers split per branch in the grammar
|
|
132
|
+
# (asme's designator/designator_code pattern): first_number /
|
|
133
|
+
# second_number (string) arrive over the bare branches,
|
|
134
|
+
# first_number_composite / second_number_composite (raw) over the
|
|
135
|
+
# branches carrying inner captures. The composite keys map onto
|
|
136
|
+
# the same dispatch.
|
|
137
|
+
when :first_number, :first_number_composite, :second_number,
|
|
138
|
+
:second_number_composite
|
|
139
|
+
type = :first_number if type == :first_number_composite
|
|
140
|
+
type = :second_number if type == :second_number_composite
|
|
132
141
|
return nil if value.nil? || value.to_s.strip.empty?
|
|
133
142
|
|
|
134
143
|
# NEW: Handle OWMWP date-based number (nested hash structure)
|
|
@@ -1039,8 +1048,9 @@ module Pubid
|
|
|
1039
1048
|
|
|
1040
1049
|
when :edition_month, :edition_year, :edition_day, :edition_has_rev
|
|
1041
1050
|
# These work together: edition_month + edition_year -> single edition ID
|
|
1042
|
-
# Skip processing if this is edition_month
|
|
1043
|
-
|
|
1051
|
+
# Skip processing if this is edition_month or edition_day alone
|
|
1052
|
+
# (both are consumed by the edition_year branch via parsed_hash)
|
|
1053
|
+
return nil if type == :edition_month || type == :edition_day
|
|
1044
1054
|
|
|
1045
1055
|
# Process edition_year, combining with edition_month if present
|
|
1046
1056
|
return nil if value.nil? || value.to_s.strip.empty?
|
|
@@ -346,7 +346,7 @@ module Pubid
|
|
|
346
346
|
# @param format [:full, :long, :abbreviated, :short, :mr] output format
|
|
347
347
|
def to_s(format = nil)
|
|
348
348
|
# Handle both keyword argument (hash) and positional argument (symbol/string)
|
|
349
|
-
|
|
349
|
+
flags = plain_render_flags(format)
|
|
350
350
|
format = format[:format] if format.is_a?(Hash)
|
|
351
351
|
|
|
352
352
|
# Default to parsed_format if available (preserves input format on round-trip)
|
|
@@ -358,7 +358,42 @@ module Pubid
|
|
|
358
358
|
# NIST's `to_s` takes a POSITIONAL format and its `render` override
|
|
359
359
|
# builds no rendering context, so neither the flag nor the context
|
|
360
360
|
# reaches the shared hook. Apply the annotation fallback here.
|
|
361
|
-
annotate_plain_render(rendered,
|
|
361
|
+
annotate_plain_render(rendered, **flags)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# The keyword flags a positional-format `to_s` hands to
|
|
365
|
+
# `annotate_plain_render`. Ruby fills the positional `format` with a
|
|
366
|
+
# Hash when a caller passes keywords, so they arrive here.
|
|
367
|
+
#
|
|
368
|
+
# `with_publisher: false` cuts the leading `NIST`/`NBS` from the
|
|
369
|
+
# finished string ({#publisher_prefixes}), which covers every place a
|
|
370
|
+
# NIST style prints a publisher — the compound `NBS …` series, the
|
|
371
|
+
# `default_publisher` subclasses and a supplement's base — in one
|
|
372
|
+
# step.
|
|
373
|
+
def plain_render_flags(format)
|
|
374
|
+
return {} unless format.is_a?(Hash)
|
|
375
|
+
|
|
376
|
+
format.slice(:annotated, :with_publisher)
|
|
377
|
+
end
|
|
378
|
+
private :plain_render_flags
|
|
379
|
+
|
|
380
|
+
# The MR style (`NIST.SP.800-53`) is a fixed machine form and ignores
|
|
381
|
+
# `with_publisher:`. The test reads the OUTPUT, not the requested
|
|
382
|
+
# format: several subclasses pick their style themselves (an id parsed
|
|
383
|
+
# from an MR string still renders the short style), so the format a
|
|
384
|
+
# caller asked for does not say which style came back.
|
|
385
|
+
def apply_with_publisher(result, format, with_publisher)
|
|
386
|
+
mr_style = result.is_a?(String) && result.match?(/\A(?:NIST|NBS)\./)
|
|
387
|
+
return result if mr_style
|
|
388
|
+
|
|
389
|
+
super
|
|
390
|
+
end
|
|
391
|
+
private :apply_with_publisher
|
|
392
|
+
|
|
393
|
+
# Every leading publisher token a NIST short style can print: the
|
|
394
|
+
# parsed publisher, and the two `default_publisher` values.
|
|
395
|
+
def publisher_prefixes
|
|
396
|
+
[publisher.to_s, "NIST", "NBS"]
|
|
362
397
|
end
|
|
363
398
|
|
|
364
399
|
# NIST has its own defined MR format (to_mr_style) used by relaton-nist
|
|
@@ -57,7 +57,7 @@ module Pubid
|
|
|
57
57
|
# string: with the flag set, `super` returns a string ending in
|
|
58
58
|
# "</span>" and the anchor no longer matches. Render plain, rewrite,
|
|
59
59
|
# then annotate.
|
|
60
|
-
|
|
60
|
+
flags = plain_render_flags(format)
|
|
61
61
|
format = format[:format] if format.is_a?(Hash)
|
|
62
62
|
|
|
63
63
|
result = super(format)
|
|
@@ -72,7 +72,7 @@ module Pubid
|
|
|
72
72
|
"e#{edition.id || '?'}.#{edition.additional_text}")
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
annotate_plain_render(result,
|
|
75
|
+
annotate_plain_render(result, **flags)
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
end
|
|
@@ -41,7 +41,7 @@ module Pubid
|
|
|
41
41
|
# Hash. Normalise it away before `super`, so the annotation is applied
|
|
42
42
|
# once, here, and covers the date-range branch too — that branch
|
|
43
43
|
# returns a hand-composed string and never reached `super` at all.
|
|
44
|
-
|
|
44
|
+
flags = plain_render_flags(format)
|
|
45
45
|
format = format[:format] || :short if format.is_a?(Hash)
|
|
46
46
|
|
|
47
47
|
# Handle date range supplements (no base identifier)
|
|
@@ -52,7 +52,7 @@ module Pubid
|
|
|
52
52
|
super(format)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
annotate_plain_render(result,
|
|
55
|
+
annotate_plain_render(result, **flags)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -45,7 +45,7 @@ module Pubid
|
|
|
45
45
|
# a Hash — Ruby converts keywords for a method that accepts none.
|
|
46
46
|
# The same idiom `Identifiers::Base#to_s` uses. This renderer
|
|
47
47
|
# ignores `format`, so only the flag is read.
|
|
48
|
-
|
|
48
|
+
flags = plain_render_flags(format)
|
|
49
49
|
|
|
50
50
|
result = "#{publisher} #{series}"
|
|
51
51
|
|
|
@@ -61,7 +61,7 @@ module Pubid
|
|
|
61
61
|
result += " #{vol_str}n#{issue_number.number}"
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
annotate_plain_render(result,
|
|
64
|
+
annotate_plain_render(result, **flags)
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
end
|
|
@@ -91,7 +91,7 @@ module Pubid
|
|
|
91
91
|
# a Hash — Ruby converts keywords for a method that accepts none.
|
|
92
92
|
# The same idiom `Identifiers::Base#to_s` uses. This renderer
|
|
93
93
|
# ignores `format`, so only the flag is read.
|
|
94
|
-
|
|
94
|
+
flags = plain_render_flags(format)
|
|
95
95
|
|
|
96
96
|
# Use actual series attribute if it contains subseries (e.g., "CRPL-F-B")
|
|
97
97
|
# Otherwise use default series_code ("CRPL")
|
|
@@ -129,7 +129,7 @@ module Pubid
|
|
|
129
129
|
result += append_short_components
|
|
130
130
|
|
|
131
131
|
result += range_notation if range_notation
|
|
132
|
-
annotate_plain_render(result,
|
|
132
|
+
annotate_plain_render(result, **flags)
|
|
133
133
|
end
|
|
134
134
|
end
|
|
135
135
|
end
|
|
@@ -38,7 +38,7 @@ module Pubid
|
|
|
38
38
|
# string: with the flag set, `super` returns a string ending in
|
|
39
39
|
# "</span>" and the anchor no longer matches. Render plain, rewrite,
|
|
40
40
|
# then annotate.
|
|
41
|
-
|
|
41
|
+
flags = plain_render_flags(format)
|
|
42
42
|
format = format[:format] if format.is_a?(Hash)
|
|
43
43
|
|
|
44
44
|
# Use the base to_s method first
|
|
@@ -50,7 +50,7 @@ module Pubid
|
|
|
50
50
|
"#{edition.type}#{edition.id}-#{edition.additional_text}")
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
annotate_plain_render(result,
|
|
53
|
+
annotate_plain_render(result, **flags)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
end
|
|
@@ -40,7 +40,7 @@ module Pubid
|
|
|
40
40
|
# `super` is handed a SYMBOL below, so the base's annotation hook
|
|
41
41
|
# never sees the flag. Capture it here and wrap what comes back —
|
|
42
42
|
# exactly once, because the base returned plain text.
|
|
43
|
-
|
|
43
|
+
flags = plain_render_flags(format)
|
|
44
44
|
|
|
45
45
|
# Handle both keyword argument (hash) and positional argument (symbol/string)
|
|
46
46
|
effective_format = if format.is_a?(Hash)
|
|
@@ -56,7 +56,7 @@ module Pubid
|
|
|
56
56
|
super(effective_format)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
annotate_plain_render(rendered,
|
|
59
|
+
annotate_plain_render(rendered, **flags)
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|