pubid 2.0.0.pre.alpha.3 → 2.0.0.pre.alpha.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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pubid/amca/identifier.rb +4 -23
  3. data/lib/pubid/amca/identifiers/base.rb +67 -30
  4. data/lib/pubid/amca/identifiers/interpretation.rb +0 -4
  5. data/lib/pubid/amca/identifiers/publication.rb +0 -4
  6. data/lib/pubid/amca/identifiers/standard.rb +0 -4
  7. data/lib/pubid/amca/renderer.rb +1 -1
  8. data/lib/pubid/amca/urn_generator.rb +2 -1
  9. data/lib/pubid/api/builder.rb +4 -0
  10. data/lib/pubid/api/identifier.rb +5 -1
  11. data/lib/pubid/api/identifiers/base.rb +2 -12
  12. data/lib/pubid/api/identifiers/mpms.rb +0 -4
  13. data/lib/pubid/api/identifiers/typeless_standard.rb +0 -3
  14. data/lib/pubid/api/single_identifier.rb +5 -8
  15. data/lib/pubid/ashrae/identifier.rb +7 -22
  16. data/lib/pubid/ashrae/identifiers/base.rb +28 -17
  17. data/lib/pubid/ashrae/parser.rb +4 -0
  18. data/lib/pubid/ashrae.rb +4 -0
  19. data/lib/pubid/asme/single_identifier.rb +3 -1
  20. data/lib/pubid/astm/single_identifier.rb +3 -1
  21. data/lib/pubid/bsi/identifier.rb +5 -31
  22. data/lib/pubid/bsi/identifiers/addendum_document.rb +0 -4
  23. data/lib/pubid/bsi/identifiers/adopted_european_norm.rb +0 -4
  24. data/lib/pubid/bsi/identifiers/adopted_international_standard.rb +0 -4
  25. data/lib/pubid/bsi/identifiers/aerospace_standard.rb +0 -3
  26. data/lib/pubid/bsi/identifiers/amendment.rb +0 -4
  27. data/lib/pubid/bsi/identifiers/british_industrial_practice.rb +0 -3
  28. data/lib/pubid/bsi/identifiers/bundled_identifier.rb +2 -5
  29. data/lib/pubid/bsi/identifiers/committee_document.rb +0 -3
  30. data/lib/pubid/bsi/identifiers/consolidated_identifier.rb +2 -5
  31. data/lib/pubid/bsi/identifiers/corrigendum.rb +0 -4
  32. data/lib/pubid/bsi/identifiers/detailed_specification.rb +0 -3
  33. data/lib/pubid/bsi/identifiers/disc.rb +0 -3
  34. data/lib/pubid/bsi/identifiers/draft_document.rb +0 -3
  35. data/lib/pubid/bsi/identifiers/electronic_book.rb +0 -3
  36. data/lib/pubid/bsi/identifiers/expert_commentary.rb +0 -4
  37. data/lib/pubid/bsi/identifiers/explanatory_supplement.rb +0 -3
  38. data/lib/pubid/bsi/identifiers/flex.rb +0 -3
  39. data/lib/pubid/bsi/identifiers/handbook.rb +0 -3
  40. data/lib/pubid/bsi/identifiers/index.rb +0 -3
  41. data/lib/pubid/bsi/identifiers/method.rb +0 -3
  42. data/lib/pubid/bsi/identifiers/national_annex.rb +0 -3
  43. data/lib/pubid/bsi/identifiers/practice_guide.rb +0 -3
  44. data/lib/pubid/bsi/identifiers/publicly_available_specification.rb +0 -3
  45. data/lib/pubid/bsi/identifiers/published_document.rb +0 -3
  46. data/lib/pubid/bsi/identifiers/section.rb +0 -3
  47. data/lib/pubid/bsi/identifiers/set.rb +2 -5
  48. data/lib/pubid/bsi/identifiers/standalone_amendment.rb +0 -3
  49. data/lib/pubid/bsi/identifiers/supplement_document.rb +0 -4
  50. data/lib/pubid/bsi/identifiers/supplementary_index.rb +0 -3
  51. data/lib/pubid/bsi/identifiers/technical_specification.rb +0 -3
  52. data/lib/pubid/bsi/identifiers/test_method.rb +0 -3
  53. data/lib/pubid/bsi/identifiers/value_added_publication.rb +0 -4
  54. data/lib/pubid/bsi/single_identifier.rb +32 -13
  55. data/lib/pubid/bsi.rb +8 -1
  56. data/lib/pubid/ccsds/identifier.rb +2 -14
  57. data/lib/pubid/cen_cenelec/identifier.rb +10 -8
  58. data/lib/pubid/cen_cenelec/identifiers/adopted_european_norm.rb +0 -4
  59. data/lib/pubid/cen_cenelec/identifiers/amendment.rb +0 -4
  60. data/lib/pubid/cen_cenelec/identifiers/base.rb +2 -9
  61. data/lib/pubid/cen_cenelec/identifiers/consolidated_identifier.rb +0 -4
  62. data/lib/pubid/cen_cenelec/identifiers/corrigendum.rb +0 -4
  63. data/lib/pubid/cen_cenelec/identifiers/european_prestandard.rb +0 -3
  64. data/lib/pubid/cen_cenelec/identifiers/fragment.rb +0 -4
  65. data/lib/pubid/cen_cenelec/single_identifier.rb +4 -7
  66. data/lib/pubid/cen_cenelec.rb +4 -0
  67. data/lib/pubid/cie/identifier.rb +4 -0
  68. data/lib/pubid/cie/single_identifier.rb +4 -4
  69. data/lib/pubid/cie.rb +4 -0
  70. data/lib/pubid/csa/identifier.rb +10 -1
  71. data/lib/pubid/csa/identifiers/base.rb +0 -3
  72. data/lib/pubid/csa/identifiers/cec.rb +0 -4
  73. data/lib/pubid/csa/identifiers/series.rb +0 -4
  74. data/lib/pubid/csa/single_identifier.rb +1 -1
  75. data/lib/pubid/csa.rb +4 -0
  76. data/lib/pubid/etsi/components/code.rb +1 -7
  77. data/lib/pubid/etsi/components/version.rb +0 -5
  78. data/lib/pubid/etsi/identifier.rb +4 -12
  79. data/lib/pubid/etsi/identifiers/base.rb +31 -24
  80. data/lib/pubid/etsi/identifiers/supplement_identifier.rb +0 -3
  81. data/lib/pubid/etsi.rb +3 -1
  82. data/lib/pubid/identifier.rb +90 -1
  83. data/lib/pubid/idf/identifier.rb +4 -0
  84. data/lib/pubid/idf.rb +4 -0
  85. data/lib/pubid/iec/identifier.rb +14 -14
  86. data/lib/pubid/iec/identifiers/base.rb +0 -4
  87. data/lib/pubid/iec/identifiers/consolidated_identifier.rb +0 -4
  88. data/lib/pubid/iec/identifiers/fragment_identifier.rb +1 -5
  89. data/lib/pubid/iec/identifiers/sheet_identifier.rb +1 -5
  90. data/lib/pubid/iec/identifiers/test_report_form.rb +0 -3
  91. data/lib/pubid/iec/identifiers/vap_identifier.rb +1 -5
  92. data/lib/pubid/iec/identifiers/working_document.rb +0 -4
  93. data/lib/pubid/iec.rb +4 -0
  94. data/lib/pubid/ieee/identifier.rb +5 -17
  95. data/lib/pubid/ieee/identifiers/adopted_standard.rb +0 -4
  96. data/lib/pubid/ieee/identifiers/base.rb +223 -201
  97. data/lib/pubid/ieee/identifiers/conformance_identifier.rb +0 -4
  98. data/lib/pubid/ieee/identifiers/corrigendum.rb +0 -4
  99. data/lib/pubid/ieee/identifiers/csa_dual_published.rb +0 -4
  100. data/lib/pubid/ieee/identifiers/dual_identifier.rb +0 -4
  101. data/lib/pubid/ieee/identifiers/dual_published.rb +0 -4
  102. data/lib/pubid/ieee/identifiers/iec_ieee_copublished.rb +0 -4
  103. data/lib/pubid/ieee/identifiers/interpretation_identifier.rb +0 -4
  104. data/lib/pubid/ieee/identifiers/multi_numbered_identifier.rb +0 -4
  105. data/lib/pubid/ieee/identifiers/parenthetical_identifier.rb +0 -4
  106. data/lib/pubid/ieee/identifiers/redlined_standard.rb +0 -4
  107. data/lib/pubid/ieee/identifiers/si_standard.rb +0 -4
  108. data/lib/pubid/ieee.rb +4 -0
  109. data/lib/pubid/iho/identifier.rb +7 -25
  110. data/lib/pubid/iho/identifiers/base.rb +62 -68
  111. data/lib/pubid/iho.rb +3 -1
  112. data/lib/pubid/iso/identifier.rb +15 -14
  113. data/lib/pubid/iso/single_identifier.rb +0 -4
  114. data/lib/pubid/iso.rb +4 -0
  115. data/lib/pubid/itu/components/code.rb +1 -7
  116. data/lib/pubid/itu/components/sector.rb +15 -4
  117. data/lib/pubid/itu/components/series.rb +0 -4
  118. data/lib/pubid/itu/identifier.rb +4 -18
  119. data/lib/pubid/itu/identifiers/base.rb +124 -122
  120. data/lib/pubid/itu.rb +3 -1
  121. data/lib/pubid/jcgm/identifiers/amendment.rb +0 -4
  122. data/lib/pubid/jcgm/identifiers/gum_guide.rb +0 -4
  123. data/lib/pubid/jcgm/single_identifier.rb +0 -4
  124. data/lib/pubid/jis/identifier.rb +2 -14
  125. data/lib/pubid/nist/identifier.rb +8 -23
  126. data/lib/pubid/nist/identifiers/base.rb +553 -544
  127. data/lib/pubid/nist/preprocessor.rb +12 -0
  128. data/lib/pubid/nist.rb +4 -0
  129. data/lib/pubid/oiml/builder.rb +21 -3
  130. data/lib/pubid/oiml/components/code.rb +7 -0
  131. data/lib/pubid/oiml/identifier.rb +44 -0
  132. data/lib/pubid/oiml/identifiers/annex.rb +10 -1
  133. data/lib/pubid/oiml/identifiers/errata.rb +15 -0
  134. data/lib/pubid/oiml/identifiers.rb +1 -1
  135. data/lib/pubid/oiml/parser.rb +59 -12
  136. data/lib/pubid/oiml/renderer.rb +27 -17
  137. data/lib/pubid/oiml/single_identifier.rb +58 -0
  138. data/lib/pubid/oiml/supplement_identifier.rb +30 -1
  139. data/lib/pubid/plateau/identifier.rb +4 -21
  140. data/lib/pubid/plateau/identifiers/base.rb +45 -36
  141. data/lib/pubid/plateau/identifiers/handbook.rb +0 -4
  142. data/lib/pubid/plateau/identifiers/technical_report.rb +0 -4
  143. data/lib/pubid/plateau/supplement_identifier.rb +0 -4
  144. data/lib/pubid/sae/identifier.rb +4 -12
  145. data/lib/pubid/sae/identifiers/base.rb +26 -17
  146. data/lib/pubid/version.rb +1 -1
  147. data/lib/pubid.rb +18 -2
  148. data/lib/tasks/export.rake +6 -5
  149. metadata +3 -4
  150. data/lib/pubid/identifier_facade.rb +0 -114
  151. data/lib/pubid/oiml/identifiers/base.rb +0 -21
