traver 0.2.2 → 0.3.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.
- 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
|