pubid-iso 0.1.1 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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: []