pubid 2.0.23 → 2.0.25

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/data/parg/calconnect_pfs.json +1 -0
  3. data/data/parg/cen_pfs.json +1 -0
  4. data/data/parg/etsi_pfs.json +1 -0
  5. data/lib/pubid/calconnect_pfs/builder.rb +35 -0
  6. data/lib/pubid/calconnect_pfs/identifier.rb +84 -0
  7. data/lib/pubid/calconnect_pfs/identifiers/standard.rb +31 -0
  8. data/lib/pubid/calconnect_pfs/identifiers.rb +7 -0
  9. data/lib/pubid/calconnect_pfs/parser.rb +10 -0
  10. data/lib/pubid/calconnect_pfs/pubid_urn_schema.rb +17 -0
  11. data/lib/pubid/calconnect_pfs/renderer.rb +10 -0
  12. data/lib/pubid/calconnect_pfs/urn_generator.rb +30 -0
  13. data/lib/pubid/calconnect_pfs.rb +60 -0
  14. data/lib/pubid/cen_pfs/builder.rb +33 -0
  15. data/lib/pubid/cen_pfs/identifier.rb +64 -0
  16. data/lib/pubid/cen_pfs/identifiers/european_norm.rb +31 -0
  17. data/lib/pubid/cen_pfs/identifiers.rb +7 -0
  18. data/lib/pubid/cen_pfs/parser.rb +10 -0
  19. data/lib/pubid/cen_pfs/pubid_urn_schema.rb +15 -0
  20. data/lib/pubid/cen_pfs/renderer.rb +10 -0
  21. data/lib/pubid/cen_pfs/urn_generator.rb +12 -0
  22. data/lib/pubid/cen_pfs.rb +71 -0
  23. data/lib/pubid/doi_pfs/identifier.rb +8 -1
  24. data/lib/pubid/doi_pfs.rb +3 -11
  25. data/lib/pubid/etsi_pfs/CLAUDE.md +95 -0
  26. data/lib/pubid/etsi_pfs/builder.rb +25 -0
  27. data/lib/pubid/etsi_pfs/identifier.rb +50 -0
  28. data/lib/pubid/etsi_pfs/identifiers/standard.rb +22 -0
  29. data/lib/pubid/etsi_pfs/identifiers.rb +7 -0
  30. data/lib/pubid/etsi_pfs/parser.rb +10 -0
  31. data/lib/pubid/etsi_pfs/pubid_urn_schema.rb +19 -0
  32. data/lib/pubid/etsi_pfs/renderer.rb +10 -0
  33. data/lib/pubid/etsi_pfs/urn_generator.rb +12 -0
  34. data/lib/pubid/etsi_pfs.rb +59 -0
  35. data/lib/pubid/itu/CLAUDE.md +25 -14
  36. data/lib/pubid/itu/builder.rb +7 -5
  37. data/lib/pubid/itu/identifiers/special_publication.rb +20 -17
  38. data/lib/pubid/itu/urn_generator.rb +3 -4
  39. data/lib/pubid/jis/CLAUDE.md +35 -0
  40. data/lib/pubid/jis/builder.rb +33 -2
  41. data/lib/pubid/jis/identifier.rb +24 -4
  42. data/lib/pubid/jis/identifiers/welding_engineering_standard.rb +21 -2
  43. data/lib/pubid/jis/identifiers/welding_engineering_technical_report.rb +13 -0
  44. data/lib/pubid/jis/identifiers/welding_engineering_technical_specification.rb +14 -0
  45. data/lib/pubid/jis/identifiers.rb +5 -0
  46. data/lib/pubid/jis/parser.rb +30 -0
  47. data/lib/pubid/jis/pubid_urn_schema.rb +14 -3
  48. data/lib/pubid/jis/renderer.rb +1 -2
  49. data/lib/pubid/version.rb +1 -1
  50. data/lib/pubid.rb +13 -0
  51. metadata +35 -2
@@ -8,6 +8,7 @@ module Pubid
8
8
  end
