pubid-iso 0.1.1 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1f95297e422efe82291fd2570ba264ca9daf1b6304dc3050ae7aebcff532739
4
- data.tar.gz: '08f400bc76e43847ae0ae0b7d0c516de05a6a9bdc1dce60abd9b69ca9745b05e'
3
+ metadata.gz: e9a5dae3e19189666e2259f498813de7aa502ee7d68e1ec4567d493be74e3acb
4
+ data.tar.gz: f7834ffc05c7eaeec131aaef54804512d2e6d9e5494da8fe286e9730493dd7be
5
5
  SHA512:
6
- metadata.gz: 6d2f14cbb013fc0e9097178bc9cf7c3b5255f21699c0e904cbd8bb4aec159464f451c679e5d2f4a24aee9c3c3397d8b882f3fbb89c096104c17da51bfe6cf4f7
7
- data.tar.gz: 3d263a1fad953c7e508b2d1936fda41fd4d827f09eb81fecc6b3379acb23502d6852cdaa99860717714934af262eb01a13039b00871af2ef8f11cf97b738e3df
6
+ metadata.gz: 5a3319d163496c073813d052ecc873fb6f2f90e2351f1c8ac891c2c093c56a59d8405bc942f44b3f57e013f1f7149a7b3a35fc7b73ca3c58a0116ebce5e85b63
7
+ data.tar.gz: 3c72a547b1abaa06142caa496e8ce6d3769499954bfeaf3f9b01a470017bd3f38a1682be9e793f7eaab019ce202367feeda9d771f13ad14cf11b9cd901dafd42
data/README.adoc CHANGED
@@ -1,2 +1,179 @@
1
1
  = ISO publication identifiers ("ISO PubID")
2
2
 
