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.
@@ -0,0 +1,187 @@
1
+ describe Transformator::Dsl do
2
+ let(:dsl) do
3
+ Module.new.extend(described_class)
4
+ end
5
+
6
+ #
7
+ # array
8
+ #
9
+ describe "#array" do
10
+ it "creates a new element with attribute \"type\" == \"array\"" do
11
+ expect(dsl.array(:foo)["type"]).to eq("array")
12
+ end
13
+
14
+ context "when called with a block" do
15
+ describe "passes an array accumulator to the block" do
16
+ it "allows appending elements to the array so that it's activesupport Hash.from_xml compatble" do
17
+ array_with_one_element = dsl.array(:foo) do |arr|
18
+ arr << dsl.element(:bar)
19
+ end
20
+
21
+ expect(dsl.find(array_with_one_element, "foo/bar")).not_to be_nil
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ #
28
+ # element
29
+ #
30
+ describe "#element" do
31
+ it "creates a new element with the given name" do
32
+ expect(dsl.element(:foo).value).to eq("foo")
33
+ end
34
+
35
+ context "when called with an \"attributes\" option" do
36
+ it "sets the attributes of the newly created element accordingly" do
37
+ attributes = { attr1: 1, attr2: "2", "attr3" => true }
38
+ expect(dsl.element(:foo, attributes: attributes).attributes).to eq({
39
+ "attr1" => "1",
40
+ "attr2" => "2",
41
+ "attr3" => "true"
42
+ })
43
+ end
44
+ end
45
+
46
+ context "when called with a \"text\" option" do
47
+ it "adds a text node to the newly created element" do
48
+ expect(dsl.element(:foo, text: "bar").text).to eq("bar")
49
+ end
50
+ end
51
+
52
+ context "when called with a \"type\" option" do
53
+ it "adds an attribute named \"type\" with the given value" do
54
+ expect(dsl.element(:foo, text: 1, type: :integer).attributes).to include({"type" => "integer"})
55
+ end
56
+ end
57
+ end
58
+
59
+ #
60
+ # elements_from_hash
61
+ #
62
+ describe "#elements_from_hash" do
63
+ let(:hash) do
64
+ {
65
+ key1: "value1",
66
+ key2: [
67
+ {
68
+ subkey: "subvalue"
69
+ }
70
+ ]
71
+ }
72
+ end
73
+
74
+ it "creates elements from the given hash" do
75
+ elements = dsl.elements_from_hash(hash)
76
+ expect(elements[0].value).to eq("key1")
77
+ expect(dsl.find(elements[1], "key2/subkey").text).to eq("subvalue") # key2 ist found due to the additional array element encoding
78
+ end
79
+ end
80
+
81
+ #
82
+ # elements_from_xml
83
+ #
84
+ describe "#elements_from_xml" do
85
+ let(:xml) do
86
+ <<-xml.strip_heredoc
87
+ <key1>value1</key1>
88
+ <key2>
89
+ <subkey>subvalue</subkey>
90
+ </key2>
91
+ xml
92
+ end
93
+
94
+ it "creates elements from the given xml string" do
95
+ elements = dsl.elements_from_xml(xml)
96
+ expect(elements[0].value).to eq("key1")
97
+ expect(dsl.find(elements[1], "subkey").text).to eq("subvalue")
98
+ end
99
+ end
100
+
101
+ #
102
+ # find
103
+ #
104
+ describe "#find" do
105
+ let(:node) do
106
+ dsl.element(:root) do |root|
107
+ root << dsl.element(:foo, text: "1")
108
+ root << dsl.element(:foo, text: "2")
109
+ end
110
+ end
111
+
112
+ describe "is a shortcut for find_all(..)[0]" do
113
+ context "when there are elements matching the given path" do
114
+ it "returns the first element found" do
115
+ expect(dsl.find(node, "foo").text).to eq("1")
116
+ end
117
+ end
118
+
119
+ context "when there are no elements matching the given path" do
120
+ it "returns nil" do
121
+ expect(dsl.find(node, "nope")).to be_nil
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ #
128
+ # find_all
129
+ #
130
+ describe "#find_all" do
131
+ let(:node) do
132
+ dsl.element(:root) do |root|
133
+ root << dsl.element(:foo, text: "1")
134
+ root << dsl.element(:foo, text: "2")
135
+ root << dsl.element(:bar) do |bar|
136
+ bar << dsl.element(:muff) do |muff|
137
+ muff << dsl.element(:key, text: "value")
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ it "understands xpath like path expressions" do
144
+ expect(dsl.find_all(node, "//key")).not_to be_nil
145
+ end
146
+
147
+ describe "finds all elements by the given path" do
148
+ context "when there are elements matching the given path" do
149
+ it "returns all elements found" do
150
+ expect(dsl.find_all(node, "foo").map(&:text)).to eq(["1", "2"])
151
+ end
152
+ end
153
+
154
+ context "when there are no elements matching the given path" do
155
+ it "returns an empty array" do
156
+ expect(dsl.find_all(node, "nope")).to eq([])
157
+ end
158
+ end
159
+ end
160
+
161
+ context "when called with a block" do
162
+ context "when there are elements matching the given path" do
163
+ it "calls the block with resulting array" do
164
+ variable_changed_inside_block = false
165
+
166
+ dsl.find_all(node, "foo") do |result|
167
+ variable_changed_inside_block = true if result.length == 2
168
+ end
169
+
170
+ expect(variable_changed_inside_block).to be(true)
171
+ end
172
+ end
173
+
174
+ context "when there are no elements matching the given path" do
175
+ it "the block is not called" do
176
+ variable_changed_inside_block = false
177
+
178
+ dsl.find_all(node, "nope") do |foo|
179
+ variable_changed_inside_block = true
180
+ end
181
+
182
+ expect(variable_changed_inside_block).to be(false)
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,42 @@
1
+ describe Transformator::FormatConverter::HashFromDocument do
2
+ let(:transformator) do
3
+ Module.new.tap do |mod|
4
+ mod.extend Transformator::FormatConverter::HashFromDocument
5
+ mod.extend Transformator::FormatConverter::DocumentFromHash
6
+ end
7
+ end
8
+
9
+ let(:hash) do
10
+ {
11
+ "key1" => "value1",
12
+ "key2" => 1,
13
+ "key3" => 1.5,
14
+ "key4" => true,
15
+ "key5" => nil,
16
+ "key6" => {
17
+ "key6_1" => "value6_1"
18
+ },
19
+ "key7" => [
20
+ "1",
21
+ 2,
22
+ true,
23
+ {
24
+ "key_arr_obj1" => [
25
+ "nested_element1",
26
+ {
27
+ "nested_key" => "nested_value"
28
+ }
29
+ ]
30
+ }
31
+ ]
32
+ }
33
+ end
34
+
35
+ let(:document) do
36
+ transformator.document_from_hash(hash)
37
+ end
38
+
39
+ it "converts a document to its corresponding hash" do
40
+ expect(transformator.hash_from_document(document)).to eq(hash)
41
+ end
42
+ end
@@ -16,174 +16,28 @@ describe Transformator::Transformation do
16
16
  end
