rmodel 0.4.0.dev → 1.0.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +4 -0
  4. data/.travis.yml +4 -3
  5. data/README.md +119 -153
  6. data/Rakefile +1 -2
  7. data/examples/mongo_embedded.rb +27 -21
  8. data/examples/scopes.rb +28 -0
  9. data/examples/sql_repository.rb +14 -26
  10. data/examples/timestamps.rb +7 -10
  11. data/examples/webapp/models/task.rb +9 -0
  12. data/examples/webapp/repositories/task_repository.rb +14 -0
  13. data/examples/webapp/server.rb +25 -0
  14. data/examples/webapp/support/mappers.rb +11 -0
  15. data/examples/webapp/support/repositories.rb +12 -0
  16. data/examples/webapp/support/sources.rb +13 -0
  17. data/examples/webapp/views/index.erb +20 -0
  18. data/lib/rmodel.rb +11 -8
  19. data/lib/rmodel/array_mapper.rb +23 -0
  20. data/lib/rmodel/base_mapper.rb +56 -0
  21. data/lib/rmodel/dummy_mapper.rb +15 -0
  22. data/lib/rmodel/mongo/mapper.rb +11 -0
  23. data/lib/rmodel/mongo/source.rb +50 -0
  24. data/lib/rmodel/repository.rb +36 -0
  25. data/lib/rmodel/repository_ext/scopable.rb +44 -0
  26. data/lib/rmodel/repository_ext/sugarable.rb +35 -0
  27. data/lib/rmodel/repository_ext/timestampable.rb +29 -0
  28. data/lib/rmodel/scope.rb +31 -0
  29. data/lib/rmodel/sequel/mapper.rb +6 -0
  30. data/lib/rmodel/sequel/source.rb +43 -0
  31. data/lib/rmodel/uni_hash.rb +16 -0
  32. data/lib/rmodel/version.rb +1 -1
  33. data/rmodel.gemspec +9 -3
  34. data/spec/rmodel/array_mapper_spec.rb +43 -0
  35. data/spec/rmodel/mongo/mapper_spec.rb +154 -0
  36. data/spec/rmodel/mongo/repository_spec.rb +16 -37
  37. data/spec/rmodel/mongo/source_spec.rb +113 -0
  38. data/spec/rmodel/sequel/mapper_spec.rb +57 -0
  39. data/spec/rmodel/sequel/repository_spec.rb +27 -38
  40. data/spec/rmodel/sequel/source_spec.rb +121 -0
  41. data/spec/shared/base_mapper.rb +39 -0
  42. data/spec/shared/clean_moped.rb +6 -2
  43. data/spec/shared/clean_sequel.rb +1 -1
  44. data/spec/shared/{repository_ext → repository}/crud.rb +20 -14
  45. data/spec/shared/repository/initialization.rb +39 -0
  46. data/spec/shared/repository/scopable.rb +137 -0
  47. data/spec/shared/repository/sugarable.rb +67 -0
  48. data/spec/shared/repository/timestampable.rb +137 -0
  49. data/spec/spec_helper.rb +17 -18
  50. metadata +120 -54
  51. data/examples/advanced_creation_of_repository.rb +0 -15
  52. data/examples/user.rb +0 -48
  53. data/lib/rmodel/base/repository.rb +0 -12
  54. data/lib/rmodel/base/repository_ext/sugarable.rb +0 -17
  55. data/lib/rmodel/base/repository_ext/timestampable.rb +0 -19
  56. data/lib/rmodel/mongo/repository.rb +0 -62
  57. data/lib/rmodel/mongo/repository_ext/query.rb +0 -34
  58. data/lib/rmodel/mongo/repository_ext/queryable.rb +0 -34
  59. data/lib/rmodel/mongo/setup.rb +0 -17
  60. data/lib/rmodel/mongo/simple_factory.rb +0 -78
  61. data/lib/rmodel/sequel/repository.rb +0 -61
  62. data/lib/rmodel/sequel/repository_ext/query.rb +0 -34
  63. data/lib/rmodel/sequel/repository_ext/queryable.rb +0 -30
  64. data/lib/rmodel/sequel/setup.rb +0 -12
  65. data/lib/rmodel/sequel/simple_factory.rb +0 -28
  66. data/lib/rmodel/setup.rb +0 -34
  67. data/spec/rmodel/mongo/repository_ext/queryable_spec.rb +0 -103
  68. data/spec/rmodel/mongo/repository_initialize_spec.rb +0 -174
  69. data/spec/rmodel/mongo/simple_factory_spec.rb +0 -195
  70. data/spec/rmodel/sequel/repository_ext/queryable_spec.rb +0 -114
  71. data/spec/rmodel/sequel/repository_initialize_spec.rb +0 -118
  72. data/spec/rmodel/sequel/simple_factory_spec.rb +0 -55
  73. data/spec/rmodel/setup_spec.rb +0 -54
  74. data/spec/shared/repository_ext/sugarable.rb +0 -44
  75. data/spec/shared/repository_ext/timestampable.rb +0 -67