@@ -6,229 +6,251 @@ module Pubid
6
6
  # Forward declare component classes
7
7
  end
8
8
 
9
- module Identifiers
10
- # Base class for all IEEE identifiers
11
- class Base < Pubid::Identifier
12
- # Generate URN for this identifier
13
- #
14
- # @return [String] URN representation
15
-
16
- attribute :publisher, :string, default: -> { "IEEE" }
17
- attribute :copublisher, :string, collection: true # IEC, ISO, ANSI, etc.
18
- attribute :code, :string # Will store code as object in initialize
19
- attribute :year, :string
20
- attribute :type, :string, default: -> { "Std" } # Std, Draft Std
21
- attribute :draft_status, :string # Unapproved, Approved, Active Unapproved
22
- attribute :draft, :string # Will store draft as object
23
- attribute :edition, :string # Edition 1.0
24
- attribute :month, :string
25
- attribute :day, :string
26
- attribute :redline, :boolean, default: -> { false }
27
- attribute :amendments, Base, collection: true # Amendment identifiers
28
- attribute :corrigenda, Base, collection: true # Corrigendum identifiers
29
- attribute :revision_of, Base # Revision relationships
30
- attribute :incorporates, Base, collection: true # Incorporated documents
31
- attribute :supersedes, Base, collection: true # Superseded documents
32
- attribute :supplement_to, Base # For supplements
33
- attribute :iso_identifier, :string # For IEC/IEEE formats
34
- attribute :parenthetical_content, :string # Raw parenthetical content
35
- attribute :note, :string # Parenthetical notes
36
- attribute :adoption, :string # Adoption notes
37
- attribute :amendment_to, :string # Amendment to relationships
38
- attribute :edition_month, :string # Month part from Edition YYYY-MM
39
- attribute :space_before_draft, :boolean, default: -> {
40
- false
41
- } # Track space before /D
42
- attribute :typed_stage, Components::TypedStage # TYPED_STAGE integration
43
- attribute :relationships, Components::Relationship, collection: true # Relationship metadata
44
- attribute :nickname, :string # Book nickname (e.g., "[The Orange Book]")
45
- attribute :interpretation, :boolean, default: -> {
46
- false
47
- } # /INT notation
48
- attribute :conf_number, :string # Conformance document number
49
- attribute :conf_year, :string # Conformance document year
50
- attribute :ashrae_number, :string # ASHRAE Guideline number
51
- attribute :ashrae_year, :string # ASHRAE Guideline year
52
- attribute :crossref, :string # IEEE cross-reference (e.g., /C62.22.1-1996)
53
- attribute :reaffirmed, :string # Reaffirmed year (e.g., "2010" for (R2010))
54
-
55
- # Store actual component objects
56
- attr_accessor :code_obj, :draft_obj
57
-
58
- def initialize(**args)
59
- super()
60
-
61
- # Handle typed_stage if provided
62
- if args[:typed_stage]
63
- self.typed_stage = args[:typed_stage]
64
- end
9
+ # Base class for all IEEE identifiers. Canonical name
10
+ # Pubid::Ieee::Identifier (Identifiers::Base is a back-compat alias). IEEE
11
+ # builds its identifiers as instances of this class directly.
12
+ class Identifier < ::Pubid::Identifier
13
+ # Generate URN for this identifier
14
+ #
15
+ # @return [String] URN representation
65
16
 
