clowne 0.1.0.pre1 → 0.1.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.
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