pub_sub_model_sync 0.2.4 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7655730b3b89716b76be52db708b7c93ec64176cc158fc84323d4e811f6dcdf1
4
- data.tar.gz: 874aa3f5c5c679fd3e7ec02550426f0824481194ebd99b1a0494180df3a22cc6
3
+ metadata.gz: 04acaa2b5befa05fd52978367afdb24c6a1a5858e10441620a2860a57ea9cd55
4
+ data.tar.gz: 25297748dd5e1099f9f251d73f7f94c0680e9c04820c3396143f9b3ca17170ad
5
5
  SHA512:
6
- metadata.gz: 9e8406293a7528fa5d697c2a6a30b4cb00cee900b349ef834fad5fd7771ce864a8338ac95bc1bcbe41568d9efa1737111720607cb0f002e684ab532e835ec651
7
- data.tar.gz: 0f995774ddf1b916db02fed9051c26b106e549261877c72a718e9e23c45544dff6c9757231e094201c9d466b2c4922d8e6364f8167697820db5833d78ee85c85
6
+ metadata.gz: dea58e39fd6d77599000a932f7db942052d5309069c8adb0e571fcb2b7be4a5d4429048371b5bac51c18ff9f016dc88fc0e85ea73ca04bc93f36536c580ea544
7
+ data.tar.gz: cead04daf416641b5d900d4c8c6a13509c49fa8256dd343552c70b578f5af3a3ba39465069999688418e4de60ba4f9a62b4e40e3b54c0c55dd89dcf366f28ab2
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Datasource local storage ignored files
5
+ /dataSources/
6
+ /dataSources.local.xml
7
+ # Editor-based HTTP Client requests
8
+ /httpRequests/
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build pub_sub_model_sync-0.1.0.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install pub_sub_model_sync-0.1.0.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install pub_sub_model_sync-0.1.0.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.1.0 and build and push pub_sub_model_sync-0.1.0.gem to TODO: Set to 'http://mygemserver.com'" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
@@ -0,0 +1,5 @@
1
+ <component name="ProjectCodeStyleConfiguration">
2
+ <state>
3
+ <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
4
+ </state>
5
+ </component>
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Encoding" addBOMForNewFiles="with NO BOM" />
4
+ </project>
@@ -0,0 +1,16 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Rubocop" enabled="true" level="WARNING" enabled_by_default="true">
5
+ <option name="mySeverityMap">
6
+ <map>
7
+ <entry key="convention" value="ERROR" />
8
+ <entry key="error" value="ERROR" />
9
+ <entry key="fatal" value="ERROR" />
10
+ <entry key="refactor" value="ERROR" />
11
+ <entry key="warning" value="ERROR" />
12
+ </map>
13
+ </option>
14
+ </inspection_tool>
15
+ </profile>
16
+ </component>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="JavaScriptSettings">
4
+ <option name="languageLevel" value="ES6" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-2.5.3" project-jdk-type="RUBY_SDK" />
7
+ </project>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/pub_sub_model_sync.iml" filepath="$PROJECT_DIR$/.idea/pub_sub_model_sync.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,96 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="ModuleRunConfigurationManager">
4
+ <shared />
5
+ </component>
6
+ <component name="NewModuleRootManager">
7
+ <content url="file://$MODULE_DIR$" />
8
+ <orderEntry type="jdk" jdkName="RVM: ruby-2.6.5" jdkType="RUBY_SDK" />
9
+ <orderEntry type="sourceFolder" forTests="false" />
10
+ <orderEntry type="library" scope="PROVIDED" name="actioncable (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
11
+ <orderEntry type="library" scope="PROVIDED" name="actionmailbox (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
12
+ <orderEntry type="library" scope="PROVIDED" name="actionmailer (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
13
+ <orderEntry type="library" scope="PROVIDED" name="actionpack (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="actiontext (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="actionview (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="activejob (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="activemodel (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="activerecord (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="activestorage (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="activesupport (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="addressable (v2.7.0, RVM: ruby-2.6.5) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="amq-protocol (v2.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.0, RVM: ruby-2.6.5) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="builder (v3.2.4, RVM: ruby-2.6.5) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v2.1.4, RVM: ruby-2.6.5) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="bunny (v2.14.3, RVM: ruby-2.6.5) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.1.6, RVM: ruby-2.6.5) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="crass (v1.0.6, RVM: ruby-2.6.5) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="database_cleaner (v1.8.4, RVM: ruby-2.6.5) [gem]" level="application" />
30
+ <orderEntry type="library" scope="PROVIDED" name="database_cleaner-active_record (v1.8.0, RVM: ruby-2.6.5) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.3, RVM: ruby-2.6.5) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="digest-crc (v0.5.1, RVM: ruby-2.6.5) [gem]" level="application" />
33
+ <orderEntry type="library" scope="PROVIDED" name="erubi (v1.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
34
+ <orderEntry type="library" scope="PROVIDED" name="faraday (v0.17.3, RVM: ruby-2.6.5) [gem]" level="application" />
35
+ <orderEntry type="library" scope="PROVIDED" name="globalid (v0.4.2, RVM: ruby-2.6.5) [gem]" level="application" />
36
+ <orderEntry type="library" scope="PROVIDED" name="google-cloud-core (v1.3.2, RVM: ruby-2.6.5) [gem]" level="application" />
37
+ <orderEntry type="library" scope="PROVIDED" name="google-cloud-env (v1.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
38
+ <orderEntry type="library" scope="PROVIDED" name="google-cloud-pubsub (v1.0.2, RVM: ruby-2.6.5) [gem]" level="application" />
39
+ <orderEntry type="library" scope="PROVIDED" name="google-gax (v1.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
40
+ <orderEntry type="library" scope="PROVIDED" name="google-protobuf (v3.11.4, RVM: ruby-2.6.5) [gem]" level="application" />
41
+ <orderEntry type="library" scope="PROVIDED" name="googleapis-common-protos (v1.3.9, RVM: ruby-2.6.5) [gem]" level="application" />
42
+ <orderEntry type="library" scope="PROVIDED" name="googleapis-common-protos-types (v1.0.4, RVM: ruby-2.6.5) [gem]" level="application" />
43
+ <orderEntry type="library" scope="PROVIDED" name="googleauth (v0.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
44
+ <orderEntry type="library" scope="PROVIDED" name="grpc (v1.27.0, RVM: ruby-2.6.5) [gem]" level="application" />
45
+ <orderEntry type="library" scope="PROVIDED" name="grpc-google-iam-v1 (v0.6.9, RVM: ruby-2.6.5) [gem]" level="application" />
46
+ <orderEntry type="library" scope="PROVIDED" name="i18n (v1.8.2, RVM: ruby-2.6.5) [gem]" level="application" />
47
+ <orderEntry type="library" scope="PROVIDED" name="jaro_winkler (v1.5.4, RVM: ruby-2.6.5) [gem]" level="application" />
48
+ <orderEntry type="library" scope="PROVIDED" name="jwt (v2.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
49
+ <orderEntry type="library" scope="PROVIDED" name="loofah (v2.5.0, RVM: ruby-2.6.5) [gem]" level="application" />
50
+ <orderEntry type="library" scope="PROVIDED" name="mail (v2.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
51
+ <orderEntry type="library" scope="PROVIDED" name="marcel (v0.3.3, RVM: ruby-2.6.5) [gem]" level="application" />
52
+ <orderEntry type="library" scope="PROVIDED" name="memoist (v0.16.2, RVM: ruby-2.6.5) [gem]" level="application" />
53
+ <orderEntry type="library" scope="PROVIDED" name="method_source (v1.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
54
+ <orderEntry type="library" scope="PROVIDED" name="mimemagic (v0.3.4, RVM: ruby-2.6.5) [gem]" level="application" />
55
+ <orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.0.2, RVM: ruby-2.6.5) [gem]" level="application" />
56
+ <orderEntry type="library" scope="PROVIDED" name="mini_portile2 (v2.4.0, RVM: ruby-2.6.5) [gem]" level="application" />
57
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v5.14.0, RVM: ruby-2.6.5) [gem]" level="application" />
58
+ <orderEntry type="library" scope="PROVIDED" name="multi_json (v1.14.1, RVM: ruby-2.6.5) [gem]" level="application" />
59
+ <orderEntry type="library" scope="PROVIDED" name="multipart-post (v2.1.1, RVM: ruby-2.6.5) [gem]" level="application" />
60
+ <orderEntry type="library" scope="PROVIDED" name="nio4r (v2.5.2, RVM: ruby-2.6.5) [gem]" level="application" />
61
+ <orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.10.9, RVM: ruby-2.6.5) [gem]" level="application" />
62
+ <orderEntry type="library" scope="PROVIDED" name="os (v1.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
63
+ <orderEntry type="library" scope="PROVIDED" name="parallel (v1.19.1, RVM: ruby-2.6.5) [gem]" level="application" />
64
+ <orderEntry type="library" scope="PROVIDED" name="parser (v2.7.0.4, RVM: ruby-2.6.5) [gem]" level="application" />
65
+ <orderEntry type="library" scope="PROVIDED" name="public_suffix (v4.0.3, RVM: ruby-2.6.5) [gem]" level="application" />
66
+ <orderEntry type="library" scope="PROVIDED" name="rack (v2.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
67
+ <orderEntry type="library" scope="PROVIDED" name="rack-test (v1.1.0, RVM: ruby-2.6.5) [gem]" level="application" />
68
+ <orderEntry type="library" scope="PROVIDED" name="rails (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
69
+ <orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.0.3, RVM: ruby-2.6.5) [gem]" level="application" />
70
+ <orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
71
+ <orderEntry type="library" scope="PROVIDED" name="railties (v6.0.2.2, RVM: ruby-2.6.5) [gem]" level="application" />
72
+ <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
73
+ <orderEntry type="library" scope="PROVIDED" name="rake (v13.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
74
+ <orderEntry type="library" scope="PROVIDED" name="rexml (v3.2.4, RVM: ruby-2.6.5) [gem]" level="application" />
75
+ <orderEntry type="library" scope="PROVIDED" name="rly (v0.2.3, RVM: ruby-2.6.5) [gem]" level="application" />
76
+ <orderEntry type="library" scope="PROVIDED" name="rspec (v3.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
77
+ <orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.9.1, RVM: ruby-2.6.5) [gem]" level="application" />
78
+ <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.9.0, RVM: ruby-2.6.5) [gem]" level="application" />
79
+ <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.9.1, RVM: ruby-2.6.5) [gem]" level="application" />
80
+ <orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.9.2, RVM: ruby-2.6.5) [gem]" level="application" />
81
+ <orderEntry type="library" scope="PROVIDED" name="rubocop (v0.80.1, RVM: ruby-2.6.5) [gem]" level="application" />
82
+ <orderEntry type="library" scope="PROVIDED" name="ruby-kafka (v1.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
83
+ <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.10.1, RVM: ruby-2.6.5) [gem]" level="application" />
84
+ <orderEntry type="library" scope="PROVIDED" name="signet (v0.11.0, RVM: ruby-2.6.5) [gem]" level="application" />
85
+ <orderEntry type="library" scope="PROVIDED" name="sprockets (v4.0.0, RVM: ruby-2.6.5) [gem]" level="application" />
86
+ <orderEntry type="library" scope="PROVIDED" name="sprockets-rails (v3.2.1, RVM: ruby-2.6.5) [gem]" level="application" />
87
+ <orderEntry type="library" scope="PROVIDED" name="sqlite3 (v1.4.2, RVM: ruby-2.6.5) [gem]" level="application" />
88
+ <orderEntry type="library" scope="PROVIDED" name="thor (v1.0.1, RVM: ruby-2.6.5) [gem]" level="application" />
89
+ <orderEntry type="library" scope="PROVIDED" name="thread_safe (v0.3.6, RVM: ruby-2.6.5) [gem]" level="application" />
90
+ <orderEntry type="library" scope="PROVIDED" name="tzinfo (v1.2.7, RVM: ruby-2.6.5) [gem]" level="application" />
91
+ <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v1.6.1, RVM: ruby-2.6.5) [gem]" level="application" />
92
+ <orderEntry type="library" scope="PROVIDED" name="websocket-driver (v0.7.1, RVM: ruby-2.6.5) [gem]" level="application" />
93
+ <orderEntry type="library" scope="PROVIDED" name="websocket-extensions (v0.1.4, RVM: ruby-2.6.5) [gem]" level="application" />
94
+ <orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.3.0, RVM: ruby-2.6.5) [gem]" level="application" />
95
+ </component>
96
+ </module>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ # 0.3.0 (April 29, 2020)
4
+ - Support for multiple identifiers when syncing
5
+ - Add klass.ps_find_model method for a custom model finder
6
+
3
7
  # 0.2.4 (April 28, 2020)
