datamappify 0.2.2 → 0.9.0
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 +2 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -0
- data/README.md +69 -78
- data/Rakefile +20 -13
- data/datamappify.gemspec +29 -57
- data/lib/datamappify.rb +7 -16
- data/lib/datamappify/data.rb +6 -0
- data/lib/datamappify/data/association_methods.rb +29 -0
- data/lib/datamappify/data/base.rb +11 -0
- data/lib/datamappify/entity.rb +44 -0
- data/lib/datamappify/entity/associated_collection.rb +28 -0
- data/lib/datamappify/entity/associated_entity.rb +28 -0
- data/lib/datamappify/entity/association_methods.rb +20 -0
- data/lib/datamappify/repository.rb +65 -0
- data/lib/datamappify/repository/persistence.rb +38 -0
- data/lib/datamappify/version.rb +3 -0
- data/spec/entity_spec.rb +83 -0
- data/spec/repository/finders_and_persistence_spec.rb +71 -0
- data/spec/repository_spec.rb +60 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/active_record_tables.rb +34 -0
- data/spec/support/comment.rb +9 -0
- data/spec/support/role.rb +9 -0
- data/spec/support/user.rb +21 -0
- metadata +244 -79
- data/MIT-LICENSE +0 -20
- data/VERSION +0 -1
- data/lib/datamappify/associations.rb +0 -21
- data/lib/datamappify/collection.rb +0 -46
- data/lib/datamappify/fake/column.rb +0 -17
- data/lib/datamappify/fake/connection.rb +0 -77
- data/lib/datamappify/fake/index.rb +0 -34
- data/lib/datamappify/railtie.rb +0 -10
- data/lib/datamappify/resource.rb +0 -35
- data/lib/datamappify/schema_dumper.rb +0 -21
- data/lib/tasks/datamappify.rake +0 -15
- data/vendor/auto_migrations/MIT-LICENSE +0 -20
- data/vendor/auto_migrations/README +0 -46
- data/vendor/auto_migrations/Rakefile +0 -24
- data/vendor/auto_migrations/init.rb +0 -2
- data/vendor/auto_migrations/lib/auto_migrations.rb +0 -178
- data/vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake +0 -20
- data/vendor/auto_migrations/test/auto_migrations_test.rb +0 -8
@@ -0,0 +1,28 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Entity
|
3
|
+
class AssociatedCollection
|
4
|
+
def initialize(context, name)
|
5
|
+
build_collection_getter(context, name)
|
6
|
+
build_collection_setter(context, name)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def build_collection_getter(context, name)
|
12
|
+
context.class_eval <<-CODE
|
13
|
+
def #{name}
|
14
|
+
@#{name} ||= []
|
15
|
+
end
|
16
|
+
CODE
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_collection_setter(context, name)
|
20
|
+
context.class_eval <<-CODE
|
21
|
+
def #{name}=(collection)
|
22
|
+
@#{name} = collection
|
23
|
+
end
|
24
|
+
CODE
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Datamappify
|
2
|
+
module Entity
|
3
|
+
class AssociatedEntity
|
4
|
+
def initialize(context, name)
|
5
|
+
build_entity_getter(context, name)
|
6
|
+
build_entity_setter(context, name)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def build_entity_getter(context, name)
|
12
|
+
context.class_eval <<-CODE
|
13
|
+
def #{name}
|
14
|
+
@#{name} ||= "#{name}".classify.constantize.new
|
15
|
+
end
|
16
|
+
CODE
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_entity_setter(context, name)
|
20
|
+
context.class_eval <<-CODE
|
21
|
+
def #{name}=(entity)
|
22
|
+
@#{name} = entity
|
23
|
+
end
|
24
|
+
CODE
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'datamappify/entity/associated_entity'
|
2
|
+
require 'datamappify/entity/associated_collection'
|
3
|
+
|
4
|
+
module Datamappify
|
5
|
+
module Entity
|
6
|
+
module AssociationMethods
|
7
|
+
def belongs_to(name, *args)
|
8
|
+
AssociatedEntity.new(self, name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_one(name, *args)
|
12
|
+
AssociatedEntity.new(self, name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_many(name, *args)
|
16
|
+
AssociatedCollection.new(self, name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'datamappify/repository/persistence'
|
2
|
+
|
3
|
+
module Datamappify
|
4
|
+
class Repository
|
5
|
+
include Persistence
|
6
|
+
|
7
|
+
def initialize(entity_class)
|
8
|
+
@entity_class = entity_class
|
9
|
+
|
10
|
+
unless data_class_is_defined?
|
11
|
+
apply_validations_to_data_class
|
12
|
+
apply_relationships_to_data_class
|
13
|
+
add_entity_to_data_class
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(entity_or_id)
|
18
|
+
data_class.find(extract_entity_id(entity_or_id))
|
19
|
+
end
|
20
|
+
|
21
|
+
def method_missing(symbol, *args)
|
22
|
+
data_class.send symbol, *args
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def data_class_is_defined?
|
28
|
+
Data.const_defined?(@entity_class.name, false)
|
29
|
+
end
|
30
|
+
|
31
|
+
def apply_validations_to_data_class
|
32
|
+
if @entity_class.stored_validations
|
33
|
+
data_class.class_eval(&@entity_class.stored_validations)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def apply_relationships_to_data_class
|
38
|
+
if @entity_class.stored_relationships
|
39
|
+
data_class.class_eval(&@entity_class.stored_relationships)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_entity_to_data_class
|
44
|
+
data_class.class_eval <<-CODE
|
45
|
+
def entity
|
46
|
+
#{@entity_class.name}.new(attributes)
|
47
|
+
end
|
48
|
+
CODE
|
49
|
+
end
|
50
|
+
|
51
|
+
def data_class
|
52
|
+
@data_class ||= begin
|
53
|
+
if data_class_is_defined?
|
54
|
+
Data.const_get(@entity_class.name, false)
|
55
|
+
else
|
56
|
+
Data.const_set(@entity_class.name, Class.new(Data::Base))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_entity_id(entity_or_id)
|
62
|
+
entity_or_id.is_a?(Integer) ? entity_or_id : entity_or_id.id
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Datamappify
|
2
|
+
class Repository
|
3
|
+
module Persistence
|
4
|
+
[:save, :save!].each do |save_method_name|
|
5
|
+
define_method save_method_name do |entity_or_collection|
|
6
|
+
entity = collection = entity_or_collection
|
7
|
+
|
8
|
+
if collection.is_a?(Array)
|
9
|
+
collection.map { |e| send(save_method_name, e) }
|
10
|
+
elsif entity.id
|
11
|
+
update_data_record(save_method_name, entity)
|
12
|
+
else
|
13
|
+
create_data_record(save_method_name, entity)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
[:destroy, :destroy!].each do |destroy_method_name|
|
19
|
+
define_method destroy_method_name do |entity_or_id|
|
20
|
+
data_class.send(destroy_method_name, extract_entity_id(entity_or_id))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_data_record(save_method_name, entity)
|
27
|
+
data_object = data_class.new(entity.attributes)
|
28
|
+
data_object.send(save_method_name) && data_object.entity
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_data_record(save_method_name, entity)
|
32
|
+
data_object = data_class.find(entity.id)
|
33
|
+
data_object.update_attributes(entity.attributes)
|
34
|
+
data_object.send(save_method_name) && data_object.entity
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/entity_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Datamappify::Entity do
|
4
|
+
let(:user) { User.new }
|
5
|
+
let(:role) { Role.new }
|
6
|
+
let(:comment) { Comment.new }
|
7
|
+
|
8
|
+
describe "attributes" do
|
9
|
+
it "has defined attributes" do
|
10
|
+
user.first_name.must_be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "raises error on undefined attributes" do
|
14
|
+
-> { user.attribute_that_does_not_exist }.must_raise NoMethodError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "assigns an attribute" do
|
18
|
+
user.first_name = 'Fred'
|
19
|
+
user.first_name.must_equal 'Fred'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "coerces an attribute" do
|
23
|
+
user.age = '42'
|
24
|
+
user.age.must_be_kind_of Fixnum
|
25
|
+
user.age.must_equal 42
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "validations" do
|
30
|
+
it "requires first name" do
|
31
|
+
user.first_name = nil
|
32
|
+
user.valid?.must_equal false
|
33
|
+
|
34
|
+
user.first_name = 'Fred'
|
35
|
+
user.valid?.must_equal true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "relationships" do
|
40
|
+
describe "getters" do
|
41
|
+
it "belongs_to" do
|
42
|
+
comment.user.must_be_kind_of User
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has_one" do
|
46
|
+
user.role.must_be_kind_of Role
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has_many" do
|
50
|
+
user.comments.must_be_kind_of Array
|
51
|
+
user.comments.must_be_empty
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "setters" do
|
56
|
+
let(:entity) { Object.new }
|
57
|
+
|
58
|
+
it "belongs_to" do
|
59
|
+
comment.user = entity
|
60
|
+
comment.user.must_be_kind_of Object
|
61
|
+
comment.user.must_equal entity
|
62
|
+
end
|
63
|
+
|
64
|
+
it "has_one" do
|
65
|
+
user.role = entity
|
66
|
+
user.role.must_be_kind_of Object
|
67
|
+
user.role.must_equal entity
|
68
|
+
end
|
69
|
+
|
70
|
+
it "has_many" do
|
71
|
+
user.comments << entity
|
72
|
+
user.comments << entity
|
73
|
+
user.comments.must_be_kind_of Array
|
74
|
+
user.comments.count.must_equal 2
|
75
|
+
user.comments[0].must_equal entity
|
76
|
+
|
77
|
+
user.comments = [entity]
|
78
|
+
user.comments.count.must_equal 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Datamappify::Repository do
|
4
|
+
let(:user_repository) { Datamappify::Repository.new(User) }
|
5
|
+
let(:user) { user_repository.first }
|
6
|
+
let(:user_valid) { User.new(:first_name => 'Batman') }
|
7
|
+
let(:user_invalid) { User.new(:first_name => 'a') }
|
8
|
+
|
9
|
+
before do
|
10
|
+
user_repository
|
11
|
+
Datamappify::Data::User.create!(:first_name => 'Fred')
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "single record" do
|
15
|
+
it "#find via id" do
|
16
|
+
user_repository.find(1).must_equal user
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#find via entity" do
|
20
|
+
user_repository.find(user.entity).must_equal user
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#save success" do
|
24
|
+
new_user = user_repository.save(user_valid)
|
25
|
+
new_user.must_be_kind_of User
|
26
|
+
new_user.first_name.must_equal 'Batman'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#save! failure" do
|
30
|
+
-> { user_repository.save!(user_invalid) }.must_raise ActiveRecord::RecordInvalid
|
31
|
+
end
|
32
|
+
|
33
|
+
it "updates an existing record" do
|
34
|
+
user.first_name = 'Steve'
|
35
|
+
changed_user = User.new(user.attributes)
|
36
|
+
user_repository.save(changed_user).first_name.must_equal 'Steve'
|
37
|
+
user_repository.count.must_equal 1
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#destroy via id" do
|
41
|
+
user_repository.destroy(1)
|
42
|
+
user_repository.count.must_equal 0
|
43
|
+
end
|
44
|
+
|
45
|
+
it "#destroy via entity" do
|
46
|
+
user_repository.destroy(user.entity)
|
47
|
+
user_repository.count.must_equal 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "collection records" do
|
52
|
+
it "#find" do
|
53
|
+
user_repository.all.must_be_kind_of ActiveRecord::Relation::ActiveRecord_Relation_Datamappify_Data_User
|
54
|
+
user_repository.count.must_equal 1
|
55
|
+
end
|
56
|
+
|
57
|
+
it "#save" do
|
58
|
+
new_user_entity = user.entity
|
59
|
+
new_user_entity.id = nil
|
60
|
+
|
61
|
+
new_users = user_repository.save([new_user_entity, user_valid])
|
62
|
+
new_users[0].first_name.must_equal 'Fred'
|
63
|
+
new_users[1].first_name.must_equal 'Batman'
|
64
|
+
|
65
|
+
user_repository.count.must_equal 3
|
66
|
+
user_repository.all[0].first_name.must_equal 'Fred'
|
67
|
+
user_repository.all[1].first_name.must_equal 'Fred'
|
68
|
+
user_repository.all[2].first_name.must_equal 'Batman'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Datamappify::Repository do
|
4
|
+
let(:user_repository) { Datamappify::Repository.new(User) }
|
5
|
+
let(:comment_repository) { Datamappify::Repository.new(Comment) }
|
6
|
+
let(:role_repository) { Datamappify::Repository.new(Role) }
|
7
|
+
|
8
|
+
describe "ActiveRecord data objects" do
|
9
|
+
it "defines the Data::User class after the repository is initialised" do
|
10
|
+
user_repository
|
11
|
+
Datamappify::Data.const_defined?(:User, false).must_equal true
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "data objects" do
|
15
|
+
subject { Datamappify::Data::User }
|
16
|
+
|
17
|
+
before do
|
18
|
+
user_repository
|
19
|
+
end
|
20
|
+
|
21
|
+
it "inherites from Datamappify::Data::Base" do
|
22
|
+
subject.superclass.must_equal Datamappify::Data::Base
|
23
|
+
subject.ancestors.must_include ActiveRecord::Base
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has 'users' as the table name" do
|
27
|
+
subject.table_name.must_equal 'users'
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "relationships" do
|
31
|
+
let(:user) { Datamappify::Data::User.new }
|
32
|
+
let(:comment) { Datamappify::Data::Comment.new }
|
33
|
+
let(:role) { Datamappify::Data::Role.new }
|
34
|
+
|
35
|
+
it "belongs_to" do
|
36
|
+
assert_correct_associated_data_class_name(comment, :user, 'Datamappify::Data::User')
|
37
|
+
comment.user.must_be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "has_one" do
|
41
|
+
assert_correct_associated_data_class_name(user, :role, 'Datamappify::Data::Role')
|
42
|
+
user.role.must_be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has_many" do
|
46
|
+
assert_correct_associated_data_class_name(user, :comments, 'Datamappify::Data::Comment')
|
47
|
+
assert_correct_associated_data_class_name(role, :users, 'Datamappify::Data::User')
|
48
|
+
user.comments.must_be_empty
|
49
|
+
role.users.must_be_empty
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def assert_correct_associated_data_class_name(klass, association_name, data_class_name)
|
55
|
+
klass.class.reflect_on_all_associations.find { |a|
|
56
|
+
a.name == association_name
|
57
|
+
}.klass.name.must_equal data_class_name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'pry'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/colorize'
|
6
|
+
require 'database_cleaner'
|
7
|
+
|
8
|
+
SimpleCov.start
|
9
|
+
|
10
|
+
SimpleCov.configure do
|
11
|
+
add_filter "/spec/"
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.expand_path('../../lib/datamappify', __FILE__)
|
15
|
+
|
16
|
+
Dir[File.expand_path('../support/**/*', __FILE__)].each { |f| require f }
|
17
|
+
|
18
|
+
DatabaseCleaner.strategy = :truncation
|
19
|
+
|
20
|
+
class MiniTest::Spec
|
21
|
+
before do
|
22
|
+
DatabaseCleaner.clean
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
ActiveRecord::Migration.suppress_messages do
|
2
|
+
ActiveRecord::Base.establish_connection(
|
3
|
+
:adapter => 'sqlite3',
|
4
|
+
:database => ':memory:'
|
5
|
+
)
|
6
|
+
|
7
|
+
ActiveRecord::Schema.define(:version => 0) do
|
8
|
+
begin
|
9
|
+
drop_table :users
|
10
|
+
drop_table :comments
|
11
|
+
drop_table :roles
|
12
|
+
rescue
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :users do |t|
|
16
|
+
t.string :first_name, :null => false
|
17
|
+
t.string :last_name
|
18
|
+
t.integer :age
|
19
|
+
t.references :role
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :comments do |t|
|
24
|
+
t.string :content
|
25
|
+
t.references :user
|
26
|
+
t.timestamps
|
27
|
+
end
|
28
|
+
|
29
|
+
create_table :roles do |t|
|
30
|
+
t.string :name
|
31
|
+
t.timestamps
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|