changeling 0.0.5 → 0.0.6

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/.rvmrc CHANGED
@@ -1,2 +1,2 @@
1
+ rvm use 1.9.3-p327@changeling --create
1
2
  rvm use 1.9.2-p290@changeling --create
2
- rvm use 1.9.3-p0@changeling --create
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Changeling [![Build Status][travis-image]][travis-link]
1
+ # Changeling [![Build Status][travis-image]][travis-link] [![Gem Version](https://badge.fury.io/rb/changeling.png)](http://badge.fury.io/rb/changeling)
2
2
 
3
3
  [travis-image]: https://secure.travis-ci.org/hahuang65/Changeling.png?branch=master
4
4
  [travis-link]: http://travis-ci.org/hahuang65/Changeling
@@ -49,7 +49,23 @@ class Post
49
49
  end
50
50
  ```
51
51
 
52
- That's it! Including the module will silently keep track of any changes made to objects of this class.
52
+ If you want to keep track of the user who made the changes:
53
+
54
+ ```ruby
55
+ # Doesn't have to be ApplicationController, perhaps you only want it in controllers for certain resources.
56
+ class ApplicationController < ActionController::Base
57
+ include Changeling::Blameling
58
+
59
+ # Changeling assumes your user is current_user, but if not, override the changeling_blame_user method like so:
60
+ def changeling_blame_user
61
+ current_account
62
+ end
63
+
64
+ # Controller logic here...
65
+ end
66
+ ```
67
+
68
+ That's it! Including the module(s) will silently keep track of any changes made to objects of this class.
53
69
  For example:
54
70
 
55
71
  ```ruby
@@ -122,6 +138,11 @@ log.before # what the before state of the object was.
122
138
  log.after # what the after state of the object is.
123
139
  => {"title" => "New Title"}
124
140
 
141
+ log.modified_by # ID of the user who made the changes to the object
142
+ # Note: this could be nil if the Blameling module was not set up in you controller, or if changes were made from a place without a user object, such as the Rails console.
143
+ # Note: integer type IDs will be integers. Non-integer types (such as Mongo's IDs) will be represented as a string.
144
+ => 33
145
+
125
146
  log.modifications # what changes were made to the object that this Logling recorded. Basically a roll up of the .before and .after methods.
126
147
  => {"title" => ["Old Title", "New Title"]}
127
148
 
@@ -129,7 +150,7 @@ log.modified_at # what time these changes were made.
129
150
  => Sat, 08 Sep 2012 10:21:46 UTC +00:00
130
151
 
131
152
  log.as_json # JSON representation of the changes.