66
- # Handle code as component object
67
- if args[:code].is_a?(String)
68
- self.code_obj = Components::Code.parse(args[:code])
69
- self.code = args[:code]
70
- elsif args[:code]
71
- self.code_obj = args[:code]
72
- self.code = args[:code].to_s
73
- end
17
+ attribute :publisher, :string, default: -> { "IEEE" }
18
+ attribute :copublisher, :string, collection: true # IEC, ISO, ANSI, etc.
19
+ attribute :code, :string # Will store code as object in initialize
20
+ attribute :year, :string
21
+ attribute :type, :string, default: -> { "Std" } # Std, Draft Std
22
+ attribute :draft_status, :string # Unapproved, Approved, Active Unapproved
23
+ attribute :draft, :string # Will store draft as object
24
+ attribute :edition, :string # Edition 1.0
25
+ attribute :month, :string
26
+ attribute :day, :string
27
+ attribute :redline, :boolean, default: -> { false }
28
+ attribute :amendments, Identifier, collection: true # Amendment identifiers
29
+ attribute :corrigenda, Identifier, collection: true # Corrigendum identifiers
30
+ attribute :revision_of, Identifier # Revision relationships
31
+ attribute :incorporates, Identifier, collection: true # Incorporated documents
32
+ attribute :supersedes, Identifier, collection: true # Superseded documents
33
+ attribute :supplement_to, Identifier # For supplements
34
+ attribute :iso_identifier, :string # For IEC/IEEE formats
35
+ attribute :parenthetical_content, :string # Raw parenthetical content
36
+ attribute :note, :string # Parenthetical notes
37
+ attribute :adoption, :string # Adoption notes
38
+ attribute :amendment_to, :string # Amendment to relationships
39
+ attribute :edition_month, :string # Month part from Edition YYYY-MM
40
+ attribute :space_before_draft, :boolean, default: -> {
41
+ false
42
+ } # Track space before /D
43
+ attribute :typed_stage, Components::TypedStage # TYPED_STAGE integration
44
+ attribute :relationships, Components::Relationship, collection: true # Relationship metadata
45
+ attribute :nickname, :string # Book nickname (e.g., "[The Orange Book]")
46
+ attribute :interpretation, :boolean, default: -> {
47
+ false
48
+ } # /INT notation
49
+ attribute :conf_number, :string # Conformance document number
50
+ attribute :conf_year, :string # Conformance document year
51
+ attribute :ashrae_number, :string # ASHRAE Guideline number
52
+ attribute :ashrae_year, :string # ASHRAE Guideline year
53
+ attribute :crossref, :string # IEEE cross-reference (e.g., /C62.22.1-1996)
54
+ attribute :reaffirmed, :string # Reaffirmed year (e.g., "2010" for (R2010))
74
55
 
