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 +4 -4
- data/bin/lint-no-raw-mdc +1 -0
- data/lib/opencdd/condition.rb +65 -0
- data/lib/opencdd/entity/name_synthesizer.rb +5 -49
- data/lib/opencdd/property.rb +0 -7
- data/lib/opencdd/property_ids.rb +52 -0
- data/lib/opencdd/validator/condition_rule.rb +3 -0
- data/lib/opencdd/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c582aa6a0bf79bedf583a586f97c1c308852b53d4efc9972b3bb883a2be425fc
|
|
4
|
+
data.tar.gz: 1195b6615ee045c3c1ac63f237ccdb930d80838db9dbe33677216e271748accc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1cbdf2e8832ccd86b95fcfc6789d8d9dfe4be656a27f7b4cac4cb854ea6f224153f5aa8cca521362f364954e123e0c50d3424da3daf031cd73f1974823794cb9
|
|
7
|
+
data.tar.gz: 072c326fba5a5807249b7ea79eda95c31fc42384c80de750dba20c741de0601c8c67afe61e9b58a27e594797c68b12cbb38b4166c0f56ce547130e610625c80c
|
data/bin/lint-no-raw-mdc
CHANGED
data/lib/opencdd/condition.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
data/lib/opencdd/property.rb
CHANGED
|
@@ -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] ||
|
data/lib/opencdd/property_ids.rb
CHANGED
|
@@ -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
|
data/lib/opencdd/version.rb
CHANGED
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.
|
|
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-
|
|
11
|
+
date: 2026-07-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: roo
|