datamappify 0.2.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5cd51d61440490e0e15894ce7243cb4c324945b5
4
+ data.tar.gz: cbbf430016eaf1c88b181806e3901a009ce9028f
5
+ SHA512:
6
+ metadata.gz: 55ecbac18bf660597c7494a12b9adf88a1597202388ae131305653c2e5902d4d455d284b37bc1ebd0e4bec82b408ea4e778198df07e4c819c264af34658a3200
7
+ data.tar.gz: 5bbc77d5ef8a8522e66461bead4a94490932138464f27d912593d8bf5ef26414bb26712c63b2f2ce234ed48b99f1fe37d5ee58959057c94f471799983282c2b8
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
+ Gemfile.lock
1
2
  pkg
3
+ coverage
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## master
2
+
3
+ ## 0.9.0 [2013-03-14]
4
+
5
+ - A total rewrite as a proof-of-concept based on the repository pattern.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in datamappify.gemspec
4
+ gemspec
data/README.md CHANGED
@@ -1,118 +1,109 @@
1
- # Datamappify
1
+ # Datamappify [![Gem Version](https://badge.fury.io/rb/datamappify.png)](http://badge.fury.io/rb/datamappify) [![Build Status](https://api.travis-ci.org/fredwu/datamappify.png)](http://travis-ci.org/fredwu/datamappify) [![Code Climate](https://codeclimate.com/github/fredwu/datamappify.png)](https://codeclimate.com/github/fredwu/datamappify)
2
2
 
