clowne 0.1.0.pre1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +7 -0
  3. data/.gitattributes +1 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +17 -0
  6. data/.travis.yml +15 -2
  7. data/CHANGELOG.md +9 -2
  8. data/Gemfile +1 -0
  9. data/README.md +25 -381
  10. data/clowne.gemspec +1 -0
  11. data/docs/.rubocop.yml +12 -0
  12. data/docs/active_record.md +36 -0
  13. data/docs/alternatives.md +26 -0
  14. data/docs/architecture.md +141 -0
  15. data/docs/basic_example.md +66 -0
  16. data/docs/configuration.md +29 -0
  17. data/docs/customization.md +64 -0
  18. data/docs/exclude_association.md +63 -0
  19. data/docs/execution_order.md +14 -0
  20. data/docs/finalize.md +35 -0
  21. data/docs/implicit_cloner.md +36 -0
  22. data/docs/include_association.md +119 -0
  23. data/docs/init_as.md +36 -0
  24. data/docs/inline_configuration.md +38 -0
  25. data/docs/installation.md +16 -0
  26. data/docs/nullify.md +37 -0
  27. data/docs/sequel.md +56 -0
  28. data/docs/supported_adapters.md +13 -0
  29. data/docs/traits.md +28 -0
  30. data/docs/web/.gitignore +11 -0
  31. data/docs/web/core/Footer.js +92 -0
  32. data/docs/web/i18n/en.json +134 -0
  33. data/docs/web/package.json +14 -0
  34. data/docs/web/pages/en/help.js +50 -0
  35. data/docs/web/pages/en/index.js +231 -0
  36. data/docs/web/pages/en/users.js +47 -0
  37. data/docs/web/sidebars.json +30 -0
  38. data/docs/web/siteConfig.js +44 -0
  39. data/docs/web/static/css/custom.css +229 -0
  40. data/docs/web/static/fonts/FiraCode-Medium.woff +0 -0
  41. data/docs/web/static/fonts/FiraCode-Regular.woff +0 -0
  42. data/docs/web/static/fonts/StemText.woff +0 -0
  43. data/docs/web/static/fonts/StemTextBold.woff +0 -0
  44. data/docs/web/static/img/favicon/favicon.ico +0 -0
  45. data/docs/web/yarn.lock +1741 -0
  46. data/gemfiles/activerecord42.gemfile +1 -0
  47. data/gemfiles/jruby.gemfile +2 -0
  48. data/gemfiles/railsmaster.gemfile +1 -0
  49. data/lib/clowne.rb +3 -1
  50. data/lib/clowne/adapters/active_record.rb +3 -12
  51. data/lib/clowne/adapters/active_record/association.rb +1 -1
  52. data/lib/clowne/adapters/active_record/associations/base.rb +8 -48
  53. data/lib/clowne/adapters/active_record/associations/has_one.rb +8 -1
  54. data/lib/clowne/adapters/active_record/associations/noop.rb +4 -1
  55. data/lib/clowne/adapters/active_record/dsl.rb +33 -0
  56. data/lib/clowne/adapters/base.rb +13 -6
  57. data/lib/clowne/adapters/base/association.rb +69 -0
  58. data/lib/clowne/adapters/base/finalize.rb +1 -1
  59. data/lib/clowne/adapters/base/init_as.rb +21 -0
  60. data/lib/clowne/adapters/registry.rb +5 -11
  61. data/lib/clowne/adapters/sequel.rb +25 -0
  62. data/lib/clowne/adapters/sequel/association.rb +47 -0
  63. data/lib/clowne/adapters/sequel/associations.rb +26 -0
  64. data/lib/clowne/adapters/sequel/associations/base.rb +23 -0
  65. data/lib/clowne/adapters/sequel/associations/many_to_many.rb +19 -0
  66. data/lib/clowne/adapters/sequel/associations/noop.rb +16 -0
  67. data/lib/clowne/adapters/sequel/associations/one_to_many.rb +23 -0
  68. data/lib/clowne/adapters/sequel/associations/one_to_one.rb +23 -0
  69. data/lib/clowne/adapters/sequel/copier.rb +23 -0
  70. data/lib/clowne/adapters/sequel/record_wrapper.rb +59 -0
  71. data/lib/clowne/cloner.rb +6 -4
  72. data/lib/clowne/declarations.rb +1 -0
  73. data/lib/clowne/declarations/exclude_association.rb +0 -5
  74. data/lib/clowne/declarations/include_association.rb +0 -2
  75. data/lib/clowne/declarations/init_as.rb +20 -0
  76. data/lib/clowne/declarations/trait.rb +2 -0
  77. data/lib/clowne/ext/orm_ext.rb +21 -0
  78. data/lib/clowne/ext/string_constantize.rb +2 -2
  79. data/lib/clowne/planner.rb +11 -4
  80. data/lib/clowne/version.rb +1 -1
  81. metadata +70 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b833f076ba69c9b626d4038e977e4a40d8de8dbb
