rom-factory 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb5feab75eb72799779fea6582a2cd96c84f7e65
4
- data.tar.gz: 771008f99234f6bd33b07581995783118c415241
3
+ metadata.gz: b0e9af2bccde24058817960957099aa19a54cda9
4
+ data.tar.gz: f99643318992b7df49913638a47043086a992519
5
5
  SHA512:
6
- metadata.gz: 76efd0835cc269ab37364c1d164698d5707733a932cd3bb0594b6bf7be697c6f708dc553ecaa4fb6c074d1483084d23bf09896207ccb5cfa7eca6e07e4208710
7
- data.tar.gz: 66e2d00acfbcc2147299f34df216f07c8e240d7a9af4b97f6fe590483a6023c77ac9d2f591354e3303232f7cd51ecd0a0023034e798118a8a6a5aad0c6c3f129
6
+ metadata.gz: 6f8a9de64072548a7e3597000b27898d4a6041f6e999be10837ef917a56ae0bade2437bc8cd85b260e9bee006e8f7042ceb6792e65e22e602dd356bea54d6c59
7
+ data.tar.gz: a809541e1f0bb8a36b8c6b7ee7c3f41f0e36c9964bb70aebd072cfc1c78658fb8b4d31e46b912bcfbae5e5a629d57e3d9c8ba4139c6c6fc636efc0198033161e
data/.travis.yml CHANGED
@@ -1,17 +1,18 @@
1
1
  language: ruby
2
- dist: trusty
3
- sudo: required
4
- cache: bundler
5
- bundler_args: --without tools
2
+ sudo: false
3
+ services:
4
+ - postgresql
5
+ - mysql
6
+ bundler_args: --without tools benchmarks
7
+ before_script:
8
+ - psql -c 'create database rom_factory;' -U postgres
6
9
  script: "bundle exec rake spec"
7
10
  after_success:
8
- - '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
11
+ - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
9
12
  rvm:
10
- - 2.4.0
11
- - 2.3
12
- - 2.2
13
- - rbx-3
14
- - jruby-9.1.6.0
13
+ - 2.3.4
14
+ - 2.4.1
15
+ - jruby-9.1.13.0
15
16
  env:
16
17
  global:
17
18
  - COVERAGE='true'
