rom-factory 0.4.0 → 0.5.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: 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