noticed 1.3.2 → 1.6.3

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.
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionCable
4
+ # Have ActionCable pick its Test SubscriptionAdapter when it's called for in cable.yml
5
+ module Server
6
+ class Configuration
7
+ def pubsub_adapter
8
+ (cable["adapter"] == "test") ? ActionCable::SubscriptionAdapter::Test : super
9
+ end
10
+ end
11
+ end
12
+
13
+ # Provides helper methods for testing Action Cable broadcasting
14
+ module TestHelper
15
+ def before_setup # :nodoc:
16
+ server = ActionCable.server
17
+ test_adapter = ActionCable::SubscriptionAdapter::Test.new(server)
18
+
19
+ @old_pubsub_adapter = server.pubsub
20
+
21
+ server.instance_variable_set(:@pubsub, test_adapter)
22
+ super
23
+ end
24
+
25
+ def after_teardown # :nodoc:
26
+ super
27
+ ActionCable.server.instance_variable_set(:@pubsub, @old_pubsub_adapter)
28
+ end
29
+
30
+ # Asserts that the number of broadcasted messages to the stream matches the given number.
31
+ #
32
+ # def test_broadcasts
33
+ # assert_broadcasts 'messages', 0
34
+ # ActionCable.server.broadcast 'messages', { text: 'hello' }
35
+ # assert_broadcasts 'messages', 1
36
+ # ActionCable.server.broadcast 'messages', { text: 'world' }
37
+ # assert_broadcasts 'messages', 2
38
+ # end
39
+ #
40
+ # If a block is passed, that block should cause the specified number of
41
+ # messages to be broadcasted.
42
+ #
43
+ # def test_broadcasts_again
44
+ # assert_broadcasts('messages', 1) do
45
+ # ActionCable.server.broadcast 'messages', { text: 'hello' }
46
+ # end
47
+ #
48
+ # assert_broadcasts('messages', 2) do
49
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
50
+ # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
51
+ # end
52
+ # end
53
+ #
54
+ def assert_broadcasts(stream, number)
55
+ if block_given?
56
+ original_count = broadcasts_size(stream)
57
+ yield
58
+ new_count = broadcasts_size(stream)
59
+ actual_count = new_count - original_count
60
+ else
61
+ actual_count = broadcasts_size(stream)
62
+ end
63
+
64
+ assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
65
+ end
66
+
67
+ # Asserts that no messages have been sent to the stream.
68
+ #
69
+ # def test_no_broadcasts
70
+ # assert_no_broadcasts 'messages'
71
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
72
+ # assert_broadcasts 'messages', 1
73
+ # end
74
+ #
75
+ # If a block is passed, that block should not cause any message to be sent.
76
+ #
77
+ # def test_broadcasts_again
78
+ # assert_no_broadcasts 'messages' do
79
+ # # No job messages should be sent from this block
80
+ # end
81
+ # end
82
+ #
83
+ # Note: This assertion is simply a shortcut for:
84
+ #
85
+ # assert_broadcasts 'messages', 0, &block
86
+ #
87
+ def assert_no_broadcasts(stream, &block)
88
+ assert_broadcasts stream, 0, &block
89
+ end
90
+
91
+ # Asserts that the specified message has been sent to the stream.
92
+ #
93
+ # def test_assert_transmitted_message
94
+ # ActionCable.server.broadcast 'messages', text: 'hello'
95
+ # assert_broadcast_on('messages', text: 'hello')
96
+ # end
97
+ #
98
+ # If a block is passed, that block should cause a message with the specified data to be sent.
99
+ #
100
+ # def test_assert_broadcast_on_again
101
+ # assert_broadcast_on('messages', text: 'hello') do
102
+ # ActionCable.server.broadcast 'messages', text: 'hello'
103
+ # end
104
+ # end
105
+ #
106
+ def assert_broadcast_on(stream, data)
107
+ # Encode to JSON and back–we want to use this value to compare
108
+ # with decoded JSON.
109
+ # Comparing JSON strings doesn't work due to the order of the keys.
110
+ serialized_msg =
111
+ ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
112
+
113
+ new_messages = broadcasts(stream)
114
+ if block_given?
115
+ old_messages = new_messages
116
+ clear_messages(stream)
117
+
118
+ yield
119
+ new_messages = broadcasts(stream)
120
+ clear_messages(stream)
121
+
122
+ # Restore all sent messages
123
+ (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
124
+ end
125
+
126
+ message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
127
+
128
+ assert message, "No messages sent with #{data} to #{stream}"
129
+ end
130
+
131
+ def pubsub_adapter # :nodoc:
132
+ ActionCable.server.pubsub
133
+ end
134
+
135
+ delegate :broadcasts, :clear_messages, to: :pubsub_adapter
136
+
137
+ private
138
+
139
+ def broadcasts_size(channel)
140
+ broadcasts(channel).size
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ # First add Rails 6.0 ActiveJob Serializers support, and then the
4
+ # DurationSerializer and SymbolSerializer.
5
+ module ActiveJob
6
+ module Arguments
7
+ # :nodoc:
8
+ OBJECT_SERIALIZER_KEY = "_aj_serialized"
9
+
10
+ def serialize_argument(argument)
11
+ case argument
12
+ when *TYPE_WHITELIST
13
+ argument
14
+ when GlobalID::Identification
15
+ convert_to_global_id_hash(argument)
16
+ when Array
17
+ argument.map { |arg| serialize_argument(arg) }
18
+ when ActiveSupport::HashWithIndifferentAccess
19
+ serialize_indifferent_hash(argument)
20
+ when Hash
21
+ symbol_keys = argument.each_key.grep(Symbol).map(&:to_s)
22
+ result = serialize_hash(argument)
23
+ result[SYMBOL_KEYS_KEY] = symbol_keys
24
+ result
25
+ when ->(arg) { arg.respond_to?(:permitted?) }
26
+ serialize_indifferent_hash(argument.to_h)
27
+ else # Add Rails 6 support for Serializers
28
+ Serializers.serialize(argument)
29
+ end
30
+ end
31
+
32
+ def deserialize_argument(argument)
33
+ case argument
34
+ when String
35
+ argument
36
+ when *TYPE_WHITELIST
37
+ argument
38
+ when Array
39
+ argument.map { |arg| deserialize_argument(arg) }
40
+ when Hash
41
+ if serialized_global_id?(argument)
42
+ deserialize_global_id argument
43
+ elsif custom_serialized?(argument)
44
+ Serializers.deserialize(argument)
45
+ else
46
+ deserialize_hash(argument)
47
+ end
48
+ else
49
+ raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}"
50
+ end
51
+ end
52
+
53
+ def custom_serialized?(hash)
54
+ hash.key?(OBJECT_SERIALIZER_KEY)
55
+ end
56
+ end
57
+
58
+ # The <tt>ActiveJob::Serializers</tt> module is used to store a list of known serializers
59
+ # and to add new ones. It also has helpers to serialize/deserialize objects.
60
+ module Serializers # :nodoc:
61
+ # Base class for serializing and deserializing custom objects.
62
+ #
63
+ # Example:
64
+ #
65
+ # class MoneySerializer < ActiveJob::Serializers::ObjectSerializer
66
+ # def serialize(money)
67
+ # super("amount" => money.amount, "currency" => money.currency)
68
+ # end
69
+ #
70
+ # def deserialize(hash)
71
+ # Money.new(hash["amount"], hash["currency"])
72
+ # end
73
+ #
74
+ # private
75
+ #
76
+ # def klass
77
+ # Money
78
+ # end
79
+ # end
80
+ class ObjectSerializer
81
+ include Singleton
82
+
83
+ class << self
84
+ delegate :serialize?, :serialize, :deserialize, to: :instance
85
+ end
86
+
87
+ # Determines if an argument should be serialized by a serializer.
88
+ def serialize?(argument)
89
+ argument.is_a?(klass)
90
+ end
91
+
92
+ # Serializes an argument to a JSON primitive type.
93
+ def serialize(hash)
94
+ {Arguments::OBJECT_SERIALIZER_KEY => self.class.name}.merge!(hash)
95
+ end
96
+
97
+ # Deserializes an argument from a JSON primitive type.
98
+ def deserialize(_argument)
99
+ raise NotImplementedError
100
+ end
101
+
102
+ private
103
+
104
+ # The class of the object that will be serialized.
105
+ def klass
106
+ raise NotImplementedError
107
+ end
108
+ end
109
+
110
+ class DurationSerializer < ObjectSerializer # :nodoc:
111
+ def serialize(duration)
112
+ super("value" => duration.value, "parts" => Arguments.serialize(duration.parts.each_with_object({}) { |v, s| s[v.first.to_s] = v.last }))
113
+ end
114
+
115
+ def deserialize(hash)
116
+ value = hash["value"]
117
+ parts = Arguments.deserialize(hash["parts"])
118
+
119
+ klass.new(value, parts)
120
+ end
121
+
122
+ private
123
+
124
+ def klass
125
+ ActiveSupport::Duration
126
+ end
127
+ end
128
+
129
+ class SymbolSerializer < ObjectSerializer # :nodoc:
130
+ def serialize(argument)
131
+ super("value" => argument.to_s)
132
+ end
133
+
134
+ def deserialize(argument)
135
+ argument["value"].to_sym
136
+ end
137
+
138
+ private
139
+
140
+ def klass
141
+ Symbol
142
+ end
143
+ end
144
+
145
+ # -----------------------------
146
+
147
+ mattr_accessor :_additional_serializers
148
+ self._additional_serializers = Set.new
149
+
150
+ class << self
151
+ # Returns serialized representative of the passed object.
152
+ # Will look up through all known serializers.
153
+ # Raises <tt>ActiveJob::SerializationError</tt> if it can't find a proper serializer.
154
+ def serialize(argument)
155
+ serializer = serializers.detect { |s| s.serialize?(argument) }
156
+ raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
157
+ serializer.serialize(argument)
158
+ end
159
+
160
+ # Returns deserialized object.
161
+ # Will look up through all known serializers.
162
+ # If no serializer found will raise <tt>ArgumentError</tt>.
163
+ def deserialize(argument)
164
+ serializer_name = argument[Arguments::OBJECT_SERIALIZER_KEY]
165
+ raise ArgumentError, "Serializer name is not present in the argument: #{argument.inspect}" unless serializer_name
166
+
167
+ serializer = serializer_name.safe_constantize
168
+ raise ArgumentError, "Serializer #{serializer_name} is not known" unless serializer
169
+
170
+ serializer.deserialize(argument)
171
+ end
172
+
173
+ # Returns list of known serializers.
174
+ def serializers
175
+ self._additional_serializers # standard:disable Style/RedundantSelf
176
+ end
177
+
178
+ # Adds new serializers to a list of known serializers.
179
+ def add_serializers(*new_serializers)
180
+ self._additional_serializers += new_serializers.flatten
181
+ end
182
+ end
183
+
184
+ add_serializers DurationSerializer,
185
+ SymbolSerializer
186
+ # The full set of 6 serializers that Rails 6.0 normally adds here -- feel free to include any others if you wish:
187
+ # SymbolSerializer,
188
+ # DurationSerializer, # (The one that we've added above in order to support testing)
189
+ # DateTimeSerializer,
190
+ # DateSerializer,
191
+ # TimeWithZoneSerializer,
192
+ # TimeSerializer
193
+ end
194
+
195
+ # Is the updated version of perform_enqueued_jobs from Rails 6.0 missing from ActionJob's TestHelper?
196
+ unless TestHelper.private_instance_methods.include?(:flush_enqueued_jobs)
197
+ module TestHelper
198
+ def perform_enqueued_jobs(only: nil, except: nil, queue: nil)
199
+ return flush_enqueued_jobs(only: only, except: except, queue: queue) unless block_given?
200
+
201
+ super
202
+ end
203
+
204
+ private
205
+
206
+ def jobs_with(jobs, only: nil, except: nil, queue: nil)
207
+ validate_option(only: only, except: except)
208
+
209
+ jobs.count do |job|
210
+ job_class = job.fetch(:job)
211
+
212
+ if only
213
+ next false unless filter_as_proc(only).call(job)
214
+ elsif except
215
+ next false if filter_as_proc(except).call(job)
216
+ end
217
+
218
+ if queue
219
+ next false unless queue.to_s == job.fetch(:queue, job_class.queue_name)
220
+ end
221
+
222
+ yield job if block_given?
223
+
224
+ true
225
+ end
226
+ end
227
+
228
+ def enqueued_jobs_with(only: nil, except: nil, queue: nil, &block)
229
+ jobs_with(enqueued_jobs, only: only, except: except, queue: queue, &block)
230
+ end
231
+
232
+ def flush_enqueued_jobs(only: nil, except: nil, queue: nil)
233
+ enqueued_jobs_with(only: only, except: except, queue: queue) do |payload|
234
+ instantiate_job(payload).perform_now
235
+ queue_adapter.performed_jobs << payload
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,18 @@
1
+ # The following implements polyfills for Rails < 6.0
2
+ module ActionCable
3
+ # If the Rails 6.0 ActionCable::TestHelper is missing then allow it to autoload
4
+ unless ActionCable.const_defined? :TestHelper
5
+ autoload :TestHelper, "rails_6_polyfills/actioncable/test_helper.rb"
6
+ end
7
+ # If the Rails 6.0 test SubscriptionAdapter is missing then allow it to autoload
8
+ unless ActionCable::SubscriptionAdapter.const_defined? :Test
9
+ module SubscriptionAdapter
10
+ autoload :Test, "rails_6_polyfills/actioncable/test_adapter.rb"
11
+ end
12
+ end
13
+ end
14
+
15
+ # If the Rails 6.0 ActionJob Serializers are missing then load support for them
16
+ unless ActiveJob.const_defined?(:Serializers)
17
+ require "rails_6_polyfills/activejob/serializers"
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: noticed
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-26 00:00:00.000000000 Z
11
+ date: 2023-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 6.0.0
19
+ version: 5.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 6.0.0
26
+ version: 5.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: http
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,76 +38,6 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 4.0.0
41
- - !ruby/object:Gem::Dependency
42
- name: pg
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: standard
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: webmock
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: mysql2
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: sqlite3
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
41
  description: Database, browser, realtime ActionCable, Email, SMS, Slack notifications,