4
- data.tar.gz: 271303497d931c2773c8c4f948baacfa9819cd4a
3
+ metadata.gz: cb07a988be474d61f3bbf9360cfc4ab25de047be
4
+ data.tar.gz: 1a4763ae4bd1537ab0a254d4a0ebcb5ddd56930d
5
5
  SHA512:
6
- metadata.gz: f4df02c8872ecdc0b1f70fd74a12549065aaf85cd6922b2648043905f3eba9d4bf415716a11b5f0a8f458d7c59d11edbe590e2e1c92f3328887ab9da38c7de1b
7
- data.tar.gz: '0683a5756b9797ac8c2a9cd60a4adbd29c214b9dbd55ef3fd736e2e05b414a7b0d92493edcde7e9a109434ceb67ca557cc55953ec08f1caad2a2c35e13ac1439'
6
+ metadata.gz: 1ff3270acfabe0aebebfd272b3cb6eb27c9c7faea337fb59489898e008095d71dbfb835062e6c99c3b0fbc4b63e909073dd7e9e46231a6c3a0ecf5762f7204ef
7
+ data.tar.gz: 53e267bcb71f9283a64bb95df753e26b38058d5283c0b0b01276209fe6a27a07b3906cfbae881734875fca9a987e25fcbda6b3143f44956ef361102296821860
@@ -0,0 +1,7 @@
1
+ version: "2"
2
+ checks:
3
+ method-complexity:
4
+ enabled: false
5
+ exclude_patterns:
6
+ - "docs/"
7
+ - "spec/"
@@ -0,0 +1 @@
1
+ docs/**/* linguist-vendored
data/.gitignore CHANGED
@@ -13,3 +13,4 @@ rubocop.html
13
13
  *.gem
14
14
  gemfiles/*.lock
15
15
  Gemfile.local
16
+ /docs/web/build/
@@ -1,19 +1,29 @@
1
+ require:
2
+ - 'rubocop-md'
1
3
  AllCops:
2
4
  Exclude:
3
5
  - 'bin/**/*'
4
6
  - 'tmp/**/*'
7
+ - 'docs/web/**/*'
5
8
  - 'vendor/**/*'
6
9
  - 'gemfiles/vendor/**/*'
7
10
  DisplayCopNames: true
8
11
  StyleGuideCopsOnly: false
9
12
  TargetRubyVersion: 2.3
10
13
 
14
+ Markdown:
15
+ WarnInvalid: true
16
+
11
17
  Rails:
12
18
  Enabled: false
13
19
 
14
20
  Naming/AccessorMethodName:
15
21
  Enabled: false
16
22
 
23
+ Naming/ClassAndModuleCamelCase:
24
+ Exclude:
25
+ - 'spec/**/*.rb'
26
+
17
27
  Style/TrivialAccessors:
18
28
  Enabled: false
19
29
 
@@ -23,6 +33,7 @@ Metrics/LineLength:
23
33
  Style/Documentation:
24
34
  Exclude:
25
35
  - 'spec/**/*.rb'
36
+ - 'README.md'
26
37
 
27
38
  Style/SymbolArray:
28
39
  Enabled: false
@@ -33,6 +44,8 @@ Style/FrozenStringLiteralComment:
33
44
  - 'Gemfile'
34
45
  - 'Rakefile'
35
46
  - '*.gemspec'
47
+ - 'CHANGELOG.md'
48
+ - 'README.md'
36
49
 
37
50
  Metrics/BlockLength:
38
51
  Exclude:
@@ -43,3 +56,7 @@ Bundler/OrderedGems:
43
56
 
44
57
  Gemspec/OrderedDependencies:
45
58
  Enabled: false
59
+
60
+ Lint/Void:
61
+ Exclude:
62
+ - 'README.md'
@@ -4,6 +4,9 @@ language: ruby
4
4
  notifications:
5
5
  email: false
6
6
 
7
+ before_install:
8
+ gem update --system
9
+
7
10
  before_script:
