clowne 1.0.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec-jruby.yml +33 -0
  3. data/.github/workflows/rspec-truffle.yml +35 -0
  4. data/.github/workflows/rspec.yml +51 -0
  5. data/.github/workflows/rubocop.yml +20 -0
  6. data/.rubocop.yml +13 -52
  7. data/CHANGELOG.md +23 -0
  8. data/Gemfile +9 -9
  9. data/README.md +10 -10
  10. data/Rakefile +3 -3
  11. data/clowne.gemspec +15 -9
  12. data/docs/.nojekyll +0 -0
  13. data/docs/.rubocop.yml +5 -2
  14. data/docs/CNAME +1 -0
  15. data/docs/README.md +131 -0
  16. data/docs/_sidebar.md +25 -0
  17. data/docs/active_record.md +2 -5
  18. data/docs/after_clone.md +53 -0
  19. data/docs/after_persist.md +9 -12
  20. data/docs/architecture.md +2 -5
  21. data/docs/assets/docsify.min.js +1 -0
  22. data/docs/assets/prism-ruby.min.js +1 -0
  23. data/docs/assets/styles.css +348 -0
  24. data/docs/assets/vue.css +1 -0
  25. data/docs/clone_mapper.md +3 -6
  26. data/docs/customization.md +1 -4
  27. data/docs/exclude_association.md +1 -4
  28. data/docs/finalize.md +6 -10
  29. data/docs/from_v02_to_v1.md +2 -10
  30. data/docs/getting_started.md +171 -0
  31. data/docs/implicit_cloner.md +1 -4
  32. data/docs/include_association.md +14 -4
  33. data/docs/index.html +29 -0
  34. data/docs/init_as.md +4 -8
  35. data/docs/inline_configuration.md +1 -4
  36. data/docs/nullify.md +1 -5
  37. data/docs/operation.md +4 -7
  38. data/docs/parameters.md +7 -10
  39. data/docs/sequel.md +1 -4
  40. data/docs/supported_adapters.md +3 -6
  41. data/docs/testing.md +18 -21
  42. data/docs/traits.md +1 -4
  43. data/gemfiles/activerecord42.gemfile +5 -5
  44. data/gemfiles/jruby.gemfile +6 -6
  45. data/gemfiles/railsmaster.gemfile +6 -6
  46. data/lib/clowne/adapters/active_record/associations/base.rb +1 -1
  47. data/lib/clowne/adapters/active_record/associations/belongs_to.rb +28 -0
  48. data/lib/clowne/adapters/active_record/associations/has_one.rb +1 -2
  49. data/lib/clowne/adapters/active_record/associations.rb +7 -5
  50. data/lib/clowne/adapters/active_record/dsl.rb +2 -2
  51. data/lib/clowne/adapters/active_record/resolvers/association.rb +1 -2
  52. data/lib/clowne/adapters/active_record.rb +3 -3
  53. data/lib/clowne/adapters/base/association.rb +1 -1
  54. data/lib/clowne/adapters/base.rb +14 -8
  55. data/lib/clowne/adapters/sequel/associations/base.rb +2 -2
  56. data/lib/clowne/adapters/sequel/associations/many_to_many.rb +4 -4
  57. data/lib/clowne/adapters/sequel/associations/one_to_many.rb +1 -1
  58. data/lib/clowne/adapters/sequel/associations/one_to_one.rb +1 -1
  59. data/lib/clowne/adapters/sequel/associations.rb +5 -5
  60. data/lib/clowne/adapters/sequel/operation.rb +6 -3
  61. data/lib/clowne/adapters/sequel/resolvers/after_persist.rb +1 -1
  62. data/lib/clowne/adapters/sequel/resolvers/association.rb +1 -2
  63. data/lib/clowne/adapters/sequel/specifications/after_persist_does_not_support.rb +1 -1
  64. data/lib/clowne/adapters/sequel.rb +7 -7
  65. data/lib/clowne/cloner.rb +11 -11
  66. data/lib/clowne/declarations/after_clone.rb +21 -0
  67. data/lib/clowne/declarations/after_persist.rb +3 -3
  68. data/lib/clowne/declarations/exclude_association.rb +1 -1
  69. data/lib/clowne/declarations/finalize.rb +3 -3
  70. data/lib/clowne/declarations/include_association.rb +1 -1
  71. data/lib/clowne/declarations/init_as.rb +3 -3
  72. data/lib/clowne/declarations/nullify.rb +2 -2
  73. data/lib/clowne/declarations/trait.rb +1 -1
  74. data/lib/clowne/declarations.rb +15 -14
  75. data/lib/clowne/ext/orm_ext.rb +1 -1
  76. data/lib/clowne/ext/record_key.rb +1 -1
  77. data/lib/clowne/ext/string_constantize.rb +1 -1
  78. data/lib/clowne/ext/yield_self_then.rb +2 -2
  79. data/lib/clowne/planner.rb +1 -1
  80. data/lib/clowne/resolvers/after_clone.rb +18 -0
  81. data/lib/clowne/resolvers/after_persist.rb +1 -1
  82. data/lib/clowne/resolvers/finalize.rb +1 -1
  83. data/lib/clowne/resolvers/init_as.rb +0 -1
  84. data/lib/clowne/rspec/clone_association.rb +3 -4
  85. data/lib/clowne/rspec/clone_associations.rb +2 -2
  86. data/lib/clowne/rspec/helpers.rb +1 -1
  87. data/lib/clowne/rspec.rb +3 -3
  88. data/lib/clowne/utils/clone_mapper.rb +1 -1
  89. data/lib/clowne/utils/operation.rb +19 -7
  90. data/lib/clowne/utils/params.rb +1 -1
  91. data/lib/clowne/version.rb +1 -1
  92. data/lib/clowne.rb +10 -11
  93. metadata +60 -38
  94. data/.travis.yml +0 -55
  95. data/docs/alternatives.md +0 -26
  96. data/docs/basic_example.md +0 -83
  97. data/docs/installation.md +0 -46
  98. data/docs/overview.md +0 -24
  99. data/docs/web/.gitignore +0 -11
  100. data/docs/web/README.md +0 -6
  101. data/docs/web/core/Footer.js +0 -88
  102. data/docs/web/i18n/en.json +0 -140
  103. data/docs/web/package.json +0 -14
  104. data/docs/web/pages/en/help.js +0 -50
  105. data/docs/web/pages/en/index.js +0 -231
  106. data/docs/web/pages/en/users.js +0 -47
  107. data/docs/web/sidebars.json +0 -37
  108. data/docs/web/siteConfig.js +0 -46
  109. data/docs/web/static/css/custom.css +0 -235
  110. data/docs/web/static/fonts/FiraCode-Medium.woff +0 -0
  111. data/docs/web/static/fonts/FiraCode-Regular.woff +0 -0
  112. data/docs/web/static/img/favicon/favicon.ico +0 -0
  113. data/docs/web/yarn.lock +0 -1741
