active_record_change_matchers 1.0.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e26db33cc55cb3efca1b3ef9824ce2e2c363636ef781f355e907afba1b68402
4
- data.tar.gz: d322588b1fd5464acf44cdd75d5593fa64325cc5690d0d69f7eb002feacfff9c
3
+ metadata.gz: ff783e18ce73bf25fcd53447eefa3062d2b0e5994d20c9766e980522d7adf663
4
+ data.tar.gz: c34bcc770bdfe89d58cbe11f0f14e2659d55cfa908ba56f624dafba3efb2c5ed
5
5
  SHA512:
6
- metadata.gz: 84e0d2efa264f21de6648b8fe8ed80591eec15376b56904115c48b0ea1123d759a1908c328736d1a4271a4b9e11cae255c67af61871167c987eb3ac4df2f5060
7
- data.tar.gz: 2095854b7ff7cfc1f26ef4e052b282af373432d5d079c192bf57d2e23b8e0a401421f958776cc82413f9c2ecca633a029b70593bd1b03e9046a662e5cfbb1550
6
+ metadata.gz: 351cf1793f1682f8b3b38e7c4768e34f93622a2c71e9bf116f817692ae7031da0456af12aadaf1aacf9f6ccb68e5d0999ed6254ff38dd51f8f2100976331bf1d
7
+ data.tar.gz: e2df1ac06efb41a1bcdd1310f681afbf526dd7feb4353d176f610fc93501938dae34451fcf523a93fcd76be397e2be4ac58f1e7339da841bfc07b6c7bcf9309a
@@ -0,0 +1,33 @@
1
+ name: Unit tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ "master" ]
6
+ pull_request:
7
+ branches: [ "master" ]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ ruby-version: ['3.3', '3.4', '4.0']
22
+
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - name: Set up Ruby
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: ${{ matrix.ruby-version }}
29
+ bundler-cache: true
30
+ - name: Prepare test database
31
+ run: bundle exec rake db:setup
32
+ - name: Run tests
33
+ run: bundle exec rspec
data/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Master (Unreleased)
4
4
 
5
+ ## 1.1.0 (2026-01-27)
6
+ - Add `create_associated(scope)` matcher: verifies creation of new record(s) within an association scope (e.g. `record.items`). Supports `with_attributes`, `which`, `and_return_it`, and `and_return_them`. Model class is inferred from the scope.
7
+ - Add `and_return_it` / `and_return_them` modifiers.
8
+ - Drop support for Rails < 7
9
+
10
+ ## 1.0.1 (2024-07-03)
11
+ - Fix broken timestamp stategy after adding the frozen time support.
12
+
5
13
  ## 1.0.0 (2024-07-03)
6
14
 
7
15
  Hard fork. Changes since the original version:
data/README.md CHANGED
@@ -1,73 +1,113 @@
1
1
  # active_record_change_matchers
2
2
 