3
+ == Purpose
4
+
5
+ This gem implements a mechanism to parse and utilize ISO publication
6
+ identifiers.
7
+
8
+ == Use cases to support
9
+
10
+ . generate the corresponding URN format (according to RFC 5141)
11
+ . generate updated PubID
12
+ . generate language specific PubID
13
+ . generate dated vs undated PubIDs
14
+
15
+
16
+ == Elements of the PubID
17
+
18
+ === Document identifier
19
+
20
+ ==== General
21
+
22
+ The ISO document identifier is assembled out of these metadata elements:
23
+
24
+ publisher:: publisher of the document
25
+ document stage:: stage of development of document, according to the Harmonized Stage Codes
26
+ document number:: numeric identifier of document
27
+ update number:: serial number of update (for amendments and technical corrigenda)
28
+ document type:: type of ISO deliverable
29
+ copyright year:: year of publication of document
30
+ language:: language of document
31
+
32
+ ==== Publisher
33
+
34
+ This is the abbreviation of the publishing organization, typically `ISO`.
35
+
36
+ If the document is published under co-publishing agreements, it can contain the
37
+ abbreviations of other publishing SDOs, delimited by `/` after `ISO`.
38
+
39
+ An International Workshop Agreement document has publisher abbreviation of
40
+ `IWA`.
41
+
42
+ [example]
43
+ ====
44
+ `ISO`, `ISO/IEC`, `ISO/IEC/IEEE`, `ISO/IEEE`, `ISO/SAE`, `IWA`
45
+ ====
46
+
47
+
48
+ ==== Document type and stage
49
+
50
+ ISO document stages in document identifiers are mapped as follows.
51
+
52
+ International Standard::
53
+
54
+ `00.00` to `00.99`::: "`PWI`"
55
+ `10.00` to `10.98`::: "`NP`"
56
+ `10.99` to `20.00`::: "`AWI`"
57
+ `20.20` to `20.99`::: "`WD`"
58
+ `30.00` to `30.99`::: "`CD`"
59
+ `40.00` to `40.99`::: "`DIS`"
60
+ `50.00` to `50.99`::: "`FDIS`"
61
+ `60.00`::: "`PRF`"
62
+ `60.60`::: empty designation
63
+
64
+ Technical Specification, Technical Report::
65
+
66
+ `00.00` to `00.99`::: "`PWI {TR,TS}`"
67
+ `10.00` to `10.98`::: "`NP {TR,TS}`"
68
+ `10.98` to `20.00`::: "`AWI {TR,TS}`"
69
+ `20.20` to `20.99`::: "`WD {TR,TS}`"
70
+ `30.00` to `30.99`::: "`CD {TR,TS}`"
71
+ `40.00` to `40.99`::: TS/TRs do not have DIS stage because they are not
72
+ international standards.
73
+ `50.00` to `50.99`::: TS/TRs do not have FDIS stage because they are not
74
+ international standards.
75
+ `60.00`::: "`PRF {TR,TS}`"
76
+ `60.60`::: "`{TR,TS}`"
77
+
78
+ //The stage abbreviations DIS and FDIS change to DTS and FDTS
79
+
80
+ Amendment::
81
+
82
+ `00.00` to `00.99`::: "`{base-document-id}/PWI Amd {num}`"
83
+ `10.00` to `10.98`::: "`{base-document-id}/NP Amd {num}`"
84
+ `10.99` to `20.00`::: "`{base-document-id}/AWI Amd {num}`"
85
+ `20.20` to `20.99`::: "`{base-document-id}/WD Amd {num}`"
86
+ `30.00` to `30.99`::: "`{base-document-id}/CD Amd {num}`"
87
+ `40.00` to `40.99`::: "`{base-document-id}/DAmd {num}`"
88
+ `50.00` to `50.99`::: "`{base-document-id}/FDAmd {num}`"
89
+ `60.00`::: "`{base-document-id}/PRF Amd {num}`"
90
+ `60.60`::: "`{base-document-id}/Amd {num}`"
91
+
92
+ Technical Corrigendum::
93
+
94
+ `00.00` to `00.99`::: "`{base-document-id}/PWI Cor {num}`"
95
+ `10.00` to `10.98`::: "`{base-document-id}/NP Cor {num}`"
96
+ `10.99` to `20.00`::: "`{base-document-id}/AWI Cor {num}`"
97
+ `20.20` to `20.99`::: "`{base-document-id}/WD Cor {num}`"
98
+ `30.00` to `30.99`::: "`{base-document-id}/CD Cor {num}`"
99
+ `40.00` to `40.99`::: "`{base-document-id}/DIS Cor {num}`"
100
+ `50.00` to `50.99`::: "`{base-document-id}/FDCor {num}`"
101
+ `60.00`::: "`{base-document-id}/PRF Cor {num}`"
102
+ `60.60`::: "`{base-document-id}/Cor {num}`"
103
+
104
+
105
+ When the Publisher element contains a "`slash`" ("`/`"), the separation in front
106
+ of the document stage will be converted into an empty space.
107
+
108
+ [example]
109
+ ====
110
+ `ISO/NP 33333` but `ISO/IEC NP 33333`.
111
+ `ISO/NP TR 33333` but `ISO/IEC NP TR 33333`.
112
+ ====
113
+
114
+ According to ISO Directives Part 1 (11ed), SE.2:
115
+
116
+ [quote]
117
+ ____
118
+ Working drafts (WD), committee drafts (CD), draft International Standards (DIS),
119
+ final draft International Standards (FDIS) and International Standards`",
120
+ "`Successive DIS on the same subject will carry the same number but will be
121
+ distinguished by a numerical suffix (.2, .3, etc.).
122
+ ____
123
+
124
+ The stage iteration number is assigned accordingly for all stages, which is
125
+ patterned as:
126
+
127
+ * `{document stage}` (no suffix if iteration is 1); or
128
+ * `{document stage}.{iteration number}`
129
+ (suffix including iteration number after 1).
130
+
131
+ Once the document is published (stage 60 substage 60), no status abbreviation is
132
+ given.
133
+
134
+
135
+ ==== Full PubID patterns
136
+
137
+ The patterns are as follows:
138
+
139
+ *International Standard*::
140
+ `{publisher} (/{document type and stage})? ({document number}) (- {part number})? (: {copyright year}) ({ISO 639 language code})?` +
141
+ +
142
+ ====
143
+ `ISO/IEEE/FDIS 33333-2`, `ISO/IEEE 33333-2:2030(E)`
144
+ ====
145
+
146
+ *Technical Report*, *Technical Specification*::
147
+ `{publisher} (/{document type and stage}) ({document number}) (- {part number})? (: {copyright year}) ({ISO 639 language code})?` +
148
+ +
149
+ ====
150
+ `ISO/IEC/FDIS TS 33333-2`, `ISO/TR 33333-2:2030(E)`, `ISO/IEC TR 33333-2:2030(E)`
151
+ ====
152
+
153
+ *Amendments*, *Technical Corrigendum*::
154
+ `{source document ID}/{document type and stage} {update number} (: {copyright year}) ({ISO 639 language code})?` +
155
+ +
156
+ ====
157
+ `ISO 33333-2:2030/DIS Cor 2:2031`, `ISO 33333-2:2030/Cor 2:2032`, `ISO/IEC 33333-2:2030/Cor 2:2032`
158
+ ====
159
+
160
+
161
+ // === Title
162
+
163
+ // `:title-intro-{en,fr}:`:: The introductory component of the English or French
164
+ // title of the document.
165
+
166
+ // `:title-main-{en,fr}:`:: The main component of the English or French title of
167
+ // the document (mandatory).
168
+
169
+ // `:title-part-{en,fr}:`:: The English or French title of the document part.
170
+
171
+ // `:title-amendment-{en,fr}:`:: (only when `doctype` is set to `amendment` or `technical-corrigendum`)
172
+ // The English or French title of the amendment [added in https://github.com/metanorma/isodoc/releases/tag/v1.3.25]
173
+
174
+ // `:amendment-number:`:: (only when `doctype` is set to `amendment`)
175
+ // The number of the amendment [added in https://github.com/metanorma/isodoc/releases/tag/v1.3.25]
176
+
177
+ // `:corrigendum-number:`:: (only when `doctype` is set to `technical-corrigendum`)
178
+ // The number of the technical corrigendum [added in https://github.com/metanorma/isodoc/releases/tag/v1.3.25]
179
+
@@ -0,0 +1,32 @@
1
+ module Pubid::Iso
2
+ class French < Identifier
3
+ def identifier(with_date, with_language_code)
4
+ if @type == "Guide"
5
+ "Guide #{originator}#{stage} #{number}#{part}#{iteration}"\
6
+ "#{with_date && rendered_year || ''}#{edition}#{supplements}#{language(with_language_code)}"
7
+ else
8
+ super
9
+ end
10
+ end
11
+
12
+ def copublisher
13
+ super.map { |copublisher| copublisher.sub("IEC", "CEI") }
14
+ end
15
+
16
+ def amendment
17
+ if @amendment_number
18
+ "Amd.#{@amendment_version}:#{@amendment_number}"
19
+ else
20
+ "Amd.#{@amendment_version}"
21
+ end
22
+ end
23
+
24
+ def corrigendum
25
+ if @corrigendum_number
26
+ "Cor.#{@corrigendum_version}:#{@corrigendum_number}"
27
+ else
28
+ "Cor.#{@corrigendum_version}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ module Pubid::Iso
2
+ class Russian < Identifier
3
+ PUBLISHER = { "ISO" => "ИСО", "IEC" => "МЭК" }.freeze
4
+ STAGE = { "FDIS" => "ОПМС",
5
+ "DIS" => "ПМС",
6
+ "NP" => "НП",
7
+ "AWI" => "АВИ",
8
+ "CD" => "КПК",
9
+ "PD" => "ПД",
10
+ "FPD" => "ФПД",
11
+
12
+
13
+ }.freeze
14
+ TYPE = { "Guide" => "Руководство",
15
+ "TS" => "ТС",
16
+ "TR" => "ТО",
17
+ "ISP" => "ИСП",
18
+ }.freeze
19
+
20
+ def identifier(with_date, with_language_code)
21
+ if @type == "Guide"
22
+ "Руководство #{originator}#{stage} #{number}#{part}#{iteration}"\
23
+ "#{with_date && rendered_year || ''}#{edition}#{supplements}#{language(with_language_code)}"
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def publisher
30
+ PUBLISHER[@publisher]
31
+ end
32
+
33
+ def copublisher
34
+ super&.map { |copublisher| PUBLISHER[copublisher] }
35
+ end
36
+
37
+ def stage
38
+ "#{(@copublisher && ' ') || '/'}#{STAGE[@stage]}" if @stage
39
+ end
40
+ end
41
+ end
@@ -1,46 +1,191 @@
1
1
  module Pubid::Iso