4
8
  - Delegate .publish to the .publisher for better understanding
5
9
 
data/Gemfile CHANGED
@@ -5,5 +5,9 @@ gem 'bunny' # rabbit-mq
5
5
  gem 'google-cloud-pubsub' # google pub/sub
6
6
  gem 'ruby-kafka' # kafka pub/sub
7
7
 
8
+ group :test do
9
+ gem 'database_cleaner-active_record'
10
+ end
11
+
8
12
  # Specify your gem's dependencies in pub_sub_model_sync.gemspec
9
13
  gemspec
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pub_sub_model_sync (0.2.4)
4
+ pub_sub_model_sync (0.3.0)
5
5
  activesupport
6
6
  rails
7
7
 
@@ -72,6 +72,10 @@ GEM
72
72
  amq-protocol (~> 2.3, >= 2.3.0)
73
73
  concurrent-ruby (1.1.6)
74
74
  crass (1.0.6)
75
+ database_cleaner (1.8.4)
76
+ database_cleaner-active_record (1.8.0)
77
+ activerecord
78
+ database_cleaner (~> 1.8.0)
75
79
  diff-lcs (1.3)
76
80
  digest-crc (0.5.1)
77
81
  erubi (1.9.0)
@@ -228,6 +232,7 @@ PLATFORMS
228
232
  DEPENDENCIES