@@ -1,114 +0,0 @@
1
- RSpec.describe Rmodel::Sequel::Repository do
2
- include_context 'clean sequel database'
3
-
4
- before do
5
- create_database
6
- stub_const('Thing', Struct.new(:id, :a, :b))
7
- stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
8
- end
9
-
10
- subject do
11
- factory = Rmodel::Sequel::SimpleFactory.new(Thing, :a, :b)
12
- ThingRepository.new(sequel_conn, :things, factory)
13
- end
14
-
15
- before do
16
- subject.insert(Thing.new(nil, 2, 3))
17
- subject.insert(Thing.new(nil, 2, 4))
18
- subject.insert(Thing.new(nil, 5, 6))
19
- end
20
-
21
- describe '.scope' do
22
- context 'when a scope w/o arguments is defined' do
23
- before do
24
- ThingRepository.class_eval do
25
- scope :a_equals_2 do
26
- where(a: 2)
27
- end
28
- end
29
- end
30
-
31
- it 'works!' do
32
- expect(subject.query.a_equals_2.count).to eq 2
33
- end
34
-
35
- it 'returns an array of instances of the appropriate class' do
36
- expect(subject.query.a_equals_2.first).to be_an_instance_of Thing
37
- end
38
- end
39
-
40
- context 'when a scope w/ arguments is defined' do
41
- before do
42
- ThingRepository.class_eval do
43
- scope :a_equals do |n|
44
- where(a: n)
45
- end
46
- end
47
- end
48
-
49
- it 'works!' do
50
- expect(subject.query.a_equals(2).count).to eq 2
51
- end
52
- end
53
-
54
- context 'when two scopes are defined and chained' do
55
- before do
56
- ThingRepository.class_eval do
57
- scope :a_equals do |n|
58
- where(a: n)
59
- end
60
-
61
- scope :b_equals do |n|
62
- where(b: n)
63
- end
64
- end
65
- end
66
-
67
- it 'works!' do
68
- expect(subject.query.a_equals(2).b_equals(4).count).to eq 1
69
- end
70
- end
71
-
72
- context 'when an unknown scope is used' do
73
- it 'raises the NoMethodError' do
74
- expect {
75
- subject.query.something
76
- }.to raise_error NoMethodError
77
- end
78
- end
79
- end
80
-
81
- describe '.query' do
82
- describe '#remove' do
83
- context 'when no scope is given' do
84
- it 'removes all objects' do
85
- subject.query.remove
86
- expect(subject.query.count).to eq 0
87
- end
88
- end
89
-
90
- context 'when the scope filters 2 objects from 3' do
91
- before do
92
- ThingRepository.class_eval do
93
- scope :a_equals_2 do
94
- where(a: 2)
95
- end
96
- end
97
- end
98
-
99
- it 'removes 2 objects' do
100
- subject.query.a_equals_2.remove
101
- expect(subject.query.count).to eq 1
102
- end
103
- end
104
- end
105
- end
106
-
107
- def create_database
108
- sequel_conn.create_table(:things) do
109
- primary_key :id
110
- Integer :a
111
- Integer :b
112
- end
113
- end
114
- end
@@ -1,118 +0,0 @@
1
- RSpec.describe Rmodel::Sequel::Repository do
2
- before do
3
- stub_const('Thing', Struct.new(:id, :name))
4
- stub_const('ThingRepository', Class.new(Rmodel::Sequel::Repository))
5
- ThingRepository.send :attr_reader, :client, :table, :factory
6
- end
7
- let(:factory) { Rmodel::Sequel::SimpleFactory.new(Thing, :name) }
8
-
9
- describe '.client(name)' do
10
- conn_options = { adapter: 'sqlite', database: 'rmodel_test.sqlite3' }
11
-
12
- subject { ThingRepository.new(nil, :things, factory) }
13
-
14
- context 'when it is called with an existent name' do
15
- before do
16
- Rmodel.setup do
17
- client :not_default, conn_options
18
- end
19
-
20
- ThingRepository.class_eval do
21
- client :not_default
22
- end
23
- end
24
- after { Rmodel::setup.clear }
25
-
26
- it 'sets the appropriate #client' do
27
- expect(subject.client).to be_a_kind_of Sequel::Database
28
- end
29
- end
30
-
31
- context 'when it is called with a non-existent name' do
32
- before do
33
- ThingRepository.class_eval do
34
- client :not_default
35
- end
36
- end
37
-
38
- it 'makes #initialize raise the ArgumentError' do
39
- expect { subject }.to raise_error ArgumentError
40
- end
41
- end
42
-
43
- context 'when it is not called' do
44
- context 'when the :default client is set' do
45
- before do
46
- Rmodel.setup do
47
- client :default, conn_options
48
- end
49
- end
50
- after { Rmodel::setup.clear }
51
-
52
- it 'sets #client to be default' do
53
- expect(subject.client).to be_a_kind_of Sequel::Database
54
- end
55
- end
56
-
57
- context 'when the :default client is not set' do
58
- it 'makes #initialize raise the ArgumentError' do
59
- expect { subject }.to raise_error ArgumentError
60
- end
61
- end
62
- end
63
- end
64
-
65
- describe '.table(name)' do
66
- subject { ThingRepository.new(Object.new, nil, factory) }
67
-
68
- context 'when the :people table is given' do
69
- before do
70
- ThingRepository.class_eval do
71
- table :people
72
- end
73
- end
74
-
75
- it 'uses the :people' do
76
- expect(subject.table).to eq :people
77
- end
78
- end
79
-
80
- context 'when no table is given' do
81
- it 'gets the right name by convention' do
82
- expect(subject.table).to eq :things
83
- end
84
- end
85
- end
86
-
87
- describe '.simple_factory(klass, attribute1, attribute2, ...)' do
88
- subject { ThingRepository.new(Object.new, :things) }
89
-
90
- context 'when it is called' do
91
- before do
92
- ThingRepository.class_eval do
93
- simple_factory Thing, :name, :email
94
- end
95
- end
96
-
97
- it 'sets the appropriate #factory' do
98
- expect(subject.factory).to be_an_instance_of Rmodel::Sequel::SimpleFactory
99
- end
100
- end
101
-
102
- context 'when it is not called' do
103
- it 'make #initialize raise an error' do
104
- expect { subject }.to raise_error ArgumentError
105
- end
106
- end
107
- end
108
-
109
- describe '#initialize(client, collection, factory)' do
110
- context 'when all constructor arguments are passed' do
111
- it 'works!' do
112
- expect {
113
- ThingRepository.new(Object.new, :users, factory)
114
- }.not_to raise_error
115
- end
116
- end
117
- end
118
- end
@@ -1,55 +0,0 @@
1
- RSpec.describe Rmodel::Sequel::SimpleFactory do
2
- context 'when the User(id, name, email) class is defined' do
3
- before { stub_const('User', Struct.new(:id, :name, :email)) }
4
-
5
- subject { described_class.new(User, :name, :email) }
6
-
7
- describe '#fromHash' do
8
- context 'when the hash with id, name and email is given' do
9
- let(:hash) { { id: 1, name: 'John', email: 'john@example.com' } }
10
- let(:result) { subject.fromHash(hash) }
11
-
12
- it 'returns an instance of User' do
13
- expect(result).to be_an_instance_of User
14
- end
15
-
16
- it 'sets the attributes correctly' do
17
- expect(result.name).to eq 'John'
18
- expect(result.email).to eq 'john@example.com'
19
- end
20
-
21
- it 'sets the User#id correctly' do
22
- expect(result.id).to eq 1
23
- end
24
- end
25
- end
26
-
27
- describe '#toHash' do
28
- let(:user) { User.new(1, 'John', 'john@example.com') }
29
- context 'when id_included is false' do
30
- let(:result) { subject.toHash(user, false) }
31
-
32
- it 'returns an instance of Hash' do
33
- expect(result).to be_an_instance_of Hash
34
- end
35
-
36
- it 'sets the keys correctly' do
37
- expect(result[:name]).to eq 'John'
38
- expect(result[:email]).to eq 'john@example.com'
39
- end
40
-
41
- it 'has no the "id" key' do
42
- expect(result.has_key?(:id)).to be false
43
- end
44
- end
45
-
46
- context 'when id_included is true' do
47
- let(:result) { subject.toHash(user, true) }
48
-
49
- it 'sets the "id" key' do
50
- expect(result[:id]).to eq 1
51
- end
52
- end
53
- end
54
- end
55
- end
@@ -1,54 +0,0 @@
1
- RSpec.describe Rmodel do
2
- describe '.setup' do
3
- before { Rmodel::Setup.instance.clear }
4
- context 'when no block is passed' do
5
- it 'returns Rmodel::Setup.instance' do
6
- expect(Rmodel.setup).to equal Rmodel::Setup.instance
7
- end
8
- end
9
-
10
- context 'when the block is passed' do
11
- let(:clients_config) { Rmodel::Setup.instance.instance_variable_get('@clients_config') }
12
-
13
- it 'returns Rmodel::Setup.instance' do
14
- expect(Rmodel.setup).to equal Rmodel::Setup.instance
15
- end
16
-
17
- it 'runs setup methods within the block' do
18
- Rmodel.setup do
19
- client :default, {}
20
- end
21
- expect(clients_config[:default]).to eq({})
22
- end
23
- end
24
- end
25
-
26
- describe Rmodel::Setup do
27
- subject { Rmodel::Setup.instance }
28
- let(:clients_config) { subject.instance_variable_get('@clients_config') }
29
-
30
- describe '#new' do
31
- it 'raises the NoMethodError' do
32
- expect { Rmodel::Setup.new }.to raise_error NoMethodError
33
- end
34
- end
35
-
36
- describe '#client(name, config)' do
37
- it 'makes config available via #clients[name]' do
38
- subject.client :default, { host: 'localhost' }
39
- expect(clients_config[:default]).to eq( host: 'localhost' )
40
- end
41
- end
42
-
43
- describe '#clear' do
44
- context 'when one client is set' do
45
- before { subject.client :default, { host: 'localhost' } }
46
-
47
- it 'removes all clients' do
48
- subject.clear
49
- expect(clients_config).to be_empty
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,44 +0,0 @@
1
- RSpec.shared_examples 'sugarable repository' do
2
- before do
3
- stub_const('Thing', Struct.new(:id, :name))
4
- end
5
-
6
- describe '#find!' do
7
- context 'when an existent id is given' do
8
- before { subject.insert(Thing.new(1)) }
9
-
10
- it 'returns the right instance' do
11
- expect(subject.find!(1)).not_to be_nil
12
- end
13
- end
14
-
15
- context 'when a non-existent id is given' do
16
- it 'raises NotFound' do
17
- expect {
18
- subject.find!(1)
19
- }.to raise_error Rmodel::NotFound
20
- end
21
- end
22
- end
23
-
24
- describe 'save' do
25
- let(:thing) { Thing.new }
26
-
27
- context 'when a new object is given' do
28
- it 'gets inserted' do
29
- subject.save(thing)
30
- expect(subject.find(thing.id)).not_to be_nil
31
- end
32
- end
33
-
34
- context 'when an existent object is given' do
35
- before { subject.insert(thing) }
36
-
37
- it 'gets updated' do
38
- thing.name = 'chair'
39
- subject.save(thing)
40
- expect(subject.find(thing.id).name).to eq 'chair'
41
- end
42
- end
43
- end
44
- end
@@ -1,67 +0,0 @@
1
- RSpec.shared_examples 'timestampable repository' do
2
- context 'when the entity object has attributes created_at and updated_at' do
3
- before do
4
- stub_const('Thing', Struct.new(:id, :name, :created_at, :updated_at))
5
- end
6
-
7
- subject { repo_w_timestamps }
8
-
9
- context 'when we insert(object)' do
10
- context 'and the object.created_at is already set' do
11
- let(:thing) { Thing.new(nil, 'chair', Time.now) }
12
-
13
- it 'doesnt change the value of created_at' do
14
- set_created_at = thing.created_at
15
- subject.insert(thing)
16
- expect(thing.created_at).to eq set_created_at
17
- end
18
- end
19
-
20
- context 'and the object.created_at is not set yet' do
21
- let(:thing) { Thing.new(nil, 'chair') }
22
-
23
- it 'sets the value of created_at' do
24
- subject.insert(thing)
25
- expect(thing.created_at).not_to be_nil
26
- end
27
- end
28
- end
29
-
30
- context 'when we update(object)' do
31
- let(:thing) { Thing.new(nil, 'chair') }
32
- before { subject.insert(thing) }
33
-
34
- it 'sets the value of created_at' do
35
- thing.name = 'table'
36
- subject.update(thing)
37
- expect(thing.updated_at).not_to be_nil
38
- end
39
- end
40
- end
41
-
42
- context 'when the entity has no attributes :created_at and updated_at' do
43
- before do
44
- stub_const('Thing', Struct.new(:id, :name))
45
- end
46
-
47
- let(:thing) { Thing.new(nil, 'chair') }
48
- subject { repo_wo_timestamps }
49
-
50
- context 'when we insert(object)' do
51
- it 'does nothing special' do
52
- subject.insert(thing)
53
- expect(thing.respond_to?(:created_at)).to be false
54
- end
55
- end
56
-
57
- context 'when we update(object)' do
58
- before { subject.insert(thing) }
59
-
60
- it 'does nothing special' do
61
- thing.name = 'table'
62
- subject.update(thing)
63
- expect(thing.respond_to?(:updated_at)).to be false
64
- end
65
- end
66
- end
67
- end