@@ -1,7 +1,4 @@
1
- ---
2
- id: customization
3
- title: Customization
4
- ---
1
+ # Customization
5
2
 
6
3
  Clowne is built with extensibility in mind. You can create your own DSL commands and resolvers.
7
4
 
@@ -1,7 +1,4 @@
1
- ---
2
- id: exclude_association
3
- title: Exclude Association
4
- ---
1
+ # Exclude Association
5
2
 
6
3
  Clowne doesn't include any association by default and doesn't provide _magic_ `include_all` declaration (although you can [add one by yourself](customization.md)).
7
4
 
data/docs/finalize.md CHANGED
@@ -1,19 +1,15 @@
1
- ---
2
- id: finalize
3
- title: Finalization
4
- sidebar_label: Finalize
5
- ---
1
+ # Finalization
6
2
 
7
3
  To apply custom transformations to the cloned record, you can use the `finalize` declaration:
8
4
 
9
5
  ```ruby
10
6
  class UserCloner < Clowne::Cloner
11
- finalize do |_source, record, _params|
12
- record.name = 'This is copy!'
7
+ finalize do |_source, record, **_params|
8
+ record.name = "This is copy!"
13
9
  end
14
10
 
15
11
  trait :change_email do
16
- finalize do |_source, record, params|
12
+ finalize do |_source, record, **params|
17
13
  record.email = params[:email]
18
14
  end
19
15
  end
@@ -22,7 +18,7 @@ end
22
18
  cloned = UserCloner.call(user).to_record
23
19
  cloned.name
24
20
  # => 'This is copy!'
25
- cloned.email == 'clone@example.com'
21
+ cloned.email == "clone@example.com"
26
22
  # => false
27
23
 
28
24
  cloned2 = UserCloner.call(user, traits: :change_email).to_record
@@ -32,4 +28,4 @@ cloned2.email
32
28
  # => 'clone@example.com'
33
29
  ```