229
233
  bundler
230
234
  bunny
235
+ database_cleaner-active_record
231
236
  google-cloud-pubsub
232
237
  pub_sub_model_sync!
233
238
  rake
data/README.md CHANGED
@@ -67,7 +67,7 @@ And then execute: $ bundle install
67
67
  # attributes: name email age
68
68
  class User < ActiveRecord::Base
69
69
  include PubSubModelSync::PublisherConcern
70
- ps_publish(%i[name email])
70
+ ps_publish(%i[id name email])
71
71
  end
72
72
 
73
73
  # App 2 (Subscriber)
@@ -95,7 +95,7 @@ PubSubModelSync::Publisher.new.publish_data(User, { msg: 'Hello' }, :greeting) #
95
95
  class User < ActiveRecord::Base
96
96
  self.table_name = 'publisher_users'
97
97
  include PubSubModelSync::PublisherConcern
98
- ps_publish(%i[name:full_name email], actions: %i[update], as_klass: 'Client', id: :client_id)
98
+ ps_publish(%i[id:client_id name:full_name email], actions: %i[update], as_klass: 'Client')
99
99
 
100
100
  def ps_skip_callback?(_action)
101
101
  false # here logic with action to skip push message
@@ -110,12 +110,17 @@ end
110
110
  class User < ActiveRecord::Base
