table_sync 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00c09777052902dc012d825d79668aeebe130d2fd4fcfefb77d3d33bbb1dc511
4
- data.tar.gz: ec571dc138e800ada7e0f4fd112516caed6f110bbaabcc64cdfb3aac36b81989
3
+ metadata.gz: fd4c73054274dd89d2a58f98fb0974a4202a78aad3512a9d85e50219ab4dc7b0
4
+ data.tar.gz: 50f863a5e00336c03c58d19733354d7287db2a66e5c415ff784c23501642331d
5
5
  SHA512:
6
- metadata.gz: 18ed6af8a53a850c59ec1fbffa2ae9e85d197644528cbde81f8502fce2a88affbedfed071890430f0abbcfa718c11567c0171eef2f90886d6d01ff4db21c10fa
7
- data.tar.gz: ea36659bef94f7cf27109c8882f5f6e5cacc90201032024ce8c41ce0bac3449dfb3172d0ba675b0f5b8d075e82bd9b0807571f49340e2d6e6a62330028c7695f
6
+ metadata.gz: 8bd844b57952aa85a32324832660b73270a28bce1c3b3a16e8a12bf02d6858531da2d1475f19865e13378b9c355639a17cf37c6f35a0b8067118d423cd9d9825
7
+ data.tar.gz: 9e5911d3ed2050128d3b7ec63c9e8d3fe1ec8c464026f531cc16a6ad183e739fdd730f1a4890176a2c3194c894f07ffd7a39b12d0e69a54c643aeac6ac021ec8
@@ -10,3 +10,7 @@ AllCops:
10
10
  - Gemfile
11
11
  - Rakefile
12
12
  - table_sync.gemspec
13
+
14
+ Style/Alias:
15
+ Enabled: true
16
+ EnforcedStyle: prefer_alias_method
@@ -1,6 +1,14 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [2.2.0] - 2020-04-12
5
+ ### Added
6
+ - Introduce Plugin ecosystem (**TableSync::Plugins**);
7
+
8
+ ## [2.1.1] - 2020-04-10
9
+ ### Fixed
10
+ - Updated docs for batch_publishing to fully reflect changes in 2.1.0
11
+
4
12
  ## [2.1.0] - 2020-04-09
5
13
  ### Added
6
14
  - **TableSync::BatchPublisher**: custom headers;
data/README.md CHANGED
@@ -21,6 +21,7 @@ require 'table_sync'
21
21
  ## Usage
22
22
 
23
23
  - [Documentation](docs/synopsis.md)
24
+ - [Development](docs/development.md)
24
25
 
25
26
  ## Contributing
26
27
 