2
2
  class Identifier
3
- STAGES = { NP: 10,
4
- WD: 20,
5
- CD: 30,
6
- DIS: 40,
7
- FDIS: 50,
8
- PRF: 50,
9
- IS: 60,
10
- Fpr: 50 }.freeze
11
-
12
3
  attr_accessor :number, :publisher, :copublisher, :stage, :substage, :part,
13
- :type, :year, :edition, :iteration, :supplements, :language
14
-
15
- def initialize(stage: nil, supplements: nil, **opts)
16
- if stage
17
- @stage = STAGES[stage.to_sym]
18
- @substage = 0
19
- end
20
-
21
- # XXX: temporary hack for ISO/IEC 19794-7:2014/Amd 1:2015/CD Cor 1 parsing
22
- supplements&.each do |supplement|
23
- if supplement[:stage]
24
- @stage = STAGES[Transformer.new.apply(stage: supplement[:stage].to_s)[:stage].to_sym]
25
- @substage = 0
26
- end
27
- end
4
+ :type, :year, :edition, :iteration, :supplements, :language,
5
+ :amendment, :amendment_version, :amendment_number,
6
+ :corrigendum, :corrigendum_version, :corrigendum_number,
7
+ :amendment_stage, :corrigendum_stage, :joint_document,
8
+ :tctype, :sctype, :wgtype, :tcnumber, :scnumber, :wgnumber
28
9
 
29
- @supplements = supplements
10
+ LANGUAGES = {
11
+ "ru" => "R",
12
+ "fr" => "F",
13
+ "en" => "E",
14
+ "ar" => "A",
15
+ }.freeze
30
16
 
17
+ def initialize(**opts)
31
18
  opts.each { |key, value| send("#{key}=", value.is_a?(Array) && value || value.to_s) }
32
19
  end
33
20
 
21
+ def get_params
22
+ instance_variables.map { |var| [var.to_s.gsub("@", "").to_sym, instance_variable_get(var)] }.to_h
23
+ end
24
+
34
25
  def urn
35
- URN.new(self)
26
+ Urn.new(**get_params)
36
27
  end
37
28
 
