json_data_extractor 0.0.11 → 0.0.13

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: aeef2dddd8e11795c682d9db785b955164fbab87e4dc1c63843ba02a76b65905
4
- data.tar.gz: e17a062f72e0ae56bc09b42ccaa237c12149b667b63dfb0e58a60dd3ea8e5830
3
+ metadata.gz: bb96ee66beec96f117282087fadea7c8bf91febb79eddf8d588bfb26a4301466
4
+ data.tar.gz: b0a5221e3eb012da640233fac6fb5ff6a41715327de6cb381bd8896e184095bd
5
5
  SHA512:
6
- metadata.gz: b574bc9f7c79a4405d7b86739e1bf50e0ccbc82f1016befedf3e5bbb0da040db263492ee8978cd3d83957546d47338980bcfba80770a620a9c637937675bad46
7
- data.tar.gz: 2a83cf29049a8c4205851a83e12e0867f42ae684564c6bc7ae9e183b4399f9a2390f9be36724f137064bf8e76f74b30d977539fdb1c620972c05a949f19883f2
6
+ metadata.gz: 48e16964d90fc098e3d2b1c9ad5136f642546a9fa04121aea8b2ed28847224fe85ee43a576476e61fbcdf501e0ae188488c23cdd1bab6bf9d1af9781d301df60
7
+ data.tar.gz: 8b7fd89bbd4ecd36b24a542112da82baeccc789e8cf86b8ce8cbbbf3444d28c2073809ba105cb96f261d88c847ca74ba31d8cbeacfe95d74d79a22b2af913907
data/README.md CHANGED
@@ -120,6 +120,35 @@ The resulting json will be:
120
120
 
121
121
  ```
122
122
 
123
+
124
+ ### Handling Default Values
125
+
126
+ With JsonDataExtractor, you can specify default values in your schema for keys that might be absent in the input JSON. Use the `path` and `default` keys in the schema for this purpose.
127
+
128
+ ```ruby
129
+ schema = {
130
+ absent_value: { path: nil },
131
+ default: { path: '$.some_real_path', default: 'foo' },
132
+ default_with_lambda: { path: '$.table', default: -> { 'DEFAULT' } },
133
+ absent_with_default: { path: nil, default: 'bar' }
134
+ }
135
+ ```
136
+
137
+ - `absent_value`: Will be `nil` in the output as there's no corresponding key in the input JSON and no default is provided.
138
+ - `default`: Will either take the value from `$.some_real_path` in the input JSON or 'foo' if the path does not exist.
139
+ - `default_with_lambda`: Will take the value from `$..table` in the input JSON or 'DEFAULT' if the path does not exist.
140
+ - `absent_with_default`: Will be 'bar' in the output as there's no corresponding key in the input JSON but a default is provided.
141
+
142
+ #### Simplified Syntax for Absent Values
143
+
144
+ For keys that you expect to be absent in the input JSON but still want to include in the output with a `nil` value, you can use a simplified syntax by setting the schema value to `nil`.
145
+
146
+ ```ruby
147
+ schema = {
148
+ absent_value: nil
149
+ }
150
+ ```
151
+
123
152
  ### Modifiers
124
153
 
125
154
  Modifiers can be supplied on object creation and/or added later by calling `#add_modifier` method.