111
111
  self.table_name = 'subscriber_users'
112
112
  include PubSubModelSync::SubscriberConcern
113
- ps_subscribe(%i[name], actions: %i[update], as_klass: 'Client', id: :custom_id)
113
+ ps_subscribe(%i[name], actions: %i[update], as_klass: 'Client', id: %i[client_id email])
114
114
  ps_class_subscribe(:greeting, as_action: :custom_greeting, as_klass: 'CustomUser')
115
+ alias_attribute :full_name, :name
115
116
 
116
117
  def self.greeting(data)
117
118
  puts 'Class message called through custom_greeting'
118
119
  end
120
+
121
+ # def self.ps_find_model(data, settings)
122
+ # where(email: data[:email], ...).first_or_initialize
123
+ # end
119
124
  end
120
125
  ```
121
126
 
@@ -132,6 +137,39 @@ end
132
137
  ```
133
138
 
134
139
  ## API
140
+ ### Subscribers
141
+ - Permit to configure class level listeners
142
+ ```ps_class_subscribe(action_name, as_action: nil, as_klass: nil)```
143
+ * as_action: (Optional) Source method name
144
+ * as_klass: (Optional) Source class name
145
+
146
+ - Permit to configure instance level listeners (CRUD)
147
+ ```ps_subscribe(attrs, as_klass: nil, actions: nil, id: nil)```
148
+ * attrs: (Array/Required) Array of all attributes to be synced
149
+ * as_klass: (String/Optional) Source class name (Instead of the model class name, will use this value)
150
+ * actions: (Array/Optional, default: create/update/destroy) permit to customize action names
151
+ * id: (Sym|Array/Optional, default: id) Attr identifier(s) to find the corresponding model
152
+
153
+ - Permit to configure a custom model finder
154
+ ```ps_find_model(data, settings)```
155
+ * data: (Hash) Data received from sync
156
+ * settings: (Hash(:klass, :action)) Class and action name from sync
157
+ Must return an existent or a new model object
158
+
159
+ - Get crud subscription configured for the class
160
+ ```User.ps_subscriber(action_name)```
161
+ * action_name (default :create, :sym): can be :create, :update, :destroy
162
+
163
+ - Inspect all configured listeners
164
+ ```PubSubModelSync::Config.listeners```
165
+
166
+ ### Publishers
167
+ - Permit to configure crud publishers
168
+ ```ps_publish(attrs, actions: nil, as_klass: nil)```
169
+ * attrs: (Array/Required) Array of attributes to be published
170
+ * actions: (Array/Optional, default: create/update/destroy) permit to customize action names
171
+ * as_klass: (String/Optional) Output class name (Instead of the model class name, will use this value)
172
+
135
173
  - Permit to cancel sync called after create/update/destroy (Before initializing sync service)
