deja_vue 0.1.2
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/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
|
+
|