38
- def self.parse(code)
39
- new(**Parser.new.parse(code).map do |k, v|
40
- Transformer.new.apply(k => v).to_a.first
41
- end.to_h)
29
+ def self.parse(code_or_params)
30
+ params = code_or_params.is_a?(String) ? Parser.new.parse(code_or_params) : code_or_params
31
+ # Parslet returns an array when match any copublisher
32
+ # otherwise it's hash
33
+ if params.is_a?(Array)
34
+ new(
35
+ **(
36
+ params.inject({}) do |r, i|
37
+ result = r
38
+ i.map {|k, v| Transformer.new.apply(k => v).to_a.first }.each do |k, v|
39
+ result = result.merge(k => r.key?(k) ? [v, r[k]] : v)
40
+ end
41
+ result
42
+ end
43
+ )
44
+ )
45
+ else
46
+ new(**params.map do |k, v|
47
+ Transformer.new.apply(k => v).to_a.first
48
+ end.to_h)
49
+ end
50
+ # merge values repeating keys into array (for copublishers)
51
+
52
+
53
+ # params.to_h)
42
54
  rescue Parslet::ParseFailed => failure
43
55
  raise Pubid::Iso::Errors::ParseError, "#{failure.message}\ncause: #{failure.parse_failure_cause.ascii_tree}"
44
56
  end
57
+
58
+ def to_s(lang: nil, with_date: true, with_language_code: :iso)
59
+ # @pubid_language = lang
60
+ case lang
61
+ when :french
62
+ French.new(**get_params)
63
+ when :russian
64
+ Russian.new(**get_params)
65
+ else
66
+ self
67
+ end.identifier(with_date, with_language_code) + (@joint_document && "|#{@joint_document}").to_s
68
+ end
69
+
70
+ def identifier(with_date, with_language_code)
71
+ if @tctype
72
+ "#{originator} #{tctype} #{tcnumber}#{sctype}#{wgtype} N#{number}"
73
+ else
74
+ "#{originator}#{type}#{stage} #{number}#{part}#{iteration}"\
75
+ "#{with_date && rendered_year || ''}#{edition}#{supplements}#{language(with_language_code)}"
76
+ end
77
+ end
78
+
79
+ def tctype
80
+ return @tctype.join("/") if @tctype.is_a?(Array)
81
+
82
+ @tctype
83
+ end
84
+
85
+ # TC 184/SC/WG 4 - no wg number
86
+ # TC 184/SC 4/WG 12 - separate sc and wg number
87
+ def sctype
88
+ return unless @sctype
89
+
90
+ if @wgnumber || !@wgtype
91
+ "/#{@sctype} #{@scnumber}"
92
+ else
93
+ "/#{@sctype}"
94
+ end
95
+ end
96
+
97
+ def wgtype
98
+ return unless @wgtype
99
+
100
+ if @wgnumber
101
+ "/#{@wgtype} #{@wgnumber}"
102
+ else
103
+ "/#{@wgtype} #{@scnumber}"
104
+ end
105
+ end
106
+
107
+ def copublisher
108
+ return nil unless @copublisher
109
+
110
+ (!@copublisher.is_a?(Array) && [@copublisher]) || @copublisher
111
+ end
112
+
113
+ def originator
114
+ if copublisher
115
+ # @copublisher = [@copublisher] unless @copublisher.is_a?(Array)
116
+ # @copublisher.map! { |copublisher| copublisher.sub("IEC", "CEI") } if @french
117
+ publisher + copublisher.map(&:to_s).sort.map do |copublisher|
118
+ "/#{copublisher.gsub('-', '/')}"
119
+ end.join
120
+ else
121
+ publisher
122
+ end
123
+ end
124
+
125
+ def stage
126
+ "#{(@copublisher && ' ') || '/'}#{@stage}" if @stage
127
+ end
128
+
129
+ def part
130
+ "-#{@part}" if @part
131
+ end
132
+
133
+ def rendered_year
134
+ @year && ":#{@year}"
135
+ end
136
+
137
+ def type
138
+ "#{(@copublisher && ' ') || '/'}#{@type}" if @type
139
+ end
140
+
141
+ def edition
142
+ " ED#{@edition}" if @edition
143
+ end
144
+
145
+ def iteration
146
+ ".#{@iteration}" if @iteration
147
+ end
148
+
149
+ def amendment
150
+ if @amendment_number
151
+ "Amd #{@amendment_version}:#{@amendment_number}"
152
+ else
153
+ "Amd #{@amendment_version}"
154
+ end
155
+ end
156
+
157
+ def corrigendum
158
+ if @corrigendum_number
159
+ "Cor #{@corrigendum_version}:#{@corrigendum_number}"
160
+ else
161
+ "Cor #{@corrigendum_version}"
162
+ end
163
+ end
164
+
165
+ def supplements
166
+ result = ""
167
+ if @amendment_version
168
+ result += (@amendment_stage && "/#{@amendment_stage} ") || "/"
169
+ result += amendment
170
+ end
171
+
172
+ if @corrigendum_version
173
+ result += (@corrigendum_stage && "/#{@corrigendum_stage} ") || "/"
174
+ result += corrigendum
175
+ end
176
+
177
+ result
178
+ end
179
+
180
+ def language(with_language_code = :iso)
181
+ if @language
182
+ if with_language_code == :single
183
+ "(#{LANGUAGES[@language]})"
184
+ else
185
+ "(#{@language})"
186
+ end
187
+ end
188
+ end
189
+
45
190
  end
46
191
  end
@@ -17,13 +17,22 @@ module Pubid::Iso
17
17
  # Stage 50.60: PRF ("proof") (non-public)
18
18
  # Stage 60: IS
