transmogrifier 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ require "transmogrifier"
2
+
3
+ describe Transmogrifier::Engine do
4
+ subject(:engine) { described_class.from_rules_array(rules) }
5
+
6
+ describe "#run" do
7
+ let(:rules) do
8
+ [
9
+ {
10
+ "type" => "append",
11
+ "selector" => "top",
12
+ "object" => {"some" => "attributes"}
13
+ },
14
+
15
+ {
16
+ "type" => "move",
17
+ "selector" => "top",
18
+ "from" => "key1",
19
+ "to" => "key2",
20
+ },
21
+
22
+ {
23
+ "type" => "delete",
24
+ "selector" => "top",
25
+ "name" => "key3"
26
+ }
27
+ ]
28
+ end
29
+
30
+ it "runs all the rules" do
31
+ input_hash = {
32
+ "top" => {
33
+ "key1" => "value1",
34
+ "key3" => "value2"
35
+ }
36
+ }
37
+
38
+ expect(engine.run(input_hash)).to eq({
39
+ "top" => {
40
+ "some" => "attributes",
41
+ "key2" => "value1",
42
+ }
43
+ })
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,84 @@
1
+ require "transmogrifier"
2
+
3
+ module Transmogrifier
4
+ describe ArrayNode do
5
+ describe "#raw" do
6
+ it "returns the underlying array" do
7
+ array = [{"name" => "object1"}, {"name" => "object2"}]
8
+ node = ArrayNode.new(array)
9
+ expect(node.raw).to eq(array)
10
+ end
11
+ end
12
+
13
+ describe "#find_all" do
14
+ it "returns wildcard matches" do
15
+ array = [
16
+ {"name" => "object1", "nested" => {"key1" => "value1"}},
17
+ {"name" => "object2", "nested" => {"key2" => "value2"}}
18
+ ]
19
+ node = ArrayNode.new(array)
20
+
21
+ expect(node.find_all([[], "nested"]).map(&:raw)).to eq([
22
+ {"key1" => "value1"},
23
+ {"key2" => "value2"},
24
+ ])
25
+ end
26
+
27
+ it "filters by attributes" do
28
+ array = [
29
+ {"type" => "object", "key1" => "value1"},
30
+ {"type" => "object", "key2" => "value2"},
31
+ ]
32
+ node = ArrayNode.new(array)
33
+
34
+ expect(node.find_all([["type", "object"]]).map(&:raw)).to eq(array)
35
+ end
36
+ end
37
+
38
+ describe "#delete" do
39
+ context "when one node matches the criteria" do
40
+ it "deletes the node from the array" do
41
+ array = [
42
+ {"name" => "object1"},
43
+ {"name" => "object2"},
44
+ ]
45
+ node = ArrayNode.new(array)
46
+ expect(node.delete([["name", "object1"]])).to eq({"name" => "object1"})
47
+ end
48
+ end
49
+
50
+ context "when more than one node matches the criteria" do
51
+ it "raises an error" do
52
+ array = [
53
+ {"name" => "object1", "common_key" => "common_value"},
54
+ {"name" => "object2", "common_key" => "common_value"},
55
+ ]
56
+ node = ArrayNode.new(array)
57
+ expect {
58
+ node.delete([["common_key", "common_value"]])
59
+ }.to raise_error
60
+ end
61
+ end
62
+
63
+ context "when no nodes match the criteria" do
64
+ it "returns nil" do
65
+ array = [
66
+ {"name" => "object1"},
67
+ {"name" => "object2"},
68
+ ]
69
+ node = ArrayNode.new(array)
70
+ expect(node.delete([["name", "not_present"]])).to be_nil
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "#append" do
76
+ it "appends the node to the array" do
77
+ array = [{"name" => "object1"}]
78
+ node = ArrayNode.new(array)
79
+ node.append("name" => "object2")
80
+ expect(node.raw).to eq([{"name" => "object1"}, {"name" => "object2"}])
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,94 @@
1
+ require "transmogrifier"
2
+
3
+ module Transmogrifier
4
+ describe HashNode do
5
+ describe "#raw" do
6
+ it "returns the passed in hash" do
7
+ node = HashNode.new({"key" => "value"})
8
+ expect(node.raw).to eq({"key" => "value"})
9
+ end
10
+ end
11
+
12
+ describe "#find_all" do
13
+ context "given an empty set of selector keys" do
14
+ it "returns itself in an array" do
15
+ hash = {
16
+ "key" => "value",
17
+ "extra_key" => "other_value",
18
+ }
19
+ node = HashNode.new(hash)
20
+
21
+ expect(node.find_all([]).map(&:raw)).to eq([{
22
+ "key" => "value",
23
+ "extra_key" => "other_value",
24
+ }])
25
+ end
26
+ end
27
+
28
+ context "given multiple selector keys" do
29
+ let(:keys) { ["key", [["k", "v"]]] }
30
+
31
+ context "when the first key is a key in the hash" do
32
+ let(:hash) {{
33
+ "key" => [
34
+ {"k" => "v", "a" => "b"},
35
+ {"k" => "not_v", "c" => "d"},
36
+ {"k" => "v", "e" => "f"},
37
+ ]
38
+ }}
39
+
40
+ it "finds all children of the first key's value satisfying the remaining selector keys" do
41
+ node = HashNode.new(hash)
42
+
43
+ expect(node.find_all(keys).map(&:raw)).to eq([
44
+ {"k" => "v", "a" => "b"},
45
+ {"k" => "v", "e" => "f"}
46
+ ])
47
+ end
48
+ end
49
+
50
+ context "when the first key is not a key in the hash" do
51
+ let(:hash) {{
52
+ "not_key" => [
53
+ {"k" => "v", "a" => "b"},
54
+ {"k" => "not_v", "c" => "d"},
55
+ {"k" => "v", "e" => "f"}
56
+ ]
57
+ }}
58
+
59
+ it "returns an empty array" do
60
+ node = HashNode.new(hash)
61
+
62
+ expect(node.find_all(keys).map(&:raw)).to eq([])
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "#delete" do
69
+ it "deletes the given key" do
70
+ hash = {"key" => "value", "extra_key" => "other_value"}
71
+ node = HashNode.new(hash)
72
+ node.delete("extra_key")
73
+
74
+ expect(node.raw).to eq({"key" => "value"})
75
+ end
76
+
77
+ it "returns the node that was deleted" do
78
+ hash = {"key" => "value", "extra_key" => "other_value"}
79
+ node = HashNode.new(hash)
80
+
81
+ expect(node.delete("extra_key")).to eq("other_value")
82
+ end
83
+ end
84
+
85
+ describe "#append" do
86
+ it "appends the given node at the key" do
87
+ hash = {"key" => "value"}
88
+ node = HashNode.new(hash)
89
+ node.append({ "extra_key" => "extra_value"})
90
+ expect(node.raw).to eq({"key" => "value", "extra_key" => "extra_value"})
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,19 @@
1
+ require "transmogrifier"
2
+
3
+ module Transmogrifier
4
+ describe Node do
5
+ describe ".for" do
6
+ it "returns a node value" do
7
+ Node.for("value").should be_a(ValueNode)
8
+ end
9
+
10
+ it "returns a hash value" do
11
+ Node.for("key" => "value").should be_a(HashNode)
12
+ end
13
+
14
+ it "returns an array value" do
15
+ Node.for(["value"]).should be_a(ArrayNode)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ require "transmogrifier"
2
+
3
+ module Transmogrifier
4
+ describe ValueNode do
5
+ describe "#raw" do
6
+ it "returns the passed in value" do
7
+ node = ValueNode.new("hello")
8
+ expect(node.raw).to eq("hello")
9
+ end
10
+ end
11
+
12
+ describe "#find_all" do
13
+ context "when given empty keys" do
14
+ it "returns an array of itself" do
15
+ node = ValueNode.new("hello")
16
+ expect(node.find_all([])).to eq([node])
17
+ end
18
+ end
19
+
20
+ context "when given non-empty keys" do
21
+ it "raises an error" do
22
+ node = ValueNode.new("hello")
23
+ expect {
24
+ node.find_all(["foo.bar"])
25
+ }.to raise_error
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "#delete" do
31
+ it "raises a NotImplementedError" do
32
+ expect {
33
+ ValueNode.new("hello").delete("key")
34
+ }.to raise_error(NotImplementedError)
35
+ end
36
+ end
37
+
38
+ describe "#append" do
39
+ it "raises a NotImplementedError" do
40
+ expect {
41
+ ValueNode.new("hello").append("value")
42
+ }.to raise_error(NotImplementedError)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ require "transmogrifier"
2
+
3
+ describe Transmogrifier::Rules::Append do
4
+ let(:input_hash) do
5
+ { "key" => "value", "array" => [] }
6
+ end
7
+
8
+ context "when the selector finds a HashNode" do
9
+ subject(:append) { described_class.new("", {"new_key" => "new_value"}) }
10
+ it "appends to the hash" do
11
+ expect(append.apply!(input_hash)).to eq({
12
+ "key" => "value",
13
+ "array" => [],
14
+ "new_key" => "new_value",
15
+ })
16
+ end
17
+ end
18
+
19
+ context "when the selector finds an ArrayNode" do
20
+ subject(:append) { described_class.new("array", {"new_key" => "new_value"}) }
21
+
22
+ it "appends to the array" do
23
+ expect(append.apply!(input_hash)).to eq({
24
+ "key" => "value",
25
+ "array" => [{"new_key" => "new_value"}],
26
+ })
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ require "transmogrifier"
2
+
3
+ describe Transmogrifier::Rules::Delete do
4
+ let(:input_hash) do
5
+ {
6
+ "key" => "value",
7
+ "array" => [{"inside" => "value"}],
8
+ "nested" => {
9
+ "key" => "value"
10
+ },
11
+ }
12
+ end
13
+
14
+ context "when the selector finds a HashNode" do
15
+ subject(:delete) { described_class.new("", "nested") }
16
+
17
+ it "deletes the hash from the parent" do
18
+ expect(delete.apply!(input_hash)).to eq({
19
+ "key" => "value",
20
+ "array" => [{"inside" => "value"}],
21
+ })
22
+ end
23
+ end
24
+
25
+ context "when the selector finds an ArrayNode" do
26
+ subject(:delete) { described_class.new("array", "[inside=value]") }
27
+
28
+ it "deletes the array from the parent" do
29
+ expect(delete.apply!(input_hash)).to eq({
30
+ "key" => "value",
31
+ "array" => [],
32
+ "nested" => {
33
+ "key" => "value"
34
+ },
35
+ })
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,110 @@
1
+ require "transmogrifier"
2
+
3
+ describe Transmogrifier::Rules::Move do
4
+ let(:input_hash) do
5
+ {
6
+ "key" => "value",
7
+ "array" => [{"inside" => "value"}],
8
+ "nested" => {
9
+ "key" => "value",
10
+ },
11
+ }
12
+ end
13
+
14
+ context "when the selector finds a HashNode" do
15
+ context "when the target key exists" do
16
+ subject(:move) { described_class.new("", "array.[inside=value]", "nested") }
17
+
18
+ it "moves the hash to the to selector" do
19
+ expect(move.apply!(input_hash)).to eq({
20
+ "key" => "value",
21
+ "array" => [],
22
+ "nested" => {
23
+ "key" => "value",
24
+ "inside" => "value",
25
+ },
26
+ })
27
+ end
28
+ end
29
+
30
+ context "when the target key doesn't exist" do
31
+ subject(:move) { described_class.new("", "array.[inside=value]", "nested.nested_again") }
32
+
33
+ it "moves the hash to a new child" do
34
+ expect(move.apply!(input_hash)).to eq({
35
+ "key" => "value",
36
+ "array" => [],
37
+ "nested" => {
38
+ "key" => "value",
39
+ "nested_again" => {
40
+ "inside" => "value",
41
+ }
42
+ },
43
+ })
44
+ end
45
+ end
46
+
47
+ context "when the from selector has a wildcard" do
48
+ let(:input_hash) do
49
+ {
50
+ "list_of_things" => [
51
+ {
52
+ "name" => "object1",
53
+ "property" => "property1",
54
+ "nested" => {}
55
+ },
56
+ {
57
+ "name" => "object2",
58
+ "property" => "property2",
59
+ "nested" => {}
60
+ },
61
+ ]
62
+ }
63
+ end
64
+ subject(:move) { described_class.new("list_of_things.[]", "property", "nested.property") }
65
+
66
+ it "moves the matched hash to the correct place" do
67
+ expect(move.apply!(input_hash)).to eq({
68
+ "list_of_things" => [
69
+ {
70
+ "name" => "object1",
71
+ "nested" => { "property" => "property1" }
72
+ },
73
+ {
74
+ "name" => "object2",
75
+ "nested" => { "property" => "property2" }
76
+ },
77
+ ]
78
+ })
79
+ end
80
+ end
81
+ end
82
+
83
+ context "when the selector finds an ArrayNode" do
84
+ subject(:move) { described_class.new("", "array", "nested.array") }
85
+
86
+ it "moves the array to the to selector" do
87
+ expect(move.apply!(input_hash)).to eq({
88
+ "key" => "value",
89
+ "nested" => {
90
+ "key" => "value",
91
+ "array" => [{"inside" => "value"}],
92
+ },
93
+ })
94
+ end
95
+ end
96
+
97
+ context "using move as a rename" do
98
+ subject(:rename) { described_class.new("", "array", "new_array") }
99
+
100
+ it "renames the node" do
101
+ expect(rename.apply!(input_hash)).to eq({
102
+ "key" => "value",
103
+ "new_array" => [{"inside" => "value"}],
104
+ "nested" => {
105
+ "key" => "value",
106
+ },
107
+ })
108
+ end
109
+ end
110
+ end