@@ -0,0 +1,43 @@
1
+ # TableSync (development)
2
+
3
+ ## Table of Contents
4
+
5
+ - [Creation and registration of the new plugin](#creation-and-registration-of-the-new-plugin)
6
+
7
+ ### Creation and registration of the new plugin
8
+
9
+ * Create a class inherited from `TableSync::Plugins::Abstract` (recommendation: place it in the plugins directory (`lib/plugins/`));
10
+ * Implement `.install!` method (`TableSync::Plugins::Abstract.install!`)
11
+ * Register the newly created class in plugins ecosystem (`TableSync.register_plugin('plugin_name', PluginClass))`);
12
+ * Usage: `TableSync.enable(:plugin_name)` / `TableSync.plugin(:plugin_name)` / `TableSync.load(:plugin_name)` (string name is supported too);
13
+
14
+ Example:
15
+
16
+ ```ruby
17
+ # 1) creation (lib/plugins/global_method.rb)
18
+ class TableSync::Plugins::GlobalMethod < TableSync::Plugins::Abstract
19
+ class << self
20
+ # 2) plugin loader method implementation
21
+ def install!
22
+ ::TableSync.extend(Module.new do
23
+ def global_method
24
+ :works!
25
+ end
26
+ end)
27
+ end
28
+ end
29
+ end
30
+
31
+ # 3) plugin registration
32
+ TableSync.register('global_method', TableSync::Plugins::GlobalMethod)
33
+
34
+ # 4) enable registerd plugin
35
+ TableSync.plugin(:global_method) # string is supported too
36
+ # --- or ---
37
+ TableSync.enable(:global_method) # string is supported too
38
+ # --- or ---
39
+ TableSync.load(:global_method) # string is supported too
40
+
41
+ # Your new functionality
42
+ TableSync.global_method # => :works!
43
+ ```
@@ -90,11 +90,10 @@ where state is one of `:created / :updated / :destroyed` and `confirm` is Rabbit
90
90
  # Manual publishing with batches
91
91
 
92
92
  You can use `TableSync::BatchPublisher` to publish changes in batches (array of hashes in `attributes`).
93
- For now, only the following changes in the table can be published: `create` and` update`.
94
93
 
95
94
  When using `TableSync::BatchPublisher`,` TableSync.routing_key_callable` is called as follows:
96
95
  `TableSync.routing_key_callable.call(klass, {})`, i.e. empty hash is passed instead of attributes.
97
- And `TableSync.routing_metadata_callable` is not called at all: header value is set to empty hash.
96
+ And `TableSync.routing_metadata_callable` is not called at all: metadata is set to empty hash.
98
97
 
99
98
  `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, where `original_attributes_array` is an array with hash of attributes of published objects and `options` is a hash of options.
100
99
 
@@ -123,11 +122,10 @@ TableSync::BatchPublisher.new(
123
122
  # Manual publishing with batches (Russian)
124
123
 
125
124
  С помощью класса `TableSync::BatchPublisher` вы можете опубликовать изменения батчами (массивом в `attributes`).
126
- Пока можно публиковать только следующие изменения в таблице: `создание записи` и `обновление записи`.
127
125
 
128
126
  При использовании `TableSync::BatchPublisher`, `TableSync.routing_key_callable` вызывается следующим образом:
129
127
  `TableSync.routing_key_callable.call(klass, {})`, то есть вместо аттрибутов передается пустой хэш.
130
- А `TableSync.routing_metadata_callable` не вызывается вовсе: в хидерах устанавливается пустой хэш.
128
+ А `TableSync.routing_metadata_callable` не вызывается вовсе: в метадате устанавливается пустой хэш.
131
129
 
132
130
  `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, где `original_attributes_array` - массив с аттрибутами публикуемых объектов и `options`- это хэш с дополнительными опциями.
133
131
 
@@ -7,26 +7,31 @@ require "active_support/core_ext/object/blank"
7
7
  require "active_support/core_ext/numeric/time"
8
8
 
9
9
  module TableSync
10
- require_relative "./table_sync/version"
11
- require_relative "./table_sync/errors"
12
- require_relative "./table_sync/event_actions"
13
- require_relative "./table_sync/event_actions/data_wrapper"
14
- require_relative "./table_sync/config"
15
- require_relative "./table_sync/config/callback_registry"
16
- require_relative "./table_sync/config_decorator"
17
- require_relative "./table_sync/dsl"
18
- require_relative "./table_sync/receiving_handler"
19
- require_relative "./table_sync/base_publisher"
20
- require_relative "./table_sync/publisher"
21
- require_relative "./table_sync/batch_publisher"
22
- require_relative "./table_sync/orm_adapter/active_record"
23
- require_relative "./table_sync/orm_adapter/sequel"
24
- require_relative "./table_sync/model/active_record"
25
- require_relative "./table_sync/model/sequel"
26
- require_relative "./table_sync/instrument"
27
- require_relative "./table_sync/instrument_adapter/active_support"
28
- require_relative "./table_sync/naming_resolver/active_record"
29
- require_relative "./table_sync/naming_resolver/sequel"
10
+ require_relative "table_sync/version"
11
+ require_relative "table_sync/errors"
12
+ require_relative "table_sync/plugins"
13
+ require_relative "table_sync/event_actions"
14
+ require_relative "table_sync/event_actions/data_wrapper"
15
+ require_relative "table_sync/config"
16
+ require_relative "table_sync/config/callback_registry"
17
+ require_relative "table_sync/config_decorator"
18
+ require_relative "table_sync/dsl"
19
+ require_relative "table_sync/receiving_handler"
20
+ require_relative "table_sync/base_publisher"
21
+ require_relative "table_sync/publisher"
22
+ require_relative "table_sync/batch_publisher"
23
+ require_relative "table_sync/orm_adapter/active_record"
24
+ require_relative "table_sync/orm_adapter/sequel"
25
+ require_relative "table_sync/model/active_record"
26
+ require_relative "table_sync/model/sequel"
27
+ require_relative "table_sync/instrument"
28
+ require_relative "table_sync/instrument_adapter/active_support"
29
+ require_relative "table_sync/naming_resolver/active_record"
30
+ require_relative "table_sync/naming_resolver/sequel"
31
+
32
+ # @api public
33
+ # @since 2.2.0
34
+ extend Plugins::AccessMixin
30
35
 
31
36
  class << self
32
37
  include Memery
@@ -38,4 +38,26 @@ module TableSync
38
38
  MSG
39
39
  end
40
40
  end
41
+
42
+ # @api public
43
+ # @since 2.2.0
44
+ PluginError = Class.new(Error)
45
+
46
+ # @api public
47
+ # @since 2.2.0
48
+ class UnregisteredPluginError < PluginError
49
+ # @param plugin_name [Any]
50
+ def initialize(plugin_name)
51
+ super("#{plugin_name} plugin is not registered")
52
+ end
53
+ end
54
+
55
+ # @api public
56
+ # @since 2.2.0
57
+ class AlreadyRegisteredPluginError < PluginError
58
+ # @param plugin_name [Any]
59
+ def initialize(plugin_name)
60
+ super("#{plugin_name} plugin already exists")
61
+ end
62
+ end
41
63
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 2.2.0
5
+ module TableSync::Plugins
6
+ require_relative "plugins/registry"
7
+ require_relative "plugins/access_mixin"
8
+ require_relative "plugins/abstract"
9
+
10
+ # @since 2.2.0
11
+ @plugin_registry = Registry.new
12
+ # @since 2.2.0
13
+ @access_lock = Mutex.new
14
+
15
+ class << self
16
+ # @param plugin_name [Symbol, String]
17
+ # @return [void]
18
+ #
19
+ # @api public
20
+ # @since 2.2.0
21
+ def load(plugin_name)
22
+ thread_safe { plugin_registry[plugin_name].load! }
23
+ end
24
+
25
+ # @return [Array<String>]
26
+ #
27
+ # @api public
28
+ # @since 2.2.0
29
+ def loaded_plugins
30
+ thread_safe { plugin_registry.loaded.keys }
31
+ end
32
+
33
+ # @return [Array<String>]
34
+ #
35
+ # @api public
36
+ # @since 2.2.0
37
+ def names
38
+ thread_safe { plugin_registry.names }
39
+ end
40
+
41
+ # @param plugin_name [Symbol, String]
42
+ # @return [void]
43
+ #
44
+ # @api private
45
+ # @since 2.2.0
46
+ def register_plugin(plugin_name, plugin_module)
47
+ thread_safe { plugin_registry[plugin_name] = plugin_module }
48
+ end
49
+
50
+ private
51
+
52
+ # @return [TableSync::Plugins::Registry]
53
+ #
54
+ # @api private
55
+ # @since 2.2.0
56
+ attr_reader :plugin_registry
57
+
58
+ # @return [Mutex]
59
+ #
60
+ # @api private
61
+ # @since 2.2.0
62
+ attr_reader :access_lock
63
+
64
+ # @return [void]
65
+ #
66
+ # @api private
67
+ # @since 2.2.0
68
+ def thread_safe
69
+ access_lock.synchronize { yield if block_given? }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ class TableSync::Plugins::Abstract
6
+ class << self
7
+ # @param child_klass [Class]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 2.2.0
12
+ def inherited(child_klass)
13
+ child_klass.instance_variable_set(:@__loaded__, false)
14
+ child_klass.instance_variable_set(:@__lock__, Mutex.new)
15
+ super
16
+ end
17
+
18
+ # @return [void]
19
+ #
20
+ # @api private
21
+ # @since 2.2.0
22
+ def load!
23
+ __thread_safe__ do
24
+ unless @__loaded__
25
+ @__loaded__ = true
26
+ install!
27
+ end
28
+ end
29
+ end
30
+
31
+ # @return [Boolean]
32
+ #
33
+ # @api private
34
+ # @since 2.2.0
35
+ def loaded?
36
+ __thread_safe__ { @__loaded__ }
37
+ end
38
+
39
+ private
40
+
41
+ # @return [void]
42
+ #
43
+ # @api private
44
+ # @since 2.2.0
45
+ def install!; end
46
+
47
+ # @return [Any]
48
+ #
49
+ # @api private
50
+ # @since 2.2.0
51
+ def __thread_safe__
52
+ @__lock__.synchronize { yield }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ module TableSync::Plugins::AccessMixin
6
+ # @param plugin_name [Symbol, String]
7
+ # @return [void]
8
+ #
9
+ # @see TableSync::Plugins
10
+ #
11
+ # @api public
12
+ # @since 2.2.0
13
+ def plugin(plugin_name)
14
+ TableSync::Plugins.load(plugin_name)
15
+ end
16
+ alias_method :enable, :plugin
17
+ alias_method :load, :plugin
18
+
19
+ # @return [Array<String>]
20
+ #
21
+ # @see TableSync::Plugins
22
+ #
23
+ # @api public
24
+ # @since 2.2.0
25
+ def plugins
26
+ TableSync::Plugins.names
27
+ end
28
+
29
+ # @return [Hash<String,Class<TableSync::Plugins::Abstract>>]
30
+ #
31
+ # @api private
32
+ # @since 2.2.0
33
+ def loaded_plugins
34
+ TableSync::Plugins.loaded_plugins
35
+ end
36
+ alias_method :enabled_plugins, :loaded_plugins
37
+
38
+ # @param plugin_name [String, Symbol]
39
+ # @param plugin_klass [Class<TableSync::Plugins::Abstract>]
40
+ # @return [void]
41
+ #
42
+ # @see TableSync::Plugins
43
+ #
44
+ # @api public
45
+ # @since 2.2.0
46
+ def register_plugin(plugin_name, plugin_klass)
47
+ TableSync::Plugins.register_plugin(plugin_name, plugin_klass)
48
+ end
49
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ class TableSync::Plugins::Registry
6
+ include Enumerable
7
+
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 2.2.0
12
+ def initialize
13
+ @plugin_set = {}
14
+ @access_lock = Mutex.new
15
+ end
16
+
17
+ # @param plugin_name [Symbol, String]
18
+ # @return [TableSync::Plugins::Abstract]
19
+ #
20
+ # @api private
21
+ # @since 2.2.0
22
+ def [](plugin_name)
23
+ thread_safe { fetch(plugin_name) }
24
+ end
25
+
26
+ # @param plugin_name [Symbol, String]
27
+ # @param plugin_module [TableSync::Plugins::Abstract]
28
+ # @return [void]
29
+ #
30
+ # @api private
31
+ # @since 2.2.0
32
+ def register(plugin_name, plugin_module)
33
+ thread_safe { apply(plugin_name, plugin_module) }
34
+ end
35
+ alias_method :[]=, :register
36
+
37
+ # @return [Array<String>]
38
+ #
39
+ # @api private
40
+ # @since 2.2.0
41
+ def names
42
+ thread_safe { plugin_names }
43
+ end
44
+
45
+ # @return [Hash<String,Class<TableSync::Plugins::Abstract>>]
46
+ #
47
+ # @api private
48
+ # @since 2.2.0
49
+ def loaded
50
+ thread_safe { loaded_plugins }
51
+ end
52
+
53
+ # @param block [Block]
54
+ # @return [Enumerable]
55
+ #
56
+ # @api private
57
+ # @since 2.2.0
58
+ def each(&block)
59
+ thread_safe { iterate(&block) }
60
+ end
61
+
62
+ private
63
+
64
+ # @return [Hash]
65
+ #
66
+ # @api private
67
+ # @since 2.2.0
68
+ attr_reader :plugin_set
69
+
70
+ # @return [Mutex]
71
+ #
72
+ # @api private
73
+ # @since 2.2.0
74
+ attr_reader :access_lock
75
+
76
+ # @return [void]
77
+ #
78
+ # @api private
79
+ # @since 2.2.0
80
+ def thread_safe
81
+ access_lock.synchronize { yield if block_given? }
82
+ end
83
+
84
+ # @return [Array<String>]
85
+ #
86
+ # @api private
87
+ # @since 2.2.0
88
+ def plugin_names
89
+ plugin_set.keys
90
+ end
91
+
92
+ # @param block [Block]
93
+ # @return [Enumerable]
94
+ #
95
+ # @api private
96
+ # @since 2.2.0
97
+ def iterate(&block)
98
+ block_given? ? plugin_set.each_pair(&block) : plugin_set.each_pair
99
+ end
100
+
101
+ # @param plugin_name [String]
102
+ # @return [Boolean]
103
+ #
104
+ # @api private
105
+ # @since 2.2.0
106
+ def registered?(plugin_name)
107
+ plugin_set.key?(plugin_name)
108
+ end
109
+
110
+ # @return [Array<TableSync::Plugins::Abstract>]
111
+ #
112
+ # @api private
113
+ # @since 2.2.0
114
+ def loaded_plugins
115
+ plugin_set.select { |_plugin_name, plugin_module| plugin_module.loaded? }
116
+ end
117
+
118
+ # @param plugin_name [Symbol, String]
119
+ # @param plugin_module [TableSync::Plugins::Abstract]
120
+ # @return [void]
121
+ #
122
+ # @raise [TableSync::AlreadyRegisteredPluginError]
123
+ #
124
+ # @api private
125
+ # @since 2.2.0
126
+ def apply(plugin_name, plugin_module)
127
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
128
+ raise(TableSync::AlreadyRegisteredPluginError.new(plugin_name)) if registered?(plugin_name)
129
+ plugin_set[plugin_name] = plugin_module
130
+ end
131
+
132
+ # @param plugin_name [Symbol, String]
133
+ # @return [TableSync::Plugins::Abstract]
134
+ #
135
+ # @raise [TableSync::UnregisteredPluginError]
136
+ #
137
+ # @api private
138
+ # @since 2.2.0
139
+ def fetch(plugin_name)
140
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
141
+ raise(TableSync::UnregisteredPluginError.new(plugin_name)) unless registered?(plugin_name)
142
+ plugin_set[plugin_name]
143
+ end
144
+
145
+ # @param key [Symbol, String]
146
+ # @return [String]
147
+ #
148
+ # @api private
149
+ # @since 2.2.0
150
+ def indifferently_accessible_plugin_name(plugin_name)
151
+ plugin_name.to_s
152
+ end
153
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TableSync
4
- VERSION = "2.1.0"
4
+ VERSION = "2.2.0"
5
5
  end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_development_dependency "coveralls", "~> 0.8"
34
34
  spec.add_development_dependency "rspec", "~> 3.8"
35
- spec.add_development_dependency "rubocop-config-umbrellio", "~> 0.74"
35
+ spec.add_development_dependency "rubocop-config-umbrellio", "~> 0.81"
36
36
  spec.add_development_dependency "simplecov", "~> 0.16"
37
37
 
38
38
  spec.add_development_dependency "activejob", ">= 4.2.11"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: table_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Umbrellio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-09 00:00:00.000000000 Z
11
+ date: 2020-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: memery
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.74'
89
+ version: '0.81'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.74'
96
+ version: '0.81'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -253,6 +253,7 @@ files:
253
253
  - Rakefile
254
254
  - bin/console
255
255
  - bin/setup
256
+ - docs/development.md
256
257
  - docs/synopsis.md
257
258
  - lib/table_sync.rb
258
259
  - lib/table_sync/base_publisher.rb
@@ -275,6 +276,10 @@ files:
275
276
  - lib/table_sync/naming_resolver/sequel.rb
276
277
  - lib/table_sync/orm_adapter/active_record.rb
277
278
  - lib/table_sync/orm_adapter/sequel.rb
279
+ - lib/table_sync/plugins.rb
280
+ - lib/table_sync/plugins/abstract.rb
281
+ - lib/table_sync/plugins/access_mixin.rb
282
+ - lib/table_sync/plugins/registry.rb
278
283
  - lib/table_sync/publisher.rb
279
284
  - lib/table_sync/receiving_handler.rb
280
285
  - lib/table_sync/version.rb