34
30
 
35
- Finalization blocks are called at the end of the [cloning process](execution_order.md).
31
+ Finalization blocks are called at the end of the [cloning process](getting_started?id=execution-order).
@@ -1,7 +1,4 @@
1
- ---
2
- id: from_v02_to_v10
3
- title: From v0.2.x to v1.0.0
4
- ---
1
+ # From v0.2.x to v1.0.0
5
2
 
6
3
  The breaking change of v1.0 is the return of a unified [`result object`](operation.md) for all adapters.
7
4
 
@@ -37,9 +34,8 @@ clone.persisted?
37
34
 
38
35
  ### Move post-processing cloning logic into [`after_persist`](after_persist.md) callback (if you have it)
39
36
 
40
- _Notice: `after_persist` supported only with [`active_record`](active_record.md) adapter._
37
+ *Notice: `after_persist` supported only with [`active_record`](active_record.md) adapter.*
41
38
 
42
- <span style="display:none;"># rubocop:disable all</span>
43
39
  ```ruby
44
40
  # Before
45
41
  clone = UserCloner.call(user)
@@ -56,8 +52,6 @@ end
56
52
 
57
53
  clone = UserCloner.call(user).tap(&:persist).to_record
58
54
  ```
59
- <span style="display:none;"># rubocop:enable all</span>
60
-
61
55
  ## Sequel
62
56
 
63
57
  ### Use `to_record` instead of `to_model`
@@ -78,7 +72,6 @@ clone.new?
78
72
 
79
73
  ### Use `operation#persist` instead of converting to model and calling `#save`
80
74
 
81
- <span style="display:none;"># rubocop:disable all</span>
82
75
  ```ruby
83
76
  # Before
84
77
  record_wrapper = UserCloner.call(user)
@@ -88,4 +81,3 @@ clone.save
88
81
  # After
89
82
  clone = UserCloner.call(user).tap(&:persist).to_record
90
83
  ```
