mailgun 0.8 → 0.11
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/.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
|