17
17
 
18
18
  describe "#new" do
19
- it "can be called with a block, containing the mapping described by the DSL" do
19
+ it "can be called with a block, containing the mapping described by the dsl" do
20
20
  transformation = described_class.new do
21
- process "foo/bar" do |elements, target|
22
- target_elements = elements.map do |element|
23
- Ox::Element.new("muff").tap do |new_element|
24
- element.nodes.each do |node|
25
- new_element << node
26
- end
27
- end
28
- end
29
-
30
- target << target_elements.first
31
- binding.pry
21
+ process "foo/bar" do |element, target|
22
+ target << element("muff", nodes: element.nodes)
32
23
  end
33
24
  end
34
25
 
35
- expect(transformation.apply_to(source_xml)).to eq(transformed_xml)
36
- end
37
- =begin
38
- context "when called with a \"context\" option" do
39
- it "passes methods from withing the mapping (e.g. procs/lambdas) to the context" do
40
- some_class = Class.new do
41
- require "yahm"
42
-
43
- def some_method(value)
44
- value.to_s + "bar"
45
- end
46
-
47
- def mapping
48
- @mapping ||= Yahm::Mapping.new(context: self) do
49
- map "/foo", to: "/bar", processed_by: lambda { |v| some_method(v) }
50
- end
51
- end
52
-
53
- def apply_mapping_to(hash)
54
- mapping.apply_to(hash)
55
- end
56
- end
57
-
58
- expect(some_class.new.apply_mapping_to({foo: "foo"})).to eq({:bar=>"foobar"})
59
- end
26
+ expect(transformation.apply(to: source_xml)).to eq(transformed_xml)
60
27
  end
61
- =end
62
28
  end