3
- ## Introduction
3
+ Separate domain logic from data persistence, based on the [Repository Pattern](http://martinfowler.com/eaaCatalog/repository.html).
4
4
 
5
- ActiveRecord is without doubt the *de facto* ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.
5
+ __This library is current in Proof-of-Concept stage, do NOT use it for anything other than experimentation.__
6
6
 
7
- Brought to you by [Envato](http://envato.com) and [Wuit](http://wuit.com).
7
+ ## Overview
8
8
 
9
- ## Disclaimer
9
+ Datamappify is a thin layer on top of ActiveRecord and [Virtus](https://github.com/solnic/virtus). The design goal is to utilise ActiveRecord but separate domain logic (behaviour) and data persistence.
10
10
 
11
- **This plugin is NOT production-ready yet!** Use with caution.
11
+ Datamappify consists of three components:
12
12
 
13
- ### Todo
13
+ - Entity
14
+ - Data
15
+ - Repository
14
16
 
15
- * Add tests
16
- * Possibly refactor `add_index` to be part of the `property` definition (as seen in the [DataMapper](http://datamapper.org/) library)
17
+ __Entity__ is your model, it is responsible for mainly storing behaviour. Some structure (i.e. model relationships) is also stored here for convenience.
17
18
 
18
- ## Why?
19
+ __Data__ as the name suggests, holds your model data. It is an ActiveRecord object.
19
20
 
20
- ### Why Not DB Migrations?
21
+ __Repository__ is responsible for data retrieval and persistence, e.g. `find`, `save` and `destroy`, etc.
21
22
 
22
- Well, depending on your specific project, DB migrations might create more trouble than it's worth. Besides, your code is already version controlled, so why create a separate version control for your DB schema?
23
-
24
- ### Why Not Use DataMapper, Sequel, etc?
25
-
26
- As stated in the introduction, ActiveRecord is the most popular ORM in the rails community, it is actively developed and battle-tested. If your only grief with ActiveRecord is the DB migrations, why not just eliminate it be happy? ;)
27
-
28
- ## How?
29
-
30
- How does this plugin work?
23
+ ## Installation
31
24
 
32
- Basically, it -
25
+ Add this line to your application's Gemfile:
33
26
 
34
- 1. Uses a DSL similar to DataMapper's for defining model properties (DB mapping).
35
- 2. `schema.rb` is automatically updated according to the model properties.
36
- 3. Automatically 'migrates' the database according to the updated schema file.
27
+ gem 'datamappify'
37
28
 
38
- ## Installation
29
+ And then execute:
39
30
 
40
- gem install datamappify
31
+ $ bundle
41
32
 
42
- Don't forget to include the library in your `Gemfile`:
33
+ Or install it yourself as:
43
34
 
44
- gem 'datamappify'
35
+ $ gem install datamappify
45
36
 
46
37
  ## Usage
47
38
 
48
- Here's an example to get you started:
39
+ Model:
49
40
 
50
- class User < ActiveRecord::Base
51
- include Datamappify::Resource
52
-
53
- property :email, :string
54
- property :password, :string, :limit => 40
55
- property :first_name, :string, :limit => 50
56
- property :last_name, :string, :limit => 50
57
- property :payment_email, :string
58
- property :timestamps
59
- add_index :email
60
- add_index :payment_email
61
- add_index :role_id
62
-
63
- belongs_to :role
64
- end
41
+ ```ruby
42
+ class User
43
+ include Datamappify::Entity
65
44
 
66
- It will create the following schema:
45
+ attribute :first_name, String
46
+ attribute :last_name, String
47
+ attribute :age, Integer
67
48
 
68
- create_table "users", :force => true do |t|
69
- t.string :email, :limit => nil
70
- t.string :password, :limit => nil
71
- t.string :first_name, :limit => nil
72
- t.string :last_name, :limit => nil
73
- t.string :payment_email, :limit => nil
74
- t.integer :role_id, :limit => nil
75
- t.datetime :created_at
76
- t.datetime :updated_at
77
- end
49
+ # ActiveModel::Validations rules are wrapped in the `validations` block
50
+ validations do
51
+ validates :first_name, :presence => true
52
+ end
78
53
 
79
- add_index "users", :email
80
- add_index "users", :payment_email
81
- add_index "users", :role_id
54
+ # ActiveRelation collections are wrapped in the `relationships` block
55
+ relationships do
56
+ has_one :role
57
+ has_many :comments
58
+ end
82
59
 
83
- #### property()
60
+ def full_name
61
+ "#{first_name} #{last_name}"
62
+ end
63
+ end
64
+ ```
84
65
 
85
- Use `property` to define and map DB columns. It accepts a number of arguments:
66
+ Corresponding repository:
86
67
 
87
- 1. Name of the column.
88
- 2. SQL type of the column, same as the ones provided by ActiveRecord migrations.
89
- 3. Column options, same as the ones provided by ActiveRecord migrations.
68
+ ```ruby
69
+ user_repository = Datamappify::Repository.new(User)
70
+ ```
90
71
 
91
- #### add_index()
72
+ Retrieving records:
92
73
 
93
- Use `add_index` to add DB indexes. It accepts a number of arguments:
74
+ ```ruby
75
+ user = user_repository.find(1)
76
+ ```
94
77
 
95
- 1. The column(s) to index on, can be just one column or a number of columns in an array.
96
- 3. Index options such as `name`, `unique` and `length`.
78
+ Saving/updating a record:
97
79
 
98
- ### Rake Tasks
80
+ ```ruby
81
+ user_repository.save(user)
82
+ ```
99
83
 
100
- To set up your database for the first time, please run:
84
+ Destroying a record:
101
85
 
102
- rake db:schema:update
103
- rake db:setup
86
+ ```ruby
87
+ user_repository.destroy(user)
88
+ ```
104
89
 
105
- Later on, to only update the `schema.rb` file, run:
90
+ ## Todo
106
91
 
107
- rake db:schema:update
92
+ - Entity should dictate Data, so schema and migrations should be automatically generated
93
+ - Support for `set_primary_key` (currently the PK is hard coded to `id`)
94
+ - Support for HABTM association type
95
+ - Support for entity attribute and data column mapping
96
+ - Repository should handle asscociated data
108
97
 
109
- To update `schema.rb` and to 'migrate' the updated database structure, run:
98
+ ## Similar Projects
110
99
 
111
- rake db:schema:auto_migrate
100
+ - [Curator](https://github.com/braintree/curator)
101
+ - [Edr](https://github.com/nulogy/edr)
112
102
 
113
103
  ## Author
114
104
 
115
- Copyright (c) 2010 Fred Wu (<http://fredwu.me>), released under the MIT license
105
+ [Fred Wu](http://fredwu.me/)
106
+
107
+ ## License
116
108
 
117
- * Envato - <http://envato.com>
118
- * Wuit - <http://wuit.com>
109
+ Licensed under [MIT](http://fredwu.mit-license.org/)
data/Rakefile CHANGED
@@ -1,18 +1,25 @@
1
- require 'rake'
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push 'lib'
6
+ t.test_files = FileList['spec/**/*_spec.rb']
7
+ t.verbose = true
8
+ end
2
9
 
3
10
  begin
4
- require 'jeweler'
5
- Jeweler::Tasks.new do |s|
6
- s.name = "datamappify"
7
- s.summary = "Turn ActiveRecord into DataMapper (sort of)!"
8
- s.description = "ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches."
9
- s.email = "ifredwu@gmail.com"
10
- s.homepage = "http://github.com/fredwu/datamappify"
11
- s.authors = ["Fred Wu"]
12
- s.require_paths = ["lib", "vendor/auto_migrations/lib"]
13
- s.add_dependency("activerecord")
11
+ require 'cane/rake_task'
12
+
13
+ desc "Run cane to check quality metrics"
14
+ Cane::RakeTask.new(:quality) do |cane|
15
+ cane.abc_max = 8
16
+ cane.no_doc = true
17
+ cane.style_glob = './lib/**/*.rb'
18
+ cane.style_measure = 120
19
+ cane.abc_exclude = []
14
20
  end
15
- Jeweler::GemcutterTasks.new
16
21
  rescue LoadError
17
- puts "Jeweler not available. Install it with: gem install jeweler"
22
+ warn "cane not available, quality task not provided."
18
23
  end
24
+
25
+ task :default => [:test, :quality]
data/datamappify.gemspec CHANGED
@@ -1,62 +1,34 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'datamappify/version'
5
5
 
6
- Gem::Specification.new do |s|
7
- s.name = %q{datamappify}
8
- s.version = "0.2.2"
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "datamappify"
8
+ spec.version = Datamappify::VERSION
9
+ spec.authors = ["Fred Wu"]
10
+ spec.email = ["ifredwu@gmail.com"]
11
+ spec.description = %q{Separate domain logic from data persistence.}
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/fredwu/datamappify"
14
+ spec.license = "MIT"
9
15
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Fred Wu"]
12
- s.date = %q{2010-09-24}
13
- s.description = %q{ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.}
14
- s.email = %q{ifredwu@gmail.com}
15
- s.extra_rdoc_files = [
16
- "README.md"
17
- ]
18
- s.files = [
19
- ".gitignore",
20
- "MIT-LICENSE",
21
- "README.md",
22
- "Rakefile",
23
- "VERSION",
24
- "datamappify.gemspec",
25
- "lib/datamappify.rb",
26
- "lib/datamappify/associations.rb",
27
- "lib/datamappify/collection.rb",
28
- "lib/datamappify/fake/column.rb",
29
- "lib/datamappify/fake/connection.rb",
30
- "lib/datamappify/fake/index.rb",
31
- "lib/datamappify/railtie.rb",
32
- "lib/datamappify/resource.rb",
33
- "lib/datamappify/schema_dumper.rb",
34
- "lib/tasks/datamappify.rake",
35
- "vendor/auto_migrations/MIT-LICENSE",
36
- "vendor/auto_migrations/README",
37
- "vendor/auto_migrations/Rakefile",
38
- "vendor/auto_migrations/init.rb",
39
- "vendor/auto_migrations/lib/auto_migrations.rb",
40
- "vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake",
41
- "vendor/auto_migrations/test/auto_migrations_test.rb"
42
- ]
43
- s.homepage = %q{http://github.com/fredwu/datamappify}
44
- s.rdoc_options = ["--charset=UTF-8"]
45
- s.require_paths = ["lib", "vendor/auto_migrations/lib"]
46
- s.rubygems_version = %q{1.3.7}
47
- s.summary = %q{Turn ActiveRecord into DataMapper (sort of)!}
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
48
20
 
49
- if s.respond_to? :specification_version then
50
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
- s.specification_version = 3
21
+ spec.add_dependency "virtus", "~> 0.5"
22
+ spec.add_dependency "activesupport", ">= 4.0.0.beta1", "< 5"
23
+ spec.add_dependency "activerecord", ">= 4.0.0.beta1", "< 5"
52
24
 
53
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
- s.add_runtime_dependency(%q<activerecord>, [">= 0"])
55
- else
56
- s.add_dependency(%q<activerecord>, [">= 0"])
57
- end
58
- else
59
- s.add_dependency(%q<activerecord>, [">= 0"])
60
- end
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "minitest"
28
+ spec.add_development_dependency "minitest-colorize"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "simplecov"
31
+ spec.add_development_dependency "cane"
32
+ spec.add_development_dependency "sqlite3"
33
+ spec.add_development_dependency "database_cleaner", ">= 1.0.0.RC1", "< 2"
61
34
  end
62
-
data/lib/datamappify.rb CHANGED
@@ -1,18 +1,9 @@
1
- raise "ActiveRecord is not present!" unless defined?(ActiveRecord)
2
-
3
- require 'auto_migrations'
4
- require 'datamappify/associations'
5
- require 'datamappify/collection'
6
- require 'datamappify/fake/column'
7
- require 'datamappify/fake/connection'
8
- require 'datamappify/fake/index'
9
- require 'datamappify/railtie'
10
- require 'datamappify/resource'
11
- require 'datamappify/schema_dumper'
1
+ require "active_support/inflector"
2
+ require "active_record"
3
+ require "datamappify/version"
4
+ require "datamappify/entity"
5
+ require "datamappify/data"
6
+ require "datamappify/repository"
12
7
 
13
8
  module Datamappify
14
- def self.run
15
- Datamappify::SchemaDumper.dump_to_file
16
- AutoMigrations.run
17
- end
18
- end
9
+ end
@@ -0,0 +1,6 @@
1
+ require 'datamappify/data/base'
2
+
3
+ module Datamappify
4
+ module Data
5
+ end
6
+ end
@@ -0,0 +1,29 @@
1
+ module Datamappify
2
+ module Data
3
+ module AssociationMethods
4
+ def belongs_to(name, scope = nil, options = {})
5
+ build_associated_repository(name)
6
+
7
+ super(name, scope = nil, options)
8
+ end
9
+
10
+ def has_one(name, scope = nil, options = {})
11
+ build_associated_repository(name)
12
+
13
+ super(name, scope = nil, options)
14
+ end
15
+
16
+ def has_many(name, scope = nil, options = {}, &extension)
17
+ build_associated_repository(name)
18
+
19
+ super(name, scope = nil, options, &extension)
20
+ end
21
+
22
+ private
23
+
24
+ def build_associated_repository(entity_or_collection_name)
25
+ Datamappify::Repository.new(entity_or_collection_name.to_s.classify.constantize)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ require 'datamappify/data/association_methods'
2
+
3
+ module Datamappify
4
+ module Data
5
+ class Base < ActiveRecord::Base
6
+ extend Data::AssociationMethods
7
+
8
+ self.abstract_class = true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ require 'virtus'
2
+ require 'datamappify/entity/association_methods'
3
+
4
+ module Datamappify
5
+ module Entity
6
+ def self.included(klass)
7
+ klass.class_eval do
8
+ include Virtus
9
+
10
+ attribute :id, Integer
11
+
12
+ extend Behaviour
13
+ extend Structure
14
+ extend AssociationMethods
15
+ end
16
+ end
17
+
18
+ module Behaviour
19
+ def self.extended(klass)
20
+ klass.class_eval do
21
+ include ActiveModel::Validations
22
+ end
23
+ end
24
+
25
+ attr_accessor :stored_validations
26
+
27
+ def validations(&block)
28
+ self.stored_validations = block
29
+
30
+ instance_eval(&block)
31
+ end
32
+ end
33
+
34
+ module Structure
35
+ attr_accessor :stored_relationships
36
+
37
+ def relationships(&block)
38
+ self.stored_relationships = block
39
+
40
+ instance_eval(&block)
41
+ end
42
+ end
43
+ end
44
+ end