changeling 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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm use 1.9.2-p290@changeling --create
2
+ rvm use 1.9.3-p0@changeling --create
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in changeling.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Howard Huang
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,139 @@
1
+ # Changeling [![Build Status][travis-image]][travis-link]
2
+
3
+ [travis-image]: https://secure.travis-ci.org/hahuang65/Changeling.png?branch=master
4
+ [travis-link]: http://travis-ci.org/hahuang65/Changeling
5
+ [travis-home]: http://travis-ci.org/
6
+
7
+ A flexible and lightweight object change tracking system.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'changeling'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```sh
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```sh
26
+ $ gem install changeling
27
+ ```
28
+
29
+ ## Requirements
30
+
31
+ * Redis (Tested on 2.4.x)
32
+
33
+ ## Usage
34
+
35
+ Include the Trackling module for any class you want to keep track of:
36
+
37
+ ```ruby
38
+ class Post
39
+ include Changeling::Trackling
40
+
41
+ # Model logic here...
42
+ end
43
+ ```
44
+
45
+ That's it! Including the module will silently keep track of any changes made to objects of this class.
46
+ For example:
47
+
48
+ ```ruby
49
+ @post = Post.first
50
+ @post.title
51
+ => 'Old Title'
52
+ @post.title = 'New Title'
53
+ @post.save
54
+ ```
55
+
56
+ This code will save a history that represents that the title for this post has been changed.
57
+
58
+ If you wish to see what has been logged, include the Probeling module:
59
+
60
+ ```ruby
61
+ class Post
62
+ include Changeling::Trackling
63
+ include Changeling::Probeling
64
+
65
+ # Model logic here...
66
+ end
67
+ ```
68
+
69
+ With Probeling, you can check out the changes that have been made! They're stored in the order that the changes are made.
70
+ You can access the up to the last 10 changes simply by calling
71
+
72
+ ```ruby
73
+ @post.history
74
+ ```
75
+
76
+ You can access a different number of records by passing in a number to the .history method:
77
+
78
+ ```ruby
79
+ # Will automatically handle if there are less than the number of histories requested.
80
+ @post.history(50)
81
+ ```
82
+
83
+ Access all of an objects history:
84
+
85
+ ```ruby
86
+ @post.all_history
87
+ ```
88
+
89
+ Properties of Loglings (history objects):
90
+
91
+ ```ruby
92
+ log = @post.history.first
93
+
94
+ log.klass # class of the object that the Logling is tracking.
95
+ => "posts"
96
+
97
+ log.object_id # the ID of the object that the Logling is tracking.
98
+ => "1"
99
+
100
+ log.before # what the before state of the object was.
101
+ => {"title" => "Old Title"}
102
+
103
+ log.after # what the after state of the object is.
104
+ => {"title" => "New Title"}
105
+
106
+ log.modifications # what changes were made to the object that this Logling recorded. Basically a roll up of the .before and .after methods.
107
+ => {"title" => ["Old Title", "New Title"]}
108
+
109
+ log.changed_at # what time these changes were made.
110
+ => Sat, 08 Sep 2012 10:21:46 UTC +00:00
111
+
112
+ log.as_json # JSON representation of the changes.
113
+ => {:modifications=>{"title" => ["Old Title", "New Title"], :changed_at => Sat, 08 Sep 2012 10:21:46 UTC +00:00}
114
+ ```
115
+
116
+ ## Testing
117
+
118
+ This library is tested using [Travis][travis-home], where it is tested
119
+ against the following interpreters (with corresponding ORM/ODMs) and datastores:
120
+
121
+ * MRI 1.9.2 (Mongoid 2.4.1, ActiveRecord 3.1.3)
122
+ * MRI 1.9.3 (Mongoid 3.0.3, ActiveRecord 3.2.7)
123
+ * Redis 2.4.x
124
+
125
+ ## Contributing
126
+
127
+ 1. Fork it
128
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
129
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
130
+ 4. Push to the branch (`git push origin my-new-feature`)
131
+ 5. Create new Pull Request
132
+
133
+ ## TODO
134
+
135
+ * Restore state from a Logling
136
+ * Use Mongo / SQL as a datastore rather than Redis (not sure about this one yet.)
137
+ * Sinatra app to monitor changes as they happen in real-time
138
+ * Analytics for changes
139
+ * Much more...
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new("spec") do |spec|
6
+ spec.pattern = "spec/**/*_spec.rb"
7
+ end
8
+
9
+ RSpec::Core::RakeTask.new('spec:progress') do |spec|
10
+ spec.rspec_opts = %w(--format progress)
11
+ spec.pattern = "spec/**/*_spec.rb"
12
+ end
13
+
14
+ task :default => :spec
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/changeling/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Howard Huang"]
6
+ gem.email = ["hahuang65@gmail.com"]
7
+ gem.description = %q{A simple, yet flexible solution to tracking changes made to objects in your database.}
8
+ gem.summary = %q{Object change-logger}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "changeling"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Changeling::VERSION
17
+
18
+ # Dependencies
19
+ gem.add_dependency "redis"
20
+
21
+ # Development Dependencies
22
+ case RUBY_VERSION
23
+ when "1.9.2"
24
+ gem.add_development_dependency "mongoid", "2.4.1"
25
+ gem.add_development_dependency "activerecord", "3.1.3"
26
+ when "1.9.3"
27
+ gem.add_development_dependency "mongoid", "3.0.3"
28
+ gem.add_development_dependency "activerecord", "3.2.7"
29
+ end
30
+ gem.add_development_dependency "rake"
31
+ gem.add_development_dependency "rspec"
32
+ gem.add_development_dependency "bson_ext"
33
+ gem.add_development_dependency "database_cleaner"
34
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'redis'
3
+ require "changeling/version"
4
+
5
+ module Changeling
6
+ autoload :Trackling, 'changeling/trackling'
7
+ autoload :Probeling, 'changeling/probeling'
8
+
9
+ module Models
10
+ autoload :Logling, 'changeling/models/logling'
11
+ end
12
+ end
@@ -0,0 +1,80 @@
1
+ module Changeling
2
+ module Models
3
+ class Logling
4
+ attr_accessor :klass, :object_id, :modifications, :before, :after, :changed_at
5
+
6
+ class << self
7
+ def create(object, changes)
8
+ logling = self.new(object, changes)
9
+ logling.save
10
+ end
11
+
12
+ def parse_changes(changes)
13
+ before = {}
14
+ after = {}
15
+
16
+ changes.each_pair do |attr, values|
17
+ before[attr] = values[0]
18
+ after[attr] = values[1]
19
+ end
20
+
21
+ [before, after]
22
+ end
23
+
24
+ def redis
25
+ @redis ||= Redis.new
26
+ end
27
+
28
+ def redis_key(klass, object_id)
29
+ "changeling::#{klass}::#{object_id}"
30
+ end
31
+
32
+ def records_for(object, length = nil)
33
+ key = self.redis_key(object.class.to_s.underscore.pluralize, object.id.to_s)
34
+ length ||= self.redis.llen(key)
35
+
36
+ results = self.redis.lrange(key, 0, length).map { |value| self.new(object, JSON.parse(value)['modifications']) }
37
+ end
38
+ end
39
+
40
+ def as_json
41
+ {
42
+ :modifications => self.modifications,
43
+ :changed_at => self.changed_at
44
+ }
45
+ end
46
+
47
+ def initialize(object, changes)
48
+ # Remove updated_at field.
49
+ changes.delete("updated_at")
50
+
51
+ self.klass = object.class.to_s.underscore.pluralize
52
+ self.object_id = object.id.to_s
53
+ self.modifications = changes
54
+
55
+ self.before, self.after = Logling.parse_changes(changes)
56
+
57
+ if object.respond_to?(:updated_at)
58
+ self.changed_at = object.updated_at
59
+ else
60
+ self.changed_at = Time.now
61
+ end
62
+ end
63
+
64
+ def redis_key
65
+ Logling.redis_key(self.klass, self.object_id)
66
+ end
67
+
68
+ def save
69
+ key = self.redis_key
70
+ value = self.serialize
71
+
72
+ Logling.redis.lpush(key, value)
73
+ end
74
+
75
+ def serialize
76
+ self.as_json.to_json
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,11 @@
1
+ module Changeling
2
+ module Probeling
3
+ def all_history
4
+ Changeling::Models::Logling.records_for(self)
5
+ end
6
+
7
+ def history(records = 10)
8
+ Changeling::Models::Logling.records_for(self, records.to_i)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Changeling
2
+ module Trackling
3
+ def self.included(base)
4
+ base.after_update :save_logling
5
+ end
6
+
7
+ def save_logling
8
+ if changes = self.changes
9
+ logling = Changeling::Models::Logling.create(self, changes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Changeling
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ test:
2
+ sessions:
3
+ default:
4
+ database: changeling_test
5
+ hosts:
6
+ - localhost:27017
@@ -0,0 +1,10 @@
1
+ class BlogPost
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+ include Changeling::Trackling
5
+ include Changeling::Probeling
6
+
7
+ field :title
8
+ field :content
9
+ field :public, :type => Boolean
10
+ end
@@ -0,0 +1,9 @@
1
+ class BlogPostNoTimestamp
2
+ include Mongoid::Document
3
+ include Changeling::Trackling
4
+ include Changeling::Probeling
5
+
6
+ field :title
7
+ field :content
8
+ field :public, :type => Boolean
9
+ end
@@ -0,0 +1,203 @@
1
+ require (File.expand_path('../../../../spec_helper', __FILE__))
2
+
3
+ describe Changeling::Models::Logling do
4
+ before(:all) do
5
+ @klass = Changeling::Models::Logling
6
+ end
7
+
8
+ # .models is defined in spec_helper.
9
+ models.each_pair do |model, args|
10
+ puts "Testing #{model} now."
11
+
12
+ before(:each) do
13
+ @object = model.new(args[:options])
14
+ @changes = args[:changes]
15
+
16
+ @logling = @klass.new(@object, @changes)
17
+ end
18
+
19
+ context "Class Methods" do
20
+ describe ".create" do
21
+ before(:each) do
22
+ @object.stub(:changes).and_return(@changes)
23
+
24
+ @klass.should_receive(:new).with(@object, @changes).and_return(@logling)
25
+ end
26
+
27
+ it "should call new with it's parameters then save the initialized logling" do
28
+ @logling.should_receive(:save)
29
+
30
+ @klass.create(@object, @changes)
31
+ end
32
+ end
33
+
34
+ describe ".new" do
35
+ before(:each) do
36
+ @before, @after = @klass.parse_changes(@changes)
37
+ end
38
+
39
+ it "should set klass as the pluralized version of the class name" do
40
+ @logling.klass.should == @object.class.to_s.underscore.pluralize
41
+ end
42
+
43
+ it "should set object_id as the stringified object's ID" do
44
+ @logling.object_id.should == @object.id.to_s
45
+ end
46
+
47
+ it "should set the modifications as the incoming changes parameter" do
48
+ @logling.modifications.should == @changes
49
+ end
50
+
51
+ it "should set before and after based on .parse_changes" do
52
+ @logling.before.should == @before
53
+ @logling.after.should == @after
54
+ end
55
+
56
+ it "should set changed_at to the object's time of update if the object responds to the updated_at method" do
57
+ @object.should_receive(:respond_to?).with(:updated_at).and_return(true)
58
+
59
+ # Setting up a variable to prevent test flakiness from passing time.
60
+ time = Time.now
61
+ @object.stub(:updated_at).and_return(time)
62
+
63
+ # Create a new logling to trigger the initialize method
64
+ @logling = @klass.new(@object, @changes)
65
+ @logling.changed_at.should == @object.updated_at
66
+ end
67
+
68
+ it "should set changed_at to the current time if the object doesn't respond to updated_at" do
69
+ @object.should_receive(:respond_to?).with(:updated_at).and_return(false)
70
+
71
+ # Setting up a variable to prevent test flakiness from passing time.
72
+ time = Time.now
73
+ Time.stub(:now).and_return(time)
74
+
75
+ # Create a new logling to trigger the initialize method
76
+ @logling = @klass.new(@object, @changes)
77
+ @logling.changed_at.should == time
78
+ end
79
+ end
80
+
81
+ describe ".parse_changes" do
82
+ before(:each) do
83
+ @object.save!
84
+
85
+ @before = @object.attributes.select { |attr| @changes.keys.include?(attr) }
86
+
87
+ @changes.each_pair do |k, v|
88
+ @object.send("#{k}=", v[1])
89
+ end
90
+
91
+ @after = @object.attributes.select { |attr| @changes.keys.include?(attr) }
92
+ end
93
+
94
+ it "should correctly match the before and after states of the object" do
95
+ @klass.parse_changes(@object.changes).should == [@before, @after]
96
+ end
97
+ end
98
+
99
+ describe ".redis_key" do
100
+ it "should consist of 3 parts, changeling::model_name::object_id" do
101
+ @klass.redis_key(@logling.klass, @logling.object_id).should == "changeling::#{@object.class.to_s.underscore.pluralize}::#{@object.id.to_s}"
102
+ end
103
+ end
104
+
105
+ describe ".records_for" do
106
+ before(:each) do
107
+ @klass.stub(:redis).and_return($redis)
108
+ end
109
+
110
+ it "should get a redis_key" do
111
+ @key = @logling.redis_key
112
+ @klass.should_receive(:redis_key).with(@logling.klass, @logling.object_id).and_return(@key)
113
+ @klass.records_for(@object)
114
+ end
115
+
116
+ it "should find the length of the Redis list" do
117
+ @key = @logling.redis_key
118
+ @klass.stub(:redis_key).and_return(@key)
119
+ $redis.should_receive(:llen).with(@key)
120
+ @klass.records_for(@object)
121
+ end
122
+
123
+ it "should not find the length of the Redis list if length option is passed" do
124
+ @key = @logling.redis_key
125
+ @klass.stub(:redis_key).and_return(@key)
126
+ $redis.should_not_receive(:llen).with(@key)
127
+ @klass.records_for(@object, 10)
128
+ end
129
+
130
+ it "should find all entries in the Redis list" do
131
+ @key = @logling.redis_key
132
+ @length = 100
133
+ @klass.stub(:redis_key).and_return(@key)
134
+ $redis.stub(:llen).and_return(@length)
135
+ $redis.should_receive(:lrange).with(@key, 0, @length).and_return([])
136
+ @klass.records_for(@object)
137
+ end
138
+
139
+ it "should find the specified amount of entries in the Redis list if length option is passed" do
140
+ @key = @logling.redis_key
141
+ @klass.stub(:redis_key).and_return(@key)
142
+ $redis.should_receive(:lrange).with(@key, 0, 5).and_return([])
143
+ @klass.records_for(@object, 5)
144
+ end
145
+ end
146
+ end
147
+
148
+ context "Instance Methods" do
149
+ describe ".as_json" do
150
+ it "should include the object's modifications attribute" do
151
+ @logling.should_receive(:modifications)
152
+ end
153
+
154
+ it "should include the object's changed_at attribute" do
155
+ @logling.should_receive(:changed_at)
156
+ end
157
+
158
+ after(:each) do
159
+ @logling.as_json
160
+ end
161
+ end
162
+
163
+ describe ".redis_key" do
164
+ it "should pass in it's klass and object_id" do
165
+ @klass.should_receive(:redis_key).with(@logling.klass, @logling.object_id)
166
+ @logling.redis_key
167
+ end
168
+ end
169
+
170
+ describe ".save" do
171
+ before(:each) do
172
+ @klass.stub(:redis).and_return($redis)
173
+ end
174
+
175
+ it "should generate a key for storing in Redis" do
176
+ @logling.should_receive(:redis_key)
177
+ end
178
+
179
+ it "should serialize the logling" do
180
+ @logling.should_receive(:serialize)
181
+ end
182
+
183
+ it "should push the serialized object into Redis" do
184
+ @key = 1
185
+ @value = 2
186
+ @logling.stub(:redis_key).and_return(@key)
187
+ @logling.stub(:serialize).and_return(@value)
188
+ $redis.should_receive(:lpush).with(@key, @value)
189
+ end
190
+
191
+ after(:each) do
192
+ @logling.save
193
+ end
194
+ end
195
+
196
+ describe ".serialize" do
197
+ it "should JSON-ify the as_json object" do
198
+ @logling.serialize.should == @logling.as_json.to_json
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,55 @@
1
+ require (File.expand_path('../../../spec_helper', __FILE__))
2
+
3
+ describe Changeling::Probeling do
4
+ before(:all) do
5
+ @klass = Changeling::Models::Logling
6
+ end
7
+
8
+ models.each_pair do |model, args|
9
+ before(:each) do
10
+ @object = model.new(args[:options])
11
+ @object.save!
12
+
13
+ args[:changes].each do |field, values|
14
+ values.reverse.each do |value|
15
+ @object.send("#{field}=", value)
16
+ @object.save!
17
+ end
18
+ end
19
+
20
+ @object.all_history.count.should == 4
21
+ end
22
+ end
23
+
24
+ describe ".all_history" do
25
+ it "should query Logling with it's pluralized class name, and it's own ID" do
26
+ @klass.should_receive(:records_for).with(@object)
27
+ @object.all_history
28
+ end
29
+
30
+ it "should return an array of Loglings" do
31
+ @object.all_history.map(&:class).uniq.should == [@klass]
32
+ end
33
+ end
34
+
35
+ describe ".history" do
36
+ it "should query Logling with it's pluralized class name, and it's own ID, and a default number of loglings to return" do
37
+ @klass.should_receive(:records_for).with(@object, 10)
38
+ @object.history
39
+ end
40
+
41
+ it "should take an argument that overrides the default" do
42
+ @klass.should_receive(:records_for).with(@object, 5)
43
+ @object.history(5)
44
+ end
45
+
46
+ it "should handle non-integer arguments" do
47
+ @klass.should_receive(:records_for).with(@object, 5)
48
+ @object.history("5")
49
+ end
50
+
51
+ it "should not error out if the record count desired is more than the total number of loglings" do
52
+ @object.history(20).count.should == 4
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,37 @@
1
+ require (File.expand_path('../../../spec_helper', __FILE__))
2
+
3
+ describe Changeling::Trackling do
4
+ before(:all) do
5
+ @klass = Changeling::Models::Logling
6
+ end
7
+
8
+ models.each_pair do |model, args|
9
+ before(:each) do
10
+ @object = model.new(args[:options])
11
+ end
12
+
13
+ describe "callbacks" do
14
+ before(:each) do
15
+ @changes = args[:changes]
16
+ end
17
+
18
+ it "should not create a logling when doing the initial save of a new object" do
19
+ @klass.should_not_receive(:create)
20
+ @object.save!
21
+ end
22
+
23
+ it "should create a logling with the changed attributes of an object when it is saved" do
24
+ # Persist object to DB so we can update it.
25
+ @object.save!
26
+
27
+ @klass.should_receive(:create).with(@object, @changes)
28
+
29
+ @changes.each_pair do |k, v|
30
+ @object.send("#{k}=", v[1])
31
+ end
32
+
33
+ @object.save!
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ require(File.expand_path('../../lib/changeling', __FILE__))
2
+ require 'mongoid'
3
+ require 'redis'
4
+ require 'database_cleaner'
5
+
6
+ # Fixtures
7
+ Dir[File.dirname(__FILE__) + "/fixtures/**/*.rb"].each { |file| require file }
8
+
9
+ # Pre 3.0 Mongoid doesn't have this constant defined...
10
+ if defined?(Mongoid::VERSION)
11
+ # Mongoid 3.0.3
12
+ Mongoid.load!(File.dirname(__FILE__) + "/config/mongoid.yml", :test)
13
+ else
14
+ # Mongoid 2.4.1
15
+ # Didn't use Mongoid.load! here since 2.4.1 doesn't allow passing in an environment to use.
16
+ Mongoid.database = Mongo::Connection.new('localhost','27017').db('changeling_test')
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.mock_with :rspec
21
+
22
+ config.before(:suite) do
23
+ DatabaseCleaner[:mongoid].strategy = :truncation
24
+ $redis = Redis.new(:db => 1)
25
+ end
26
+
27
+ config.before(:each) do
28
+ $redis.flushdb
29
+ DatabaseCleaner.start
30
+ end
31
+
32
+ config.after(:each) do
33
+ DatabaseCleaner.clean
34
+ end
35
+ end
36
+
37
+ def models
38
+ @models = {
39
+ BlogPost => {
40
+ :options => {
41
+ :title => "Changeling",
42
+ :content => "Something about Changeling",
43
+ :public => false
44
+ },
45
+ :changes => {
46
+ "public" => [false, true],
47
+ "content" => ["Something about Changeling", "Content about Changeling"]
48
+ }
49
+ },
50
+
51
+ BlogPostNoTimestamp => {
52
+ :options => {
53
+ :title => "Changeling",
54
+ :content => "Something about Changeling",
55
+ :public => false
56
+ },
57
+ :changes => {
58
+ "public" => [false, true],
59
+ "content" => ["Something about Changeling", "Content about Changeling"]
60
+ }
61
+ }
62
+ }
63
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: changeling
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Howard Huang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: redis
16
+ requirement: &70287887029460 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70287887029460
25
+ - !ruby/object:Gem::Dependency
26
+ name: mongoid
27
+ requirement: &70287887028580 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.3
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70287887028580
36
+ - !ruby/object:Gem::Dependency
37
+ name: activerecord
38
+ requirement: &70287887028040 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
43
+ version: 3.2.7
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70287887028040
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70287887027640 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70287887027640
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: &70287887027080 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70287887027080
69
+ - !ruby/object:Gem::Dependency
70
+ name: bson_ext
71
+ requirement: &70287887026620 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70287887026620
80
+ - !ruby/object:Gem::Dependency
81
+ name: database_cleaner
82
+ requirement: &70287887026120 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70287887026120
91
+ description: A simple, yet flexible solution to tracking changes made to objects in
92
+ your database.
93
+ email:
94
+ - hahuang65@gmail.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - .gitignore
100
+ - .rvmrc
101
+ - .travis.yml
102
+ - Gemfile
103
+ - LICENSE
104
+ - README.md
105
+ - Rakefile
106
+ - changeling.gemspec
107
+ - lib/changeling.rb
108
+ - lib/changeling/models/logling.rb
109
+ - lib/changeling/probeling.rb
110
+ - lib/changeling/trackling.rb
111
+ - lib/changeling/version.rb
112
+ - spec/config/mongoid.yml
113
+ - spec/fixtures/models/mongoid/blog_post.rb
114
+ - spec/fixtures/models/mongoid/blog_post_no_timestamp.rb
115
+ - spec/lib/changeling/models/logling_spec.rb
116
+ - spec/lib/changeling/probeling_spec.rb
117
+ - spec/lib/changeling/trackling_spec.rb
118
+ - spec/spec_helper.rb
119
+ homepage: ''
120
+ licenses: []
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 1.8.15
140
+ signing_key:
141
+ specification_version: 3
142
+ summary: Object change-logger
143
+ test_files:
144
+ - spec/config/mongoid.yml
145
+ - spec/fixtures/models/mongoid/blog_post.rb
146
+ - spec/fixtures/models/mongoid/blog_post_no_timestamp.rb
147
+ - spec/lib/changeling/models/logling_spec.rb
148
+ - spec/lib/changeling/probeling_spec.rb
149
+ - spec/lib/changeling/trackling_spec.rb
150
+ - spec/spec_helper.rb