75
- # Handle draft as component object
76
- if args[:draft_obj]
77
- self.draft_obj = args[:draft_obj]
78
- self.draft = args[:draft_obj].to_s
79
- elsif args[:draft].is_a?(String)
80
- self.draft_obj = Components::Draft.parse(args[:draft])
81
- self.draft = draft_obj.to_s
82
- elsif args[:draft]
83
- self.draft_obj = args[:draft]
84
- self.draft = args[:draft].to_s
85
- end
56
+ # Store actual component objects
57
+ attr_accessor :code_obj, :draft_obj
86
58
 
87
- # Set other attributes
88
- attrs = self.class.attributes
89
- args.each do |key, value|
90
- next if %i[code draft draft_obj typed_stage].include?(key)
59
+ def initialize(**args)
60
+ super()
91
61
 
92
- setter = :"#{key}="
93
- public_send(setter, value) if attrs.key?(key)
94
- end
62
+ # Handle typed_stage if provided
63
+ if args[:typed_stage]
64
+ self.typed_stage = args[:typed_stage]
95
65
  end
96
66
 
97
- # Override accessors to return component objects
98
- def code
99
- code_obj
67
+ # Handle code as component object
68
+ if args[:code].is_a?(String)
69
+ self.code_obj = Components::Code.parse(args[:code])
70
+ self.code = args[:code]
71
+ elsif args[:code]
72
+ self.code_obj = args[:code]
73
+ self.code = args[:code].to_s
100
74
  end
