has_changelogs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +81 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/has_changelogs.gemspec +38 -0
- data/lib/has_changelogs/version.rb +3 -0
- data/lib/has_changelogs.rb +173 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1869edef6186e5ad2e9cd9c9b22270005cff43e0
|
4
|
+
data.tar.gz: f4c0e30bc0ec59be808b12bb64410f61bcc9e4f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 05d3d5ec172f9268bc21e23d1e6f825b27ea73651de45d9bdd2d47a72096158d60b9185152f1ca62b183606b583606501581ae38f323425ffe979d97003c9073
|
7
|
+
data.tar.gz: e43ec882886adfaf94d50f8d196066d838d60528c9f03b27533865db757a411a48b9d4afd3a38ef26cb2e7ca81d33322d1da15a79f5bb0718b45ed0dd24b3ba9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 TODO: Write your name
|
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,81 @@
|
|
1
|
+
# HasChangelogs
|
2
|
+
|
3
|
+
has_changelogs tracks changes on a model and it's associations for applications that need to have change history. The version is however, 0.1.0, so use at your own perril.
|
4
|
+
|
5
|
+
Especially a generator for the changelog model is missing - see /spec/fixtures/active_record/changelog.rb for it.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'has_changelogs'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install has_changelogs
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Given you had a fitting Changelog Model (see ./spec/fixtures/active_record/changelog.rb) you can do the following:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class User < ActiveRecord::Base
|
29
|
+
has_changelogs
|
30
|
+
|
31
|
+
def my_condition
|
32
|
+
name == "True Condition"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class LogEverythingUser < User
|
37
|
+
has_changelogs ignore: [:type, :id]
|
38
|
+
end
|
39
|
+
|
40
|
+
class OnlyName < User
|
41
|
+
has_changelogs only: :name
|
42
|
+
end
|
43
|
+
|
44
|
+
class IgnoreName < User
|
45
|
+
has_changelogs ignore: :name
|
46
|
+
end
|
47
|
+
|
48
|
+
class IfCondition < User
|
49
|
+
has_changelogs if: :my_condition
|
50
|
+
end
|
51
|
+
|
52
|
+
class UnlessCondition < User
|
53
|
+
has_changelogs unless: :my_condition
|
54
|
+
end
|
55
|
+
|
56
|
+
class WithPassportsUser < LogEverythingUser
|
57
|
+
has_many :passports, foreign_key: :user_id
|
58
|
+
end
|
59
|
+
|
60
|
+
class Passport < ActiveRecord::Base
|
61
|
+
belongs_to :user, class_name: "WithPassportsUser"
|
62
|
+
has_changelogs at: :user
|
63
|
+
end
|
64
|
+
|
65
|
+
```
|
66
|
+
|
67
|
+
## Development
|
68
|
+
|
69
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
70
|
+
|
71
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bitcrowd/has_changelogs.
|
76
|
+
|
77
|
+
|
78
|
+
## License
|
79
|
+
|
80
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
81
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "has_changelogs"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'has_changelogs/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'has_changelogs'
|
8
|
+
spec.version = HasChangelogs::VERSION
|
9
|
+
spec.authors = ['Elizabeth Brae', 'Christoph Beck']
|
10
|
+
spec.email = ["info@bitcrowd.net"]
|
11
|
+
|
12
|
+
spec.summary = %q{has_changelogs tracks changes on a model and it's associations for applications that need to have change history.}
|
13
|
+
spec.description = %q{has_changelogs tracks changes on a model and it's associations for applications that need to have change history. This is not about versioning your model, and the version is however, 0.1.0, so use at your own perril. The changelogs contain a JSON representation of the changes.}
|
14
|
+
spec.homepage = "https://github.com/bitcrowd/has_changelogs"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_dependency "activesupport"
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
31
|
+
spec.add_development_dependency "sqlite3"
|
32
|
+
spec.add_development_dependency "activerecord"
|
33
|
+
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
spec.add_development_dependency "rspec"
|
36
|
+
spec.add_development_dependency "pry"
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'has_changelogs/version'
|
3
|
+
|
4
|
+
module HasChangelogs
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def has_changelogs(options = {})
|
8
|
+
send :include, InstanceMethods
|
9
|
+
|
10
|
+
after_create :record_created if !options[:on] || options[:on].include?(:create)
|
11
|
+
before_destroy :record_will_be_destroyed if !options[:on] || options[:on].include?(:destroy)
|
12
|
+
|
13
|
+
after_update :record_updated, :if => :change_relevant? if !options[:on] || options[:on].include?(:update)
|
14
|
+
|
15
|
+
prepare_class_options(options)
|
16
|
+
|
17
|
+
has_many :changelogs, as: :logable
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def prepare_class_options(options)
|
23
|
+
class_attribute :has_changelog_options
|
24
|
+
self.has_changelog_options = options.dup
|
25
|
+
|
26
|
+
has_changelog_options[:ignore] = (Array(has_changelog_options[:ignore]) | [:updated_at, :created_at, :id] ).map &:to_s
|
27
|
+
has_changelog_options[:only] = Array(has_changelog_options[:only]).map &:to_s
|
28
|
+
has_changelog_options[:force] = Array(has_changelog_options[:force]).map &:to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
module InstanceMethods
|
34
|
+
|
35
|
+
def change_relevant?
|
36
|
+
if_condition = self.class.has_changelog_options[:if]
|
37
|
+
unless_condition = self.class.has_changelog_options[:unless]
|
38
|
+
|
39
|
+
conditions_met?(if_condition, unless_condition) && object_changed_notably?
|
40
|
+
end
|
41
|
+
|
42
|
+
def conditions_met?(if_condition, unless_condition)
|
43
|
+
(if_condition.blank? || if_condition.call(self)) &&
|
44
|
+
(unless_condition.blank? || !unless_condition.call(self))
|
45
|
+
end
|
46
|
+
|
47
|
+
def notable_changes
|
48
|
+
notable_attributes
|
49
|
+
end
|
50
|
+
|
51
|
+
def notable_attributes
|
52
|
+
only = self.class.has_changelog_options[:only]
|
53
|
+
force = self.class.has_changelog_options[:force]
|
54
|
+
notable = only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
55
|
+
notable + force
|
56
|
+
end
|
57
|
+
|
58
|
+
def changed_and_not_ignored
|
59
|
+
ignore = self.class.has_changelog_options[:ignore]
|
60
|
+
changed - ignore
|
61
|
+
end
|
62
|
+
|
63
|
+
def object_changed_notably?
|
64
|
+
notable_changes.any?
|
65
|
+
end
|
66
|
+
# the actions
|
67
|
+
|
68
|
+
def record_created
|
69
|
+
log_change(log_scope: log_scope, log_action: 'created', changed_data: log_data, log_origin: log_origin)
|
70
|
+
end
|
71
|
+
|
72
|
+
def record_updated
|
73
|
+
log_change(log_scope: log_scope, log_action: 'updated', changed_data: log_data, log_origin: log_origin)
|
74
|
+
end
|
75
|
+
|
76
|
+
def record_will_be_destroyed
|
77
|
+
log_change(log_scope: log_scope, log_action: 'destroyed', changed_data: self.attributes, log_origin: log_origin)
|
78
|
+
end
|
79
|
+
|
80
|
+
def log_change(options = {})
|
81
|
+
changelog_association.create(options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def log_scope
|
85
|
+
has_changelog_options[:at].present? ? :association : :instance
|
86
|
+
end
|
87
|
+
|
88
|
+
def logged_model
|
89
|
+
has_changelog_options[:at].present? ?
|
90
|
+
send(has_changelog_options[:at]) : self
|
91
|
+
end
|
92
|
+
|
93
|
+
def log_origin
|
94
|
+
self.class.to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
def changelog_association
|
98
|
+
logged_model.send changelog_association_name
|
99
|
+
end
|
100
|
+
|
101
|
+
def changelog_association_name
|
102
|
+
self.class.has_changelog_options[:changelogs_association] || :changelogs
|
103
|
+
end
|
104
|
+
|
105
|
+
def log_data(options = {})
|
106
|
+
raw_changed_data(options).select do |key, value|
|
107
|
+
notable_changes.include? key.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def raw_changed_data(options = {})
|
112
|
+
options[:change_data] || self.changes || {}
|
113
|
+
end
|
114
|
+
|
115
|
+
# def epic_hero!(options = {})
|
116
|
+
# options[:epic_hero]
|
117
|
+
# end
|
118
|
+
|
119
|
+
# def epic_action!(options = {})
|
120
|
+
# options[:epic_action] || "updated"
|
121
|
+
# end
|
122
|
+
|
123
|
+
# def epic_action_by_admin!(options = {})
|
124
|
+
# !!options[:epic_action_by_admin]
|
125
|
+
# end
|
126
|
+
|
127
|
+
# def log_item(options = {})
|
128
|
+
# options[:log_item] || self
|
129
|
+
# end
|
130
|
+
|
131
|
+
# def epic_item_nickname!(options = {})
|
132
|
+
# options[:log_item_nickname]
|
133
|
+
# end
|
134
|
+
|
135
|
+
# def epic_item_owner!(options = {})
|
136
|
+
# options[:log_item_owner]
|
137
|
+
# end
|
138
|
+
|
139
|
+
|
140
|
+
# def epic_treasure!(options = {})
|
141
|
+
# options[:epic_treasure]
|
142
|
+
# end
|
143
|
+
# def epic_treasure_nickname!(options = {})
|
144
|
+
# options[:epic_treasure_nickname]
|
145
|
+
# end
|
146
|
+
# def epic_treasureguard!(options = {})
|
147
|
+
# options[:epic_treasureguard]
|
148
|
+
# end
|
149
|
+
|
150
|
+
# def epic_change_data!(options = {})
|
151
|
+
# raw_change_data.to_json
|
152
|
+
# end
|
153
|
+
|
154
|
+
# def epic_change_attributes!(options = {})
|
155
|
+
# options[:epic_change_attributes] || raw_change_data(options).keys.join(",")
|
156
|
+
# end
|
157
|
+
|
158
|
+
# private
|
159
|
+
|
160
|
+
# def raw_change_data(options = {})
|
161
|
+
# options[:epic_change_data] || self.changes || {}
|
162
|
+
# end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.included(receiver)
|
167
|
+
receiver.extend ClassMethods
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
ActiveSupport.on_load(:active_record) do
|
172
|
+
include HasChangelogs
|
173
|
+
end
|
metadata
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_changelogs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elizabeth Brae
|
8
|
+
- Christoph Beck
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-10-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.10'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.10'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: sqlite3
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: activerecord
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rake
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '10.0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '10.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: pry
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
description: has_changelogs tracks changes on a model and it's associations for applications
|
113
|
+
that need to have change history. This is not about versioning your model, and the
|
114
|
+
version is however, 0.1.0, so use at your own perril. The changelogs contain a JSON
|
115
|
+
representation of the changes.
|
116
|
+
email:
|
117
|
+
- info@bitcrowd.net
|
118
|
+
executables: []
|
119
|
+
extensions: []
|
120
|
+
extra_rdoc_files: []
|
121
|
+
files:
|
122
|
+
- ".gitignore"
|
123
|
+
- ".rspec"
|
124
|
+
- ".travis.yml"
|
125
|
+
- Gemfile
|
126
|
+
- LICENSE.txt
|
127
|
+
- README.md
|
128
|
+
- Rakefile
|
129
|
+
- bin/console
|
130
|
+
- bin/setup
|
131
|
+
- has_changelogs.gemspec
|
132
|
+
- lib/has_changelogs.rb
|
133
|
+
- lib/has_changelogs/version.rb
|
134
|
+
homepage: https://github.com/bitcrowd/has_changelogs
|
135
|
+
licenses:
|
136
|
+
- MIT
|
137
|
+
metadata:
|
138
|
+
allowed_push_host: https://rubygems.org
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.4.5.1
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: has_changelogs tracks changes on a model and it's associations for applications
|
159
|
+
that need to have change history.
|
160
|
+
test_files: []
|