circuitdata 0.6.4 → 0.7.0

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 (32) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +25 -122
  3. data/Rakefile +4 -6
  4. data/lib/circuitdata.rb +32 -120
  5. data/lib/circuitdata/bury/bury.rb +61 -0
  6. data/lib/circuitdata/dereferencer.rb +49 -17
  7. data/lib/circuitdata/exposed_area.rb +84 -0
  8. data/lib/circuitdata/json_schema.rb +14 -0
  9. data/lib/circuitdata/json_validator.rb +56 -0
  10. data/lib/circuitdata/json_validator/json_schema_error_parser.rb +57 -0
  11. data/lib/circuitdata/material_validator.rb +40 -0
  12. data/lib/circuitdata/product.rb +125 -0
  13. data/lib/circuitdata/product_id_validator.rb +81 -0
  14. data/lib/circuitdata/profile.rb +31 -69
  15. data/lib/circuitdata/schema.rb +145 -0
  16. data/lib/circuitdata/schema_files/schema_v1_dereferenced.json +107155 -0
  17. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema.json +68 -5307
  18. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_generics.json +23 -0
  19. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_materials.json +99 -0
  20. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_products.json +779 -0
  21. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_profiles_and_capabilities.json +323 -0
  22. data/lib/circuitdata/summary.rb +96 -0
  23. data/lib/circuitdata/validator.rb +28 -0
  24. data/lib/circuitdata/version.rb +2 -1
  25. metadata +113 -20
  26. data/lib/circuitdata/bk_comparer.rb +0 -106
  27. data/lib/circuitdata/compatibility_checker.rb +0 -160
  28. data/lib/circuitdata/file_comparer.rb +0 -276
  29. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_schema_definitions.json +0 -1249
  30. data/lib/circuitdata/schema_files/v1/ottp_circuitdata_skeleton_schema.json +0 -94
  31. data/lib/circuitdata/schema_files/v1/ottp_schema_definitions.json +0 -102
  32. data/lib/circuitdata/tools.rb +0 -207
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e0f932ee59269f6cc563b1ddd5a85aeaf69d716c
4
- data.tar.gz: c93d8bcf99e9a2723e680b902865668089c1420a
2
+ SHA256:
3
+ metadata.gz: cee57a28b38b2f4e09b6e27af0140b0d6bfe02287ec8e6452519c7f4106e9d84
4
+ data.tar.gz: 02ed3d0c396aab1df49448c3ee9f78977ff16c7483384240b94729178068710b
5
5
  SHA512:
6
- metadata.gz: 55325d670241f121a5ac81eff19d641662a3d27429a75615f0f06c6d3bb756f5f6f8cffd3fb1da367daa0069a56d48982eac088f79b862db93bec13f2f8a1cf7
7
- data.tar.gz: 79a08cc7a9cfacebbd7af0ff349bfda4c0744a65c13845a23690fa34b16dd08cf1dbcf0854d3a263d781222b797988831fdc5ab54a2ceb122ba8fcd7010ef6a6
6
+ metadata.gz: acd38a087dcfe90a368ab15d491f272cc00af1b9addc9749723e80cd626e766b5ed01aa92e87df54b38565b25c0ebf73666fd4085f3c8af1f93b7d7a23ddc57a
7
+ data.tar.gz: 87eb841eb3ab9d350f8e1bc7f7278b450771f278cc9c0713527c16bab3e9097c2c916cfe1e60106e12717b9d26fc00bb9c5f929f9a9a0a4fb09c281c09f84468
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # Circuitdata
2
+
2
3
  This gem provides helper functions that allows you to do schema checks and control files up against each other according to the [CircuitData Language](https://circuitdata.org)
3
4
 
4
5
  ## Installation
6
+
5
7
  Add this line to your application's Gemfile:
6
8
 
7
9
  ```ruby
@@ -9,153 +11,38 @@ gem 'circuitdata'
9
11
  ```
10
12
 
11
13
  And then execute:
14
+
12
15
  ```bash
13
16
  $ bundle
14
17
  ```
15
18
 
16
19
  Or install it yourself as:
20
+
17
21
  ```bash
18
22
  $ gem install circuitdata
19
23
  ```
20
24
 
21
25
  ## Usage
26
+
22
27
  If not in rails
28
+
23
29
  ```
24
30
  require 'circuitdata'
25
31
  ```
26
32
 
27
33
  ### Commands
28
34
 
29
- #### `Circuitdata.compatibility_checker`
30
-
31
- Test one file against the schema
32
- ```ruby
33
- Circuitdata.compatibility_checker('testfile-product.json')
34
- ```
35
- When valid gives:
36
- ```ruby
37
- {
38
- :error => false,
39
- :errormessage => "",
40
- :validationserrors => {},
41
- :restrictederrors => {},
42
- :enforcederrors => {},
43
- :capabilitieserrors => {}
44
- }
45
- ```
46
-
47
- Test two files up against each other (one must be a product file).
48
- ```ruby
49
- Circuitdata.compatibility_checker('testfile-product.json','testfile-profile-restricted.json')
50
- ```
51
-
52
- When invalid results in:
53
- ```ruby
54
- {
55
- :error => true,
56
- :errormessage => "The product to check did not meet the requirements",
57
- :validationserrors => {},
58
- :restrictederrors => {
59
- "#/open_trade_transfer_package/products/testproduct/printed_circuits_fabrication_data/board/thickness" => [
60
- "of type number matched the disallowed schema"
61
- ]
62
- },
63
- :enforcederrors => {},
64
- :capabilitieserrors => {}
65
- }
66
- ```
67
-
68
- Turn off validation against the schema
69
- ```ruby
70
- Circuitdata.compatibility_checker( 'testfile-product.json', 'testfile-profile-restricted.json', false )
71
- ```
72
- Gives:
73
- ```ruby
74
- {
75
- :error => true,
76
- :errormessage => "The product to check did not meet the requirements",
77
- :validationserrors => {},
78
- :restrictederrors => {
79
- "#/open_trade_transfer_package/products/testproduct/printed_circuits_fabrication_data/board/thickness" => ["of type number matched the disallowed schema"]
80
- },
81
- :enforcederrors => {},
82
- :capabilitieserrors => {}
83
- }
84
-
85
- ```
86
-
87
- #### `Circuitdata.compare_files`
88
-
89
- Run a test with several files against each other and get a complete list of values and conflicts, and a summary
90
- ```ruby
91
- product1 = File.join(__dir__, 'test/test_data/test_product1.json')
92
- profile_restricted = File.join(__dir__, 'test/test_data/testfile-profile-restricted.json')
93
- profile_default = File.join(__dir__, 'test/test_data/testfile-profile-default.json')
94
- file_hash = {product1: product1, restricted: profile_restricted, default: profile_default}
95
-
96
- Circuitdata.compare_files(file_hash, true)
97
- ```
98
-
99
- Results in:
100
- ```ruby
101
- {
102
- :error=>false,
103
- :message=>nil,
104
- :conflict=>false,
105
- :product_name=>"testproduct",
106
- :columns=>[
107
- :summary,
108
- :product1,
109
- :restricted,
110
- :default
111
- ],
112
- :master_column=>nil,
113
- :rows=>{
114
- :rigid_conductive_layer=>{
115
- :count=>{
116
- :product1=>{
117
- :value=>11,
118
- :conflict=>false,
119
- :conflicts_with=>[],
120
- :conflict_message=>[]
121
- },
122
- :restricted=>{
123
- :value=>nil,
124
- :conflict=>false,
125
- :conflicts_with=>[],
126
- :conflict_message=>[]
127
- },
128
- :default=>{
129
- :value=>nil,
130
- :conflict=>false,
131
- :conflicts_with=>[],
132
- :conflict_message=>[]
133
- },
134
- :summary=>{
135
- :value=>11,
136
- :conflict=>false,
137
- :conflicts_with=>[:product1],
138
- :conflict_message=>[]
139
- }
140
- }
141
- # ...
142
- }
143
- }
144
- }
145
- ```
146
-
147
35
  #### `Circuitdata.dereferenced_schema`
148
36
 
149
37
  This returns the JSON schema used internally to validate the Circuit Data information. It
150
38
  returns the schema without any usage of `$ref` so that it can be utilized without any knowledge of the internal paths.
151
39
 
152
- #### `Circuitdata::Profile.schema`
153
-
154
- Returns a subset of the Circuit Data schema that relates to profiles. This is a schema without any `$ref`s.
155
40
  #### `Circuitdata::Profile.questions`
41
+
156
42
  Returns a list of grouped questions that can be used for populating an input interface related to profiles.
157
43
 
158
44
  Example output:
45
+
159
46
  ```ruby
160
47
  [
161
48
  {
@@ -172,7 +59,7 @@ Example output:
172
59
  uom: ["um"],
173
60
  description: "The roughness of the copper foil."
174
61
  },
175
- path: "/open_trade_transfer_package/profiles/defaults/printed_circuits_fabrication_data/rigid_conductive_layer/copper_foil_roughness"
62
+ path: "/open_trade_transfer_package/profiles/default/printed_circuits_fabrication_data/rigid_conductive_layer/copper_foil_roughness"
176
63
  }
177
64
  },
178
65
  ]
@@ -180,5 +67,21 @@ Example output:
180
67
  # ...
181
68
  ]
182
69
  ```
70
+
71
+ ### Validation
72
+
73
+ To validate a CircuitData JSON file the `Validator` can be used. This will check that a file matches the schema defined in the CircuitData language as well as logical issues. An example of a logical issue is missing layers in the layers list for a product.
74
+
75
+ The following is an example of using the `Validator`:
76
+
77
+ ```
78
+ validator = Circuitdata::Validator.new(json_file_contents)
79
+ if !validator.valid?
80
+ puts validator.errors.inspect
81
+ end
82
+ # ...
83
+ ```
84
+
183
85
  ## License
86
+
184
87
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,8 +1,6 @@
1
- require 'rake/testtask'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
2
3
 
3
- Rake::TestTask.new do |t|
4
- t.libs << 'test'
5
- end
4
+ RSpec::Core::RakeTask.new(:spec)
6
5
 
7
- desc "Run tests"
8
- task :default => :test
6
+ task :default => :spec
@@ -1,132 +1,44 @@
1
1
  module Circuitdata
2
2
  # SHOULD ONLY HOUSE COMMON FUNCTIONS ONLY
3
- require 'active_support/all'
4
- require 'json-schema'
5
- require_relative './circuitdata/file_comparer'
6
- require_relative './circuitdata/compatibility_checker'
7
- require_relative './circuitdata/dereferencer'
8
- require_relative './circuitdata/profile'
9
- require_relative './circuitdata/tools'
10
3
 
11
- SCHEMA_PATH = 'circuitdata/schema_files/v1/ottp_circuitdata_schema.json'
12
- SCHEMA_FULL_PATH = File.join(__dir__, SCHEMA_PATH)
13
-
14
- def self.get_data_summary(data)
15
- types = []
16
- wrapper = data&.dig(:open_trade_transfer_package)
17
- types << 'profile_restricted' unless wrapper&.dig(:profiles, :restricted).nil?
18
- types << 'profile_enforced' unless wrapper&.dig(:profiles, :enforced).nil?
19
- types << 'profile_defaults' unless wrapper&.dig(:profiles, :defaults).nil?
20
- types << 'capabilities' unless wrapper&.dig(:capabilities).nil?
21
-
22
- products = wrapper&.dig(:products)
23
- product_names = products.nil? ? [] : products.keys # this will return all the product names
24
- types << 'product' if product_names.any?
25
- # loop through the products
26
- products.each do |k, v|
27
- if v&.dig(:stackup, :specification_level) == 'specified' && !v&.dig(:stackup, :specification_level, :specified).nil?
28
- types << 'stackup'
29
- end
30
- end unless products.nil?
31
-
32
- return product_names, types
33
- end
34
-
35
- def self.read_json(file)
36
- error, message, data = false, nil, nil
37
-
38
- if file.is_a? Hash
39
- begin
40
- data = file
41
- data.deep_symbolize_keys!
42
- rescue
43
- error = true
44
- message = "Could not convert the Hash into JSON"
45
- end
46
- else
47
- begin
48
- open(file) do |f|
49
- data = JSON.parse(f.read, symbolize_names: true)
50
- end
51
- rescue
52
- error = true
53
- message = "Could not read the file"
54
- end
55
- end
56
- return error, message, data
4
+ require "active_support/all"
5
+ require_relative "./circuitdata/version"
6
+ require_relative "./circuitdata/json_schema"
7
+ require_relative "./circuitdata/dereferencer"
8
+ require_relative "./circuitdata/profile"
9
+ require_relative "./circuitdata/schema"
10
+ require_relative "./circuitdata/product"
11
+ require_relative "./circuitdata/validator"
12
+ require_relative "./circuitdata/json_validator"
13
+ require_relative "./circuitdata/material_validator"
14
+ require_relative "./circuitdata/product_id_validator"
15
+ require_relative "./circuitdata/bury/bury"
16
+ require_relative "./circuitdata/product_id_validator"
17
+ require_relative "./circuitdata/exposed_area"
18
+ require_relative "./circuitdata/summary"
19
+
20
+ SCHEMA_BASE_PATH = File.join(__dir__, "circuitdata/schema_files/v1")
21
+ SCHEMA_FULL_PATH = File.join(SCHEMA_BASE_PATH, "..", "schema_v1_dereferenced.json")
22
+ DEFINITIONS_FULL_PATH = File.join(
23
+ SCHEMA_BASE_PATH, "ottp_circuitdata_schema_definitions.json"
24
+ )
25
+ def self.dereferenced_schema(schema_file_path: SCHEMA_FULL_PATH)
26
+ schema_cache[schema_file_path] ||= Dereferencer.dereference(
27
+ schema(schema_file_path: schema_file_path),
28
+ File.dirname(schema_file_path)
29
+ )
57
30
  end
58
31
 
59
- def self.validate(content)
60
- error, message, validations_errors = false, nil, {}
32
+ private
61
33
 
62
- begin
63
- validated = JSON::Validator.fully_validate(SCHEMA_FULL_PATH, content, :errors_as_objects => true)
64
- rescue JSON::Schema::ReadFailed
65
- error = true
66
- message = "Could not read the validating schema"
67
- rescue JSON::Schema::SchemaError
68
- error = true
69
- message = "There is something was wrong with the validating schema"
70
- end
71
- unless error
72
- if validated.count > 0
73
- error = true
74
- message = "Could not validate the file against the CircuitData json schema"
75
- validated.each do |val_error|
76
- validations_errors[val_error[:fragment]] = [] unless validations_errors.has_key? val_error[:fragment]
77
- begin
78
- keep = val_error[:message].match("^(The\\sproperty\\s\\'[\\s\\S]*\\'\\s)([\\s\\S]*)(\\sin\\sschema\\sfile[\\s\\S]*)$").captures[1]
79
- rescue
80
- keep = val_error[:message]
81
- end
82
- validations_errors[val_error[:fragment]] << keep
83
- end
84
- end
85
- end
86
- return error, message, validations_errors
87
- end
88
-
89
- def self.schema
34
+ def self.schema(schema_file_path: SCHEMA_FULL_PATH)
90
35
  JSON.parse(
91
- File.read(SCHEMA_FULL_PATH),
92
- symbolize_names: true
36
+ File.read(schema_file_path),
37
+ symbolize_names: true,
93
38
  )
94
39
  end
95
40
 
96
- def self.dereferenced_schema
97
- Dereferencer.dereference(
98
- schema,
99
- File.dirname(Circuitdata::SCHEMA_FULL_PATH)
100
- )
101
- end
102
-
103
- def self.compare_files(file_hash, validate_origins=false)
104
- comparer = FileComparer.new(file_hash, validate_origins)
105
- comparer.compare
106
- end
107
-
108
- def self.compatibility_checker(product_file, check_file=nil, validate_origins=false)
109
- checker = CompatibilityChecker.new(product_file, check_file, validate_origins)
110
- checker.start_check
111
- end
112
-
113
- def self.create_documentation()
114
- docu = Tools.new()
115
- ra = docu.create_structure
116
- docu.create_documentation(ra)
117
- end
118
-
119
- def self.test
120
- product1 = File.join(File.dirname(__FILE__), '../test/test_data/test_product1.json')
121
- product2 = File.join(File.dirname(__FILE__), '../test/test_data/test_product2.json')
122
- profile_restricted = File.join(File.dirname(__FILE__), '../test/test_data/testfile-profile-restricted.json')
123
- profile_enforced = File.join(File.dirname(__FILE__), '../test/test_data/testfile-profile-enforced.json')
124
- profile_default = File.join(File.dirname(__FILE__), '../test/test_data/testfile-profile-default.json')
125
- capabilities = File.join(File.dirname(__FILE__), '../test/test_data/testfile-capability.json')
126
-
127
- # THEN TEST THE COMPARE FILES:
128
- puts "Testing file comparison"
129
- file_hash = {product1: product1, product2: product2, restricted: profile_restricted, enforced: profile_enforced, default: profile_default, capability: capabilities}
130
- Circuitdata.compare_files(file_hash, true)
41
+ def self.schema_cache
42
+ @schema_cache ||= {}
131
43
  end
132
44
  end
@@ -0,0 +1,61 @@
1
+ module Circuitdata
2
+ module Bury
3
+ class InvalidDataError < StandardError; end
4
+
5
+ class << self
6
+ def bury(data, *path, value)
7
+ current_data = data
8
+ path[0..-2].each_with_index do |part, i|
9
+ current_data = next_level(part, path[i + 1], current_data)
10
+ end
11
+ if !value.nil?
12
+ current_data[path.last] = value
13
+ else
14
+ current_data.delete(path.last)
15
+ end
16
+ data
17
+ end
18
+
19
+ def dig(data, *path)
20
+ current_data = data
21
+ path.each do |part|
22
+ current_data = next_level(part, nil, current_data, initialize_missing: false)
23
+ return nil if current_data.nil?
24
+ end
25
+ current_data
26
+ end
27
+
28
+ private
29
+
30
+ def find_matching_hash(data, partial_hash)
31
+ unless data.is_a?(Array)
32
+ fail InvalidDataError, "parent of #{partial_hash} is not an array"
33
+ end
34
+ data.find do |el|
35
+ partial_hash.all? { |k, v| el[k] == v }
36
+ end
37
+ end
38
+
39
+ def next_level(part, next_part, current_data, initialize_missing: true)
40
+ if part.is_a?(Hash)
41
+ existing_hash = find_matching_hash(current_data, part)
42
+ if !existing_hash
43
+ return nil unless initialize_missing
44
+ new_data = part.dup
45
+ current_data.push(new_data)
46
+ new_data
47
+ else
48
+ existing_hash
49
+ end
50
+ elsif current_data[part].nil?
51
+ return nil unless initialize_missing
52
+ next_is_array = next_part.is_a?(Integer) || next_part.is_a?(Hash)
53
+ current_data[part] = next_is_array ? [] : {}
54
+ current_data[part]
55
+ else
56
+ current_data[part]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end