paper_trail_changes 0.0.0 → 0.0.1
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.
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/lib/paper_trail_changes.rb +93 -1
- data/paper_trail_changes.gemspec +5 -2
- data/spec/paper_trail_changes_spec.rb +48 -0
- metadata +19 -3
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
data/lib/paper_trail_changes.rb
CHANGED
@@ -1,6 +1,98 @@
|
|
1
|
+
require "string-cases"
|
2
|
+
|
1
3
|
class PaperTrailChanges
|
2
|
-
def last_version(model)
|
4
|
+
def self.last_version(model)
|
3
5
|
version = Version.where(:item_type => model.class.name, :item_id => model.id, :event => :update).order(:id).reverse_order.first
|
4
6
|
return version
|
5
7
|
end
|
8
|
+
|
9
|
+
CHANGES_SINCE_VERSION_VALID_ARGS = [:version_id, :version_at, :model, :attributes]
|
10
|
+
def self.changes_since_version(args)
|
11
|
+
args.each do |key, val|
|
12
|
+
raise "Invalid argument: '#{key}'." unless CHANGES_SINCE_VERSION_VALID_ARGS.include?(key)
|
13
|
+
end
|
14
|
+
|
15
|
+
attributes, model = args[:attributes], args[:model]
|
16
|
+
|
17
|
+
column_types = PaperTrailChanges.column_types_from_class(model.class)
|
18
|
+
|
19
|
+
if args[:version_id]
|
20
|
+
version_obj = Version.find(args[:version_id]) rescue nil
|
21
|
+
elsif args[:version_at]
|
22
|
+
version_model = model.version_at(args[:version_at])
|
23
|
+
end
|
24
|
+
|
25
|
+
version_model = model if version_obj.nil? && version_model.nil?
|
26
|
+
|
27
|
+
if version_obj
|
28
|
+
version_hash = Psych.load(version_obj.object).stringify_keys
|
29
|
+
elsif version_model
|
30
|
+
version_hash = {}
|
31
|
+
version_model.attributes.each do |key, val|
|
32
|
+
version_hash[key.to_s] = version_model.__send__("#{key}_before_type_cast")
|
33
|
+
end
|
34
|
+
else
|
35
|
+
raise "Dont know what to do?"
|
36
|
+
end
|
37
|
+
|
38
|
+
changes_since = PaperTrailChanges.changes_hash(
|
39
|
+
:attributes => attributes,
|
40
|
+
:version_hash => version_hash,
|
41
|
+
:model => model,
|
42
|
+
:column_types => column_types
|
43
|
+
)
|
44
|
+
|
45
|
+
return changes_since
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.column_types_from_class(class_obj)
|
49
|
+
column_types = {}
|
50
|
+
class_obj.columns_hash.each do |name, col|
|
51
|
+
column_types[name] = col.type
|
52
|
+
end
|
53
|
+
|
54
|
+
return column_types
|
55
|
+
end
|
56
|
+
|
57
|
+
CHANGES_HASH_VALID_ARGS = [:attributes, :version_hash, :model, :column_types]
|
58
|
+
def self.changes_hash(args)
|
59
|
+
args.each do |key, val|
|
60
|
+
raise "Invalid argument: '#{key}'." unless CHANGES_HASH_VALID_ARGS.include?(key)
|
61
|
+
end
|
62
|
+
|
63
|
+
attributes, version_hash, model, column_types = args[:attributes], args[:version_hash], args[:model], args[:column_types]
|
64
|
+
changes_since = {}
|
65
|
+
|
66
|
+
attributes.each do |key, val|
|
67
|
+
key_s = key.to_s
|
68
|
+
|
69
|
+
if match = key_s.match(/^(.+)_attributes$/)
|
70
|
+
# Nested model. Since paper-trail doesn't keep track of this just pass it through.
|
71
|
+
changes_since[key] = val
|
72
|
+
elsif version_hash.key?(key_s)
|
73
|
+
last_val = version_hash[key_s]
|
74
|
+
changed = false
|
75
|
+
type = column_types[key_s]
|
76
|
+
|
77
|
+
if type == :string || type == :date || type == :text || type == :datetime
|
78
|
+
changed = true if last_val.to_s != val.to_s
|
79
|
+
elsif type == :integer
|
80
|
+
changed = true if last_val.to_i != val.to_i
|
81
|
+
changed = true if last_val == nil && val
|
82
|
+
elsif type == :boolean
|
83
|
+
bool_i = last_val ? 1 : 0
|
84
|
+
changed = true if bool_i != val.to_i
|
85
|
+
changed = true if last_val == nil && val
|
86
|
+
else
|
87
|
+
raise "Unknown type: '#{type}'."
|
88
|
+
end
|
89
|
+
|
90
|
+
changes_since[key_s] = val if changed
|
91
|
+
else
|
92
|
+
changes_since[key_s] = val
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
return changes_since
|
97
|
+
end
|
6
98
|
end
|
data/paper_trail_changes.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "paper_trail_changes"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["kaspernj"]
|
12
|
-
s.date = "2013-08-
|
12
|
+
s.date = "2013-08-15"
|
13
13
|
s.description = "A gem to do various stuff with PaperTrail versions."
|
14
14
|
s.email = "k@spernj.org"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -40,17 +40,20 @@ Gem::Specification.new do |s|
|
|
40
40
|
s.specification_version = 3
|
41
41
|
|
42
42
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
43
|
+
s.add_runtime_dependency(%q<string-cases>, [">= 0"])
|
43
44
|
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
44
45
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
45
46
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
46
47
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
47
48
|
else
|
49
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
48
50
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
49
51
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
50
52
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
51
53
|
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
52
54
|
end
|
53
55
|
else
|
56
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
54
57
|
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
55
58
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
56
59
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
@@ -1,5 +1,53 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
+
class Submodel
|
4
|
+
def columns_hash
|
5
|
+
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
describe "PaperTrailChanges" do
|
10
|
+
it "should handle booleans" do
|
11
|
+
changes = PaperTrailChanges.changes_hash(
|
12
|
+
:attributes => {"works" => "1", "fails" => 0, "doesnt_fail" => "1"},
|
13
|
+
:version_hash => {"works" => true, "fails" => false, "doesnt_fail" => false},
|
14
|
+
:column_types => {"works" => :boolean, "fails" => :boolean, "doesnt_fail" => :boolean}
|
15
|
+
)
|
16
|
+
|
17
|
+
changes.length.should eql(1)
|
18
|
+
changes.keys.first.should eql("doesnt_fail")
|
19
|
+
changes.values.first.should eql("1")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should handle integers" do
|
23
|
+
changes = PaperTrailChanges.changes_hash(
|
24
|
+
:attributes => {"number1" => "1", "number2" => "2", "number3" => "3"},
|
25
|
+
:version_hash => {"number1" => 1, "number2" => 2, "number3" => 33},
|
26
|
+
:column_types => {"number1" => :integer, "number2" => :integer, "number3" => :integer}
|
27
|
+
)
|
28
|
+
|
29
|
+
changes.length.should eql(1)
|
30
|
+
changes.keys.first.should eql("number3")
|
31
|
+
changes.values.first.should eql("3")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should handle strings" do
|
35
|
+
changes = PaperTrailChanges.changes_hash(
|
36
|
+
:attributes => {"str1" => "123", "str2" => "234", "str3" => 3},
|
37
|
+
:version_hash => {"str1" => "1234", "str2" => "234", "str3" => 3},
|
38
|
+
:column_types => {"str1" => :string, "str2" => :text, "str3" => :string}
|
39
|
+
)
|
40
|
+
|
41
|
+
changes.length.should eql(1)
|
42
|
+
changes.keys.first.should eql("str1")
|
43
|
+
changes.values.first.should eql("123")
|
44
|
+
end
|
4
45
|
|
46
|
+
it "should handle nested attributes" do
|
47
|
+
changes = PaperTrailChanges.changes_hash(
|
48
|
+
:attributes => {"submodel_attributes" => {"test1" => "test1", "test2" => 2, "test3" => "changed"}},
|
49
|
+
:version_hash => {"submodel" => {"test1" => "test1", "test2" => 2, "test3" => "test3"}},
|
50
|
+
:column_types => {}
|
51
|
+
)
|
52
|
+
end
|
5
53
|
end
|
metadata
CHANGED
@@ -2,15 +2,31 @@
|
|
2
2
|
name: paper_trail_changes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- kaspernj
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
none: false
|
17
|
+
requirements:
|
18
|
+
- - ! '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
name: string-cases
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
requirement: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
version_requirements: !ruby/object:Gem::Requirement
|
16
32
|
none: false
|
@@ -109,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
109
125
|
- !ruby/object:Gem::Version
|
110
126
|
segments:
|
111
127
|
- 0
|
112
|
-
hash: -
|
128
|
+
hash: -3375604828162703244
|
113
129
|
version: '0'
|
114
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
131
|
none: false
|