decontaminate 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -1
- data/lib/decontaminate/decoder/array.rb +2 -2
- data/lib/decontaminate/decoder/child_node_proxy.rb +2 -2
- data/lib/decontaminate/decoder/hash.rb +2 -2
- data/lib/decontaminate/decoder/scalar.rb +2 -2
- data/lib/decontaminate/decoder/tuple.rb +3 -3
- data/lib/decontaminate/decontaminator.rb +36 -5
- data/lib/decontaminate/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f731111d47eb751ba591ab27befd41721b22ab09
|
4
|
+
data.tar.gz: 4355d58ea218c7ea312e50ccd37bc4dd314345a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95e52b38d6260c8789ebedab7a56efa09e51464eefce1e02ac56adc3d82c8eea6062da2fabcb17e1cee2a675bc4359e94dd515dc676e38fa21857ee0396c2598
|
7
|
+
data.tar.gz: 1c6d7a83b722b26fc570dd4198e0b6ef3c6bd88c77bf6a3e0c759163da1bfecb44bbec44d000517765627652096465817c8e3250e7f743ad610d2ac6b99c1984
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Decontaminate
|
1
|
+
# Decontaminate [![Gem Version](https://badge.fury.io/rb/decontaminate.svg)](https://badge.fury.io/rb/decontaminate) [![Build Status](https://travis-ci.org/lexi-lambda/decontaminate.svg?branch=0.2.0)](https://travis-ci.org/lexi-lambda/decontaminate)
|
2
2
|
|
3
3
|
Decontaminate is a tool for extracting information from large, potentially nested XML documents. It provides a simple Ruby DSL for selecting values from Nokogiri objects and storing the results in JSON-like Ruby hashes and arrays.
|
4
4
|
|
@@ -78,6 +78,19 @@ scalar 'RatingPercentage', key: 'rating_ratio', type: :float do |percentage|
|
|
78
78
|
end
|
79
79
|
```
|
80
80
|
|
81
|
+
Transformer blocks are evaluated in the context of the decontaminator instance, so instance methods can be called. Additionally, it is possible to call instance methods as transformers directly without needing to pass a block by passing the name of the method as the `transformer:` keyword argument.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
scalar 'RatingPercentage',
|
85
|
+
key: 'rating_ratio',
|
86
|
+
type: :float,
|
87
|
+
transformer: :percentage_to_ratio
|
88
|
+
|
89
|
+
def percentage_to_ratio(percentage)
|
90
|
+
percentage && percentage / 100.0
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
81
94
|
### Nested Values
|
82
95
|
|
83
96
|
It's also possible to specify nested or even deeply nested hashes with the `hash` class method:
|
@@ -195,6 +208,8 @@ tuple ['Height/text()', 'Height/@units'], key: 'height_cm' do |height, units|
|
|
195
208
|
end
|
196
209
|
```
|
197
210
|
|
211
|
+
Tuples also support the shorthand `transformer:` argument that `scalar` and `scalars` support.
|
212
|
+
|
198
213
|
### Flattening nested data
|
199
214
|
|
200
215
|
Since source data is sometimes more nested than is desired, the `with` method is a helper for scoping decontamination directives to a given XML element without increasing the nesting depth of the resulting object. Like `hash`, it accepts an XPath and a block, but the attributes created from within the block will not be wrapped in a hash.
|
@@ -8,11 +8,11 @@ module Decontaminate
|
|
8
8
|
@decoder = decoder
|
9
9
|
end
|
10
10
|
|
11
|
-
def decode(xml_node)
|
11
|
+
def decode(this, xml_node)
|
12
12
|
children = xml_node && xml_node.xpath(xpath)
|
13
13
|
return [] unless children
|
14
14
|
children.map do |child|
|
15
|
-
decoder.decode child
|
15
|
+
decoder.decode this, child
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -8,9 +8,9 @@ module Decontaminate
|
|
8
8
|
@decontaminator = decontaminator
|
9
9
|
end
|
10
10
|
|
11
|
-
def decode(xml_node)
|
11
|
+
def decode(this, xml_node)
|
12
12
|
child = xml_node && xml_node.at_xpath(xpath)
|
13
|
-
decontaminator.new(child).as_json
|
13
|
+
decontaminator.new(child, instance: this).as_json
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -9,9 +9,9 @@ module Decontaminate
|
|
9
9
|
@transformer = transformer
|
10
10
|
end
|
11
11
|
|
12
|
-
def decode(xml_node)
|
12
|
+
def decode(this, xml_node)
|
13
13
|
value = value_from_xml_node xml_node
|
14
|
-
value =
|
14
|
+
value = this.instance_exec(value, &transformer) if transformer
|
15
15
|
value
|
16
16
|
end
|
17
17
|
|
@@ -9,13 +9,13 @@ module Decontaminate
|
|
9
9
|
@transformer = transformer
|
10
10
|
end
|
11
11
|
|
12
|
-
def decode(xml_node)
|
12
|
+
def decode(this, xml_node)
|
13
13
|
xml_nodes = xpaths.map { |xpath| xml_node && xml_node.at_xpath(xpath) }
|
14
14
|
tuple = xml_nodes.map do |element_node|
|
15
|
-
decoder.decode element_node
|
15
|
+
decoder.decode this, element_node
|
16
16
|
end
|
17
17
|
|
18
|
-
tuple =
|
18
|
+
tuple = this.instance_exec(*tuple, &transformer) if transformer
|
19
19
|
|
20
20
|
tuple
|
21
21
|
end
|
@@ -22,13 +22,24 @@ module Decontaminate
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def scalar(xpath,
|
25
|
+
def scalar(xpath,
|
26
|
+
type: :string,
|
27
|
+
key: infer_key(xpath),
|
28
|
+
transformer: nil,
|
29
|
+
&block)
|
30
|
+
block ||= self_proc_for_method transformer
|
26
31
|
add_decoder key, Decontaminate::Decoder::Scalar.new(xpath, type, block)
|
27
32
|
end
|
28
33
|
|
29
|
-
def scalars(xpath = nil,
|
34
|
+
def scalars(xpath = nil,
|
35
|
+
path: nil,
|
36
|
+
type: :string,
|
37
|
+
key: nil,
|
38
|
+
transformer: nil,
|
39
|
+
&block)
|
30
40
|
resolved_path = path || infer_plural_path(xpath)
|
31
41
|
key ||= infer_key(path || xpath)
|
42
|
+
block ||= self_proc_for_method transformer
|
32
43
|
|
33
44
|
singular = Decontaminate::Decoder::Scalar.new('.', type, block)
|
34
45
|
decoder = Decontaminate::Decoder::Array.new(resolved_path, singular)
|
@@ -36,9 +47,16 @@ module Decontaminate
|
|
36
47
|
add_decoder key, decoder
|
37
48
|
end
|
38
49
|
|
39
|
-
def tuple(paths,
|
50
|
+
def tuple(paths,
|
51
|
+
key:,
|
52
|
+
type: :string,
|
53
|
+
transformer: nil,
|
54
|
+
&block)
|
55
|
+
block ||= self_proc_for_method transformer
|
56
|
+
|
40
57
|
scalar = Decontaminate::Decoder::Scalar.new('.', type, nil)
|
41
58
|
decoder = Decontaminate::Decoder::Tuple.new(paths, scalar, block)
|
59
|
+
|
42
60
|
add_decoder key, decoder
|
43
61
|
end
|
44
62
|
|
@@ -84,12 +102,19 @@ module Decontaminate
|
|
84
102
|
def infer_plural_path(xpath)
|
85
103
|
xpath + '/' + xpath.split('/').last.singularize
|
86
104
|
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def self_proc_for_method(sym)
|
109
|
+
sym && proc { |*args| send sym, *args }
|
110
|
+
end
|
87
111
|
end
|
88
112
|
|
89
113
|
attr_reader :xml_node
|
90
114
|
|
91
|
-
def initialize(xml_node)
|
115
|
+
def initialize(xml_node, instance: nil)
|
92
116
|
@xml_node = xml_node
|
117
|
+
@instance = instance
|
93
118
|
end
|
94
119
|
|
95
120
|
def as_json
|
@@ -97,7 +122,7 @@ module Decontaminate
|
|
97
122
|
|
98
123
|
root_node = xml_node && xml_node.at_xpath(root)
|
99
124
|
decoders.each do |key, decoder|
|
100
|
-
acc[key] = decoder.decode root_node
|
125
|
+
acc[key] = decoder.decode instance, root_node
|
101
126
|
end
|
102
127
|
|
103
128
|
acc
|
@@ -105,6 +130,12 @@ module Decontaminate
|
|
105
130
|
|
106
131
|
private
|
107
132
|
|
133
|
+
# The canonical instance that all blocks should run within. Child
|
134
|
+
# (anonymous) decontaminators should delegate to the parent.
|
135
|
+
def instance
|
136
|
+
@instance || self
|
137
|
+
end
|
138
|
+
|
108
139
|
def decoders
|
109
140
|
self.class.decoders
|
110
141
|
end
|