sequel-audited 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c52f472b39ee0ab66ec77534cd6d7ce8da5a3742
4
+ data.tar.gz: 9d9608ea1ffe32bae666fb861245abeab665fedb
5
+ SHA512:
6
+ metadata.gz: 7241c36c7c392410411f6ee8ded9fc5dd0009d43f65661b040f628705e9509b2a9ec5dff2358f55477894b2d93daa5e0ed87dda467b0b7f4401bebb6e5f6590e
7
+ data.tar.gz: 9bbf1561eab29675294e993ce76468b02da609683cae5fba4864ce5fa28d1d9b6bfcc48b1fc4ad6b837c2600232aa4f3e44fee2f645127515b30effc5f888174
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ spec/sequel-audited-test.db
11
+ .env.test
12
+ rubocop
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at kematzy@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sequel-audited.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Kematzy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,659 @@
1
+ # Sequel::Audited
2
+
3
+ **sequel-audited** is a [Sequel](http://sequel.jeremyevans.net/) plugin that logs changes made to any
4
+ audited model, including who created, updated and destroyed the record, and what was changed
5
+ and when the change was made.
6
+
7
+ This plugin provides model auditing (a.k.a: record versioning) for DB scenarios when DB triggers
8
+ are not possible. (ie: on a web app on Heroku).
9
+
10
+
11
+
12
+ ## Disclaimer
13
+
14
+ This is still **work-in-progress**, and is therefore **NOT production ready**, so **use with care**
15
+ and test thoroughly before depending upon this gem for mission-critical stuff!
16
+ You have been warned! No warranties and guarantees expressed or implied!
17
+
18
+ <br>
19
+
20
+ Having said that, the code base has 100% code coverage and I believe all significant tests pass.
21
+
22
+ <br>
23
+
24
+ ### Version 0.2.x
25
+
26
+ Version 0.2.x have various breaking changes and makes even more assumptions based upon my usage scenario.
27
+ So your milage may vary.
28
+
29
+
30
+ ----
31
+
32
+ <br>
33
+
34
+ ## Installation
35
+
36
+ ### 1) Install the gem
37
+
38
+ Add this line to your app's Gemfile:
39
+
40
+
41
+ ```ruby
42
+ gem "sequel-audited"
43
+ ```
44
+
45
+ And then execute:
46
+
47
+ ```bash
48
+ $ bundle
49
+ ```
50
+
51
+ Or install it yourself as:
52
+
53
+ ```bash
54
+ $ gem install sequel-audited
55
+ ```
56
+
57
+
58
+ ### 2) Generate Migration
59
+
60
+ In your apps Rakefile add the following:
61
+
62
+ ```ruby
63
+ load "tasks/sequel-audited/migrate.rake"
64
+ ```
65
+
66
+ Then verify that the Rake task is available by calling:
67
+
68
+ ```bash
69
+ bundle exec rake -T
70
+ ```
71
+
72
+ which should output something like this:
73
+
74
+ ```bash
75
+ ....
76
+ rake audited:add_migration # Installs Sequel::Audited migration, but does not run it.
77
+ ....
78
+ ```
79
+
80
+ Run the sequel-audit rake task:
81
+
82
+ ```bash
83
+ bundle exec rake audited:add_migration
84
+ ```
85
+ After this you can comment out the rake task in your Rakefile until you need to update. And then
86
+ finally run db:migrate to update your DB.
87
+
88
+ ```bash
89
+ bundle exec rake db:migrate
90
+ ```
91
+
92
+
93
+ ### 3) Add the `:uuid` plugin
94
+
95
+ You need to add the `:uuid` plugin to models as follows:
96
+
97
+ ```ruby
98
+ class YourModel < Sequel::Model
99
+ # convert the :id primary key to a unique UUID token, for greater record security
100
+ plugin(:uuid, field: :id)
101
+ end
102
+ ```
103
+
104
+ ...and change the `primary_key :id`, column to a `:uuid` formatted column in your model migrations.
105
+
106
+ ```ruby
107
+ ...
108
+ create_table(:your_model) do
109
+ primary_key :id, :uuid
110
+ ...
111
+ end
112
+ ```
113
+
114
+ **SideNote**: I'm using `:uuid` keys here for safer tracking of model records and to circumvent any primary key issues due to `integer` or `string` keys and wrong casting of those within the DB.
115
+
116
+ <br>
117
+
118
+
119
+ ### 4) Add `:pg_json_ops` and ``pg_json`` extensions
120
+
121
+ You need to add the `:pg_json` extension to support JSON formatted content before instantiation the DB connection:
122
+
123
+ ```ruby
124
+ # add PG JSON OPS extension. NOTE! before the DB.connect call
125
+ Sequel.extension(:pg_json_ops)
126
+ ```
127
+ and the `:pg_json` extension after the DB connection call.
128
+
129
+ ```ruby
130
+ # add PG JSON extensions NOTE! after the DB.connect call.
131
+ DB.extension :pg_json
132
+ ```
133
+
134
+ <br>
135
+
136
+ ### IMPORTANT SIDENOTE!
137
+
138
+ If you are using PostgreSQL as your database, then it's a good idea to convert the the `changed`
139
+ column to the `JSON` type for automatic translations into a Ruby hash.
140
+
141
+ Otherwise, you have to use `JSON.parse(@v.changed)` to convert it to a hash if and when you want
142
+ to use it.
143
+
144
+ <br>
145
+
146
+ ------
147
+
148
+
149
+ ## Usage
150
+
151
+
152
+ Using this plugin is fairly simple and straight-forward. Just add it to the individual models you wish to
153
+ have audits (versions) for.
154
+
155
+ ```ruby
156
+ # auditing single model
157
+ class Post < Sequel::Model
158
+ plugin(:audited)
159
+ end
160
+ ```
161
+
162
+ ### GOTCHA!!
163
+
164
+ Do NOT add the plugin globally to all models, as things will likely not work properly.
165
+
166
+ ```ruby
167
+ # auditing all models. VERY BAD INDEED!! DO NOT DO!
168
+ Sequel::Model.plugin :audited
169
+ ```
170
+
171
+
172
+ By default this will audit / version all columns on the model, **except** the default ignored columns configured in `Sequel::Audited.audited_default_ignored_columns` (see [Configuration Options](#configuration-options) below).
173
+
174
+ <br>
175
+
176
+ #### Basic usage => `plugin(:audited)`
177
+
178
+ ```ruby
179
+ # Given a Post model with these columns:
180
+ [:id, :category_id, :title, :body, :author_id, :created_at, :updated_at]
181
+
182
+ # Auditing all columns*
183
+ Post.plugin :audited
184
+
185
+ #=> [:id, :category_id, :title, :body, :author_id] # audited columns
186
+ #=> [:created_at, :updated_at] # ignored columns
187
+
188
+ ```
189
+ <br>
190
+
191
+ #### Advanced Usage => `plugin(:audited, :only => [...])`
192
+
193
+ ```ruby
194
+ # Auditing a Single column
195
+
196
+ Post.plugin(:audited, only: :title)
197
+
198
+ #=> [:title] # audited columns
199
+ #=> [:id, :category_id, :body, :author_id, :created_at, :updated_at] # ignored columns
200
+
201
+
202
+ # Auditing Multiple columns
203
+
204
+ Post.plugin(:audited, only: [:title, :body])
205
+ #=> [:title, :body] # audited columns
206
+ #=> [:id, :category_id, :author_id, :created_at, :updated_at] # ignored columns
207
+
208
+ ```
209
+ <br>
210
+
211
+ #### Advanced Usage => `plugin(:audited, :except => [...])`
212
+
213
+ **NOTE!** this option does NOT ignore the default ignored columns, so use with care.
214
+
215
+ ```ruby
216
+ # Auditing all columns except specified columns
217
+
218
+ Post.plugin(:audited, except: :title)
219
+
220
+ #=> [:id, :category_id, :author_id, :created_at, :updated_at] # audited columns
221
+ #=> [:title] # ignored columns
222
+
223
+
224
+ Post.plugin(:audited, except: [:title, :author_id])
225
+
226
+ #=> [:id, :category_id, :created_at, :updated_at] # audited columns
227
+ #=> [:title, :author_id] # ignored columns
228
+
229
+ ```
230
+ <br>
231
+
232
+ ---
233
+
234
+ <br>
235
+
236
+
237
+ ## How it works
238
+
239
+ You have to look behind the curtain to see what this plugin actually does.
240
+
241
+ In a new clean DB...
242
+
243
+ ### 1) Create
244
+
245
+ When you create a new record like this:
246
+
247
+ ```ruby
248
+ Category.create(name: 'Sequel')
249
+ #<Category @values={
250
+ :id => 1,
251
+ :name => "Sequel",
252
+ :position => 1,
253
+ :created_at => <timestamp>,
254
+ :updated_at => nil
255
+ }>
256
+
257
+ # in the background a new row in DB[:audit_logs] has been added with the following info:
258
+
259
+ #<AuditLog @values={
260
+ :id => 1,
261
+ :item_type => "Category",
262
+ :item_uuid => <UUID>,
263
+ :event => "create",
264
+ # NOTE! all model values are stored by default on new records.
265
+ :changed => "{\"id\":1,\"name\":\"Sequel\",\"created_at\":\"<timestamp>\"}",
266
+ :version => 1,
267
+ :user_id => <uuid>,
268
+ :username => "joeblogs",
269
+ :user_type => "User",
270
+ :created_at => <timestamp>
271
+ }>
272
+ ```
273
+
274
+ ### 2) Updates
275
+
276
+ When you update a record like this:
277
+
278
+ ```ruby
279
+ cat = Category.first
280
+ cat.update(name: 'Ruby Sequel')
281
+ #<Category @values={
282
+ :id => 1,
283
+ :name => "Ruby Sequel",
284
+ :position => 1,
285
+ :created_at => <timestamp>,
286
+ :updated_at => <timestamp>
287
+ }>
288
+
289
+ # in the background a new row in DB[:audit_logs] has been added with the following info:
290
+
291
+ #<AuditLog @values={
292
+ :id => 2,
293
+ :item_type => "Category",
294
+ :item_uuid => <uuid>,
295
+ :event => "update",
296
+ # NOTE! only the changes are stored
297
+ :changed => "{\"name\":[\"Sequel\",\"Ruby Sequel\"]}",
298
+ :version => 2,
299
+ :user_id => <uuid>,
300
+ :username => "joeblogs",
301
+ :user_type => "User",
302
+ :created_at => <timestamp>
303
+ }>
304
+ ```
305
+
306
+
307
+ ### 3) Destroys (Deletes)
308
+
309
+ When you delete a record like this:
310
+
311
+ ```ruby
312
+ cat = Category.first
313
+ cat.delete
314
+
315
+ # in the background a new row in DB[:audit_logs] is added with the info:
316
+
317
+ #<AuditLog @values={
318
+ :id => 3,
319
+ :item_type => "Category",
320
+ :item_uuid => <uuid>,
321
+ :event => "destroy",
322
+ # NOTE! all model values are stored by default on deleted records
323
+ :changed => "{\"id\":1,\"name\":\"Ruby Sequel\",\"created_at\":\"<timestamp>\",\"updated_at\":\"<timestamp>\"}",
324
+ :version => 3,
325
+ :user_id => <uuid>,
326
+ :username => "joeblogs",
327
+ :user_type => "User",
328
+ :created_at => <timestamp>
329
+ }>
330
+ ```
331
+
332
+
333
+ This way you can **easily track what was created, changed or deleted** and **who did it** and **when they did it**.
334
+
335
+ <br>
336
+
337
+ ---
338
+
339
+ <br>
340
+
341
+
342
+ ## Configuration Options
343
+
344
+
345
+ **sequel-audited** supports two forms of configurations:
346
+
347
+ ### A) Global configuration options
348
+
349
+ #### `Sequel::Audited.audited_current_user_method`
350
+
351
+ Sets the name of the global method that provides the current user object.
352
+ Default is: `:current_user`.
353
+
354
+ You can easily change the name of this method by calling:
355
+
356
+ ```ruby
357
+ Sequel::Audited.audited_current_user_method = :audited_user
358
+ ```
359
+
360
+ **NOTE!** the name of the function must be given as a symbol.
361
+
362
+ <br>
363
+
364
+ #### `Sequel::Audited.audited_model_name`
365
+
366
+ Enables adding your own Audit model. Default is: `:AuditLog`
367
+
368
+ ```ruby
369
+ Sequel::Audited.audited_model_name = :YourCustomModel
370
+ ```
371
+ **NOTE!** the name of the model must be given as a symbol.
372
+
373
+ <br>
374
+
375
+ #### `Sequel::Audited.audited_enabled`
376
+
377
+ Toggle for enabling / disabling auditing throughout all audited models.
378
+ Default is: `true` i.e: enabled.
379
+
380
+ <br>
381
+
382
+
383
+ #### `Sequel::Audited.audited_default_ignored_columns`
384
+
385
+ An array of columns that are ignored by default. Default value is:
386
+
387
+ ```ruby
388
+ [:lock_version, :created_at, :updated_at, :created_on, :updated_on]
389
+ ```
390
+ **NOTE!** `:timestamps` related columns must be ignored or you may end up with situation
391
+ where an update triggers multiple copies of the record in the audit log.
392
+
393
+ <br>
394
+
395
+
396
+ ```ruby
397
+ # NOTE! array values must be given as symbols.
398
+ Sequel::Audited.audited_default_ignored_columns = [:id, :mycolumn, ...]
399
+ ```
400
+
401
+ <br>
402
+
403
+ ### B) Per Audited Model configurations
404
+
405
+ You can also set these settings on a per model setting by passing the following options:
406
+
407
+ #### `:user_method => :something`
408
+
409
+ This option will use a different method for the current user within this model only.
410
+
411
+ Example:
412
+
413
+ ```ruby
414
+ # if you have a global method like
415
+ def current_client
416
+ @current_client ||= Client[session[:client_id]]
417
+ end
418
+
419
+ # and set
420
+ ClientProfile.plugin(:audited, :user_method => :current_client)
421
+
422
+ # then the user info will be taken from DB[:clients].
423
+ #<Client @values={:username=>"happyclient"... }>
424
+
425
+ ```
426
+
427
+ **NOTE!** the current user model must respond to `:id` and `:username` attributes.
428
+
429
+ <br>
430
+
431
+ #### `:default_ignored_columns => [...]`
432
+
433
+ This option allows you to set custom default ignored columns in the audited model. It's basically
434
+ just an option *just-in-case*, but it's probably better to use the `:only => []` or `:except => []`
435
+ options instead (see [Usage](#usage) above).
436
+
437
+ <br>
438
+
439
+ ----
440
+
441
+ <br>
442
+
443
+
444
+
445
+ ## Class Methods
446
+
447
+ You can easily track all changes made to a model / row / field(s) like this:
448
+
449
+
450
+ ### `#.audited_version?`
451
+
452
+ ```ruby
453
+ # check if model have any audits (only works on audited models)
454
+ Post.audited_versions?
455
+ #=> returns true / false if any audits have been made
456
+ ```
457
+
458
+ ### `#.audited_version([conditions])`
459
+
460
+ ```ruby
461
+ # grab all audits for a particular model. Returns an array.
462
+ Post.audited_versions
463
+ #=> [
464
+ { id: 1, item_type: 'Post', item_uuid: '<uuid>', version: 1,
465
+ event: 'create', changed: "{JSON SERIALIZED OBJECT}",
466
+ user_id: <uuid>, username: "joeblogs", created_at: <timestamp>
467
+ },
468
+ {...}
469
+ ]
470
+
471
+
472
+ # filtered by uuid key value
473
+ Posts.audited_versions(item_uuid: <uuid>)
474
+
475
+ # filtered by user :id or :username value
476
+ Posts.audited_versions(user_id: user.id)
477
+ Posts.audited_versions(username: "joeblogs")
478
+
479
+ # filtered to last two (2) days only
480
+ Posts.audited_versions(:created_at < Date.today - 2)
481
+
482
+ ```
483
+
484
+
485
+
486
+ 2) Track all changes made by a user / user_group.
487
+
488
+ ```ruby
489
+ joe = User[username: "joe"]
490
+
491
+ joe.audited_versions
492
+ #=> returns all audits made by joe
493
+ ['SELECT * FROM `audit_logs` WHERE username = "joe" ORDER BY created_at DESC']
494
+
495
+ joe.audited_versions(:item_type => Post)
496
+ #=> returns all audits made by joe on the Post model
497
+ ['SELECT * FROM `audit_logs` WHERE username = "joe" AND item_type = 'Post' ORDER BY created_at DESC']
498
+ ```
499
+
500
+
501
+
502
+ ## Instance Methods
503
+
504
+ When you call `.plugin(:audited)` in your model, you get these methods:
505
+
506
+
507
+ ### `.versions`
508
+
509
+ ```ruby
510
+ class Post < Sequel::Model
511
+ plugin(:audited)
512
+ end
513
+
514
+ # Returns this post's versions.
515
+ post.versions #=> [<array of versions>]
516
+ ```
517
+
518
+ <br>
519
+
520
+ ### `.blame`
521
+ -- aliased as: `.last_audited_by`
522
+
523
+ ```ruby
524
+ # Returns the username of the user who last changed the record
525
+ post.blame
526
+ post.last_audited_by #=> 'joeblogs'
527
+ ```
528
+
529
+ <br>
530
+
531
+
532
+ ### `.last_audited_at`
533
+ -- aliased as: `.last_audited_on`
534
+
535
+ ```ruby
536
+ # Returns the timestamp last changed the record
537
+ post.last_audited_at
538
+ post.last_audited_on #=> <timestamp>
539
+ ```
540
+
541
+ <br>
542
+
543
+ ### Features and functionality to be implemented
544
+
545
+ Please help out if you would want this sooner than me ;-)
546
+
547
+ ```ruby
548
+ # Returns the post (not a version) as it looked at around the the given timestamp.
549
+ post.version_at(timestamp)
550
+
551
+ # Returns the objects (not Versions) as they were between the given times.
552
+ post.versions_between(start_time, end_time)
553
+
554
+ # Returns the post (not a version) as it was most recently.
555
+ post.previous_version
556
+
557
+ # Returns the post (not a version) as it became next.
558
+ post.next_version
559
+
560
+
561
+ # Temporarily turn Audited on for all posts.
562
+ post.audited_on!
563
+
564
+ # Temporarily turn Audited off for all posts.
565
+ post.audited_off!
566
+ ```
567
+
568
+
569
+
570
+ <br>
571
+
572
+ ----
573
+
574
+ <br>
575
+
576
+
577
+ ## TODO's
578
+
579
+ Not everything is perfect or fully formed, so this gem may be in need of the following:
580
+
581
+ * It needs some **stress testing** and **THREADS support & testing**. Does the gem work in all
582
+ situations / instances?
583
+
584
+ I really would appreciate the wisdom of someone with a good understanding of these type of
585
+ things. Please help me ensure it's working great at all times.
586
+
587
+
588
+ * It could probably be cleaned up and made more efficient by a much better programmer than me.
589
+ Please feel free to provide some suggestions or pull-requests.
590
+
591
+
592
+ * Solid **testing and support for more DB's, other than PostgreSQL** currently tested
593
+ against. Not a priority as I currently have no such requirements. Please feel free to
594
+ submit a pull-request.
595
+
596
+ * Testing for use with Rails, Sinatra or other Ruby frameworks. I don't see much issues here, but
597
+ I'm NOT bothered to do this testing as [Roda](http://roda.jeremyevans.net/) is my preferred
598
+ Ruby framework. Please feel free to submit a pull-request.
599
+
600
+ * Support for `:on => [:create, :update]` option to limit auditing to only some actions. Not sure
601
+ if this is really worthwhile, but could be added as a feature. Please feel free to submit a
602
+ pull-request.
603
+
604
+ * Support for sweeping (compacting) old updates if there are too many. Not sure how to handle this.
605
+ Suggestions and ideas are most welcome.
606
+
607
+ I think a simple cron job could extract all records with `event: 'update'` older than a specific
608
+ time period (3 - 6 months) and dump them into something else, instead of adding this feature.
609
+
610
+ If you are running this on a free app on Heroku, with many and frequent updates, you might want
611
+ to pay attention to this functionality as there's a 10,000 rows limit on Heroku.
612
+
613
+
614
+
615
+
616
+ ## Development
617
+
618
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run
619
+ the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
620
+
621
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
622
+ update the version number in `version.rb`, and then run `bundle exec rake release`, which will create
623
+ a git tag for the version, push git commits and tags, and push the `.gem` file to
624
+ [rubygems.org](https://rubygems.org).
625
+
626
+
627
+
628
+ ## Contributing
629
+
630
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kematzy/sequel-audited.
631
+
632
+ Please run `bundle exec rake coverage` and `bundle exec rake rubocop` on your code before you
633
+ send a pull-request.
634
+
635
+
636
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are
637
+ expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
638
+
639
+
640
+ ## License
641
+
642
+ &copy; Copyright Kematzy, 2015 - 2016
643
+ &copy; Copyright [Daniel Goh, 2017](https://github.com/tohchye)
644
+
645
+ Heavily inspired by:
646
+
647
+ * the [sequel](https://github.com/jeremyevans/sequel) gem by Jeremy Evans and many others released
648
+ under the MIT license.
649
+
650
+ * the [audited](https://github.com/collectiveidea/audited) gem by Brandon Keepers, Kenneth Kalmer,
651
+ Daniel Morrison, Brian Ryckbost, Steve Richert & Ryan Glover released under the MIT licence.
652
+
653
+ * the [paper_trail](https://github.com/airblade/paper_trail) gem by Andy Stewart & Ben Atkins
654
+ released under the MIT license.
655
+
656
+
657
+ The gem is available as open source under the terms of the
658
+ [MIT License](http://opensource.org/licenses/MIT).
659
+