3
- Custom RSpec matchers for ActiveRecord record creation.
4
- This is a hard-fork of [active_record_block_matchers](https://github.com/nwallace/active_record_block_matchers). See [the changelog](CHANGELOG.md) for changes since the original gem was written.
3
+ RSpec matchers that assert **exactly which** ActiveRecord records were created inside a block—by count, model, attributes, and association scope.
4
+
5
+ This is a hard fork of [active_record_block_matchers](https://github.com/nwallace/active_record_block_matchers). See [CHANGELOG](CHANGELOG.md) for changes since the original.
6
+
7
+ ---
8
+
9
+ ## Table of contents
10
+
11
+ - [Requirements](#requirements)
12
+ - [Installation](#installation)
13
+ - [Quick start](#quick-start)
14
+ - [Matcher reference](#matcher-reference)
15
+ - [Summary](#matcher-summary)
16
+ - [create_a / create_a_new](#create_a--create_a_new)
17
+ - [create / create_records](#create--create_records)
18
+ - [create_associated](#create_associated)
19
+ - [Record retrieval strategies](#record-retrieval-strategies)
20
+ - [Configuration](#configuration)
21
+ - [Tips and gotchas](#tips-and-gotchas)
22
+ - [Development](#development)
23
+ - [Contributing](#contributing)
24
+
25
+ ---
26
+
27
+ ## Requirements
28
+
29
+ - **Ruby** ≥ 3.3
30
+ - **Rails** ≥ 7 (ActiveRecord)
31
+ - **RSpec** ≥ 3 (rspec-expectations)
32
+
33
+ ---
5
34
 
6
35
  ## Installation
7
36
 
8
- Add this line to your application's Gemfile:
37
+ Add to your Gemfile:
9
38
 
10
39
  ```ruby
11
40
  gem 'active_record_change_matchers'
12
41
  ```
13
42
 
14
- And then execute:
15
-
16
- $ bundle
43
+ Then:
17
44
 
18
- Or install it yourself as:
45
+ ```bash
46
+ bundle install
47
+ ```
19
48
 
20
- $ gem install active_record_change_matchers
49
+ ---
21
50
 
22
- ## Quick Examples
51
+ ## Quick start
23
52
 
24
53
  ```ruby
25
- expect {
26
- post :create, user: { username: "bob", password: "BlueSteel45" }
27
- }.to create_a(User)
28
- .with_attributes(username: "bob")
29
- .which {|bob| expect(AuthLibrary.authenticate("bob", "BlueSteel45")).to eq bob }
54
+ # One record of a given model
55
+ expect { post :create, params: { user: { name: "Bob" } } }
56
+ .to create_a(User)
57
+ .with_attributes(name: "bob") # e.g. after downcasing in a callback
30
58
 
31
- expect {
32
- post :create, user: { username: "bob", password: "BlueSteel45" }
33
- }.to create(User => 1, Profile => 1)
59
+ # Several models, exact counts
60
+ expect { sign_up!("bob", "secret") }
61
+ .to create(User => 1, Profile => 1)
34
62
  .with_attributes(
35
- User => [{username: "bob"}],
36
- Profile => [{avatar_url: Avatar.default_avatar_url}],
37
- ).which { |new_records_hash|
38
- new_user = new_records_hash[User].first
39
- new_profile = new_records_hash[Profile].first
40
- expect(new_user.profile).to eq new_profile
63
+ User => [{ name: "bob" }],
64
+ Profile => [{ avatar_url: Profile.default_avatar_url }]
65
+ )
66
+ .which { |records|
67
+ user = records[User].first
68
+ profile = records[Profile].first
69
+ expect(user.profile).to eq profile
41
70
  }
71
+
72
+ # New records only within an association
73
+ expect { create_items }
74
+ .to create_associated(record.items => 2)
75
+ .with_attributes([{ content: "item1" }, { content: "item2" }])
42
76
  ```
43
77
 
44
- ## Detailed Examples
78
+ ---
45
79
 
46
- #### `create_a`
80
+ ## Matcher reference
47
81
 
48
- aliases: `create_an`, `create_a_new`
82
+ ### Matcher summary
49
83
 
50
- Example:
84
+ | Matcher | Aliases | Use when you want to assert… |
85
+ |----------------------|-------------------|--------------------------------------------------------|
86
+ | `create_a(Model)` | `create_an`, `create_a_new` | Exactly one new record of that model |
87
+ | `create(Model => n, …)` | `create_records` | Exact counts of new records per model |
88
+ | `create_associated(scope)` | — | New records only within that association (e.g. `user.posts`) |
51
89
 
52
- ```ruby
53
- expect { User.create! }.to create_a(User)
54
- ```
90
+ All support chaining:
55
91
 
56
- This can be very useful for controller tests:
92
+ - **`.with_attributes(...)`** attribute (or computed) expectations; works with [composable matchers](https://rspec.info/features/3-13/rspec-expectations/composing-matchers/).
93
+ - **`.which { |record_or_hash| ... }`** – extra expectations in a block (e.g. associations, side effects).
94
+ - **`.and_return_it`** / **`.and_return_them`** – that the block’s return value is the created record(s).
57
95
 
58
- ```ruby
59
- expect { post :create, user: user_params }.to create_a(User)
60
- ```
96
+ `create_a` also supports **`.which_is_expected_to(matcher)`** for a single composable matcher on the new record.
97
+
98
+ ---
99
+
100
+ ### create_a / create_a_new
101
+
102
+ Asserts the block creates **exactly one** new record of the given model. Ignores records that already existed before the block ran.
61
103
 
62
- You can chain `.with_attributes` as well to define a list of values you expect the new object to have. This works with both database attributes and computed values.
104
+ **Minimal:**
63
105
 
64
106
  ```ruby
65
- expect { User.create!(username: "bob") }
66
- .to create_a(User)
67
- .with_attributes(username: "bob")
107
+ expect { User.create! }.to create_a(User)
68
108
  ```
69
109
 
70
- This is a great way to test ActiveReocrd hooks on your model. For example, if your User model downcases all usernames before saving them to the database, you can test it like this:
110
+ **With attributes** (DB columns or any reader, e.g. from callbacks):
71
111
 
72
112
  ```ruby
73
113
  expect { User.create!(username: "BOB") }
@@ -75,7 +115,7 @@ expect { User.create!(username: "BOB") }
75
115
  .with_attributes(username: "bob")
76
116
  ```
77
117
 
78
- You can even use RSpec's [composable matchers][^1]:
118
+ **With composable matchers:**
79
119
 
80
120
  ```ruby
81
121
  expect { User.create!(username: "bob") }
@@ -83,133 +123,270 @@ expect { User.create!(username: "bob") }
83
123
  .with_attributes(username: a_string_starting_with("b"))
84
124
  ```
85
125
 
86
- If you need to make assertions about things other than attribute equality, you can also chain `.which_is_expected_to` with a (composable) matcher:
126
+ **With a matcher (`.which_is_expected_to`):**
87
127
 
88
128
  ```ruby
89
- expect { User.create!(username: "BOB", password: "BlueSteel45") }
129
+ expect { User.create!(username: "BOB", password: "secret") }
90
130
  .to create_a(User)
91
131
  .which_is_expected_to(
92
132
  have_attributes(encrypted_password: be_present)
93
- .and(eq(AuthLibrary.authenticate("bob", "BlueSteel45")))
133
+ .and(eq(Auth.authenticate("bob", "secret")))
94
134
  )
95
135
  ```
96
136
 
97
- If that's doesn't provide enough flexibility, you can also chain `.which` with a block, and your block will receive the newly created record:
137
+ **With a block (`.which`)** when you need full control:
98
138
 
99
139
  ```ruby
100
- expect { User.create!(username: "BOB", password: "BlueSteel45") }
140
+ expect { User.create!(username: "BOB", password: "secret") }
101
141
  .to create_a(User)
102
142
  .which { |user|
103
143
  expect(user.encrypted_password).to be_present
104
- expect(AuthLibrary.authenticate("bob", "BlueSteel45")).to eq user
144
+ expect(Auth.authenticate("bob", "secret")).to eq user
105
145
  }
106
146
  ```
107
147
 
108
- **Gotcha Warning:** Be careful about your block syntax when chaining `.which` in your tests. If you write the above example with a `do...end`, the example will parse like this: `expect {...}.to(create_a(User).which) do |user| ... end`, so your block will not execute, and it may appear that your test is passing, when it is not.
148
+ **That the block returns the new record (`.and_return_it`):**
149
+
150
+ ```ruby
151
+ expect { create_user(name: "bob") }
152
+ .to create_a(User)
153
+ .with_attributes(name: "bob")
154
+ .and_return_it
155
+ ```
156
+
157
+ **Negated:** use `.not_to create_a(User)` to assert the block did *not* create exactly one `User` (e.g. created zero or more than one).
158
+
159
+ **Failure cases:**
109
160
 
110
- #### `create`
161
+ - Creates 0 → *"the block should have created 1 User, but created 0"*
162
+ - Creates 2+ → *"the block should have created 1 User, but created 2"*
163
+ - Attribute mismatch → *"Expected :username to be \"bob\", but was \"BOB\""*
164
+ - `.which` or `.which_is_expected_to` fail → their messages are shown
111
165
 
112
- aliases: `create_records`
166
+ ---
113
167
 
114
- Example:
168
+ ### create / create_records
169
+
170
+ Asserts the block creates **exactly** the given counts per model. Argument is a hash: `Model => count`.
171
+
172
+ **Minimal:**
115
173
 
116
174
  ```ruby
117
175
  expect { User.create!; User.create!; Profile.create! }
118
176
  .to create(User => 2, Profile => 1)
119
177
  ```
120
178
 
121
- Just like the other matcher, you can chain `with_attributes` and `which` to assert about the particulars of the records:
179
+ **With attributes:** provide one hash per created record. Keys are model classes; values are arrays of attribute hashes. Order of hashes need not match creation order.
122
180
 
123
181
  ```ruby
124
- expect { UserService.sign_up!(username: "bob", password: "BlueSteel45") }
125
- .to create(User => 1, Profile => 1)
182
+ expect { User.create!(username: "bob"); User.create!(username: "rhonda") }
183
+ .to create(User => 2)
126
184
  .with_attributes(
127
- User => [{username: "bob"}],
128
- Profile => [{avatar_url: Avatar.default_avatar_url}]
129
- ).which { |records|
130
- # records is a hash with model classes for keys and the new records for values
131
- new_user = records[User].first
132
- new_profile = records[Profile].first
133
- expect(AuthLibrary.authenticate("bob", "BlueSteel45")).to eq new_user
134
- expect(new_user.profile).to eq new_profile
135
- }
185
+ User => [{ username: "rhonda" }, { username: "bob" }]
186
+ )
136
187
  ```
137
188
 
138
- As noted, the `which` block yields a hash containing the new records whose counts were specified.
189
+ You must supply **as many attribute hashes as the expected count** for that model. Fewer raises an argument error; you can use empty hashes for records you don’t care to constrain:
139
190
 
140
- Order doesn't matter for the attributes specified in `with_attributes`, but you must provide an attribute hash for every record that was created. This means, if you expect the block to create, say 2 User records, you must provide an attributes hash for each new User record:
191
+ ```ruby
192
+ .with_attributes(User => [{ username: "bob" }, {}])
193
+ ```
194
+
195
+ **With a block (`.which`):** the block receives a hash `Model => [records]`:
141
196
 
142
197
  ```ruby
143
- # This is correct:
144
- expect { User.create!(username: "bob"); User.create!(username: "rhonda") }
145
- .to create(User => 2)
198
+ expect { sign_up!("bob", "secret") }
199
+ .to create(User => 1, Profile => 1)
146
200
  .with_attributes(
147
- User => [{username: "rhonda"}, {username: "bob"}]
201
+ User => [{ username: "bob" }],
202
+ Profile => [{ avatar_url: Profile.default_avatar_url }]
148
203
  )
204
+ .which { |records|
205
+ user = records[User].first
206
+ profile = records[Profile].first
207
+ expect(user.profile).to eq profile
208
+ }
209
+ ```
149
210
 
150
- # This will raise an error:
151
- expect { User.create!(username: "bob"); User.create!(username: "rhonda") }
152
- .to create(User => 2)
153
- .with_attributes(
154
- User => [{username: "rhonda"}]
155
- )
211
+ **That the block returns all created records (`.and_return_them`):** the matcher checks that every created record appears in the block’s return value (array, relation, or any enumerable).
156
212
 
157
- # But this is totally fine if you really need a workaround:
158
- # Just put the empty hashes last
159
- expect { User.create!(username: "bob"); User.create!(username: "rhonda") }
160
- .to create(User => 2)
213
+ ```ruby
214
+ expect { [User.create!, User.create!] }.to create(User => 2).and_return_them
215
+ ```
216
+
217
+ **Negated:** `.not_to create(User => 2)` asserts the block did not create exactly two `User`s.
218
+
219
+ ---
220
+
221
+ ### create_associated
222
+
223
+ Asserts that new record(s) were created **within the given association scope(s)** only. The model is inferred from the scope (e.g. `user.posts` → `Post`). Other associations and pre-existing records are ignored.
224
+
225
+ **Scope form (expects exactly one new record in that association):**
226
+
227
+ ```ruby
228
+ expect { user.posts.create!(title: "Hi") }.to create_associated(user.posts)
229
+ ```
230
+
231
+ **Hash form (expects the given count per scope):**
232
+
233
+ ```ruby
234
+ expect {
235
+ user.posts.create!(title: "A")
236
+ user.posts.create!(title: "B")
237
+ }.to create_associated(user.posts => 2)
238
+ ```
239
+
240
+ **With attributes**
241
+
242
+ - One scope, one record: pass a single hash.
243
+ - One scope, many records: pass an array of hashes.
244
+ - Multiple scopes: pass a hash keyed by scope, each value an array of attribute hashes.
245
+
246
+ ```ruby
247
+ # One record, single hash
248
+ expect { user.posts.create!(title: "Hi") }
249
+ .to create_associated(user.posts)
250
+ .with_attributes(title: "Hi")
251
+
252
+ # One scope, multiple records
253
+ expect { add_two_posts }
254
+ .to create_associated(user.posts => 2)
255
+ .with_attributes([{ title: "First" }, { title: "Second" }])
256
+
257
+ # Multiple scopes
258
+ expect { create_mine_and_theirs }
259
+ .to create_associated(user_a.posts => 1, user_b.posts => 1)
161
260
  .with_attributes(
162
- User => [{username: "rhonda"}, {}]
261
+ user_a.posts => [{ title: "a" }],
262
+ user_b.posts => [{ title: "b" }]
163
263
  )
164
264
  ```
165
265
 
166
- ## Record Retrieval Strategies
266
+ **With `.which`:** the block receives a hash **model class => records** (same shape as `create` / `create_records`):
267
+
268
+ ```ruby
269
+ expect { user.posts.create!(title: "x") }
270
+ .to create_associated(user.posts)
271
+ .which { |records_by_klass|
272
+ expect(records_by_klass[Post].first.title).to eq "x"
273
+ }
274
+ ```
275
+
276
+ **Return value:**
277
+
278
+ - Use **`.and_return_it`** only when expecting **exactly one** record (single scope, count 1). It asserts the block returns that record.
279
+ - Use **`.and_return_them`** when expecting multiple records; it asserts the block’s return value contains all created records.
280
+
281
+ Using `.and_return_it` with multiple records (e.g. `create_associated(scope => 2).and_return_it`) raises `ArgumentError`.
167
282
 
168
- There are currently two retrieval strategies implemented: `:id` and `:timestamp`. `:id` is the default, but this can be configured via the `default_strategy` configuration variable (more details [below](#configuration)).
283
+ **Failure cases:**
169
284
 
170
- The ID and Timestamp Strategies work similarly. The ID Strategy queries the appropriate table(s) to find the highest ID value(s) before the block, then finds new records by looking for records with an ID that higher than that. The Timestamp Strategy uses `Time.current` to record the time before the block. Then it finds new records by looking for records that have a timestamp later than that.
285
+ - No records in scope *"The block should have created 1 Post within the scope, but created 0."*
286
+ - Records created in a *different* association (or by another owner) are not counted—you’ll get “created 0” if the wrong scope was used.
287
+ - Wrong count or attribute mismatch produces messages similar to `create` / `create_records`.
171
288
 
172
- The ID Strategy is the default because it doesn't rely on time values that may be imprecise or mocked out. The Timestamp Strategy is useful if your tables don't have autoincrementing integer primary keys.
289
+ ---
290
+
291
+ ## Record retrieval strategies
292
+
293
+ The matchers need to know which rows were “new” after the block. Two strategies are built in:
294
+
295
+ | Strategy | How it finds new records | Default | When to use it |
296
+ |-------------|--------------------------|----------|-----------------|
297
+ | **`:id`** | Compares max primary key before/after the block | ✓ | Tables with auto-increment integer PKs (default). |
298
+ | **`:timestamp`** | Compares `created_at` (or configured column) before/after; supports frozen time | — | Non-integer PKs or no `id`. |
299
+
300
+ **`:id`** is the default because it doesn’t depend on clock precision or time mocking. Use **`:timestamp`** when you don’t have a monotonic `id` (e.g. UUIDs, legacy schemas).
301
+
302
+ Strategy can be set globally in [configuration](#configuration) or overridden per expectation:
303
+
304
+ ```ruby
305
+ expect { Person.create! }.to create_a(Person, strategy: :timestamp)
306
+ ```
307
+
308
+ `create_associated` uses the configured default strategy only (it has no per-call strategy option).
309
+
310
+ ---
173
311
 
174
312
  ## Configuration
175
313
 
176
- You can configure the column names used by the ID or Timestamp Strategies. Put code like this in your `spec_helper.rb` or similar file:
314
+ Configure column names and default strategy in your RSpec setup (e.g. `spec/rails_helper.rb` or `spec_helper.rb`):
177
315
 
178
316
  ```ruby
179
317
  ActiveRecordChangeMatchers::Config.configure do |config|
180
-
181
- # default value is "id"
318
+ # Primary key column for :id strategy (default: "id")
182
319
  config.id_column_name = "primary_key"
183
320
 
184
- # default value is "created_at"
321
+ # Timestamp column for :timestamp strategy (default: "created_at")
185
322
  config.created_at_column_name = "created_timestamp"
186
323
 
187
- # default value is :id
188
- # must be one of [:id, :timestamp]
324
+ # Default strategy: :id or :timestamp (default: :id)
189
325
  config.default_strategy = :timestamp
190
326
  end
191
327
  ```
192
328
 
193
- You can also override the default strategy for individual assertions if needed:
329
+ ---
330
+
331
+ ## Tips and gotchas
332
+
333
+ **Block syntax with `.which`**
334
+
335
+ Use braces `{ }` for the block passed to `.which`. With `do ... end`, Ruby binds the block to `expect(...).to(...)` instead of `.which`, so the block may never run and the test can falsely pass:
194
336
 
195
337
  ```ruby
196
- expect { Person.create! }.to create_a(Person, strategy: :id)
338
+ # Prefer:
339
+ .to create_a(User).which { |user| expect(user.name).to eq "bob" }
340
+
341
+ # Parsing trap with do/end:
342
+ .to create_a(User).which do |user|
343
+ expect(user.name).to eq "bob" # this block is not passed to .which
344
+ end
345
+ ```
346
+
347
+ **Composable matchers**
348
+
349
+ `with_attributes` accepts RSpec composable matchers, which keeps specs readable and failure messages clear:
350
+
351
+ ```ruby
352
+ .with_attributes(
353
+ username: a_string_matching(/\A[a-z]+\z/),
354
+ age: be_between(18, 120)
355
+ )
197
356
  ```
198
357
 
358
+ **Attributes and virtual/derived values**
359
+
360
+ `with_attributes` uses `record.public_send(field)` for each key, so you can assert on any public reader—database columns, delegations, or methods (e.g. `full_name` built from `first_name` and `last_name`).
361
+
362
+ ---
199
363
 
200
364
  ## Development
201
365
 
202
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
366
+ ```bash
367
+ git clone https://github.com/Darhazer/active_record_change_matchers
368
+ cd active_record_change_matchers
369
+ bin/setup
370
+ bundle exec rspec
371
+ ```
372
+
373
+ To install the gem locally:
374
+
375
+ ```bash
376
+ bundle exec rake install
377
+ ```
203
378
 
204
- To install this gem onto your local machine, run `bundle exec rake install`.
379
+ ---
205
380
 
206
381
  ## Contributing
207
382
 
208
- 1. Fork it ( https://github.com/[my-github-username]/active_record_change_matchers/fork )
209
- 2. Create your feature branch (`git checkout -b my-new-feature`)
210
- 3. Commit your changes (`git commit -am 'Add some feature'`)
211
- 4. Push to the branch (`git push origin my-new-feature`)
212
- 5. Create a new Pull Request
383
+ 1. Fork the repo.
384
+ 2. Create a feature branch: `git checkout -b my-feature`
385
+ 3. Commit changes: `git commit -am 'Add my feature'`
386
+ 4. Push: `git push origin my-feature`
387
+ 5. Open a Pull Request against this repository.
213
388
 
389
+ ---
214
390
 
215
- [^1]: https://rspec.info/features/3-13/rspec-expectations/composing-matchers/
391
+ **License:** MIT.
392
+ **Changelog:** [CHANGELOG.md](CHANGELOG.md).
data/Rakefile CHANGED
@@ -8,9 +8,3 @@ RSpec::Core::RakeTask.new(:spec) do |t|
8
8
  t.pattern = Dir.glob('spec/**/*_spec.rb')
9
9
  t.rspec_opts = '--format documentation'
10
10
  end
11
-
12
- task :travis do
13
- Rake::Task['db:setup'].invoke
14
- Rake::Task[:spec].invoke
15
- end
16
-
@@ -1,33 +1,32 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "active_record_change_matchers/version"
3
+ require 'active_record_change_matchers/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "active_record_change_matchers"
6
+ spec.name = 'active_record_change_matchers'
8
7
  spec.version = ActiveRecordChangeMatchers::VERSION
9
- spec.authors = ["Maxim Krizhanovski", "Nathan Wallace"]
10
- spec.email = ["maxim.krizhanovski@hey.com"]
8
+ spec.authors = ['Maxim Krizhanovski', 'Nathan Wallace']
9
+ spec.email = ['maxim.krizhanovski@hey.com']
11
10
 
12
- spec.summary = %q{Additional RSpec custom matchers for ActiveRecord}
13
- spec.description = %q{This gem adds custom block expectation matchers for RSpec, such as `expect { ... }.to create_a_new(User)`}
14
- spec.homepage = "https://github.com/Darhazer/active_record_change_matchers"
15
- spec.license = "MIT"
11
+ spec.summary = 'Additional RSpec custom matchers for ActiveRecord'
12
+ spec.description = 'This gem adds custom block expectation matchers for RSpec, such as `expect { ... }.to create_a_new(User)`'
13
+ spec.homepage = 'https://github.com/Darhazer/active_record_change_matchers'
14
+ spec.license = 'MIT'
16
15
 
17
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- spec.bindir = "exe"
17
+ spec.bindir = 'exe'
19
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
- spec.require_paths = ["lib"]
21
- spec.required_ruby_version = ">= 1.9.3"
19
+ spec.require_paths = ['lib']
20
+ spec.required_ruby_version = '>= 3.3.0'
22
21
 
23
- spec.add_dependency "activerecord", ">= 3.2.0"
24
- spec.add_dependency "rspec-expectations", ">= 3.0.0"
22
+ spec.add_dependency 'activerecord', '>= 7.0'
23
+ spec.add_dependency 'rspec-expectations', '>= 3.0.0'
25
24
 
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec", "~> 3.6"
28
- spec.add_development_dependency "pry", "~> 0.10"
29
- spec.add_development_dependency "sqlite3", "~> 1.3"
30
- spec.add_development_dependency "database_cleaner", "~> 1.6"
31
- spec.add_development_dependency "standalone_migrations", "~> 5.2"
32
- spec.add_development_dependency "timecop", "~> 0.9"
25
+ spec.add_development_dependency 'database_cleaner'
26
+ spec.add_development_dependency 'pry'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec'
29
+ spec.add_development_dependency 'sqlite3'
30
+ spec.add_development_dependency 'standalone_migrations'
31
+ spec.add_development_dependency 'timecop'
33
32
  end
@@ -1,4 +1,4 @@
1
- class CreatePeople < ActiveRecord::Migration
1
+ class CreatePeople < ActiveRecord::Migration[6.0]
2
2
  def change
3
3
  create_table :people do |t|
4
4
  t.string :first_name
@@ -1,4 +1,4 @@
1
- class CreateDogs < ActiveRecord::Migration
1
+ class CreateDogs < ActiveRecord::Migration[6.0]
2
2
  def change
3
3
  create_table :dogs do |t|
4
4
  t.string :name
@@ -0,0 +1,9 @@
1
+ class CreatePets < ActiveRecord::Migration[6.0]
2
+ def change
3
+ create_table :pets do |t|
4
+ t.references :person, null: false, foreign_key: true
5
+ t.string :name
6
+ t.timestamps
7
+ end
8
+ end
9
+ end