101
75
 
102
- def draft
103
- draft_obj
76
+ # Handle draft as component object
77
+ if args[:draft_obj]
78
+ self.draft_obj = args[:draft_obj]
79
+ self.draft = args[:draft_obj].to_s
80
+ elsif args[:draft].is_a?(String)
81
+ self.draft_obj = Components::Draft.parse(args[:draft])
82
+ self.draft = draft_obj.to_s
83
+ elsif args[:draft]
84
+ self.draft_obj = args[:draft]
85
+ self.draft = args[:draft].to_s
104
86
  end
105
87
 
106
- # Expose numeric month from draft if available
107
- def draft_month
108
- return nil unless draft_obj.is_a?(Components::Draft)
88
+ # Set other attributes
89
+ attrs = self.class.attributes
90
+ args.each do |key, value|
91
+ next if %i[code draft draft_obj typed_stage].include?(key)
109
92
 
110
- draft_obj.numeric_month
93
+ setter = :"#{key}="
94
+ public_send(setter, value) if attrs.key?(key)
111
95
  end
96
+ end
112
97
 
113
- # Parse IEEE identifier string.
114
- #
115
- # PreParser owns all regex/dispatch logic; this method is a thin
116
- # orchestrator that consumes a PreParser::Result and routes to the
117
- # correct builder.
118
- def self.parse(input)
119
- result = PreParser.preprocess(input)
120
-
121
- case result.dispatch
122
- when :aiee_simple
123
- return Aiee::Identifier.parse(result.input)
124
- when :iec_ieee_copublished
125
- return parse_single(result.input)
126
- when :dual_semicolon
127
- return build_dual(result.parts)
128
- when :dual_reaffirmed
129
- return build_reaffirmed(result)
130
- when :dual_ire
131
- return build_dual_with_reaffirmed(result)
132
- when :dual_space_separated
133
- return build_dual(result.parts)
134
- when :dual_and
135
- return build_dual(result.parts)
136
- when :dual_ampersand
137
- return build_dual(result.parts)
138
- when :aiee_asa_adoption
139
- return build_aiee_asa_adoption(result.parts)
140
- when :adopted
141
- return build_adopted(result.parts)
142
- else
143
- parse_single(result.input)
144
- end
145
- rescue Parslet::ParseFailed
146
- parse_single(input)
147
- end
98
+ # Override accessors to return component objects.
99
+ def code
100
+ code_obj
101
+ end
148
102
 
149
- # ---- dispatch constructors (used by parse) ----
103
+ def draft
104
+ draft_obj
105
+ end
150
106
 
151
- def self.build_dual(parts)
152
- first = parse_single(parts[0])
153
- second = parse_single(parts[1])
154
- Identifiers::DualPublished.new(
155
- first_identifier: first,
156
- second_identifier: second,
157
- )
158
- end
159
- private_class_method :build_dual
107
+ # Lazily rebuild the parsed component objects from the underlying string
108
+ # attributes. After from_hash, lutaml restores the :code/:draft strings
109
+ # (@code/@draft) but not these objects; the renderer reads code_obj/
110
+ # draft_obj directly, so rebuild on demand to render a deserialized
111
+ # identifier identically to the parsed one. On the parse path code_obj/
112
+ # draft_obj are already set, so the `||=` returns them unchanged.
113
+ def code_obj
114
+ @code_obj ||=
115
+ (Components::Code.parse(@code.to_s) unless @code.nil? || @code.to_s.empty?)
116
+ end
160
117
 
