clowne 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +4 -4
- data/docs/after_clone.md +56 -0
- data/docs/include_association.md +13 -0
- data/docs/overview.md +1 -0
- data/docs/web/i18n/en.json +1 -0
- data/docs/web/sidebars.json +1 -0
- data/lib/clowne/adapters/active_record/associations.rb +2 -0
- data/lib/clowne/adapters/active_record/associations/belongs_to.rb +29 -0
- data/lib/clowne/adapters/base.rb +7 -1
- data/lib/clowne/adapters/sequel/operation.rb +3 -1
- data/lib/clowne/declarations.rb +1 -0
- data/lib/clowne/declarations/after_clone.rb +21 -0
- data/lib/clowne/resolvers/after_clone.rb +17 -0
- data/lib/clowne/utils/operation.rb +16 -4
- data/lib/clowne/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50a2126fd3d4f4581bb9d06a1d53489dab431e2285683cba815df66a683d154a
|
4
|
+
data.tar.gz: 973bebd26c7e8e33807d6a4a3438d5f72aefb540bbbf4ce4d5aecfcf58761893
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db3a1a9e38b180a2a5ad6cd490fe9852f074de4484df91ff62525fb88497a2785ef9307745a264bcb082a42ff9f1be95848534a949a78c96e591141c24fefea1
|
7
|
+
data.tar.gz: 565def47871791088a954d8ffd7ea374de91d37844fcc3bed97f35c6e299d65bd14f3c817906815b79544a7080a456058ed46dbf375d5d200ba7956b79149ac3
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## 1.1.0 (2019-03-20)
|
4
|
+
|
5
|
+
|
6
|
+
- Add `after_clone` declaration. ([@elardo][])
|
7
|
+
- Add opporotunity to include belongs_to association for active_record adapter. ([@madding][])
|
8
|
+
|
3
9
|
## 1.0.0 (2019-02-26)
|
4
10
|
|
5
11
|
- Return `Operation` instance as a rusult of cloning. ([@ssnickolay][])
|
@@ -36,3 +42,5 @@ See [migration guide](https://clowne.evilmartians.io/docs/from_v02_to_v10.html)
|
|
36
42
|
|
37
43
|
[@palkan]: https://github.com/palkan
|
38
44
|
[@ssnickolay]: https://github.com/ssnickolay
|
45
|
+
[@elardo]: https://github.com/elardo
|
46
|
+
[@madding]: https://github.com/madding
|
data/README.md
CHANGED
@@ -114,10 +114,10 @@ Take a look at our [documentation](https://clowne.evilmartians.io) for more info
|
|
114
114
|
|
115
115
|
### Supported ORM adapters
|
116
116
|
|
117
|
-
Adapter |1:1 | 1:M | M:M |
|
118
|
-
|
119
|
-
[Active Record](https://clowne.evilmartians.io/clowne/docs/active_record.html) | has_one | has_many | has_and_belongs_to|
|
120
|
-
[Sequel](https://clowne.evilmartians.io/clowne/docs/sequel.html) | one_to_one | one_to_many | many_to_many |
|
117
|
+
Adapter |1:1 |*:1 | 1:M | M:M |
|
118
|
+
------------------------------------------|------------|------------|-------------|-------------------------|
|
119
|
+
[Active Record](https://clowne.evilmartians.io/clowne/docs/active_record.html) | has_one | belongs_to | has_many | has_and_belongs_to|
|
120
|
+
[Sequel](https://clowne.evilmartians.io/clowne/docs/sequel.html) | one_to_one | - | one_to_many | many_to_many |
|
121
121
|
|
122
122
|
## Maintainers
|
123
123
|
|
data/docs/after_clone.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
---
|
2
|
+
id: after_clone
|
3
|
+
title: After Clone
|
4
|
+
---
|
5
|
+
|
6
|
+
The `after_clone` callbacks can help you to make additional operations on cloned record, like checking it with some business logic or actualizing cloned record attributes, before it will be saved to the database. Also it can help to avoid unneeded usage of [`after_persist`](after_persist.md) callbacks, and additional queries to database.
|
7
|
+
|
8
|
+
Examples:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
class User < ActiveRecord::Base
|
12
|
+
# create_table :users do |t|
|
13
|
+
# t.string :login
|
14
|
+
# t.integer :draft_count
|
15
|
+
# end
|
16
|
+
|
17
|
+
has_many :posts # all user's posts
|
18
|
+
end
|
19
|
+
|
20
|
+
class Post < ActiveRecord::Base
|
21
|
+
# create_table :posts do |t|
|
22
|
+
# t.integer :user_id
|
23
|
+
# t.boolean :is_draft
|
24
|
+
# end
|
25
|
+
|
26
|
+
scope :draft, -> { where is_draft: true }
|
27
|
+
end
|
28
|
+
|
29
|
+
class UserCloner < Clowne::Cloner
|
30
|
+
# clone user and his posts, which is drafts
|
31
|
+
include_association :posts, scope: :draft
|
32
|
+
|
33
|
+
after_clone do |_origin, clone, **|
|
34
|
+
# actualize user attribute
|
35
|
+
clone.draft_count = clone.posts.count
|
36
|
+
end
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
`after_clone` runs when you call `Operation#to_record` or [`Operation#persist`]('operation.md) (or `Operation#persist!`)
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# prepare data
|
44
|
+
user = User.create
|
45
|
+
3.times { Post.create(user: user, is_draft: false) }
|
46
|
+
2.times { Post.create(user: user, is_draft: true) }
|
47
|
+
|
48
|
+
operation = UserCloner.call(user)
|
49
|
+
# => <#Clowne::Utils::Operation ...>
|
50
|
+
|
51
|
+
clone = operation.to_record
|
52
|
+
# => <#User id: nil, draft_count: 2 ...>
|
53
|
+
|
54
|
+
clone.draft_count == user.posts.draft.count
|
55
|
+
# => true
|
56
|
+
```
|
data/docs/include_association.md
CHANGED
@@ -23,6 +23,13 @@ The declaration supports additional arguments:
|
|
23
23
|
include_association name, scope, options
|
24
24
|
```
|
25
25
|
|
26
|
+
### Supported Associations
|
27
|
+
|
28
|
+
Adapter |1:1 |*:1 | 1:M | M:M |
|
29
|
+
------------------------------------------|------------|------------|-------------|-------------------------|
|
30
|
+
[Active Record](https://clowne.evilmartians.io/clowne/docs/active_record.html) | has_one | belongs_to | has_many | has_and_belongs_to|
|
31
|
+
[Sequel](https://clowne.evilmartians.io/clowne/docs/sequel.html) | one_to_one | - | one_to_many | many_to_many |
|
32
|
+
|
26
33
|
## Scope
|
27
34
|
|
28
35
|
Scope can be a:
|
@@ -121,3 +128,9 @@ end
|
|
121
128
|
```
|
122
129
|
|
123
130
|
**NOTE:** in that case, it's not possible to provide custom scopes and options.
|
131
|
+
|
132
|
+
### Belongs To association
|
133
|
+
|
134
|
+
You can include belongs_to association, but will do it carefully.
|
135
|
+
If you have loop by relations in your models, when you clone it will raise SystemStackError.
|
136
|
+
Check this [test](https://github.com/palkan/clowne/blob/master/spec/clowne/integrations/active_record_belongs_to_spec.rb) for instance.
|
data/docs/overview.md
CHANGED
@@ -20,5 +20,6 @@ All built-in adapters have the same order and what happens when you call `Operat
|
|
20
20
|
- [`clone associations`](include_association.md)
|
21
21
|
- [`nullify`](nullify.md) attributes
|
22
22
|
- run [`finalize`](finalize.md) blocks. _The order of [`finalize`](finalize.md) blocks is the order they've been written._
|
23
|
+
- run [`after_clone`](after_clone.md) callbacks
|
23
24
|
- __SAVE CLONED RECORD__
|
24
25
|
- run [`after_persist`](after_persist.md) callbacks
|
data/docs/web/i18n/en.json
CHANGED
data/docs/web/sidebars.json
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'clowne/adapters/active_record/associations/base'
|
4
4
|
require 'clowne/adapters/active_record/associations/noop'
|
5
|
+
require 'clowne/adapters/active_record/associations/belongs_to'
|
5
6
|
require 'clowne/adapters/active_record/associations/has_one'
|
6
7
|
require 'clowne/adapters/active_record/associations/has_many'
|
7
8
|
require 'clowne/adapters/active_record/associations/has_and_belongs_to_many'
|
@@ -11,6 +12,7 @@ module Clowne
|
|
11
12
|
class ActiveRecord
|
12
13
|
module Associations
|
13
14
|
AR_2_CLONER = {
|
15
|
+
belongs_to: BelongsTo,
|
14
16
|
has_one: HasOne,
|
15
17
|
has_many: HasMany,
|
16
18
|
has_and_belongs_to_many: HABTM
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clowne
|
4
|
+
module Adapters # :nodoc: all
|
5
|
+
class ActiveRecord
|
6
|
+
module Associations
|
7
|
+
class BelongsTo < Base
|
8
|
+
# rubocop: disable Metrics/MethodLength
|
9
|
+
def call(record)
|
10
|
+
child = association
|
11
|
+
return record unless child
|
12
|
+
|
13
|
+
unless declaration.scope.nil?
|
14
|
+
warn(
|
15
|
+
'[Clowne] Belongs to association does not support scopes ' \
|
16
|
+
"(#{@association_name} for #{@source.class})"
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
child_clone = clone_one(child)
|
21
|
+
record.__send__(:"#{association_name}=", child_clone)
|
22
|
+
record
|
23
|
+
end
|
24
|
+
# rubocop: enable Metrics/MethodLength
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/clowne/adapters/base.rb
CHANGED
@@ -6,6 +6,7 @@ require 'clowne/resolvers/init_as'
|
|
6
6
|
require 'clowne/resolvers/nullify'
|
7
7
|
require 'clowne/resolvers/finalize'
|
8
8
|
require 'clowne/resolvers/after_persist'
|
9
|
+
require 'clowne/resolvers/after_clone'
|
9
10
|
|
10
11
|
module Clowne
|
11
12
|
module Adapters
|
@@ -70,6 +71,11 @@ Clowne::Adapters::Base.register_resolver(
|
|
70
71
|
)
|
71
72
|
|
72
73
|
Clowne::Adapters::Base.register_resolver(
|
73
|
-
:
|
74
|
+
:after_clone, Clowne::Resolvers::AfterClone,
|
74
75
|
after: :finalize
|
75
76
|
)
|
77
|
+
|
78
|
+
Clowne::Adapters::Base.register_resolver(
|
79
|
+
:after_persist, Clowne::Resolvers::AfterPersist,
|
80
|
+
after: :after_clone
|
81
|
+
)
|
data/lib/clowne/declarations.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clowne
|
4
|
+
module Declarations
|
5
|
+
class AfterClone < Base # :nodoc: all
|
6
|
+
attr_reader :block
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
raise ArgumentError, 'Block is required for after_clone' unless block_given?
|
10
|
+
|
11
|
+
@block = Proc.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile(plan)
|
15
|
+
plan.add(:after_clone, self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Clowne::Declarations.add :after_clone, Clowne::Declarations::AfterClone
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Clowne
|
4
|
+
class Resolvers
|
5
|
+
module AfterClone # :nodoc: all
|
6
|
+
def self.call(source, record, declaration, params:, **_options)
|
7
|
+
operation = Clowne::Utils::Operation.current
|
8
|
+
operation.add_after_clone(
|
9
|
+
proc do
|
10
|
+
declaration.block.call(source, record, params)
|
11
|
+
end
|
12
|
+
)
|
13
|
+
record
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -35,12 +35,17 @@ module Clowne
|
|
35
35
|
attr_reader :mapper
|
36
36
|
|
37
37
|
def initialize(mapper)
|
38
|
-
@
|
38
|
+
@after_clone_blocks = []
|
39
|
+
@after_persist_blocks = []
|
39
40
|
@mapper = mapper
|
40
41
|
end
|
41
42
|
|
42
43
|
def add_after_persist(block)
|
43
|
-
@
|
44
|
+
@after_persist_blocks.unshift(block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_after_clone(block)
|
48
|
+
@after_clone_blocks.unshift(block)
|
44
49
|
end
|
45
50
|
|
46
51
|
def add_mapping(origin, clone)
|
@@ -48,7 +53,10 @@ module Clowne
|
|
48
53
|
end
|
49
54
|
|
50
55
|
def to_record
|
51
|
-
@
|
56
|
+
return @_record if defined?(@_record)
|
57
|
+
|
58
|
+
run_after_clone
|
59
|
+
@_record = @clone
|
52
60
|
end
|
53
61
|
|
54
62
|
def persist!
|
@@ -76,7 +84,11 @@ module Clowne
|
|
76
84
|
end
|
77
85
|
|
78
86
|
def run_after_persist
|
79
|
-
@
|
87
|
+
@after_persist_blocks.each(&:call)
|
88
|
+
end
|
89
|
+
|
90
|
+
def run_after_clone
|
91
|
+
@after_clone_blocks.each(&:call)
|
80
92
|
end
|
81
93
|
end
|
82
94
|
end
|
data/lib/clowne/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clowne
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladimir Dementyev
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-03-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -134,6 +134,7 @@ files:
|
|
134
134
|
- clowne.gemspec
|
135
135
|
- docs/.rubocop.yml
|
136
136
|
- docs/active_record.md
|
137
|
+
- docs/after_clone.md
|
137
138
|
- docs/after_persist.md
|
138
139
|
- docs/alternatives.md
|
139
140
|
- docs/architecture.md
|
@@ -178,6 +179,7 @@ files:
|
|
178
179
|
- lib/clowne/adapters/active_record.rb
|
179
180
|
- lib/clowne/adapters/active_record/associations.rb
|
180
181
|
- lib/clowne/adapters/active_record/associations/base.rb
|
182
|
+
- lib/clowne/adapters/active_record/associations/belongs_to.rb
|
181
183
|
- lib/clowne/adapters/active_record/associations/has_and_belongs_to_many.rb
|
182
184
|
- lib/clowne/adapters/active_record/associations/has_many.rb
|
183
185
|
- lib/clowne/adapters/active_record/associations/has_one.rb
|
@@ -202,6 +204,7 @@ files:
|
|
202
204
|
- lib/clowne/adapters/sequel/specifications/after_persist_does_not_support.rb
|
203
205
|
- lib/clowne/cloner.rb
|
204
206
|
- lib/clowne/declarations.rb
|
207
|
+
- lib/clowne/declarations/after_clone.rb
|
205
208
|
- lib/clowne/declarations/after_persist.rb
|
206
209
|
- lib/clowne/declarations/base.rb
|
207
210
|
- lib/clowne/declarations/exclude_association.rb
|
@@ -217,6 +220,7 @@ files:
|
|
217
220
|
- lib/clowne/ext/string_constantize.rb
|
218
221
|
- lib/clowne/ext/yield_self_then.rb
|
219
222
|
- lib/clowne/planner.rb
|
223
|
+
- lib/clowne/resolvers/after_clone.rb
|
220
224
|
- lib/clowne/resolvers/after_persist.rb
|
221
225
|
- lib/clowne/resolvers/finalize.rb
|
222
226
|
- lib/clowne/resolvers/init_as.rb
|