9
9
 
10
10
  def build(data)
11
+ data = flatten_supplement(data)
11
12
  # Handle supplement case first; the SYMBOL clause (if any) attaches to
12
13
  # the outermost identifier, be it the base or the supplement. The
13
14
  # bindings bind the supplement's fields flat (amd_type/amd_number/…),
@@ -29,6 +30,19 @@ module Pubid
29
30
 
30
31
  private
31
32
 
33
+ SUPPLEMENT_KEYS = %i[amendment explanation corrigendum].freeze
34
+
35
+ # The typed bindings carry a supplement's fields flat (amd_type, …).
36
+ # The raw parse tree nests them under :amendment, :explanation or
37
+ # :corrigendum. Read both shapes, or the tree path drops the
38
+ # supplement.
39
+ def flatten_supplement(data)
40
+ key = SUPPLEMENT_KEYS.find { |k| data[k].is_a?(Hash) }
41
+ return data unless key
42
+
43
+ data.except(key).merge(data[key].compact)
44
+ end
45
+
32
46
  # nil => no SYMBOL clause; "" => bare "SYMBOL" keyword; otherwise value.
33
47
  def attach_symbol(identifier, data)
34
48
  identifier.symbol = data[:symbol_value].to_s if data[:symbol_present]
@@ -44,13 +58,30 @@ module Pubid
44
58
  reaffirmed: (true if data[:reaffirmed]),
45
59
  }
46
60
  # A WES id carries no series letter, so its series stays nil.
47
- wes = Identifiers::WeldingEngineeringStandard
48
- return wes.new(**attrs) if data[:wes]
61
+ return build_wes(data, attrs) if data[:wes]
49
62
 
50
63
  jis_class_for_type(data[:type]&.to_s)
51
64
  .new(series: data[:series].to_s, **attrs)
52
65
  end
53
66
 
67
+ # `wes_type` ("TR"/"TS") picks the WES class. `wes_language` is a
68
+ # language printed before the year ("WES 1112(E):2022").
69
+ def build_wes(data, attrs)
70
+ attrs = attrs.merge(wes_language_attrs(data)) if data[:wes_language]
71
+ Identifiers::WeldingEngineeringStandard
72
+ .class_for_type(data[:wes_type]&.to_s).new(**attrs)
73
+ end
74
+
75
+ def wes_language_attrs(data)
76
+ if data[:language]
77
+ raise Pubid::Errors::ParseError.new(
78
+ "a WES id carries one language, not two", nil
79
+ )
80
+ end
81
+
82
+ { language: data[:wes_language].to_s, language_before_year: true }
83
+ end
84
+
54
85
  def jis_class_for_type(type)
55
86
  case type
56
87
  when "TR" then Identifiers::TechnicalReport
@@ -21,6 +21,11 @@ module Pubid
21
21
  attribute :parts, :string, collection: true # Optional multi-level parts
22
22
  attribute :year, :integer
23
23
  attribute :language, :string # "E" or "J"
24
+ # A WES id can print its language before the year ("WES 1112(E):2022")
25
+ # or after it ("WES 1112:2022(E)"). This records the source position.
26
+ # It is spelling only, so `==` does not read it.
27
+ attribute :language_before_year, :boolean
28
+ equality_ignored :language_before_year
24
29
  # Reaffirmation (再確認): a trailing "R" on the year marks an edition
25
30
  # that was reaffirmed without revision (e.g. ":2019R").
26
31
  attribute :reaffirmed, :boolean
@@ -45,6 +50,10 @@ module Pubid
45
50
  "pubid:jis:explanation" => "Pubid::Jis::Identifiers::Explanation",
46
51
  "pubid:jis:welding-engineering-standard" =>
47
52
  "Pubid::Jis::Identifiers::WeldingEngineeringStandard",
53
+ "pubid:jis:welding-engineering-technical-report" =>
54
+ "Pubid::Jis::Identifiers::WeldingEngineeringTechnicalReport",
55
+ "pubid:jis:welding-engineering-technical-specification" =>
56
+ "Pubid::Jis::Identifiers::WeldingEngineeringTechnicalSpecification",
48
57
  }.freeze