161
- def self.build_reaffirmed(result)
162
- parsed = parse_single(result.input)
163
- parsed.reaffirmed = result.metadata[:reaffirmed] if parsed.class.attributes.key?(:reaffirmed)
164
- parsed
165
- end
166
- private_class_method :build_reaffirmed
167
-
168
- def self.build_dual_with_reaffirmed(result)
169
- ieee_id = parse_single(result.parts[0])
170
- ieee_id.reaffirmed = result.metadata[:reaffirmed] if ieee_id.class.attributes.key?(:reaffirmed)
171
- ire_id = parse_single(result.parts[1])
172
- Identifiers::DualPublished.new(
173
- first_identifier: ieee_id,
174
- second_identifier: ire_id,
175
- )
118
+ def draft_obj
119
+ @draft_obj ||=
120
+ (Components::Draft.parse(@draft.to_s) unless @draft.nil? || @draft.to_s.empty?)
121
+ end
122
+
123
+ # Expose numeric month from draft if available
124
+ def draft_month
125
+ return nil unless draft_obj.is_a?(Components::Draft)
126
+
127
+ draft_obj.numeric_month
128
+ end
129
+
130
+ # Parse IEEE identifier string.
131
+ #
132
+ # PreParser owns all regex/dispatch logic; this method is a thin
133
+ # orchestrator that consumes a PreParser::Result and routes to the
134
+ # correct builder.
135
+ def self.parse(input)
136
+ if input.length > Pubid::MAX_INPUT_LENGTH
137
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
176
138
  end
177
- private_class_method :build_dual_with_reaffirmed
178
-
179
- def self.build_aiee_asa_adoption(parts)
180
- aiee_id = parse_single(parts[0])
181
- asa_id = parse_single(parts[1])
182
- Identifiers::AdoptedStandard.new(
183
- ieee_identifier: aiee_id,
184
- adopted_identifier: asa_id,
185
- )
139
+
140
+ result = PreParser.preprocess(input)
141
+
142
+ case result.dispatch
143
+ when :aiee_simple
144
+ return Aiee::Identifier.parse(result.input)
145
+ when :iec_ieee_copublished
146
+ return parse_single(result.input)
147
+ when :dual_semicolon
148
+ return build_dual(result.parts)
149
+ when :dual_reaffirmed
150
+ return build_reaffirmed(result)
151
+ when :dual_ire
152
+ return build_dual_with_reaffirmed(result)
153
+ when :dual_space_separated
154
+ return build_dual(result.parts)
155
+ when :dual_and
156
+ return build_dual(result.parts)
157
+ when :dual_ampersand
158
+ return build_dual(result.parts)
159
+ when :aiee_asa_adoption
160
+ return build_aiee_asa_adoption(result.parts)
161
+ when :adopted
162
+ return build_adopted(result.parts)
163
+ else
164
+ parse_single(result.input)
186
165
  end
187
- private_class_method :build_aiee_asa_adoption
188
-
189
- def self.build_adopted(parts)
190
- ieee_id = parse_single(parts[0])
191
- adopted_parts = parts[1].split(",").map(&:strip)
192
- adopted_ids = adopted_parts.map do |part|
193
- if part.start_with?("IEC")
194
- Pubid::Iec.parse(normalize_iec_adoption(part))
195
- elsif part.start_with?("ANSI")
196
- Pubid::Ansi.parse(part)
197
- else
198
- parse_single(part)
199
- end
166
+ rescue Parslet::ParseFailed
167
+ parse_single(input)
168
+ end
169
+
170
+ # ---- dispatch constructors (used by parse) ----
171
+
172
+ def self.build_dual(parts)
173
+ first = parse_single(parts[0])
174
+ second = parse_single(parts[1])
175
+ Identifiers::DualPublished.new(
176
+ first_identifier: first,
177
+ second_identifier: second,
178
+ )
179
+ end
180
+ private_class_method :build_dual
181
+
182
+ def self.build_reaffirmed(result)
183
+ parsed = parse_single(result.input)
184
+ parsed.reaffirmed = result.metadata[:reaffirmed] if parsed.class.attributes.key?(:reaffirmed)
185
+ parsed
186
+ end
187
+ private_class_method :build_reaffirmed
188
+
189
+ def self.build_dual_with_reaffirmed(result)
190
+ ieee_id = parse_single(result.parts[0])
191
+ ieee_id.reaffirmed = result.metadata[:reaffirmed] if ieee_id.class.attributes.key?(:reaffirmed)
192
+ ire_id = parse_single(result.parts[1])
193
+ Identifiers::DualPublished.new(
194
+ first_identifier: ieee_id,
195
+ second_identifier: ire_id,
196
+ )
197
+ end
198
+ private_class_method :build_dual_with_reaffirmed
199
+
200
+ def self.build_aiee_asa_adoption(parts)
201
+ aiee_id = parse_single(parts[0])
202
+ asa_id = parse_single(parts[1])
203
+ Identifiers::AdoptedStandard.new(
204
+ ieee_identifier: aiee_id,
205
+ adopted_identifier: asa_id,
206
+ )
207
+ end
208
+ private_class_method :build_aiee_asa_adoption
209
+
210
+ def self.build_adopted(parts)
211
+ ieee_id = parse_single(parts[0])
212
+ adopted_parts = parts[1].split(",").map(&:strip)
213
+ adopted_ids = adopted_parts.map do |part|
214
+ if part.start_with?("IEC")
215
+ Pubid::Iec.parse(normalize_iec_adoption(part))
216
+ elsif part.start_with?("ANSI")
217
+ Pubid::Ansi.parse(part)
218
+ else
219
+ parse_single(part)
200
220
  end
