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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed508040aa612bbd6bd5755a5078ef5e2254abb0
4
- data.tar.gz: 0aba48d5e505bc9bf9541ad84d3d993400392ecc
3
+ metadata.gz: 009d9a2721da257a5d9bb38e0196d84668b6dc35
4
+ data.tar.gz: 4a8aef2efb71d6f859b61e9fd21e52a8f8da2873
5
5
  SHA512:
6
- metadata.gz: 1f99785aef8bf9e7ff8a4dd4f31c4a0d423465e4f023065037964f6f3b81dbb59a9946415569514cfb4c472cfb336905027419acc89f1cac5330cfb355ec46a4
7
- data.tar.gz: 276b82bd4f7b1f3954dfbc7c14076c17784aadc08f3539c865b9ce55df5b7adb63a46792019e4a2331f79f3164af52681c282c1dabee541cf75acc58e98d80b5
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 an object with attributes:
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.factory(:post, {
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.factory(:published_post, :post, {
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.factory(:draft_post, :post, {
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 object:
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 object collections:
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
- posts: [
63
- { title: "Post #1" },
64
- { title: "Post #2" }
65
- ]
77
+ user: :mike
66
78
  })
67
79
 
68
- blog.posts #=> [#<Post @title="Post #1">, #<Post @title="Post #2">]
80
+ ```
69
81
 
70
- # More concise syntax
82
+ Create associated collections:
83
+
84
+ ```ruby
71
85
  blog = Traver.create(blog: {
72
86
  title: "Hello",
73
- posts: [2, title: "Post #${n}"]
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
- # Having defined factory
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
- blog.posts #=> [#<Post @title="Post #1">, #<Post @title="Post #2">]
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
- Any level of nesting:
105
+ Create associated collections using factory names:
89
106
 
90
107
  ```ruby
91
- blog = Traver.create(blog: {
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(:user, 2, email: "user${n}@mail.me")
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,7 @@
1
+ module Traver
2
+ class PoroDefaultParamsCreator
3
+ def default_params(object_class)
4
+ {}
5
+ end
6
+ end
7
+ 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
- @defined_factories = {}
4
+ undefine_all_factories
7
5
  end
8
6
 
9
- def self.instance
10
- @instance ||= FactoryDefiner.new
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
- def define_factory(factory_name, *options)
14
- parent_name = nil
15
-
16
- if options.size == 1
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 get_object_class(factory_name)
26
- if defined_factories[factory_name] && parent_name = defined_factories[factory_name][:parent]
27
- get_object_class(parent_name)
28
- else
29
- Object.const_get(camelize(factory_name.to_s))
30
- end
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 apply_factory_params(factory_name, params)
34
- factory_params = get_factory_params(factory_name)
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
- private
30
+ def undefine_all_factories
31
+ @factories = {}
32
+ end
40
33
 
41
- def get_factory_params(factory_name)
42
- if factory = defined_factories[factory_name]
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
- def camelize(str)
48
- str.split('_').map(&:capitalize).join
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[singularize(key).to_sym]
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.end_with?("s")
34
- end
35
-
36
- def singularize(value)
37
- value.chomp("s")
33
+ value == value.pluralize
38
34
  end
39
35
  end
40
36
  end
@@ -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
- @params = params
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.created_object)
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
- attr_reader :factory_name, :params
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
- def initialize(options)
8
- options = { options => {} } if options.is_a?(Symbol)
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
- @factory_name, @params = options.first
11
- @factory_definer = FactoryDefiner.instance
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
- instantiate_object
16
- set_object_state
17
- persist_object
18
- call_after_create_hook
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 :factory_definer
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
- @created_object = get_class.new
81
+ @object = factory.object_class.new
26
82
  end
27
83
 
28
- def get_class
29
- factory_definer.get_object_class(factory_name)
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 set_object_state
33
- factory_params.each do |attribute, value|
34
- if nested_params?(value)
35
- create_nested_object(attribute, value)
36
- elsif collection_params?(value)
37
- create_collection(attribute, value)
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
- def nested_params?(params)
49
- params.is_a?(Hash)
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 create_nested_object(k, v)
53
- set_attribute(k, do_create_object(k => v))
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 do_create_object(params)
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.created_object
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
- def collection_params?(params)
69
- params.is_a?(Array)
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
- def create_collection(attribute, collection_params)
73
- collection = collection_params.map do |params|
74
- do_create_object(singularize(attribute) => params)
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(attribute, collection)
152
+ set_attribute(collection_name, create_nested_collection(factory_name, params_array))
78
153
  end
79
154
 
80
- def singularize(val)
81
- val.to_s.chomp("s").to_sym
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
- created_object.save if defined?(Rails)
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,9 @@
1
+ module Traver
2
+ class ActiveRecordObjectPersister
3
+ def persist_object(object)
4
+ unless object.save
5
+ raise "Unable to save #{object.class}: #{object.errors.full_messages}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ module Traver
2
+ class PoroObjectPersister
3
+ def persist_object(object)
4
+ end
5
+ end
6
+ 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,7 @@
1
+ module Traver
2
+ class Settings
3
+ attr_reader :object_persister,
4
+ :attributes_resolver,
5
+ :default_params_creator
6
+ end
7
+ 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
@@ -1,3 +1,3 @@
1
1
  module Traver
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/traver.rb CHANGED
@@ -1,28 +1,67 @@
1
- require "traver/version"
2
- require "traver/factory_definer"
3
- require "traver/object_creator"
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
- def self.factory(factory_name, *options)
11
- factory_definer = FactoryDefiner.instance
12
- factory_definer.define_factory(factory_name, *options)
13
- end
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
- def self.create(options)
16
- object_creator = ObjectCreator.new(options)
17
- object_creator.create_object
17
+ def create_graph(*options)
18
+ load_factories
19
+
20
+ traver_constructor.create_graph(*options)
21
+ end
18
22
 
19
- object_creator.created_object
20
- end
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
- def self.create_graph(params = {})
23
- graph_creator = GraphCreator.new(params)
24
- graph_creator.create_graph
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
- graph_creator.graph
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.2.2
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-03-10 00:00:00.000000000 Z
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