49
58
 
50
59
  key_value do
@@ -54,6 +63,7 @@ module Pubid
54
63
  map "parts", to: :parts
55
64
  map "year", to: :year
56
65
  map "language", to: :language
66
+ map "language_before_year", to: :language_before_year
57
67
  map "reaffirmed", to: :reaffirmed
58
68
  # render_empty keeps a bare "SYMBOL" (empty-string value) in the hash so
59
69
  # it round-trips distinctly from "no symbol" (nil).
@@ -75,6 +85,17 @@ module Pubid
75
85
  reaffirmed == true
76
86
  end
77
87
 
88
+ def language_before_year?
89
+ language_before_year == true
90
+ end
91
+
92
+ # The ":year[R]" and "(lang)" tail, in the order the source used.
93
+ def year_and_language
94
+ year_part = year ? ":#{year_with_reaffirmation}" : ""
95
+ lang_part = language ? "(#{language})" : ""
96
+ language_before_year? ? lang_part + year_part : year_part + lang_part
97
+ end
98
+
78
99
  # Render a year with its reaffirmation marker, e.g. "2019R".
79
100
  def year_with_reaffirmation
80
101
  "#{year}#{'R' if reaffirmed?}"
@@ -184,10 +205,9 @@ module Pubid
184
205
  raise Pubid::Errors::InvalidInputError, Pubid::INPUT_TOO_LONG_MESSAGE
185
206
  end
186
207
 
187
- identifier = ::Pubid.utf8_input(identifier)
188
-
189
- parsed = Pubid::Parg::Model.bound(:jis, identifier)
190
- Builder.build(parsed)
208
+ face, bindings = Parser.ingest(::Pubid.utf8_input(identifier))
209
+ parsed = Pubid::Parg::Model.bound(:jis, face)
210
+ Builder.build(parsed.merge(bindings))
191
211
  end
192
212
  end
193
213
  end
@@ -6,9 +6,20 @@ module Pubid
6
6
  # Japan Welding Engineering Society standard. JSA sells WES next to JIS,
7
7
  # so it parses through the JIS flavor, but the id carries no series
8
8
  # letter and no JIS prefix.
9
- # Examples: WES 7700-1:2019, WES 7301:2020R
9
+ # Examples: WES 7700-1:2019, WES 7301:2020R, WES 1112(E):2022
10
10
  class WeldingEngineeringStandard < SingleIdentifier
11
11
  PUBLISHER = "WES"
12
+ # The type token after the WES root: "TR", "TS", or nil.
13
+ WES_TYPE = nil
14
+
15
+ # The WES class for a type token ("TR", "TS" or nil).
16
+ def self.class_for_type(type)
17
+ case type
18
+ when "TR" then WeldingEngineeringTechnicalReport
19
+ when "TS" then WeldingEngineeringTechnicalSpecification
20
+ else WeldingEngineeringStandard
21
+ end
22
+ end
12
23
 
13
24
  def type_prefix
14
25
  nil
@@ -20,8 +31,12 @@ module Pubid
20
31
  nil
21
32
  end
22
33
 
34
+ def wes_type
35
+ self.class::WES_TYPE
36
+ end
37
+
23
38
  def code
24
- result = "#{PUBLISHER} #{number}"
39
+ result = [PUBLISHER, wes_type, number].compact.join(" ")
25
40
  result += parts.map { |p| "-#{p}" }.join if parts&.any?
26
41
  result
27
42
  end
@@ -29,6 +44,10 @@ module Pubid
29
44
  def mr_publisher
30
45
  PUBLISHER.downcase
31
46
  end
47
+
48
+ def mr_type
49
+ wes_type&.downcase
50
+ end
32
51
  end
33
52
  end
