mongo 2.1.0.rc0 → 2.1.0

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.
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