transformator 0.0.1 → 0.1.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.
- checksums.yaml +4 -4
- data/Rakefile +43 -0
- data/assets/primo_search_response.xml +2878 -0
- data/assets/primo_search_response_1.xml +2467 -0
- data/examples/primo_search_response_transformation.rb +123 -0
- data/examples/search_request_transformation.rb +89 -0
- data/lib/transformator/dsl.rb +93 -0
- data/lib/transformator/format_converter/document_from_hash.rb +13 -0
- data/lib/transformator/format_converter/document_from_object.rb +20 -0
- data/lib/transformator/format_converter/document_from_xml.rb +28 -0
- data/lib/transformator/format_converter/hash_from_document.rb +61 -0
- data/lib/transformator/format_converter/xml_from_document.rb +7 -0
- data/lib/transformator/format_converter.rb +27 -0
- data/lib/transformator/transformation.rb +49 -23
- data/lib/transformator/version.rb +1 -1
- data/lib/transformator.rb +28 -0
- data/spec/examples/primo_search_response_transformation_spec.rb +19 -0
- data/spec/examples/search_request_transformation_spec.rb +48 -0
- data/spec/transformator/dsl_spec.rb +187 -0
- data/spec/transformator/format_converter/hash_from_document_spec.rb +42 -0
- data/spec/transformator/transformation_spec.rb +13 -159
- data/spec/transformator_spec.rb +8 -0
- data/transformator.gemspec +5 -2
- metadata +67 -18
@@ -0,0 +1,123 @@
|
|
1
|
+
require "transformator"
|
2
|
+
|
3
|
+
module Transformator::Examples
|
4
|
+
class PrimoSearchResponseTransformation
|
5
|
+
def self.apply(*args)
|
6
|
+
transformation.apply(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.transformation
|
10
|
+
Transformator::Transformation.new do
|
11
|
+
def search_brief_return_transformation
|
12
|
+
@search_brief_return_transformation ||= Transformator::Transformation.new do
|
13
|
+
#
|
14
|
+
# setup target skeleton
|
15
|
+
#
|
16
|
+
process :document do |source, target|
|
17
|
+
target_skeleton = {
|
18
|
+
took: nil,
|
19
|
+
hits: {
|
20
|
+
hits: []
|
21
|
+
},
|
22
|
+
facets: {}
|
23
|
+
}
|
24
|
+
|
25
|
+
elements_from_hash(target_skeleton).each do |element|
|
26
|
+
target << element
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# facets
|
32
|
+
#
|
33
|
+
process "SEGMENTS/JAGROOT/RESULT/FACETLIST/FACET" do |source_facet, target|
|
34
|
+
# syntactic mapping
|
35
|
+
find(target, "facets") << element(source_facet["NAME"]) do |target_facet|
|
36
|
+
source_facet_values = find_all(source_facet, "FACET_VALUES")
|
37
|
+
|
38
|
+
target_facet << element("_type", text: "terms")
|
39
|
+
target_facet << element("total", text: source_facet_values.length, type: "integer")
|
40
|
+
target_facet << (terms_array = array("terms"))
|
41
|
+
|
42
|
+
source_facet_values.each do |source_facet_value|
|
43
|
+
array(terms_array) do |term|
|
44
|
+
term << element("term", text: source_facet_value[:KEY])
|
45
|
+
term << element("count", text: source_facet_value[:VALUE], type: "integer")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# records
|
53
|
+
#
|
54
|
+
process "SEGMENTS/JAGROOT/RESULT/DOCSET/DOC" do |record, target|
|
55
|
+
array(find(target, "hits/hits")) do |hit|
|
56
|
+
# syntactic mapping
|
57
|
+
hit << element("_type", text: "record")
|
58
|
+
hit << _source = element("_source") do |element|
|
59
|
+
record.locate("PrimoNMBib/record/?").each do |section|
|
60
|
+
element << section
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# semantic mapping
|
65
|
+
{
|
66
|
+
"display/creationdate" => "created",
|
67
|
+
"display/description" => "description",
|
68
|
+
"display/edition" => "edition",
|
69
|
+
"display/format" => "format",
|
70
|
+
"display/language" => "language",
|
71
|
+
"display/title" => "title",
|
72
|
+
"display/subject" => "subject",
|
73
|
+
"display/publisher" => "publisher", # may there be more than one?
|
74
|
+
"control/recordid" => "id"
|
75
|
+
}
|
76
|
+
.each_pair do |from, to|
|
77
|
+
find(_source, "_source/#{from}") do |element|
|
78
|
+
hit << element(to, text: element.text)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
find_all(_source, "_source/display/creator").each do |creator|
|
83
|
+
hit << element("creator", text: creator.text)
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# identifier
|
88
|
+
#
|
89
|
+
hit << array("identifier") do |identifier|
|
90
|
+
# ilsApiId
|
91
|
+
identifier << element(find(_source, "control/ilsapiid").text, text: "ilsApiId")
|
92
|
+
|
93
|
+
# isbns
|
94
|
+
find_all(_source, "search/isbn").each do |isbn|
|
95
|
+
identifier << element(isbn.text, text: "isbn")
|
96
|
+
end
|
97
|
+
|
98
|
+
# recordId
|
99
|
+
identifier << element(find(_source, "control/recordid").text, text: "recordId")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
process :document do |source, target|
|
107
|
+
# parse the "string encoded" inner search brief return
|
108
|
+
search_brief_return = Transformator.document_from_xml(
|
109
|
+
find(source, "Envelope/Body/searchBriefResponse/searchBriefReturn").text,
|
110
|
+
remove_namespaces: true,
|
111
|
+
remove_whitespace_only_text_nodes: false
|
112
|
+
)
|
113
|
+
|
114
|
+
# apply the literal transformation and merge the result's nodes with target
|
115
|
+
search_brief_return_transformation.apply(
|
116
|
+
to: search_brief_return,
|
117
|
+
output: :ox_document
|
118
|
+
).nodes.each { |node| target << node }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "transformator"
|
2
|
+
|
3
|
+
module Transformator::Examples
|
4
|
+
class SearchRequestTransformation
|
5
|
+
def self.apply(*args)
|
6
|
+
transformation.apply(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.transformation
|
10
|
+
Transformator::Transformation.new do
|
11
|
+
#
|
12
|
+
# setup outer target skeleton
|
13
|
+
#
|
14
|
+
process :target do |target|
|
15
|
+
target << element_from_xml(
|
16
|
+
<<-xml.strip_heredoc
|
17
|
+
<env:Envelope
|
18
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
19
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
20
|
+
xmlns:impl="http://primo.kobv.de/PrimoWebServices/services/searcher"
|
21
|
+
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
|
22
|
+
xmlns:ins0="http://xml.apache.org/xml-soap">
|
23
|
+
<env:Body>
|
24
|
+
<impl:searchBrief></impl:searchBrief>
|
25
|
+
</env:Body>
|
26
|
+
</env:Envelope>
|
27
|
+
xml
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# setup inner search request that will be wrapped in a cdata element at the end
|
33
|
+
#
|
34
|
+
process :none do
|
35
|
+
# we setup this skeleton instead of dynamic element creation because order matters with primo
|
36
|
+
@search_request = element_from_xml(
|
37
|
+
<<-xml.strip_heredoc
|
38
|
+
<searchRequest xmlns="http://www.exlibris.com/primo/xsd/wsRequest" xmlns:uic="http://www.exlibris.com/primo/xsd/primoview/uicomponents">
|
39
|
+
<PrimoSearchRequest xmlns="http://www.exlibris.com/primo/xsd/search/request">
|
40
|
+
<QueryTerms>
|
41
|
+
<BoolOpeator>AND</BoolOpeator>
|
42
|
+
</QueryTerms>
|
43
|
+
<StartIndex></StartIndex>
|
44
|
+
<BulkSize></BulkSize>
|
45
|
+
<DidUMeanEnabled>false</DidUMeanEnabled>
|
46
|
+
<HighlightingEnabled>false</HighlightingEnabled>
|
47
|
+
<Languages></Languages>
|
48
|
+
<SortByList></SortByList>
|
49
|
+
<Locations></Locations>
|
50
|
+
</PrimoSearchRequest>
|
51
|
+
<onCampus>false</onCampus>
|
52
|
+
</searchRequest>
|
53
|
+
xml
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# transform source into target
|
59
|
+
#
|
60
|
+
process "/from" do |element|
|
61
|
+
find(@search_request, "PrimoSearchRequest/StartIndex") << element.text
|
62
|
+
end
|
63
|
+
|
64
|
+
process "/size" do |element|
|
65
|
+
find(@search_request, "PrimoSearchRequest/BulkSize") << element.text
|
66
|
+
end
|
67
|
+
|
68
|
+
process "//query_string" do |query_string|
|
69
|
+
find(@search_request, "PrimoSearchRequest/QueryTerms") << element_from_xml(
|
70
|
+
<<-xml.strip_heredoc
|
71
|
+
<QueryTerm>
|
72
|
+
<IndexField></IndexField>
|
73
|
+
<PrecisionOperator>contains</PrecisionOperator>
|
74
|
+
<Value>#{find(query_string, "query").text}</Value>
|
75
|
+
</QueryTerm>
|
76
|
+
xml
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# finally, wrap the search request into a cdata element
|
82
|
+
#
|
83
|
+
process :target do |target|
|
84
|
+
find(target, "//impl:searchBrief") << cdata(xml_from_element(@search_request))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "ox"
|
2
|
+
|
3
|
+
module Transformator::Dsl
|
4
|
+
def array(name_or_node, &block)
|
5
|
+
name_or_node = name_or_node.to_s if name_or_node.is_a?(Symbol) # eliminate "symbol"-case
|
6
|
+
|
7
|
+
name = name_or_node.is_a?(String) ? name_or_node : name_or_node.value
|
8
|
+
node = name_or_node.is_a?(Ox::Element) ? name_or_node : element(name, type: "array")
|
9
|
+
|
10
|
+
if block
|
11
|
+
append_accumulator = Struct.new(:elements) do
|
12
|
+
def <<(element)
|
13
|
+
self.elements.push(element)
|
14
|
+
end
|
15
|
+
end.new([])
|
16
|
+
|
17
|
+
yield(append_accumulator)
|
18
|
+
|
19
|
+
node << element(name) do |array_element|
|
20
|
+
append_accumulator.elements.each do |element|
|
21
|
+
array_element << element
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
node
|
27
|
+
end
|
28
|
+
|
29
|
+
def cdata(content, &block)
|
30
|
+
new_cdata = Ox::CData.new(content)
|
31
|
+
block ? yield(new_cdata) : new_cdata
|
32
|
+
end
|
33
|
+
|
34
|
+
def element(name, options = {}, &block)
|
35
|
+
new_element = Ox::Element.new(name)
|
36
|
+
|
37
|
+
if (attributes = options[:attributes]).is_a?(Hash)
|
38
|
+
attributes.each_pair do |key, value|
|
39
|
+
new_element[key.to_s] = value.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if nodes = options[:nodes]
|
44
|
+
(nodes.is_a?(Array) ? nodes : [nodes]).each do |node|
|
45
|
+
new_element << node
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if text = options[:text]
|
50
|
+
new_element << text.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
if type = options[:type]
|
54
|
+
new_element["type"] = type.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
yield(new_element) if block
|
58
|
+
new_element
|
59
|
+
end
|
60
|
+
|
61
|
+
def elements_from_hash(hash)
|
62
|
+
Transformator.document_from_hash(hash).root.nodes
|
63
|
+
end
|
64
|
+
|
65
|
+
def element_from_xml(xml, options = {})
|
66
|
+
elements_from_xml(xml, options).first
|
67
|
+
end
|
68
|
+
|
69
|
+
def elements_from_xml(xml, options = {})
|
70
|
+
Transformator.document_from_xml(xml, options).nodes
|
71
|
+
end
|
72
|
+
|
73
|
+
def find(node, path, &block)
|
74
|
+
find_result = find_all(node, path).first
|
75
|
+
|
76
|
+
if block && find_result
|
77
|
+
yield(find_result)
|
78
|
+
else
|
79
|
+
find_result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_all(node, path, &block)
|
84
|
+
find_all_result = node.locate(Transformator.oxify_path(path))
|
85
|
+
|
86
|
+
yield(find_all_result) if block && !find_all_result.empty?
|
87
|
+
find_all_result
|
88
|
+
end
|
89
|
+
|
90
|
+
def xml_from_element(element)
|
91
|
+
Transformator.xml_from_document(element, with_xml: false)
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "active_support/core_ext/hash/conversions"
|
2
|
+
require "libxml"
|
3
|
+
require "transformator/format_converter/document_from_xml"
|
4
|
+
|
5
|
+
module Transformator::FormatConverter::DocumentFromHash
|
6
|
+
include Transformator::FormatConverter::DocumentFromXml
|
7
|
+
|
8
|
+
def document_from_hash(hash)
|
9
|
+
ActiveSupport::XmlMini.backend = "LibXML"
|
10
|
+
xml = hash.to_xml(dasherize: false, indent: 0, root: :hash, skip_types: false)
|
11
|
+
document_from_xml(xml, remove_whitespace_only_text_nodes: false)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Transformator::FormatConverter::DocumentFromObject
|
2
|
+
def document_from_object(obj, options = {})
|
3
|
+
case Transformator.determine_format(obj)
|
4
|
+
when :hash
|
5
|
+
Transformator.document_from_hash(obj)
|
6
|
+
when :json
|
7
|
+
Transformator.document_from_json(obj)
|
8
|
+
when :ox_document
|
9
|
+
obj
|
10
|
+
when :xml
|
11
|
+
Transformator.document_from_xml(
|
12
|
+
obj,
|
13
|
+
remove_whitespace_only_text_nodes: false,
|
14
|
+
remove_namespaces: true
|
15
|
+
)
|
16
|
+
when nil
|
17
|
+
Ox::Document.new(version: "1.0", encoding: "UTF-8")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Transformator::FormatConverter::DocumentFromXml
|
2
|
+
def document_from_xml(xml, options = {})
|
3
|
+
xml =
|
4
|
+
if options[:remove_whitespace_only_text_nodes] || options[:remove_namespaces]
|
5
|
+
xml.dup
|
6
|
+
else
|
7
|
+
xml
|
8
|
+
end
|
9
|
+
|
10
|
+
unless options[:remove_whitespace_only_text_nodes] == false
|
11
|
+
Transformator::FormatConverter.remove_whitespace_only_text_nodes!(xml)
|
12
|
+
end
|
13
|
+
|
14
|
+
if options[:remove_namespaces] == true
|
15
|
+
Transformator::FormatConverter.remove_namespaces!(xml)
|
16
|
+
end
|
17
|
+
|
18
|
+
if xml[/\A\s*<\?xml/]
|
19
|
+
Ox.parse(xml)
|
20
|
+
else
|
21
|
+
Ox::Document.new(version: "1.0", encoding: "UTF-8").tap do |new_document|
|
22
|
+
Ox.parse("<root>" << xml << "</root>").nodes.each do |node|
|
23
|
+
new_document << node
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "ox"
|
2
|
+
|
3
|
+
module Transformator::FormatConverter::HashFromDocument
|
4
|
+
def hash_from_document(document)
|
5
|
+
document =
|
6
|
+
if document.root.value == "hash"
|
7
|
+
document
|
8
|
+
else
|
9
|
+
hash_container_document = Ox::Document.new
|
10
|
+
hash_container_document << (hash_root_element = Ox::Element.new("hash"))
|
11
|
+
document.nodes.each do |node|
|
12
|
+
hash_root_element << node
|
13
|
+
end
|
14
|
+
|
15
|
+
hash_container_document
|
16
|
+
end
|
17
|
+
|
18
|
+
hash = Transformator::FormatConverter::HashFromDocument.process_node(document.root, {})
|
19
|
+
hash["hash"].nil? ? hash : hash["hash"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.process_node(node, hash)
|
23
|
+
value =
|
24
|
+
if (child_nodes = node.nodes).all? { |child_node| child_node.is_a?(String) }
|
25
|
+
case node[:type]
|
26
|
+
when "integer" then child_nodes.join.to_i
|
27
|
+
when "float" then child_nodes.join.to_f
|
28
|
+
when "boolean" then child_nodes.join.downcase == "true"
|
29
|
+
else node[:nil] == "true" ? nil : child_nodes.join
|
30
|
+
end
|
31
|
+
else
|
32
|
+
if node[:type] == "array"
|
33
|
+
node.locate(node.value)
|
34
|
+
.map do |child_node|
|
35
|
+
if (arr_element = process_node(child_node, {})).is_a?(Hash) && arr_element.keys == [node.value]
|
36
|
+
arr_element.values.first
|
37
|
+
else
|
38
|
+
arr_element
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else
|
42
|
+
{}.tap do |child_nodes_hash|
|
43
|
+
child_nodes.each do |child_node|
|
44
|
+
process_node(child_node, child_nodes_hash)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
hash[node.value] =
|
51
|
+
if hash[node.value].nil?
|
52
|
+
value
|
53
|
+
elsif hash[node.value].is_a?(Array)
|
54
|
+
hash[node.value] << value
|
55
|
+
else
|
56
|
+
[hash[node.value], value]
|
57
|
+
end
|
58
|
+
|
59
|
+
hash
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Transformator::FormatConverter
|
2
|
+
require_relative "./format_converter/document_from_hash"
|
3
|
+
require_relative "./format_converter/document_from_object"
|
4
|
+
require_relative "./format_converter/document_from_xml"
|
5
|
+
require_relative "./format_converter/hash_from_document"
|
6
|
+
require_relative "./format_converter/xml_from_document"
|
7
|
+
|
8
|
+
include DocumentFromHash
|
9
|
+
include DocumentFromObject
|
10
|
+
include DocumentFromXml
|
11
|
+
include HashFromDocument
|
12
|
+
include XmlFromDocument
|
13
|
+
|
14
|
+
def self.remove_namespaces!(xml)
|
15
|
+
xml.gsub!(/<(\/?)\w+:(\w+)/, "<\\1\\2")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.remove_whitespace_only_text_nodes(xml)
|
19
|
+
remove_whitespace_only_text_nodes!(xml.dup)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.remove_whitespace_only_text_nodes!(xml)
|
23
|
+
# remove whitespace only text nodes
|
24
|
+
xml.gsub!(/>(\s|\n|\r)+</, "><")
|
25
|
+
xml
|
26
|
+
end
|
27
|
+
end
|
@@ -1,41 +1,67 @@
|
|
1
1
|
require "ox"
|
2
|
+
require "transformator/dsl"
|
2
3
|
|
3
4
|
class Transformator::Transformation
|
4
5
|
def initialize(options = {}, &block)
|
5
|
-
@context = options[:context]
|
6
6
|
@rules = []
|
7
7
|
self.instance_eval(&block) if block
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
#
|
11
|
+
public
|
12
|
+
#
|
13
|
+
def apply(options = {})
|
14
|
+
source = Transformator.document_from_object(options[:source] ||= options[:to])
|
15
|
+
target = Transformator.document_from_object(options[:target])
|
16
|
+
|
17
|
+
@rules.each do |rule|
|
18
|
+
block = rule[:callable]
|
19
|
+
path = rule[:path]
|
20
|
+
type = rule[:type]
|
21
|
+
|
22
|
+
# allow user do process source => source, target => target or target => source
|
23
|
+
_source = options[:source] == :target ? target : source
|
24
|
+
_target = options[:target] == :source ? source : target
|
25
|
+
|
26
|
+
if type == :process
|
27
|
+
if path.is_a?(Array)
|
28
|
+
block.call(
|
29
|
+
path.map do |_path| { _path => find_all(_source, _path) } end,
|
30
|
+
_target
|
31
|
+
)
|
32
|
+
elsif path.is_a?(String)
|
33
|
+
find_all(_source, path).each do |element_to_process|
|
34
|
+
block.call(element_to_process, _target)
|
35
|
+
end
|
36
|
+
elsif path.is_a?(Symbol)
|
37
|
+
if path == :document
|
38
|
+
block.call(_source, _target)
|
39
|
+
elsif path == :none
|
40
|
+
block.call
|
41
|
+
elsif path == :source
|
42
|
+
block.call(source, _target)
|
43
|
+
elsif path == :target
|
44
|
+
block.call(target, _target)
|
45
|
+
end
|
46
|
+
end
|
15
47
|
end
|
16
48
|
end
|
17
49
|
|
18
|
-
|
50
|
+
case options[:output_format] || Transformator.determine_format(options[:source])
|
51
|
+
when :hash then Transformator.hash_from_document(target)
|
52
|
+
when :ox_document then target
|
53
|
+
when :xml then Ox.dump(target, with_xml: true)
|
54
|
+
else raise "Unknown output format!"
|
55
|
+
end
|
19
56
|
end
|
20
57
|
|
58
|
+
#
|
21
59
|
private
|
22
|
-
|
60
|
+
#
|
61
|
+
include Transformator::Dsl
|
62
|
+
|
23
63
|
def process(path, options = {}, &block)
|
24
|
-
@rules.push({ callable: block, path: path }.merge(options))
|
64
|
+
@rules.push({ callable: block, path: path, type: :process}.merge(options))
|
25
65
|
self
|
26
66
|
end
|
27
|
-
|
28
|
-
def apply_rule(rule, source, target, options = {})
|
29
|
-
value =
|
30
|
-
if rule[:path].is_a?(Array)
|
31
|
-
rule[:path].inject({}) do |hash, path|
|
32
|
-
hash[path] = source.locate(path)
|
33
|
-
memo
|
34
|
-
end
|
35
|
-
else
|
36
|
-
source.locate(rule[:path])
|
37
|
-
end
|
38
|
-
|
39
|
-
(options[:context] || @context || self).instance_exec(value, target, &rule[:callable])
|
40
|
-
end
|
41
67
|
end
|
data/lib/transformator.rb
CHANGED
@@ -1,5 +1,33 @@
|
|
1
|
+
require "ox"
|
1
2
|
require "transformator/version"
|
2
3
|
|
3
4
|
module Transformator
|
5
|
+
require_relative "./transformator/dsl"
|
6
|
+
require_relative "./transformator/format_converter"
|
4
7
|
require_relative "./transformator/transformation"
|
8
|
+
|
9
|
+
extend Transformator::FormatConverter
|
10
|
+
|
11
|
+
def self.determine_format(obj)
|
12
|
+
if obj.is_a?(Hash)
|
13
|
+
:hash
|
14
|
+
elsif obj.is_a?(Ox::Document)
|
15
|
+
:ox_document
|
16
|
+
elsif obj.is_a?(String) && obj[/\A\s*{/]
|
17
|
+
:json
|
18
|
+
elsif obj.is_a?(String) && obj[/\A\s*</]
|
19
|
+
:xml
|
20
|
+
elsif obj.nil?
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
raise "Unkown format!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.oxify_path(path)
|
28
|
+
path
|
29
|
+
.gsub(/\A\/\/(\S+)/, "*/\\1")
|
30
|
+
.gsub(/(\S*)\/\/(\S*)/, "\\1/*/\\2")
|
31
|
+
.gsub(/\A\/(\w+)(\S*)/, "?/\\1\\2") # replace "/foo" with "?/foo"
|
32
|
+
end
|
5
33
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../../examples/primo_search_response_transformation"
|
2
|
+
|
3
|
+
describe "Examples" do
|
4
|
+
let(:primo_search_response) do
|
5
|
+
File.read(
|
6
|
+
File.expand_path(
|
7
|
+
File.join(
|
8
|
+
File.dirname(__FILE__), "../../assets/primo_search_response_1.xml"
|
9
|
+
)
|
10
|
+
)
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "transforms primo search response" do
|
15
|
+
Transformator::Examples::PrimoSearchResponseTransformation.apply(to: primo_search_response, output_format: :hash).tap do |w|
|
16
|
+
# binding.pry
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "../../examples/search_request_transformation"
|
2
|
+
|
3
|
+
describe "Examples" do
|
4
|
+
let(:search_request_hash) do
|
5
|
+
{
|
6
|
+
from: 0,
|
7
|
+
size: 20,
|
8
|
+
query: {
|
9
|
+
bool: {
|
10
|
+
must: [
|
11
|
+
{
|
12
|
+
query_string: {
|
13
|
+
query: "linux",
|
14
|
+
default_operator: "AND",
|
15
|
+
fields: [
|
16
|
+
"title^2",
|
17
|
+
"_all"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
},
|
21
|
+
{
|
22
|
+
query_string: {
|
23
|
+
query: "kofler",
|
24
|
+
default_operator: "AND",
|
25
|
+
fields: [
|
26
|
+
"creator"
|
27
|
+
]
|
28
|
+
}
|
29
|
+
},
|
30
|
+
{
|
31
|
+
range: {
|
32
|
+
lsr09: {
|
33
|
+
gte: 20140101
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
]
|
38
|
+
}
|
39
|
+
},
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "transforms search request to primo soap body" do
|
44
|
+
Transformator::Examples::SearchRequestTransformation.apply(to: search_request_hash, output_format: :xml).tap do |w|
|
45
|
+
# binding.pry
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|