data_works 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +529 -0
- data/Rakefile +6 -0
- data/_config.yml +1 -0
- data/bin/_guard-core +17 -0
- data/bin/guard +17 -0
- data/bin/rake +17 -0
- data/bin/rspec +17 -0
- data/data_works.gemspec +35 -0
- data/lib/data_works.rb +15 -0
- data/lib/data_works/base.rb +26 -0
- data/lib/data_works/config.rb +19 -0
- data/lib/data_works/exceptions.rb +6 -0
- data/lib/data_works/grafter.rb +51 -0
- data/lib/data_works/necessary_parent.rb +27 -0
- data/lib/data_works/parent_creator.rb +67 -0
- data/lib/data_works/railtie.rb +17 -0
- data/lib/data_works/relationships.rb +29 -0
- data/lib/data_works/stale_relationship_checker.rb +87 -0
- data/lib/data_works/version.rb +4 -0
- data/lib/data_works/visualization.rb +127 -0
- data/lib/data_works/works.rb +111 -0
- data/lib/tasks/bless.rake +6 -0
- data/spec/adding_records_spec.rb +118 -0
- data/spec/factories/factories.rb +78 -0
- data/spec/helper/data_works_spec_helper.rb +46 -0
- data/spec/helper/test_models.rb +106 -0
- data/spec/helper/test_tables.rb +120 -0
- data/spec/lib/data_faker.rb +37 -0
- data/spec/relationships_spec.rb +108 -0
- data/spec/restricted_parentage_spec.rb +35 -0
- data/spec/singluar_ending_in_es_spec.rb +31 -0
- data/spec/spec_helper.rb +33 -0
- metadata +292 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# data_works needs its own set of tables and ActiveRecord models to test with.
|
4
|
+
require_relative 'test_tables'
|
5
|
+
DataWorks::TestTables.create!
|
6
|
+
require_relative 'test_models'
|
7
|
+
|
8
|
+
module DataWorks
|
9
|
+
class StaleRelationshipChecker
|
10
|
+
def self.check!
|
11
|
+
true # For self testing purposes we can just state that the data model has not changed
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
DataWorks.configure do |config|
|
17
|
+
|
18
|
+
config.necessary_parents = {
|
19
|
+
address: [:pet_profile],
|
20
|
+
agency: [],
|
21
|
+
bell_toy: [{ :pet => :pet_bird }],
|
22
|
+
hooman_toy: [:pet],
|
23
|
+
kind: [],
|
24
|
+
pet: [],
|
25
|
+
pet_bird: [],
|
26
|
+
pet_food: [],
|
27
|
+
pet_profile: [:pet],
|
28
|
+
pet_sitter: [:agency, :kind],
|
29
|
+
pet_sitting_patronage: [:pet_sitter, :pet],
|
30
|
+
tag: [:pet],
|
31
|
+
toy: [:pet],
|
32
|
+
album: [],
|
33
|
+
product: [],
|
34
|
+
picture: [{ :imageable => :product }, :album],
|
35
|
+
}
|
36
|
+
|
37
|
+
config.autocreated_children = {
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
class TheDataWorks < DataWorks::Base
|
42
|
+
end
|
43
|
+
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.include FactoryGirl::Syntax::Methods
|
46
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
#*******************************************************************************
|
2
|
+
# For testing basic associations.
|
3
|
+
#*******************************************************************************
|
4
|
+
|
5
|
+
class Pet < ActiveRecord::Base
|
6
|
+
has_many :toys
|
7
|
+
has_one :pet_tag
|
8
|
+
has_one :pet_profile
|
9
|
+
has_one :address, through: :pet_profile
|
10
|
+
# We explicitly name the join table so that this code works with both Rails 3 and Rails 4.
|
11
|
+
has_and_belongs_to_many :pet_foods, join_table: 'pet_foods_pets'
|
12
|
+
has_many :pet_sitting_patronages
|
13
|
+
has_many :pet_sitters, through: :pet_sitting_patronages
|
14
|
+
end
|
15
|
+
|
16
|
+
class Toy < ActiveRecord::Base
|
17
|
+
validates :name, length: { minimum: 3 }
|
18
|
+
belongs_to :pet
|
19
|
+
end
|
20
|
+
|
21
|
+
class PetTag < ActiveRecord::Base
|
22
|
+
belongs_to :pet
|
23
|
+
end
|
24
|
+
|
25
|
+
class PetFood < ActiveRecord::Base
|
26
|
+
# Rails 3 expects the join table to be called pet_foods_pets
|
27
|
+
# Rails 4 expects the join table to be called pet_foods_pets
|
28
|
+
# We explicitly name the join table so that this code works with both Rails 3 and Rails 4.
|
29
|
+
has_and_belongs_to_many :pets, join_table: 'pet_foods_pets'
|
30
|
+
end
|
31
|
+
|
32
|
+
class Agency < ActiveRecord::Base
|
33
|
+
has_many :pet_sitters
|
34
|
+
end
|
35
|
+
|
36
|
+
class Kind < ActiveHash::Base
|
37
|
+
self.data = [
|
38
|
+
{:id => 1, :name => "Amateur"},
|
39
|
+
{:id => 2, :name => "Professional"}
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
class PetSitter < ActiveRecord::Base
|
44
|
+
extend ActiveHash::Associations::ActiveRecordExtensions
|
45
|
+
belongs_to :kind
|
46
|
+
belongs_to :agency
|
47
|
+
has_many :pet_sitting_patronages
|
48
|
+
has_many :pets, through: :pet_sitting_patronages
|
49
|
+
end
|
50
|
+
|
51
|
+
class PetSittingPatronage < ActiveRecord::Base
|
52
|
+
belongs_to :pet
|
53
|
+
belongs_to :pet_sitter
|
54
|
+
end
|
55
|
+
|
56
|
+
class PetProfile < ActiveRecord::Base
|
57
|
+
belongs_to :pet
|
58
|
+
has_one :address
|
59
|
+
end
|
60
|
+
|
61
|
+
class Address < ActiveRecord::Base
|
62
|
+
belongs_to :pet_profile
|
63
|
+
end
|
64
|
+
|
65
|
+
#*******************************************************************************
|
66
|
+
# For testing polymorphic associations and custom-named foreign keys.
|
67
|
+
#
|
68
|
+
|
69
|
+
class Picture < ActiveRecord::Base
|
70
|
+
belongs_to :imageable, polymorphic: true
|
71
|
+
belongs_to :album, foreign_key: 'picture_album_id'
|
72
|
+
end
|
73
|
+
|
74
|
+
class Product < ActiveRecord::Base
|
75
|
+
has_many :pictures, as: :imageable
|
76
|
+
end
|
77
|
+
|
78
|
+
class Album < ActiveRecord::Base
|
79
|
+
has_many :pictures, foreign_key: 'picture_album_id'
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
# #*******************************************************************************
|
85
|
+
# # For testing denormalized data structures.
|
86
|
+
# #
|
87
|
+
|
88
|
+
# class Owner < ActiveRecord::Base
|
89
|
+
# has_many :vehicles
|
90
|
+
# has_many :amenities # this is not normalized, you wouldn't normally do this
|
91
|
+
# end
|
92
|
+
|
93
|
+
# class Vehicle < ActiveRecord::Base
|
94
|
+
# has_many :amenities
|
95
|
+
# belongs_to :owner
|
96
|
+
# end
|
97
|
+
|
98
|
+
# class Amenity < ActiveRecord::Base
|
99
|
+
# belongs_to :vehicle
|
100
|
+
# belongs_to :owner # this is not normalized, you wouldn't normally do this
|
101
|
+
# has_one :warranty
|
102
|
+
# end
|
103
|
+
|
104
|
+
# class Warranty < ActiveRecord::Base
|
105
|
+
# belongs_to :amenity
|
106
|
+
# end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module DataWorks
|
2
|
+
class TestTables
|
3
|
+
|
4
|
+
def self.create!
|
5
|
+
return if @already_created_tables
|
6
|
+
ActiveRecord::Migration.class_eval do
|
7
|
+
suppress_messages do
|
8
|
+
|
9
|
+
create_table :agencies, force: true do |t|
|
10
|
+
t.string :name, null: false
|
11
|
+
t.timestamps null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table :addresses, force: true do |t|
|
15
|
+
t.string :street, null: false
|
16
|
+
t.string :city, null: false
|
17
|
+
t.string :state, null: false
|
18
|
+
t.integer :pet_profile_id, null: false
|
19
|
+
t.timestamps null: false
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :pet_foods, force: true do |t|
|
23
|
+
t.string :name, null: false
|
24
|
+
t.timestamps null: false
|
25
|
+
end
|
26
|
+
|
27
|
+
create_table :pet_foods_pets, force: true, id: false do |t|
|
28
|
+
t.integer :pet_id, null: false
|
29
|
+
t.integer :pet_food_id, null: false
|
30
|
+
end
|
31
|
+
|
32
|
+
create_table :pet_profiles, force: true do |t|
|
33
|
+
t.string :description, null: false
|
34
|
+
t.string :nickname
|
35
|
+
t.integer :pet_id, null: false
|
36
|
+
t.timestamps null: false
|
37
|
+
end
|
38
|
+
|
39
|
+
create_table :pet_sitters, force: true do |t|
|
40
|
+
t.string :name, null: false
|
41
|
+
t.integer :agency_id, null: false
|
42
|
+
t.integer :kind_id, null: false
|
43
|
+
t.timestamps null: false
|
44
|
+
end
|
45
|
+
|
46
|
+
create_table :pet_sitting_patronages, force: true do |t|
|
47
|
+
t.integer :pet_id, null: false
|
48
|
+
t.integer :pet_sitter_id, null: false
|
49
|
+
t.timestamps null: false
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table :pet_tags, force: true do |t|
|
53
|
+
t.string :registered_name, null: false
|
54
|
+
t.integer :pet_id, null: false
|
55
|
+
t.timestamps null: false
|
56
|
+
end
|
57
|
+
|
58
|
+
create_table :pets, force: true do |t|
|
59
|
+
t.string :name, null: false
|
60
|
+
t.string :kind, null: false
|
61
|
+
t.integer :birth_year
|
62
|
+
t.timestamps null: false
|
63
|
+
end
|
64
|
+
|
65
|
+
create_table :toys, force: true do |t|
|
66
|
+
t.string :name
|
67
|
+
t.string :kind
|
68
|
+
t.integer :pet_id
|
69
|
+
t.timestamps null: false
|
70
|
+
end
|
71
|
+
|
72
|
+
create_table :albums, force: true do |t|
|
73
|
+
t.string :name, null: false
|
74
|
+
t.timestamps null: false
|
75
|
+
end
|
76
|
+
|
77
|
+
create_table :pictures, force: true do |t|
|
78
|
+
t.string :name
|
79
|
+
t.integer :imageable_id
|
80
|
+
t.string :imageable_type
|
81
|
+
t.integer :picture_album_id
|
82
|
+
t.timestamps null: false
|
83
|
+
end
|
84
|
+
|
85
|
+
create_table :products, force: true do |t|
|
86
|
+
t.string :name
|
87
|
+
t.timestamps null: false
|
88
|
+
end
|
89
|
+
|
90
|
+
# create_table :amenities, force: true do |t|
|
91
|
+
# t.string :name
|
92
|
+
# t.integer :vehicle_id
|
93
|
+
# t.integer :owner_id
|
94
|
+
# t.timestamps null: false
|
95
|
+
# end
|
96
|
+
|
97
|
+
# create_table :owners, force: true do |t|
|
98
|
+
# t.string :name, null: false
|
99
|
+
# t.timestamps null: false
|
100
|
+
# end
|
101
|
+
|
102
|
+
# create_table :vehicles, force: true do |t|
|
103
|
+
# t.string :name
|
104
|
+
# t.integer :owner_id
|
105
|
+
# t.timestamps null: false
|
106
|
+
# end
|
107
|
+
|
108
|
+
# create_table :warranties, force: true do |t|
|
109
|
+
# t.string :name
|
110
|
+
# t.integer :amenity_id
|
111
|
+
# t.timestamps null: false
|
112
|
+
# end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
@already_created_tables = true
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Anywhere you need fake string data, use this method.
|
2
|
+
def fake_string
|
3
|
+
words = []
|
4
|
+
(rand(2)+2).times { words << DataFaker.hawaiian_word }
|
5
|
+
words.join(' ')
|
6
|
+
end
|
7
|
+
|
8
|
+
# Don't use this method, use fake_string instead.
|
9
|
+
# Ok, you win, in the situation you described fake_word
|
10
|
+
# makes more sense. Here you go, use it if you need to.
|
11
|
+
def fake_word
|
12
|
+
DataFaker.hawaiian_word
|
13
|
+
end
|
14
|
+
|
15
|
+
# Basically, this is the faker gem + a shrink ray.
|
16
|
+
class DataFaker
|
17
|
+
|
18
|
+
HAWAIIAN_VOWELS = %w( a e i o u )
|
19
|
+
|
20
|
+
HAWAIIAN_CONSONANTS = %w( h k l m n p t w )
|
21
|
+
|
22
|
+
def self.hawaiian_syllable
|
23
|
+
s = ''
|
24
|
+
if rand(100) < 90
|
25
|
+
s << HAWAIIAN_CONSONANTS.sample
|
26
|
+
end
|
27
|
+
s << HAWAIIAN_VOWELS.sample
|
28
|
+
s
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.hawaiian_word
|
32
|
+
word = ''
|
33
|
+
(rand(3)+3).times { word << hawaiian_syllable }
|
34
|
+
word
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require_relative "helper/data_works_spec_helper"
|
2
|
+
|
3
|
+
describe DataWorks::Relationships do
|
4
|
+
describe "#necessary_parents_for" do
|
5
|
+
describe "pet" do
|
6
|
+
it "returns an empty collection" do
|
7
|
+
expect(DataWorks::Relationships.necessary_parents_for(:pet)).to be_empty
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "pet_food" do
|
12
|
+
it "returns an empty collection" do
|
13
|
+
expect(DataWorks::Relationships.necessary_parents_for(:pet_food)).to be_empty
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "agency" do
|
18
|
+
it "returns an empty collection" do
|
19
|
+
expect(DataWorks::Relationships.necessary_parents_for(:agency)).to be_empty
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "toy" do
|
24
|
+
it "returns a collection with a single parent object " do
|
25
|
+
expect(DataWorks::Relationships.necessary_parents_for(:toy).count).to eq 1
|
26
|
+
end
|
27
|
+
it "returns a parent object with #association_name => pet" do
|
28
|
+
parents = DataWorks::Relationships.necessary_parents_for(:toy)
|
29
|
+
expect(parents.first.association_name).to eq(:pet)
|
30
|
+
end
|
31
|
+
it "returns a parent object with #model_name => pet" do
|
32
|
+
parents = DataWorks::Relationships.necessary_parents_for(:toy)
|
33
|
+
expect(parents.first.model_name).to eq(:pet)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "tag" do
|
38
|
+
it "returns a collection with a single parent object " do
|
39
|
+
expect(DataWorks::Relationships.necessary_parents_for(:tag).count).to eq 1
|
40
|
+
end
|
41
|
+
it "returns a parent object with #association_name => pet" do
|
42
|
+
parents = DataWorks::Relationships.necessary_parents_for(:tag)
|
43
|
+
expect(parents.first.association_name).to eq(:pet)
|
44
|
+
end
|
45
|
+
it "returns a parent object with #model_name => pet" do
|
46
|
+
parents = DataWorks::Relationships.necessary_parents_for(:tag)
|
47
|
+
expect(parents.first.model_name).to eq(:pet)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "pet_profile" do
|
52
|
+
it "returns a collection with a single parent object " do
|
53
|
+
expect(DataWorks::Relationships.necessary_parents_for(:pet_profile).count).to eq 1
|
54
|
+
end
|
55
|
+
it "returns a parent object with #association_name => pet" do
|
56
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_profile)
|
57
|
+
expect(parents.first.association_name).to eq(:pet)
|
58
|
+
end
|
59
|
+
it "returns a parent object with #model_name => pet" do
|
60
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_profile)
|
61
|
+
expect(parents.first.model_name).to eq(:pet)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "pet_sitter" do
|
66
|
+
it "returns a collection with a single parent object " do
|
67
|
+
expect(DataWorks::Relationships.necessary_parents_for(:pet_sitter).count).to eq 2
|
68
|
+
end
|
69
|
+
it "returns a parent object with #association_name => agency" do
|
70
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_sitter)
|
71
|
+
expect(parents.first.association_name).to eq(:agency)
|
72
|
+
end
|
73
|
+
it "returns a parent object with #model_name => agency" do
|
74
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_sitter)
|
75
|
+
expect(parents.first.model_name).to eq(:agency)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "address" do
|
80
|
+
it "returns a collection with a single parent object " do
|
81
|
+
expect(DataWorks::Relationships.necessary_parents_for(:address).count).to eq 1
|
82
|
+
end
|
83
|
+
it "returns a parent object with #association_name => pet_profile" do
|
84
|
+
parents = DataWorks::Relationships.necessary_parents_for(:address)
|
85
|
+
expect(parents.first.association_name).to eq(:pet_profile)
|
86
|
+
end
|
87
|
+
it "returns a parent object with #model_name => pet_profile" do
|
88
|
+
parents = DataWorks::Relationships.necessary_parents_for(:address)
|
89
|
+
expect(parents.first.model_name).to eq(:pet_profile)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "pet_sitting_patronage" do
|
94
|
+
it "returns a collection with two parent objects" do
|
95
|
+
expect(DataWorks::Relationships.necessary_parents_for(:pet_sitting_patronage).count).to eq 2
|
96
|
+
end
|
97
|
+
it "returns an array of parent objects with #association_names => pet_sitter, pet" do
|
98
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_sitting_patronage)
|
99
|
+
expect(parents.map(&:association_name)).to contain_exactly(:pet_sitter, :pet)
|
100
|
+
end
|
101
|
+
it "returns an array of parent objects with #model_names => pet_sitter, pet" do
|
102
|
+
parents = DataWorks::Relationships.necessary_parents_for(:pet_sitting_patronage)
|
103
|
+
expect(parents.map(&:model_name)).to contain_exactly(:pet_sitter, :pet)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative "helper/data_works_spec_helper"
|
2
|
+
|
3
|
+
describe 'DataWorks#set_restriction' do
|
4
|
+
let!(:data) { TheDataWorks.new }
|
5
|
+
|
6
|
+
describe 'setting a restriction using the metheod/registry option'do
|
7
|
+
let!(:darth_cuddles) { data.add_pet }
|
8
|
+
let!(:kittylo_ren) { data.add_pet }
|
9
|
+
|
10
|
+
it 'restricts the parent record for new children to the given object' do
|
11
|
+
death_star = data.add_toy
|
12
|
+
data.set_restriction(for_model: :pet, to: kittylo_ren)
|
13
|
+
star_killer = data.add_toy
|
14
|
+
expect(death_star.pet).to eq darth_cuddles
|
15
|
+
expect(star_killer.pet).to eq kittylo_ren
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'setting a restriction using the block option'do
|
20
|
+
let!(:darth_cuddles) { data.add_pet }
|
21
|
+
let!(:kittylo_ren) { data.add_pet }
|
22
|
+
|
23
|
+
it 'restricts the parent record for new children to the given object' do
|
24
|
+
death_star = data.add_toy
|
25
|
+
star_killer = data.set_restriction(for_model: :pet, to: kittylo_ren) do
|
26
|
+
data.add_toy
|
27
|
+
end
|
28
|
+
wookie_doll = data.add_toy
|
29
|
+
expect(death_star.pet).to eq darth_cuddles
|
30
|
+
expect(wookie_doll.pet).to eq darth_cuddles
|
31
|
+
expect(star_killer.pet).to eq kittylo_ren
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|