pubid 2.0.1 → 2.0.3
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/ieee/update_codes.yaml +2 -2
- data/data/parg/adobe.json +1 -1
- data/data/parg/aiee.json +1 -1
- data/data/parg/aiee.parg +99 -9
- 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/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/ecma.json +1 -1
- data/data/parg/etsi.json +1 -1
- data/data/parg/evs.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 -1
- data/data/parg/iho.json +1 -0
- data/data/parg/ire.json +1 -1
- data/data/parg/ire.parg +51 -12
- data/data/parg/isbn.json +1 -1
- data/data/parg/iso.json +1 -1
- data/data/parg/iso.parg +751 -0
- 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/nesc.parg +97 -12
- data/data/parg/nist.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/tgpp.json +1 -1
- data/data/parg/un.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/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/parser.rb +2 -37
- data/lib/pubid/easc/builder.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 +6 -0
- 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/builder.rb +48 -39
- data/lib/pubid/iala/identifier.rb +1 -1
- 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/CLAUDE.md +2 -0
- data/lib/pubid/ieee/aiee/identifier.rb +2 -1
- data/lib/pubid/ieee/aiee.rb +0 -1
- data/lib/pubid/ieee/builder.rb +177 -30
- data/lib/pubid/ieee/components/code.rb +46 -7
- data/lib/pubid/ieee/identifiers/base.rb +5 -2
- data/lib/pubid/ieee/identifiers/joint_development.rb +7 -3
- data/lib/pubid/ieee/ire/identifier.rb +2 -1
- data/lib/pubid/ieee/ire.rb +0 -1
- data/lib/pubid/ieee/nesc/builder.rb +1 -1
- data/lib/pubid/ieee/nesc.rb +0 -1
- data/lib/pubid/ieee/parser.rb +1 -1257
- data/lib/pubid/ieee/project_renderer.rb +5 -1
- data/lib/pubid/ieee/renderer.rb +4 -2
- data/lib/pubid/ieee/urn_generator.rb +4 -1
- 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 +98 -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 +14 -1
- data/lib/pubid/iho/urn_parser.rb +45 -32
- 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/CLAUDE.md +66 -0
- data/lib/pubid/iso/builder.rb +229 -15
- data/lib/pubid/iso/identifier.rb +22 -12
- data/lib/pubid/iso/identifiers/directives.rb +6 -3
- data/lib/pubid/iso/identifiers/guide.rb +6 -3
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
- data/lib/pubid/iso/normalizer.rb +5 -4
- data/lib/pubid/iso/parser.rb +1 -539
- data/lib/pubid/iso/supplement_identifier.rb +6 -3
- data/lib/pubid/iso/urn_parser.rb +13 -8
- 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/CLAUDE.md +36 -0
- data/lib/pubid/jis/builder.rb +30 -41
- data/lib/pubid/jis/identifier.rb +12 -2
- data/lib/pubid/jis/identifiers/welding_engineering_standard.rb +35 -0
- data/lib/pubid/jis/identifiers.rb +2 -0
- data/lib/pubid/jis/parser.rb +1 -128
- data/lib/pubid/jis/renderer.rb +1 -1
- data/lib/pubid/jis/supplement_identifier.rb +5 -5
- data/lib/pubid/jis/urn_parser.rb +2 -1
- data/lib/pubid/jis.rb +3 -2
- 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/parser.rb +2 -16
- 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/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/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/parser.rb +2 -27
- data/lib/pubid/xsf/identifier.rb +10 -6
- data/lib/pubid/xsf/parser.rb +3 -31
- data/lib/pubid/xsf/renderer.rb +2 -4
- data/lib/pubid.rb +8 -9
- metadata +9 -23
- 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/ecma/parser.rb
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Ecma
|
|
7
|
-
#
|
|
5
|
+
# Grammar for ECMA identifiers.
|
|
8
6
|
#
|
|
9
7
|
# Four printed forms:
|
|
10
8
|
# ECMA-411 standard
|
|
@@ -20,57 +18,7 @@ module Pubid
|
|
|
20
18
|
# Each branch captures its number under a distinct key so the builder can
|
|
21
19
|
# pick the identifier class without a separate type token. Numbers are kept
|
|
22
20
|
# as strings to preserve any leading zeros.
|
|
23
|
-
class Parser
|
|
24
|
-
rule(:digits) { match["0-9"].repeat(1) }
|
|
25
|
-
|
|
26
|
-
rule(:prefix) { str("ECMA") }
|
|
27
|
-
|
|
28
|
-
rule(:tr) { str(" TR/") >> digits.as(:tr_number) }
|
|
29
|
-
|
|
30
|
-
rule(:mem) { str(" MEM/") >> digits.as(:mem_number) }
|
|
31
|
-
|
|
32
|
-
# Standards print with a hyphen ("ECMA-6"), but references are commonly
|
|
33
|
-
# written with a space ("ECMA 6"). Both parse; the renderer normalises to
|
|
34
|
-
# the hyphen, so the space form round-trips as "ECMA-6" by design and must
|
|
35
|
-
# never enter the byte-exact `pass` fixtures.
|
|
36
|
-
rule(:standard_separator) { str("-") | str(" ") }
|
|
37
|
-
|
|
38
|
-
rule(:standard) do
|
|
39
|
-
standard_separator >> digits.as(:number) >>
|
|
40
|
-
(str("-") >> digits.as(:part)).maybe
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Editions are not all integers: ECMA-402 ed5.1 is a real document. The
|
|
44
|
-
# value is stored verbatim so it renders and serializes unchanged.
|
|
45
|
-
rule(:edition_number) { digits >> (str(".") >> digits).repeat(0) }
|
|
46
|
-
|
|
47
|
-
rule(:edition) { str(" ed") >> edition_number.as(:edition) }
|
|
48
|
-
|
|
49
|
-
rule(:volume) { str(" vol") >> digits.as(:volume) }
|
|
50
|
-
|
|
51
|
-
# The suffixes attach AFTER the type alternation, so a technical report
|
|
52
|
-
# and a memento carry them exactly as a standard does.
|
|
53
|
-
#
|
|
54
|
-
# Two PEG facts this arrangement depends on:
|
|
55
|
-
#
|
|
56
|
-
# 1. `standard` cannot shadow " TR/" or " MEM/", because after the space
|
|
57
|
-
# it demands a digit and "T"/"M" are not digits. Keeping tr|mem first
|
|
58
|
-
# is belt-and-braces; the DISJOINT FIRST CHARACTER is the load-bearing
|
|
59
|
-
# invariant.
|
|
60
|
-
# 2. Appending a sequence moves the alternation out of tail position, so
|
|
61
|
-
# Parslet no longer threads consume_all into it and will not backtrack
|
|
62
|
-
# into an alternative that already succeeded. A future branch that
|
|
63
|
-
# could match a proper prefix of another branch's input would now fail
|
|
64
|
-
# the whole parse instead of being rescued by the next alternative.
|
|
65
|
-
rule(:identifier) do
|
|
66
|
-
prefix >> (tr | mem | standard) >> edition.maybe >> volume.maybe
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
rule(:root) { identifier }
|
|
70
|
-
|
|
71
|
-
def self.parse(input)
|
|
72
|
-
new.parse(input)
|
|
73
|
-
end
|
|
21
|
+
class Parser
|
|
74
22
|
end
|
|
75
23
|
end
|
|
76
24
|
end
|
data/lib/pubid/ecma/renderer.rb
CHANGED
|
@@ -11,8 +11,8 @@ module Pubid
|
|
|
11
11
|
# "ECMA MEM/1970" memento
|
|
12
12
|
# "ECMA-269 ed3 vol2" with the edition and volume suffixes
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
14
|
+
# The ECMA token is part of the designation and is always rendered; see
|
|
15
|
+
# `Pubid::Ecma::Identifier#publisher_prefixes`.
|
|
16
16
|
class Renderer < ::Pubid::Renderers::Base
|
|
17
17
|
PUBLISHER = "ECMA"
|
|
18
18
|
|
|
@@ -32,7 +32,7 @@ module Pubid
|
|
|
32
32
|
# with a space ("ECMA TR/101"). type_prefix is nil only for standards.
|
|
33
33
|
sep = id.type_prefix.nil? ? "" : " "
|
|
34
34
|
core = id.type_prefix.nil? ? standard_core(id) : typed_core(id)
|
|
35
|
-
result =
|
|
35
|
+
result = "#{PUBLISHER}#{sep}#{core}"
|
|
36
36
|
result + suffixes(id, with_edition, with_volume)
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -58,10 +58,6 @@ module Pubid
|
|
|
58
58
|
def typed_core(id)
|
|
59
59
|
"#{id.type_prefix}/#{id.number}"
|
|
60
60
|
end
|
|
61
|
-
|
|
62
|
-
def with_publisher?(id)
|
|
63
|
-
id.with_publisher != false
|
|
64
|
-
end
|
|
65
61
|
end
|
|
66
62
|
end
|
|
67
63
|
end
|
data/lib/pubid/errors.rb
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
# no `require "pubid"` here: errors.rb loads from pubid.rb itself, and
|
|
4
4
|
# the umbrella self-require is a circular load whose failure order is
|
|
5
5
|
# platform-dependent (windows raises mid-cycle where linux tolerates it)
|
|
6
|
-
require "parslet"
|
|
7
6
|
|
|
8
7
|
module Pubid
|
|
9
8
|
# Every failure pubid raises.
|
|
10
9
|
#
|
|
11
|
-
# The three classes below have three different superclasses
|
|
12
|
-
#
|
|
13
|
-
# `Parslet::ParseFailed`, and the input guards have always raised
|
|
10
|
+
# The three classes below have three different superclasses: a parse
|
|
11
|
+
# failure is a `StandardError`, and the input guards have always raised
|
|
14
12
|
# `ArgumentError`. What unifies them is the marker module
|
|
15
13
|
# {Pubid::Errors::Error}, which every one of them includes, so a caller that
|
|
16
14
|
# wants "pubid could not do this" writes one rescue:
|
|
@@ -21,8 +19,8 @@ module Pubid
|
|
|
21
19
|
# warn e.message
|
|
22
20
|
# end
|
|
23
21
|
#
|
|
24
|
-
# A URN failure deliberately does not
|
|
25
|
-
# grammar runs, so there is no parse failure to report.
|
|
22
|
+
# A URN failure deliberately does not share the parse failure's
|
|
23
|
+
# superclass: no grammar runs, so there is no parse failure to report.
|
|
26
24
|
module Errors
|
|
27
25
|
# Marker module included by every pubid error. Rescue this to catch all
|
|
28
26
|
# of them, whatever their superclass.
|
|
@@ -32,13 +30,14 @@ module Pubid
|
|
|
32
30
|
#
|
|
33
31
|
# Raised for a grammar rejection, and also for the few flavors that reject
|
|
34
32
|
# an input before the grammar runs (a CSA comment line, a bad ISBN check
|
|
35
|
-
# digit). Those synthetic failures carry no
|
|
36
|
-
# {#parse_failure_cause} is nillable — check it before
|
|
37
|
-
# `ascii_tree` on it.
|
|
33
|
+
# digit). Those synthetic failures carry no cause, so
|
|
34
|
+
# {#parse_failure_cause} is nillable — check it before using it.
|
|
38
35
|
#
|
|
39
36
|
# v1's `Pubid::Core::Errors::ParseError` flattened the cause into the
|
|
40
|
-
# message and threw the object away. This one keeps it.
|
|
41
|
-
|
|
37
|
+
# message and threw the object away. This one keeps it. The superclass
|
|
38
|
+
# was `Parslet::ParseFailed` while the grammars ran on parslet; the parg
|
|
39
|
+
# artifacts retired that engine, and the class stands on its own now.
|
|
40
|
+
class ParseError < ::StandardError
|
|
42
41
|
include Error
|
|
43
42
|
|
|
44
43
|
# The string that could not be parsed, when it is known.
|
|
@@ -54,16 +53,22 @@ module Pubid
|
|
|
54
53
|
attr_reader :flavor
|
|
55
54
|
|
|
56
55
|
# @param message [String]
|
|
57
|
-
# @param parse_failure_cause [
|
|
56
|
+
# @param parse_failure_cause [Object, nil] the engine's structured
|
|
58
57
|
# cause, nil for a failure raised without running a grammar
|
|
59
58
|
# @param input [String, nil]
|
|
60
59
|
# @param flavor [String, nil]
|
|
61
60
|
def initialize(message, parse_failure_cause = nil, input: nil,
|
|
62
61
|
flavor: nil)
|
|
63
|
-
super(message
|
|
62
|
+
super(message)
|
|
63
|
+
@parse_failure_cause = parse_failure_cause
|
|
64
64
|
@input = input
|
|
65
65
|
@flavor = flavor
|
|
66
66
|
end
|
|
67
|
+
|
|
68
|
+
# @return [Object, nil]
|
|
69
|
+
def parse_failure_cause
|
|
70
|
+
@parse_failure_cause
|
|
71
|
+
end
|
|
67
72
|
end
|
|
68
73
|
|
|
69
74
|
# A URN could not be turned into an identifier object.
|
data/lib/pubid/etsi/builder.rb
CHANGED
|
@@ -28,17 +28,20 @@ module Pubid
|
|
|
28
28
|
supplements_array = data[:supplements]
|
|
29
29
|
supplements_array = [supplements_array] unless supplements_array.is_a?(Array)
|
|
30
30
|
|
|
31
|
-
# Build supplements recursively - each wraps the previous
|
|
31
|
+
# Build supplements recursively - each wraps the previous. The
|
|
32
|
+
# bindings pair each supplement's kind ("/A", "/C") with its number
|
|
33
|
+
# by occurrence index.
|
|
32
34
|
supplements_array.reduce(base) do |current_base, supp|
|
|
33
|
-
|
|
35
|
+
case supp[:supplement_kind]
|
|
36
|
+
when "/A"
|
|
34
37
|
Identifiers::Amendment.new(
|
|
35
38
|
base: current_base,
|
|
36
|
-
number: supp[:
|
|
39
|
+
number: supp[:supplement_number].to_i,
|
|
37
40
|
)
|
|
38
|
-
|
|
41
|
+
when "/C"
|
|
39
42
|
Identifiers::Corrigendum.new(
|
|
40
43
|
base: current_base,
|
|
41
|
-
number: supp[:
|
|
44
|
+
number: supp[:supplement_number].to_i,
|
|
42
45
|
)
|
|
43
46
|
else
|
|
44
47
|
current_base # Skip unknown supplement types
|
data/lib/pubid/etsi/parser.rb
CHANGED
|
@@ -1,139 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Etsi
|
|
7
|
-
class Parser
|
|
8
|
-
# Basic elements
|
|
9
|
-
rule(:digit) { match["0-9"] }
|
|
10
|
-
rule(:digits) { digit.repeat(1) }
|
|
11
|
-
rule(:letter) { match["A-Za-z"] }
|
|
12
|
-
rule(:alnum) { match["A-Za-z0-9"] }
|
|
13
|
-
rule(:letters) { letter.repeat(1) }
|
|
14
|
-
rule(:alnums) { alnum.repeat(1) }
|
|
15
|
-
rule(:space) { str(" ") }
|
|
16
|
-
rule(:dash) { str("-") }
|
|
17
|
-
rule(:dot) { str(".") }
|
|
18
|
-
|
|
19
|
-
# ETSI prefix
|
|
20
|
-
rule(:etsi_prefix) { str("ETSI") >> space }
|
|
21
|
-
|
|
22
|
-
# Type prefixes - all 15 types
|
|
23
|
-
rule(:type) do
|
|
24
|
-
(str("I-ETS") | str("TCRTR") | str("GTS") | str("ETR") |
|
|
25
|
-
str("ETS") | str("TBR") | str("NET") | str("EN") |
|
|
26
|
-
str("ES") | str("EG") | str("TS") | str("GR") |
|
|
27
|
-
str("GS") | str("SR") | str("TR")).as(:type)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Number variants
|
|
31
|
-
|
|
32
|
-
# GSM with dotted number: "GSM 11.14", "GSM 02.01"
|
|
33
|
-
rule(:gsm_with_space_number) do
|
|
34
|
-
str("GSM").capture(:gsm_prefix) >> space >>
|
|
35
|
-
digits.capture(:main) >> dot >> digits.capture(:sub)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Number with dot: 11.40, 02.01
|
|
39
|
-
rule(:dotted_number) do
|
|
40
|
-
digits.capture(:main) >> dot >> digits.capture(:sub)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Complex format: ABC 123 or ABC-DEF 123 or IP6 031
|
|
44
|
-
rule(:complex_number) do
|
|
45
|
-
alnums.capture(:prefix1) >>
|
|
46
|
-
(dash >> alnums.capture(:prefix2)).maybe >>
|
|
47
|
-
space >>
|
|
48
|
-
digits.capture(:num)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Simple format: just digits
|
|
52
|
-
rule(:simple_number) do
|
|
53
|
-
digits.capture(:num)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Main number
|
|
57
|
-
rule(:number) do
|
|
58
|
-
(gsm_with_space_number | dotted_number | complex_number | simple_number).as(:number)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Optional minor part
|
|
62
|
-
rule(:minor) do
|
|
63
|
-
space >> digits.as(:minor)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Parts
|
|
67
|
-
rule(:part) do
|
|
68
|
-
dash >> alnums.as(:part)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
rule(:parts) { part.repeat(0).as(:parts) }
|
|
72
|
-
|
|
73
|
-
# Version
|
|
74
|
-
rule(:version) do
|
|
75
|
-
str("V") >> match["0-9."].repeat(1).as(:version)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Edition
|
|
79
|
-
rule(:edition) do
|
|
80
|
-
str("ed.") >> digits.as(:edition)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Version or edition
|
|
84
|
-
rule(:version_or_edition) do
|
|
85
|
-
version | edition
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Published date
|
|
89
|
-
rule(:date_part) do
|
|
90
|
-
str("(") >>
|
|
91
|
-
digit.repeat(4, 4).as(:year) >>
|
|
92
|
-
dash >>
|
|
93
|
-
digit.repeat(2, 2).as(:month) >>
|
|
94
|
-
str(")")
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Individual supplements
|
|
98
|
-
rule(:amendment) do
|
|
99
|
-
str("/A") >> digits.as(:number)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
rule(:corrigendum) do
|
|
103
|
-
str("/C") >> digits.as(:number)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# Single supplement (AMD or COR)
|
|
107
|
-
rule(:single_supplement) do
|
|
108
|
-
amendment.as(:amendment) | corrigendum.as(:corrigendum)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
# Multiple supplements
|
|
112
|
-
rule(:supplements) do
|
|
113
|
-
single_supplement.repeat(1).as(:supplements)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# Main identifier
|
|
117
|
-
#
|
|
118
|
-
# The mandatory core is `etsi_prefix type number` (+ optional
|
|
119
|
-
# minor/parts/supplements), mirroring ISO. The version/edition and date
|
|
120
|
-
# suffixes are optional so a partial reference (e.g. "ETSI GS ZSM 012")
|
|
121
|
-
# parses with version/date left nil. Each `.maybe` guards its own leading
|
|
122
|
-
# space so no trailing space is demanded when the suffix is absent.
|
|
123
|
-
rule(:identifier) do
|
|
124
|
-
etsi_prefix >>
|
|
125
|
-
type >> space >>
|
|
126
|
-
number >> minor.maybe >> parts >>
|
|
127
|
-
supplements.maybe >>
|
|
128
|
-
(space >> version_or_edition).maybe >>
|
|
129
|
-
(space >> date_part).maybe
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
rule(:root) { identifier }
|
|
133
|
-
|
|
134
|
-
def self.parse(input)
|
|
135
|
-
new.parse(input)
|
|
136
|
-
end
|
|
5
|
+
class Parser
|
|
137
6
|
end
|
|
138
7
|
end
|
|
139
8
|
end
|
data/lib/pubid/evs/identifier.rb
CHANGED
|
@@ -42,6 +42,13 @@ module Pubid
|
|
|
42
42
|
render(format: :human, **opts)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# Every EVS form starts with the `EVS` publisher, welded to an adopted
|
|
46
|
+
# designation by a dash (`EVS-EN 18216:2026`); `with_publisher: false`
|
|
47
|
+
# leaves the adopted designation (`EN 18216:2026`).
|
|
48
|
+
def publisher_prefixes
|
|
49
|
+
["EVS"]
|
|
50
|
+
end
|
|
51
|
+
|
|
45
52
|
def self.parse(string)
|
|
46
53
|
unless string.is_a?(String)
|
|
47
54
|
raise Pubid::Errors::InvalidInputError,
|
data/lib/pubid/evs/parser.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Evs
|
|
7
5
|
# Grammar for the printed EVS national-adoption reference, composed with
|
|
@@ -16,12 +14,7 @@ module Pubid
|
|
|
16
14
|
#
|
|
17
15
|
# "EVS-EN 18216:2026" → {evs_separator, adopted: {publisher, number, year}}
|
|
18
16
|
# "EVS-EN ISO 9001:2015/A1:2024" → {evs_separator, adopted: {publisher, adopted_string, supplements}}
|
|
19
|
-
class Parser
|
|
20
|
-
rule(:root) do
|
|
21
|
-
str("EVS") >>
|
|
22
|
-
(str("-") | str(" ")).as(:evs_separator) >>
|
|
23
|
-
::Pubid::CenCenelec::Parser.new.identifier.as(:adopted)
|
|
24
|
-
end
|
|
17
|
+
class Parser
|
|
25
18
|
end
|
|
26
19
|
end
|
|
27
20
|
end
|
data/lib/pubid/evs.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Pubid
|
|
|
39
39
|
language = identifier[/ (et-en|et|en)\z/, 1]
|
|
40
40
|
body = language ? identifier.sub(/ #{Regexp.escape(language)}\z/, "") : identifier
|
|
41
41
|
|
|
42
|
-
parsed = Pubid::Parg::
|
|
42
|
+
parsed = Pubid::Parg::Model.bound(:evs, body)
|
|
43
43
|
built = Builder.new.build(parsed)
|
|
44
44
|
# An "(all parts)" parse wraps the identifier — the language belongs
|
|
45
45
|
# to the inner EVS identifier, not the flavor-less wrapper.
|
data/lib/pubid/gb/identifier.rb
CHANGED
|
@@ -67,6 +67,12 @@ module Pubid
|
|
|
67
67
|
render(format: :human, **opts)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
# `GB` is the standard code, welded to the mandate (`GB/T`), not a
|
|
71
|
+
# publisher prefix: `with_publisher: false` keeps it, as BSI keeps `BS`.
|
|
72
|
+
def publisher_prefixes
|
|
73
|
+
[]
|
|
74
|
+
end
|
|
75
|
+
|
|
70
76
|
# Parse a Chinese Standard identifier string.
|
|
71
77
|
# @param identifier [String]
|
|
72
78
|
# @return [Pubid::Gb::Identifier]
|
data/lib/pubid/gb/parser.rb
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Gb
|
|
7
|
-
#
|
|
5
|
+
# Grammar for Chinese Standard identifiers.
|
|
8
6
|
#
|
|
9
7
|
# Accepts the canonical printed form
|
|
10
8
|
#
|
|
@@ -14,54 +12,7 @@ module Pubid
|
|
|
14
12
|
# T/GZAEPI, ...). TYPE is T (recommended), Z (guideline), or omitted.
|
|
15
13
|
# YEAR is 4 digits, separated by either ASCII dash or em-dash (Chinese
|
|
16
14
|
# typography uses the em-dash form).
|
|
17
|
-
class Parser
|
|
18
|
-
rule(:space) { str(" ") }
|
|
19
|
-
rule(:dot) { str(".") }
|
|
20
|
-
rule(:dash) { str("-") | str("—") }
|
|
21
|
-
rule(:digits) { match("[0-9]").repeat(1) }
|
|
22
|
-
|
|
23
|
-
# Publisher token: national/industry codes (1-3 letters, optionally
|
|
24
|
-
# followed by /T or /Z) OR social-group form "T/{ACRONYM}".
|
|
25
|
-
rule(:publisher_code) do
|
|
26
|
-
# Social-group form: "T/" then 2+ uppercase letters/digits.
|
|
27
|
-
(str("T/") >> match("[A-Z0-9]").repeat(1)).as(:publisher_code) |
|
|
28
|
-
# Confidential national series. The lowercase "n" is part of the
|
|
29
|
-
# code, so it comes before the uppercase-only rule below: a PEG
|
|
30
|
-
# takes the first branch that matches and does not backtrack.
|
|
31
|
-
(str("GBn") >> (str("/T") | str("/Z")).maybe).as(:publisher_code) |
|
|
32
|
-
# Standard form: 1-3 letters, optional slash-T-or-Z.
|
|
33
|
-
(match("[A-Z]").repeat(1, 3) >>
|
|
34
|
-
(str("/T") | str("/Z")).maybe).as(:publisher_code)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Mandate category captured separately when the publisher token didn't
|
|
38
|
-
# already include it. Allows "GB/T" (inline) and "GB" + " T" (separate)
|
|
39
|
-
# to both parse.
|
|
40
|
-
rule(:mandate_suffix) do
|
|
41
|
-
(str("/") >> (str("T") | str("Z")).as(:mandate)).maybe
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
rule(:number) { digits.as(:number) }
|
|
45
|
-
rule(:part) { dot >> digits.as(:part) }
|
|
46
|
-
rule(:year) { (dash >> match("[0-9]").repeat(4, 4).as(:year)).maybe }
|
|
47
|
-
rule(:all_parts_flag) do
|
|
48
|
-
(space >> str("(") >> str("all parts") >> str(")")).as(:all_parts)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
rule(:identifier) do
|
|
52
|
-
publisher_code >>
|
|
53
|
-
space >>
|
|
54
|
-
number >>
|
|
55
|
-
part.maybe >>
|
|
56
|
-
year >>
|
|
57
|
-
all_parts_flag.maybe
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
rule(:root) { identifier }
|
|
61
|
-
|
|
62
|
-
def self.parse(input)
|
|
63
|
-
new.parse(input)
|
|
64
|
-
end
|
|
15
|
+
class Parser
|
|
65
16
|
end
|
|
66
17
|
end
|
|
67
18
|
end
|
|
@@ -23,7 +23,7 @@ module Pubid
|
|
|
23
23
|
::Pubid::INPUT_TOO_LONG_MESSAGE
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
parsed = Pubid::Parg::
|
|
26
|
+
parsed = Pubid::Parg::Model.bound(:gost, Parser.normalize_input(identifier))
|
|
27
27
|
Builder.build(parsed)
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -38,6 +38,14 @@ module Pubid
|
|
|
38
38
|
# document.
|
|
39
39
|
subset_strict :copublisher
|
|
40
40
|
|
|
41
|
+
# `GOST` (and `GOST R`) is the national standard designation, as `GB`
|
|
42
|
+
# and `BS` are, not a publisher prefix: `GOST 26951-2025` without it is
|
|
43
|
+
# no designation, and `GOST IEC 62868` would read as the IEC document.
|
|
44
|
+
# `with_publisher: false` therefore keeps it.
|
|
45
|
+
def publisher_prefixes
|
|
46
|
+
[]
|
|
47
|
+
end
|
|
48
|
+
|
|
41
49
|
GOST_TYPE_MAP = {
|
|
42
50
|
"pubid:gost:interstate-standard" => "Pubid::Gost::Identifiers::InterstateStandard",
|
|
43
51
|
"pubid:gost:national-standard" => "Pubid::Gost::Identifiers::NationalStandard",
|
data/lib/pubid/gost/parser.rb
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Gost
|
|
7
|
-
#
|
|
5
|
+
# Grammar for GOST identifiers.
|
|
8
6
|
#
|
|
9
7
|
# Accepts the Latin and Cyrillic surface forms observed in the wild:
|
|
10
8
|
#
|
|
@@ -26,87 +24,12 @@ module Pubid
|
|
|
26
24
|
#
|
|
27
25
|
# The builder interprets prefix_text (splits copublisher vs subtype,
|
|
28
26
|
# normalizes Cyrillic to Latin) and raw (splits number vs year).
|
|
29
|
-
class Parser
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
root :identifier
|
|
33
|
-
|
|
34
|
-
rule(:space) { str(" ") }
|
|
35
|
-
rule(:space?) { space.maybe }
|
|
36
|
-
rule(:dot) { str(".") }
|
|
37
|
-
|
|
38
|
-
rule(:year_sep) do
|
|
39
|
-
(str("-") | str("—") | str("–")) >> space?.maybe
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
rule(:gost_word) do
|
|
43
|
-
(str("GOST") | str("ГОСТ")).as(:gost_word) >> space
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
rule(:scope_r) do
|
|
47
|
-
(match("R") | match("Р")).as(:scope_r) >> space
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Everything between scope_r and the first digit: copublisher,
|
|
51
|
-
# subtype, or both. Captured as a raw string — the builder splits
|
|
52
|
-
# it into copublisher + subtype. Matches uppercase letters (Latin
|
|
53
|
-
# and Cyrillic), forward slashes, and spaces between words.
|
|
54
|
-
rule(:prefix_text) do
|
|
55
|
-
(match("[A-ZА-Яa-zа-я/]").repeat(1) >>
|
|
56
|
-
(space >> match("[A-ZА-Яa-zа-я/]").repeat(1)).repeat).as(:prefix_text) >> space
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
rule(:digits) do
|
|
60
|
-
match("[0-9]").repeat(1)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
rule(:raw_body) do
|
|
64
|
-
(digits >> ((dot | year_sep) >> digits).repeat).as(:raw)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# IDT adoption suffix: "/<foreign-identifier>". The slash is
|
|
68
|
-
# consumed but NOT captured — only the foreign identifier text
|
|
69
|
-
# goes into :adopted_raw. Captures everything after the first
|
|
70
|
-
# slash, including subsequent slashes (the adopted identifier
|
|
71
|
-
# may itself contain slashes, e.g. "ISO/TR 25901-1:2016").
|
|
72
|
-
rule(:adopted_part) do
|
|
73
|
-
space?.maybe >> str("/") >> match(".").repeat(1).as(:adopted_raw)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Adoption reference in parens: "(<foreign-id>)". The parens
|
|
77
|
-
# themselves are consumed but NOT captured. The content goes
|
|
78
|
-
# into :adopted_reference_raw. This form appears for MOD/NEQ
|
|
79
|
-
# adoptions where the foreign standard is referenced but not
|
|
80
|
-
# identical (IDT would use the slash form instead).
|
|
81
|
-
rule(:adopted_reference_part) do
|
|
82
|
-
space?.maybe >> str("(") >> match("[^)]").repeat(1).as(:adopted_reference_raw) >> str(")")
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
rule(:identifier) do
|
|
86
|
-
gost_word >> scope_r.maybe >> prefix_text.maybe >> raw_body >>
|
|
87
|
-
adopted_part.maybe >> adopted_reference_part.maybe
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Pre-parse ingestion normalizations (R2): every parse path —
|
|
91
|
-
# parslet and PG artifact alike — feeds the grammar the same
|
|
92
|
-
# normalized string.
|
|
27
|
+
class Parser
|
|
28
|
+
# Pre-parse ingestion normalizations (R2): every parse path feeds
|
|
29
|
+
# the grammar the same normalized string.
|
|
93
30
|
def self.normalize_input(string)
|
|
94
31
|
string.strip
|
|
95
32
|
end
|
|
96
|
-
|
|
97
|
-
def self.parse(string)
|
|
98
|
-
unless string.is_a?(String)
|
|
99
|
-
raise ::Pubid::Errors::InvalidInputError,
|
|
100
|
-
::Pubid::INPUT_NOT_A_STRING_MESSAGE
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
if string.length > ::Pubid::MAX_INPUT_LENGTH
|
|
104
|
-
raise ::Pubid::Errors::InvalidInputError,
|
|
105
|
-
::Pubid::INPUT_TOO_LONG_MESSAGE
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
new.parse(normalize_input(string))
|
|
109
|
-
end
|
|
110
33
|
end
|
|
111
34
|
end
|
|
112
35
|
end
|