circuitdata 0.6.4 → 0.7.0

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