inform-runtime 1.0.4
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 +7 -0
- data/LICENSE +623 -0
- data/README.md +185 -0
- data/Rakefile +65 -0
- data/config/database.yml +37 -0
- data/exe/inform.rb +6 -0
- data/game/config.yml +5 -0
- data/game/example.inf +76 -0
- data/game/example.rb +90 -0
- data/game/forms/example_form.rb +2 -0
- data/game/grammar/game_grammar.inf.rb +11 -0
- data/game/languages/english.rb +2 -0
- data/game/models/example_model.rb +2 -0
- data/game/modules/example_module.rb +9 -0
- data/game/rules/example_state.rb +2 -0
- data/game/scripts/example_script.rb +2 -0
- data/game/topics/example_topic.rb +2 -0
- data/game/verbs/game_verbs.rb +15 -0
- data/game/verbs/metaverbs.rb +2028 -0
- data/lib/runtime/articles.rb +138 -0
- data/lib/runtime/builtins.rb +359 -0
- data/lib/runtime/color.rb +145 -0
- data/lib/runtime/command.rb +470 -0
- data/lib/runtime/config.rb +48 -0
- data/lib/runtime/context.rb +78 -0
- data/lib/runtime/daemon.rb +266 -0
- data/lib/runtime/database.rb +500 -0
- data/lib/runtime/events.rb +771 -0
- data/lib/runtime/experimental/handler_dsl.rb +175 -0
- data/lib/runtime/game.rb +74 -0
- data/lib/runtime/game_loader.rb +132 -0
- data/lib/runtime/grammar_parser.rb +553 -0
- data/lib/runtime/helpers.rb +177 -0
- data/lib/runtime/history.rb +45 -0
- data/lib/runtime/inflector.rb +195 -0
- data/lib/runtime/io.rb +174 -0
- data/lib/runtime/kernel.rb +450 -0
- data/lib/runtime/library.rb +59 -0
- data/lib/runtime/library_loader.rb +135 -0
- data/lib/runtime/link.rb +158 -0
- data/lib/runtime/logging.rb +197 -0
- data/lib/runtime/mixins.rb +570 -0
- data/lib/runtime/module.rb +202 -0
- data/lib/runtime/object.rb +761 -0
- data/lib/runtime/options.rb +104 -0
- data/lib/runtime/persistence.rb +292 -0
- data/lib/runtime/plurals.rb +60 -0
- data/lib/runtime/prototype.rb +307 -0
- data/lib/runtime/publication.rb +92 -0
- data/lib/runtime/runtime.rb +321 -0
- data/lib/runtime/session.rb +202 -0
- data/lib/runtime/stdlib.rb +604 -0
- data/lib/runtime/subscription.rb +47 -0
- data/lib/runtime/tag.rb +287 -0
- data/lib/runtime/tree.rb +204 -0
- data/lib/runtime/version.rb +24 -0
- data/lib/runtime/world_tree.rb +69 -0
- data/lib/runtime.rb +35 -0
- metadata +199 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU General Public License
|
|
19
|
+
# along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
# The Inform module
|
|
22
|
+
module Inform
|
|
23
|
+
# The Inform::Prototypical module
|
|
24
|
+
module Prototypical
|
|
25
|
+
def context_event
|
|
26
|
+
Thread.current[:event]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def instance_variables_map
|
|
30
|
+
instance_variables.each_with_object({}) do |key, memo|
|
|
31
|
+
memo[key] = instance_variable_get(key)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def values
|
|
36
|
+
super || instance_variables_map
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
log.warn "Unexpected error invoking super(Inform::Prototypical#values): #{e.message}"
|
|
39
|
+
instance_variables_map
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def string?(key)
|
|
43
|
+
v = self.&key
|
|
44
|
+
return false if v.nil?
|
|
45
|
+
v.respond_to?(:to_s) && !v.to_s.empty?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
MethodWriterTemplate = '%<method_name>s='.freeze
|
|
49
|
+
|
|
50
|
+
# This method tries to access or write values given by *args
|
|
51
|
+
# to the property using an accessor or writer method, and
|
|
52
|
+
# failing that, will invoke the prototype method, which
|
|
53
|
+
# dynamically defines an accessor or writer method on the
|
|
54
|
+
# receiver for future ease of access.
|
|
55
|
+
# rubocop: disable Metrics/AbcSize
|
|
56
|
+
# rubocop: disable Metrics/BlockNesting
|
|
57
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
58
|
+
# rubocop: disable Metrics/MethodLength
|
|
59
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
60
|
+
def &(property, *args)
|
|
61
|
+
return nil if property.nil?
|
|
62
|
+
return super unless property.is_a?(Symbol) || property.is_a?(String)
|
|
63
|
+
return nil if property.respond_to?(:empty?) && property.empty?
|
|
64
|
+
property, sub_property = property.to_s.split('.').map(&:to_sym)
|
|
65
|
+
if !args.empty?
|
|
66
|
+
setter = format(MethodWriterTemplate, method_name: property)
|
|
67
|
+
if !sub_property.nil?
|
|
68
|
+
value = self.send(property)
|
|
69
|
+
if value.object?
|
|
70
|
+
value.&(sub_property, *args)
|
|
71
|
+
elsif value.respond_to?(:key?)
|
|
72
|
+
value[sub_property] = (args.length > 1 ? args : args.first)
|
|
73
|
+
self.send(setter, value)
|
|
74
|
+
else
|
|
75
|
+
self.send(setter, *args)
|
|
76
|
+
end
|
|
77
|
+
elsif self.respond_to?(property) && args.length == self.method(property).arity
|
|
78
|
+
self.send(property, *args)
|
|
79
|
+
elsif self.respond_to?(setter) && args.length == self.method(setter).arity
|
|
80
|
+
self.send(setter, *args)
|
|
81
|
+
elsif !Kernel.methods.include?(property)
|
|
82
|
+
self.send(property, *args)
|
|
83
|
+
else
|
|
84
|
+
self.prototype(property, *args)
|
|
85
|
+
end
|
|
86
|
+
elsif !sub_property.nil?
|
|
87
|
+
value = self.send(property)
|
|
88
|
+
if value.object?
|
|
89
|
+
value.&(sub_property, *args)
|
|
90
|
+
elsif value.respond_to?(property)
|
|
91
|
+
value.send(property)
|
|
92
|
+
elsif value.respond_to?(:key?)
|
|
93
|
+
value[sub_property]
|
|
94
|
+
else
|
|
95
|
+
value
|
|
96
|
+
end
|
|
97
|
+
elsif self.respond_to?(property)
|
|
98
|
+
self.send(property)
|
|
99
|
+
elsif (self.properties.respond_to?(:key?) && self.properties.key?(property)) ||
|
|
100
|
+
(self.respond_to?(:_key?) && self._key?(property))
|
|
101
|
+
self.prototype(property)
|
|
102
|
+
else
|
|
103
|
+
return nil
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
# rubocop: enable Metrics/AbcSize
|
|
107
|
+
# rubocop: enable Metrics/BlockNesting
|
|
108
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
109
|
+
# rubocop: enable Metrics/MethodLength
|
|
110
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
111
|
+
|
|
112
|
+
# This method attempts to get a value if it exists.
|
|
113
|
+
# If no value is already set on the receiver, any given
|
|
114
|
+
# arguments will be set on the receiver for future access.
|
|
115
|
+
def |(property, *args)
|
|
116
|
+
return nil if property.nil?
|
|
117
|
+
return super unless property.respond_to?(:to_s)
|
|
118
|
+
return nil if property.to_s.empty?
|
|
119
|
+
v = self.&property
|
|
120
|
+
v || send(property, *args)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
VariableTemplate = '@%<property>s'.freeze
|
|
124
|
+
MethodBooleanOrBangPattern = %r{([\?!]+)$}.freeze
|
|
125
|
+
MethodWriterPattern = %r{=$}.freeze
|
|
126
|
+
LinkPattern = %r{.+_to$}.freeze
|
|
127
|
+
|
|
128
|
+
# rubocop: disable Metrics/AbcSize
|
|
129
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
130
|
+
# rubocop: disable Metrics/MethodLength
|
|
131
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
132
|
+
# rubocop: disable Style/MissingRespondToMissing
|
|
133
|
+
def method_missing(method, *args, &block)
|
|
134
|
+
return super if method == :to_ary
|
|
135
|
+
m = method.to_s
|
|
136
|
+
return super if MethodBooleanOrBangPattern.match?(m)
|
|
137
|
+
mname = MethodWriterPattern.match?(m) ? m.chop : m
|
|
138
|
+
property = mname.to_sym
|
|
139
|
+
variable = format(VariableTemplate, property: property).to_sym
|
|
140
|
+
event = context_event
|
|
141
|
+
|
|
142
|
+
if MethodWriterPattern.match?(m) || (LinkPattern.match?(m) && !args.empty?)
|
|
143
|
+
if !event.nil? && Inform::Runtime.invocation_properties.include?(property)
|
|
144
|
+
event.send(method, *args, &block)
|
|
145
|
+
elsif inflib&.library_method?(method)
|
|
146
|
+
inflib.send(method, *args, &block)
|
|
147
|
+
else
|
|
148
|
+
self.prototype(method, *args, &block)
|
|
149
|
+
end
|
|
150
|
+
elsif !event.nil? && Inform::Runtime.invocation_properties.include?(property)
|
|
151
|
+
result = event.send(method, *args, &block)
|
|
152
|
+
log.debug("Value for event #{event}.#{method} is: #{result || 'nil'}") if defined? DEBUG
|
|
153
|
+
result
|
|
154
|
+
elsif inflib&.library_method?(method)
|
|
155
|
+
inflib.send(method, *args, &block)
|
|
156
|
+
elsif inflib.respond_to?(method) && Inform::Runtime.invocation_properties.include?(property)
|
|
157
|
+
inflib.send(method, *args, &block)
|
|
158
|
+
elsif inflib&.instance_variable_get(variable) || inflib&.instance_variables&.include?(variable)
|
|
159
|
+
inflib.instance_variable_get(variable)
|
|
160
|
+
elsif (properties.respond_to?(:key?) && properties.key?(property)) ||
|
|
161
|
+
(respond_to?(:_key?) && _key?(property)) ||
|
|
162
|
+
!args.empty?
|
|
163
|
+
self.prototype(method, *args, &block)
|
|
164
|
+
else
|
|
165
|
+
super
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
# rubocop: enable Metrics/AbcSize
|
|
169
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
170
|
+
# rubocop: enable Metrics/MethodLength
|
|
171
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
172
|
+
# rubocop: enable Style/MissingRespondToMissing
|
|
173
|
+
|
|
174
|
+
# def respond_to_missing?(method, include_all=false)
|
|
175
|
+
# m = method.to_s
|
|
176
|
+
# return false if m =~ /\?$/
|
|
177
|
+
# mname = m =~ /\=$/ ? m.chop : m
|
|
178
|
+
# property = mname.intern
|
|
179
|
+
# Inform::Runtime.invocation_properties.include? property
|
|
180
|
+
# end
|
|
181
|
+
|
|
182
|
+
def accessor_and_writer(key)
|
|
183
|
+
return [key.to_s.chop, key] if MethodWriterPattern.match?(key)
|
|
184
|
+
[key, format(MethodWriterTemplate, method_name: key)]
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
AccessorMethodTemplate = %(
|
|
188
|
+
def %<accessor>s(*args)
|
|
189
|
+
args.empty? ? self._get(__method__) : self._set(__method__, *args)
|
|
190
|
+
end
|
|
191
|
+
).freeze
|
|
192
|
+
|
|
193
|
+
WriterMethodTemplate = %(
|
|
194
|
+
def %<writer>s(value)
|
|
195
|
+
self._assign(__method__.to_s.chop.to_sym, value)
|
|
196
|
+
end
|
|
197
|
+
).freeze
|
|
198
|
+
|
|
199
|
+
# rubocop: disable Metrics/AbcSize
|
|
200
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
201
|
+
# rubocop: disable Metrics/MethodLength
|
|
202
|
+
def prototype(key, *args, &block)
|
|
203
|
+
ensure_properties_attribute!
|
|
204
|
+
accessor, writer = accessor_and_writer(key)
|
|
205
|
+
if key_refers_to_link?(key)
|
|
206
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
207
|
+
if args.empty? && self.properties.key?(key)
|
|
208
|
+
return if (to_obj = get_constant(self.properties[key])).nil? || !to_obj.object?
|
|
209
|
+
self.link(key, to_obj)
|
|
210
|
+
self.properties.delete(key)
|
|
211
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
212
|
+
return to_obj
|
|
213
|
+
end
|
|
214
|
+
self.properties[key] = args.first
|
|
215
|
+
end
|
|
216
|
+
accessor = format(AccessorMethodTemplate, accessor: accessor)
|
|
217
|
+
self.instance_eval(accessor, __FILE__, __LINE__)
|
|
218
|
+
writer = format(WriterMethodTemplate, writer: writer)
|
|
219
|
+
self.instance_eval(writer, __FILE__, __LINE__)
|
|
220
|
+
self.send(key, *args, &block)
|
|
221
|
+
end
|
|
222
|
+
# rubocop: enable Metrics/AbcSize
|
|
223
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
224
|
+
# rubocop: enable Metrics/MethodLength
|
|
225
|
+
|
|
226
|
+
MISSING_PROPERTIES_MESSAGE = 'Missing properties attribute for: ' \
|
|
227
|
+
'%<identity>s'.freeze
|
|
228
|
+
|
|
229
|
+
def ensure_properties_attribute!
|
|
230
|
+
return unless self.properties.nil?
|
|
231
|
+
raise StandardError, format(MISSING_PROPERTIES_MESSAGE, identity: self.identity)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def key_refers_to_link?(key)
|
|
235
|
+
Inform::Library::DeclaredProperties.memo.key?(key) && LinkPattern.match?(key.to_s)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def _get(key)
|
|
239
|
+
result = nil
|
|
240
|
+
result = self._get_object(key) if self.respond_to?(:_key?) && self._key?(key)
|
|
241
|
+
result || self.properties.dup[key]
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# rubocop: disable Metrics/AbcSize
|
|
245
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
246
|
+
# rubocop: disable Metrics/MethodLength
|
|
247
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
248
|
+
def _set(key, *values)
|
|
249
|
+
raise "The key parameter must be a symbol" unless key.is_a? Symbol
|
|
250
|
+
raise "The values parameter may not be empty" if values.empty?
|
|
251
|
+
result = nil
|
|
252
|
+
if values.first.object?
|
|
253
|
+
result = self._set_object(key, values.first) if respond_to? :_set_object
|
|
254
|
+
elsif values.first.nil? && self.respond_to?(:_key?) && self._key?(key)
|
|
255
|
+
result = self._unset_object(key) if self.respond_to?(:_unset_object)
|
|
256
|
+
elsif values.first.nil?
|
|
257
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
258
|
+
self.properties.delete(key)
|
|
259
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
260
|
+
elsif values.length > 1
|
|
261
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
262
|
+
self.properties[key] = []
|
|
263
|
+
self.properties[key].concat(values)
|
|
264
|
+
values.clear
|
|
265
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
266
|
+
else
|
|
267
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
268
|
+
self.properties[key] = values.first
|
|
269
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
270
|
+
end
|
|
271
|
+
result || self.properties.dup[key]
|
|
272
|
+
end
|
|
273
|
+
# rubocop: enable Metrics/AbcSize
|
|
274
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
275
|
+
# rubocop: enable Metrics/MethodLength
|
|
276
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
277
|
+
|
|
278
|
+
# rubocop: disable Metrics/AbcSize
|
|
279
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
280
|
+
# rubocop: disable Metrics/MethodLength
|
|
281
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
282
|
+
def _assign(key, value)
|
|
283
|
+
raise "The key parameter must be a symbol" unless key.is_a? Symbol
|
|
284
|
+
result = nil
|
|
285
|
+
if value.object?
|
|
286
|
+
result = self._set_object(key, value) if self.respond_to?(:_set_object)
|
|
287
|
+
elsif value.nil? && self.respond_to?(:_key?) && self._key?(key)
|
|
288
|
+
result = self._unset_object(key) if self.respond_to?(:_unset_object)
|
|
289
|
+
elsif value.nil? && self.properties.key?(key)
|
|
290
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
291
|
+
self.properties.delete(key)
|
|
292
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
293
|
+
else
|
|
294
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
295
|
+
self.properties[key] = value
|
|
296
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
297
|
+
end
|
|
298
|
+
result || self.properties.dup[key]
|
|
299
|
+
end
|
|
300
|
+
# rubocop: enable Metrics/AbcSize
|
|
301
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
302
|
+
# rubocop: enable Metrics/MethodLength
|
|
303
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
304
|
+
end
|
|
305
|
+
# module Prototypical
|
|
306
|
+
end
|
|
307
|
+
# module Inform
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU General Public License
|
|
19
|
+
# along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
require_relative 'subscription'
|
|
22
|
+
|
|
23
|
+
# The Inform module
|
|
24
|
+
module Inform
|
|
25
|
+
# The Publisher module to implement rudimentary pub-sub functionality
|
|
26
|
+
module Publisher
|
|
27
|
+
include Inform::Subscribers
|
|
28
|
+
|
|
29
|
+
def muted?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# rubocop: disable Metrics/AbcSize
|
|
34
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
35
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
36
|
+
def subscribers
|
|
37
|
+
safe_refresh if respond_to?(:safe_refresh)
|
|
38
|
+
root_obj = attempt_twice { root } if self.respond_to?(:root) # TODO: FIXME
|
|
39
|
+
return explicit_subscribers.dup if root_obj.nil?
|
|
40
|
+
eavesdroppers = (root_obj&.safe_refresh&.branch || []) - [self]
|
|
41
|
+
# explicit_subscribers + (eavesdroppers & Session.players) # TODO: FIXME
|
|
42
|
+
players = defined?(Session) ? Session.players.dup : []
|
|
43
|
+
explicit_subscribers + eavesdroppers.each_with_object([]) do |o1, memo|
|
|
44
|
+
memo.concat(players.select { |o2| o1 == o2 })
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
# rubocop: enable Metrics/AbcSize
|
|
48
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
49
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
50
|
+
|
|
51
|
+
def publish_only(message, *args, &condition)
|
|
52
|
+
return if muted?
|
|
53
|
+
(subscribers & args.flatten).each do |subscriber|
|
|
54
|
+
next if block_given? && !condition.call(subscriber)
|
|
55
|
+
subscriber.update(message)
|
|
56
|
+
end
|
|
57
|
+
false
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def publish_except(message, *args, &condition)
|
|
61
|
+
return if muted?
|
|
62
|
+
(subscribers - args.flatten).each do |subscriber|
|
|
63
|
+
next if block_given? && !condition.call(subscriber)
|
|
64
|
+
log.warn "publishing message (#{message}) to subscriber: #{subscriber}"
|
|
65
|
+
subscriber.update(message)
|
|
66
|
+
end
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# For system messages (to the InformLibrary, mainly)
|
|
71
|
+
def publish_system_message(message, *args, &condition)
|
|
72
|
+
subscribers.each do |subscriber|
|
|
73
|
+
next if block_given? && !condition.call(subscriber, *args)
|
|
74
|
+
subscriber.send(message, *args) if subscriber.respond_to?(message)
|
|
75
|
+
end
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def publish(message, *args, &condition)
|
|
80
|
+
return publish_system_message(message, *args, &condition) if message.is_a?(Symbol)
|
|
81
|
+
return if muted?
|
|
82
|
+
subscribers.each do |subscriber|
|
|
83
|
+
next if block_given? && !condition.call(subscriber)
|
|
84
|
+
# log.info "#{subscriber.name}#update message: #{message.inspect}"
|
|
85
|
+
subscriber.update(message, *args)
|
|
86
|
+
end
|
|
87
|
+
false
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
# module Publisher
|
|
91
|
+
end
|
|
92
|
+
# module Inform
|