19
19
  class Parser < Parslet::Parser
20
+ rule(:space) { str(" ") }
21
+ rule(:space?) { space.maybe }
22
+
20
23
  rule(:digits) do
21
24
  match('\d').repeat(1)
22
25
  end
23
26
 
24
27
  rule(:stage) do
25
- (str("NP") | str("WD") | str("CD") | str("DIS") | str("FDIS") | str("PRF") |
26
- str("IS") | str("AWI") | str("FD") | str("D")).as(:stage)
28
+ Russian::STAGE.values.reduce(
29
+ # other stages
30
+ str("NP") | str("WD") | str("CD") | str("DIS") | str("FDIS") | str("PRF") |
31
+ str("IS") | str("AWI") | str("PWI") |
32
+ # AMD and COR stages
33
+ str("FPD") | str("pD") | str("PD") | str("FD") | str("D")) do |acc, stage|
34
+ acc | str(stage)
35
+ end
27
36
  end
28
37
 
29
38
  # TYPES = {
@@ -36,32 +45,62 @@ module Pubid::Iso
36
45
  # # type = "data" / "guide" / "isp" / "iwa" /
37
46
  # # "pas" / "r" / "tr" / "ts" / "tta"
38
47
  rule(:type) do
39
- (str("DATA") | str("ISP") | str("IWA") | str("R") | str("TTA") |
40
- str("TS") | str("TR") | str("PAS") | str("Guide")).as(:type)
48
+ (
49
+ Russian::TYPE.values.reduce(
50
+ str("DATA") | str("ISP") | str("IWA") | str("R") | str("TTA") |
51
+ str("TS") | str("TR") | str("PAS") | str("Guide") | str("GUIDE")) do |acc, type|
52
+ acc | str(type)
53
+ end
54
+ ).as(:type)
55
+ end
56
+
57
+ rule(:tctype) do
58
+ # tc-types
59
+ str("TC") | str("JTC") | str("PC") | str("IT") | str("CAB") | str("CASCO") | str("COPOLCO") |
60
+ str("COUNCIL") | str("CPSG") | str("CS") | str("DEVCO") | str("GA") | str("GAAB") | str("INFCO") |
61
+ str("ISOlutions") | str("ITN") | str("REMCO") | str("TMB") | str("TMBG") | str("WMO") |
62
+ str("DMT") | str("JCG") | str("SGPM") | str("ATMG") | str("CCCC") | str("CCCC-TG") | str("JDMT") |
63
+ str("JSAG") | str("JSCTF-TF") | str("JTCG") | str("JTCG-TF") | str("SAG_Acc") | str("SAG_CRMI") |
64
+ str("SAG_CRMI_CG") | str("SAG_ESG") | str("SAG_ESG_CG") | str("SAG_MRS") | str("SAG SF") | str("SAG SF_CG") |
65
+ str("SMCC") | str("STMG") | str("MENA STAR")
66
+ end
67
+
68
+ rule(:sctype) do
69
+ str("SC")
70
+ end
71
+
72
+ rule(:wgtype) do
73
+ str("AG") | str("AHG") | str("AhG") | str("WG") | str("JWG") | str("QC") | str("TF") |
74
+ str("PPC") | str("CAG") | str("WG SGDG") | str("WG SR") | str("STAR") | str("STTF") | str("TIG") |
75
+ str("CPAG") | str("CSC") | str("ITSAG") | str("CSC/FIN") | str("CSC/NOM") | str("CSC/OVE") |
76
+ str("CSC/SP") | str("CSC/FIN") | str("JAG")
41
77
  end
42
78
 
43
79
  rule(:year) do
44
- match('\d').repeat(4, 4)
80
+ match('\d').repeat(4, 4).as(:year)
45
81
  end
46
82
 
47
83
  rule(:part) do
48
- (str("-") | str("/")) >> str(" ").maybe >>
49
- (match['[\dA-Z]'] | str("-")).repeat(1).as(:part)
84
+ (str("-") | str("/")) >> space? >>
85
+ (str("Amd") | str("Cor")).absent? >> (match['[\dA-Z]'] | str("-")).repeat(1).as(:part)
50
86
  end
51
87
 
52
88
  rule(:originator) do
53
89
  organization.as(:publisher) >>
54
- (str(" ").maybe >> str("/") >> organization.as(:copublisher)).maybe
90
+ (space? >> str("/") >> organization.as(:copublisher)).repeat
55
91
  end
56
92
 
57
93
  rule(:organization) do
58
- str("IEC/IEEE") | str("IEC") | str("IEEE") | str("CIW") | str("SAE") |
94
+ Russian::PUBLISHER.values.reduce(
95
+ str("IEC") | str("IEEE") | str("CIW") | str("SAE") |
59
96
  str("CIE") | str("ASME") | str("ASTM") | str("OECD") | str("ISO") |
60
- str("IWA") | str("HL7")
97
+ str("IWA") | str("HL7") | str("CEI")) do |acc, publisher|
98
+ acc | str(publisher)
99
+ end
61
100
  end
62
101
 
63
102
  rule(:edition) do
