opencdd 0.3.0 → 0.3.1

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: b88da823f5a7adb8f4d88f16a2f1e97d4f3136579bea025ef28c178753ab7f0e
4
- data.tar.gz: 6171d27282b147b1c80fb137d8523d9644bb58fcaf364d13e89fee8713b7b814
3
+ metadata.gz: c582aa6a0bf79bedf583a586f97c1c308852b53d4efc9972b3bb883a2be425fc
4
+ data.tar.gz: 1195b6615ee045c3c1ac63f237ccdb930d80838db9dbe33677216e271748accc
5
5
  SHA512:
6
- metadata.gz: b373faf0cd5ac6d5e2d6f62af3e0a3a57abe2300589fd9d4c19135ccaf7ac28b385bf9946a4d090d178b293b15dfcce4a77c60a1b452d2e31cbf0ceab2f3ab89
7
- data.tar.gz: b7ceac12c85b84943405c25fd04b112e5e282332b30c24ccc3367779a2a4bb3688c945efb81ee3e9641108e6b99e57d3c889f32e5dbad1249e50c9e2728cd344
6
+ metadata.gz: 1cbdf2e8832ccd86b95fcfc6789d8d9dfe4be656a27f7b4cac4cb854ea6f224153f5aa8cca521362f364954e123e0c50d3424da3daf031cd73f1974823794cb9
7
+ data.tar.gz: 072c326fba5a5807249b7ea79eda95c31fc42384c80de750dba20c741de0601c8c67afe61e9b58a27e594797c68b12cbb38b4166c0f56ce547130e610625c80c
data/bin/lint-no-raw-mdc CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env bash
1
2
  # lint-no-raw-mdc — fail if any raw MDC_P### / MDC_C### / EXT_P### /
2
3
  # EXT_C### / CIM_P### string literal appears in lib/opencdd/ outside
3
4
  # the designated SSOT files.
@@ -13,6 +13,12 @@ module Opencdd
13
13
  (?<right>.+)
14
14
  \z/x.freeze
15
15
 
16
+ # A single bare token (IRDI or short code) without internal whitespace.
17
+ # Used to detect class-reference conditions of the form
18
+ # `0112/2///62683#ACE132` and distinguish them from malformed input
19
+ # like "no operator here" (which has internal whitespace).
20
+ SINGLE_TOKEN_PATTERN = /\A\S+\z/.freeze
21
+
16
22
  attr_reader :left, :operator, :right
17
23
 
18
24
  def initialize(left, operator, right)
@@ -24,6 +30,10 @@ module Opencdd
24
30
  @right = right
25
31
  end
26
32
 
33
+ def class_reference?
34
+ false
35
+ end
36
+
27
37
  def set?
28
38
  @right.is_a?(Set)
29
39
  end
@@ -76,6 +86,12 @@ module Opencdd
76
86
  op = Regexp.last_match(:op)
77
87
  raw_right = Regexp.last_match(:right).strip
78
88
  new(left, op, parse_rhs(raw_right))
89
+ elsif s =~ SET_PATTERN
90
+ body = Regexp.last_match(:body)
91
+ elements = body.split(/[,\s]+/).map(&:strip).reject(&:empty?)
92
+ ClassReference.new(irdis: elements)
93
+ elsif SINGLE_TOKEN_PATTERN.match?(s)
94
+ ClassReference.new(irdis: [s])
79
95
  else
80
96
  raise ArgumentError, "invalid condition expression: #{s.inspect}"
81
97
  end
@@ -116,5 +132,54 @@ module Opencdd
116
132
  def normalize_for_eq(value)
117
133
  value.is_a?(Set) ? value.to_a.sort : value
118
134
  end