136
174
  ```model.ps_skip_callback?(action)```
137
175
  Note: Return true to cancel sync
@@ -150,29 +188,24 @@ end
150
188
  - Perform sync on demand (:create, :update, :destroy):
151
189
  The target model will receive a notification to perform the indicated action
152
190
  ```my_model.ps_perform_sync(action_name, custom_settings = {})```
153
- * custom_settings: override default settings defined for action_name ({ attrs: [], as_klass: nil, id: nil })
191
+ * custom_settings: override default settings defined for action_name ({ attrs: [], as_klass: nil })
154
192
 
155
- - Class level notification:
193
+ - Publish a class level notification:
156
194
  ```User.ps_class_publish(data, action: action_name, as_klass: custom_klass_name)```
157
195
  Target class ```User.action_name``` will be called when message is received
158
196
  * data: (required, :hash) message value to deliver
159
- * action_name: (required, :sim) same action name as defined in ps_class_subscribe(...)
160
- * as_klass: (optional, :string) same class name as defined in ps_class_subscribe(...)
197
+ * action_name: (required, :sim) Action name
198
+ * as_klass: (optional, :string) Custom class name (Default current model name)
161
199
 
162
- - Class level notification (Same as above: on demand call)
200
+ - Publish a class level notification (Same as above: on demand call)
163
201
  ```PubSubModelSync::Publisher.new.publish_data(Klass_name, data, action_name)```
164
202
  * klass_name: (required, Class) same class name as defined in ps_class_subscribe(...)
