footprint 1.0.0.pre → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -1
- data/.rspec +1 -1
- data/README.md +120 -9
- data/Rakefile +20 -0
- data/footprint.gemspec +8 -4
- data/lib/footprint.rb +12 -4
- data/lib/footprint/impression.rb +31 -0
- data/lib/footprint/leave_a_track.rb +49 -0
- data/lib/footprint/version.rb +1 -1
- data/lib/generators/footprint/document/document_generator.rb +26 -0
- data/spec/factories.rb +55 -0
- data/spec/footprint/impression_spec.rb +60 -0
- data/spec/footprint/track_spec.rb +75 -0
- data/spec/footprint_spec.rb +11 -0
- data/spec/generators/rspec/document/document_generator_spec.rb +19 -0
- data/spec/schema/documents/leopard_footprint.rb +18 -0
- data/spec/schema/documents/yeti_footprint.rb +19 -0
- data/spec/schema/migrations/001_create_yetis.rb +20 -0
- data/spec/schema/migrations/002_create_leopards.rb +19 -0
- data/spec/schema/models/leopard.rb +3 -0
- data/spec/schema/models/yeti.rb +4 -0
- data/spec/spec_helper.rb +78 -0
- metadata +87 -10
- data/spec/lib/footprint_spec.rb +0 -7
data/.gitignore
CHANGED
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
--color
|
2
|
-
--format
|
2
|
+
--format documentation
|
data/README.md
CHANGED
@@ -1,24 +1,122 @@
|
|
1
1
|
# Footprint
|
2
2
|
|
3
|
-
|
3
|
+
**Footprint** is a **MongoDB-backed** versioning system for those **Big Applications** which have a need for storing
|
4
|
+
|
5
|
+
* Huge amounts of Version data for auditing purposes
|
6
|
+
* All states of a record for analysis by BI tools
|
7
|
+
|
8
|
+
But struggle because they cannot
|
9
|
+
|
10
|
+
* Use a simple database system due to performance constraints
|
11
|
+
* Shift to a NoSQL DB completely because of transaction requirements
|
12
|
+
|
13
|
+
Footprint integrates seamlessly into your ActiveRecord-driven Rails Application, effectively converting it into a Hybrid application, storing only version data (or **Impressions**, as they are called) in a MongoDB database.
|
4
14
|
|
5
15
|
## Installation
|
6
16
|
|
7
|
-
Add
|
17
|
+
Add Footprint to your Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem "footprint", "1.0.0.rc2"
|
21
|
+
```
|
22
|
+
|
23
|
+
Generate mongoid.yml if you don't have one in your project already
|
24
|
+
|
25
|
+
```bash
|
26
|
+
$ rails g mongoid:config
|
27
|
+
```
|
28
|
+
|
29
|
+
Modify your config/application.rb to use ActiveRecord generators by default
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
config.generators do |g|
|
33
|
+
g.orm :active_record
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
Add a special lookup for Mongoid gem: (will be removed when Mongoid 3.1.0 is released)
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
gem "mongoid", :git => 'git@github.com:mongoid/mongoid.git'
|
41
|
+
```
|
42
|
+
|
43
|
+
## Setting Up Documents for your ActiveRecord models
|
44
|
+
|
45
|
+
Generate a document from an existing ActiveRecord Model
|
46
|
+
|
47
|
+
```bash
|
48
|
+
$ rails g footprint:document User
|
49
|
+
```
|
50
|
+
|
51
|
+
Add `leave_a_track` to your Model class
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class User < ActiveRecord::Base
|
55
|
+
leave_a_track
|
56
|
+
attr_accessible :name, :dob
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
## Handling Impressions
|
8
61
|
|
9
|
-
|
62
|
+
### Querying
|
10
63
|
|
11
|
-
|
64
|
+
Impressions (a.k.a versions) of a record are accessible through `impressions` attribute
|
12
65
|
|
13
|
-
|
66
|
+
```ruby
|
67
|
+
u = User.find(1)
|
68
|
+
u.impressions
|
69
|
+
```
|
14
70
|
|
15
|
-
|
71
|
+
### Collecting values
|
16
72
|
|
17
|
-
|
73
|
+
Collecting specific values in Impressions too is very similar to normal AR model behavior
|
18
74
|
|
19
|
-
|
75
|
+
```ruby
|
76
|
+
u = User.find(1)
|
77
|
+
u.impressons.collect { |imp| imp.name }
|
78
|
+
```
|
20
79
|
|
21
|
-
|
80
|
+
### Reviving a copy of the parent
|
81
|
+
|
82
|
+
Converting an Impression to an ActiveRecord model, to mirror the parent can be done via `as_parent` method
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
User.create("name" => "Subhash", "join_date" => 2.days.ago) # User:1
|
86
|
+
u = User.find(1)
|
87
|
+
u.impressions.count # 1
|
88
|
+
u.name = "Subhash Bhushan"
|
89
|
+
u.save
|
90
|
+
u.impressions.count # 2
|
91
|
+
User copy_of_user_1 = u.impressions.last.as_parent
|
92
|
+
```
|
93
|
+
|
94
|
+
### Sorting
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
p.impressions.asc(:updated_at)
|
98
|
+
p.impressions.order_by(:updated_at.asc)
|
99
|
+
p.impressions.desc(:updated_at)
|
100
|
+
```
|
101
|
+
|
102
|
+
For a complete list of sorting options: [Mongoid Sorting](http://mongoid.org/en/origin/docs/options.html#sorting)
|
103
|
+
|
104
|
+
### Pagination
|
105
|
+
|
106
|
+
`Kaminari` is the preferred way to paginate mongoid documents. `will_paginate_mongoid` gem is an option for those who already use `will_paginate`.
|
107
|
+
* [will_paginate_mongoid](https://github.com/lucasas/will_paginate_mongoid)
|
108
|
+
* [kaminari](https://github.com/amatsuda/kaminari) ([Example](http://code.dblock.org/mongoid-202-dropped-pagination-kaminari))
|
109
|
+
|
110
|
+
## Setting up MongoDB
|
111
|
+
|
112
|
+
Getting a MongoDB instance up and running is pretty simple.
|
113
|
+
Visit [Installation Guides](http://docs.mongodb.org/manual/installation/) to set up one for your OS.
|
114
|
+
|
115
|
+
The tutorial [Getting Started with MongoDB Development](http://docs.mongodb.org/manual/tutorial/getting-started/) explains basics of connecting to a MongoDB instance and querying on collections
|
116
|
+
|
117
|
+
## Known Issues
|
118
|
+
|
119
|
+
* If you get a message that "ActiveRecord model 'Project' was not found" while generating a document, do `rake db:migrate` and then try generating the document again.
|
22
120
|
|
23
121
|
## Contributing
|
24
122
|
|
@@ -27,3 +125,16 @@ TODO: Write usage instructions here
|
|
27
125
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
126
|
4. Push to the branch (`git push origin my-new-feature`)
|
29
127
|
5. Create new Pull Request
|
128
|
+
|
129
|
+
## Inspirations
|
130
|
+
|
131
|
+
* [Paper Trail](https://github.com/airblade/paper_trail)
|
132
|
+
* [Mongoid](mongoid.org/en/mongoid/index.html)
|
133
|
+
|
134
|
+
## Resources
|
135
|
+
|
136
|
+
* MongoDB
|
137
|
+
* [Why MongoDB](https://speakerdeck.com/jnunemaker/why-mongodb-is-awesome)
|
138
|
+
* [Installation](http://docs.mongodb.org/manual/installation/)
|
139
|
+
* [Hybrid Applications](http://www.slideshare.net/spf13/hybrid-mongodb-and-rdbms-applications)
|
140
|
+
* [Versioning Strategies](http://blog.jondh.me.uk/2011/11/relational-database-versioning-strategies/)
|
data/Rakefile
CHANGED
@@ -1 +1,21 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require 'active_record'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
namespace :db do
|
6
|
+
desc "Migrate the database through scripts in spec/schema/migrations"
|
7
|
+
task :prepare => :environment do
|
8
|
+
ActiveRecord::Migration.verbose = true
|
9
|
+
|
10
|
+
MIGRATIONS = File.join(File.dirname(__FILE__), "spec/schema/migrations")
|
11
|
+
ActiveRecord::Migrator.migrate(MIGRATIONS)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :environment do
|
15
|
+
Dir.mkdir("db") unless File.exist?("db")
|
16
|
+
File.delete('db/fpdb') if File.exist?('db/fpdb')
|
17
|
+
|
18
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: "db/fpdb"
|
19
|
+
ActiveRecord::Base.logger = Logger.new(File.open('db/database.log', 'a'))
|
20
|
+
end
|
21
|
+
end
|
data/footprint.gemspec
CHANGED
@@ -8,17 +8,21 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Footprint::VERSION
|
9
9
|
gem.authors = ["Subhash Bhushan"]
|
10
10
|
gem.email = ["subhash.bhushan@stratalabs.in"]
|
11
|
-
gem.description = %q{Big Data Versioning for those seriously Big
|
12
|
-
gem.summary = %q{Big Data Versioning for those seriously Big
|
11
|
+
gem.description = %q{Big Data Versioning for those seriously Big Applications}
|
12
|
+
gem.summary = %q{Big Data Versioning for those seriously Big Applications}
|
13
13
|
gem.homepage = ""
|
14
|
+
gem.license = "MIT"
|
14
15
|
|
15
16
|
gem.add_development_dependency "rspec", "~> 2.12"
|
16
17
|
gem.add_development_dependency "guard-rspec"
|
17
18
|
gem.add_development_dependency "growl", "~> 1.0.3"
|
18
19
|
gem.add_development_dependency "rb-fsevent", "~> 0.9.1"
|
19
|
-
gem.add_development_dependency "
|
20
|
+
gem.add_development_dependency "factory_girl"
|
21
|
+
gem.add_development_dependency "sqlite3"
|
22
|
+
gem.add_development_dependency "ammeter"
|
20
23
|
|
21
|
-
gem.
|
24
|
+
gem.add_dependency "mongoid", "~> 3.0"
|
25
|
+
gem.add_dependency "activerecord", "~> 3.2.0"
|
22
26
|
|
23
27
|
gem.files = `git ls-files`.split($/)
|
24
28
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
data/lib/footprint.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
require "footprint/version"
|
2
|
+
require "footprint/impression"
|
3
|
+
require "footprint/leave_a_track"
|
4
|
+
|
5
|
+
require "generators/footprint/document/document_generator"
|
6
|
+
|
7
|
+
require "active_support/inflector"
|
2
8
|
|
3
9
|
module Footprint
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load(:active_record) do
|
14
|
+
include Footprint::Model
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
|
3
|
+
module Footprint
|
4
|
+
class Impression
|
5
|
+
include Mongoid::Document
|
6
|
+
|
7
|
+
def self.leave(model, phase)
|
8
|
+
self.create attributes_for_impression(model).merge(mandatory_attributes(model)).merge(:phase => phase)
|
9
|
+
end
|
10
|
+
|
11
|
+
def as_parent
|
12
|
+
parent = Object.const_get(parent_type).new (self.attributes).except("_id", "_type", "parent_id", "parent_type", "phase", "created_at", "updated_at")
|
13
|
+
|
14
|
+
#id,created_at and updated_at is attr-protected, so no mass-assignment
|
15
|
+
parent.id = self.parent_id
|
16
|
+
parent.created_at = self.created_at
|
17
|
+
parent.updated_at = self.updated_at
|
18
|
+
parent
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def self.mandatory_attributes(model)
|
24
|
+
Hash.new.merge(:parent_id => model.id, :parent_type => model.class.name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.attributes_for_impression(model)
|
28
|
+
model.attributes.except(:id)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Footprint
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
def leave_a_track
|
11
|
+
send :include, InstanceMethods
|
12
|
+
|
13
|
+
class_attribute :impressions_association_name
|
14
|
+
self.impressions_association_name = self.name + "Footprint"
|
15
|
+
|
16
|
+
class_attribute :impressions_class
|
17
|
+
self.impressions_class = Object.const_get(self.impressions_association_name)
|
18
|
+
|
19
|
+
class_attribute :leaving_a_track
|
20
|
+
self.leaving_a_track = true
|
21
|
+
|
22
|
+
after_create :impression_of_create
|
23
|
+
after_update :impression_of_update
|
24
|
+
after_destroy :impression_of_destroy
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
def impressions
|
31
|
+
impressions_class.where(parent_id: self.id)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def impression_of_create
|
37
|
+
impressions_class.leave self, "create"
|
38
|
+
end
|
39
|
+
|
40
|
+
def impression_of_update
|
41
|
+
impressions_class.leave(self, "update") if changed?
|
42
|
+
end
|
43
|
+
|
44
|
+
def impression_of_destroy
|
45
|
+
impressions_class.leave self, "destroy"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/footprint/version.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Footprint
|
4
|
+
module Generators
|
5
|
+
class DocumentGenerator < Rails::Generators::Base
|
6
|
+
argument :model_name, :type => :string, :desc => "Active Record model to generate Document from"
|
7
|
+
|
8
|
+
def run_mongoid_generator
|
9
|
+
begin
|
10
|
+
#TODO Provide option to prevent generation of test unit files (--skip-test-unit)
|
11
|
+
attributes = Object.const_get(model_name).columns_hash.except("id").values.collect { |c| c.name + ":" + type_class(c.sql_type) }.join(" ") + " phase:string parent_id:integer parent_type:string"
|
12
|
+
generate "mongoid:model", "#{model_name.camelize}Footprint #{attributes} --parent Footprint::Impression --collection=#{model_name.downcase.pluralize}"
|
13
|
+
rescue Exception => e
|
14
|
+
Logger.new(STDOUT).error("ActiveRecord model \"#{model_name.to_s}\" was not found")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def type_class(sql_type)
|
21
|
+
return "string" if sql_type.to_s == "varchar(255)"
|
22
|
+
return sql_type.downcase
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :yeti do
|
3
|
+
sequence(:name) { |n| "Yeti#{n}" }
|
4
|
+
notes "Yet to Start Tracking"
|
5
|
+
region "Himalayas"
|
6
|
+
|
7
|
+
trait :male do
|
8
|
+
gender "Male"
|
9
|
+
end
|
10
|
+
trait :female do
|
11
|
+
gender "Female"
|
12
|
+
end
|
13
|
+
|
14
|
+
trait :dangerous do
|
15
|
+
name "Ivan"
|
16
|
+
aggression 9
|
17
|
+
mass 9
|
18
|
+
strength 10
|
19
|
+
height 325
|
20
|
+
weight 1400
|
21
|
+
region "Himalayas"
|
22
|
+
notes "Stay away and take evasive measures - Extremely dangerous"
|
23
|
+
end
|
24
|
+
trait :tameable do
|
25
|
+
name "Johanne"
|
26
|
+
aggression 1
|
27
|
+
mass 8
|
28
|
+
strength 6
|
29
|
+
height 310
|
30
|
+
weight 1100
|
31
|
+
region "Amazon"
|
32
|
+
notes "Gentle and harmless"
|
33
|
+
end
|
34
|
+
trait :huge do
|
35
|
+
name "Duncan"
|
36
|
+
aggression 5
|
37
|
+
mass 10
|
38
|
+
strength 9
|
39
|
+
height 375
|
40
|
+
weight 1700
|
41
|
+
region "Andes"
|
42
|
+
notes "Unknown behavior - Be wary of proximity"
|
43
|
+
end
|
44
|
+
|
45
|
+
factory :male_yeti, traits: [:male]
|
46
|
+
factory :female_yeti, traits: [:female]
|
47
|
+
|
48
|
+
factory :male_dangerous_yeti, traits: [:male, :dangerous]
|
49
|
+
factory :female_tameable_yeti, traits: [:female, :tameable]
|
50
|
+
factory :male_huge_yeti, traits: [:male, :huge]
|
51
|
+
factory :female_dangerous_yeti, traits: [:female, :dangerous, name: "Victoria"]
|
52
|
+
factory :male_tameable_yeti, traits: [:male, :tameable, name: "Beethoven"]
|
53
|
+
factory :female_huge_yeti, traits: [:female, :huge, name: "Hidimbi"]
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Footprint::Impression do
|
4
|
+
before(:each) do
|
5
|
+
@yeti = FactoryGirl.create(:yeti)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "is linked" do
|
9
|
+
it "to parent" do
|
10
|
+
expect(@yeti.impressions.first.parent_id).to eq(@yeti.id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "shares attributes of parent" do
|
15
|
+
it "like name" do
|
16
|
+
expect(@yeti.impressions.first.name).to eq(@yeti.name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "records mandatory criteria" do
|
21
|
+
it "like parent_id" do
|
22
|
+
expect(@yeti.impressions.first.parent_id).to eq(@yeti.id)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "like parent_type" do
|
26
|
+
expect(@yeti.impressions.first.parent_type).to eq(@yeti.class.name)
|
27
|
+
end
|
28
|
+
|
29
|
+
context "like phase" do
|
30
|
+
it "of birth" do
|
31
|
+
expect(@yeti.impressions.first.phase).to eq("create")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "of growth" do
|
35
|
+
@yeti.name = "Changed"
|
36
|
+
@yeti.save
|
37
|
+
expect(@yeti.impressions.last.phase).to eq("update")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "of death" do
|
41
|
+
@yeti.destroy
|
42
|
+
expect(@yeti.impressions.last.phase).to eq("destroy")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "returns" do
|
48
|
+
it "an impression in general cases" do
|
49
|
+
expect(@yeti.impressions.first.class).to be_instance_of(YetiFootprint.class)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "the parent type when asked" do
|
53
|
+
expect(@yeti.impressions.first.as_parent).to be_instance_of(Yeti)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns its parent when asked" do
|
57
|
+
expect(@yeti.impressions.first.as_parent.id).to eq(@yeti.impressions.first.parent_id)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Footprint::Model do
|
4
|
+
before(:each) do
|
5
|
+
@yeti = FactoryGirl.build(:yeti)
|
6
|
+
end
|
7
|
+
|
8
|
+
context "during its lifetime" do
|
9
|
+
it "can be conceived" do
|
10
|
+
expect( @yeti ).to be_valid
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can be born" do
|
14
|
+
expect{ @yeti.save }.to change{Yeti.count}.by(1)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "can grow" do
|
18
|
+
@yeti.save
|
19
|
+
expect{ @yeti.update_attributes(:height => 100) }.not_to change{Yeti.count}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can die" do
|
23
|
+
@yeti.save
|
24
|
+
expect { @yeti.destroy }.to change{Yeti.count}.by(-1)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with tracking enabled" do
|
29
|
+
it "can be monitored" do
|
30
|
+
expect( Yeti.new ).to be_leaving_a_track
|
31
|
+
end
|
32
|
+
|
33
|
+
context "while alive" do
|
34
|
+
context "will leave an impression" do
|
35
|
+
it "when born" do
|
36
|
+
expect { @yeti.save }.to change{YetiFootprint.count}.by(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "when growing" do
|
40
|
+
@yeti.save
|
41
|
+
@yeti.name = @yeti.name + "Changed"
|
42
|
+
expect { @yeti.save }.to change{YetiFootprint.count}.by(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "when dead" do
|
46
|
+
@yeti.save
|
47
|
+
expect { @yeti.destroy }.to change{YetiFootprint.count}.by(1)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when saved multiple times" do
|
52
|
+
it "will store multiple impressions" do
|
53
|
+
expect {
|
54
|
+
@yeti.save
|
55
|
+
@yeti.name = @yeti.name + "Changed"
|
56
|
+
@yeti.save
|
57
|
+
}.to change{YetiFootprint.count}.by(2)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "will not leave an impression" do
|
62
|
+
it "if there is no growth" do
|
63
|
+
@yeti.save
|
64
|
+
expect { @yeti.save }.to_not change{YetiFootprint.count}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "with no tracking" do
|
71
|
+
it "does not respond to leaving_a_track" do
|
72
|
+
expect(Leopard.new).to_not respond_to(:leaving_a_track)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
# Generators are not automatically loaded by Rails
|
4
|
+
require 'generators/footprint/document/document_generator'
|
5
|
+
|
6
|
+
describe Footprint::Generators::DocumentGenerator do
|
7
|
+
destination File.expand_path("../../../../../tmp", __FILE__)
|
8
|
+
before { prepare_destination }
|
9
|
+
|
10
|
+
describe "with valid ActiveRecord model" do
|
11
|
+
describe "generates a document" do
|
12
|
+
# run_generator %w(Yeti)
|
13
|
+
# subject { file('app/models/yeti_footprint.rb') }
|
14
|
+
#it { should exist }
|
15
|
+
# TODO Fix problem of 'scope/rails' not found in spec
|
16
|
+
it "needs a fix problem 'script/rails' not found"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class LeopardFootprint
|
2
|
+
include Mongoid::Document
|
3
|
+
store_in collection: "leopards"
|
4
|
+
field :id, type: Integer
|
5
|
+
field :name, type: String
|
6
|
+
field :region, type: String
|
7
|
+
field :height, type: Integer
|
8
|
+
field :weight, type: Integer
|
9
|
+
field :strength, type: Integer
|
10
|
+
field :speed, type: Integer
|
11
|
+
field :aggression, type: Integer
|
12
|
+
field :notes, type: String
|
13
|
+
field :created_at, type: Time
|
14
|
+
field :updated_at, type: Time
|
15
|
+
field :phase, type: String
|
16
|
+
field :parent_id, type: Integer
|
17
|
+
field :parent_type, type: String
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class YetiFootprint < Footprint::Impression
|
2
|
+
include Mongoid::Document
|
3
|
+
store_in collection: "yetis"
|
4
|
+
field :id, type: Integer
|
5
|
+
field :name, type: String
|
6
|
+
field :gender, type: String
|
7
|
+
field :region, type: String
|
8
|
+
field :height, type: Integer
|
9
|
+
field :weight, type: Integer
|
10
|
+
field :strength, type: Integer
|
11
|
+
field :aggression, type: Integer
|
12
|
+
field :mass, type: Integer
|
13
|
+
field :notes, type: String
|
14
|
+
field :created_at, type: Time
|
15
|
+
field :updated_at, type: Time
|
16
|
+
field :phase, type: String
|
17
|
+
field :parent_id, type: Integer
|
18
|
+
field :parent_type, type: String
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateYetis < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :yetis, :force => true do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :gender
|
6
|
+
t.string :region
|
7
|
+
t.integer :height
|
8
|
+
t.integer :weight
|
9
|
+
t.integer :strength
|
10
|
+
t.integer :aggression
|
11
|
+
t.integer :mass
|
12
|
+
t.string :notes
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :yetis
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateLeopards < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :leopards, :force => true do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :region
|
6
|
+
t.integer :height
|
7
|
+
t.integer :weight
|
8
|
+
t.integer :strength
|
9
|
+
t.integer :speed
|
10
|
+
t.integer :aggression
|
11
|
+
t.string :notes
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
drop_table :leopards
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,68 @@
|
|
1
|
+
#Required for ammeter - start
|
2
|
+
require 'rails/all'
|
3
|
+
|
4
|
+
module Footprint
|
5
|
+
class Application < ::Rails::Application
|
6
|
+
end
|
7
|
+
end
|
8
|
+
#Required for ammeter - end
|
9
|
+
|
10
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
11
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
12
|
+
|
13
|
+
MODELS = File.join(File.dirname(__FILE__), "schema/models")
|
14
|
+
DOCUMENTS = File.join(File.dirname(__FILE__), "schema/documents")
|
15
|
+
$LOAD_PATH.unshift(MODELS)
|
16
|
+
$LOAD_PATH.unshift(DOCUMENTS)
|
17
|
+
|
1
18
|
require 'footprint'
|
19
|
+
require 'active_record'
|
20
|
+
require 'ammeter/init'
|
21
|
+
require 'factory_girl'
|
22
|
+
require "mongoid"
|
23
|
+
|
24
|
+
# Autoload every model for the test suite that sits in spec/schema/models.
|
25
|
+
Dir[ File.join(MODELS, "*.rb") ].sort.each do |file|
|
26
|
+
name = File.basename(file, ".rb")
|
27
|
+
autoload name.camelize.to_sym, name
|
28
|
+
end
|
29
|
+
|
30
|
+
# Autoload every document for the test suite that sits in spec/schema/documents.
|
31
|
+
Dir[ File.join(DOCUMENTS, "*.rb") ].sort.each do |file|
|
32
|
+
name = File.basename(file, ".rb")
|
33
|
+
autoload name.camelize.to_sym, name
|
34
|
+
end
|
35
|
+
|
36
|
+
# To load FactoryGirl in a non-rails environment
|
37
|
+
FactoryGirl.find_definitions
|
38
|
+
|
39
|
+
# Mongoid Configuration - start
|
40
|
+
# These environment variables can be set if wanting to test against a database
|
41
|
+
# that is not on the local machine.
|
42
|
+
ENV["MONGOID_SPEC_HOST"] ||= "localhost"
|
43
|
+
ENV["MONGOID_SPEC_PORT"] ||= "27017"
|
44
|
+
|
45
|
+
# These are used when creating any connection in the test suite.
|
46
|
+
HOST = ENV["MONGOID_SPEC_HOST"]
|
47
|
+
PORT = ENV["MONGOID_SPEC_PORT"].to_i
|
48
|
+
|
49
|
+
# Moped.logger.level = Logger::DEBUG
|
50
|
+
# Mongoid.logger.level = Logger::DEBUG
|
51
|
+
|
52
|
+
# When testing locally we use the database named mongoid_test. However when
|
53
|
+
# tests are running in parallel on Travis we need to use different database
|
54
|
+
# names for each process running since we do not have transactions and want a
|
55
|
+
# clean slate before each spec run.
|
56
|
+
def database_id
|
57
|
+
"mongoid_test"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set the database that the spec suite connects to.
|
61
|
+
Mongoid.configure do |config|
|
62
|
+
config.allow_dynamic_fields = false
|
63
|
+
config.connect_to(database_id, consistency: :strong)
|
64
|
+
end
|
65
|
+
# Mongoid Configuration - end
|
2
66
|
|
3
67
|
RSpec.configure do |config|
|
4
68
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
@@ -10,4 +74,18 @@ RSpec.configure do |config|
|
|
10
74
|
# the seed, which is printed after each run.
|
11
75
|
# --seed 1234
|
12
76
|
config.order = 'random'
|
77
|
+
|
78
|
+
config.expect_with :rspec do |c|
|
79
|
+
c.syntax = :expect
|
80
|
+
end
|
81
|
+
|
82
|
+
#Initialize database connection
|
83
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: "db/fpdb"
|
84
|
+
|
85
|
+
#Initialize Mongoid
|
86
|
+
# Drop all collections and clear the identity map before each spec.
|
87
|
+
config.before(:each) do
|
88
|
+
Mongoid.purge!
|
89
|
+
Mongoid::IdentityMap.clear
|
90
|
+
end
|
13
91
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: footprint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.rc2
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -76,7 +76,39 @@ dependencies:
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: 0.9.1
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: factory_girl
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sqlite3
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: ammeter
|
80
112
|
requirement: !ruby/object:Gem::Requirement
|
81
113
|
none: false
|
82
114
|
requirements:
|
@@ -98,7 +130,23 @@ dependencies:
|
|
98
130
|
requirements:
|
99
131
|
- - ~>
|
100
132
|
- !ruby/object:Gem::Version
|
101
|
-
version: 3.0
|
133
|
+
version: '3.0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '3.0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: activerecord
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ~>
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 3.2.0
|
102
150
|
type: :runtime
|
103
151
|
prerelease: false
|
104
152
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,8 +154,8 @@ dependencies:
|
|
106
154
|
requirements:
|
107
155
|
- - ~>
|
108
156
|
- !ruby/object:Gem::Version
|
109
|
-
version: 3.
|
110
|
-
description: Big Data Versioning for those seriously Big
|
157
|
+
version: 3.2.0
|
158
|
+
description: Big Data Versioning for those seriously Big Applications
|
111
159
|
email:
|
112
160
|
- subhash.bhushan@stratalabs.in
|
113
161
|
executables: []
|
@@ -123,11 +171,28 @@ files:
|
|
123
171
|
- Rakefile
|
124
172
|
- footprint.gemspec
|
125
173
|
- lib/footprint.rb
|
174
|
+
- lib/footprint/impression.rb
|
175
|
+
- lib/footprint/leave_a_track.rb
|
126
176
|
- lib/footprint/version.rb
|
127
|
-
-
|
177
|
+
- lib/generators/footprint/.DS_Store
|
178
|
+
- lib/generators/footprint/document/document_generator.rb
|
179
|
+
- spec/factories.rb
|
180
|
+
- spec/footprint/impression_spec.rb
|
181
|
+
- spec/footprint/track_spec.rb
|
182
|
+
- spec/footprint_spec.rb
|
183
|
+
- spec/generators/.DS_Store
|
184
|
+
- spec/generators/rspec/.DS_Store
|
185
|
+
- spec/generators/rspec/document/document_generator_spec.rb
|
186
|
+
- spec/schema/documents/leopard_footprint.rb
|
187
|
+
- spec/schema/documents/yeti_footprint.rb
|
188
|
+
- spec/schema/migrations/001_create_yetis.rb
|
189
|
+
- spec/schema/migrations/002_create_leopards.rb
|
190
|
+
- spec/schema/models/leopard.rb
|
191
|
+
- spec/schema/models/yeti.rb
|
128
192
|
- spec/spec_helper.rb
|
129
193
|
homepage: ''
|
130
|
-
licenses:
|
194
|
+
licenses:
|
195
|
+
- MIT
|
131
196
|
post_install_message:
|
132
197
|
rdoc_options: []
|
133
198
|
require_paths:
|
@@ -149,7 +214,19 @@ rubyforge_project:
|
|
149
214
|
rubygems_version: 1.8.24
|
150
215
|
signing_key:
|
151
216
|
specification_version: 3
|
152
|
-
summary: Big Data Versioning for those seriously Big
|
217
|
+
summary: Big Data Versioning for those seriously Big Applications
|
153
218
|
test_files:
|
154
|
-
- spec/
|
219
|
+
- spec/factories.rb
|
220
|
+
- spec/footprint/impression_spec.rb
|
221
|
+
- spec/footprint/track_spec.rb
|
222
|
+
- spec/footprint_spec.rb
|
223
|
+
- spec/generators/.DS_Store
|
224
|
+
- spec/generators/rspec/.DS_Store
|
225
|
+
- spec/generators/rspec/document/document_generator_spec.rb
|
226
|
+
- spec/schema/documents/leopard_footprint.rb
|
227
|
+
- spec/schema/documents/yeti_footprint.rb
|
228
|
+
- spec/schema/migrations/001_create_yetis.rb
|
229
|
+
- spec/schema/migrations/002_create_leopards.rb
|
230
|
+
- spec/schema/models/leopard.rb
|
231
|
+
- spec/schema/models/yeti.rb
|
155
232
|
- spec/spec_helper.rb
|