132
- => {:class => Post, :oid => 1, :modifications=> { "title" => ["Old Title", "New Title"] }, :modified_at => Sat, 08 Sep 2012 10:21:46 UTC +00:00}
153
+ => {:class => Post, :oid => 1, :modified_by => 33, :modifications=> { "title" => ["Old Title", "New Title"] }, :modified_at => Sat, 08 Sep 2012 10:21:46 UTC +00:00}
133
154
  ```
134
155
 
135
156
  ## Testing
@@ -32,6 +32,9 @@ Gem::Specification.new do |gem|
32
32
  end
33
33
  gem.add_development_dependency "rake"
34
34
  gem.add_development_dependency "rspec"
35
+ gem.add_development_dependency "rspec-rails"
35
36
  gem.add_development_dependency "bson_ext"
36
37
  gem.add_development_dependency "database_cleaner"
38
+ gem.add_development_dependency "sqlite3"
39
+ gem.add_development_dependency "rails"
37
40
  end
@@ -7,8 +7,28 @@ module Changeling
7
7
 
8
8
  autoload :Trackling, 'changeling/trackling'
9
9
  autoload :Probeling, 'changeling/probeling'
10
+ autoload :Blameling, 'changeling/blameling'
10
11
 
11
12
  module Models
12
13
  autoload :Logling, 'changeling/models/logling'
13
14
  end
15
+
16
+ module Support
17
+ autoload :Search, 'changeling/support/search'
18
+ end
19
+
20
+ def self.blame_user
21
+ self.changeling_store[:blame_user]
22
+ end
23
+
24
+ def self.blame_user=(user)
25
+ self.changeling_store[:blame_user] = user
26
+ end
27
+
28
+ private
29
+ def self.changeling_store
30
+ Thread.current[:changeling] ||= {
31
+ :blame_user => nil
32
+ }
33
+ end
14
34
  end
@@ -0,0 +1,17 @@
1
+ module Changeling
2
+ module Blameling
3
+ def self.included(base)
4
+ base.before_filter :set_changeling_blame_user
5
+ end
6
+
7
+ protected
8
+ def changeling_blame_user
9
+ current_user rescue nil
10
+ end
11
+
12
+ private
13
+ def set_changeling_blame_user
14
+ Changeling.blame_user = changeling_blame_user
15
+ end
16
+ end
17
+ end
@@ -2,13 +2,15 @@ module Changeling
2
2
  module Models
3
3
  class Logling
4
4
  extend ActiveModel::Naming
5
- attr_accessor :klass, :oid, :modifications, :before, :after, :modified_at, :modified_fields
5
+ attr_accessor :klass, :oid, :modified_by, :modifications, :before, :after, :modified_at, :modified_fields
6
6
 
7
7
  include Tire::Model::Search
8
+ include Tire::Model::Callbacks
8
9
  include Tire::Model::Persistence
9
10
 
10
11
  property :klass, :type => 'string'
11
12
  property :oid, :type => 'string'
13
+ property :modified_by, :type => 'string'
12
14
  property :modifications, :type => 'string'
13
15
  property :modified_fields, :type => 'string', :analyzer => 'keyword'
14
16
  property :modified_at, :type => 'date'
@@ -16,6 +18,7 @@ module Changeling
16
18
  mapping do
17
19
  indexes :klass, :type => "string"
18
20
  indexes :oid, :type => "string"
21
+ indexes :modified_by, :type => "string"
19
22
  indexes :modifications, :type => 'string'
20
23
  indexes :modified_fields, :type => 'string', :analyzer => 'keyword'
21
24
  indexes :modified_at, :type => 'date'
@@ -40,59 +43,38 @@ module Changeling
40
43
  end
41
44
 
42
45
  def klassify(object)
43
- object.class
46
+ object.class.to_s.underscore
44
47
  end
45
48
 
46
- # TODO: Refactor me! More specs!
47
49
  def records_for(object, length = nil, field = nil)
48
- self.tire.index.refresh
49
-
50
- if field
51
- results = self.search do
52
- query do
53
- filtered do
54
- query { all }
55
- filter :terms, :klass => [Logling.klassify(object).to_s.underscore]
56
- filter :terms, :oid => [object.id.to_s]
57
- filter :terms, :modified_fields => [field]
58
- end
59
- end
60
-
61
- sort { by :modified_at, "desc" }
62
- end.results
63
- else
64
- results = self.search do
65
- query do
66
- filtered do
67
- query { all }
68
- filter :terms, :klass => [Logling.klassify(object).to_s.underscore]
69
- filter :terms, :oid => [object.id.to_s]
70
- end
71
- end
72
-
73
- sort { by :modified_at, "desc" }
74
- end.results
75
- end
50
+ filters = [
51
+ { :klass => Logling.klassify(object) },
52
+ { :oid => object.id.to_s }
53
+ ]
54
+
55
+ filters << { :modified_fields => field } if field
76
56
 
77
- results = results.take(length) if length
78
-
79
- # Some apps may return Tire::Results::Item objects in results instead of Changeling objects.
80
- results.map { |result|
81
- if result.class == Changeling::Models::Logling
82
- result
83
- elsif result.class == Tire::Results::Item
84
- Logling.new(JSON.parse(result.to_json))
85
- elsif result.class == Hash
86
- Logling.new(result)
87
- end
57
+ sort = {
58
+ :field => :modified_at,
59
+ :direction => :desc
88
60
  }
61
+
62
+ results = Changeling::Support::Search.find_by(:filters => filters, :sort => sort)
63
+
64
+ if length
65
+ results.take(length)
66
+ else
67
+ results
68
+ end
89
69
  end
90
70
  end
91
71
 
92
72
  def to_indexed_json
93
73
  {
74
+ :id => self.id,
94
75
  :klass => self.klass.to_s.underscore,
95
76
  :oid => self.oid.to_s,
77
+ :modified_by => self.modified_by,
96
78
  :modifications => self.modifications.to_json,
97
79
  :modified_at => self.modified_at,
98
80
  :modified_fields => self.modified_fields
@@ -103,16 +85,23 @@ module Changeling
103
85
  {
104
86
  :class => self.klass,
105
87
  :oid => self.oid,
88
+ :modified_by => self.modified_by,
106
89
  :modifications => self.modifications,
107
90
  :modified_at => self.modified_at
108
91
  }
109
92
  end
110
93
 
94
+ def id
95
+ # Make sure ElasticSearch creates new entries rather than update old entries.
96
+ Digest::MD5.hexdigest("#{self.klass}:#{self.oid}:#{self.modifications}")
97
+ end
98
+
111
99
  def initialize(object)
112
100
  if object.class == Hash
113
101
  changes = JSON.parse(object['modifications'])
114
102
  self.klass = object['klass'].camelize.constantize
115
103
  self.oid = object['oid'].to_i.to_s == object['oid'] ? object['oid'].to_i : object['oid']
104
+ self.modified_by = object['modified_by'].to_i.to_s == object['modified_by'] ? object['modified_by'].to_i : object['modified_by']
116
105
  self.modifications = changes
117
106
  self.modified_fields = self.modifications.keys
118
107
 
@@ -124,8 +113,9 @@ module Changeling
124
113
  # Remove updated_at field.
125
114
  changes.delete("updated_at")
126
115
 
127
- self.klass = Logling.klassify(object)
116
+ self.klass = object.class
128
117
  self.oid = object.id
118
+ self.modified_by = Changeling.blame_user.try(:id) || nil
129
119
  self.modifications = changes
130
120
  self.modified_fields = self.modifications.keys
131
121
 
@@ -141,7 +131,7 @@ module Changeling
141
131
 
142
132
  def save
143
133
  unless self.modifications.empty?
144
- _run_save_callbacks {}
134
+ self.update_index
145
135
  end
146
136
  end
147
137
  end
@@ -0,0 +1,40 @@
1
+ module Changeling
2
+ module Support
3
+ class Search
4
+ def self.find_by(args)
5
+ return [] unless args.kind_of?(Hash)
6
+
7
+ filters = args[:filters]
8
+ sort = args[:sort]
9
+ return [] unless filters || sort
10
+
11
+ @class = Changeling::Models::Logling
12
+ @class.tire.index.refresh
13
+
14
+ results = @class.search do
15
+ query do
16
+ filtered do
17
+ query { all }
18
+ filters.each do |f|
19
+ filter :terms, { f.first[0].to_sym => [f.first[1].to_s] }
20
+ end
21
+ end
22
+ end
23
+
24
+ sort { by sort[:field], sort[:direction].to_s }
25
+ end.results
26
+
27
+ # Some apps may return Tire::Results::Item objects in results instead of Changeling objects.
28
+ results.map { |result|
29
+ if result.class == @class
30
+ result
31
+ elsif result.class == Tire::Results::Item
32
+ @class.new(JSON.parse(result.to_json))
33
+ elsif result.class == Hash
34
+ @class.new(result)
35
+ end
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module Changeling
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsApp do
4
+ controller(RailsApp::BlamelingController) do
5
+ extend(RSpec::Rails::ControllerExampleGroup::BypassRescue)
6
+ end
7
+
8
+ before(:each) do
9
+ # Request needs to be setup to avoid path setting error
10
+ @request = ActionController::TestRequest.new
11
+ end
12
+
13
+ it "should set current_user if Blameling is included" do
14
+ Thread.new {
15
+ post :create
16
+ # Look in application.rb for the User class and it's id method.
17
+ BlogPost.last.all_history.last.modified_by.should == 33
18
+ }.join
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsApp do
4
+ controller(RailsApp::BlogPostsController) do
5
+ extend(RSpec::Rails::ControllerExampleGroup::BypassRescue)
6
+ end
7
+
8
+ before(:each) do
9
+ # Request needs to be setup to avoid path setting error
10
+ @request = ActionController::TestRequest.new
11
+ end
12
+
13
+ it "should not set current_user if Blameling is not included" do
14
+ Thread.new {
15
+ post :create
16
+ # Look in application.rb for the User class and it's id method.
17
+ BlogPost.last.all_history.last.modified_by.should == nil
18
+ }.join
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsApp do
4
+ controller(RailsApp::CurrentAccountController) do
5
+ extend(RSpec::Rails::ControllerExampleGroup::BypassRescue)
6
+ end
7
+
8
+ before(:each) do
9
+ # Request needs to be setup to avoid path setting error
10
+ @request = ActionController::TestRequest.new
11
+ end
12
+
13
+ it "should not set current_user if current_user is not defined" do
14
+ Thread.new {
15
+ post :create
16
+ # Look in application.rb for the User class and it's id method.
17
+ BlogPost.last.all_history.last.modified_by.should == 88
18
+ }.join
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe RailsApp do
4
+ controller(RailsApp::NoCurrentUserController) do
5
+ extend(RSpec::Rails::ControllerExampleGroup::BypassRescue)
6
+ end
7
+
8
+ before(:each) do
9
+ # Request needs to be setup to avoid path setting error
10
+ @request = ActionController::TestRequest.new
11
+ end
12
+
13
+ it "should not set current_user if current_user is not defined" do
14
+ Thread.new {
15
+ post :create
16
+ # Look in application.rb for the User class and it's id method.
17
+ BlogPost.last.all_history.last.modified_by.should == nil
18
+ }.join
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module RailsApp
4
+ class Application < Rails::Application
5
+ # app config here
6
+ # config.secret_token = '572c86f5ede338bd8aba8dae0fd3a326aabababc98d1e6ce34b9f5'
7
+ # routes.draw do
8
+ # resources :blog_posts
9
+ # end
10
+ end
11
+
12
+ class ApplicationController < ActionController::Base
13
+ def render(*attributes)
14
+ # Override render so we don't have to deal with rendering in tests.
15
+ end
16
+
17
+ def current_user
18
+ User.new
19
+ end
20
+ end
21
+
22
+ class User
23
+ def id
24
+ 33
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ require (File.expand_path('../blog_posts_controller', __FILE__))
2
+
3
+ module RailsApp
4
+ class BlamelingController < BlogPostsController
5
+ include Changeling::Blameling
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ module RailsApp
2
+ class BlogPostsController < ApplicationController
3
+ def create
4
+ @object = BlogPost.new(models[BlogPost][:options])
5
+ @object.save!
6
+
7
+ models[BlogPost][:changes].each do |field, values|
8
+ values.reverse.each do |value|
9
+ @object.send("#{field}=", value)
10
+ @object.save!
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require (File.expand_path('../no_current_user_controller', __FILE__))
2
+
3
+ module RailsApp
4
+ class CurrentAccountController < NoCurrentUserController
5
+ def changeling_blame_user
6
+ current_account
7
+ end
8
+
9
+ def current_account
10
+ Account.new
11
+ end
12
+ end
13
+
14
+ class Account
15
+ def id
16
+ 88
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ require (File.expand_path('../blameling_controller', __FILE__))
2
+
3
+ module RailsApp
4
+ class NoCurrentUserController < BlamelingController
5
+ undef :current_user
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # Setup for the fields etc. happens in spec_helper.
2
+ class BlogPostActiveRecord < ActiveRecord::Base
3
+ include Changeling::Trackling
4
+ include Changeling::Probeling
5
+ end
@@ -1,4 +1,4 @@
1
- require (File.expand_path('../../../../spec_helper', __FILE__))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Changeling::Models::Logling do
4
4
  before(:all) do
@@ -83,8 +83,8 @@ describe Changeling::Models::Logling do
83
83
  @before, @after = @klass.parse_changes(@changes)
84
84
  end
85
85
 
86
- it "should set klass as the .klassify-ed value" do
87
- @logling.klass.should == @klass.klassify(@object)
86
+ it "should set klass as the object's class" do
87
+ @logling.klass.should == @object.class
88
88
  end
89
89
 
90
90
  it "should set oid as the object's ID" do
@@ -161,39 +161,73 @@ describe Changeling::Models::Logling do
161
161
  end
162
162
 
163
163
  describe ".klassify" do
164
- it "should return the object's class" do
165
- @klass.klassify(@object).should == @object.class
164
+ it "should return the object's class as an underscored string" do
165
+ @klass.klassify(@object).should == @object.class.to_s.underscore
166
166
  end
167
167
  end
168
168
 
169
- # TODO: More specs!
170
169
  describe ".records_for" do
171
170
  before(:each) do
172
- @index = @klass.tire.index
171
+ @search = Changeling::Support::Search
173
172
  @results = []
174
- @klass.stub_chain(:tire, :index).and_return(@index)
175
- @klass.stub_chain(:search, :results).and_return(@results)
176
173
  end
177
174
 
178
- it "should refresh the ElasticSearch index" do
179
- @index.should_receive(:refresh)
175
+ context "length parameter" do
176
+ before(:each) do
177
+ @search.stub(:find_by).and_return(@results)
178
+ end
179
+
180
+ it "should only return the amount specified" do
181
+ num = 5
182
+ @results.should_receive(:take).with(num).and_return([])
183
+ @klass.records_for(@object, 5)
184
+ end
185
+
186
+ it "should return all if no amount is specified" do
187
+ @results.should_not_receive(:take)
188
+ @klass.records_for(@object)
189
+ end
190
+ end
191
+
192
+ it "should search with filters on the klass and oid" do
193
+ @search.should_receive(:find_by).with(hash_including({
194
+ :filters => [
195
+ { :klass => @klass.klassify(@object) },
196
+ { :oid => @object.id.to_s }
197
+ ]
198
+ })).and_return(@results)
180
199
  @klass.records_for(@object)
181
200
  end
182
201
 
183
- it "should only return the amount specified" do
184
- num = 5
185
- @results.should_receive(:take).with(num).and_return([])
186
- @klass.records_for(@object, 5)
202
+ it "should search with a filter on the field if one is passed in" do
203
+ @search.should_receive(:find_by).with(hash_including(
204
+ :filters => [
205
+ { :klass => @klass.klassify(@object) },
206
+ { :oid => @object.id.to_s },
207
+ { :modified_fields => "field" }
208
+ ]
209
+ )).and_return(@results)
210
+ @klass.records_for(@object, nil, "field")
187
211
  end
188
212
 
189
- it "should return all if no amount is specified" do
190
- @results.should_not_receive(:take)
191
- @klass.records_for(@object)
213
+ it "should sort by descending modified_at" do
214
+ @search.should_receive(:find_by).with(hash_including({
215
+ :sort => {
216
+ :field => :modified_at,
217
+ :direction => :desc
218
+ }
219
+ })).and_return(@results)
220
+ @klass.records_for(@object, nil)
192
221
  end
193
222
  end
194
223
  end
195
224
 
196
225
  context "Instance Methods" do
226
+ before(:each) do
227
+ # Stub :id so that it doesn't screw up these test's expectations.
228
+ @logling.stub(:id).and_return(1)
229
+ end
230
+
197
231
  describe ".to_indexed_json" do
198
232
  it "should include the object's klass attribute" do
199
233
  @logling.should_receive(:klass)
@@ -232,7 +266,7 @@ describe Changeling::Models::Logling do
232
266
  end
233
267
 
234
268
  it "should include the object's klass attribute" do
235
- @json[:class].should == @klass.klassify(@object)
269
+ @json[:class].should == @object.class
236
270
  end
237
271
 
238
272
  it "should include the object's oid attribute" do
@@ -254,7 +288,7 @@ describe Changeling::Models::Logling do
254
288
 
255
289
  describe ".save" do
256
290
  it "should update the ElasticSearch index" do
257
- @logling.should_receive(:_run_save_callbacks)
291
+ @logling.should_receive(:update_index)
258
292
  end
259
293
 
260
294
  it "should not update the index if there are no changes" do
@@ -1,4 +1,4 @@
1
- require (File.expand_path('../../../spec_helper', __FILE__))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Changeling::Probeling do
4
4
  before(:all) do
@@ -0,0 +1,81 @@
1
+ require 'spec_helper'
2
+
3
+ describe Changeling::Support::Search do
4
+ before(:all) do
5
+ @klass = Changeling::Models::Logling
6
+ @search = Changeling::Support::Search
7
+ end
8
+
9
+ describe ".find_by" do
10
+ before(:each) do
11
+ @index = @klass.tire.index
12
+ @klass.stub_chain(:tire, :index).and_return(@index)
13
+
14
+ filters = [
15
+ { :klass => "blog_post" },
16
+ { :oid => "1" }
17
+ ]
18
+
19
+ sort = {
20
+ :field => :modified_at,
21
+ :direction => :desc
22
+ }
23
+
24
+ @options = { :filters => filters, :sort => sort }
25
+
26
+ @results = []
27
+
28
+ models.each_pair do |model, args|
29
+ object = model.new(args[:options])
30
+ changes = args[:changes]
31
+
32
+ object.stub(:changes).and_return(changes)
33
+ @results << @klass.new(object)
34
+ end
35
+
36
+ @klass.stub_chain(:search, :results).and_return(@results)
37
+ end
38
+
39
+ it "should return an empty array if options are not a hash" do
40
+ @search.find_by(nil).should == []
41
+ end
42
+
43
+ it "should return an empty array if options do not include filters or sort keys" do
44
+ @search.find_by({}).should == []
45
+ end
46
+
47
+ it "should refresh the ElasticSearch index" do
48
+ @index.should_receive(:refresh)
49
+ @search.find_by(@options)
50
+ end
51
+
52
+ context "results processing" do
53
+ it "should return objects as is if they are Logling objects" do
54
+ @search.find_by(@options).should == @results
55
+ end
56
+
57
+ it "should parse them and convert them into Logling objects if they are returned as Tire::Results::Item objects" do
58
+ @tire_object = Tire::Results::Item.new
59
+ @tire_json = "{}"
60
+ @hash = {}
61
+
62
+ @results = [@tire_object]
63
+ @klass.stub_chain(:search, :results).and_return(@results)
64
+
65
+ @tire_object.should_receive(:to_json).and_return(@tire_json)
66
+ JSON.should_receive(:parse).with(@tire_json).and_return(@hash)
67
+ @klass.should_receive(:new).with(@hash)
68
+
69
+ @search.find_by(@options)
70
+ end
71
+
72
+ it "should convert them into Logling objects if they are returned as Hash objects" do
73
+ @results = [{}, {}]
74
+ @klass.stub_chain(:search, :results).and_return(@results)
75
+
76
+ @results.each { |r| @klass.should_receive(:new).with(r) }
77
+ @search.find_by(@options)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,4 +1,4 @@
1
- require (File.expand_path('../../../spec_helper', __FILE__))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Changeling::Trackling do
4
4
  before(:all) do
@@ -1,6 +1,9 @@
1
1
  require(File.expand_path('../../lib/changeling', __FILE__))
2
2
  require 'mongoid'
3
3
  require 'database_cleaner'
4
+ require 'rails/all'
5
+ require 'rspec/rails'
6
+ require 'action_controller/railtie' # allows ActionController::Base
4
7
 
5
8
  # Fixtures
6
9
  Dir[File.dirname(__FILE__) + "/fixtures/**/*.rb"].each { |file| require file }
@@ -15,10 +18,24 @@ else
15
18
  Mongoid.database = Mongo::Connection.new('localhost','27017').db('changeling_test')
16
19
  end
17
20
 
21
+ # ActiveRecord setup
22
+ ActiveRecord::Base.establish_connection( :adapter => 'sqlite3', :database => ":memory:" )
23
+
24
+ ActiveRecord::Migration.verbose = false
25
+ ActiveRecord::Schema.define(:version => 1) do
26
+ # See the activerecord folder under spec/fixtures/models
27
+ create_table :blog_post_active_records do |t|
28
+ t.string :title
29
+ t.string :content
30
+ t.boolean :public
31
+ end
32
+ end
33
+
18
34
  RSpec.configure do |config|
19
35
  config.mock_with :rspec
20
36
 
21
37
  config.before(:suite) do
38
+ DatabaseCleaner[:active_record].strategy = :truncation
22
39
  DatabaseCleaner[:mongoid].strategy = :truncation
23
40
  Tire::Model::Search.index_prefix "changeling_test"
24
41
  end
@@ -48,29 +65,21 @@ def clear_tire_indexes
48
65
  end
49
66
 
50
67
  def models
51
- @models = {
52
- BlogPost => {
53
- :options => {
54
- :title => "Changeling",
55
- :content => "Something about Changeling",
56
- :public => false
57
- },
58
- :changes => {
59
- "public" => [false, true],
60
- "content" => ["Something about Changeling", "Content about Changeling"]
61
- }
68
+ hash = {
69
+ :options => {
70
+ :title => "Changeling",
71
+ :content => "Something about Changeling",
72
+ :public => false
62
73
  },
63
-
64
- BlogPostNoTimestamp => {
65
- :options => {
66
- :title => "Changeling",
67
- :content => "Something about Changeling",
68
- :public => false
69
- },
70
- :changes => {
71
- "public" => [false, true],
72
- "content" => ["Something about Changeling", "Content about Changeling"]
73
- }
74
+ :changes => {
75
+ "public" => [false, true],
76
+ "content" => ["Something about Changeling", "Content about Changeling"]
74
77
  }
75
78
  }
79
+
80
+ @models = {
81
+ BlogPost => hash,
82
+ BlogPostNoTimestamp => hash,
83
+ BlogPostActiveRecord => hash
84
+ }
76
85
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: changeling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-10 00:00:00.000000000 Z
12
+ date: 2013-02-09 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: tire
16
- requirement: &70170915769820 !ruby/object:Gem::Requirement
16
+ requirement: &70261420742240 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70170915769820
24
+ version_requirements: *70261420742240
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activemodel
27
- requirement: &70170915767980 !ruby/object:Gem::Requirement
27
+ requirement: &70261420741820 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,32 +32,32 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70170915767980
35
+ version_requirements: *70261420741820
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: mongoid
38
- requirement: &70170915766520 !ruby/object:Gem::Requirement
38
+ requirement: &70261420741320 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - =
42
42
  - !ruby/object:Gem::Version
43
- version: 3.0.3
43
+ version: 2.4.1
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70170915766520
46
+ version_requirements: *70261420741320
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: activerecord
49
- requirement: &70170915764360 !ruby/object:Gem::Requirement
49
+ requirement: &70261420740820 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - =
53
53
  - !ruby/object:Gem::Version
54
- version: 3.2.7
54
+ version: 3.1.3
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70170915764360
57
+ version_requirements: *70261420740820
58
58
  - !ruby/object:Gem::Dependency
59
- name: debugger
60
- requirement: &70170915763160 !ruby/object:Gem::Requirement
59
+ name: ruby-debug19
60
+ requirement: &70261420740440 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70170915763160
68
+ version_requirements: *70261420740440
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
- requirement: &70170915777700 !ruby/object:Gem::Requirement
71
+ requirement: &70261420739980 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70170915777700
79
+ version_requirements: *70261420739980
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rspec
82
- requirement: &70170915775660 !ruby/object:Gem::Requirement
82
+ requirement: &70261404212700 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,21 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70170915775660
90
+ version_requirements: *70261404212700
91
+ - !ruby/object:Gem::Dependency
92
+ name: rspec-rails
93
+ requirement: &70261404212280 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70261404212280
91
102
  - !ruby/object:Gem::Dependency
92
103
  name: bson_ext
93
- requirement: &70170915773840 !ruby/object:Gem::Requirement
104
+ requirement: &70261404211860 !ruby/object:Gem::Requirement
94
105
  none: false
95
106
  requirements:
96
107
  - - ! '>='
@@ -98,10 +109,32 @@ dependencies:
98
109
  version: '0'
99
110
  type: :development
100
111
  prerelease: false
101
- version_requirements: *70170915773840
112
+ version_requirements: *70261404211860
102
113
  - !ruby/object:Gem::Dependency
103
114
  name: database_cleaner
104
- requirement: &70170915771240 !ruby/object:Gem::Requirement
115
+ requirement: &70261404211440 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *70261404211440
124
+ - !ruby/object:Gem::Dependency
125
+ name: sqlite3
126
+ requirement: &70261404211020 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *70261404211020
135
+ - !ruby/object:Gem::Dependency
136
+ name: rails
137
+ requirement: &70261404210600 !ruby/object:Gem::Requirement
105
138
  none: false
106
139
  requirements:
107
140
  - - ! '>='
@@ -109,7 +142,7 @@ dependencies:
109
142
  version: '0'
110
143
  type: :development
111
144
  prerelease: false
112
- version_requirements: *70170915771240
145
+ version_requirements: *70261404210600
113
146
  description: A simple, yet flexible solution to tracking changes made to objects in
114
147
  your database.
115
148
  email:
@@ -128,15 +161,28 @@ files:
128
161
  - Rakefile
129
162
  - changeling.gemspec
130
163
  - lib/changeling.rb
164
+ - lib/changeling/blameling.rb
131
165
  - lib/changeling/models/logling.rb
132
166
  - lib/changeling/probeling.rb
167
+ - lib/changeling/support/search.rb
133
168
  - lib/changeling/trackling.rb
134
169
  - lib/changeling/version.rb
135
170
  - spec/config/mongoid.yml
136
- - spec/fixtures/models/mongoid/blog_post.rb
137
- - spec/fixtures/models/mongoid/blog_post_no_timestamp.rb
171
+ - spec/controllers/blameling_controller_spec.rb
172
+ - spec/controllers/blog_posts_controller_spec.rb
173
+ - spec/controllers/current_account_controller_spec.rb
174
+ - spec/controllers/no_current_user_controller_spec.rb
175
+ - spec/fixtures/app/application.rb
176
+ - spec/fixtures/app/controllers/blameling_controller.rb
177
+ - spec/fixtures/app/controllers/blog_posts_controller.rb
178
+ - spec/fixtures/app/controllers/current_account_controller.rb
179
+ - spec/fixtures/app/controllers/no_current_user_controller.rb
180
+ - spec/fixtures/app/models/blog_post.rb
181
+ - spec/fixtures/app/models/blog_post_active_record.rb
182
+ - spec/fixtures/app/models/blog_post_no_timestamp.rb
138
183
  - spec/lib/changeling/models/logling_spec.rb
139
184
  - spec/lib/changeling/probeling_spec.rb
185
+ - spec/lib/changeling/support/search_spec.rb
140
186
  - spec/lib/changeling/trackling_spec.rb
141
187
  - spec/spec_helper.rb
142
188
  homepage: ''
@@ -159,15 +205,26 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
205
  version: '0'
160
206
  requirements: []
161
207
  rubyforge_project:
162
- rubygems_version: 1.8.6
208
+ rubygems_version: 1.8.15
163
209
  signing_key:
164
210
  specification_version: 3
165
211
  summary: Object change-logger
166
212
  test_files:
167
213
  - spec/config/mongoid.yml
168
- - spec/fixtures/models/mongoid/blog_post.rb
169
- - spec/fixtures/models/mongoid/blog_post_no_timestamp.rb
214
+ - spec/controllers/blameling_controller_spec.rb
215
+ - spec/controllers/blog_posts_controller_spec.rb
216
+ - spec/controllers/current_account_controller_spec.rb
217
+ - spec/controllers/no_current_user_controller_spec.rb
218
+ - spec/fixtures/app/application.rb
219
+ - spec/fixtures/app/controllers/blameling_controller.rb
220
+ - spec/fixtures/app/controllers/blog_posts_controller.rb
221
+ - spec/fixtures/app/controllers/current_account_controller.rb
222
+ - spec/fixtures/app/controllers/no_current_user_controller.rb
223
+ - spec/fixtures/app/models/blog_post.rb
224
+ - spec/fixtures/app/models/blog_post_active_record.rb
225
+ - spec/fixtures/app/models/blog_post_no_timestamp.rb
170
226
  - spec/lib/changeling/models/logling_spec.rb
171
227
  - spec/lib/changeling/probeling_spec.rb
228
+ - spec/lib/changeling/support/search_spec.rb
172
229
  - spec/lib/changeling/trackling_spec.rb
173
230
  - spec/spec_helper.rb