8
11
  # Only generate coverage report for the specified job
9
12
  - if [ "$CC_REPORT" == "true" ]; then curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter; fi
@@ -11,8 +14,8 @@ before_script:
11
14
  - if [ "$CC_REPORT" == "true" ]; then ./cc-test-reporter before-build; fi
12
15
  script:
13
16
  - bundle exec rake
14
- after_script:
15
17
  - if [ "$CC_REPORT" == "true" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
18
+ - if [ "$DEPLOY_ME" == "true" ]; then (cd ./docs/web && yarn && yarn run build); fi
16
19
 
17
20
  matrix:
18
21
  fast_finish: true
@@ -25,7 +28,9 @@ matrix:
25
28
  gemfile: Gemfile
26
29
  - rvm: 2.4.3
27
30
  gemfile: Gemfile
28
- env: CC_REPORT=true
31
+ env:
32
+ - CC_REPORT=true
33
+ - DEPLOY_ME=true
29
34
  - rvm: 2.4.1
30
35
  gemfile: gemfiles/activerecord42.gemfile
31
36
  - rvm: 2.3.1
@@ -37,3 +42,11 @@ matrix:
37
42
  gemfile: gemfiles/railsmaster.gemfile
38
43
  - rvm: jruby-9.1.0.0
39
44
  gemfile: gemfiles/jruby.gemfile
45
+ deploy:
46
+ provider: pages
47
+ skip_cleanup: true
48
+ github_token: $GITHUB_TOKEN
49
+ local_dir: "./docs/web/build/clowne"
50
+ on:
51
+ branch: master
52
+ condition: $DEPLOY_ME = true
@@ -1,9 +1,16 @@
1
1
  # Change log
2
2
 
3
- ## master branch
3
+ ## 0.1.0 (2018-02-01)
4
+
5
+ - Add `init_as` declaration. ([@palkan][])
6
+
7
+ - Support [Sequel](https://github.com/jeremyevans/sequel). ([@ssnickolay][])
8
+
9
+ - Support passing a block to `#clowne` for inline configuration. ([@palkan][])
10
+
11
+ ## 0.1.0.beta1 (2018-01-08)
4
12
 
5
13
  - Initial version. ([@ssnickolay][], [@palkan][])
6
14
 
7
15
  [@palkan]: https://github.com/palkan
8
16
  [@ssnickolay]: https://github.com/ssnickolay
9
-
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gemspec
6
6
  gem 'pry-byebug'
7
7
  gem 'sqlite3'
8
8
  gem 'activerecord', '>= 5.0'
9
+ gem 'sequel', '>= 5.0'
9
10
  gem 'simplecov'
10
11
 
11
12
  local_gemfile = 'Gemfile.local'
data/README.md CHANGED
@@ -1,26 +1,17 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/clowne.svg)](https://badge.fury.io/rb/clowne)
2
2
  [![Build Status](https://travis-ci.org/palkan/clowne.svg?branch=master)](https://travis-ci.org/palkan/clowne)
3
- [![Code Climate](https://codeclimate.com/github/palkan/clowne.svg)](https://codeclimate.com/github/palkan/clowne)
4
3
  [![Test Coverage](https://codeclimate.com/github/palkan/clowne/badges/coverage.svg)](https://codeclimate.com/github/palkan/clowne/coverage)
4
+ [![Docs](https://img.shields.io/readthedocs/pip.svg)](https://palkan.github.io/clowne)
5
5
 
6
6
  # Clowne
7
7
 
8
- **NOTICE**: gem is currently under heavy development, we plan to release the first version 'till the end of the year.
8
+ **NOTE**: this is the documentation for pre-release version **0.1.0.beta1**.
9
9
 
10
- A flexible gem for cloning your models. Clowne focuses on ease of use and provides the ability to connect various ORM adapters (currently only ActiveRecord is supported).
10
+ A flexible gem for cloning your models. Clowne focuses on ease of use and provides the ability to connect various ORM adapters.
11
11
 
12
12
  <a href="https://evilmartians.com/">
13
13
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
14
14
 
15
- ### Alternatives
16
-
17
- Why did we decide to build our own cloning gem?
18
-
19
- First, existing solutions turned out not stable and flexible enough for us.
20
-
21
- Secondly, they are Rails-only. And we are not.
22
-
23
- Nevertheless, thanks to [amoeba](https://github.com/amoeba-rb/amoeba) and [deep_cloneable](https://github.com/moiristo/deep_cloneable) for inspiration.
24
15
 
25
16
  ## Installation
26
17
 
@@ -38,9 +29,7 @@ gem 'clowne'
38
29
 
39
30
  ## Quick Start
40
31
 
41
- This is a basic example that demonstrates how to clone your ActiveRecord model. For detailed documentation see [Features](#features).
42
-
43
- At first, define your cloneable model
32
+ Assume that you have the following model:
44
33
 
45
34
  ```ruby
46
35
  class User < ActiveRecord::Base
@@ -55,7 +44,7 @@ class User < ActiveRecord::Base
55
44
  end
56
45
  ```
57
46
 
58
- The next step is to declare cloner
47
+ Let's declare our cloners first:
59
48
 
60
49
  ```ruby
61
50
  class UserCloner < Clowne::Cloner
@@ -65,8 +54,8 @@ class UserCloner < Clowne::Cloner
65
54
  include_association :posts
66
55
 
67
56
  nullify :login
68
-
69
- # params here is an arbitrary hash passed into cloner
57
+
58
+ # params here is an arbitrary Hash passed into cloner
70
59
  finalize do |_source, record, params|
71
60
  record.email = params[:email]
72
61
  end
@@ -79,382 +68,37 @@ class SpecialProfileCloner < Clowne::Cloner
79
68
  end
80
69
  ```
81
70
 
82
- and call it
71
+ Now you can use `UserCloner` to clone existing records:
83
72
 
84
73
  ```ruby
85
- clone = UserCloner.call(User.last, { email: "fake@example.com" })
86
- clone.persisted?
74
+ user = User.last
75
+ #=> <#User(login: 'clown', email: 'clown@circus.example.com')>
76
+
77
+ cloned = UserCloner.call(user, email: 'fake@example.com')
78
+ cloned.persisted?
87
79
  # => false
88
- clone.save!
89
- clone.login
80
+
81
+ cloned.save!
82
+ cloned.login
90
83
  # => nil
91
- clone.email
84
+ cloned.email
92
85
  # => "fake@example.com"
93
86
 
94
87
  # associations:
95
- clone.posts.count == User.last.posts.count
88
+ cloned.posts.count == user.posts.count
96
89
  # => true
97
- clone.profile.name
90
+ cloned.profile.name
98
91
  # => nil
99
92
  ```
100
93
 
101
- ## <a name="features">Features
102
-
103
- - [Configuration](#configuration)
104
- - [Include one association](#include_association)
105
- - - [Scope](#include_association_scope)
106
- - - [Options](#include_association_options)
107
- - [Exclude association](#exclude_association)
108
- - [Nullify attribute(s)](#nullify)
109
- - [Execute finalize block](#finalize)
110
- - [Traits](#traits)
111
- - [Execution order](#execution_order)
112
- - [Customization](#customization)
94
+ Take a look at our [documentation](https://palkan.github.io/clowne) for more information!
113
95
 
114
- ### <a name="configuration"></a>Configuration
96
+ ### Supported ORM adapters
115
97
 
116
- You can configure the default adapter for cloners:
117
-
118
- ```ruby
119
- # somewhere in initializers
120
- Clowne.default_adapter = :active_record
121
- ```
122
-
123
- ### <a name="include_association"></a>Include one association
124
-
125
- Powerful declaration for including model's association.
126
-
127
- ```ruby
128
- class User < ActiveRecord::Base
129
- has_one :profile
130
- end
131
-
132
- class UserCloner < Clowne::Cloner
133
- adapter Clowne::ActiveRecord::Adapter
134
-
135
- include_association :profile
136
- end
137
- ```
138
-
139
- But it's not all! :) The DSL looks like
140
-
141
- ```ruby
142
- include_association name, scope, options
143
- ```
144
-
145
- #### <a name="include_association_scope"></a>Include one association: Scope
146
- Scope can be a:
147
-
148
- `Symbol` - named scope.
149
-
150
- `Proc` - custom scope (supports parameter passing).
151
-
152
- Example:
153
-
154
- ```ruby
155
- class User < ActiveRecord::Base
156
- has_many :accounts
157
- has_many :posts
158
- end
159
-
160
- class Account < ActiveRecord::Base
161
- scope :active, -> where(active: true)
162
- end
163
-
164
- class Post < ActiveRecord::Base
165
- # t.string :status
166
- end
167
-
168
- class UserCloner < Clowne::Cloner
169
- adapter Clowne::ActiveRecord::Adapter
170
-
171
- include_association :accounts, :active
172
- include_association :posts, ->(params) { where(state: params[:post_status] }
173
- end
174
-
175
- # posts will be cloned only with draft status
176
- UserCloner.call(user, { post_status: :draft })
177
- # => <#User...
178
- ```
179
-
180
- #### <a name="include_association_options"></a>Include one association: Options
181
-
182
- Options keys can be a:
183
-
184
- `:clone_with` - use custom cloner for all children.
185
-
186
- `:traits` - define special traits.
187
-
188
- Example:
189
-
190
- ```ruby
191
- class User < ActiveRecord::Base
192
- has_many :posts
193
- end
194
-
195
- class Post < ActiveRecord::Base
196
- # t.string :title
197
- has_many :tags
198
- end
199
- ```
200
-
201
- ```ruby
202
- class PostSpecialCloner < Clowne::Cloner
203
- adapter :active_record
204
-
205
- nullify :title
206
-
207
- trait :with_tags do
208
- include_association :tags
209
- end
210
- end
211
-
212
- class UserCloner < Clowne::Cloner
213
- adapter :active_record
214
-
215
- include_association :posts, clone_with: PostSpecialCloner
216
- # or clone user's posts with tags!
217
- # include_association :posts, clone_with: PostSpecialCloner, traits: :with_tags
218
- end
219
-
220
- UserCloner.call(user)
221
- # => <#User...
222
- ```
223
-
224
- **Notice: if custom cloner is not defined, clowne tries to find default cloner and use it. (PostCloner for previous example)**
225
-
226
- ### <a name="exclude_association"></a>Exclude association
227
-
228
- Exclude association from copying
229
-
230
- ```ruby
231
- class UserCloner < Clowne::Cloner
232
- adapter Clowne::ActiveRecord::Adapter
233
-
234
- include_association :posts
235
-
236
- trait :without_posts do
237
- exclude_association :posts
238
- end
239
- end
240
-
241
- # copy user and posts
242
- clone = UserCloner.call(user)
243
- clone.posts.count == user.posts.count
244
- # => true
245
-
246
- # copy only user
247
- clone2 = UserCloner.call(user, traits: :without_posts)
248
- clone2.posts
249
- # => []
250
- ```
251
-
252
- **NOTE**: once excluded association cannot be re-included, e.g. the following cloner:
253
-
254
- ```ruby
255
- class UserCloner < Clowne::Cloner
256
- exclude_association :comments
257
-
258
- trait :with_comments do
259
- # That wouldn't work
260
- include_association :comments
261
- end
262
- end
263
-
264
- clone = UserCloner.call(user, traits: :with_comments)
265
- clone.comments.empty? #=> true
266
- ```
267
-
268
- Why so? That allows to have deterministic cloning plans when combining multiple traits
269
- (or inheriting cloners).
270
-
271
- ### <a name="nullify"></a>Nullify attribute(s)
272
-
273
- Nullify attributes:
274
-
275
- ```ruby
276
- class User < ActiveRecord::Base
277
- # t.string :name
278
- # t.string :surename
279
- # t.string :email
280
- end
281
-
282
- class UserCloner < Clowne::Cloner
283
- adapter Clowne::ActiveRecord::Adapter
284
-
285
- nullify :name, :email
286
-
287
- trait :nullify_surename do
288
- nullify :surename
289
- end
290
- end
291
-
292
- # nullify only name
293
- clone = UserCloner.call(user)
294
- clone.name.nil?
295
- # => true
296
- clone.email.nil?
297
- # => true
298
- clone.surename.nil?
299
- # => false
300
-
301
- # nullify name and surename
302
- clone2 = UserCloner.call(user, traits: :nullify_surename)
303
- clone.name.nil?
304
- # => true
305
- clone.surename.nil?
306
- # => true
307
- ```
308
-
309
- ### <a name="finalize"></a>Execute finalize block
310
-
311
- Simple callback for changing record manually.
312
-
313
- ```ruby
314
- class UserCloner < Clowne::Cloner
315
- adapter Clowne::ActiveRecord::Adapter
316
-
317
- finalize do |source, record, params|
318
- record.name = 'This is copy!'
319
- end
320
-
321
- trait :change_email do
322
- finalize do |source, record, params|
323
- record.email = params[:email]
324
- end
325
- end
326
- end
327
-
328
- # execute first finalize
329
- clone = UserCloner.call(user)
330
- clone.name
331
- # => 'This is copy!'
332
- clone.email == 'clone@example.com'
333
- # => false
334
-
335
- # execute both finalizes
336
- clone2 = UserCloner.call(user, traits: :change_email)
337
- clone.name
338
- # => 'This is copy!'
339
- clone.email
340
- # => 'clone@example.com'
341
- ```
342
-
343
- ### <a name="traits"></a>Traits
344
-
345
- Traits allow you to group cloner declarations together and then apply them (like in factory_bot).
346
-
347
- ```ruby
348
- class UserCloner < Clowne::Cloner
349
- adapter Clowne::ActiveRecord::Adapter
350
-
351
- trait :with_posts do
352
- include_association :posts
353
- end
354
-
355
- trait :with_profile do
356
- include_association :profile
357
- end
358
-
359
- trait :nullify_name do
360
- nullify :name
361
- end
362
- end
363
-
364
- # execute first finalize
365
- UserCloner.call(user, traits: [:with_posts, :with_profile, :nullify_name])
366
- # or
367
- UserCloner.call(user, traits: :nullify_name)
368
- # or
369
- # ...
370
- ```
371
-
372
- ### <a name="execution_order"></a>Execution order
373
-
374
- The order of cloning actions depends on the adapter.
375
-
376
- For ActiveRecord:
377
- - clone associations
378
- - nullify attributes
379
- - run `finalize` blocks
380
- The order of `finalize` blocks is the order they've been written.
381
-
382
- ### <a name="customization"></a>Customization
383
-
384
- Clowne is built with extensibility in mind. You can create your own DSL commands and resolvers.
385
-
386
- Let's consider an example.
387
-
388
- Suppose that you want to add `include_all` declaration to automagically include all associations (for ActiveRecord).
389
-
390
- First, you should add a custom declaration:
391
-
392
- ```ruby
393
- class IncludeAll # :nodoc: all
394
- def compile(plan)
395
- # Just add all_associations object to plan
396
- plan.set(:all_associations, self)
397
- # Plan supports 3 types of registers:
398
- #
399
- # 1) Scalar
400
- #
401
- # plan.set(key, value)
402
- # plan.remove(key)
403
- #
404
- # 2) Append-only lists
405
- #
406
- # plan.add(key, value)
407
- #
408
- # 3) Two-phase set (2P-Set) (see below)
409
- #
410
- # plan.add_to(type, key, value)
411
- # plan.remove_from(type, key)
412
- end
413
- end
414
-
415
- # Register our declrations, i.e. extend DSL
416
- Clowne::Declarations.add :include_all, Clowne::Declarations::IncludeAll
417
- ```
418
-
419
- \* Operations over [2P-Set](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type#2P-Set_(Two-Phase_Set)) (adding/removing) do not depend on the order of execution; we use "remove-wins" semantics, i.e. when a key has been removed, it cannot be re-added.
420
-
421
- Secondly, register a resolver:
422
-
423
- ```ruby
424
- class AllAssociations
425
- # This method is called when all_associations command is applied.
426
- #
427
- # source – source record
428
- # record – target record (our clone)
429
- # declaration – declaration object
430
- # params – custom params passed to cloner
431
- def call(source, record, declaration, params:)
432
- source.class.reflections.each do |name, reflection|
433
- # Exclude belongs_to associations
434
- next if reflection.macro == :belongs_to
435
- # Resolve and apply association cloner
436
- cloner_class = Clowne::Adapters::ActiveRecord::Associations.cloner_for(reflection)
437
- cloner_class.new(reflection, source, declaration, params).call(record)
438
- end
439
- record
440
- end
441
- end
442
-
443
- # Finally, register the resolver
444
- Clowne::Adapters::ActiveRecord.register_resolver(
445
- :all_associations, AllAssociations
446
- )
447
- ```
448
-
449
- Now you can use it likes this:
450
-
451
- ```ruby
452
- class UserCloner < Clowne::Cloner
453
- adapter :active_record
454
-
455
- include_all
456
- end
457
- ```
98
+ Adapter |1:1 | 1:M | M:M |
99
+ ------------------------------------------|------------|-------------|-------------------------|
100
+ [Active Record](https://palkan.github.io/clowne/docs/active_record.html) | has_one | has_many | has_and_belongs_to_many |
101
+ [Sequel](https://palkan.github.io/clowne/docs/sequel.html) | one_to_one | one_to_many | many_to_many |
458
102
 
459
103
  ## Maintainers
460
104