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 CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
+ gem "string-cases"
5
6
 
6
7
  # Add dependencies to develop your gem here.
7
8
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -52,6 +52,7 @@ GEM
52
52
  rspec-expectations (2.8.0)
53
53
  diff-lcs (~> 1.1.2)
54
54
  rspec-mocks (2.8.0)
55
+ string-cases (0.0.0)
55
56
 
56
57
  PLATFORMS
57
58
  ruby
@@ -61,3 +62,4 @@ DEPENDENCIES
61
62
  jeweler (~> 1.8.4)
62
63
  rdoc (~> 3.12)
63
64
  rspec (~> 2.8.0)
65
+ string-cases
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.0.1
@@ -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
@@ -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.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-14"
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.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-14 00:00:00.000000000 Z
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: -3618021520237963186
128
+ hash: -3375604828162703244
113
129
  version: '0'
114
130
  required_rubygems_version: !ruby/object:Gem::Requirement
115
131
  none: false