@@ -163,9 +192,91 @@ results = extractor.extract(schema)
163
192
  ```
164
193
 
165
194
  Modifiers are called in the order in which they are defined, so keep that in mind when defining your
166
- schema. By default JDE raises an ArgumentError if a modifier is not applicable, but this behaviour
195
+ schema. By default JDE raises an ArgumentError if a modifier is not applicable, but this behaviour
167
196
  can be configured to ignore missing modifiers. See Configuration options for details
168
197
 
198
+ ### Maps
199
+
200
+ The JsonDataExtractor gem provides a powerful feature called "maps" that allows you to transform
201
+ extracted data using predefined mappings. Maps are useful when you want to convert specific values
202
+ from the source data into different values based on predefined rules. The best use case is when you
203
+ need to traverse a complex tree to get to a value and them just convert it to your own disctionary.
204
+ E.g.:
205
+
206
+ ```ruby
207
+ data = {
208
+ cars: [
209
+ { make: 'A', fuel: 1 },
210
+ { make: 'B', fuel: 2 },
211
+ { make: 'C', fuel: 3 },
212
+ { make: 'D', fuel: nil },
213
+ ]
214
+ }
215
+
216
+ FUEL_TYPES = { 1 => 'Petrol', 2 => 'Diesel', nil => 'Unknown' }
217
+ schema = {
218
+ fuel: {
219
+ path: '$.cars[*].fuel',
220
+ map: FUEL_TYPES
221
+ }
222
+ }
223
+ result = JsonDataExtractor.new(data).extract(schema) # => {"fuel":["Petrol","Diesel",nil,"Unknown"]}
224
+ ```
225
+
226
+ A map is essentially a dictionary that defines key-value pairs, where the keys represent the source
227
+ values and the corresponding values represent the transformed values. When extracting data, you can
228
+ apply one or multiple maps to modify the extracted values.
229
+
230
+ #### Syntax
231
+
232
+ To define a map, you can use the `map` or `maps` key in the schema. The map value can be a single
233
+ hash or an array of hashes, where each hash represents a separate mapping rule. Here's an example:
234
+
235
+ ```ruby
236
+ {
237
+ path: "$.data[*].category",
238
+ map: {
239
+ "fruit" => "Fresh Fruit",
240
+ "vegetable" => "Organic Vegetable",
241
+ "meat" => "Premium Meat"
242
+ },
243
+ }
244
+ ```
245
+
246
+ Multiple maps can also be provided. In this case, each map is applied to the result of previous
247
+ transformation:
248
+
249
+ ```ruby
250
+ {
251
+ path: "$.data[*].category",
252
+ maps: [
253
+ {
254
+ "fruit" => "Fresh Fruit",
255
+ "vegetable" => "Organic Vegetable",
256
+ "meat" => "Premium Meat",
257
+ },
258
+ {
259
+ "Fresh Fruit" => "Frisches Obst",
260
+ "Organic Vegetable" => "Biologisches Gemüse",
261
+ "Premium Meat" => "Hochwertiges Fleisch",
262
+ }
263
+ ]
264
+ }
265
+ ```
266
+
267
+ _(the example is a little bit silly, but you should get the idea of chaining maps)_
268
+
269
+ You can use keys `:map` and `:maps` interchangeably much like `:modifier`, `:modifiers`.
270
+
271
+ #### Notes
272
+
273
+ - Maps can be used together with modifiers but this has less sense as you can always apply complex
274
+ mapping rules in modifiers themselves.
275
+ - If used together with modifiers, maps are applied **after** modifiers.
276
+ - If a map does not have a key corresponding to a transformed value, it will return nil, be careful
277
+ - Maps are applied in the order they are defined in the schema. Be cautious of the order if you have
278
+ overlapping or conflicting mapping rules.
279
+
169
280
  ### Nested schemas
170
281
 
171
282
  JDE supports nested schemas. Just provide your element with a type of `array` and add a `schema` key
@@ -189,26 +300,37 @@ E.g. this is a valid real-life schema with nested data:
189
300
  }
190
301
  }
191
302
  ```
303
+
192
304
  Nested schema can be also applied to objects, not arrays. See specs for more examples.
193
305
 
194
306
  ## Configuration Options
195
- The JsonDataExtractor gem provides a configuration option to control the behavior when encountering invalid modifiers.
307
+
308
+ The JsonDataExtractor gem provides a configuration option to control the behavior when encountering
309
+ invalid modifiers.
196
310
 
197
311
  ### Strict Modifiers
198
- By default, the gem operates in strict mode, which means that if an invalid modifier is encountered, an `ArgumentError` will be raised. This ensures that only valid modifiers are applied to the extracted data.
199
312
 