135
+
136
+ # A condition of the form `{0112/2///62683#ACE132}` or a bare
137
+ # `0112/2///62683#ACE132` — meaning "this property applies when the
138
+ # host class is one of the listed IRDIs". IEC 62683 stores property
139
+ # conditions this way; the regular boolean-expression grammar in
140
+ # +Condition+ cannot represent it.
141
+ class ClassReference < Condition
142
+ attr_reader :irdis
143
+
144
+ # The binding key (string or symbol) consulted by +#satisfied_by?+
145
+ # to discover the host class IRDI. Callers that resolve the host
146
+ # class via a different key should override +satisfied_by?+.
147
+ HOST_CLASS_KEYS = [:class, :host_class, "class", "host_class"].freeze
148
+
149
+ def initialize(irdis:)
150
+ @irdis = Array(irdis).map(&:to_s)
151
+ @left = nil
152
+ @operator = nil
153
+ @right = nil
154
+ end
155
+
156
+ def class_reference?
157
+ true
158
+ end
159
+
160
+ def set?
161
+ @irdis.size > 1
162
+ end
163
+
164
+ def satisfied_by?(bindings)
165
+ hash = bindings.is_a?(Hash) ? bindings : bindings.to_h
166
+ actual = HOST_CLASS_KEYS.map { |k| hash[k] }.compact.first
167
+ return true if actual.nil?
168
+ @irdis.any? { |irdi| actual.to_s == irdi }
169
+ end
170
+
171
+ def to_s
172
+ @irdis.size == 1 ? @irdis.first : "{#{@irdis.join(', ')}}"
173
+ end
174
+
175
+ def ==(other)
176
+ other.is_a?(ClassReference) && Set.new(@irdis) == Set.new(other.irdis)
177
+ end
178
+ alias_method :eql?, :==
179
+
180
+ def hash
181
+ Set.new(@irdis).hash
182
+ end
183
+ end
119
184
  end
120
185
  end
@@ -12,56 +12,12 @@ module Opencdd
12
12
  # Extracted from SheetSchema so SheetSchema focuses on header
13
13
  # parsing + Column construction. Name synthesis is a separate
14
14
  # concern with its own test surface.
15
+ #
16
+ # The name→ID table itself lives in Opencdd::PropertyIds::IEC_COLUMN_NAMES
17
+ # (the lint-exempt SSOT). NAME_TO_PROPERTY_ID is kept here as a
18
+ # back-compat alias so existing callers see no public-API change.
15
19
  module NameSynthesizer
16
- # IEC 62656-1 defined column names mapped to canonical
17
- # property IDs. These names appear in the #PROPERTY_NAME
18
- # directive row when #PROPERTY_ID is absent.
19
- NAME_TO_PROPERTY_ID = {
20
- "Code" => "MDC_P001_5",
21
- "Version" => "MDC_P002_1",
22
- "Revision" => "MDC_P002_2",
23
- "VersionInitiationDate" => "MDC_P003_1",
24
- "VersionReleaseDate" => "MDC_P003_2",
25
- "RevisionReleaseDate" => "MDC_P003_3",
26
- "PreferredName" => "MDC_P004",
27
- "SynonymousName" => "MDC_P007",
28
- "ShortName" => "MDC_P005",
29
- "Definition" => "MDC_P006",
30
- "DefinitionSource" => "MDC_P006_1",
31
- "Note" => "MDC_P008",
32
- "Remark" => "MDC_P009",
33
- "Drawing" => "MDC_P008_1",
34
- "GUID" => "MDC_P066",
35
- "TimeStamp" => "MDC_P067",
36
- "ClassType" => "MDC_P011",
37
- "Superclass" => "MDC_P010",
38
- "IsCaseOf" => "MDC_P013",
39
- "ApplicableProperties" => "MDC_P014",
40
- "ImportedProperties" => "MDC_P090",
41
- "SubClassSelection" => "MDC_P016",
42
- "DataType" => "MDC_P022",
43
- "ValueFormat" => "MDC_P024",
44
- "DefinitionClass" => "MDC_P021",
45
- "Unit" => "MDC_P041",
46
- "Condition" => "MDC_P028",
47
- "ListType" => "MDC_P046",
48
- "CodeList" => "MDC_P044",
49
- "TermList" => "MDC_P043",
50
- "EnumerationCode" => "MDC_P044",
51
- "RelationType" => "MDC_P200",
52
- "RelationDomain" => "MDC_P201",
53
- "FunctionDomain" => "MDC_P202",
54
- "FunctionCodomain" => "MDC_P203",
55
- "Formula" => "MDC_P204",
56
- "FormulaLanguage" => "MDC_P205",
57
- "FormulaExternalSolver" => "MDC_P206",
58
- "TriggerEvent" => "MDC_P207",
59
- "DomainElementType" => "MDC_P208",
60
- "CodomainElementType" => "MDC_P209",
61
- "Role" => "MDC_P210",
62
- "Segment" => "MDC_P211",
63
- "SuperRelation" => "MDC_P212",
64
- }.freeze
20
+ NAME_TO_PROPERTY_ID = Opencdd::PropertyIds::IEC_COLUMN_NAMES
65
21
 
66
22
  # Given a PROPERTY_NAME directive row (Array of name strings),
67
23
  # returns a parallel Array of property IDs (or nil where the
@@ -69,13 +69,6 @@ module Opencdd
69
69
  end
70
70
  field :condition, synthetic: true do
71
71
  @condition ||= Opencdd::Condition.parse(properties[Opencdd::PropertyIds::MDC_P028])