data/.yardopts ADDED
@@ -0,0 +1,7 @@
1
+ --plugin junk
2
+ --query '@api.text != "private"'
3
+ --embed-mixins
4
+ -r README.md
5
+ --markup-provider=redcarpet
6
+ --markup=markdown
7
+ --files CHANGELOG.md
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.5.0 to-be-released
2
+
3
+ ### Added
4
+
5
+ * Updated to rom 4.0 (solnic)
6
+ * Support for `has_many` and `has_one` associations (solnic)
7
+ * Support for attributes depending on values from other attributes (solnic)
8
+ * Support for `rand` inside the generator block (flash-gordon)
9
+
10
+ ### Changed
11
+
12
+ * Depends on `rom-core` now (solnic)
13
+
14
+ [Compare v0.4.0...v0.5.0](https://github.com/rom-rb/rom-factory/compare/v0.4.0...v0.5.0)
15
+
1
16
  ## v0.4.0 2017-03-03
2
17
 
3
18
  This is a revamp of the original `rom_factory` gem which adds new features and
data/Gemfile CHANGED
@@ -7,11 +7,37 @@ gem 'simplecov', require: false, platform: :mri
7
7
  gem 'codeclimate-test-reporter', require: false, platform: :mri
8
8
 
9
9
  gem 'rspec', '~> 3.0'
10
- gem 'rom', '~> 3.0'
11
- gem 'rom-sql', '~> 1.0'
12
- gem 'sqlite3', '~> 1.3', platforms: [:mri, :rbx]
13
- gem 'jdbc-sqlite3', platforms: :jruby
10
+
11
+ group :test do
12
+ gem 'rom-sql', '~> 2.1'
13
+ gem 'inflecto'
14
+ gem 'pry-byebug', platforms: :mri
15
+ gem 'pry', platforms: %i(jruby rbx)
16
+ gem 'codeclimate-test-reporter', require: false
17
+ gem 'simplecov', require: false
18
+
19
+ if RUBY_ENGINE == 'rbx'
20
+ gem 'pg', '~> 0.18.0', platforms: :rbx
21
+ else
22
+ gem 'pg', platforms: :mri
23
+ end
24
+
25
+ gem 'mysql2', platforms: [:mri, :rbx]
26
+ gem 'jdbc-postgres', platforms: :jruby
27
+ gem 'jdbc-mysql', platforms: :jruby
28
+ gem 'sqlite3', '~> 1.3', platforms: [:mri, :rbx]
29
+ gem 'jdbc-sqlite3', platforms: :jruby
30
+ end
14
31
 
15
32
  group :tools do
16
33
  gem 'byebug', platform: :mri
34
+ gem 'redcarpet' # for yard
35
+ end
36
+
37
+ group :benchmarks do
38
+ gem 'activerecord'
39
+ gem 'benchmark-ips'
40
+ gem 'factory_girl'
41
+ gem 'fabrication'
42
+ gem 'pg', platforms: :mri
17
43
  end
data/README.md CHANGED
@@ -15,6 +15,10 @@
15
15
 
16
16
  Data generator with support for persistence backends, built on top of [rom-rb](http://rom-rb.org) and [dry-rb](http://dry-rb.org).
17
17
 
18
+ More information:
19
+
20
+ - [API docs](http://rubydoc.info/gems/rom-factory)
21
+
18
22
  ## Installation
19
23
 
20
24
  Add this line to your application's Gemfile:
@@ -31,201 +35,27 @@ Or install it yourself as:
31
35
 
32
36
  $ gem install rom-factory
33
37
 
34
- ## Configuration
35
-
36
- First, you have to define ROM container:
37
-
38
- ```ruby
39
- rom = ROM.container(:sql, 'sqlite::memory') do |conf|
40
- conf.default.create_table(:users) do
41
- primary_key :id
42
- column :last_name, String, null: false
43
- column :first_name, String, null: false
44
- column :email, String, null: false
45
- column :admin, TrueClass, null: false, default: false
46
- column :created_at, Time, null: false
47
- column :updated_at, Time, null: false
48
- end
49
- end
50
- ```
51
-
52
- > Notice that if you're using ROM in your application, then simply set up factory using your existing ROM container
53
-
54
- Once that is done, you will have to specify which container ROM::Factory will use:
55
-
56
- ```ruby
57
- Factory = ROM::Factory.configure do |config|
58
- config.rom = rom
59
- end
60
- ```
61
-
62
- This returns a new factory ready to be used.
63
-
64
- ## Simple use case
65
-
66
- After configuration is done, you can define builders using your `Factory`:
67
-
68
- ```ruby
69
- Factory.define(:user) do |f|
70
- f.first_name "Janis"
71
- f.last_name "Miezitis"
72
- f.email "janjiss@gmail.com"
73
- end
74
- ```
75
-
76
- Then you can use it to generate data:
77
-
78
- ```ruby
79
- user = Factory[:user]
80
- user.email #=> "janjiss@gmail.com"
81
- ```
82
-
83
- ### Callable properties
84
-
85
- You can easily define dynamic (callbale) properties if value needs to change every time it needs to be called.
86
- Anything that responds to `.call` can be a dynamic property.
87
-
88
- ```ruby
89
- Factory.define(:user) do |f|
90
- f.first_name "Janis"
91
- f.last_name "Miezitis"
92
- f.email "janjiss@gmail.com"
93
- f.created_at {Time.now}
94
- end
95
-
96
- user = Factory[:user]
97
- user.created_at #=> 2016-08-27 18:17:08 -0500
98
- ```
99
-
100
- ### Sequencing
101
-
102
- If you want attributes to be unique each time you generate data, you can use sequence to achieve that:
103
-
104
- ```ruby
105
- Factory.define(:user) do |f|
106
- f.first_name "Janis"
107
- f.last_name "Miezitis"
108
- f.sequence :email do |n|
109
- "janjiss#{n}@gmail.com"
110
- end
111
- end
112
-
113
- user1 = Factory[:user]
114
- user2 = Factory[:user]
115
-
116
- user1.email #=> janjiss1@gmail.com
117
- user2.email #=> janjiss2@gmail.com
118
- ```
119
-
120
- ### Timestamps
121
-
122
- There is a support for timestamps for `created_at` and `updated_at` attributes:
123
-
124
- ```ruby
125
- Factory.define(:user) do |f|
126
- f.first_name "Janis"
127
- f.last_name "Miezitis"
128
- f.email "janjiss@gmail.com"
129
- f.timestamps
130
- end
131
-
132
- user = Factory[:user]
133
- user.created_at #=> 2016-08-27 18:17:08 -0500
134
- user.updated_at #=> 2016-08-27 18:17:10 -0500
135
- ```
136
-
137
- ### Associations
138
-
139
- If you defined associations in your relations, you can use `association` builder:
140
-
141
- ``` ruby
142
- factories.define(:user) do |f|
143
- f.first_name 'Jane'
144
- f.last_name 'Doe'
145
- f.email 'jane@doe.org'
146
- f.timestamps
147
- end
148
-
149
- factories.define(:task) do |f|
150
- f.title 'A task'
151
- f.association(:user)
152
- end
153
-
154
- task = factories[:task]
155
- ```
156
-
157
- > Currently only `belongs_to` is supported
158
-
159
- ### Fake data generator
160
-
161
- There's a builtin support for [Faker](https://github.com/stympy/faker) gem with a `fake` shortcut in the DSL:
38
+ ### Performance
162
39
 
40
+ Seems like this thing is a bit faster than other popular factory gems:
163
41
 
164
- ``` ruby
165
- factories.define(:user) do |f|
166
- f.first_name { fake(:name, :first_name) }
167
- f.last_name { fake(:name, :last_name) }
168
- f.email { fake(:internet, :email) }
169
- f.timestamps
170
- end
171
42
  ```
172
-
173
- ### Extending existing builders
174
-
175
- You can create a hierarchy of builders easily, which is useful if you want to share data generation logic across
176
- multiple definitions:
177
-
178
- ``` ruby
179
- Factory.define(:user) do |f|
180
- f.first_name "Janis"
181
- f.last_name "Miezitis"
182
- f.email "janjiss@gmail.com"
183
- f.admin false
184
- f.timestamps
185
- end
186
-
187
- Factory.define(admin: :user) do |f|
188
- f.admin true
189
- end
190
-
191
- user = Factory[:admin]
192
-
193
- user.admin # true
43
+ Warming up --------------------------------------
44
+ rom-factory 1.000 i/100ms
45
+ factory_girl 1.000 i/100ms
46
+ fabrication 1.000 i/100ms
47
+ Calculating -------------------------------------
48
+ rom-factory 1.550 (± 0.0%) i/s - 8.000 in 5.166227s
49
+ factory_girl 0.982 (± 0.0%) i/s - 5.000 in 5.098193s
50
+ fabrication 1.011 (± 0.0%) i/s - 6.000 in 5.942209s
51
+
52
+ Comparison:
53
+ rom-factory: 1.5 i/s
54
+ fabrication: 1.0 i/s - 1.53x slower
55
+ factory_girl: 1.0 i/s - 1.58x slower
194
56
  ```
195
57
 
196
- ### Setting up relation backend explicitly
197
-
198
- By default, relation is configured automatically based on the builder name. For example if your builder is called `:user`, then `:users`
199
- relation name will be inferred. If you want to set up a relation explicitly, use `:relation` option:
200
-
201
- ``` ruby
202
- Factory.define(:user, relation: :people) do |f|
203
- f.first_name "Janis"
204
- f.last_name "Miezitis"
205
- f.email "janjiss@gmail.com"
206
- f.admin false
207
- f.timestamps
208
- end
209
- ```
210
-
211
- ### Generating structs without persistence
212
-
213
- You can generate struct objects without persisting them using `#structs` generator:
214
-
215
- ``` ruby
216
- Factory.define(:user) do |f|
217
- f.first_name "Janis"
218
- f.last_name "Miezitis"
219
- f.email "janjiss@gmail.com"
220
- f.admin false
221
- f.timestamps
222
- end
223
-
224
- user = Factory.structs[:user]
225
-
226
- user.id # auto-generated fake PK
227
- user.first_name # "Janis"
228
- ```
58
+ > See [benchmarks/basic.rb](https://github.com/rom-rb/rom-factory/blob/master/benchmarks/basic.rb)
229
59
 
230
60
  ## Credits
231
61
 
@@ -0,0 +1,70 @@
1
+ require 'rom-factory'
2
+ require 'rom-core'
3
+ require 'active_record'
4
+ require 'factory_girl'
5
+ require 'fabrication'
6
+ require 'benchmark/ips'
7
+
8
+ DATABASE_URL = 'postgres://localhost/rom_factory_bench'.freeze
9
+
10
+ rom = ROM.container(:sql, DATABASE_URL) do |conf|
11
+ conf.default.connection.create_table?(:users) do
12
+ primary_key :id
13
+ column :last_name, String, null: false
14
+ column :first_name, String, null: false
15
+ column :admin, TrueClass
16
+ end
17
+
18
+ conf.relation(:users) do
19
+ schema(infer: true)
20
+ end
21
+ end
22
+
23
+ factory = ROM::Factory.configure { |c| c.rom = rom }
24
+
25
+ factory.define(:user) do |f|
26
+ f.first_name "John"
27
+ f.last_name "Doe"
28
+ f.admin false
29
+ end
30
+
31
+ class User < ActiveRecord::Base
32
+ end
33
+
34
+ ActiveRecord::Base.establish_connection(DATABASE_URL)
35
+
36
+ FactoryGirl.define do
37
+ factory(:user) do
38
+ first_name "John"
39
+ last_name "Doe"
40
+ admin false
41
+ end
42
+ end
43
+
44
+ Fabricator(:user) do
45
+ first_name "John"
46
+ last_name "Doe"
47
+ admin false
48
+ end
49
+
50
+ Benchmark.ips do |x|
51
+ x.report('rom-factory persisted struct') do
52
+ 1000.times do
53
+ factory[:user]
54
+ end
55
+ end
56
+
57
+ x.report('factory_girl') do
58
+ 1000.times do
59
+ FactoryGirl.create(:user)
60
+ end
61
+ end
62
+
63
+ x.report('fabrication') do
64
+ 1000.times do
65
+ Fabricate(:user)
66
+ end
67
+ end
68
+
69
+ x.compare!
70
+ end
data/lib/rom/factory.rb CHANGED
@@ -2,9 +2,24 @@ require 'dry/core/class_builder'
2
2
  require 'rom/factory/factories'
3
3
 
4
4
  module ROM
5
+ # Main ROM::Factory API
6
+ #
7
+ # @api public
5
8
  module Factory
6
9
  DEFAULT_NAME = 'Factories'.freeze
7
10
 
11
+ # Configure a new factory
12
+ #
13
+ # @example
14
+ # MyFactory = ROM::Factory.configure do |config|
15
+ # config.rom = my_rom_container
16
+ # end
17
+ #
18
+ # @param [Symbol] name An optional factory class name
19
+ #
20
+ # @return [Class]
21
+ #
22
+ # @api public
8
23
  def self.configure(name = DEFAULT_NAME, &block)
9
24
  Dry::Core::ClassBuilder.new(name: name, parent: Factories).call do |klass|
10
25
  klass.configure(&block)
@@ -0,0 +1,64 @@
1
+ require 'tsort'
2
+
3
+ module ROM
4
+ module Factory
5
+ # @api private
6
+ class AttributeRegistry
7
+ include Enumerable
8
+ include TSort
9
+
10
+ # @api private
11
+ attr_reader :elements
12
+
13
+ # @api private
14
+ def initialize(elements = [])
15
+ @elements = elements
16
+ end
17
+
18
+ # @api private
19
+ def each(&block)
20
+ elements.each(&block)
21
+ end
22
+
23
+ # @api private
24
+ def [](name)
25
+ detect { |e| e.name.equal?(name) }
26
+ end
27
+
28
+ # @api private
29
+ def <<(element)
30
+ existing = self[element.name]
31
+ elements.delete(existing) if existing
32
+ elements << element
33
+ self
34
+ end
35
+
36
+ # @api private
37
+ def dup
38
+ self.class.new(elements.dup)
39
+ end
40
+
41
+ # @api private
42
+ def values
43
+ self.class.new(elements.select(&:value?))
44
+ end
45
+
46
+ # @api private
47
+ def associations
48
+ self.class.new(elements.select { |e| e.kind_of?(Attributes::Association::Core) })
49
+ end
50
+
51
+ private
52
+
53
+ # @api private
54
+ def tsort_each_node(&block)
55
+ each(&block)
56
+ end
57
+
58
+ # @api private
59
+ def tsort_each_child(attr, &block)
60
+ attr.dependency_names.map { |name| self[name] }.compact.each(&block)
61
+ end
62
+ end
63
+ end
64
+ end