165
203
  * data: (required, :hash) message value to deliver
166
204
  * action_name: (required, :sim) same action name as defined in ps_class_subscribe(...)
167
205
 
168
- - Get crud subscription configured for the class
169
- ```User.ps_subscriber(action_name)```
170
- * action_name (default :create, :sym): can be :create, :update, :destroy
171
206
  - Get crud publisher configured for the class
172
207
  ```User.ps_publisher(action_name)```
173
208
  * action_name (default :create, :sym): can be :create, :update, :destroy
174
- - Inspect all configured listeners
175
- ```PubSubModelSync::Config.listeners```
176
209
 
177
210
  ## Testing with RSpec
178
211
  - Config: (spec/rails_helper.rb)
@@ -205,12 +238,10 @@ end
205
238
  # Subscriber
206
239
  it 'receive model message' do
207
240
  action = :create
208
- data = { name: 'name' }
209
- user_id = 999
210
- attrs = PubSubModelSync::Publisher.build_attrs('User', action, user_id)
211
- publisher = PubSubModelSync::MessageProcessor.new(data, 'User', action, id: user_id)
241
+ data = { name: 'name', id: 999 }
242
+ publisher = PubSubModelSync::MessageProcessor.new(data, 'User', action)
212
243
  publisher.process
213
- expect(User.where(id: user_id).any?).to be_truth
244
+ expect(User.where(id: data[:id]).any?).to be_truth
214
245
  end
215
246
 
216
247
  it 'receive class message' do
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'google/cloud/pubsub'
4
3
  module PubSubModelSync
5
4
  class Connector
6
5
  attr_accessor :service
@@ -2,19 +2,18 @@
2
2
 
3
3
  module PubSubModelSync
4
4
  class MessageProcessor
5
- attr_accessor :data, :attrs, :settings
5
+ attr_accessor :data, :settings, :message_id
6
6
 
7
7
  # @param data (Hash): any hash value to deliver
8
- # @param settings (optional): { id: id_val }
9
- def initialize(data, klass, action, settings = {})
8
+ def initialize(data, klass, action)
10
9
  @data = data
11
- @settings = settings
12
- @attrs = settings.merge(klass: klass, action: action)
10
+ @settings = { klass: klass, action: action }
11
+ @message_id = [klass, action, Time.current.to_i].join('-')
13
12
  end
14
13
 
15
14
  def process
16
15
  @failed = false
17
- log 'processing message'
16
+ log "processing message: #{[data, settings]}"
18
17
  listeners = filter_listeners
19
18
  return log 'Skipped: No listeners' unless listeners.any?
20
19
 
@@ -45,7 +44,7 @@ module PubSubModelSync
45
44
  # support for: create, update, destroy
46
45
  def call_listener(listener)
47
46
  model = find_model(listener)
48
- if attrs[:action].to_sym == :destroy
47
+ if settings[:action].to_sym == :destroy
49
48
  model.destroy!
50
49
  else
51
50
  populate_model(model, listener)
@@ -58,8 +57,17 @@ module PubSubModelSync
58
57
 
59
58
  def find_model(listener)
60
59
  model_class = listener[:klass].constantize
61
- identifier = listener[:settings][:id] || :id
62
- model_class.where(identifier => attrs[:id]).first_or_initialize
60
+ if model_class.respond_to?(:ps_find_model)
61
+ return model_class.ps_find_model(data, settings)
62
+ end
63
+
64
+ model_class.where(model_identifiers(listener)).first_or_initialize
65
+ end
66
+
67
+ def model_identifiers(listener)
68
+ identifiers = listener[:settings][:id]
69
+ identifiers = [identifiers] unless identifiers.is_a?(Array)
70
+ identifiers.map { |key| [key, data[key.to_sym]] }.to_h
63
71
  end
64
72
 
65
73
  def populate_model(model, listener)
@@ -72,13 +80,13 @@ module PubSubModelSync
72
80
  def filter_listeners
73
81
  listeners = PubSubModelSync::Config.listeners
