Class: Schemable::SchemaModifier
- Inherits:
-
Object
- Object
- Schemable::SchemaModifier
- Defined in:
- lib/schemable/schema_modifier.rb
Overview
The SchemaModifier class provides methods for modifying a given schema. It includes methods for parsing paths, checking if a path exists in a schema, deeply merging hashes, adding properties to a schema, and deleting properties from a schema.
Instance Method Summary collapse
-
#add_properties(original_schema, new_schema, path) ⇒ Hash
Adds properties to a schema at a given path.
-
#deep_merge_hashes(destination, new_data) ⇒ Hash
Deeply merges two hashes.
-
#delete_properties(original_schema, path) ⇒ Hash
Deletes properties from a schema at a given path.
-
#parse_path(path) ⇒ Array<Symbol>
Parses a given path into an array of symbols.
-
#path_exists?(schema, path) ⇒ Boolean
Checks if a given path exists in a schema.
Instance Method Details
#add_properties(original_schema, new_schema, path) ⇒ Hash
This method accepts paths in the following formats:
Adds properties to a schema at a given path.
-
‘path.to.property’
-
‘path.to.array..property’
-
‘.’
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/schemable/schema_modifier.rb', line 142 def add_properties(original_schema, new_schema, path) return deep_merge_hashes(original_schema, new_schema) if path == '.' unless path_exists?(original_schema, path) puts "Error: Path '#{path}' does not exist in the original schema" return original_schema end path_segments = parse_path(path) current_segment = original_schema last_segment = path_segments.pop # Navigate to the specified location in the schema path_segments.each do |segment| if current_segment.is_a?(Array) index = segment.to_s.match(/\[(\d+)\]|\d+/)[1] if index&.match?(/\A\d+\z/) && index.to_i < current_segment.length current_segment = current_segment[index.to_i] else puts "Error: Invalid index in path '#{path}'" return original_schema end elsif current_segment.is_a?(Hash) && current_segment.key?(segment) current_segment = current_segment[segment] else puts "Error: Expected a Hash but found #{current_segment.class} in path '#{path}'" return original_schema end end # Merge the new schema into the specified location if current_segment.is_a?(Array) index = last_segment.to_s.match(/\[(\d+)\]|\d+/)[1] if index&.match?(/\A\d+\z/) && index.to_i < current_segment.length current_segment[index.to_i] = deep_merge_hashes(current_segment[index.to_i], new_schema) else puts "Error: Invalid index in path '#{path}'" end else current_segment[last_segment] = deep_merge_hashes(current_segment[last_segment], new_schema) end original_schema end |
#deep_merge_hashes(destination, new_data) ⇒ Hash
Deeply merges two hashes.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/schemable/schema_modifier.rb', line 96 def deep_merge_hashes(destination, new_data) if destination.is_a?(Hash) && new_data.is_a?(Array) destination.merge(new_data) elsif destination.is_a?(Array) && new_data.is_a?(Hash) destination.push(new_data) elsif destination.is_a?(Hash) && new_data.is_a?(Hash) new_data.each do |key, value| if destination[key].is_a?(Hash) && value.is_a?(Hash) destination[key] = deep_merge_hashes(destination[key], value) elsif destination[key].is_a?(Array) && value.is_a?(Array) destination[key].concat(value) elsif destination[key].is_a?(Array) && value.is_a?(Hash) destination[key].push(value) else destination[key] = value end end end destination end |
#delete_properties(original_schema, path) ⇒ Hash
Deletes properties from a schema at a given path.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/schemable/schema_modifier.rb', line 203 def delete_properties(original_schema, path) return original_schema if path == '.' unless path_exists?(original_schema, path) puts "Error: Path '#{path}' does not exist in the original schema" return original_schema end path_segments = parse_path(path) current_segment = original_schema last_segment = path_segments.pop # Navigate to the parent of the last segment in the path path_segments.each do |segment| if current_segment.is_a?(Array) index = segment.to_s.match(/\[(\d+)\]|\d+/)[1] if index&.match?(/\A\d+\z/) && index.to_i < current_segment.length current_segment = current_segment[index.to_i] else puts "Error: Invalid index in path '#{path}'" return original_schema end elsif current_segment.is_a?(Hash) && current_segment.key?(segment) current_segment = current_segment[segment] else puts "Error: Expected a Hash but found #{current_segment.class} in path '#{path}'" return original_schema end end # Delete the last segment in the path if current_segment.is_a?(Array) index = last_segment.to_s.match(/\[(\d+)\]|\d+/)[1] if index&.match?(/\A\d+\z/) && index.to_i < current_segment.length current_segment.delete_at(index.to_i) else puts "Error: Invalid index in path '#{path}'" end else current_segment.delete(last_segment) end original_schema end |
#parse_path(path) ⇒ Array<Symbol>
This method accepts paths in the following formats:
Parses a given path into an array of symbols.
-
‘path.to.property’
-
‘path.to.array..property’
21 22 23 |
# File 'lib/schemable/schema_modifier.rb', line 21 def parse_path(path) path.split('.').map(&:to_sym) end |
#path_exists?(schema, path) ⇒ Boolean
Checks if a given path exists in a schema.
path = 'path.properties.to.properties.property'
incorrect_path = 'path.properties.to.properties.invalid'
path_exists?(schema, path) #=> true
path_exists?(schema, incorrect_path) #=> false
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/schemable/schema_modifier.rb', line 52 def path_exists?(schema, path) path_segments = parse_path(path) path_segments.reduce(schema) do |current_segment, next_segment| if current_segment.is_a?(Array) # The regex pattern '/\[(\d+)\]|\d+/' matches square brackets containing one or more digits, # or standalone digits. Used for parsing array indices in a path. index = next_segment.to_s.match(/\[(\d+)\]|\d+/)[1] # The regex pattern '/\A\d+\z/' matches a sequence of one or more digits from the start ('\A') # to the end ('\z') of a string. It checks if a string consists of only digits. return false if index.nil? || !index.match?(/\A\d+\z/) || index.to_i >= current_segment.length current_segment[index.to_i] else return false unless current_segment.is_a?(Hash) && current_segment.key?(next_segment) current_segment[next_segment] end end true end |