34
53
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Jis
5
+ module Identifiers
6
+ # WES technical report. The type token follows the WES root.
7
+ # Example: WES TR 2032:2024
8
+ class WeldingEngineeringTechnicalReport < WeldingEngineeringStandard
9
+ WES_TYPE = "TR"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pubid
4
+ module Jis
5
+ module Identifiers
6
+ # WES technical specification. The type token follows the WES root.
7
+ # Examples: WES TS 2816:2015, WES TS 2816(E):2015
8
+ class WeldingEngineeringTechnicalSpecification <
9
+ WeldingEngineeringStandard
10
+ WES_TYPE = "TS"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -15,6 +15,11 @@ module Pubid
15
15
  "#{__dir__}/identifiers/technical_specification"
16
16
  autoload :WeldingEngineeringStandard,
17
17
  "#{__dir__}/identifiers/welding_engineering_standard"
18
+ autoload :WeldingEngineeringTechnicalReport,
19
+ "#{__dir__}/identifiers/welding_engineering_technical_report"
20
+ autoload :WeldingEngineeringTechnicalSpecification,
21
+ "#{__dir__}/identifiers/" \
22
+ "welding_engineering_technical_specification"
18
23
  end
19
24
  end
20
25
  end
@@ -2,7 +2,37 @@
2
2
 
3
3
  module Pubid
4
4
  module Jis
5
+ # The JIS grammar is the vendored artifact data/parg/jis.json. This class
6
+ # holds only the Ruby ingestion in front of it.
5
7
  class Parser
8
+ # A WES type token or a language before the year. Full-width forms
9
+ # are accepted, as in the grammar.
10
+ WES_SHIM = /
11
+ \A(?<root>WES[  ])
12
+ (?:(?<type>TR|TS)[  ])?
13
+ (?<number>\d+(?:[-ー]\d+)*)
14
+ (?:[((](?<lang>[EJ])[))](?=[::]))?
15
+ /x
16
+
17
+ # The vendored grammar (pubid-grammar artifacts/jis.json) reads neither
18
+ # "WES TR 2032" nor "WES 1112(E):2022". Until it does, cut those tokens
19
+ # from the input and bind them as `wes_type` and `wes_language`, the
20
+ # captures the grammar is to bind (hand-off
21
+ # pubid__pubid-grammar__jis-wes-language-tr-ts). Other input passes
22
+ # unchanged.
23
+ # @param input [String]
24
+ # @return [Array(String, Hash)] the input for the grammar, the bindings
25
+ # to merge into what the grammar binds
26
+ def self.ingest(input)
27
+ match = WES_SHIM.match(input)
28
+ return [input, {}] unless match && (match[:type] || match[:lang])
29
+
30
+ bindings = {}
31
+ bindings[:wes_type] = match[:type] if match[:type]
32
+ bindings[:wes_language] = match[:lang] if match[:lang]
33
+ rest = input[match.end(0)..]
34
+ ["#{match[:root]}#{match[:number]}#{rest}", bindings]
35
+ end
6
36
  end
7
37
  end
8
38
  end
@@ -13,17 +13,28 @@ module Pubid
13
13
  atom "parts", "part", kind: :list
14
14
  atom "year", "year", kind: :int
15
15
  atom "reaffirmed", "reaffirmed", kind: :bool
16
+ atom "language", "lang"
17
+ # Where a WES id prints its language: "WES 1112(E):2022" against
18
+ # "WES 1112:2022(E)". Spelling only.
19
+ facet "language_before_year", "langfirst", kind: :bool
16
20
 
17
21
  type "pubid:jis:all-parts", "all"
18
- type "pubid:jis:amendment", "amd"
19
- type "pubid:jis:corrigendum", "cor"
20
- type "pubid:jis:explanation", "e"
22
+ # A supplement's number is its Integer ordinal. The document it
23
+ # supplements comes first, along +base+. An explanation can have no
24
+ # number ("…/EXPL"), so its number is an atom.
25
+ supplement = [["number", :int]]
26
+ type "pubid:jis:amendment", "amd", core: supplement
27
+ type "pubid:jis:corrigendum", "cor", core: supplement
28
+ type "pubid:jis:explanation", "e", core: [],
29
+ atoms: [["number", "n", :int]]
21
30
  type "pubid:jis:identifier", "id"