201
- Identifiers::AdoptedStandard.new(
202
- ieee_identifier: ieee_id,
203
- adopted_identifiers: adopted_ids,
204
- )
205
- end
206
- private_class_method :build_adopted
207
-
208
- # "IEC 60255-24 Edition 2.0 2013-04" → "IEC 60255-24:2013-04 ED2.0"
209
- def self.normalize_iec_adoption(part)
210
- iec_part = part.dup
211
- iec_part.gsub!(/\s+Edition\s+([0-9.]+)\s+([0-9-]+)/, ':\2 ED\1')
212
- iec_part.gsub!(/\s+Edition\s+([0-9.]+)\s*$/, ' ED\1')
213
- iec_part
214
- end
215
- private_class_method :normalize_iec_adoption
216
-
217
- # Parse a single IEEE identifier
218
- def self.parse_single(input)
219
- # Apply legacy update_codes normalization first, before Parser's extensive preprocessing
220
- normalized = Core::UpdateCodes.apply(input, :ieee)
221
- parsed = Parser.parse(normalized) # Use class method for preprocessing
222
- builder = Builder.new(Base)
223
- # Pass the original input string to builder for context
224
- builder.original_input = input
225
- builder.build(parsed)
226
221
  end
222
+ Identifiers::AdoptedStandard.new(
223
+ ieee_identifier: ieee_id,
224
+ adopted_identifiers: adopted_ids,
225
+ )
226
+ end
227
+ private_class_method :build_adopted
227
228
 
228
- def to_s
229
- render(format: :human)
230
- end
229
+ # "IEC 60255-24 Edition 2.0 2013-04" → "IEC 60255-24:2013-04 ED2.0"
230
+ def self.normalize_iec_adoption(part)
231
+ iec_part = part.dup
232
+ iec_part.gsub!(/\s+Edition\s+([0-9.]+)\s+([0-9-]+)/, ':\2 ED\1')
233
+ iec_part.gsub!(/\s+Edition\s+([0-9.]+)\s*$/, ' ED\1')
234
+ iec_part
231
235
  end
236
+ private_class_method :normalize_iec_adoption
237
+
238
+ # Parse a single IEEE identifier
239
+ def self.parse_single(input)
240
+ # Apply legacy update_codes normalization first, before Parser's extensive preprocessing
241
+ normalized = Core::UpdateCodes.apply(input, :ieee)
242
+ parsed = Parser.parse(normalized) # Use class method for preprocessing
243
+ builder = Builder.new(Identifier)
244
+ # Pass the original input string to builder for context
245
+ builder.original_input = input
246
+ builder.build(parsed)
247
+ end
248
+ end
249
+
250
+ module Identifiers
251
+ # Backward-compatible alias: IEEE's base class used to be
252
+ # Pubid::Ieee::Identifiers::Base. It is now Pubid::Ieee::Identifier.
253
+ Base = Pubid::Ieee::Identifier
232
254
  end
233
255
  end
234
256
  end
@@ -19,10 +19,6 @@ module Pubid
19
19
  stage_code: "published",
20
20
  ),
21
21
  ].freeze
22
-
23
- def to_s
24
- render(format: :human)
25
- end
26
22
  end
27
23
  end
28
24
  end
@@ -19,10 +19,6 @@ module Pubid
19
19
  stage_code: "published",
20
20
  ),
21
21
  ].freeze
22
-
23
- def to_s
24
- render(format: :human)
25
- end
26
22
  end
27
23
  end
28
24
  end
@@ -32,10 +32,6 @@ module Pubid
32
32
  ieee_identifier.typed_stage
33
33
  end
34
34
 
35
- def to_s
36
- render(format: :human)
37
- end
38
-
39
35
  def self.parse(string)
40
36
  Base.parse(string)
41
37
  end
@@ -8,10 +8,6 @@ module Pubid
8
8
  class DualIdentifier < Base
9
9
  attribute :first_identifier, Base, polymorphic: true
10
10
  attribute :second_identifier, Base, polymorphic: true
