mailgun 0.8 → 0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +13 -0
- data/CONTRIBUTORS.md +5 -1
- data/README.md +39 -2
- data/lib/mailgun.rb +6 -1
- data/lib/mailgun/address.rb +20 -0
- data/lib/mailgun/base.rb +45 -16
- data/lib/mailgun/client.rb +87 -0
- data/lib/mailgun/domain.rb +9 -4
- data/lib/mailgun/list/member.rb +9 -1
- data/lib/mailgun/mailgun_error.rb +54 -1
- data/lib/mailgun/route.rb +9 -4
- data/lib/mailgun/secure.rb +30 -0
- data/lib/mailgun/webhook.rb +55 -0
- data/lib/multimap/spec/enumerable_examples.rb +22 -22
- data/lib/multimap/spec/hash_examples.rb +88 -88
- data/lib/multimap/spec/multiset_spec.rb +62 -62
- data/lib/multimap/spec/nested_multimap_spec.rb +58 -58
- data/lib/multimap/spec/set_examples.rb +112 -112
- data/lib/multimap/spec/spec_helper.rb +2 -2
- data/mailgun.gemspec +3 -5
- data/spec/address_spec.rb +27 -0
- data/spec/base_spec.rb +31 -25
- data/spec/bounce_spec.rb +5 -5
- data/spec/client_spec.rb +118 -0
- data/spec/complaint_spec.rb +4 -4
- data/spec/domain_spec.rb +17 -5
- data/spec/helpers/mailgun_helper.rb +9 -0
- data/spec/list/member_spec.rb +7 -7
- data/spec/list/message_spec.rb +3 -3
- data/spec/list_spec.rb +6 -6
- data/spec/log_spec.rb +2 -2
- data/spec/mailbox_spec.rb +4 -4
- data/spec/route_spec.rb +10 -11
- data/spec/secure_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/unsubscribe_spec.rb +6 -6
- data/spec/webhook_spec.rb +115 -0
- metadata +22 -21
data/lib/mailgun/route.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
module Mailgun
|
2
2
|
class Route
|
3
|
-
|
4
3
|
def initialize(mailgun)
|
5
4
|
@mailgun = mailgun
|
6
5
|
end
|
7
|
-
|
6
|
+
|
8
7
|
def list(options={})
|
9
8
|
Mailgun.submit(:get, route_url, options)["items"] || []
|
10
9
|
end
|
@@ -26,6 +25,8 @@ module Mailgun
|
|
26
25
|
data['action'] = action
|
27
26
|
end
|
28
27
|
|
28
|
+
data = data.to_hash
|
29
|
+
|
29
30
|
# TODO: Raise an error or return false if unable to create route
|
30
31
|
Mailgun.submit(:post, route_url, data)["route"]["id"]
|
31
32
|
end
|
@@ -33,6 +34,8 @@ module Mailgun
|
|
33
34
|
def update(route_id, params)
|
34
35
|
data = ::Multimap.new
|
35
36
|
|
37
|
+
params = Hash[params.map{ |k, v| [k.to_s, v] }]
|
38
|
+
|
36
39
|
['priority', 'description'].each do |key|
|
37
40
|
data[key] = params[key] if params.has_key?(key)
|
38
41
|
end
|
@@ -47,13 +50,15 @@ module Mailgun
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
53
|
+
data = data.to_hash
|
54
|
+
|
50
55
|
Mailgun.submit(:put, route_url(route_id), data)
|
51
56
|
end
|
52
|
-
|
57
|
+
|
53
58
|
def destroy(route_id)
|
54
59
|
Mailgun.submit(:delete, route_url(route_id))["id"]
|
55
60
|
end
|
56
|
-
|
61
|
+
|
57
62
|
private
|
58
63
|
|
59
64
|
def route_url(route_id=nil)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# verifySignature: function(timestamp, token, signature, minutes_offset) {
|
2
|
+
# var offset = Math.round((new Date()).getTime() / 1000) - (minutes_offset || 5) * 60;
|
3
|
+
# if(timestamp < offset)
|
4
|
+
# return false;
|
5
|
+
#
|
6
|
+
# var hmac = crypto.createHmac('sha256', api_key);
|
7
|
+
# hmac.update(timestamp + token);
|
8
|
+
# return signature == hmac.digest('hex');
|
9
|
+
# },
|
10
|
+
|
11
|
+
module Mailgun
|
12
|
+
class Secure
|
13
|
+
def initialize(mailgun)
|
14
|
+
@mailgun = mailgun
|
15
|
+
end
|
16
|
+
|
17
|
+
# check request auth
|
18
|
+
def check_request_auth(timestamp, token, signature, offset=-5)
|
19
|
+
if offset != 0
|
20
|
+
offset = Time.now.to_i + offset * 60
|
21
|
+
return false if timestamp < offset
|
22
|
+
end
|
23
|
+
|
24
|
+
return signature == OpenSSL::HMAC.hexdigest(
|
25
|
+
OpenSSL::Digest::Digest.new('sha256'),
|
26
|
+
Mailgun.api_key,
|
27
|
+
'%s%s' % [timestamp, token])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Mailgun
|
2
|
+
# Interface to manage webhooks
|
3
|
+
# https://documentation.mailgun.com/api-webhooks.html#webhooks
|
4
|
+
class Webhook
|
5
|
+
attr_accessor :default_webhook_url, :domain
|
6
|
+
|
7
|
+
# Used internally, called from Mailgun::Base
|
8
|
+
def initialize(mailgun, domain, url)
|
9
|
+
@mailgun = mailgun
|
10
|
+
@domain = domain
|
11
|
+
@default_webhook_url = url
|
12
|
+
end
|
13
|
+
|
14
|
+
# List of currently available webhooks
|
15
|
+
def available_ids
|
16
|
+
%w(bounce deliver drop spam unsubscribe click open).map(&:to_sym)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a list of webhooks set for the specified domain
|
20
|
+
def list
|
21
|
+
Mailgun.submit(:get, webhook_url)["webhooks"] || []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns details about the webhook specified
|
25
|
+
def find(id)
|
26
|
+
Mailgun.submit :get, webhook_url(id)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates a new webhook
|
30
|
+
# Note: Creating an Open or Click webhook will enable Open or Click tracking
|
31
|
+
def create(id, url=default_webhook_url)
|
32
|
+
params = {:id => id, :url => url}
|
33
|
+
Mailgun.submit :post, webhook_url, params
|
34
|
+
end
|
35
|
+
|
36
|
+
# Updates an existing webhook
|
37
|
+
def update(id, url=default_webhook_url)
|
38
|
+
params = {:url => url}
|
39
|
+
Mailgun.submit :put, webhook_url(id), params
|
40
|
+
end
|
41
|
+
|
42
|
+
# Deletes an existing webhook
|
43
|
+
# Note: Deleting an Open or Click webhook will disable Open or Click tracking
|
44
|
+
def delete(id)
|
45
|
+
Mailgun.submit :delete, webhook_url(id)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
# Helper method to generate the proper url for Mailgun webhook API calls
|
51
|
+
def webhook_url(id=nil)
|
52
|
+
"#{@mailgun.base_url}/domains/#{domain}/webhooks#{'/' + id if id}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,50 +1,50 @@
|
|
1
1
|
shared_examples_for Enumerable, Multimap, "with inital values {'a' => [100], 'b' => [200, 300]}" do
|
2
2
|
it "should check all key/value pairs for condition" do
|
3
|
-
@map.all? { |key, value| key =~ /\w/ }.
|
4
|
-
@map.all? { |key, value| key =~ /\d/ }.
|
5
|
-
@map.all? { |key, value| value > 0 }.
|
6
|
-
@map.all? { |key, value| value > 200 }.
|
3
|
+
expect(@map.all? { |key, value| key =~ /\w/ }).to be_true
|
4
|
+
expect(@map.all? { |key, value| key =~ /\d/ }).to be_false
|
5
|
+
expect(@map.all? { |key, value| value > 0 }).to be_true
|
6
|
+
expect(@map.all? { |key, value| value > 200 }).to be_false
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should check any key/value pairs for condition" do
|
10
|
-
@map.any? { |key, value| key == "a" }.
|
11
|
-
@map.any? { |key, value| key == "z" }.
|
12
|
-
@map.any? { |key, value| value == 100 }.
|
13
|
-
@map.any? { |key, value| value > 1000 }.
|
10
|
+
expect(@map.any? { |key, value| key == "a" }).to be_true
|
11
|
+
expect(@map.any? { |key, value| key == "z" }).to be_false
|
12
|
+
expect(@map.any? { |key, value| value == 100 }).to be_true
|
13
|
+
expect(@map.any? { |key, value| value > 1000 }).to be_false
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should collect key/value pairs" do
|
17
|
-
@map.collect { |key, value| [key, value] }.
|
18
|
-
@map.map { |key, value| [key, value] }.
|
17
|
+
expect(@map.collect { |key, value| [key, value] }).to sorted_eql([["a", 100], ["b", 200], ["b", 300]])
|
18
|
+
expect(@map.map { |key, value| [key, value] }).to sorted_eql([["a", 100], ["b", 200], ["b", 300]])
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should detect key/value pair" do
|
22
|
-
@map.detect { |key, value| value > 200 }.
|
23
|
-
@map.find { |key, value| value > 200 }.
|
22
|
+
expect(@map.detect { |key, value| value > 200 }).to eql(["b", 300])
|
23
|
+
expect(@map.find { |key, value| value > 200 }).to eql(["b", 300])
|
24
24
|
end
|
25
25
|
|
26
26
|
it "should return entries" do
|
27
|
-
@map.entries.
|
28
|
-
@map.to_a.
|
27
|
+
expect(@map.entries).to sorted_eql([["a", 100], ["b", 200], ["b", 300]])
|
28
|
+
expect(@map.to_a).to sorted_eql([["a", 100], ["b", 200], ["b", 300]])
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should find all key/value pairs" do
|
32
|
-
@map.find_all { |key, value| value >= 200 }.
|
33
|
-
@map.select { |key, value| value >= 200 }.
|
32
|
+
expect(@map.find_all { |key, value| value >= 200 }).to eql([["b", 200], ["b", 300]])
|
33
|
+
expect(@map.select { |key, value| value >= 200 }).to eql(Multimap["b", [200, 300]])
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should combine key/value pairs with inject" do
|
37
|
-
@map.inject(0) { |sum, (key, value)| sum + value }.
|
37
|
+
expect(@map.inject(0) { |sum, (key, value)| sum + value }).to eql(600)
|
38
38
|
|
39
39
|
@map.inject(0) { |memo, (key, value)|
|
40
40
|
memo > value ? memo : value
|
41
|
-
}.
|
41
|
+
expect(}).to eql(300)
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should check for key membership" do
|
45
|
-
@map.member?("a").
|
46
|
-
@map.include?("a").
|
47
|
-
@map.member?("z").
|
48
|
-
@map.include?("z").
|
45
|
+
expect(@map.member?("a")).to be_true
|
46
|
+
expect(@map.include?("a")).to be_true
|
47
|
+
expect(@map.member?("z")).to be_false
|
48
|
+
expect(@map.include?("z")).to be_false
|
49
49
|
end
|
50
50
|
end
|
@@ -8,152 +8,152 @@ shared_examples_for Hash, Multimap, "with inital values {'a' => [100], 'b' => [2
|
|
8
8
|
map2["a"] = 100
|
9
9
|
map2["b"] = 200
|
10
10
|
map2["b"] = 300
|
11
|
-
@map.
|
11
|
+
expect(@map).to eql(map2)
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should not be equal to another Multimap if they contain different values" do
|
15
|
-
@map.
|
15
|
+
expect(@map).to_not == Multimap["a" => [100], "b" => [200]]
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should retrieve container of values for key" do
|
19
|
-
@map["a"].
|
20
|
-
@map["b"].
|
21
|
-
@map["z"].
|
19
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
20
|
+
expect(@map["b"]).to eql(@container.new([200, 300]))
|
21
|
+
expect(@map["z"]).to eql(@container.new)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should append values to container at key" do
|
25
25
|
@map["a"] = 400
|
26
26
|
@map.store("b", 500)
|
27
|
-
@map["a"].
|
28
|
-
@map["b"].
|
27
|
+
expect(@map["a"]).to eql(@container.new([100, 400]))
|
28
|
+
expect(@map["b"]).to eql(@container.new([200, 300, 500]))
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should clear all key/values" do
|
32
32
|
@map.clear
|
33
|
-
@map.
|
33
|
+
expect(@map).to be_empty
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should be the class of the container" do
|
37
|
-
@map.default.class.
|
37
|
+
expect(@map.default.class).to eql(@container)
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should delete all values at key" do
|
41
41
|
@map.delete("a")
|
42
|
-
@map["a"].
|
42
|
+
expect(@map["a"]).to eql(@container.new)
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should delete single value at key" do
|
46
46
|
@map.delete("b", 200)
|
47
|
-
@map["b"].
|
47
|
+
expect(@map["b"]).to eql(@container.new([300]))
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should delete if key condition is matched" do
|
51
|
-
@map.delete_if { |key, value| key >= "b" }.
|
52
|
-
@map["a"].
|
53
|
-
@map["b"].
|
51
|
+
expect(@map.delete_if { |key, value| key >= "b" }).to eql(@map)
|
52
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
53
|
+
expect(@map["b"]).to eql(@container.new)
|
54
54
|
|
55
|
-
@map.delete_if { |key, value| key > "z" }.
|
55
|
+
expect(@map.delete_if { |key, value| key > "z" }).to eql(@map)
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should delete if value condition is matched" do
|
59
|
-
@map.delete_if { |key, value| value >= 300 }.
|
60
|
-
@map["a"].
|
61
|
-
@map["b"].
|
59
|
+
expect(@map.delete_if { |key, value| value >= 300 }).to eql(@map)
|
60
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
61
|
+
expect(@map["b"]).to eql(@container.new([200]))
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should duplicate the containers" do
|
65
65
|
map2 = @map.dup
|
66
|
-
map2.
|
67
|
-
map2.
|
68
|
-
map2["a"].
|
69
|
-
map2["b"].
|
70
|
-
map2.default.
|
71
|
-
map2.default.
|
66
|
+
expect(map2).to_not equal(@map)
|
67
|
+
expect(map2).to eql(@map)
|
68
|
+
expect(map2["a"]).to_not equal(@map["a"])
|
69
|
+
expect(map2["b"]).to_not equal(@map["b"])
|
70
|
+
expect(map2.default).to_not equal(@map.default)
|
71
|
+
expect(map2.default).to eql(@map.default)
|
72
72
|
end
|
73
73
|
|
74
74
|
it "should freeze containers" do
|
75
75
|
@map.freeze
|
76
|
-
@map.
|
77
|
-
@map["a"].
|
78
|
-
@map["b"].
|
76
|
+
expect(@map).to be_frozen
|
77
|
+
expect(@map["a"]).to be_frozen
|
78
|
+
expect(@map["b"]).to be_frozen
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should iterate over each key/value pair and yield an array" do
|
82
82
|
a = []
|
83
83
|
@map.each { |pair| a << pair }
|
84
|
-
a.
|
84
|
+
expect(a).to sorted_eql([["a", 100], ["b", 200], ["b", 300]])
|
85
85
|
end
|
86
86
|
|
87
87
|
it "should iterate over each container" do
|
88
88
|
a = []
|
89
89
|
@map.each_container { |container| a << container }
|
90
|
-
a.
|
90
|
+
expect(a).to sorted_eql([@container.new([100]), @container.new([200, 300])])
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should iterate over each key/container" do
|
94
94
|
a = []
|
95
95
|
@map.each_association { |key, container| a << [key, container] }
|
96
|
-
a.
|
96
|
+
expect(a).to sorted_eql([["a", @container.new([100])], ["b", @container.new([200, 300])]])
|
97
97
|
end
|
98
98
|
|
99
99
|
it "should iterate over each key" do
|
100
100
|
a = []
|
101
101
|
@map.each_key { |key| a << key }
|
102
|
-
a.
|
102
|
+
expect(a).to sorted_eql(["a", "b", "b"])
|
103
103
|
end
|
104
104
|
|
105
105
|
it "should iterate over each key/value pair and yield the pair" do
|
106
106
|
h = {}
|
107
107
|
@map.each_pair { |key, value| (h[key] ||= []) << value }
|
108
|
-
h.
|
108
|
+
expect(h).to eql({ "a" => [100], "b" => [200, 300] })
|
109
109
|
end
|
110
110
|
|
111
111
|
it "should iterate over each value" do
|
112
112
|
a = []
|
113
113
|
@map.each_value { |value| a << value }
|
114
|
-
a.
|
114
|
+
expect(a).to sorted_eql([100, 200, 300])
|
115
115
|
end
|
116
116
|
|
117
117
|
it "should be empty if there are no key/value pairs" do
|
118
118
|
@map.clear
|
119
|
-
@map.
|
119
|
+
expect(@map).to be_empty
|
120
120
|
end
|
121
121
|
|
122
122
|
it "should not be empty if there are any key/value pairs" do
|
123
|
-
@map.
|
123
|
+
expect(@map).to_not be_empty
|
124
124
|
end
|
125
125
|
|
126
126
|
it "should fetch container of values for key" do
|
127
|
-
@map.fetch("a").
|
128
|
-
@map.fetch("b").
|
129
|
-
lambda { @map.fetch("z") }.
|
127
|
+
expect(@map.fetch("a")).to eql(@container.new([100]))
|
128
|
+
expect(@map.fetch("b")).to eql(@container.new([200, 300]))
|
129
|
+
expect(lambda { @map.fetch("z") }).to raise_error(IndexError)
|
130
130
|
end
|
131
131
|
|
132
132
|
it "should check if key is present" do
|
133
|
-
@map.has_key?("a").
|
134
|
-
@map.key?("a").
|
135
|
-
@map.has_key?("z").
|
136
|
-
@map.key?("z").
|
133
|
+
expect(@map.has_key?("a")).to be_true
|
134
|
+
expect(@map.key?("a")).to be_true
|
135
|
+
expect(@map.has_key?("z")).to be_false
|
136
|
+
expect(@map.key?("z")).to be_false
|
137
137
|
end
|
138
138
|
|
139
139
|
it "should check containers when looking up by value" do
|
140
|
-
@map.has_value?(100).
|
141
|
-
@map.value?(100).
|
142
|
-
@map.has_value?(999).
|
143
|
-
@map.value?(999).
|
140
|
+
expect(@map.has_value?(100)).to be_true
|
141
|
+
expect(@map.value?(100)).to be_true
|
142
|
+
expect(@map.has_value?(999)).to be_false
|
143
|
+
expect(@map.value?(999)).to be_false
|
144
144
|
end
|
145
145
|
|
146
146
|
it "it should return the index for value" do
|
147
147
|
if @map.respond_to?(:index)
|
148
|
-
@map.index(200).
|
149
|
-
@map.index(999).
|
148
|
+
expect(@map.index(200)).to eql(@container.new(["b"]))
|
149
|
+
expect(@map.index(999)).to eql(@container.new)
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
153
153
|
it "should replace the contents of hash" do
|
154
154
|
@map.replace({ "c" => @container.new([300]), "d" => @container.new([400]) })
|
155
|
-
@map["a"].
|
156
|
-
@map["c"].
|
155
|
+
expect(@map["a"]).to eql(@container.new)
|
156
|
+
expect(@map["c"]).to eql(@container.new([300]))
|
157
157
|
end
|
158
158
|
|
159
159
|
it "should return an inverted Multimap" do
|
@@ -162,103 +162,103 @@ shared_examples_for Hash, Multimap, "with inital values {'a' => [100], 'b' => [2
|
|
162
162
|
map2[100] = "a"
|
163
163
|
map2[200] = "b"
|
164
164
|
map2[300] = "b"
|
165
|
-
@map.invert.
|
165
|
+
expect(@map.invert).to eql(map2)
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
169
|
it "should return array of keys" do
|
170
|
-
@map.keys.
|
170
|
+
expect(@map.keys).to eql(["a", "b", "b"])
|
171
171
|
end
|
172
172
|
|
173
173
|
it "should return the number of key/value pairs" do
|
174
|
-
@map.length.
|
175
|
-
@map.size.
|
174
|
+
expect(@map.length).to eql(3)
|
175
|
+
expect(@map.size).to eql(3)
|
176
176
|
end
|
177
177
|
|
178
178
|
it "should duplicate map and with merged values" do
|
179
179
|
map = @map.merge("b" => 254, "c" => @container.new([300]))
|
180
|
-
map["a"].
|
181
|
-
map["b"].
|
182
|
-
map["c"].
|
180
|
+
expect(map["a"]).to eql(@container.new([100]))
|
181
|
+
expect(map["b"]).to eql(@container.new([200, 300, 254]))
|
182
|
+
expect(map["c"]).to eql(@container.new([300]))
|
183
183
|
|
184
|
-
@map["a"].
|
185
|
-
@map["b"].
|
186
|
-
@map["c"].
|
184
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
185
|
+
expect(@map["b"]).to eql(@container.new([200, 300]))
|
186
|
+
expect(@map["c"]).to eql(@container.new)
|
187
187
|
end
|
188
188
|
|
189
189
|
it "should update map" do
|
190
190
|
@map.update("b" => 254, "c" => @container.new([300]))
|
191
|
-
@map["a"].
|
192
|
-
@map["b"].
|
193
|
-
@map["c"].
|
191
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
192
|
+
expect(@map["b"]).to eql(@container.new([200, 300, 254]))
|
193
|
+
expect(@map["c"]).to eql(@container.new([300]))
|
194
194
|
|
195
195
|
klass = @map.class
|
196
196
|
@map.update(klass[@container.new, {"a" => @container.new([400, 500]), "c" => 600}])
|
197
|
-
@map["a"].
|
198
|
-
@map["b"].
|
199
|
-
@map["c"].
|
197
|
+
expect(@map["a"]).to eql(@container.new([100, 400, 500]))
|
198
|
+
expect(@map["b"]).to eql(@container.new([200, 300, 254]))
|
199
|
+
expect(@map["c"]).to eql(@container.new([300, 600]))
|
200
200
|
end
|
201
201
|
|
202
202
|
it "should reject key pairs on copy of the map" do
|
203
203
|
map = @map.reject { |key, value| key >= "b" }
|
204
|
-
map["b"].
|
205
|
-
@map["b"].
|
204
|
+
expect(map["b"]).to eql(@container.new)
|
205
|
+
expect(@map["b"]).to eql(@container.new([200, 300]))
|
206
206
|
end
|
207
207
|
|
208
208
|
it "should reject value pairs on copy of the map" do
|
209
209
|
map = @map.reject { |key, value| value >= 300 }
|
210
|
-
map["b"].
|
211
|
-
@map["b"].
|
210
|
+
expect(map["b"]).to eql(@container.new([200]))
|
211
|
+
expect(@map["b"]).to eql(@container.new([200, 300]))
|
212
212
|
end
|
213
213
|
|
214
214
|
it "should reject key pairs" do
|
215
|
-
@map.reject! { |key, value| key >= "b" }.
|
216
|
-
@map["a"].
|
217
|
-
@map["b"].
|
215
|
+
expect(@map.reject! { |key, value| key >= "b" }).to eql(@map)
|
216
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
217
|
+
expect(@map["b"]).to eql(@container.new)
|
218
218
|
|
219
|
-
@map.reject! { |key, value| key >= "z" }.
|
219
|
+
expect(@map.reject! { |key, value| key >= "z" }).to eql(nil)
|
220
220
|
end
|
221
221
|
|
222
222
|
it "should reject value pairs" do
|
223
|
-
@map.reject! { |key, value| value >= 300 }.
|
224
|
-
@map["a"].
|
225
|
-
@map["b"].
|
223
|
+
expect(@map.reject! { |key, value| value >= 300 }).to eql(@map)
|
224
|
+
expect(@map["a"]).to eql(@container.new([100]))
|
225
|
+
expect(@map["b"]).to eql(@container.new([200]))
|
226
226
|
|
227
|
-
@map.reject! { |key, value| key >= "z" }.
|
227
|
+
expect(@map.reject! { |key, value| key >= "z" }).to eql(nil)
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should select key/value pairs" do
|
231
|
-
@map.select { |k, v| k > "a" }.
|
232
|
-
@map.select { |k, v| v < 200 }.
|
231
|
+
expect(@map.select { |k, v| k > "a" }).to eql(Multimap["b", [200, 300]])
|
232
|
+
expect(@map.select { |k, v| v < 200 }).to eql(Multimap["a", 100])
|
233
233
|
end
|
234
234
|
|
235
235
|
it "should convert to hash" do
|
236
|
-
@map.to_hash["a"].
|
237
|
-
@map.to_hash["b"].
|
238
|
-
@map.to_hash.
|
236
|
+
expect(@map.to_hash["a"]).to eql(@container.new([100]))
|
237
|
+
expect(@map.to_hash["b"]).to eql(@container.new([200, 300]))
|
238
|
+
expect(@map.to_hash).to_not equal(@map)
|
239
239
|
end
|
240
240
|
|
241
241
|
it "should return all containers" do
|
242
|
-
@map.containers.
|
242
|
+
expect(@map.containers).to sorted_eql([@container.new([100]), @container.new([200, 300])])
|
243
243
|
end
|
244
244
|
|
245
245
|
it "should return all values" do
|
246
|
-
@map.values.
|
246
|
+
expect(@map.values).to sorted_eql([100, 200, 300])
|
247
247
|
end
|
248
248
|
|
249
249
|
it "should return return values at keys" do
|
250
|
-
@map.values_at("a", "b").
|
250
|
+
expect(@map.values_at("a", "b")).to eql([@container.new([100]), @container.new([200, 300])])
|
251
251
|
end
|
252
252
|
|
253
253
|
it "should marshal hash" do
|
254
254
|
data = Marshal.dump(@map)
|
255
|
-
Marshal.load(data).
|
255
|
+
expect(Marshal.load(data)).to eql(@map)
|
256
256
|
end
|
257
257
|
|
258
258
|
it "should dump yaml" do
|
259
259
|
require 'yaml'
|
260
260
|
|
261
261
|
data = YAML.dump(@map)
|
262
|
-
YAML.load(data).
|
262
|
+
expect(YAML.load(data)).to eql(@map)
|
263
263
|
end
|
264
264
|
end
|