74
82
  listeners.select do |listener|
75
- listener[:as_klass].to_s == attrs[:klass].to_s &&
76
- listener[:as_action].to_s == attrs[:action].to_s
83
+ listener[:as_klass].to_s == settings[:klass].to_s &&
84
+ listener[:as_action].to_s == settings[:action].to_s
77
85
  end
78
86
  end
79
87
 
80
88
  def log(message, kind = :info)
81
- PubSubModelSync::Config.log "#{message} ==> #{[data, attrs]}", kind
89
+ PubSubModelSync::Config.log "(ID: #{message_id}) #{message}", kind
82
90
  end
83
91
  end
84
92
  end
@@ -14,14 +14,13 @@ module PubSubModelSync
14
14
  publish(data, attributes)
15
15
  end
16
16
 
17
- # @param settings (Hash): { attrs: [], as_klass: nil, id: nil }
18
- def publish_model(model, action, settings = nil)
17
+ # @param custom_settings (Hash): { attrs: [], as_klass: nil }
18
+ def publish_model(model, action, custom_settings = {})
19
19
  return if model.ps_skip_sync?(action)
20
20
 
21
- settings ||= model.class.ps_publisher_info(action)
21
+ settings = model.class.ps_publisher(action).merge(custom_settings)
22
22
  attributes = build_model_attrs(model, action, settings)
23
- data = {}
24
- data = build_model_data(model, settings[:attrs]) if action != :destroy
23
+ data = build_model_data(model, settings[:attrs])
25
24
  res_before = model.ps_before_sync(action, data)
26
25
  return if res_before == :cancel
27
26
 
@@ -29,12 +28,8 @@ module PubSubModelSync
29
28
  model.ps_after_sync(action, data)
30
29
  end
31
30
 
32
- def self.build_attrs(klass, action, id = nil)
33
- {
34
- klass: klass.to_s,
35
- action: action.to_sym,
36
- id: id
37
- }
31
+ def self.build_attrs(klass, action)
32
+ { klass: klass.to_s, action: action.to_sym }
38
33
  end
39
34
 
40
35
  private
@@ -52,8 +47,7 @@ module PubSubModelSync
52
47
 
53
48
  def build_model_attrs(model, action, settings)
54
49
  as_klass = (settings[:as_klass] || model.class.name).to_s
55
- id_val = model.send(settings[:id] || :id)
56
- self.class.build_attrs(as_klass, action, id_val)
50
+ self.class.build_attrs(as_klass, action)
57
51
  end
58
52
 
59
53
  def log(msg)
@@ -23,20 +23,20 @@ module PubSubModelSync
23
23
  def ps_after_sync(_action, _data); end
24
24
 
25
25
  # To perform sync on demand
26
- # @param custom_settings (Hash): { attrs: [], as_klass: nil, id: nil }
26
+ # @param custom_settings (Hash): { attrs: [], as_klass: nil }
27
27
  def ps_perform_sync(action = :create, custom_settings = {})
28
28
  service = self.class.ps_publisher_service
29
- model_settings = self.class.ps_publisher_info(action) || {}
29
+ model_settings = self.class.ps_publisher(action) || {}
30
30
  service.publish_model(self, action, model_settings.merge(custom_settings))
31
31
  end
32
32
 
33
33
  module ClassMethods
34
34
  # Permit to configure to publish crud actions (:create, :update, :destroy)
35
- # @param settings (Hash): { actions: nil, as_klass: nil, id: nil }
36
- def ps_publish(attrs, settings = {})
37
- actions = settings.delete(:actions) || %i[create update destroy]
35
+ def ps_publish(attrs, actions: %i[create update destroy], as_klass: nil)
36
+ as_klass ||= name
38
37
  actions.each do |action|
39
- info = settings.merge(klass: name, action: action, attrs: attrs)
38
+ info = { klass: name, action: action, attrs: attrs,
39
+ as_klass: as_klass }
40
40
  PubSubModelSync::Config.publishers << info