22
31
  type "pubid:jis:japanese-industrial-standard", "jis"
23
32
  type "pubid:jis:standard", "std"
24
33
  type "pubid:jis:technical-report", "tr"
25
34
  type "pubid:jis:technical-specification", "ts"
26
35
  type "pubid:jis:welding-engineering-standard", "wes"
36
+ type "pubid:jis:welding-engineering-technical-report", "westr"
37
+ type "pubid:jis:welding-engineering-technical-specification", "wests"
27
38
  end
28
39
  end
29
40
  end
@@ -49,8 +49,7 @@ module Pubid
49
49
  result = parts.join(" ")
50
50
  result += " " if result.length.positive?
51
51
  result += id.code.to_s
52
- result += ":#{id.year_with_reaffirmation}" if id.year
53
- result += "(#{id.language})" if id.language
52
+ result += id.year_and_language
54
53
  result += id.symbol_suffix
55
54
  result
56
55
  end
data/lib/pubid/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pubid
4
- VERSION = "2.0.23"
4
+ VERSION = "2.0.25"
5
5
  end
data/lib/pubid.rb CHANGED
@@ -233,12 +233,25 @@ module Pubid
233
233
  autoload :Bipm, "pubid/bipm"
234
234
  autoload :Bsi, "pubid/bsi"
235
235
  autoload :Calconnect, "pubid/calconnect"
236
+ # The PFS-compiled dev alias of calconnect (pubid/pubid#706 §8): the
237
+ # acceptance port, registered beside the coded flavor, never routed by
238
+ # Pubid.parse (registry keys sort the coded key first).
239
+ autoload :CalconnectPfs, "pubid/calconnect_pfs"
240
+ # The PFS-compiled module-composition surface of cen_cenelec
241
+ # (pubid/pubid#706 §4): the EN face composed from the module library —
242
+ # the measured boundary of what the modules absorb
243
+ # (spec/pubid/cen_pfs/parity_spec.rb's ledger).
244
+ autoload :CenPfs, "pubid/cen_pfs"
236
245
  autoload :Ccsds, "pubid/ccsds"
237
246
  autoload :CenCenelec, "pubid/cen_cenelec"
238
247
  autoload :Cie, "pubid/cie"
239
248
  autoload :Csa, "pubid/csa"
240
249
  autoload :Ecma, "pubid/ecma"
241
250
  autoload :Etsi, "pubid/etsi"
251
+ # The PFS-compiled dev alias of etsi (pubid/pubid#706): registered
252
+ # beside the coded flavor, never routed by Pubid.parse (registry keys
253
+ # sort "etsi" first).
254
+ autoload :EtsiPfs, "pubid/etsi_pfs"
242
255
  autoload :Evs, "pubid/evs"
243
256
  autoload :Gost, "pubid/gost"
244
257
  autoload :Gb, "pubid/gb"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubid
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.23
4
+ version: 2.0.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-11-12 00:00:00.000000000 Z
11
+ date: 2026-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -91,9 +91,11 @@ files:
91
91
  - data/parg/bipm.parg
92
92
  - data/parg/bsi.json
93
93
  - data/parg/calconnect.json
94
+ - data/parg/calconnect_pfs.json
94
95
  - data/parg/ccsds.json
95
96
  - data/parg/cen_cenelec.json
96
97
  - data/parg/cen_cenelec.parg
98
+ - data/parg/cen_pfs.json
97
99
  - data/parg/cie.json
98
100
  - data/parg/csa.json
99
101
  - data/parg/doi.json
@@ -101,6 +103,7 @@ files:
101
103
  - data/parg/easc.json
102
104
  - data/parg/ecma.json
103
105
  - data/parg/etsi.json
106
+ - data/parg/etsi_pfs.json
104
107
  - data/parg/evs.json