11
-
12
- def to_s
13
- render(format: :human)
14
- end
15
11
  end
16
12
  end
17
13
  end
@@ -14,10 +14,6 @@ module Pubid
14
14
  # Second organization's identifier
15
15
  attribute :second_identifier, Base, polymorphic: true
16
16
 
17
- def to_s
18
- render(format: :human)
19
- end
20
-
21
17
  def publisher
22
18
  # Return array of both publishers
23
19
  [first_identifier&.publisher, second_identifier&.publisher].compact
@@ -12,10 +12,6 @@ module Pubid
12
12
  attribute :draft_info, :string # Draft information like "/D5"
13
13
  attribute :iec_year, :string # IEC year like "2013"
14
14
  attribute :date_info, :string # Date information like "(10/07)"
15
-
16
- def to_s
17
- render(format: :human)
18
- end
19
15
  end
20
16
  end
21
17
  end
@@ -18,10 +18,6 @@ module Pubid
18
18
  stage_code: "published",
19
19
  ),
20
20
  ].freeze
21
-
22
- def to_s
23
- render(format: :human)
24
- end
25
21
  end
26
22
  end
27
23
  end
@@ -16,10 +16,6 @@ module Pubid
16
16
  # Secondary identifier (additional number for same document)
17
17
  attr_accessor :secondary_identifier
18
18
 
19
- def to_s
20
- render(format: :human)
21
- end
22
-
23
19
  def publisher
24
20
  primary_identifier&.publisher
25
21
  end
@@ -8,10 +8,6 @@ module Pubid
8
8
  class ParentheticalIdentifier < Base
9
9
  attribute :base_identifier, Base, polymorphic: true
10
10
  attribute :parenthetical_identifier, Base, polymorphic: true
11
-
12
- def to_s
13
- render(format: :human)
14
- end
15
11
  end
16
12
  end
17
13
  end
@@ -17,10 +17,6 @@ module Pubid
17
17
  # Redline flag (always true for this class)
18
18
  attribute :redline, :boolean, default: -> { true }
19
19
 
20
- def to_s
21
- render(format: :human)
22
- end
23
-
24
20
  def publisher
25
21
  base_identifier&.publisher || "IEEE"
26
22
  end
@@ -29,10 +29,6 @@ module Pubid
29
29
 
30
30
  # Use proper Draft component (Lutaml::Model object)
31
31
  attr_accessor :draft_obj
32
-
33
- def to_s
34
- render(format: :human)
35
- end
36
32
  end
37
33
  end
38
34
  end
data/lib/pubid/ieee.rb CHANGED
@@ -25,6 +25,10 @@ module Pubid
25
25
 
26
26
  class << self
27
27
  def parse(input)
28
+ if input.length > Pubid::MAX_INPUT_LENGTH
29
+ raise ArgumentError, Pubid::INPUT_TOO_LONG_MESSAGE
30
+ end
31
+
28
32
  Identifier.parse(input)
29
33
  end
30
34
 
@@ -1,27 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Pubid
4
- module Iho
5
- # Entry point for parsing IHO identifiers.
6
- #
7
- # `extend Pubid::IdentifierFacade` provides polymorphic `from_hash` (routing
8
- # to the concrete subclass via the `_type` discriminator) and pairs with
9
- # `include Pubid::Iho::Identifier` in Identifiers::Base for identity
10
- # (`is_a?`/`===`), so a consumer handed this module can both deserialize and
11
- # identity-check IHO ids through it.
12
- module Identifier
13
- extend Pubid::IdentifierFacade
14
-
15
- # Parse an IHO identifier string into an identifier object
16
- # @param identifier [String] The IHO identifier string to parse
17
- # @return [Pubid::Iho::Identifiers::Base] The appropriate identifier object
18
- # @raise [Parslet::ParseFailed] If parsing fails
19
- def self.parse(identifier)
20
- parsed = Parser.parse(identifier)
21
- Builder.build(parsed)
22
- rescue Parslet::ParseFailed => e
23
- raise "Failed to parse IHO identifier '#{identifier}': #{e.message}"
24
- end
25
- end
26
- end
27
- end
3
+ # The IHO flavor base class is Pubid::Iho::Identifier — a real Pubid::Identifier
4
+ # subclass that every concrete IHO identifier descends from, so `is_a?` identity
5
+ # and the shared polymorphic `from_hash` work natively (no facade needed). Its
6
+ # body, `.parse`, and the Identifiers::Base back-compat alias live in
7
+ # identifiers/base.rb; this file just ensures it is loaded when a consumer
8
+ # references Pubid::Iho::Identifier directly.
9
+ require_relative "identifiers/base"