112
42
  and more for Rails apps
113
43
  email:
@@ -120,6 +50,10 @@ files:
120
50
  - README.md
121
51
  - Rakefile
122
52
  - lib/generators/noticed/delivery_method_generator.rb
53
+ - lib/generators/noticed/model/base_generator.rb
54
+ - lib/generators/noticed/model/mysql_generator.rb
55
+ - lib/generators/noticed/model/postgresql_generator.rb
56
+ - lib/generators/noticed/model/sqlite3_generator.rb
123
57
  - lib/generators/noticed/model_generator.rb
124
58
  - lib/generators/noticed/notification_generator.rb
125
59
  - lib/generators/noticed/templates/README
@@ -132,6 +66,8 @@ files:
132
66
  - lib/noticed/delivery_methods/base.rb
133
67
  - lib/noticed/delivery_methods/database.rb
134
68
  - lib/noticed/delivery_methods/email.rb
69
+ - lib/noticed/delivery_methods/fcm.rb
70
+ - lib/noticed/delivery_methods/ios.rb
135
71
  - lib/noticed/delivery_methods/microsoft_teams.rb
136
72
  - lib/noticed/delivery_methods/slack.rb
137
73
  - lib/noticed/delivery_methods/test.rb
@@ -144,6 +80,10 @@ files:
144
80
  - lib/noticed/text_coder.rb
145
81
  - lib/noticed/translation.rb
146
82
  - lib/noticed/version.rb
83
+ - lib/rails_6_polyfills/actioncable/test_adapter.rb
84
+ - lib/rails_6_polyfills/actioncable/test_helper.rb
85
+ - lib/rails_6_polyfills/activejob/serializers.rb
86
+ - lib/rails_6_polyfills/base.rb
147
87
  - lib/tasks/noticed_tasks.rake
148
88
  homepage: https://github.com/excid3/noticed
149
89
  licenses:
@@ -164,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
104
  - !ruby/object:Gem::Version
165
105
  version: '0'
166
106
  requirements: []
167
- rubygems_version: 3.2.3
107
+ rubygems_version: 3.4.12
168
108
  signing_key:
169
109
  specification_version: 4
170
110
  summary: Notifications for Ruby on Rails applications