63
- =begin
64
- describe ".apply_to" do
65
- let(:mapping) do
66
- Yahm::Mapping.new do
67
- map "/record_id", to: "/id"
68
- map "/record/title", to: "/title"
69
- map "/record/isbns", to: "/my_data/isbns"
70
- map "/record/isbns[1]", to: "/main_isbn" # when an array, one can specifiy which element to choose
71
- map "/record/count", to: "/count", processed_by: lambda { |v| v.to_i }
72
- map "/record/languages", to: "/languages", force_array: true
73
- map "/record/authors", to: "/authors", split_by: ";"
74
- map "/record/version", to: "/version", default: 1
75
- map "/record/creators", to: "/creators", force_array: true # when source value is nil, there should be an empty array in the target hash
76
- map "/record/publishers", to: "/publishers", split_by: ";" # if there are is no source value, this should result to nil in the target hash
77
- end
78
- end
79
-
80
- let(:input_hash) do
81
- {
82
- record_id: "some_id123",
83
- record: {
84
- title: "some title",
85
- isbns: [
86
- "3-86680-192-0",
87
- "3-680-08783-7"
88
- ],
89
- count: "3",
90
- languages: "ger",
91
- authors: "John Doe; Jane Doe"
92
- }
93
- }
94
- end
95
-
96
- let(:expected_result) do
97
- {
98
- :id=>"some_id123",
99
- :title=>"some title",
100
- :my_data=>{:isbns=>["3-86680-192-0", "3-680-08783-7"]},
101
- :main_isbn=>"3-680-08783-7",
102
- :count=>3,
103
- :languages=>["ger"],
104
- :authors=>["John Doe", "Jane Doe"],
105
- :version=>1,
106
- :creators=>[],
107
- :publishers=>nil
108
- }
109
- end
110
-
111
- it "translates a given hash according to @rules" do
112
- expect(mapping.apply_to(input_hash)).to eq(expected_result)
113
- end
114
-
115
- context "when threading is enabled" do
116
- it "translates a given hash according to @rules" do
117
- mapping.use_threads = true
118
- expect(mapping.apply_to(input_hash)).to eq(expected_result)
119
- end
120
- end
121
29
 
122
- it "does not apply \"split_by\" if source value is an array" do
123
- expect(Yahm::Mapping.new { map "/source/value", to: "/target", split_by: ";" }.apply_to(source: { value: ["foo", "foo;bar"] }))
124
- .to eq({
125
- :target => ["foo", "foo;bar"]
126
- })
127
- end
128
-
129
- it "processes the source value by the lambda/proc given by \"processed_by\"" do
130
- expect(Yahm::Mapping.new { map "/source/value", to: "/target", processed_by: lambda { |v| v.downcase } }.apply_to(source: { value: "A STRING" }))
131
- .to eq({
132
- :target => "a string"
133
- })
134
-
135
- expect(Yahm::Mapping.new { map "/source/value", to: "/target", processed_by: proc { |v| v.downcase } }.apply_to(source: { value: "A STRING" }))
136
- .to eq({
137
- :target => "a string"
138
- })
139
- end
140
-
141
- it "returns nil if the source path does not exist" do
142
- expect(Yahm::Mapping.new { map "/source/value/min", to: "/target" }.apply_to(foo: "bar")).to eq({
143
- :target => nil
144
- })
145
- end
146
-
147
- it "accepts a lambda/proc as :to option" do
148
- expect(Yahm::Mapping.new { map "/source", to: lambda { |v, result| result.merge!(target: true) } }.apply_to(foo: "bar"))
149
- .to eq({
150
- :target => true
151
- })
152
- end
153
-
154
- it "provides multiple values as an array of values to lambdas/procs" do
155
- expect(Yahm::Mapping.new { map "/source", to: "/array_length", processed_by: lambda { |v| v.length } }.apply_to(source: ["bar", "moep"]))
156
- .to eq({
157
- :array_length => 2
158
- })
159
- end
160
-
161
- it "can map multiple input fields to one output field" do
162
- mapping = Yahm::Mapping.new do
163
- map ["/hello", "/world", "/foo"], to: "/combined", processed_by: lambda { |v| v.values.compact.join(" ") }
164
- end
165
-
166
- expect(mapping.apply_to({
167
- hello: "hello",
168
- world: "world"
169
- })).to eq({
170
- combined: "hello world"
171
- })
172
- end
173
-
174
- it "can be called with a \"context\" option to set/overwrite the mapping context" do
175
- mapping = Yahm::Mapping.new do
176
- map "/source", to: "/target", processed_by: lambda { |v| process_value(v) }
177
- end
178
-
179
- context = Module.new do
180
- def self.process_value(v)
181
- v.to_i
30
+ describe ".process" do
31
+ context "when called with the special path :document" do
32
+ it "provides the whole input document to the block" do
33
+ transformation = described_class.new do
34
+ process :document do |document, target|
35
+ target << element("muff", nodes: ["muff"]) if document.nodes.empty?
36
+ end
182
37
  end
183
- end
184
38
 
185
- expect(mapping.apply_to({source: "1"}, context: context)).to eq({target: 1})
39
+ expect(transformation.apply(to: nil, output_format: :xml)).to eq(transformed_xml)
40
+ end
186
41
  end
187
42
  end
188
- =end
189
43
  end
@@ -1,2 +1,10 @@
1
1
  describe Transformator do
