transformator 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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