64
- str(" ") >> ((str("ED") | str("Ed ") | str("Ed.")) >>
103
+ space >> ((str("ED") | str("Ed ") | str("Ed.")) >>
65
104
  digits.as(:edition) | str("Ed").as(:edition))
66
105
  end
67
106
 
@@ -69,33 +108,75 @@ module Pubid::Iso
69
108
  str(".") >> digits.as(:iteration)
70
109
  end
71
110
 
72
- rule(:supplement) do
73
- (str("/") | str(" ")).maybe >>
74
- (str("Amd") | str("AMD") | str("Cor") | str("COR")).as(:supplement) >>
75
- str(" ") >>
76
- digits.as(:supplement_version) >>
77
- (str(":") >> digits.as(:supplement_number)).maybe
111
+ rule(:amendment) do
112
+ (str("/") >> stage.as(:amendment_stage)).maybe >>
113
+ (str("/") | space).maybe >>
114
+ (str("Amd") | str("AMD") | str("AM")).as(:amendment) >>
115
+ (space | str(".")) >>
116
+ digits.as(:amendment_version) >>
117
+ (str(":") >> digits.as(:amendment_number)).maybe
118
+ end
119
+
120
+ rule(:corrigendum) do
121
+ (str("/") >> stage.as(:corrigendum_stage)).maybe >>
122
+ (str("/") | space).maybe >>
123
+ (str("Cor") | str("COR")).as(:corrigendum) >>
124
+ (space | str(".")) >>
125
+ digits.as(:corrigendum_version) >>
126
+ (str(":") >> digits.as(:corrigendum_number)).maybe
78
127
  end
79
128
 
80
129
  rule(:language) do
81
- str("(") >> match["a-z"].repeat(1).as(:language) >> str(")")
130
+ str("(") >> (
131
+ ( # parse ru,en,fr
132
+ (match["a-z"].repeat(1) >> str(",").maybe) |
133
+ # parse R/E/F
134
+ ((str("E") | str("F") | str("A") | str("R")) >> str("/").maybe)
135
+ ).repeat.as(:language)
136
+ ) >> str(")")
137
+ end
138
+
139
+ rule(:guide_prefix) do
140
+ str("Guide") | str("GUIDE") | str("Руководство") | str("Руководства")
141
+ end
142
+
143
+ # Parse technical committee documents
144
+ rule(:tc_document_body) do
145
+ (tctype.as(:tctype) >> str("/").maybe).repeat >> space >> digits.as(:tcnumber) >>
146
+ (str("/") >> (
147
+ ((sctype.as(:sctype) >> space >> digits.as(:scnumber) >> str("/")).maybe >>
148
+ wgtype.as(:wgtype) >> space >> digits.as(:wgnumber)) |
149
+ (sctype.as(:sctype) >> (space | str("/") >> wgtype.as(:wgtype) >> space) >> digits.as(:scnumber))
150
+ )).maybe >>
151
+ str(" N") >> space? >> digits.as(:number)
152
+ end
153
+
154
+ rule(:std_document_body) do
155
+ (type | stage.as(:stage)).maybe >>
156
+ # for ISO/IEC WD TS 25025
157
+ space? >> ((stage.as(:stage) | type) >> space).maybe >>
158
+ digits.as(:number) >>
159
+ # for identifiers like ISO 5537/IDF 26
160
+ (str("|") >> (str("IDF") >> space >> digits).as(:joint_document)).maybe >>
161
+ part.maybe >> iteration.maybe >>
162
+ (space? >> str(":") >> year).maybe >>
163
+ # stage before amendment
164
+ (
165
+ # stage before corrigendum
166
+ ((amendment >> corrigendum.maybe) | corrigendum).maybe) >>
167
+ edition.maybe >>
168
+ language.maybe
82
169
  end
83
170
 
84
171
  rule(:identifier) do
85
172
  str("Fpr").as(:stage).maybe >>
86
173
  # Withdrawn e.g: WD/ISO 10360-5:2000
87
174
  str("WD/").maybe >>
88
- originator >> ((str(" ") | str("/")) >>
89
- # for ISO/FDIS
90
- (type | stage)).maybe >>
91
- # for ISO/IEC WD TS 25025
92
- str(" ").maybe >> ((stage | type) >> str(" ")).maybe >>
93
- digits.as(:number) >> part.maybe >> iteration.maybe >>
94
- (str(" ").maybe >> str(":") >> year).maybe >>
95
- ((str("/") >> stage).maybe >>
96
- supplement).repeat.as(:supplements) >>
97
- edition.maybe >>
98
- language.maybe
175
+ # for French and Russian PubIDs starting with Guide type
176
+ (guide_prefix.as(:type) >> space).maybe >>
177
+ (stage.as(:stage) >> space).maybe >>
178
+ originator >> (space | str("/")) >>
179
+ (tc_document_body | std_document_body)
99
180
  end
100
181
 
101
182
  rule(:root) { identifier }
@@ -4,16 +4,93 @@ module Pubid::Iso
4
4
  { edition: "1" }
5
5
  end
6
6
 
7
- rule(stage: simple(:stage)) do
8
- { stage: case stage
9
- when "D"
10
- "DIS"
11
- when "FD"
12
- "FDIS"
13
- else
14
- stage
15
- end
7
+ rule(stage: simple(:stage)) do |context|
8
+ { stage: convert_stage(context[:stage]) }
9
+ end
10
+
11
+ rule(amendment_stage: simple(:amendment_stage)) do |context|
12
+ { amendment_stage: convert_stage(context[:amendment_stage]) }
13
+ end
14
+
15
+ rule(corrigendum_stage: simple(:corrigendum_stage)) do |context|
16
+ { corrigendum_stage: convert_stage(context[:corrigendum_stage]) }
17
+ end
18
+
19
+ rule(language: simple(:language)) do |context|
20
+ if context[:language].to_s.include?("/")
21
+ { language: context[:language]
22
+ .to_s.split("/")
23
+ .map { |code| convert_language(code) }.join(",") }
24
+ else
25
+ { language: convert_language(context[:language]) }
26
+ end
27
+ end
28
+
29
+ rule(type: simple(:type)) do
30
+ russian_type = Russian::TYPE.key(type.to_s)
31
+ { type: russian_type&.to_s ||
32
+ case type
33
+ # XXX: can't put 2 alternative Russian translations to dictionary, temporary hack
34
+ when "GUIDE", "Руководства"
35
+ "Guide"
36
+ when "ТС"
37
+ "TS"
38
+ when "ТО"
39
+ "TR"
40
+ else
41
+ type
42
+ end
43
+ }
44
+ end
45
+
46
+ rule(copublisher: simple(:copublisher)) do
47
+ russian_copublisher = Russian::PUBLISHER.key(copublisher.to_s)
48
+ { copublisher: russian_copublisher&.to_s ||
49
+ case copublisher
50
+ when "CEI"
51
+ "IEC"
52
+ else
53
+ copublisher
54
+ end
16
55
  }
17
56
  end
57
+
58
+ rule(publisher: simple(:publisher)) do
59
+ russian_publisher = Russian::PUBLISHER.key(publisher.to_s)
60
+ { publisher: russian_publisher&.to_s || publisher }
61
+ end
62
+
63
+ def self.convert_stage(code)
64
+ russian_code = Russian::STAGE.key(code.to_s)
65
+ return russian_code.to_s if russian_code
66
+
67
+ case code
68
+ when "D"
69
+ "DIS"
70
+ when "FD"
71
+ "FDIS"
72
+ when "Fpr"
73
+ "PRF"
74
+ when "pD", "PD"
75
+ "CD"
76
+ else
77
+ code
78
+ end
79
+ end
80
+
81
+ def self.convert_language(code)
82
+ case code
83
+ when "R"
84
+ "ru"
85
+ when "F"
86
+ "fr"
87
+ when "E"
88
+ "en"
89
+ when "A"
90
+ "ar"
91
+ else
92
+ code
93
+ end
94
+ end
18
95
  end
19
96
  end
data/lib/pubid/iso/urn.rb CHANGED
@@ -1,9 +1,18 @@
1
1
  module Pubid::Iso
2
- class URN
3
- attr_accessor :identifier
2
+ class Urn < Identifier
4
3
 
5
- def initialize(identifier)
6
- @identifier = identifier
4
+ STAGES = { PWI: 0,
5
+ NP: 10,
6
+ AWI: 20,
7
+ WD: 20.20,
8
+ CD: 30,
9
+ DIS: 40,
10
+ FDIS: 50,
11
+ PRF: 50,
12
+ IS: 60 }.freeze
13
+
14
+ def initialize(**opts)
15
+ opts.each { |key, value| send("#{key}=", value) }
7
16
  end
8
17
 
9
18
  def to_s
@@ -11,58 +20,104 @@ module Pubid::Iso
11
20
  # [[":" status] ":" edition]
12
21
  # [":" docversion] [":" language]
13
22
 
14
- "urn:iso:std:#{originator}#{type}:#{identifier.number}#{part}#{stage}#{edition}#{supplement}#{language}"
23
+ if tctype
24
+ "urn:iso:doc:#{originator}:#{tctype.downcase}:#{tcnumber}#{sctype}#{wgtype}:#{number}"
25
+ else
26
+ "urn:iso:std:#{originator}#{type}:#{number}#{part}#{stage}#{edition}#{supplement}#{language}"
27
+ end
28
+ end
29
+
30
+ def tctype
31
+ return @tctype.join(":") if @tctype.is_a?(Array)
32
+
33
+ @tctype
34
+ end
35
+
36
+ def sctype
37
+ return unless @sctype
38
+
39
+ ":#{@sctype.downcase}:#{@scnumber}"
40
+ end
41
+
42
+ def wgtype
43
+ return unless @wgtype
44
+
45
+ if @wgnumber
46
+ ":#{@wgtype.downcase}:#{@wgnumber}"
47
+ else
48
+ ":#{@wgtype.downcase}"
49
+ end
15
50
  end
16
51
 
17
52
  def part
18
- ":-#{identifier.part}" if identifier.part
53
+ ":-#{@part}" if @part
54
+ end
55
+
56
+ def render_stage(stage)
57
+ ":stage-#{sprintf('%05.2f', STAGES[stage.to_sym])}#{iteration}"
19
58
  end
20
59
 
21
60
  def stage
22
- ":stage-#{identifier.stage}.#{sprintf('%02d', identifier.substage)}#{iteration}" if identifier.stage
61
+ return render_stage(@stage) if @stage
62
+
63
+ return render_stage(@amendment_stage) if @amendment_stage
64
+
65
+ render_stage(@corrigendum_stage) if @corrigendum_stage
23
66
  end
24
67
 
25
68
  def originator
26
69
  # originator = "iso" / "iso-iec" / "iso-cie" / "iso-astm" /
27
70
  # "iso-ieee" / "iec"
28
71
 
29
- if identifier.copublisher
30
- "#{identifier.publisher.downcase}-#{identifier.copublisher.downcase.gsub('/', '-')}"
72
+ if @copublisher
73
+ @copublisher = [@copublisher] unless @copublisher.is_a?(Array)
74
+ @publisher.downcase + @copublisher.map(&:to_s).sort.map do |copublisher|
75
+ "-#{copublisher.downcase.gsub('/', '-')}"
76
+ end.join
31
77
  else
32
- identifier.publisher.downcase
78
+ @publisher.downcase
33
79
  end
34
80
  end
35
81
 
36
82
  def edition
37
- ":ed-#{identifier.edition}" if identifier.edition
83
+ ":ed-#{@edition}" if @edition
38
84
  end
39
85
 
40
86
  def iteration
41
- ".v#{identifier.iteration}" if identifier.iteration
87
+ ".v#{@iteration}" if @iteration
42
88
  end
43
89
 
44
90
  def type
45
91
  # type = "data" / "guide" / "isp" / "iwa" /
46
92
  # "pas" / "r" / "tr" / "ts" / "tta"
47
-
48
- if identifier.type
49
- ":#{identifier.type.downcase}"
93
+ if @type
94
+ ":#{@type.downcase}"
50
95
  end
51
96
  end
52
97
 
53
98
  def supplement
54
- identifier.supplements&.map do |supplement|
55
- if supplement[:supplement_number]
56
- ":#{supplement[:supplement].to_s.downcase}:#{supplement[:supplement_number]}:v#{supplement[:supplement_version]}"
57
- else
58
- ":#{supplement[:supplement].to_s.downcase}:v#{supplement[:supplement_version]}"
59
- end
60
- end&.join
99
+ result = ""
100
+ if @amendment
101
+ result += if @amendment_number
102
+ ":amd:#{@amendment_number}:v#{@amendment_version}"
103
+ else
104
+ ":amd:#{@amendment_version}:v1"
105
+ end
106
+ end
107
+ if @corrigendum
108
+ result += if @corrigendum_number
109
+ ":cor:#{@corrigendum_number}:v#{@corrigendum_version}"
110
+ else
111
+ ":cor:#{@corrigendum_version}:v1"
112
+ end
113
+ end
114
+
115
+ result
61
116
  end
62
117
 
63
118
  def language
64
- if identifier.language
65
- ":#{identifier.language}"
119
+ if @language
120
+ ":#{@language}"
66
121
  end
67
122
  end
68
123
  end
@@ -1,5 +1,5 @@
1
1
  module Pubid
2
2
  module Iso
3
- VERSION = "0.1.1".freeze
3
+ VERSION = "0.1.4".freeze
4
4
  end
5
5
  end
data/lib/pubid/iso.rb CHANGED
@@ -11,5 +11,7 @@ end
11
11
  require_relative "iso/errors"
12
12
  require_relative "iso/parser"
13
13
  require_relative "iso/transformer"
14
- require_relative "iso/urn"
15
14
  require_relative "iso/identifier"
15
+ require_relative "iso/identifier/french"
16
+ require_relative "iso/identifier/russian"
17
+ require_relative "iso/urn"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pubid-iso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-06 00:00:00.000000000 Z
11
+ date: 2022-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -109,6 +109,8 @@ files:
109
109
  - lib/pubid/iso.rb
110
110
  - lib/pubid/iso/errors.rb
111
111
  - lib/pubid/iso/identifier.rb
112
+ - lib/pubid/iso/identifier/french.rb
113
+ - lib/pubid/iso/identifier/russian.rb
112
114
  - lib/pubid/iso/parser.rb
113
115
  - lib/pubid/iso/transformer.rb
114
116
  - lib/pubid/iso/urn.rb
@@ -117,7 +119,7 @@ homepage: https://github.com/metanorma/pubid-iso
117
119
  licenses:
118
120
  - BSD-2-Clause
119
121
  metadata: {}
120
- post_install_message:
122
+ post_install_message:
121
123
  rdoc_options: []
122
124
  require_paths:
123
125
  - lib
@@ -132,8 +134,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
134
  - !ruby/object:Gem::Version
133
135
  version: '0'
134
136
  requirements: []
135
- rubygems_version: 3.3.3
136
- signing_key:
137
+ rubygems_version: 3.0.3.1
138
+ signing_key:
137
139
  specification_version: 4
138
140
  summary: Library to generate, parse and manipulate ISO PubID.
139
141
  test_files: []