2
+ describe "#oxify_path" do
3
+ it "maps xpath like path expressions to Ox compatible ones" do
4
+ expect(described_class.oxify_path("/foo")).to eq("?/foo")
5
+ expect(described_class.oxify_path("/foo/bar")).to eq("?/foo/bar")
6
+ expect(described_class.oxify_path("//bar")).to eq("*/bar")
7
+ expect(described_class.oxify_path("/foo//bar")).to eq("?/foo/*/bar")
8
+ end
9
+ end
2
10
  end
@@ -16,9 +16,12 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "ox", ">= 2.0.0", "< 3.0.0"
19
+ spec.add_dependency "activesupport", ">= 3"
20
+ spec.add_dependency "builder", ">= 3"
21
+ spec.add_dependency "libxml-ruby", ">= 0.9.7"
22
+ spec.add_dependency "ox", ">= 2"
20
23
 
21
- spec.add_development_dependency "activesupport", ">= 3.0.0", "< 5.0.0"
24
+ spec.add_development_dependency "benchmark-ips", ">= 2.0.0"
22
25
  spec.add_development_dependency "bundler", "~> 1.6"
23
26
  spec.add_development_dependency "rake"
24
27
  spec.add_development_dependency "rspec", ">= 3.0.0", "< 4.0.0"
metadata CHANGED
@@ -1,55 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transformator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Sievers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-07 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ox
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.0
20
- - - "<"
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
21
25
  - !ruby/object:Gem::Version
22
- version: 3.0.0
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
23
34
  type: :runtime
24
35
  prerelease: false
25
36
  version_requirements: !ruby/object:Gem::Requirement
26
37
  requirements:
27
38
  - - ">="
28
39
  - !ruby/object:Gem::Version
29
- version: 2.0.0
30
- - - "<"
40
+ version: '3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: libxml-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
31
46
  - !ruby/object:Gem::Version
32
- version: 3.0.0
47
+ version: 0.9.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.7
33
55
  - !ruby/object:Gem::Dependency
34
- name: activesupport
56
+ name: ox
35
57
  requirement: !ruby/object:Gem::Requirement
36
58
  requirements:
37
59
  - - ">="
38
60
  - !ruby/object:Gem::Version
39
- version: 3.0.0
40
- - - "<"
61
+ version: '2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: benchmark-ips
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
41
74
  - !ruby/object:Gem::Version
42
- version: 5.0.0
75
+ version: 2.0.0
43
76
  type: :development
44
77
  prerelease: false
45
78
  version_requirements: !ruby/object:Gem::Requirement
46
79
  requirements:
47
80
  - - ">="
48
81
  - !ruby/object:Gem::Version
49
- version: 3.0.0
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: 5.0.0
82
+ version: 2.0.0
53
83
  - !ruby/object:Gem::Dependency
54
84
  name: bundler
55
85
  requirement: !ruby/object:Gem::Requirement
@@ -110,10 +140,25 @@ files:
110
140
  - LICENSE.txt
111
141
  - README.md
112
142
  - Rakefile
143
+ - assets/primo_search_response.xml
144
+ - assets/primo_search_response_1.xml
145
+ - examples/primo_search_response_transformation.rb
146
+ - examples/search_request_transformation.rb
113
147
  - lib/transformator.rb
148
+ - lib/transformator/dsl.rb
149
+ - lib/transformator/format_converter.rb
150
+ - lib/transformator/format_converter/document_from_hash.rb
151
+ - lib/transformator/format_converter/document_from_object.rb
152
+ - lib/transformator/format_converter/document_from_xml.rb
153
+ - lib/transformator/format_converter/hash_from_document.rb
154
+ - lib/transformator/format_converter/xml_from_document.rb
114
155
  - lib/transformator/transformation.rb
115
156
  - lib/transformator/version.rb
157
+ - spec/examples/primo_search_response_transformation_spec.rb
158
+ - spec/examples/search_request_transformation_spec.rb
116
159
  - spec/spec_helper.rb
160
+ - spec/transformator/dsl_spec.rb
161
+ - spec/transformator/format_converter/hash_from_document_spec.rb
117
162
  - spec/transformator/transformation_spec.rb
118
163
  - spec/transformator_spec.rb
119
164
  - transformator.gemspec
@@ -137,11 +182,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
182
  version: '0'
138
183
  requirements: []
139
184
  rubyforge_project:
140
- rubygems_version: 2.2.2
185
+ rubygems_version: 2.4.2
141
186
  signing_key:
142
187
  specification_version: 4
143
188
  summary: A ruby dsl for transforming hashes or json/xml documents
144
189
  test_files:
190
+ - spec/examples/primo_search_response_transformation_spec.rb
191
+ - spec/examples/search_request_transformation_spec.rb
145
192
  - spec/spec_helper.rb
193
+ - spec/transformator/dsl_spec.rb
194
+ - spec/transformator/format_converter/hash_from_document_spec.rb
146
195
  - spec/transformator/transformation_spec.rb
147
196
  - spec/transformator_spec.rb