deja_vue 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +9 -0
- data/README.rdoc +75 -0
- data/Rakefile +19 -0
- data/deja_vue.gemspec +29 -0
- data/lib/deja_vue.rb +98 -0
- data/lib/deja_vue/has_deja_vue.rb +85 -0
- data/lib/deja_vue/history.rb +184 -0
- data/rails/init.rb +3 -0
- metadata +81 -0
data/Manifest
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
= DejaVue
|
2
|
+
|
3
|
+
Yet another gem to store version of your models. But it uses mongodb as
|
4
|
+
backend. Based on PaperTrail (http://github.com/airblade/paper_trail/).
|
5
|
+
|
6
|
+
== Why choose DejaVue
|
7
|
+
|
8
|
+
The main goal of DejaVue is to keep track of associated models. It's
|
9
|
+
useful for a model whose relations change among time and to see how
|
10
|
+
it really looked like at a certain point.
|
11
|
+
|
12
|
+
There are 3 kinds of versioning: create, update, destroy
|
13
|
+
Differently from PaperTrail, each version will record the current model info.
|
14
|
+
So PapelTrail _create_ versions have reify == nil
|
15
|
+
DejaVue have _create_ version == model_version_when_creating
|
16
|
+
|
17
|
+
== Installing
|
18
|
+
|
19
|
+
$ bundle install
|
20
|
+
$ gem install gemcutter
|
21
|
+
$ gem build deja_vue.gemspec
|
22
|
+
$ gem install ./deja_vue-*.gem
|
23
|
+
|
24
|
+
== Beggining with DejaVue: Add to your model
|
25
|
+
|
26
|
+
Add a single line and your model will start beeing versionated:
|
27
|
+
|
28
|
+
def SomeModel < ActiveRecord::Base
|
29
|
+
has_deja_vue
|
30
|
+
end
|
31
|
+
|
32
|
+
Or, for example, use the ignore option:
|
33
|
+
|
34
|
+
def SomeModel < ActiveRecord::Base
|
35
|
+
has_deja_vue :ignore => :location
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
== More Options
|
40
|
+
|
41
|
+
You might pass some options, including:
|
42
|
+
:ignore | An Array of fields that will be ignored. If
|
43
|
+
| only those fields have changed, then no version
|
44
|
+
| will be created.
|
45
|
+
| has_deja_vue :ignore => :last_exported_on
|
46
|
+
:associations | Store associated models to be record with the model
|
47
|
+
| so it can be fully restored. Right now it works only
|
48
|
+
| with has_one / belongs_to relationships.
|
49
|
+
| Ex.:
|
50
|
+
| class Account < ActiveRecord::Base
|
51
|
+
| has_one :account_preference
|
52
|
+
|
|
53
|
+
| has_deja_vue :associations => [:account_preference]
|
54
|
+
| end
|
55
|
+
|
|
56
|
+
:extra_info_fields | Almost the same as the above option. But it handles
|
57
|
+
| more simple info (like strings, integers, floats).
|
58
|
+
| Useful to store a tag_list field or a counter cache
|
59
|
+
| Ex:
|
60
|
+
|
|
61
|
+
| class BlogPost < ActiveRecord::Base
|
62
|
+
| acts_as_taggable_on :tags
|
63
|
+
|
|
64
|
+
| has_deja_vue :extra_info_fields => [:tag_list]
|
65
|
+
| end
|
66
|
+
|
|
67
|
+
:who_did_it | a default value for record who_did_it when you
|
68
|
+
| are not in a request-response cycle (ex. in a job).
|
69
|
+
| Ex.:
|
70
|
+
| has_deja_vue :who_did_it => 'admin'
|
71
|
+
| Alternatively you are able to set the user right
|
72
|
+
| before save the model that will be versionated, using:
|
73
|
+
| DejaVue.who_did_it = 'otavio'
|
74
|
+
| SomeModel.save
|
75
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
begin
|
2
|
+
# Rspec 1.3.0
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
desc 'Default: run specs'
|
5
|
+
task :default => :spec
|
6
|
+
Spec::Rake::SpecTask.new do |t|
|
7
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
8
|
+
end
|
9
|
+
|
10
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
11
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
12
|
+
t.rcov = true
|
13
|
+
t.rcov_opts = ['--exclude', 'spec']
|
14
|
+
end
|
15
|
+
|
16
|
+
rescue LoadError
|
17
|
+
puts "Rspec not available. Install it with: gem install rspec"
|
18
|
+
end
|
19
|
+
|
data/deja_vue.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
|
5
|
+
require 'deja_vue/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = %q{deja_vue}
|
9
|
+
s.version = DejaVue::VERSION
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ["Riopro Informatica Ltda"]
|
13
|
+
s.date = %q{2010-08-11}
|
14
|
+
s.description = %q{DejaVue -> Ruby versioning Gem using MongoDB as backend}
|
15
|
+
s.email = %q{riopro@riopro.com.br}
|
16
|
+
s.extra_rdoc_files = ["README.rdoc", "lib/deja_vue.rb"]
|
17
|
+
s.files = ["Manifest", "README.rdoc", "Rakefile", "deja_vue.gemspec", "lib/deja_vue.rb", "lib/deja_vue/has_deja_vue.rb", "lib/deja_vue/history.rb", "rails/init.rb"]
|
18
|
+
s.homepage = %q{http://github.com/riopro/deja_vue}
|
19
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "deja_vue", "--main", "README.rdoc"]
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.rubyforge_project = %q{deja_vue}
|
22
|
+
s.rubygems_version = %q{1.3.7}
|
23
|
+
s.summary = %q{Keep track of your models changing history, using MongoDB as backend}
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
27
|
+
s.specification_version = 3
|
28
|
+
end
|
29
|
+
end
|
data/lib/deja_vue.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'deja_vue/has_deja_vue'
|
2
|
+
require 'deja_vue/history'
|
3
|
+
|
4
|
+
# Based on PaperTrail (http://github.com/airblade/paper_trail/).
|
5
|
+
# Using:
|
6
|
+
# Add an initializer at config/initializers and require 'deja_vue'
|
7
|
+
# Add to your model:
|
8
|
+
# has_deja_vue
|
9
|
+
# You might pass some options, including:
|
10
|
+
# :ignore | An Array of fields that will be ignored. If
|
11
|
+
# | only those fields have changed, then no version
|
12
|
+
# | will be created.
|
13
|
+
# | has_deja_vue :ignore => :last_exported_on
|
14
|
+
# :associations | Store associated models to be record with the model
|
15
|
+
# | so it can be fully restored. Right now it works only
|
16
|
+
# | with has_one / belongs_to relationships.
|
17
|
+
# | Ex.:
|
18
|
+
# | class Account < ActiveRecord::Base
|
19
|
+
# | has_one :account_preference
|
20
|
+
# |
|
21
|
+
# | has_deja_vue :associations => [:account_preference]
|
22
|
+
# | end
|
23
|
+
# |
|
24
|
+
# :extra_info_fields | Almost the same as the above option. But it handles
|
25
|
+
# | more simple info (like strings, integers, floats).
|
26
|
+
# | Useful to store a tag_list field or a counter cache
|
27
|
+
# | Ex:
|
28
|
+
# |
|
29
|
+
# | class BlogPost < ActiveRecord::Base
|
30
|
+
# | acts_as_taggable_on :tags
|
31
|
+
# |
|
32
|
+
# | has_deja_vue :extra_info_fields => [:tag_list]
|
33
|
+
# | end
|
34
|
+
# |
|
35
|
+
# :who_did_it | a default value for record who_did_it when you
|
36
|
+
# | are not in a request-response cycle (ex. in a job).
|
37
|
+
# | Ex.:
|
38
|
+
# | has_deja_vue :who_did_it => 'admin'
|
39
|
+
# | Alternatively you are able to set the user right
|
40
|
+
# | before save the model that will be versionated, using:
|
41
|
+
# | DejaVue.who_did_it = 'otavio'
|
42
|
+
# | SomeModel.save
|
43
|
+
#
|
44
|
+
# There are 3 kinds of versioning: create, update, destroy
|
45
|
+
# Differently from PaperTrail, each version will record the current model info.
|
46
|
+
# So PapelTrail _create_ versions have reify == nil
|
47
|
+
# DejaVue have _create_ version == model_version_when_creating
|
48
|
+
module DejaVue
|
49
|
+
|
50
|
+
def self.included(base)
|
51
|
+
base.before_filter :set_deja_vue_user
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.who_did_it
|
55
|
+
Thread.current[:who_did_it]
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.who_did_it=(value)
|
59
|
+
Thread.current[:who_did_it] = value
|
60
|
+
end
|
61
|
+
|
62
|
+
# Used to set an user to be versionated, execute the block and
|
63
|
+
# then rollback to the thread's regular user.
|
64
|
+
# Example:
|
65
|
+
#
|
66
|
+
# @blog_post = BlogPost.find 10
|
67
|
+
# @blog_post.title = "new title"
|
68
|
+
# DejaVue.setting_user_as('someone') do
|
69
|
+
# @blog_post.save
|
70
|
+
# end
|
71
|
+
def self.setting_user_as(value, &block)
|
72
|
+
actual_user = Thread.current[:who_did_it]
|
73
|
+
Thread.current[:who_did_it] = value
|
74
|
+
yield if block_given?
|
75
|
+
Thread.current[:who_did_it] = actual_user
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
# Returns the user who is responsible for any changes that occur.
|
81
|
+
# By default this calls `current_user` and returns the result.
|
82
|
+
#
|
83
|
+
# Override this method in your controller to call a different
|
84
|
+
# method, e.g. `current_person`, or anything you like.
|
85
|
+
def user_for_deja_vue
|
86
|
+
return current_user if current_user && current_user.is_a?(String)
|
87
|
+
current_user[:id] if current_user && current_user[:id]
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Verifies if current controller responds to current_user method
|
93
|
+
def set_deja_vue_user
|
94
|
+
Thread.current[:who_did_it] = user_for_deja_vue
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
ActionController::Base.send :include, DejaVue
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module DejaVue
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.send :extend, ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Options:
|
10
|
+
# :ignore an array of attributes for which a new +Version+ will not be created if only they change.
|
11
|
+
def has_deja_vue(options = {})
|
12
|
+
send :include, InstanceMethods
|
13
|
+
|
14
|
+
cattr_accessor :deja_vue_options
|
15
|
+
options[:ignore] = options[:ignore].map &:to_s if options[:ignore]
|
16
|
+
self.deja_vue_options = options
|
17
|
+
|
18
|
+
cattr_accessor :deja_vue_active
|
19
|
+
self.deja_vue_active = true
|
20
|
+
|
21
|
+
before_save :check_for_version_changes
|
22
|
+
after_update :record_update_version
|
23
|
+
after_create :record_create_version
|
24
|
+
after_destroy :record_destroy_version
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
# FIXME: not implemented yet
|
29
|
+
def deja_vue_off
|
30
|
+
self.deja_vue_active = false
|
31
|
+
end
|
32
|
+
|
33
|
+
# FIXME: not implemented yet
|
34
|
+
def deja_vue_on
|
35
|
+
self.deja_vue_active = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
|
41
|
+
# return array with changed fields after object has been saved
|
42
|
+
# (created or updated).
|
43
|
+
# Whe need this to validate if the changes must be recorded after save
|
44
|
+
def version_changes
|
45
|
+
@version_changes
|
46
|
+
end
|
47
|
+
|
48
|
+
# Search for all change history from the current object
|
49
|
+
def histories(extra_options={})
|
50
|
+
default_options = {:versionable_type => self.class.to_s, :versionable_id => self.id.to_s}
|
51
|
+
History.where(extra_options.merge(default_options)).sort(:created_at.desc).all
|
52
|
+
end
|
53
|
+
|
54
|
+
# Search for a change history from the current object by id
|
55
|
+
def history(param_id)
|
56
|
+
History.where(:versionable_type => self.class.to_s, :versionable_id => self.id.to_s, :id => param_id).first
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def check_for_version_changes
|
62
|
+
@version_changes = self.changed
|
63
|
+
end
|
64
|
+
|
65
|
+
def versionate_as(kind_of_version)
|
66
|
+
History.versionate(self, kind_of_version, deja_vue_options.merge(:who_did_it => DejaVue.who_did_it)) if DejaVue.who_did_it
|
67
|
+
History.versionate(self, kind_of_version, deja_vue_options) unless DejaVue.who_did_it
|
68
|
+
end
|
69
|
+
|
70
|
+
def record_update_version
|
71
|
+
versionate_as("update")
|
72
|
+
end
|
73
|
+
|
74
|
+
def record_create_version
|
75
|
+
versionate_as("create")
|
76
|
+
end
|
77
|
+
|
78
|
+
def record_destroy_version
|
79
|
+
versionate_as("destroy")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
ActiveRecord::Base.send :include, DejaVue
|
@@ -0,0 +1,184 @@
|
|
1
|
+
class History
|
2
|
+
include MongoMapper::Document
|
3
|
+
|
4
|
+
key :versionable_type, String, :required => true, :index => true
|
5
|
+
key :versionable_id, String, :required => true, :index => true
|
6
|
+
key :kind_of_version, String, :required => true
|
7
|
+
key :version_attributes, Hash, :required => true
|
8
|
+
key :version_associations,Hash, :index => true
|
9
|
+
key :extra_info, Hash # para armazenar informações relacionadas, como tag_list
|
10
|
+
key :changed_fields, Array
|
11
|
+
key :who_did_it, String
|
12
|
+
timestamps!
|
13
|
+
ensure_index :created_at
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
# Validations
|
18
|
+
#
|
19
|
+
validates_true_for :version_attributes, :logic => lambda { !version_attributes.empty? }
|
20
|
+
|
21
|
+
#
|
22
|
+
# Constants
|
23
|
+
#
|
24
|
+
|
25
|
+
DEFAULT_IGNORED_FIELDS = ["updated_at", "created_at"]
|
26
|
+
|
27
|
+
KIND_OF_VERSIONS = %w( create update destroy )
|
28
|
+
|
29
|
+
#
|
30
|
+
# Class Methods
|
31
|
+
#
|
32
|
+
|
33
|
+
def self.versionate(object, kind_of_version, options={})
|
34
|
+
return false if object.blank?
|
35
|
+
History.new.create_version(object, kind_of_version, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# marreta para teste rodar, por causa do i18n do remarkable, FIXME
|
39
|
+
def self.human_name(foo)
|
40
|
+
"History"
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Instance Methods
|
45
|
+
#
|
46
|
+
|
47
|
+
def create_version(object, kind_of_version, options={})
|
48
|
+
self.ignored_fields= options[:ignore] if options[:ignore]
|
49
|
+
self.who_did_it = check_and_retrieve_user(options[:who_did_it]) if options[:who_did_it]
|
50
|
+
self.kind_of_version = kind_of_version
|
51
|
+
self.versionable_type = object.class.name
|
52
|
+
self.versionable_id = object.id.to_s
|
53
|
+
|
54
|
+
unless self.kind_of_version == "destroy"
|
55
|
+
return false unless self.has_changed?(object)
|
56
|
+
end
|
57
|
+
self.version_attributes = attributes_filter(object.attributes)
|
58
|
+
store_version_associations object, options
|
59
|
+
store_extra_info(object, options)
|
60
|
+
self.save
|
61
|
+
end
|
62
|
+
|
63
|
+
# Rebuild the versionated object.
|
64
|
+
# Do not rebuild if it's not saved
|
65
|
+
def version
|
66
|
+
return nil if self.new_record?
|
67
|
+
@version ||= recreate_version_object
|
68
|
+
end
|
69
|
+
|
70
|
+
# fields that whose change won't cause a history trace
|
71
|
+
def ignored_fields
|
72
|
+
@ignored_fields || DEFAULT_IGNORED_FIELDS
|
73
|
+
end
|
74
|
+
|
75
|
+
def ignored_fields=(fields_array)
|
76
|
+
fields = nil
|
77
|
+
fields = fields_array if fields_array.is_a?(Array)
|
78
|
+
fields = [fields_array.to_s] if ( fields_array.is_a?(String) || fields_array.is_a?(Symbol) )
|
79
|
+
return false unless fields.is_a?(Array)
|
80
|
+
@ignored_fields = ( DEFAULT_IGNORED_FIELDS + fields ).uniq
|
81
|
+
end
|
82
|
+
|
83
|
+
# return true id object has changed
|
84
|
+
def has_changed?(object)
|
85
|
+
return false unless object.try(:version_changes)
|
86
|
+
!store_changed_fields(object).empty?
|
87
|
+
end
|
88
|
+
|
89
|
+
def next_version
|
90
|
+
History.where(:created_at.gte => self.created_at, # could have the same creation date, as long it's not the same object
|
91
|
+
:id.ne => self.id, # ne => not equal to
|
92
|
+
:versionable_type => self.versionable_type,
|
93
|
+
:versionable_id => self.versionable_id).sort(:created_at.asc).first
|
94
|
+
end
|
95
|
+
|
96
|
+
def previous_version
|
97
|
+
History.where(:created_at.lte => self.created_at, # could have the same creation date, as long it's not the same object
|
98
|
+
:id.ne => self.id, # ne => not equal to
|
99
|
+
:versionable_type => self.versionable_type,
|
100
|
+
:versionable_id => self.versionable_id).sort(:created_at.desc).first
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
|
105
|
+
# Retrieve the versionated object
|
106
|
+
def recreate_version_object
|
107
|
+
model = recreate_model(self.versionable_type, self.version_attributes)
|
108
|
+
model.id = self.versionable_id
|
109
|
+
|
110
|
+
self.version_associations.each do |associated_object, associated_object_attributes|
|
111
|
+
model.try "#{associated_object.to_s}=", recreate_model(associated_object, associated_object_attributes)
|
112
|
+
end
|
113
|
+
update_fields model, self.extra_info
|
114
|
+
model
|
115
|
+
end
|
116
|
+
|
117
|
+
# recreates object from a class name and its attributes
|
118
|
+
def recreate_model(class_name, attributes_hash={})
|
119
|
+
associated_klass = class_name.to_s.camelize.constantize.new
|
120
|
+
update_fields associated_klass, attributes_hash
|
121
|
+
associated_klass
|
122
|
+
end
|
123
|
+
|
124
|
+
# updates values for an instantiated class
|
125
|
+
def update_fields(class_object, attributes_hash={})
|
126
|
+
attributes_hash.each do |key, value|
|
127
|
+
class_object.send "#{key.to_s}=", value
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# If user is a Class, try to retrieve user
|
132
|
+
# from an Authlogic User Session.
|
133
|
+
# If it is an Authlogic object, return the user id.
|
134
|
+
#
|
135
|
+
# Else it returns the current object.
|
136
|
+
def check_and_retrieve_user(user)
|
137
|
+
if user.is_a? Class
|
138
|
+
begin
|
139
|
+
user.find.user.id
|
140
|
+
rescue
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
else
|
144
|
+
user
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def store_version_associations(object, options)
|
149
|
+
self.version_associations = {}
|
150
|
+
options[:associations].each do |association|
|
151
|
+
self.version_associations.store(association, attributes_filter( object.try(association).attributes) ) if object.try(association)
|
152
|
+
end if options[:associations]
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
def store_changed_fields(object)
|
157
|
+
self.changed_fields = object.version_changes - self.ignored_fields if self.ignored_fields.is_a?(Array)
|
158
|
+
self.changed_fields
|
159
|
+
end
|
160
|
+
|
161
|
+
def store_extra_info(object, options)
|
162
|
+
self.extra_info = {}
|
163
|
+
options[:extra_info_fields].each do |extra_info|
|
164
|
+
self.extra_info.store( extra_info, object.try(extra_info) ) if object.try(extra_info)
|
165
|
+
end if options[:extra_info_fields]
|
166
|
+
self.extra_info = attributes_filter(self.extra_info)
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
|
+
def attributes_filter(key_value={})
|
171
|
+
key_value.each do |k,v|
|
172
|
+
key_value[k]=v.to_s if key_value[k].is_a?(Date)
|
173
|
+
end
|
174
|
+
key_value.each do |k,v|
|
175
|
+
key_value[k]=v.utc.to_s if key_value[k].is_a?(Time)
|
176
|
+
end
|
177
|
+
key_value.each do |k,v|
|
178
|
+
key_value[k]=v.to_f if key_value[k].is_a?(BigDecimal)
|
179
|
+
end
|
180
|
+
|
181
|
+
key_value
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
data/rails/init.rb
ADDED
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deja_vue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Riopro Informatica Ltda
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-11 00:00:00 -03:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: DejaVue -> Ruby versioning Gem using MongoDB as backend
|
23
|
+
email: riopro@riopro.com.br
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.rdoc
|
30
|
+
- lib/deja_vue.rb
|
31
|
+
files:
|
32
|
+
- Manifest
|
33
|
+
- README.rdoc
|
34
|
+
- Rakefile
|
35
|
+
- deja_vue.gemspec
|
36
|
+
- lib/deja_vue.rb
|
37
|
+
- lib/deja_vue/has_deja_vue.rb
|
38
|
+
- lib/deja_vue/history.rb
|
39
|
+
- rails/init.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/riopro/deja_vue
|
42
|
+
licenses: []
|
43
|
+
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --line-numbers
|
47
|
+
- --inline-source
|
48
|
+
- --title
|
49
|
+
- deja_vue
|
50
|
+
- --main
|
51
|
+
- README.rdoc
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 11
|
69
|
+
segments:
|
70
|
+
- 1
|
71
|
+
- 2
|
72
|
+
version: "1.2"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project: deja_vue
|
76
|
+
rubygems_version: 1.3.7
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Keep track of your models changing history, using MongoDB as backend
|
80
|
+
test_files: []
|
81
|
+
|