200
- To change this behavior and allow the use of invalid modifiers without raising an error, you can configure the gem to operate in non-strict mode.
313
+ By default, the gem operates in strict mode, which means that if an invalid modifier is encountered,
314
+ an `ArgumentError` will be raised. This ensures that only valid modifiers are applied to the
315
+ extracted data.
316
+
317
+ To change this behavior and allow the use of invalid modifiers without raising an error, you can
318
+ configure the gem to operate in non-strict mode.
201
319
 
202
320
  ```ruby
203
321
  JsonDataExtractor.configure do |config|
204
322
  config.strict_modifiers = false
205
323
  end
206
324
  ```
207
- When `strict_modifiers` is set to `false`, any invalid modifiers will be ignored, and the original value will be returned without applying any modification.
208
325
 
209
- It is important to note that enabling non-strict mode should be done with caution, as it can lead to unexpected behavior if there are typos or incorrect modifiers specified in the schema.
326
+ When `strict_modifiers` is set to `false`, any invalid modifiers will be ignored, and the original
327
+ value will be returned without applying any modification.
328
+
329
+ It is important to note that enabling non-strict mode should be done with caution, as it can lead to
330
+ unexpected behavior if there are typos or incorrect modifiers specified in the schema.
210
331
 
211
- By default, `strict_modifiers` is set to `true`, providing a safe and strict behavior. However, you can customize this configuration option according to your specific needs.
332
+ By default, `strict_modifiers` is set to `true`, providing a safe and strict behavior. However, you
333
+ can customize this configuration option according to your specific needs.
212
334
 
213
335
  ## TODO
214
336
 
@@ -20,9 +20,18 @@ class JsonDataExtractor
20
20
  def extract(schema)
21
21
  results = {}
22
22
  schema.each do |key, val|
23
+ default_value = nil
23
24
  if val.is_a?(Hash)
24
25
  val.transform_keys!(&:to_sym)
25
26
  path = val[:path]
27
+ default_value = val[:default]
28
+ maps = Array([val[:maps] || val[:map]]).flatten.compact.map do |map|
29
+ if map.is_a?(Hash)
30
+ map
31
+ else
32
+ raise ArgumentError, "Invalid map: #{map.inspect}"
33
+ end
34
+ end
26
35
  modifiers = Array(val[:modifiers] || val[:modifier]).map do |mod|
27
36
  case mod
28
37
  when Symbol, Proc
@@ -38,14 +47,17 @@ class JsonDataExtractor
38
47
  else
39
48
  path = val
40
49
  modifiers = []
50
+ maps = []
41
51
  end
42
52
 
43
- extracted_data = JsonPath.on(@data, path)
53
+ extracted_data = JsonPath.on(@data, path) if path
44
54
 
45
- if extracted_data.empty?
46
- results[key] = nil
55
+ if extracted_data.nil? || extracted_data.empty?
56
+ results[key] = default_value.is_a?(Proc) ? default_value.call : (default_value || nil)
47
57
  else
48
- results[key] = apply_modifiers(extracted_data, modifiers)
58
+ extracted_data.map! { |val| val.nil? ? default_value : val }
59
+ transformed_data = apply_modifiers(extracted_data, modifiers)
60
+ results[key] = apply_maps(transformed_data, maps)
49
61
 
50
62
  if array_type && nested
51
63
  results[key] = extract_nested_data(results[key], nested)
@@ -72,6 +84,14 @@ class JsonDataExtractor
72
84
  end
73
85
  end
74
86
 
87
+ def apply_maps(data, maps)
88
+ data.map do |value|
89
+ mapped_value = value
90
+ maps.each { |map| mapped_value = map[mapped_value] }
91
+ mapped_value
92
+ end
93
+ end
94
+
75
95
  def apply_modifiers(data, modifiers)
76
96
  data.map do |value|
77
97
  modified_value = value
@@ -96,7 +116,6 @@ class JsonDataExtractor
96
116
  end
97
117
  end
98
118
 
99
-
100
119
  class << self
101
120
  def configuration
102
121
  @configuration ||= Configuration.new
data/lib/src/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class JsonDataExtractor
2
- VERSION = '0.0.11'
2
+ VERSION = '0.0.13'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_data_extractor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Buslaev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-06 00:00:00.000000000 Z
11
+ date: 2023-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler