mongo 2.1.0.rc0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +5 -2
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -2
  5. data/lib/mongo.rb +2 -1
  6. data/lib/mongo/address.rb +11 -5
  7. data/lib/mongo/address/ipv4.rb +6 -1
  8. data/lib/mongo/auth/cr/conversation.rb +1 -1
  9. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  10. data/lib/mongo/auth/scram/conversation.rb +1 -1
  11. data/lib/mongo/auth/user/view.rb +2 -2
  12. data/lib/mongo/auth/x509/conversation.rb +1 -1
  13. data/lib/mongo/bulk_write.rb +12 -9
  14. data/lib/mongo/bulk_write/transformable.rb +20 -5
  15. data/lib/mongo/client.rb +11 -11
  16. data/lib/mongo/cluster.rb +2 -2
  17. data/lib/mongo/collection.rb +21 -8
  18. data/lib/mongo/collection/view.rb +1 -0
  19. data/lib/mongo/collection/view/aggregation.rb +11 -5
  20. data/lib/mongo/collection/view/iterable.rb +6 -2
  21. data/lib/mongo/collection/view/map_reduce.rb +39 -5
  22. data/lib/mongo/collection/view/readable.rb +35 -30
  23. data/lib/mongo/collection/view/writable.rb +26 -18
  24. data/lib/mongo/database.rb +12 -2
  25. data/lib/mongo/database/view.rb +4 -3
  26. data/lib/mongo/dbref.rb +4 -4
  27. data/lib/mongo/grid/fs_bucket.rb +8 -1
  28. data/lib/mongo/grid/stream/read.rb +1 -1
  29. data/lib/mongo/index.rb +5 -0
  30. data/lib/mongo/index/view.rb +2 -2
  31. data/lib/mongo/monitoring/command_log_subscriber.rb +9 -3
  32. data/lib/mongo/monitoring/event.rb +1 -0
  33. data/lib/mongo/monitoring/event/command_started.rb +2 -1
  34. data/lib/mongo/monitoring/event/command_succeeded.rb +6 -3
  35. data/lib/mongo/monitoring/event/secure.rb +58 -0
  36. data/lib/mongo/operation.rb +31 -1
  37. data/lib/mongo/operation/commands/collections_info.rb +2 -0
  38. data/lib/mongo/operation/commands/collections_info/result.rb +39 -0
  39. data/lib/mongo/operation/commands/list_indexes/result.rb +2 -1
  40. data/lib/mongo/operation/commands/map_reduce/result.rb +1 -1
  41. data/lib/mongo/operation/read/query.rb +2 -0
  42. data/lib/mongo/operation/read/query/result.rb +40 -0
  43. data/lib/mongo/operation/result.rb +13 -1
  44. data/lib/mongo/operation/write/bulk/delete.rb +2 -2
  45. data/lib/mongo/operation/write/bulk/update.rb +3 -3
  46. data/lib/mongo/operation/write/delete.rb +2 -2
  47. data/lib/mongo/operation/write/update.rb +9 -4
  48. data/lib/mongo/options.rb +1 -0
  49. data/lib/mongo/options/redacted.rb +156 -0
  50. data/lib/mongo/protocol/insert.rb +25 -6
  51. data/lib/mongo/protocol/query.rb +45 -31
  52. data/lib/mongo/protocol/reply.rb +29 -6
  53. data/lib/mongo/protocol/serializers.rb +1 -1
  54. data/lib/mongo/retryable.rb +83 -0
  55. data/lib/mongo/server.rb +16 -3
  56. data/lib/mongo/server/connectable.rb +21 -3
  57. data/lib/mongo/server/connection.rb +38 -4
  58. data/lib/mongo/server/connection_pool.rb +12 -0
  59. data/lib/mongo/server/connection_pool/queue.rb +15 -0
  60. data/lib/mongo/server/monitor/connection.rb +2 -2
  61. data/lib/mongo/server_selector.rb +5 -0
  62. data/lib/mongo/server_selector/selectable.rb +16 -9
  63. data/lib/mongo/socket.rb +6 -2
  64. data/lib/mongo/uri.rb +1 -1
  65. data/lib/mongo/version.rb +1 -1
  66. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +11 -11
  67. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +10 -10
  68. data/spec/mongo/client_spec.rb +101 -18
  69. data/spec/mongo/collection_spec.rb +44 -0
  70. data/spec/mongo/connection_string_spec.rb +36 -58
  71. data/spec/mongo/database_spec.rb +20 -0
  72. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  73. data/spec/mongo/grid/stream/write_spec.rb +2 -2
  74. data/spec/mongo/monitoring/event/command_started_spec.rb +26 -0
  75. data/spec/mongo/monitoring/event/command_succeeded_spec.rb +26 -0
  76. data/spec/mongo/monitoring/event/secure_spec.rb +57 -0
  77. data/spec/mongo/operation/commands/aggregate_spec.rb +0 -16
  78. data/spec/mongo/operation/commands/command_spec.rb +0 -18
  79. data/spec/mongo/operation/kill_cursors_spec.rb +0 -16
  80. data/spec/mongo/operation/read/get_more_spec.rb +0 -16
  81. data/spec/mongo/operation/read/query_spec.rb +19 -16
  82. data/spec/mongo/operation/write/bulk/delete_spec.rb +16 -16
  83. data/spec/mongo/operation/write/bulk/update_spec.rb +6 -6
  84. data/spec/mongo/operation/write/command/delete_spec.rb +0 -16
  85. data/spec/mongo/operation/write/command/insert_spec.rb +0 -16
  86. data/spec/mongo/operation/write/command/update_spec.rb +0 -16
  87. data/spec/mongo/operation/write/delete_spec.rb +3 -3
  88. data/spec/mongo/operation/write/update_spec.rb +6 -6
  89. data/spec/mongo/options/redacted_spec.rb +350 -0
  90. data/spec/mongo/protocol/query_spec.rb +15 -1
  91. data/spec/mongo/retryable_spec.rb +147 -0
  92. data/spec/mongo/server/connection_pool/queue_spec.rb +16 -0
  93. data/spec/mongo/server/connection_pool_spec.rb +32 -0
  94. data/spec/mongo/server/connection_spec.rb +37 -0
  95. data/spec/mongo/server_discovery_and_monitoring_spec.rb +24 -59
  96. data/spec/mongo/server_selection_rtt_spec.rb +37 -57
  97. data/spec/mongo/server_selection_spec.rb +2 -0
  98. data/spec/mongo/server_selector/nearest_spec.rb +1 -0
  99. data/spec/mongo/server_selector/primary_preferred_spec.rb +1 -0
  100. data/spec/mongo/server_selector/primary_spec.rb +8 -2
  101. data/spec/mongo/server_selector/secondary_preferred_spec.rb +1 -0
  102. data/spec/mongo/server_selector/secondary_spec.rb +1 -0
  103. data/spec/mongo/server_spec.rb +68 -1
  104. data/spec/mongo/socket/ssl_spec.rb +29 -5
  105. data/spec/mongo/uri_spec.rb +20 -20
  106. data/spec/support/crud.rb +7 -1
  107. data/spec/support/matchers.rb +1 -1
  108. data/spec/support/shared/server_selector.rb +58 -2
  109. metadata +20 -5
  110. metadata.gz.sig +0 -0
@@ -4,7 +4,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
4
4
  include_context 'operation'
5
5
 
6
6
  let(:documents) do
7
- [ { q: { foo: 1 }, limit: 1 } ]
7
+ [ { 'q' => { foo: 1 }, 'limit' => 1 } ]
8
8
  end
9
9
 
10
10
  let(:spec) do
@@ -42,7 +42,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
42
42
 
43
43
  context 'when two ops have different specs' do
44
44
  let(:other_docs) do
45
- [ { q: { bar: 1 }, limit: 1 } ]
45
+ [ { 'q' => { bar: 1 }, 'limit' => 1 } ]
46
46
  end
47
47
 
48
48
  let(:other_spec) do
@@ -89,7 +89,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
89
89
  context 'when the delete succeeds' do
90
90
 
91
91
  let(:documents) do
92
- [{ q: { field: 'test' }, limit: 1 }]
92
+ [{ 'q' => { field: 'test' }, 'limit' => 1 }]
93
93
  end
94
94
 
95
95
  it 'deletes the document from the database' do
@@ -113,7 +113,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
113
113
  context 'when the deletes succeed' do
114
114
 
115
115
  let(:documents) do
116
- [{ q: { field: 'test' }, limit: 0 }]
116
+ [{ 'q' => { field: 'test' }, 'limit' => 0 }]
117
117
  end
118
118
 
119
119
  it 'deletes the documents from the database' do
@@ -127,10 +127,10 @@ describe Mongo::Operation::Write::Bulk::Delete do
127
127
 
128
128
  let(:documents) do
129
129
  [ failing_delete_doc,
130
- { q: { field: 'test' }, limit: 1 }
130
+ { 'q' => { field: 'test' }, 'limit' => 1 }
131
131
  ]
132
132
  end
133
-
133
+
134
134
  let(:spec) do
135
135
  { :deletes => documents,
136
136
  :db_name => TEST_DB,
@@ -139,7 +139,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
139
139
  :ordered => true
140
140
  }
141
141
  end
142
-
142
+
143
143
  let(:failing_delete) do
144
144
  described_class.new(spec)
145
145
  end
@@ -151,7 +151,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
151
151
  let(:write_concern) do
152
152
  Mongo::WriteConcern.get(w: 1)
153
153
  end
154
-
154
+
155
155
  it 'aborts after first error' do
156
156
  failing_delete.execute(authorized_primary.context)
157
157
  expect(authorized_collection.find.count).to eq(2)
@@ -159,11 +159,11 @@ describe Mongo::Operation::Write::Bulk::Delete do
159
159
  end
160
160
 
161
161
  context 'when write concern is unacknowledged' do
162
-
162
+
163
163
  let(:write_concern) do
164
164
  Mongo::WriteConcern.get(w: 0)
165
165
  end
166
-
166
+
167
167
  it 'aborts after first error' do
168
168
  failing_delete.execute(authorized_primary.context)
169
169
  expect(authorized_collection.find.count).to eq(2)
@@ -176,10 +176,10 @@ describe Mongo::Operation::Write::Bulk::Delete do
176
176
 
177
177
  let(:documents) do
178
178
  [ failing_delete_doc,
179
- { q: { field: 'test' }, limit: 1 }
179
+ { 'q' => { field: 'test' }, 'limit' => 1 }
180
180
  ]
181
181
  end
182
-
182
+
183
183
  let(:spec) do
184
184
  { :deletes => documents,
185
185
  :db_name => TEST_DB,
@@ -188,7 +188,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
188
188
  :ordered => false
189
189
  }
190
190
  end
191
-
191
+
192
192
  let(:failing_delete) do
193
193
  described_class.new(spec)
194
194
  end
@@ -200,7 +200,7 @@ describe Mongo::Operation::Write::Bulk::Delete do
200
200
  let(:write_concern) do
201
201
  Mongo::WriteConcern.get(w: 1)
202
202
  end
203
-
203
+
204
204
  it 'does not abort after first error' do
205
205
  failing_delete.execute(authorized_primary.context)
206
206
  expect(authorized_collection.find.count).to eq(1)
@@ -208,11 +208,11 @@ describe Mongo::Operation::Write::Bulk::Delete do
208
208
  end
209
209
 
210
210
  context 'when write concern is unacknowledged' do
211
-
211
+
212
212
  let(:write_concern) do
213
213
  Mongo::WriteConcern.get(w: 0)
214
214
  end
215
-
215
+
216
216
  it 'does not abort after first error' do
217
217
  failing_delete.execute(authorized_primary.context)
218
218
  sleep(1)
@@ -90,7 +90,7 @@ describe Mongo::Operation::Write::Bulk::Update do
90
90
  context 'when the update passes' do
91
91
 
92
92
  let(:documents) do
93
- [{ q: { other: 'test' }, u: { '$set' => { field: 'blah' }}, multi: false }]
93
+ [{ 'q' => { other: 'test' }, 'u' => { '$set' => { field: 'blah' }}, 'multi' => false }]
94
94
  end
95
95
 
96
96
  it 'updates the document' do
@@ -114,7 +114,7 @@ describe Mongo::Operation::Write::Bulk::Update do
114
114
  context 'when the updates succeed' do
115
115
 
116
116
  let(:documents) do
117
- [{ q: { other: 'test' }, u: { '$set' => { field: 'blah' }}, multi: true }]
117
+ [{ 'q' => { other: 'test' }, 'u' => { '$set' => { field: 'blah' }}, 'multi' => true }]
118
118
  end
119
119
 
120
120
  it 'updates the documents' do
@@ -127,8 +127,8 @@ describe Mongo::Operation::Write::Bulk::Update do
127
127
  context 'when the updates are ordered' do
128
128
 
129
129
  let(:documents) do
130
- [ { q: { name: 'test' }, u: { '$st' => { field: 'blah' }}, multi: true},
131
- { q: { field: 'test' }, u: { '$set' => { other: 'blah' }}, multi: true }
130
+ [ { 'q' => { name: 'test' }, 'u' => { '$st' => { field: 'blah' }}, 'multi' => true},
131
+ { 'q' => { field: 'test' }, 'u' => { '$set' => { other: 'blah' }}, 'multi' => true }
132
132
  ]
133
133
  end
134
134
 
@@ -176,8 +176,8 @@ describe Mongo::Operation::Write::Bulk::Update do
176
176
  context 'when the updates are unordered' do
177
177
 
178
178
  let(:documents) do
179
- [ { q: { name: 'test' }, u: { '$st' => { field: 'blah' }}, multi: true},
180
- { q: { field: 'test' }, u: { '$set' => { other: 'blah' }}, multi: false }
179
+ [ { 'q' => { name: 'test' }, 'u' => { '$st' => { field: 'blah' }}, 'multi' => true},
180
+ { 'q' => { field: 'test' }, 'u' => { '$set' => { other: 'blah' }}, 'multi' => false }
181
181
  ]
182
182
  end
183
183
 
@@ -56,22 +56,6 @@ describe Mongo::Operation::Write::Command::Delete do
56
56
  end
57
57
  end
58
58
 
59
- context '#merge' do
60
- let(:other_op) { described_class.new(spec) }
61
-
62
- it 'is not allowed' do
63
- expect{ op.merge(other_op) }.to raise_exception
64
- end
65
- end
66
-
67
- context '#merge!' do
68
- let(:other_op) { described_class.new(spec) }
69
-
70
- it 'is not allowed' do
71
- expect{ op.merge!(other_op) }.to raise_exception
72
- end
73
- end
74
-
75
59
  describe '#execute' do
76
60
 
77
61
  context 'server' do
@@ -56,22 +56,6 @@ describe Mongo::Operation::Write::Command::Insert do
56
56
  end
57
57
  end
58
58
 
59
- context '#merge' do
60
- let(:other_op) { described_class.new(spec) }
61
-
62
- it 'is not allowed' do
63
- expect{ op.merge(other_op) }.to raise_exception
64
- end
65
- end
66
-
67
- context '#merge!' do
68
- let(:other_op) { described_class.new(spec) }
69
-
70
- it 'is not allowed' do
71
- expect{ op.merge!(other_op) }.to raise_exception
72
- end
73
- end
74
-
75
59
  describe '#execute' do
76
60
 
77
61
  context 'server' do
@@ -62,22 +62,6 @@ describe Mongo::Operation::Write::Command::Update do
62
62
  end
63
63
  end
64
64
 
65
- context '#merge' do
66
- let(:other_op) { described_class.new(spec) }
67
-
68
- it 'is not allowed' do
69
- expect{ op.merge(other_op) }.to raise_exception
70
- end
71
- end
72
-
73
- context '#merge!' do
74
- let(:other_op) { described_class.new(spec) }
75
-
76
- it 'is not allowed' do
77
- expect{ op.merge!(other_op) }.to raise_exception
78
- end
79
- end
80
-
81
65
  describe '#execute' do
82
66
 
83
67
  context 'server' do
@@ -89,7 +89,7 @@ describe Mongo::Operation::Write::Delete do
89
89
  context 'when the delete succeeds' do
90
90
 
91
91
  let(:document) do
92
- { q: { field: 'test' }, limit: 1 }
92
+ { 'q' => { field: 'test' }, 'limit' => 1 }
93
93
  end
94
94
 
95
95
  let(:result) do
@@ -133,7 +133,7 @@ describe Mongo::Operation::Write::Delete do
133
133
  context 'when the deletes succeed' do
134
134
 
135
135
  let(:document) do
136
- { q: { field: 'test' }, limit: 0 }
136
+ { 'q' => { field: 'test' }, 'limit' => 0 }
137
137
  end
138
138
 
139
139
  let(:result) do
@@ -172,7 +172,7 @@ describe Mongo::Operation::Write::Delete do
172
172
  context 'when a document exceeds max bson size' do
173
173
 
174
174
  let(:document) do
175
- { q: { field: 't'*17000000 }, limit: 0 }
175
+ { 'q' => { field: 't'*17000000 }, 'limit' => 0 }
176
176
  end
177
177
 
178
178
  it 'raises an error' do
@@ -95,7 +95,7 @@ describe Mongo::Operation::Write::Update do
95
95
  context 'when the update succeeds' do
96
96
 
97
97
  let(:document) do
98
- { q: { name: 'test' }, u: { '$set' => { field: 'blah' }}, limit: 1 }
98
+ { 'q' => { name: 'test' }, 'u' => { '$set' => { field: 'blah' }}, limit: 1 }
99
99
  end
100
100
 
101
101
  let(:result) do
@@ -122,7 +122,7 @@ describe Mongo::Operation::Write::Update do
122
122
  context 'when the update fails' do
123
123
 
124
124
  let(:document) do
125
- { q: { name: 'test' }, u: { '$st' => { field: 'blah' } } }
125
+ { 'q' => { name: 'test' }, 'u' => { '$st' => { field: 'blah' } } }
126
126
  end
127
127
 
128
128
  it 'raises an exception' do
@@ -147,7 +147,7 @@ describe Mongo::Operation::Write::Update do
147
147
  context 'when the updates succeed' do
148
148
 
149
149
  let(:document) do
150
- { q: { field: 'test' }, u: { '$set' => { other: 'blah' }}, multi: true }
150
+ { 'q' => { field: 'test' }, 'u' => { '$set' => { other: 'blah' }}, 'multi' => true }
151
151
  end
152
152
 
153
153
  let(:result) do
@@ -174,7 +174,7 @@ describe Mongo::Operation::Write::Update do
174
174
  context 'when an update fails' do
175
175
 
176
176
  let(:document) do
177
- { q: { name: 'test' }, u: { '$st' => { field: 'blah' } }, multi: true }
177
+ { 'q' => { name: 'test' }, 'u' => { '$st' => { field: 'blah' } }, 'multi' => true }
178
178
  end
179
179
 
180
180
  it 'raises an exception' do
@@ -187,7 +187,7 @@ describe Mongo::Operation::Write::Update do
187
187
  context 'when a document exceeds max bson size' do
188
188
 
189
189
  let(:document) do
190
- { q: { name: 't'*17000000}, u: { '$set' => { field: 'blah' } } }
190
+ { 'q' => { name: 't'*17000000}, 'u' => { '$set' => { field: 'blah' } } }
191
191
  end
192
192
 
193
193
  it 'raises an error' do
@@ -200,7 +200,7 @@ describe Mongo::Operation::Write::Update do
200
200
  context 'when upsert is true' do
201
201
 
202
202
  let(:document) do
203
- { q: { field: 'non-existent' }, u: { '$set' => { other: 'blah' }}, upsert: true }
203
+ { 'q' => { field: 'non-existent' }, 'u' => { '$set' => { other: 'blah' }}, 'upsert' => true }
204
204
  end
205
205
 
206
206
  let(:result) do
@@ -0,0 +1,350 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Options::Redacted do
4
+
5
+ let(:options) do
6
+ described_class.new(original_opts)
7
+ end
8
+
9
+ describe '#to_s' do
10
+
11
+ context 'when the hash contains a sensitive key' do
12
+
13
+ let(:original_opts) do
14
+ { password: 'sensitive_data' }
15
+ end
16
+
17
+ it 'replaces the value with the redacted string' do
18
+ expect(options.to_s).not_to match(original_opts[:password])
19
+ end
20
+
21
+ it 'replaces the value with the redacted string' do
22
+ expect(options.to_s).to match(Mongo::Options::Redacted::STRING_REPLACEMENT)
23
+ end
24
+ end
25
+
26
+ context 'when the hash does not contain a sensitive key' do
27
+
28
+ let(:original_opts) do
29
+ { user: 'emily' }
30
+ end
31
+
32
+ it 'prints all the values' do
33
+ expect(options.to_s).to match(original_opts[:user])
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '#inspect' do
39
+
40
+ context 'when the hash contains a sensitive key' do
41
+
42
+ let(:original_opts) do
43
+ { password: 'sensitive_data' }
44
+ end
45
+
46
+ it 'replaces the value with the redacted string' do
47
+ expect(options.inspect).not_to match(original_opts[:password])
48
+ end
49
+
50
+ it 'replaces the value with the redacted string' do
51
+ expect(options.inspect).to match(Mongo::Options::Redacted::STRING_REPLACEMENT)
52
+ end
53
+ end
54
+
55
+ context 'when the hash does not contain a sensitive key' do
56
+
57
+ let(:original_opts) do
58
+ { name: 'some_name' }
59
+ end
60
+
61
+ it 'does not replace the value with the redacted string' do
62
+ expect(options.inspect).to match(original_opts[:name])
63
+ end
64
+
65
+ it 'does not replace the value with the redacted string' do
66
+ expect(options.inspect).not_to match(Mongo::Options::Redacted::STRING_REPLACEMENT)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '#has_key?' do
72
+
73
+ context 'when the original key is a String' do
74
+
75
+ let(:original_opts) do
76
+ { 'name' => 'Emily' }
77
+ end
78
+
79
+ context 'when the method argument is a String' do
80
+
81
+ it 'returns true' do
82
+ expect(options.has_key?('name')).to be(true)
83
+ end
84
+ end
85
+
86
+ context 'when method argument is a Symbol' do
87
+
88
+ it 'returns true' do
89
+ expect(options.has_key?(:name)).to be(true)
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'when the original key is a Symbol' do
95
+
96
+ let(:original_opts) do
97
+ { name: 'Emily' }
98
+ end
99
+
100
+ context 'when the method argument is a String' do
101
+
102
+ it 'returns true' do
103
+ expect(options.has_key?('name')).to be(true)
104
+ end
105
+ end
106
+
107
+ context 'when method argument is a Symbol' do
108
+
109
+ it 'returns true' do
110
+ expect(options.has_key?(:name)).to be(true)
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'when the hash does not contain the key' do
116
+
117
+ let(:original_opts) do
118
+ { other: 'Emily' }
119
+ end
120
+
121
+ context 'when the method argument is a String' do
122
+
123
+ it 'returns false' do
124
+ expect(options.has_key?('name')).to be(false)
125
+ end
126
+ end
127
+
128
+ context 'when method argument is a Symbol' do
129
+
130
+ it 'returns false' do
131
+ expect(options.has_key?(:name)).to be(false)
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ describe '#reject' do
138
+
139
+ let(:options) do
140
+ described_class.new(a: 1, b: 2, c: 3)
141
+ end
142
+
143
+ context 'when no block is provided' do
144
+
145
+ it 'returns an enumerable' do
146
+ expect(options.reject).to be_a(Enumerator)
147
+ end
148
+ end
149
+
150
+ context 'when a block is provided' do
151
+
152
+ context 'when the block evaluates to true for some pairs' do
153
+
154
+ let(:result) do
155
+ options.reject { |k,v| k == 'a' }
156
+ end
157
+
158
+ it 'returns an object consisting of only the remaining pairs' do
159
+ expect(result).to eq(described_class.new(b: 2, c: 3))
160
+ end
161
+
162
+ it 'returns a new object' do
163
+ expect(result).not_to be(options)
164
+ end
165
+ end
166
+
167
+ context 'when the block does not evaluate to true for any pairs' do
168
+
169
+ let(:result) do
170
+ options.reject { |k,v| k == 'd' }
171
+ end
172
+
173
+ it 'returns an object with all pairs intact' do
174
+ expect(result).to eq(described_class.new(a: 1, b: 2, c: 3))
175
+ end
176
+
177
+ it 'returns a new object' do
178
+ expect(result).not_to be(options)
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ describe '#reject!' do
185
+
186
+ let(:options) do
187
+ described_class.new(a: 1, b: 2, c: 3)
188
+ end
189
+
190
+ context 'when no block is provided' do
191
+
192
+ it 'returns an enumerable' do
193
+ expect(options.reject).to be_a(Enumerator)
194
+ end
195
+ end
196
+
197
+ context 'when a block is provided' do
198
+
199
+ context 'when the block evaluates to true for some pairs' do
200
+
201
+ let(:result) do
202
+ options.reject! { |k,v| k == 'a' }
203
+ end
204
+
205
+ it 'returns an object consisting of only the remaining pairs' do
206
+ expect(result).to eq(described_class.new(b: 2, c: 3))
207
+ end
208
+
209
+ it 'returns the same object' do
210
+ expect(result).to be(options)
211
+ end
212
+ end
213
+
214
+ context 'when the block does not evaluate to true for any pairs' do
215
+
216
+ let(:result) do
217
+ options.reject! { |k,v| k == 'd' }
218
+ end
219
+
220
+ it 'returns nil' do
221
+ expect(result).to be(nil)
222
+ end
223
+ end
224
+ end
225
+ end
226
+
227
+ describe '#select' do
228
+
229
+ let(:options) do
230
+ described_class.new(a: 1, b: 2, c: 3)
231
+ end
232
+
233
+ context 'when no block is provided' do
234
+
235
+ it 'returns an enumerable' do
236
+ expect(options.reject).to be_a(Enumerator)
237
+ end
238
+ end
239
+
240
+ context 'when a block is provided' do
241
+
242
+ context 'when the block evaluates to true for some pairs' do
243
+
244
+ let(:result) do
245
+ options.select { |k,v| k == 'a' }
246
+ end
247
+
248
+ it 'returns an object consisting of those pairs' do
249
+ expect(result).to eq(described_class.new(a: 1))
250
+ end
251
+
252
+ it 'returns a new object' do
253
+ expect(result).not_to be(options)
254
+ end
255
+ end
256
+
257
+ context 'when the block does not evaluate to true for any pairs' do
258
+
259
+ let(:result) do
260
+ options.select { |k,v| k == 'd' }
261
+ end
262
+
263
+ it 'returns an object with no pairs' do
264
+ expect(result).to eq(described_class.new)
265
+ end
266
+
267
+ it 'returns a new object' do
268
+ expect(result).not_to be(options)
269
+ end
270
+ end
271
+
272
+ context 'when the object is unchanged' do
273
+
274
+ let(:options) do
275
+ described_class.new(a: 1, b: 2, c: 3)
276
+ end
277
+
278
+ let(:result) do
279
+ options.select { |k,v| ['a', 'b', 'c'].include?(k) }
280
+ end
281
+
282
+ it 'returns a new object' do
283
+ expect(result).to eq(described_class.new(a: 1, b: 2, c: 3))
284
+ end
285
+ end
286
+ end
287
+ end
288
+
289
+ describe '#select!' do
290
+
291
+ let(:options) do
292
+ described_class.new(a: 1, b: 2, c: 3)
293
+ end
294
+
295
+ context 'when no block is provided' do
296
+
297
+ it 'returns an enumerable' do
298
+ expect(options.reject).to be_a(Enumerator)
299
+ end
300
+ end
301
+
302
+ context 'when a block is provided' do
303
+
304
+ context 'when the block evaluates to true for some pairs' do
305
+
306
+ let(:result) do
307
+ options.select! { |k,v| k == 'a' }
308
+ end
309
+
310
+ it 'returns an object consisting of those pairs' do
311
+ expect(result).to eq(described_class.new(a: 1))
312
+ end
313
+
314
+ it 'returns the same object' do
315
+ expect(result).to be(options)
316
+ end
317
+ end
318
+
319
+ context 'when the block does not evaluate to true for any pairs' do
320
+
321
+ let(:result) do
322
+ options.select! { |k,v| k == 'd' }
323
+ end
324
+
325
+ it 'returns an object with no pairs' do
326
+ expect(result).to eq(described_class.new)
327
+ end
328
+
329
+ it 'returns the same object' do
330
+ expect(result).to be(options)
331
+ end
332
+ end
333
+
334
+ context 'when the object is unchanged' do
335
+
336
+ let(:options) do
337
+ described_class.new(a: 1, b: 2, c: 3)
338
+ end
339
+
340
+ let(:result) do
341
+ options.select! { |k,v| ['a', 'b', 'c'].include?(k) }
342
+ end
343
+
344
+ it 'returns nil' do
345
+ expect(result).to be(nil)
346
+ end
347
+ end
348
+ end
349
+ end
350
+ end