traver 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +71 -31
- data/lib/traver/attributes_resolver.rb +27 -0
- data/lib/traver/attributes_resolvers/active_record_attributes_resolver.rb +21 -0
- data/lib/traver/attributes_resolvers/poro_attributes_resolver.rb +24 -0
- data/lib/traver/default_params_creators/active_record_default_params_creator.rb +11 -0
- data/lib/traver/default_params_creators/poro_default_params_creator.rb +7 -0
- data/lib/traver/factories_loader.rb +30 -0
- data/lib/traver/factory.rb +35 -0
- data/lib/traver/factory_definer.rb +26 -32
- data/lib/traver/graph.rb +2 -6
- data/lib/traver/graph_creator.rb +13 -5
- data/lib/traver/list_creator.rb +26 -0
- data/lib/traver/object_creator.rb +174 -46
- data/lib/traver/object_persisters/active_record_object_persister.rb +9 -0
- data/lib/traver/object_persisters/poro_object_persister.rb +6 -0
- data/lib/traver/sequencer.rb +24 -0
- data/lib/traver/settings/active_record_settings.rb +13 -0
- data/lib/traver/settings/poro_settings.rb +13 -0
- data/lib/traver/settings.rb +7 -0
- data/lib/traver/traver_constructor.rb +93 -0
- data/lib/traver/version.rb +1 -1
- data/lib/traver.rb +57 -18
- data/traver.gemspec +3 -1
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 009d9a2721da257a5d9bb38e0196d84668b6dc35
|
4
|
+
data.tar.gz: 4a8aef2efb71d6f859b61e9fd21e52a8f8da2873
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b866419d6f2dddb32299145968d1f6374d5b5966edad94ba61665c6fbd846ecb05d531ca0c6ebb6ab29a8dede324f1f10205e92961d6e56ef03adca765adc0f
|
7
|
+
data.tar.gz: 5736f5f8b098dcff077586255cfb9b211b2f97017df3521c9783a9359ab4e4b4e6c39a2026adca5e7df409c3727bf96fc8ebe888012d4ac4a031573fe2053a69
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ and run `bundle install` from your shell.
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
Create
|
21
|
+
Create object with attributes:
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
blog = Traver.create(blog: { title: "Blog" }) #=> #<Blog @title="Blog">
|
@@ -27,15 +27,26 @@ blog = Traver.create(blog: { title: "Blog" }) #=> #<Blog @title="Blog">
|
|
27
27
|
Define and use factories:
|
28
28
|
|
29
29
|
```ruby
|
30
|
-
Traver.
|
30
|
+
Traver.define_factory(:user, {
|
31
|
+
full_name: "Walter White"
|
32
|
+
})
|
33
|
+
|
34
|
+
Traver.define_factory(:post, {
|
31
35
|
title: "Hello"
|
32
36
|
})
|
33
37
|
|
34
|
-
Traver.
|
38
|
+
Traver.create(:user) #=> #<User @full_name="Walter White">
|
39
|
+
Traver.create(:post) #=> #<Post @title="Hello">
|
40
|
+
```
|
41
|
+
|
42
|
+
Define child factories:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
Traver.define_factory(:published_post, :post, {
|
35
46
|
published: true
|
36
47
|
})
|
37
48
|
|
38
|
-
Traver.
|
49
|
+
Traver.define_factory(:draft_post, :post, {
|
39
50
|
published: false
|
40
51
|
})
|
41
52
|
|
@@ -43,7 +54,7 @@ Traver.create(:published_post) #=> #<Post @title="Hello", @published=true>
|
|
43
54
|
Traver.create(:draft_post) #=> #<Post @title="Hello", @published=false>
|
44
55
|
```
|
45
56
|
|
46
|
-
Create associated
|
57
|
+
Create associated objects:
|
47
58
|
|
48
59
|
```ruby
|
49
60
|
blog = Traver.create(blog: {
|
@@ -54,56 +65,57 @@ blog = Traver.create(blog: {
|
|
54
65
|
blog.user #=> #<User @name="Mike">
|
55
66
|
```
|
56
67
|
|
57
|
-
Create
|
68
|
+
Create associated objects using factory names:
|
58
69
|
|
59
70
|
```ruby
|
71
|
+
Traver.define_factory(:mike, :user, {
|
72
|
+
name: "Mike"
|
73
|
+
})
|
74
|
+
|
60
75
|
blog = Traver.create(blog: {
|
61
76
|
title: "Hello",
|
62
|
-
|
63
|
-
{ title: "Post #1" },
|
64
|
-
{ title: "Post #2" }
|
65
|
-
]
|
77
|
+
user: :mike
|
66
78
|
})
|
67
79
|
|
68
|
-
|
80
|
+
```
|
69
81
|
|
70
|
-
|
82
|
+
Create associated collections:
|
83
|
+
|
84
|
+
```ruby
|
71
85
|
blog = Traver.create(blog: {
|
72
86
|
title: "Hello",
|
73
|
-
posts: [
|
87
|
+
posts: [
|
88
|
+
{ title: "Post #1" },
|
89
|
+
{ title: "Post #2" }
|
90
|
+
]
|
74
91
|
})
|
75
92
|
|
76
93
|
blog.posts #=> [#<Post @title="Post #1">, #<Post @title="Post #2">]
|
77
94
|
|
78
|
-
|
79
|
-
Traver.factory(post: { title: "Post #${n}"})
|
80
|
-
|
81
|
-
# Even more concise
|
82
|
-
blog = Traver.create(blog: { title: "Hello", posts: 2 })
|
95
|
+
```
|
83
96
|
|
84
|
-
|
97
|
+
Create associated collections using numbers:
|
85
98
|
|
99
|
+
```ruby
|
100
|
+
Traver.create(blog: { title: "Hello", posts: 2 })
|
101
|
+
Traver.create(blog: { title: "Hello", posts: [2, title: "Post #${n}"] })
|
102
|
+
Traver.create(blog: { title: "Hello", posts: [2, :published_post] })
|
86
103
|
```
|
87
104
|
|
88
|
-
|
105
|
+
Create associated collections using factory names:
|
89
106
|
|
90
107
|
```ruby
|
91
|
-
|
92
|
-
title: "Blog",
|
93
|
-
posts: [{
|
94
|
-
title: "Hello",
|
95
|
-
tags: [{ name: "Happy" }]
|
96
|
-
}]
|
97
|
-
})
|
98
|
-
|
99
|
-
blog.posts.first.tag.first #=> #<Tag @name="Happy">
|
108
|
+
Traver.create(blog: { title: "Hello", posts: [:published_post, :draft_post] })
|
100
109
|
```
|
101
110
|
|
102
|
-
Create lists:
|
111
|
+
Create lists with sequences:
|
103
112
|
|
104
113
|
```ruby
|
105
|
-
users = Traver.create_list(
|
114
|
+
users = Traver.create_list(2, user: { email: "user${n}@mail.me" })
|
106
115
|
#=> [#<User @email="user1@mail.me">, #<User @email="user2@mail.me">]
|
116
|
+
|
117
|
+
users = Traver.create_list(2, :published_post)
|
118
|
+
#=> [#<Post @published=true>, #<User @published=true>]
|
107
119
|
```
|
108
120
|
|
109
121
|
Graph is a convenient way to reference created objects:
|
@@ -121,6 +133,34 @@ graph.tag2 #=> #<Tag>
|
|
121
133
|
blog, post = Traver.create_graph(blog: { posts: 1 })[:blog, :post]
|
122
134
|
```
|
123
135
|
|
136
|
+
Reference already created objects:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
blog = Traver.create(blog: {
|
140
|
+
post: { tags: 1 }
|
141
|
+
tags: [-> (graph) { graph.tag1 }]
|
142
|
+
})
|
143
|
+
```
|
144
|
+
|
145
|
+
## Rails
|
146
|
+
|
147
|
+
By default Traver loads factories from`test/factories.rb` or `spec/factories.rb` for rspec users.
|
148
|
+
|
149
|
+
Objects for `belongs_to` associations are created automatically:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class Blog < ActiveRecord::Base
|
153
|
+
has_many :blogs
|
154
|
+
end
|
155
|
+
|
156
|
+
class Post < ActiveRecord::Base
|
157
|
+
belongs_to :blog
|
158
|
+
end
|
159
|
+
|
160
|
+
post = Traver.create(:post) #=> #<Post>
|
161
|
+
post.blog #=> #<Blog>
|
162
|
+
```
|
163
|
+
|
124
164
|
## Development
|
125
165
|
|
126
166
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Traver
|
2
|
+
class AttributesResolver
|
3
|
+
def select_attributes_params(params, object_class)
|
4
|
+
params.select { |name, value| regular_attribute?(object_class, name, value) }
|
5
|
+
end
|
6
|
+
|
7
|
+
def select_objects_params(params, object_class)
|
8
|
+
params.select { |name, value| nested_object?(object_class, name, value) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def select_has_one_objects_params(params, object_class)
|
12
|
+
params.select { |name, value| has_one_object?(object_class, name, value) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def select_collections_params(object, factory, params)
|
16
|
+
params.select { |name, value| nested_collection?(factory.object_class, name, value) }
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def regular_attribute?(object_class, name, value)
|
22
|
+
!nested_object?(object_class, name, value) &&
|
23
|
+
!nested_collection?(object_class, name, value) &&
|
24
|
+
!has_one_object?(object_class, name, value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Traver
|
2
|
+
class ActiveRecordAttributesResolver < AttributesResolver
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def nested_object?(object_class, name, value)
|
7
|
+
reflection = object_class.reflect_on_association(name)
|
8
|
+
reflection && reflection.macro == :belongs_to
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_one_object?(object_class, name, value)
|
12
|
+
reflection = object_class.reflect_on_association(name)
|
13
|
+
reflection && reflection.macro == :has_one
|
14
|
+
end
|
15
|
+
|
16
|
+
def nested_collection?(object_class, name, value)
|
17
|
+
reflection = object_class.reflect_on_association(name)
|
18
|
+
reflection && reflection.collection?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Traver
|
2
|
+
class PoroAttributesResolver < AttributesResolver
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def nested_object?(object_class, name, value)
|
7
|
+
Object.const_defined?(name.to_s.camelize)
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_one_object?(object_class, name, value)
|
11
|
+
nested_object?(object_class, name, value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def nested_collection?(object_class, name, value)
|
15
|
+
if plural?(name)
|
16
|
+
Object.const_defined?(name.to_s.singularize.camelize)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def plural?(val)
|
21
|
+
val.to_s.pluralize == val.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Traver
|
2
|
+
class ActiveRecordDefaultParamsCreator
|
3
|
+
def default_params(object_class)
|
4
|
+
associations = object_class.reflect_on_all_associations(:belongs_to)
|
5
|
+
|
6
|
+
associations.each_with_object({}) do |association, result|
|
7
|
+
result[association.name] = :__ref__
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Traver
|
2
|
+
class FactoriesLoader
|
3
|
+
attr_reader :base_dir, :folder_name
|
4
|
+
attr_reader :factories_loaded
|
5
|
+
|
6
|
+
FILE_NAME = "factories.rb"
|
7
|
+
|
8
|
+
def initialize(base_dir, folder_name = "test")
|
9
|
+
@base_dir = base_dir
|
10
|
+
@folder_name = folder_name
|
11
|
+
|
12
|
+
@factories_loaded = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_factories
|
16
|
+
unless factories_loaded
|
17
|
+
factories_file_path = File.join(base_dir, folder_name, FILE_NAME)
|
18
|
+
|
19
|
+
require factories_file_path
|
20
|
+
|
21
|
+
@factories_loaded = true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class NilFactoriesLoader
|
27
|
+
def load_factories
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Traver
|
2
|
+
class Factory
|
3
|
+
attr_reader :name, :params, :parent_factory
|
4
|
+
|
5
|
+
def initialize(name, params, parent_factory)
|
6
|
+
@name = name
|
7
|
+
@params = params
|
8
|
+
@parent_factory = parent_factory
|
9
|
+
end
|
10
|
+
|
11
|
+
def root_factory
|
12
|
+
parent_factory ? parent_factory.root_factory : self
|
13
|
+
end
|
14
|
+
|
15
|
+
def inherited_params
|
16
|
+
if parent_factory
|
17
|
+
parent_factory.inherited_params.merge(params)
|
18
|
+
else
|
19
|
+
params
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def root_name
|
24
|
+
root_factory.name
|
25
|
+
end
|
26
|
+
|
27
|
+
def object_class_name
|
28
|
+
root_factory.name.to_s.camelize
|
29
|
+
end
|
30
|
+
|
31
|
+
def object_class
|
32
|
+
Object.const_get(object_class_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,51 +1,45 @@
|
|
1
1
|
module Traver
|
2
2
|
class FactoryDefiner
|
3
|
-
attr_reader :defined_factories
|
4
|
-
|
5
3
|
def initialize
|
6
|
-
|
4
|
+
undefine_all_factories
|
7
5
|
end
|
8
6
|
|
9
|
-
def
|
10
|
-
|
7
|
+
def define_factory(factory_name, parent_name, params)
|
8
|
+
factories[factory_name] = Factory.new(factory_name, params, factory_by_name(parent_name))
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
params = options.first
|
18
|
-
elsif options.size == 2
|
19
|
-
parent_name, params = options
|
20
|
-
end
|
21
|
-
|
22
|
-
defined_factories[factory_name] = { params: params, parent: parent_name }
|
11
|
+
alias :factory :define_factory
|
12
|
+
|
13
|
+
def factory_params(factory_name)
|
14
|
+
factory_by_name(factory_name).params
|
23
15
|
end
|
24
16
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
17
|
+
def parent_factory_name(factory_name)
|
18
|
+
factory_by_name(factory_name).parent_factory &&
|
19
|
+
factory_by_name(factory_name).parent_factory.name
|
20
|
+
end
|
21
|
+
|
22
|
+
def parent_factory_params(factory_name)
|
23
|
+
factory_by_name(factory_name).parent_factory.params
|
31
24
|
end
|
32
25
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
factory_params.merge(params)
|
26
|
+
def factory_by_name(factory_name)
|
27
|
+
factories[factory_name] || default_factory(factory_name) if factory_name
|
37
28
|
end
|
38
29
|
|
39
|
-
|
30
|
+
def undefine_all_factories
|
31
|
+
@factories = {}
|
32
|
+
end
|
40
33
|
|
41
|
-
def
|
42
|
-
|
43
|
-
get_factory_params(factory[:parent]).merge(factory[:params])
|
44
|
-
end || {}
|
34
|
+
def factories_count
|
35
|
+
factories.keys.length
|
45
36
|
end
|
46
37
|
|
47
|
-
|
48
|
-
|
38
|
+
private
|
39
|
+
attr_reader :factories
|
40
|
+
|
41
|
+
def default_factory(factory_name)
|
42
|
+
Factory.new(factory_name, {}, nil)
|
49
43
|
end
|
50
44
|
end
|
51
45
|
end
|
data/lib/traver/graph.rb
CHANGED
@@ -13,7 +13,7 @@ module Traver
|
|
13
13
|
key = key.to_s
|
14
14
|
|
15
15
|
if plural?(key)
|
16
|
-
vertices[
|
16
|
+
vertices[key.singularize.to_sym]
|
17
17
|
else
|
18
18
|
name, index = key.split(/(\d+)$/)
|
19
19
|
index = (index || 1).to_i
|
@@ -30,11 +30,7 @@ module Traver
|
|
30
30
|
attr_reader :vertices
|
31
31
|
|
32
32
|
def plural?(value)
|
33
|
-
value.
|
34
|
-
end
|
35
|
-
|
36
|
-
def singularize(value)
|
37
|
-
value.chomp("s")
|
33
|
+
value == value.pluralize
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
data/lib/traver/graph_creator.rb
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
module Traver
|
2
2
|
class GraphCreator
|
3
|
-
attr_reader :params
|
3
|
+
attr_reader :factory_name, :params, :factory_definer, :sequencer
|
4
4
|
attr_reader :graph
|
5
5
|
|
6
|
-
def initialize(params
|
7
|
-
@
|
6
|
+
def initialize(factory_name, params, factory_definer, sequencer)
|
7
|
+
@factory_name = factory_name
|
8
|
+
@params = params
|
9
|
+
@factory_definer = factory_definer
|
10
|
+
@sequencer = sequencer
|
11
|
+
|
12
|
+
@object_creator = ObjectCreator.new(factory_name, params, factory_definer, sequencer)
|
13
|
+
|
8
14
|
@graph = Graph.new
|
9
15
|
end
|
10
16
|
|
11
17
|
def create_graph
|
12
|
-
object_creator = ObjectCreator.new(params)
|
13
18
|
object_creator.after_create = lambda do |creator|
|
14
|
-
graph.add_vertex(creator.factory_name, creator.
|
19
|
+
graph.add_vertex(creator.factory_name, creator.object)
|
15
20
|
end
|
16
21
|
|
17
22
|
object_creator.create_object
|
18
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
attr_reader :object_creator
|
19
27
|
end
|
20
28
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Traver
|
2
|
+
class ListCreator
|
3
|
+
attr_reader :num, :factory_name, :params, :factory_definer, :sequencer
|
4
|
+
attr_reader :list
|
5
|
+
|
6
|
+
def initialize(num, factory_name, params, factory_definer, sequencer)
|
7
|
+
@num = num
|
8
|
+
@factory_name = factory_name
|
9
|
+
@params = params
|
10
|
+
@factory_definer = factory_definer
|
11
|
+
@sequencer = sequencer
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_list
|
15
|
+
@list = num.times.map do
|
16
|
+
object_creator.create_object(factory_name, params, factory_definer, sequencer)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def object_creator
|
23
|
+
ObjectCreator
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,92 +1,220 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
1
3
|
module Traver
|
2
4
|
class ObjectCreator
|
3
|
-
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :factory_name, :params, :factory_definer, :sequencer, :cache, :nesting
|
8
|
+
attr_reader :object
|
9
|
+
|
4
10
|
attr_accessor :after_create
|
5
|
-
attr_reader :created_object
|
6
11
|
|
7
|
-
|
8
|
-
|
12
|
+
def_delegators :settings, :object_persister,
|
13
|
+
:attributes_resolver,
|
14
|
+
:default_params_creator
|
15
|
+
|
16
|
+
def self.create_object(factory_name, params, factory_definer, sequencer, cache = {}, nesting = 1)
|
17
|
+
creator = new(factory_name, params, factory_definer, sequencer, cache, nesting)
|
18
|
+
creator.create_object
|
9
19
|
|
10
|
-
|
11
|
-
|
20
|
+
creator.object
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(factory_name, params, factory_definer, sequencer, cache = {}, nesting = 1)
|
24
|
+
@factory_name = factory_name
|
25
|
+
@params = params
|
26
|
+
@factory_definer = factory_definer
|
27
|
+
@sequencer = sequencer
|
28
|
+
@cache = cache
|
29
|
+
@nesting = nesting
|
12
30
|
end
|
13
31
|
|
14
32
|
def create_object
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
33
|
+
obtain_factory
|
34
|
+
|
35
|
+
if obtain_object_from_cache?
|
36
|
+
obtain_object_from_cache
|
37
|
+
else
|
38
|
+
# puts "#{'-' * nesting} #{factory_name}<br/>"
|
39
|
+
|
40
|
+
change_ref_to_be_empty_hash
|
41
|
+
merge_factory_params
|
42
|
+
merge_default_params
|
43
|
+
instantiate_object
|
44
|
+
set_nested_objects
|
45
|
+
set_attributes
|
46
|
+
persist_object
|
47
|
+
set_has_one_objects
|
48
|
+
set_nested_collections
|
49
|
+
call_after_create_hook
|
50
|
+
end
|
19
51
|
end
|
20
52
|
|
21
53
|
private
|
22
|
-
attr_reader :
|
54
|
+
attr_reader :factory
|
55
|
+
|
56
|
+
def obtain_factory
|
57
|
+
@factory = factory_definer.factory_by_name(factory_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def obtain_object_from_cache?
|
61
|
+
params == :__ref__ && cache.has_key?(factory.root_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def obtain_object_from_cache
|
65
|
+
@object = cache[factory.root_name]
|
66
|
+
end
|
67
|
+
|
68
|
+
def change_ref_to_be_empty_hash
|
69
|
+
@params = {} if params == :__ref__
|
70
|
+
end
|
71
|
+
|
72
|
+
def merge_factory_params
|
73
|
+
@params = factory.inherited_params.merge(params)
|
74
|
+
end
|
75
|
+
|
76
|
+
def merge_default_params
|
77
|
+
@params = default_params_creator.default_params(factory.object_class).merge(params)
|
78
|
+
end
|
23
79
|
|
24
80
|
def instantiate_object
|
25
|
-
@
|
81
|
+
@object = factory.object_class.new
|
26
82
|
end
|
27
83
|
|
28
|
-
|
29
|
-
|
84
|
+
# Attributes
|
85
|
+
|
86
|
+
def set_attributes
|
87
|
+
attributes_resolver.select_attributes_params(params, factory.object_class).each do |name, value|
|
88
|
+
set_attribute(name, value)
|
89
|
+
end
|
30
90
|
end
|
31
91
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
else
|
39
|
-
set_attribute(attribute, value)
|
92
|
+
def set_attribute(attribute, value)
|
93
|
+
if value.is_a?(Proc)
|
94
|
+
value = object.instance_exec(&value)
|
95
|
+
elsif value.is_a?(String)
|
96
|
+
if sequencer.value_has_sequence?(value)
|
97
|
+
value = sequencer.interpolate_sequence(attribute, value)
|
40
98
|
end
|
41
99
|
end
|
100
|
+
|
101
|
+
object.public_send("#{attribute}=", value)
|
42
102
|
end
|
43
|
-
|
44
|
-
def factory_params
|
45
|
-
factory_definer.apply_factory_params(factory_name, params)
|
46
|
-
end
|
47
103
|
|
48
|
-
|
49
|
-
|
104
|
+
# Nested Objects
|
105
|
+
|
106
|
+
def set_nested_objects
|
107
|
+
attributes_resolver.select_objects_params(params, factory.object_class).each do |name, value|
|
108
|
+
set_nested_object(name, value)
|
109
|
+
end
|
50
110
|
end
|
51
111
|
|
52
|
-
def
|
53
|
-
|
112
|
+
def set_nested_object(name, value)
|
113
|
+
if value.is_a?(Integer)
|
114
|
+
set_attribute(name, create_nested_object(name, {}))
|
115
|
+
elsif value.is_a?(Hash) || value == :__ref__
|
116
|
+
set_attribute(name, create_nested_object(name, value))
|
117
|
+
elsif value.is_a?(Symbol)
|
118
|
+
set_attribute(name, create_nested_object(value, {}))
|
119
|
+
else
|
120
|
+
set_attribute(name, value)
|
121
|
+
end
|
54
122
|
end
|
55
123
|
|
56
|
-
def
|
57
|
-
object_creator = ObjectCreator.new(params)
|
124
|
+
def create_nested_object(factory_name, params)
|
125
|
+
object_creator = ObjectCreator.new(factory_name, params, factory_definer, sequencer, cache, nesting + 1)
|
58
126
|
object_creator.after_create = after_create
|
59
127
|
object_creator.create_object
|
60
128
|
|
61
|
-
object_creator.
|
129
|
+
object_creator.object
|
62
130
|
end
|
63
131
|
|
64
|
-
def set_attribute(attribute, value)
|
65
|
-
created_object.public_send("#{attribute}=", value)
|
66
|
-
end
|
67
132
|
|
68
|
-
|
69
|
-
|
133
|
+
# Has one objects
|
134
|
+
|
135
|
+
def set_has_one_objects
|
136
|
+
attributes_resolver.select_has_one_objects_params(params, factory.object_class).each do |name, value|
|
137
|
+
set_nested_object(name, value)
|
138
|
+
end
|
70
139
|
end
|
71
140
|
|
72
|
-
|
73
|
-
|
74
|
-
|
141
|
+
# Nested Collections
|
142
|
+
|
143
|
+
def set_nested_collections
|
144
|
+
attributes_resolver.select_collections_params(object, factory, params).each do |collection_name, params_array|
|
145
|
+
set_nested_collection(collection_name, params_array)
|
75
146
|
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def set_nested_collection(collection_name, params_array)
|
150
|
+
factory_name = collection_name.to_s.singularize.to_sym
|
76
151
|
|
77
|
-
set_attribute(
|
152
|
+
set_attribute(collection_name, create_nested_collection(factory_name, params_array))
|
78
153
|
end
|
79
154
|
|
80
|
-
def
|
81
|
-
|
155
|
+
def create_nested_collection(factory_name, params_array)
|
156
|
+
if params_array.is_a?(Integer)
|
157
|
+
params_array = [{}] * params_array
|
158
|
+
|
159
|
+
params_array.map do |params|
|
160
|
+
create_nested_object(factory_name, params)
|
161
|
+
end
|
162
|
+
elsif params_array.first.is_a?(Symbol)
|
163
|
+
params_array.map do |factory_name|
|
164
|
+
create_nested_object(factory_name, {})
|
165
|
+
end
|
166
|
+
else
|
167
|
+
if params_array.first.is_a?(Integer)
|
168
|
+
num, hash_or_symbol = params_array
|
169
|
+
|
170
|
+
if hash_or_symbol.nil?
|
171
|
+
params_array = [{}] * num
|
172
|
+
elsif (hash = hash_or_symbol).is_a?(Hash)
|
173
|
+
params_array = [hash] * num
|
174
|
+
elsif hash_or_symbol.is_a?(Symbol)
|
175
|
+
factory_name = hash_or_symbol
|
176
|
+
|
177
|
+
params_array = [{}] * num
|
178
|
+
else
|
179
|
+
raise "Wrong collection params #{params_array}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
params_array.map do |params|
|
184
|
+
create_nested_object(factory_name, params)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Settings
|
190
|
+
|
191
|
+
|
192
|
+
def settings
|
193
|
+
@settings ||=
|
194
|
+
if object_is_active_record?
|
195
|
+
ActiveRecordSettings.new
|
196
|
+
else
|
197
|
+
PoroSettings.new
|
198
|
+
end
|
82
199
|
end
|
83
200
|
|
201
|
+
def object_is_active_record?
|
202
|
+
factory.object_class < ActiveRecord::Base
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
# Persist Object
|
207
|
+
|
84
208
|
def persist_object
|
85
|
-
|
209
|
+
object_persister.persist_object(object)
|
210
|
+
cache[factory.root_name] = object
|
86
211
|
end
|
87
212
|
|
213
|
+
|
214
|
+
# Hooks
|
215
|
+
|
88
216
|
def call_after_create_hook
|
89
217
|
after_create.call(self) if after_create
|
90
218
|
end
|
91
219
|
end
|
92
|
-
end
|
220
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Sequencer
|
2
|
+
attr_reader :sequence_store
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@sequence_store = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def value_has_sequence?(value)
|
9
|
+
!!(value =~ /\$\{n\}/)
|
10
|
+
end
|
11
|
+
|
12
|
+
def interpolate_sequence(name, value)
|
13
|
+
value.sub("${n}", next_sequence_value_for(name).to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def next_sequence_value_for(name)
|
19
|
+
sequence_store[name] ||= 0
|
20
|
+
sequence_store[name] += 1
|
21
|
+
|
22
|
+
sequence_store[name]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "traver/settings"
|
2
|
+
|
3
|
+
module Traver
|
4
|
+
class ActiveRecordSettings < Settings
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
|
8
|
+
@object_persister = ActiveRecordObjectPersister.new
|
9
|
+
@attributes_resolver = ActiveRecordAttributesResolver.new
|
10
|
+
@default_params_creator = ActiveRecordDefaultParamsCreator.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "traver/settings"
|
2
|
+
|
3
|
+
module Traver
|
4
|
+
class PoroSettings < Settings
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
|
8
|
+
@object_persister = PoroObjectPersister.new
|
9
|
+
@attributes_resolver = PoroAttributesResolver.new
|
10
|
+
@default_params_creator = PoroDefaultParamsCreator.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Traver
|
2
|
+
class TraverConstructor
|
3
|
+
attr_reader :factory_definer, :sequencer
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@factory_definer = FactoryDefiner.new
|
7
|
+
@sequencer = Sequencer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def create(*options)
|
11
|
+
factory_name, params = parse_create_options(options)
|
12
|
+
|
13
|
+
ObjectCreator.create_object(factory_name, params, factory_definer, sequencer)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_graph(*options)
|
17
|
+
factory_name, params = parse_create_options(options)
|
18
|
+
|
19
|
+
graph_creator = GraphCreator.new(factory_name, params, factory_definer, sequencer)
|
20
|
+
graph_creator.create_graph
|
21
|
+
|
22
|
+
graph_creator.graph
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_list(num, *options)
|
26
|
+
factory_name, params = parse_create_options(options)
|
27
|
+
|
28
|
+
list_creator = ListCreator.new(num, factory_name, params, factory_definer, sequencer)
|
29
|
+
list_creator.create_list
|
30
|
+
|
31
|
+
list_creator.list
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_factories(&block)
|
35
|
+
instance_exec(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :factories :define_factories
|
39
|
+
|
40
|
+
def define_factory(factory_name, *options)
|
41
|
+
parent_factory_name, params = parse_factory_options(options)
|
42
|
+
|
43
|
+
factory_definer.define_factory(factory_name, parent_factory_name, params)
|
44
|
+
end
|
45
|
+
|
46
|
+
alias :factory :define_factory
|
47
|
+
|
48
|
+
def undefine_all_factories
|
49
|
+
factory_definer.undefine_all_factories
|
50
|
+
end
|
51
|
+
|
52
|
+
def factories_count
|
53
|
+
factory_definer.factories_count
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def parse_create_options(options)
|
59
|
+
if factory_girl_options?(options)
|
60
|
+
parse_factory_girl_options(options)
|
61
|
+
else
|
62
|
+
parse_traver_options(options)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def factory_girl_options?(options)
|
67
|
+
options.first.is_a?(Symbol)
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_factory_girl_options(options)
|
71
|
+
factory_name, params = options
|
72
|
+
params ||= {}
|
73
|
+
|
74
|
+
[factory_name, params]
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_traver_options(options)
|
78
|
+
options.first.first
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse_factory_options(options)
|
82
|
+
parent_factory_name = nil
|
83
|
+
|
84
|
+
if options.size == 1
|
85
|
+
params = options.first
|
86
|
+
elsif options.size == 2
|
87
|
+
parent_factory_name, params = options
|
88
|
+
end
|
89
|
+
|
90
|
+
[parent_factory_name, params]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/traver/version.rb
CHANGED
data/lib/traver.rb
CHANGED
@@ -1,28 +1,67 @@
|
|
1
|
-
require "
|
2
|
-
|
3
|
-
|
4
|
-
require "traver/graph"
|
5
|
-
require "traver/graph_creator"
|
1
|
+
require "active_support/inflector"
|
2
|
+
|
3
|
+
Dir["#{File.dirname(__FILE__)}/traver/**/*.rb"].each { |file| require file }
|
6
4
|
|
7
5
|
module Traver
|
8
6
|
class Error < Exception; end
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
class << self
|
9
|
+
attr_reader :factories_loaded
|
10
|
+
|
11
|
+
def create(*options)
|
12
|
+
load_factories
|
13
|
+
|
14
|
+
traver_constructor.create(*options)
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
def create_graph(*options)
|
18
|
+
load_factories
|
19
|
+
|
20
|
+
traver_constructor.create_graph(*options)
|
21
|
+
end
|
18
22
|
|
19
|
-
|
20
|
-
|
23
|
+
def create_list(num, *options)
|
24
|
+
load_factories
|
25
|
+
|
26
|
+
traver_constructor.create_list(num, *options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def define_factory(factory_name, *options)
|
30
|
+
traver_constructor.define_factory(factory_name, *options)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias :factory :define_factory
|
34
|
+
|
35
|
+
def define_factories(&block)
|
36
|
+
traver_constructor.define_factories(&block)
|
37
|
+
end
|
38
|
+
|
39
|
+
alias :factories :define_factories
|
21
40
|
|
22
|
-
|
23
|
-
|
24
|
-
|
41
|
+
def undefine_all_factories
|
42
|
+
traver_constructor.undefine_all_factories
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def traver_constructor
|
48
|
+
@traver_constructor ||= TraverConstructor.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_factories
|
52
|
+
unless factories_loaded
|
53
|
+
factories_loader.load_factories
|
54
|
+
|
55
|
+
@factories_loaded = true
|
56
|
+
end
|
57
|
+
end
|
25
58
|
|
26
|
-
|
59
|
+
def factories_loader
|
60
|
+
if defined?(Rails)
|
61
|
+
FactoriesLoader.new(Rails.root, "spec")
|
62
|
+
else
|
63
|
+
NilFactoriesLoader.new
|
64
|
+
end
|
65
|
+
end
|
27
66
|
end
|
28
67
|
end
|
data/traver.gemspec
CHANGED
@@ -18,7 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.bindir = "exe"
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
|
-
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "activesupport"
|
23
|
+
|
22
24
|
spec.add_development_dependency "bundler", "~> 1.11"
|
23
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
26
|
spec.add_development_dependency "minitest", "~> 5.0"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: traver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuri Kaspervich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,10 +110,25 @@ files:
|
|
96
110
|
- bin/console
|
97
111
|
- bin/setup
|
98
112
|
- lib/traver.rb
|
113
|
+
- lib/traver/attributes_resolver.rb
|
114
|
+
- lib/traver/attributes_resolvers/active_record_attributes_resolver.rb
|
115
|
+
- lib/traver/attributes_resolvers/poro_attributes_resolver.rb
|
116
|
+
- lib/traver/default_params_creators/active_record_default_params_creator.rb
|
117
|
+
- lib/traver/default_params_creators/poro_default_params_creator.rb
|
118
|
+
- lib/traver/factories_loader.rb
|
119
|
+
- lib/traver/factory.rb
|
99
120
|
- lib/traver/factory_definer.rb
|
100
121
|
- lib/traver/graph.rb
|
101
122
|
- lib/traver/graph_creator.rb
|
123
|
+
- lib/traver/list_creator.rb
|
102
124
|
- lib/traver/object_creator.rb
|
125
|
+
- lib/traver/object_persisters/active_record_object_persister.rb
|
126
|
+
- lib/traver/object_persisters/poro_object_persister.rb
|
127
|
+
- lib/traver/sequencer.rb
|
128
|
+
- lib/traver/settings.rb
|
129
|
+
- lib/traver/settings/active_record_settings.rb
|
130
|
+
- lib/traver/settings/poro_settings.rb
|
131
|
+
- lib/traver/traver_constructor.rb
|
103
132
|
- lib/traver/version.rb
|
104
133
|
- traver.gemspec
|
105
134
|
homepage: http://github.com/yukas/traver
|