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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile +4 -0
  6. data/README.md +69 -78
  7. data/Rakefile +20 -13
  8. data/datamappify.gemspec +29 -57
  9. data/lib/datamappify.rb +7 -16
  10. data/lib/datamappify/data.rb +6 -0
  11. data/lib/datamappify/data/association_methods.rb +29 -0
  12. data/lib/datamappify/data/base.rb +11 -0
  13. data/lib/datamappify/entity.rb +44 -0
  14. data/lib/datamappify/entity/associated_collection.rb +28 -0
  15. data/lib/datamappify/entity/associated_entity.rb +28 -0
  16. data/lib/datamappify/entity/association_methods.rb +20 -0
  17. data/lib/datamappify/repository.rb +65 -0
  18. data/lib/datamappify/repository/persistence.rb +38 -0
  19. data/lib/datamappify/version.rb +3 -0
  20. data/spec/entity_spec.rb +83 -0
  21. data/spec/repository/finders_and_persistence_spec.rb +71 -0
  22. data/spec/repository_spec.rb +60 -0
  23. data/spec/spec_helper.rb +24 -0
  24. data/spec/support/active_record_tables.rb +34 -0
  25. data/spec/support/comment.rb +9 -0
  26. data/spec/support/role.rb +9 -0
  27. data/spec/support/user.rb +21 -0
  28. metadata +244 -79
  29. data/MIT-LICENSE +0 -20
  30. data/VERSION +0 -1
  31. data/lib/datamappify/associations.rb +0 -21
  32. data/lib/datamappify/collection.rb +0 -46
  33. data/lib/datamappify/fake/column.rb +0 -17
  34. data/lib/datamappify/fake/connection.rb +0 -77
  35. data/lib/datamappify/fake/index.rb +0 -34
  36. data/lib/datamappify/railtie.rb +0 -10
  37. data/lib/datamappify/resource.rb +0 -35
  38. data/lib/datamappify/schema_dumper.rb +0 -21
  39. data/lib/tasks/datamappify.rake +0 -15
  40. data/vendor/auto_migrations/MIT-LICENSE +0 -20
  41. data/vendor/auto_migrations/README +0 -46
  42. data/vendor/auto_migrations/Rakefile +0 -24
  43. data/vendor/auto_migrations/init.rb +0 -2
  44. data/vendor/auto_migrations/lib/auto_migrations.rb +0 -178
  45. data/vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake +0 -20
  46. 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
@@ -0,0 +1,3 @@
1
+ module Datamappify
2
+ VERSION = '0.9.0'
3
+ end
@@ -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
@@ -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