rd3 0.0.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.
- data/.rspec +4 -0
- data/.rvmrc +71 -0
- data/.simplecov +5 -0
- data/Gemfile +22 -0
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/rd3.rb +32 -0
- data/lib/rd3/configuration.rb +5 -0
- data/lib/rd3/data_providers/azure_table_storage.rb +67 -0
- data/lib/rd3/data_providers/rdbms.rb +62 -0
- data/lib/rd3/model.rb +108 -0
- data/lib/rd3/railtie.rb +7 -0
- data/lib/rd3/repository.rb +61 -0
- data/rd3.gemspec +102 -0
- data/spec/config/azure_table_storage.yml +3 -0
- data/spec/config/mysql.yml +7 -0
- data/spec/config/postgresql.yml +7 -0
- data/spec/lib/rd3/data_providers/azure_table_storage_spec.rb +30 -0
- data/spec/lib/rd3/data_providers/rdbms_spec.rb +41 -0
- data/spec/lib/rd3/model_spec.rb +158 -0
- data/spec/lib/rd3/repository_spec.rb +65 -0
- data/spec/lib/rd3_spec.rb +18 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/data_provider_shared_examples.rb +131 -0
- data/spec/support/rdbms_shared_context.rb +29 -0
- metadata +286 -0
data/lib/rd3/railtie.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module RD3
|
2
|
+
module Repository
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
#module ClassMethods
|
6
|
+
included do
|
7
|
+
def self.config_file_name(config=nil)
|
8
|
+
return @config_file_name if @config_file_name
|
9
|
+
|
10
|
+
if config
|
11
|
+
# config file name must be set before including the
|
12
|
+
# db provider module
|
13
|
+
@config_file_name = config
|
14
|
+
|
15
|
+
# derive the data provider from the
|
16
|
+
# config file name (convention based)
|
17
|
+
@data_provider = _map_config_file_name_to_data_provider(config)
|
18
|
+
|
19
|
+
self.module_eval <<-EVAL
|
20
|
+
include RD3::DataProviders::#{@data_provider.capitalize}
|
21
|
+
EVAL
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.model
|
26
|
+
@model ||= name.gsub('Repository', '').constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.data_provider
|
30
|
+
@data_provider
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.find_by_key(key, opts)
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.save(l_obj)
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.delete(key, opts)
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
|
45
|
+
def self._map_config_file_name_to_data_provider(config_file_name)
|
46
|
+
provider = config_file_name.to_s.split('_').first.to_sym
|
47
|
+
#@data_provider = case provider
|
48
|
+
#when :mysql then RD3::DataProviders::Rdbms
|
49
|
+
#when :postgresql then RD3::DataProviders::Rdbms
|
50
|
+
#else raise TypeError, "#{provider} is not a supported data provider"
|
51
|
+
#end
|
52
|
+
case provider
|
53
|
+
when :mysql then :rdbms
|
54
|
+
when :postgresql then :rdbms
|
55
|
+
else raise TypeError, "#{provider} is not a supported data provider"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end # module ClassMethods
|
59
|
+
|
60
|
+
end # module Repository
|
61
|
+
end # module RD3
|
data/rd3.gemspec
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "rd3"
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["obie quelland"]
|
12
|
+
s.date = "2012-12-04"
|
13
|
+
s.description = " enable domain driven design approach via POROs and Repositories vs Rails' ActiveRecord "
|
14
|
+
s.email = "quelland@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".rspec",
|
21
|
+
".rvmrc",
|
22
|
+
".simplecov",
|
23
|
+
"Gemfile",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.md",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"lib/rd3.rb",
|
29
|
+
"lib/rd3/configuration.rb",
|
30
|
+
"lib/rd3/data_providers/azure_table_storage.rb",
|
31
|
+
"lib/rd3/data_providers/rdbms.rb",
|
32
|
+
"lib/rd3/model.rb",
|
33
|
+
"lib/rd3/railtie.rb",
|
34
|
+
"lib/rd3/repository.rb",
|
35
|
+
"rd3.gemspec",
|
36
|
+
"spec/config/azure_table_storage.yml",
|
37
|
+
"spec/config/mysql.yml",
|
38
|
+
"spec/config/postgresql.yml",
|
39
|
+
"spec/lib/rd3/data_providers/azure_table_storage_spec.rb",
|
40
|
+
"spec/lib/rd3/data_providers/rdbms_spec.rb",
|
41
|
+
"spec/lib/rd3/model_spec.rb",
|
42
|
+
"spec/lib/rd3/repository_spec.rb",
|
43
|
+
"spec/lib/rd3_spec.rb",
|
44
|
+
"spec/spec_helper.rb",
|
45
|
+
"spec/support/data_provider_shared_examples.rb",
|
46
|
+
"spec/support/rdbms_shared_context.rb"
|
47
|
+
]
|
48
|
+
s.homepage = "http://github.com/obieq/rd3"
|
49
|
+
s.licenses = ["MIT"]
|
50
|
+
s.require_paths = ["lib"]
|
51
|
+
s.rubygems_version = "1.8.24"
|
52
|
+
s.summary = "RD3 is a ruby gem that adheres to and facilitates domain driven design principles"
|
53
|
+
|
54
|
+
if s.respond_to? :specification_version then
|
55
|
+
s.specification_version = 3
|
56
|
+
|
57
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<activemodel>, [">= 0"])
|
60
|
+
s.add_runtime_dependency(%q<require_all>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<rdoc>, [">= 3.12"])
|
62
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
63
|
+
s.add_development_dependency(%q<jeweler>, [">= 1.8.4"])
|
64
|
+
s.add_development_dependency(%q<rspec>, [">= 2.12.0"])
|
65
|
+
s.add_development_dependency(%q<simplecov>, [">= 0.7.1"])
|
66
|
+
s.add_development_dependency(%q<mysql2>, [">= 0.3.11"])
|
67
|
+
s.add_development_dependency(%q<pg>, [">= 0.14.1"])
|
68
|
+
s.add_development_dependency(%q<sequel>, [">= 3.41.0"])
|
69
|
+
s.add_development_dependency(%q<waz-storage>, [">= 1.1.4"])
|
70
|
+
s.add_development_dependency(%q<database_cleaner>, [">= 0.9.1"])
|
71
|
+
else
|
72
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
73
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
74
|
+
s.add_dependency(%q<require_all>, [">= 0"])
|
75
|
+
s.add_dependency(%q<rdoc>, [">= 3.12"])
|
76
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
77
|
+
s.add_dependency(%q<jeweler>, [">= 1.8.4"])
|
78
|
+
s.add_dependency(%q<rspec>, [">= 2.12.0"])
|
79
|
+
s.add_dependency(%q<simplecov>, [">= 0.7.1"])
|
80
|
+
s.add_dependency(%q<mysql2>, [">= 0.3.11"])
|
81
|
+
s.add_dependency(%q<pg>, [">= 0.14.1"])
|
82
|
+
s.add_dependency(%q<sequel>, [">= 3.41.0"])
|
83
|
+
s.add_dependency(%q<waz-storage>, [">= 1.1.4"])
|
84
|
+
s.add_dependency(%q<database_cleaner>, [">= 0.9.1"])
|
85
|
+
end
|
86
|
+
else
|
87
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
88
|
+
s.add_dependency(%q<activemodel>, [">= 0"])
|
89
|
+
s.add_dependency(%q<require_all>, [">= 0"])
|
90
|
+
s.add_dependency(%q<rdoc>, [">= 3.12"])
|
91
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
92
|
+
s.add_dependency(%q<jeweler>, [">= 1.8.4"])
|
93
|
+
s.add_dependency(%q<rspec>, [">= 2.12.0"])
|
94
|
+
s.add_dependency(%q<simplecov>, [">= 0.7.1"])
|
95
|
+
s.add_dependency(%q<mysql2>, [">= 0.3.11"])
|
96
|
+
s.add_dependency(%q<pg>, [">= 0.14.1"])
|
97
|
+
s.add_dependency(%q<sequel>, [">= 3.41.0"])
|
98
|
+
s.add_dependency(%q<waz-storage>, [">= 1.1.4"])
|
99
|
+
s.add_dependency(%q<database_cleaner>, [">= 0.9.1"])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
AZURE_SPEC_TABLE_NAME = :"rd3spectester#{Random.rand(999)}"
|
4
|
+
|
5
|
+
class RD3::AzureTableStorageTestClass
|
6
|
+
include RD3::DataProviders::AzureTableStorage
|
7
|
+
|
8
|
+
def self.config_file_name
|
9
|
+
:azure_table_storage
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.table_name
|
13
|
+
AZURE_SPEC_TABLE_NAME
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe RD3::DataProviders::AzureTableStorage, :speed => :slow do
|
18
|
+
it_behaves_like "data provider", :azure_table_storage
|
19
|
+
|
20
|
+
let(:repo) {RD3::AzureTableStorageTestClass}
|
21
|
+
|
22
|
+
before(:all) do
|
23
|
+
repo.client.create_table AZURE_SPEC_TABLE_NAME
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:all) do
|
27
|
+
repo.client.delete_table AZURE_SPEC_TABLE_NAME
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RDBMS_SPEC_TABLE_NAME = :rd3_spec_tester
|
4
|
+
|
5
|
+
class RD3::MySqlRdbmsTestClass
|
6
|
+
include RD3::DataProviders::Rdbms
|
7
|
+
|
8
|
+
def self.config_file_name
|
9
|
+
:mysql
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.table_name
|
13
|
+
RDBMS_SPEC_TABLE_NAME
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class RD3::PostgresqlRdbmsTestClass
|
18
|
+
include RD3::DataProviders::Rdbms
|
19
|
+
|
20
|
+
def self.config_file_name
|
21
|
+
:postgresql
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.table_name
|
25
|
+
RDBMS_SPEC_TABLE_NAME
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe RD3::DataProviders::Rdbms do
|
30
|
+
|
31
|
+
context "mysql" do
|
32
|
+
include_context "shared rdbms context", RD3::MySqlRdbmsTestClass
|
33
|
+
it_behaves_like "data provider", :mysql
|
34
|
+
end
|
35
|
+
|
36
|
+
context "postgresql" do
|
37
|
+
include_context "shared rdbms context", RD3::PostgresqlRdbmsTestClass
|
38
|
+
it_behaves_like "data provider", :postgresql
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
ID = 23
|
4
|
+
ACTIVE = false
|
5
|
+
CREATED_AT = "01/01/01 23:23:59"
|
6
|
+
UPDATED_AT = "02/02/02 23:23:59"
|
7
|
+
EMAIL = 'test@testing.com'
|
8
|
+
AGE = 6
|
9
|
+
|
10
|
+
class TestModel
|
11
|
+
include RD3::Model
|
12
|
+
|
13
|
+
attribute :email
|
14
|
+
attribute :age
|
15
|
+
|
16
|
+
validates :email, :presence => true
|
17
|
+
validates :age, :presence => true
|
18
|
+
end
|
19
|
+
|
20
|
+
describe RD3::Model do
|
21
|
+
|
22
|
+
let(:test_model) { TestModel.new(:id => ID, :email => EMAIL,
|
23
|
+
:age => AGE, :active => ACTIVE,
|
24
|
+
:created_at => CREATED_AT, :updated_at => UPDATED_AT) }
|
25
|
+
|
26
|
+
context 'initializing' do
|
27
|
+
|
28
|
+
it 'should initialize without attributes hash' do
|
29
|
+
tm = TestModel.new
|
30
|
+
tm.should_not be_nil
|
31
|
+
tm.active.should be_true # default value
|
32
|
+
|
33
|
+
# dirty should be false when calling parameterless 'new' method
|
34
|
+
tm.dirty?.should be_false
|
35
|
+
|
36
|
+
# set the id
|
37
|
+
tm.id = 5
|
38
|
+
|
39
|
+
# number of class attributes (array)
|
40
|
+
tm.class_attributes.count.should eq(6)
|
41
|
+
|
42
|
+
# number of attributes (hash of only those properties that have been set thus far)
|
43
|
+
# so, in this example, both active and id properties have been set
|
44
|
+
tm.attributes.count.should eq(2)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should initialize with attributes hash' do
|
48
|
+
test_model.should_not be_nil
|
49
|
+
test_model.email.should eq(EMAIL)
|
50
|
+
test_model.age.should eq(AGE)
|
51
|
+
test_model.active.should eq(ACTIVE)
|
52
|
+
|
53
|
+
# dirty should be true when initializing with a hash
|
54
|
+
test_model.dirty?.should be_true
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should initialize with class instance' do
|
58
|
+
tm = TestModel.new(test_model)
|
59
|
+
tm.should_not be_nil
|
60
|
+
tm.id.should eq(test_model.id)
|
61
|
+
tm.email.should eq(test_model.email)
|
62
|
+
tm.age.should eq(test_model.age)
|
63
|
+
tm.active.should eq(test_model.active)
|
64
|
+
tm.created_at.should eq(test_model.created_at)
|
65
|
+
tm.updated_at.should eq(test_model.updated_at)
|
66
|
+
|
67
|
+
# dirty should be false when calling 'new' method with an instance of a class
|
68
|
+
tm.dirty?.should be_false
|
69
|
+
end
|
70
|
+
|
71
|
+
end # context 'initializing'
|
72
|
+
|
73
|
+
it 'should set dirty flag' do
|
74
|
+
tm = TestModel.new
|
75
|
+
tm.should_not be_nil
|
76
|
+
tm.dirty?.should be_false
|
77
|
+
|
78
|
+
tm.age = 6
|
79
|
+
tm.dirty?.should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should not be persisted' do
|
83
|
+
TestModel.new.persisted?.should be_false
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should be persisted' do
|
87
|
+
test_model.persisted?.should be_true
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should have class attributes' do
|
91
|
+
test_model.class_attributes.should_not be_nil
|
92
|
+
test_model.class_attributes.is_a?(Array)
|
93
|
+
test_model.class_attributes.include?(:id).should be_true
|
94
|
+
test_model.class_attributes.include?(:active).should be_true
|
95
|
+
test_model.class_attributes.include?(:created_at).should be_true
|
96
|
+
test_model.class_attributes.include?(:updated_at).should be_true
|
97
|
+
test_model.class_attributes.include?(:email).should be_true
|
98
|
+
test_model.class_attributes.include?(:age).should be_true
|
99
|
+
|
100
|
+
# dirty should not be a class attribute!!
|
101
|
+
test_model.class_attributes.include?(:dirty).should be_false
|
102
|
+
test_model.class_attributes.count.should eq(6)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should have instance attributes' do
|
106
|
+
test_model.attributes.should_not be_nil
|
107
|
+
test_model.attributes.count.should eq(6)
|
108
|
+
test_model.attributes.is_a?(Hash)
|
109
|
+
test_model.attributes[:id].should eq(ID)
|
110
|
+
test_model.attributes[:active].should eq(ACTIVE)
|
111
|
+
test_model.attributes[:created_at].should eq(CREATED_AT)
|
112
|
+
test_model.attributes[:updated_at].should eq(UPDATED_AT)
|
113
|
+
test_model.attributes[:email].should eq(EMAIL)
|
114
|
+
test_model.attributes[:age].should eq(AGE)
|
115
|
+
test_model.attributes[:dirty].should be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should raise an exception when getting a value for a missing property' do
|
119
|
+
expect { test_model.duodenum }.to raise_error(NoMethodError, /undefined method/)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should raise an exception when setting a value for a missing property' do
|
123
|
+
expect { test_model.duodenum = 6 }.to raise_error(NoMethodError, /undefined method/)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should transfer errors' do
|
127
|
+
test_model.email = nil
|
128
|
+
test_model.age = nil
|
129
|
+
test_model.valid?.should be_false
|
130
|
+
test_model.errors.count.should eq(2)
|
131
|
+
|
132
|
+
test_model2 = TestModel.new(:email => 'testing@rspec.org', :age => 16)
|
133
|
+
test_model2.valid?.should be_true
|
134
|
+
test_model2.errors.count.should eq(0)
|
135
|
+
test_model2.errors = test_model.errors
|
136
|
+
test_model2.errors.count.should eq(2)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should call to_json' do
|
140
|
+
json = test_model.to_json
|
141
|
+
json.class.should eq(String)
|
142
|
+
json.length.should eq(138)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should call as_json' do
|
146
|
+
json = test_model.as_json
|
147
|
+
json.class.should eq(Hash)
|
148
|
+
json.length.should eq(7)
|
149
|
+
json['id'].should eq(ID)
|
150
|
+
json['active'].should eq(ACTIVE)
|
151
|
+
json['created_at'].should eq(CREATED_AT)
|
152
|
+
json['updated_at'].should eq(UPDATED_AT)
|
153
|
+
json['email'].should eq(EMAIL)
|
154
|
+
json['age'].should eq(AGE)
|
155
|
+
json['dirty'].should be_true
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class RD3::RepoTest
|
4
|
+
include RD3::Model
|
5
|
+
end
|
6
|
+
|
7
|
+
class RD3::RepoTestRepository
|
8
|
+
include RD3::Repository
|
9
|
+
|
10
|
+
config_file_name :mysql
|
11
|
+
end
|
12
|
+
|
13
|
+
class RD3::RepoTest2Repository
|
14
|
+
include RD3::Repository
|
15
|
+
|
16
|
+
config_file_name :postgresql_search_db
|
17
|
+
end
|
18
|
+
|
19
|
+
class RD3::NoConfigFileRepository
|
20
|
+
include RD3::Repository
|
21
|
+
end
|
22
|
+
|
23
|
+
describe RD3::Repository do
|
24
|
+
|
25
|
+
let(:mysql_repo) {RD3::RepoTestRepository}
|
26
|
+
let(:postgresql_repo) {RD3::RepoTest2Repository}
|
27
|
+
let(:no_config_file_repo) {RD3::NoConfigFileRepository}
|
28
|
+
|
29
|
+
it 'should set and get config file name' do
|
30
|
+
mysql_repo.config_file_name.should eq(:mysql)
|
31
|
+
postgresql_repo.config_file_name.should eq(:postgresql_search_db)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should derive data provider from config file name' do
|
35
|
+
#mysql_repo.data_provider.should eq(RD3::DataProviders::Rdbms)
|
36
|
+
#postgresql_repo.data_provider.should eq(RD3::DataProviders::Rdbms)
|
37
|
+
mysql_repo.data_provider.should eq(:rdbms)
|
38
|
+
postgresql_repo.data_provider.should eq(:rdbms)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should derive model from repository name' do
|
42
|
+
mysql_repo.model.should eq(RD3::RepoTest)
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'exceptions' do
|
46
|
+
|
47
|
+
it 'should raise type error for unsupported data provider' do
|
48
|
+
expect {no_config_file_repo.config_file_name :unsupported_config_file}.to raise_error TypeError
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should raise not implemented error for find_by_key' do
|
52
|
+
expect {no_config_file_repo.find_by_key(1, nil)}.to raise_error NotImplementedError
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should raise not implemented error for save' do
|
56
|
+
expect {no_config_file_repo.save(nil)}.to raise_error NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should raise not implemented error for delete' do
|
60
|
+
expect {no_config_file_repo.delete(1, nil)}.to raise_error NotImplementedError
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|