91
- <span style="display:none;"># rubocop:enable all</span>
@@ -0,0 +1,171 @@
1
+ # Getting Started
2
+
3
+ ## Installation
4
+
5
+ To install Clowne with RubyGems:
6
+
7
+ ```ruby
8
+ gem install clowne
9
+ ```
10
+
11
+ Or add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem "clowne"
15
+ ```
16
+
17
+ ## Configuration
18
+
19
+ Basic cloner implementation looks like:
20
+
21
+ ```ruby
22
+ class SomeCloner < Clowne::Cloner
23
+ adapter :active_record # or adapter Clowne::Adapters::ActiveRecord
24
+ # some implementation ...
25
+ end
26
+ ```
27
+
28
+ You can configure the default adapter for cloners:
29
+
30
+ ```ruby
31
+ # put to initializer
32
+ # e.g. config/initializers/clowne.rb
33
+ Clowne.default_adapter = :active_record
34
+ ```
35
+
36
+ and skip explicit adapter declaration
37
+
38
+ ```ruby
39
+ class SomeCloner < Clowne::Cloner
40
+ # some implementation ...
41
+ end
42
+ ```
43
+ See the list of [available adapters](supported_adapters.md).
44
+
45
+ ## Basic Example
46
+
47
+ Assume that you have the following model:
48
+
49
+ ```ruby
50
+ class User < ActiveRecord::Base
51
+ # create_table :users do |t|
52
+ # t.string :login
53
+ # t.string :email
54
+ # t.timestamps null: false
55
+ # end
56
+
57
+ has_one :profile
58
+ has_many :posts
59
+ end
60
+
61
+ class Profile < ActiveRecord::Base
62
+ # create_table :profiles do |t|
63
+ # t.string :name
64
+ # end
65
+ end
66
+
67
+ class Post < ActiveRecord::Base
68
+ # create_table :posts
69
+ end
70
+ ```
71
+
72
+ Let's declare our cloners first:
73
+
74
+ ```ruby
75
+ class UserCloner < Clowne::Cloner
76
+ adapter :active_record
77
+
78
+ include_association :profile, clone_with: SpecialProfileCloner
79
+ include_association :posts
80
+
81
+ nullify :login
82
+
83
+ # params here is an arbitrary Hash passed into cloner
84
+ finalize do |_source, record, **params|
85
+ record.email = params[:email]
86
+ end
87
+ end
88
+
89
+ class SpecialProfileCloner < Clowne::Cloner
90
+ adapter :active_record
91
+
92
+ nullify :name
93
+ end
94
+ ```
95
+
96
+ Now you can use `UserCloner` to clone existing records:
97
+
98
+ ```ruby
99
+ user = User.last
100
+ # => <#User id: 1, login: 'clown', email: 'clown@circus.example.com'>
101
+
102
+ operation = UserCloner.call(user, email: "fake@example.com")
103
+ # => <#Clowne::Utils::Operation...>
104
+
105
+ operation.to_record
106
+ # => <#User id: nil, login: nil, email: 'fake@example.com'>
107
+
108
+ operation.persist!
109
+ # => true
110
+
111
+ cloned = operation.to_record
112
+ # => <#User id: 2, login: nil, email: 'fake@example.com'>
113
+
114
+ cloned.login
115
+ # => nil
116
+ cloned.email
117
+ # => "fake@example.com"
118
+
119
+ # associations:
120
+ cloned.posts.count == user.posts.count
121
+ # => true
122
+ cloned.profile.name
123
+ # => nil
124
+ ```
125
+
126
+ ## Overview
127
+
128
+ In [the basic example](#basic-example), you can see that Clowne consists of flexible DSL which is used in a class inherited of `Clowne::Cloner`.
129
+
130
+ You can combinate this DSL via [`traits`](traits.md) and make a cloning plan which exactly you want.
131
+
132
+ **We strongly recommend [`write tests`](testing.md) to cover resulting cloner logic**
133
+
134
+ Cloner class returns [`Operation`](operation.md) instance as a result of cloning. The operation provides methods to save cloned record. You can wrap this call to a transaction if it is necessary.
135
+
136
+ ### Execution Order
137
+
138
+ The order of cloning actions depends on the adapter (i.e., could be customized).
139
+
140
+ All built-in adapters have the same order and what happens when you call `Operation#persist`:
141
+ - init clone (see [`init_as`](init_as.md)) (empty by default)
142
+ - [`clone associations`](include_association.md)
143
+ - [`nullify`](nullify.md) attributes
144
+ - run [`finalize`](finalize.md) blocks. _The order of [`finalize`](finalize.md) blocks is the order they've been written._
145
+ - run [`after_clone`](after_clone.md) callbacks
146
+ - __SAVE CLONED RECORD__
147
+ - run [`after_persist`](after_persist.md) callbacks
148
+
149
+ ## Motivation & Alternatives
150
+
151
+ ### Why did we decide to build our own cloning gem instead of using the existing solutions?
152
+
153
+ First, the existing solutions turned out not to be stable and flexible enough for us.
154
+
155
+ Secondly, they are Rails-only (or, more precisely, ActiveRecord-only).
156
+
157
+ Nevertheless, thanks to [amoeba](https://github.com/amoeba-rb/amoeba) and [deep_cloneable](https://github.com/moiristo/deep_cloneable) for inspiration.
158
+
159
+ For ActiveRecord we support amoeba-like [in-model configuration](active_record.md) and you can add missing DSL declarations yourself [easily](customization.md).
160
+
161
+ We also provide an ability to specify cloning [configuration in-place](inline_configuration.md) like `deep_clonable` does.
162
+
163
+ So, we took the best of these too and brought to the outside-of-Rails world.
164
+
165
+ ### Why build a gem to clone models at all?
166
+
167
+ That's a good question. Of course, you can write plain old Ruby services do handle the cloning logic. But for complex models hierarchies, this approach has major disadvantages: high code complexity and lack of re-usability.
168
+
169
+ The things become even worse when you deal with STI models and different cloning contexts.
170
+
171
+ That's why we decided to build a specific cloning tool.
@@ -1,7 +1,4 @@
1
- ---
2
- id: implicit_cloner
3
- title: Implicit Cloner
4
- ---
1
+ # Implicit Cloner
5
2
 
6
3
  When [cloning associations](include_association.md) Clowne tries to infer an appropriate cloner class for the records (unless `clone_with` specified).
7
4
 
@@ -1,7 +1,4 @@
1
- ---
2
- id: include_association
3
- title: Include Association
4
- ---
1
+ # Include Association
5
2
 
6
3
  Use this declaration to clone model's associations:
7
4
 
@@ -23,6 +20,13 @@ The declaration supports additional arguments:
23
20
  include_association name, scope, options
24
21
  ```
25
22
 
23
+ ### Supported Associations
24
+
25
+ Adapter |1:1 |*:1 | 1:M | M:M |
26
+ ------------------------------------------|------------|------------|-------------|-------------------------|
27
+ [Active Record](active_record) | has_one | belongs_to | has_many | has_and_belongs_to|
28
+ [Sequel](sequel) | one_to_one | - | one_to_many | many_to_many |
29
+
26
30
  ## Scope
27
31
 
28
32
  Scope can be a:
@@ -121,3 +125,9 @@ end
121
125
  ```
122
126
 
123
127
  **NOTE:** in that case, it's not possible to provide custom scopes and options.
128
+
129
+ ### Belongs To association
130
+
131
+ You can include belongs_to association, but will do it carefully.
132
+ If you have loop by relations in your models, when you clone it will raise SystemStackError.
133
+ Check this [test](https://github.com/palkan/clowne/blob/master/spec/clowne/integrations/active_record_belongs_to_spec.rb) for instance.
data/docs/index.html ADDED
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Document</title>
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
+ <meta name="description" content="Description">
8
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
9
+ <link rel="stylesheet" href="assets/vue.css">
10
+ <link rel="stylesheet" href="assets/styles.css">
11
+ </head>
12
+ <body>
13
+ <div id="app"></div>
14
+ <script>
15
+ window.$docsify = {
16
+ name: 'Clowne',
17
+ repo: 'https://github.com/clowne-rb/clowne',
18
+ loadSidebar: true,
19
+ subMaxLevel: 2,
20
+ auto2top: true,
21
+ search: {
22
+ namespace: 'clowne'
23
+ }
24
+ }
25
+ </script>
26
+ <script src="assets/docsify.min.js"></script>
27
+ <script src="assets/prism-ruby.min.js"></script>
28
+ </body>
29
+ </html>
data/docs/init_as.md CHANGED
@@ -1,8 +1,4 @@
1
- ---
2
- id: init_as
3
- title: Initialize Cloning Target
4
- sidebar_label: Init As
5
- ---
1
+ # Initialize Cloning Target
6
2
 
7
3
  You can override the default Clowne method which generates a _plain_ copy of a source object.
8
4
  By default, Clowne initiates the cloned record using a `#dup` method.
@@ -27,12 +23,12 @@ class UserCloner < Clowne::Cloner
27
23
  end
28
24
  end
29
25
 
30
- jack = User.find_by(email: 'jack@evl.ms')
26
+ jack = User.find_by(email: "jack@evl.ms")
31
27
  # => <#User id: 1, ...>
32
- jack.create_profile(name: 'Jack')
28
+ jack.create_profile(name: "Jack")
33
29
  # => <#Profile id: 1, name: 'Jack', ...>
34
30
 
35
- john = User.find_by(email: 'john@evl.ms')
31
+ john = User.find_by(email: "john@evl.ms")
36
32
  # => <#User id: 2, ...>
37
33
 
38
34
  # we want to clone Jack's profile to John's user,
@@ -1,7 +1,4 @@
1
- ---
2
- id: inline_configuration
3
- title: Inline Configuration
4
- ---
1
+ # Inline Configuration
5
2
 
6
3
  You can also enhance the cloner configuration inline (i.e., add declarations dynamically):
7
4
 
data/docs/nullify.md CHANGED
@@ -1,8 +1,4 @@
1
- ---
2
- id: nullify
3
- title: Nullify Attributes
4
- sidebar_label: Nullify
5
- ---
1
+ # Nullify Attributes
6
2
 
7
3
  To set a bunch of attributes to `nil` you can use the `nullify` declaration:
8
4
 
data/docs/operation.md CHANGED
@@ -1,7 +1,4 @@
1
- ---
2
- id: operation
3
- title: Operation
4
- ---
1
+ # Operation
5
2
 
6
3
  Since version 1.0 Clowne has been returning specific result object instead of a raw cloned object. It has allowed unifying interface between adapters and has opened an opportunity to implement new features. We call this object `Operation`.
7
4
 
@@ -14,11 +11,11 @@ class UserCloner < Clowne::Cloner
14
11
  nullify :email
15
12
 
16
13
  after_persist do |_origin, cloned, **|
17
- cloned.update_attributes(email: "evl-#{cloned.id}.ms")
14
+ cloned.update(email: "evl-#{cloned.id}.ms")
18
15
  end
19
16
  end
20
17
 
21
- user = User.create(email: 'evl.ms')
18
+ user = User.create(email: "evl.ms")
22
19
  # => <#User id: 1, email: 'evl.ms', ...>
23
20
 
24
21
  operation = UserCloner.call(user)
@@ -37,7 +34,7 @@ operation.to_record
37
34
  # Call only after_persist callbacks:
38
35
  user2 = operation.to_record
39
36
  # => <#User id: 2, email: 'evl-2.ms', ...>
40
- user2.update_attributes(email: 'admin@example.com')
37
+ user2.update(email: "admin@example.com")
41
38
  # => <#User id: 2, email: 'admin@example.com' ...>
42
39
  operation.run_after_persist
43
40
  # => <#User id: 2, email: 'evl-2.ms', ...>
data/docs/parameters.md CHANGED
@@ -1,7 +1,4 @@
1
- ---
2
- id: parameters
3
- title: Parameters
4
- ---
1
+ # Parameters
5
2
 
6
3
  Clowne provides parameters for make your cloning logic more flexible. You can see their using in [`include_association`](include_association.md#scope) and [`finalize`](finalize.md) documentation pages.
7
4
 
@@ -11,12 +8,12 @@ Example:
11
8
  class UserCloner < Clowne::Cloner
12
9
  include_association :posts, ->(params) { where(state: params[:state]) }
13
10
 
14
- finalize do |_source, record, params|
11
+ finalize do |_source, record, **params|
15
12
  record.email = params[:email]
16
13
  end
17
14
  end
18
15
 
19
- operation = UserCloner.call(user, state: :draft, email: 'cloned@example.com')
16
+ operation = UserCloner.call(user, state: :draft, email: "cloned@example.com")
20
17
  cloned = operation.to_record
21
18
  cloned.email
22
19
  # => 'cloned@example.com'
@@ -30,7 +27,7 @@ As result we strongly recommend to use ruby keyword arguments instead of params
30
27
 
31
28
  ```ruby
32
29
  # Bad
33
- finalize do |_source, record, params|
30
+ finalize do |_source, record, **params|
34
31
  record.email = params[:email]
35
32
  end
36
33
 
@@ -42,7 +39,7 @@ end
42
39
 
43
40
  ## Nested Parameters
44
41
 
45
- Also we implemented control over the parameters for cloning associations (you can read more [here](https://github.com/palkan/clowne/issues/15)).
42
+ Also we implemented control over the parameters for cloning associations (you can read more [here](https://github.com/clowne-rb/clowne/issues/15)).
46
43
 
47
44
  Let's explain what the difference:
48
45
 
@@ -85,7 +82,7 @@ class UserCloner < Clowne::Cloner
85
82
  end
86
83
 
87
84
  class ProfileCloner < Clowne::Cloner
88
- finalize do |_source, record, params|
85
+ finalize do |_source, record, **params|
89
86
  record.jsonb_field = params
90
87
  end
91
88
  end
@@ -93,7 +90,7 @@ end
93
90
  # Execute:
94
91
 
95
92
  def get_profile_jsonb(user, trait)
96
- params = { profile: { name: 'John', surname: 'Cena' } }
93
+ params = {profile: {name: "John", surname: "Cena"}}
97
94
  cloned = UserCloner.call(user, traits: trait, **params).to_record
98
95
  cloned.profile.jsonb_field
99
96
  end
data/docs/sequel.md CHANGED
@@ -1,7 +1,4 @@
1
- ---
2
- id: sequel
3
- title: Sequel
4
- ---
1
+ # Sequel
5
2
 
6
3
  Under the hood, Clowne uses Sequel [`NestedAttributes` plugin](http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/NestedAttributes.html) for cloning source's associations, and you need to configure it.
7
4
 
@@ -1,13 +1,10 @@
1
- ---
2
- id: supported_adapters
3
- title: Supported Adapters
4
- ---
1
+ # Supported Adapters
5
2
 
6
3
  Clowne supports the following ORM adapters (and associations):
7
4
 
8
5
  Adapter |1:1 | 1:M | M:M |
9
6
  ---------------------------------------------------|------------|-------------|-------------------------|
10
- [:active_record](/docs/active_record.html) | has_one | has_many | has_and_belongs_to_many |
11
- [:sequel](/docs/sequel.html) | one_to_one | one_to_many | many_to_many |
7
+ [:active_record](active_record) | has_one | has_many | has_and_belongs_to_many |
8
+ [:sequel](sequel) | one_to_one | one_to_many | many_to_many |
12
9
 
13
10
  For more information see the corresponding adapter documentation.
data/docs/testing.md CHANGED
@@ -1,7 +1,4 @@
1
- ---
2
- id: testing
3
- title: Testing
4
- ---
1
+ # Testing
5
2
 
6
3
  Clowne provides specific tools to help you test your cloners.
7
4
 
@@ -52,7 +49,7 @@ class UserCloner < Clowne::Cloner
52
49
 
53
50
  trait :with_popular_posts do
54
51
  include_association :posts, (lambda do |params|
55
- where('rating > ?', params[:min_rating])
52
+ where("rating > ?", params[:min_rating])
56
53
  end)
57
54
  end
58
55
  end
@@ -62,7 +59,7 @@ class PostCloner < Clowne::Cloner
62
59
  include_association :comments
63
60
 
64
61
  trait :mark_as_copy do |_, record|
65
- record.title += ' (copy)'
62
+ record.title += " (copy)"
66
63
  end
67
64
  end
68
65
  ```
@@ -74,7 +71,7 @@ Currently, only [RSpec](http://rspec.info/) is supported.
74
71
  Add this line to your `spec_helper.rb` (or `rails_helper.rb`):
75
72
 
76
73
  ```ruby
77
- require 'clowne/rspec'
74
+ require "clowne/rspec"
78
75
  ```
79
76
 
80
77
  ## Configuration matchers
@@ -151,47 +148,47 @@ Most of the time these actions don't depend on each other, thus we can test them
151
148
  ```ruby
152
149
  # spec/cloners/user_cloner_spec.rb
153
150
  RSpec.describe UserCloner, type: :cloner do
154
- subject(:user) { create :user, name: 'Bombon' }
151
+ subject(:user) { create :user, name: "Bombon" }
155
152
 
156
- specify 'simple case' do
153
+ specify "simple case" do
157
154
  # apply only the specified part of the plan
158
155
  cloned_user = described_class.partial_apply(:nullify, user).to_record
159
156
  expect(cloned_user.email).to be_nil
160
157
  # finalize wasn't applied
161
- expect(cloned_user.name).to eq 'Bombon'
158
+ expect(cloned_user.name).to eq "Bombon"
162
159
  end
163
160
 
164
- specify 'with params' do
165
- cloned_user = described_class.partial_apply(:finalize, user, name: 'new name').to_record
161
+ specify "with params" do
162
+ cloned_user = described_class.partial_apply(:finalize, user, name: "new name").to_record
166
163
  # nullify actions were not applied!
167
164
  expect(cloned_user.email).to eq user.email
168
165
  # finalize was applied
169
- expect(cloned_user.name).to eq 'new name'
166
+ expect(cloned_user.name).to eq "new name"
170
167
  end
171
168
 
172
- specify 'with traits' do
173
- a_user = create(:user, name: 'Dindon')
169
+ specify "with traits" do
170
+ a_user = create(:user, name: "Dindon")
174
171
  cloned_user = described_class.partial_apply(
175
172
  :init_as, user, traits: :copy, target: a_user
176
173
  ).to_record
177
174
  # returned user is the same as target
178
175
  expect(cloned_user).to be_eql(a_user)
179
- expect(cloned_user.name).to eq 'Bombon'
176
+ expect(cloned_user.name).to eq "Bombon"
180
177
  end
181
178
 
182
- specify 'associations' do
183
- create(:post, user: user, rating: 1, text: 'Boom Boom')
184
- create(:post, user: user, rating: 2, text: 'Flying Dumplings')
179
+ specify "associations" do
180
+ create(:post, user: user, rating: 1, text: "Boom Boom")
181
+ create(:post, user: user, rating: 2, text: "Flying Dumplings")
185
182
 
186
183
  # you can specify which associations to include (you can use array)
187
184
  # to apply all associations write:
188
185
  # plan.apply(:association)
189
186
  cloned_user = described_class.partial_apply(
190
- 'association.posts', user, traits: :with_popular_posts, min_rating: 1
187
+ "association.posts", user, traits: :with_popular_posts, min_rating: 1
191
188
  ).to_record
192
189
 
193
190
  expect(cloned_user.posts.size).to eq 1
194
- expect(cloned_user.posts.first.text).to eq 'Flying Dumplings'
191
+ expect(cloned_user.posts.first.text).to eq "Flying Dumplings"
195
192
  end
196
193
  end
197
194
  ```
data/docs/traits.md CHANGED
@@ -1,7 +1,4 @@
1
- ---
2
- id: traits
3
- title: Traits
4
- ---
1
+ # Traits
5
2
 
6
3
  Traits allow you to group cloner declarations together and then apply them (like in [`factory_bot`](https://github.com/thoughtbot/factory_bot)):
7
4
 
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
- gem 'activerecord', '~> 4.2'
6
- gem 'sequel', '>= 5.0'
7
- gem 'sqlite3', '~> 1.3.6'
5
+ gem "activerecord", "~> 4.2"
6
+ gem "sequel", ">= 5.0"
7
+ gem "sqlite3", "~> 1.3.13"
8
8
 
9
- gemspec path: '..'
9
+ gemspec path: ".."
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
- gem 'activerecord-jdbcsqlite3-adapter', '~> 50.0'
6
- gem 'jdbc-sqlite3'
7
- gem 'activerecord', '~> 5.0.0'
8
- gem 'sequel', '>= 5.0'
5
+ gem "activerecord-jdbcsqlite3-adapter", "~> 50.0"
6
+ gem "jdbc-sqlite3"
7
+ gem "activerecord", "~> 5.0.0"
8
+ gem "sequel", ">= 5.0"
9
9
 
10
- gemspec path: '..'
10
+ gemspec path: ".."
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
- gem 'arel', github: 'rails/arel'
6
- gem 'rails', github: 'rails/rails'
7
- gem 'sequel', github: 'jeremyevans/sequel'
8
- gem 'sqlite3'
5
+ gem "arel", github: "rails/arel"
6
+ gem "rails", github: "rails/rails"
7
+ gem "sequel", github: "jeremyevans/sequel"
8
+ gem "sqlite3"
9
9
 
10
- gemspec path: '..'
10
+ gemspec path: ".."
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'clowne/adapters/base/association'
3
+ require "clowne/adapters/base/association"
4
4
 
5
5
  module Clowne
6
6
  module Adapters # :nodoc: all