105
108
  - data/parg/gb.json
106
109
  - data/parg/gost.json
@@ -352,6 +355,15 @@ files:
352
355
  - lib/pubid/calconnect/renderer.rb
353
356
  - lib/pubid/calconnect/urn_generator.rb
354
357
  - lib/pubid/calconnect/urn_parser.rb
358
+ - lib/pubid/calconnect_pfs.rb
359
+ - lib/pubid/calconnect_pfs/builder.rb
360
+ - lib/pubid/calconnect_pfs/identifier.rb
361
+ - lib/pubid/calconnect_pfs/identifiers.rb
362
+ - lib/pubid/calconnect_pfs/identifiers/standard.rb
363
+ - lib/pubid/calconnect_pfs/parser.rb
364
+ - lib/pubid/calconnect_pfs/pubid_urn_schema.rb
365
+ - lib/pubid/calconnect_pfs/renderer.rb
366
+ - lib/pubid/calconnect_pfs/urn_generator.rb
355
367
  - lib/pubid/ccsds.rb
356
368
  - lib/pubid/ccsds/builder.rb
357
369
  - lib/pubid/ccsds/identifier.rb
@@ -391,6 +403,15 @@ files:
391
403
  - lib/pubid/cen_cenelec/single_identifier.rb
392
404
  - lib/pubid/cen_cenelec/urn_generator.rb
393
405
  - lib/pubid/cen_cenelec/urn_parser.rb
406
+ - lib/pubid/cen_pfs.rb
407
+ - lib/pubid/cen_pfs/builder.rb
408
+ - lib/pubid/cen_pfs/identifier.rb
409
+ - lib/pubid/cen_pfs/identifiers.rb
410
+ - lib/pubid/cen_pfs/identifiers/european_norm.rb
411
+ - lib/pubid/cen_pfs/parser.rb
412
+ - lib/pubid/cen_pfs/pubid_urn_schema.rb
413
+ - lib/pubid/cen_pfs/renderer.rb
414
+ - lib/pubid/cen_pfs/urn_generator.rb
394
415
  - lib/pubid/cie.rb
395
416
  - lib/pubid/cie/CLAUDE.md
396
417
  - lib/pubid/cie/builder.rb
@@ -525,6 +546,16 @@ files:
525
546
  - lib/pubid/etsi/renderer.rb
526
547
  - lib/pubid/etsi/urn_generator.rb
527
548
  - lib/pubid/etsi/urn_parser.rb
549
+ - lib/pubid/etsi_pfs.rb
550
+ - lib/pubid/etsi_pfs/CLAUDE.md
551
+ - lib/pubid/etsi_pfs/builder.rb
552
+ - lib/pubid/etsi_pfs/identifier.rb
553
+ - lib/pubid/etsi_pfs/identifiers.rb
554
+ - lib/pubid/etsi_pfs/identifiers/standard.rb
555
+ - lib/pubid/etsi_pfs/parser.rb
556
+ - lib/pubid/etsi_pfs/pubid_urn_schema.rb
557
+ - lib/pubid/etsi_pfs/renderer.rb
558
+ - lib/pubid/etsi_pfs/urn_generator.rb
528
559
  - lib/pubid/evs.rb
529
560
  - lib/pubid/evs/CLAUDE.md
530
561
  - lib/pubid/evs/builder.rb
@@ -866,6 +897,8 @@ files:
866
897
  - lib/pubid/jis/identifiers/technical_report.rb
867
898
  - lib/pubid/jis/identifiers/technical_specification.rb
868
899
  - lib/pubid/jis/identifiers/welding_engineering_standard.rb
900
+ - lib/pubid/jis/identifiers/welding_engineering_technical_report.rb
901
+ - lib/pubid/jis/identifiers/welding_engineering_technical_specification.rb
869
902
  - lib/pubid/jis/parser.rb
870
903
  - lib/pubid/jis/pubid_urn_schema.rb
871
904
  - lib/pubid/jis/renderer.rb