72
- rescue ArgumentError
73
- # IEC CDD occasionally stores a bare class-reference set in the
74
- # condition column (e.g. "{0112/2///62683#ACE132}") instead of
75
- # a `left OP right` boolean expression. Condition's grammar
76
- # rejects that shape; treat it as nil rather than crashing the
77
- # import. Tracked in TODO.full-cdd/17-condition-grammar-fix.md.
78
- @condition = nil
79
72
  end
80
73
  field :formula, synthetic: true do
81
74
  properties[Opencdd::PropertyIds::MDC_P027_1] ||
@@ -142,6 +142,58 @@ module Opencdd
142
142
  # ontology registry). Kept here as an alias for back-compat.
143
143
  PARCEL_VARIANT_TO_CANONICAL = Opencdd::Parcel::SheetSchema::VARIANT_TO_CANONICAL
144
144
 
145
+ # IEC 62656-1 defined PROPERTY_NAME directive column names mapped
146
+ # to canonical property IDs. Used by Opencdd::Entity::NameSynthesizer
147
+ # when a Parcel sheet omits the #PROPERTY_ID directive row and
148
+ # only carries #PROPERTY_NAME. Declared here so the raw IDs live
149
+ # in the lint-exempt SSOT instead of in the synthesis module.
150
+ IEC_COLUMN_NAMES = {
151
+ "Code" => "MDC_P001_5",
152
+ "Version" => "MDC_P002_1",
153
+ "Revision" => "MDC_P002_2",
154
+ "VersionInitiationDate" => "MDC_P003_1",
155
+ "VersionReleaseDate" => "MDC_P003_2",
156
+ "RevisionReleaseDate" => "MDC_P003_3",
157
+ "PreferredName" => "MDC_P004",
158
+ "SynonymousName" => "MDC_P007",
159
+ "ShortName" => "MDC_P005",
160
+ "Definition" => "MDC_P006",
161
+ "DefinitionSource" => "MDC_P006_1",
162
+ "Note" => "MDC_P008",
163
+ "Remark" => "MDC_P009",
164
+ "Drawing" => "MDC_P008_1",
165
+ "GUID" => "MDC_P066",
166
+ "TimeStamp" => "MDC_P067",
167
+ "ClassType" => "MDC_P011",
168
+ "Superclass" => "MDC_P010",
169
+ "IsCaseOf" => "MDC_P013",
170
+ "ApplicableProperties" => "MDC_P014",
171
+ "ImportedProperties" => "MDC_P090",
172
+ "SubClassSelection" => "MDC_P016",
173
+ "DataType" => "MDC_P022",
174
+ "ValueFormat" => "MDC_P024",
175
+ "DefinitionClass" => "MDC_P021",
176
+ "Unit" => "MDC_P041",
177
+ "Condition" => "MDC_P028",
178
+ "ListType" => "MDC_P046",
179
+ "CodeList" => "MDC_P044",
180
+ "TermList" => "MDC_P043",
181
+ "EnumerationCode" => "MDC_P044",
182
+ "RelationType" => "MDC_P200",
183
+ "RelationDomain" => "MDC_P201",
184
+ "FunctionDomain" => "MDC_P202",
185
+ "FunctionCodomain" => "MDC_P203",
186
+ "Formula" => "MDC_P204",
187
+ "FormulaLanguage" => "MDC_P205",
188
+ "FormulaExternalSolver" => "MDC_P206",
189
+ "TriggerEvent" => "MDC_P207",
190
+ "DomainElementType" => "MDC_P208",
191
+ "CodomainElementType" => "MDC_P209",
192
+ "Role" => "MDC_P210",
193
+ "Segment" => "MDC_P211",
194
+ "SuperRelation" => "MDC_P212",
195
+ }.freeze
196
+
145
197
  REGISTRY.each_key do |id|
146
198
  const_set(id, id.freeze) unless const_defined?(id, false)
147
199
  end
@@ -14,6 +14,9 @@ module Opencdd
14
14
 
15
15
  def call(value, _context)
16
16
  return true if value.nil? || value.to_s.strip.empty?
17
+ # parse returns a boolean Condition or a Condition::ClassReference
18
+ # for bare-IRDI / bare-set conditions (IEC 62683 shape). Both are
19
+ # valid; only malformed input raises ArgumentError.
17
20
  !Opencdd::Condition.parse(value.to_s).nil?
18
21
  rescue ArgumentError
19
22
  false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Opencdd
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opencdd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenCDD contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-23 00:00:00.000000000 Z
11
+ date: 2026-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: roo