41
41
  ps_register_callback(action.to_sym, info)
42
42
  end
@@ -49,10 +49,10 @@ module PubSubModelSync
49
49
  end
50
50
 
51
51
  # Publisher info for specific action
52
- def ps_publisher_info(action = :create)
53
- PubSubModelSync::Config.publishers.select do |listener|
52
+ def ps_publisher(action = :create)
53
+ PubSubModelSync::Config.publishers.find do |listener|
54
54
  listener[:klass] == name && listener[:action] == action
55
- end.last
55
+ end
56
56
  end
57
57
 
58
58
  def ps_publisher_service
@@ -18,11 +18,11 @@ module PubSubModelSync
18
18
 
19
19
  private
20
20
 
21
- # @param payload (String JSON): '{"data":{},"attributes":{..}}'
21
+ # @param payload (String JSON): '{"data":{}, "attributes":{..}}'
22
22
  # refer: PubSubModelSync::Publisher (.publish_model | .publish_data)
23
23
  def perform_message(payload)
24
24
  data, attrs = parse_message_payload(payload)
25
- args = [data, attrs[:klass], attrs[:action], attrs]
25
+ args = [data, attrs[:klass], attrs[:action]]
26
26
  PubSubModelSync::MessageProcessor.new(*args).process
27
27
  end
28
28
 
@@ -7,11 +7,9 @@ module PubSubModelSync
7
7
  end
8
8
 
9
9
  module ClassMethods
10
- # @param settings (Hash): { as_klass: nil, actions: nil, id: nil }
11
- def ps_subscribe(attrs, settings = {})
12
- as_klass = (settings[:as_klass] || name).to_s
13
- actions = settings.delete(:actions) || %i[create update destroy]
14
- settings = settings.merge(attrs: attrs)
10
+ def ps_subscribe(attrs, as_klass: nil, actions: nil, id: :id)
11
+ actions ||= %i[create update destroy]
12
+ settings = { attrs: attrs, id: id }
15
13
  actions.each do |action|
16
14
  add_ps_subscriber(as_klass, action, action, false, settings)
17
15
  end
@@ -22,13 +20,14 @@ module PubSubModelSync
22
20
  end
23
21
 
24
22
  def ps_subscriber(action = :create)
25
- PubSubModelSync::Config.listeners.select do |listener|
23
+ PubSubModelSync::Config.listeners.find do |listener|
26
24
  listener[:klass] == name && listener[:action] == action
27
- end.last
25
+ end
28
26
  end
29
27
 
30
28
  private
31
29
 
30
+ # @param settings (Hash): { id:, attrs: }
32
31
  def add_ps_subscriber(as_klass, action, as_action, direct_mode, settings)
33
32
  listener = {
34
33
  klass: name,
@@ -38,7 +37,7 @@ module PubSubModelSync
38
37
  direct_mode: direct_mode,
39
38
  settings: settings
40
39
  }
41
- PubSubModelSync::Config.listeners << listener
40
+ PubSubModelSync::Config.listeners.push(listener) && listener
42
41
  end
43
42
  end
44
43
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PubSubModelSync
4
- VERSION = '0.2.4'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pub_sub_model_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Owen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-28 00:00:00.000000000 Z
11
+ date: 2020-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -103,6 +103,15 @@ extra_rdoc_files: []
103
103
  files:
104
104
  - ".github/workflows/ruby.yml"
105
105
  - ".gitignore"
106
+ - ".idea/.gitignore"
107
+ - ".idea/.rakeTasks"
108
+ - ".idea/codeStyles/codeStyleConfig.xml"
109
+ - ".idea/encodings.xml"
110
+ - ".idea/inspectionProfiles/Project_Default.xml"
111
+ - ".idea/misc.xml"
112
+ - ".idea/modules.xml"
113
+ - ".idea/pub_sub_model_sync.iml"
114
+ - ".idea/vcs.xml"
106
115
  - ".rspec"
107
116
  - ".rubocop.yml"
108
117
  - CHANGELOG.md