Class: DiscoursePluginRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/discourse_plugin_registry.rb

Overview

A class that handles interaction between a plugin and the Discourse App.

Constant Summary collapse

JS_REGEX =
/\.js$|\.js\.erb$|\.js\.es6\z/
VENDORED_CORE_PRETTY_TEXT_MAP =
{
  "moment.js" => "vendor/assets/javascripts/moment.js",
  "moment-timezone.js" => "vendor/assets/javascripts/moment-timezone-with-data.js",
}
@@register_names =
Set.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.apply_modifier(name, arg, *more_args) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/discourse_plugin_registry.rb', line 268

def self.apply_modifier(name, arg, *more_args)
  return arg if !@modifiers

  registered_modifiers = @modifiers[name]
  return arg if !registered_modifiers

  # iterate as fast as possible to minimize cost (avoiding each)
  # also erases one stack frame
  length = registered_modifiers.length
  index = 0
  while index < length
    plugin_instance, block = registered_modifiers[index]
    arg = block.call(arg, *more_args) if plugin_instance.enabled?

    index += 1
  end

  arg
end

.build_html(name, ctx = nil) ⇒ Object



216
217
218
219
# File 'lib/discourse_plugin_registry.rb', line 216

def self.build_html(name, ctx = nil)
  builders = html_builders[name] || []
  builders.map { |b| b.call(ctx) }.join("\n").html_safe
end

.clear_modifiers!Object



243
244
245
246
247
248
# File 'lib/discourse_plugin_registry.rb', line 243

def self.clear_modifiers!
  if Rails.env.test? && GlobalSetting.load_plugins?
    raise "Clearing modifiers during a plugin spec run will affect all future specs. Use unregister_modifier instead."
  end
  @modifiers = nil
end

.core_asset_for_name(name) ⇒ Object

Raises:

  • (KeyError)


237
238
239
240
241
# File 'lib/discourse_plugin_registry.rb', line 237

def self.core_asset_for_name(name)
  asset = VENDORED_CORE_PRETTY_TEXT_MAP[name]
  raise KeyError, "Asset #{name} not found in #{VENDORED_CORE_PRETTY_TEXT_MAP}" unless asset
  asset
end

.define_filtered_register(register_name) ⇒ Object

Plugins often need to add values to a list, and we need to filter those lists at runtime to ignore values from disabled plugins. Unlike define_register, the type of the register cannot be defined, and is always Array.

Create a new register (see ‘define_register`) with some additions:

- Register is created in a class variable using the specified name/type
- Defines singleton method to access the register
- Defines instance method as a shortcut to the singleton method
- Automatically deletes the register on registry.reset!


40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/discourse_plugin_registry.rb', line 40

def self.define_filtered_register(register_name)
  return if respond_to?(register_name)
  define_register(register_name, Array)

  singleton_class.alias_method :"_raw_#{register_name}", :"#{register_name}"

  define_singleton_method(register_name) do
    public_send(:"_raw_#{register_name}").filter_map { |h| h[:value] if h[:plugin].enabled? }.uniq
  end

  define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
    public_send(:"_raw_#{register_name}") << { plugin: plugin, value: value }
  end
end

.define_register(register_name, type) ⇒ Object

Plugins often need to be able to register additional handlers, data, or classes that will be used by core classes. This should be used if you need to control which type the registry is, and if it doesn’t need to be removed if the plugin is disabled.

Shortcut to create new register in the plugin registry

- Register is created in a class variable using the specified name/type
- Defines singleton method to access the register
- Defines instance method as a shortcut to the singleton method
- Automatically deletes the register on registry.reset!


19
20
21
22
23
24
25
26
27
28
29
# File 'lib/discourse_plugin_registry.rb', line 19

def self.define_register(register_name, type)
  return if respond_to?(register_name)
  @@register_names << register_name

  define_singleton_method(register_name) do
    instance_variable_get(:"@#{register_name}") ||
      instance_variable_set(:"@#{register_name}", type.new)
  end

  define_method(register_name) { self.class.public_send(register_name) }
end

.register_asset(asset, opts = nil, plugin_directory_name = nil) ⇒ Object



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/discourse_plugin_registry.rb', line 167

def self.register_asset(asset, opts = nil, plugin_directory_name = nil)
  if asset =~ JS_REGEX
    if opts == :vendored_pretty_text
      self.vendored_pretty_text << asset
    elsif opts == :vendored_core_pretty_text
      self.vendored_core_pretty_text << asset
    else
      self.javascripts << asset
    end
  elsif asset =~ /\.css$|\.scss\z/
    if opts == :mobile
      self.mobile_stylesheets[plugin_directory_name] ||= Set.new
      self.mobile_stylesheets[plugin_directory_name] << asset
    elsif opts == :desktop
      self.desktop_stylesheets[plugin_directory_name] ||= Set.new
      self.desktop_stylesheets[plugin_directory_name] << asset
    elsif opts == :color_definitions
      self.color_definition_stylesheets[plugin_directory_name] = asset
    else
      self.stylesheets[plugin_directory_name] ||= Set.new
      self.stylesheets[plugin_directory_name] << asset
    end
  end
end

.register_auth_provider(auth_provider) ⇒ Object



131
132
133
# File 'lib/discourse_plugin_registry.rb', line 131

def self.register_auth_provider(auth_provider)
  self.auth_providers << auth_provider
end

.register_html_builder(name, &block) ⇒ Object



211
212
213
214
# File 'lib/discourse_plugin_registry.rb', line 211

def self.register_html_builder(name, &block)
  html_builders[name] ||= []
  html_builders[name] << block
end

.register_locale(locale, options = {}) ⇒ Object



157
158
159
# File 'lib/discourse_plugin_registry.rb', line 157

def self.register_locale(locale, options = {})
  self.locales[locale] = options
end

.register_mail_poller(mail_poller) ⇒ Object



135
136
137
# File 'lib/discourse_plugin_registry.rb', line 135

def self.register_mail_poller(mail_poller)
  self.mail_pollers << mail_poller
end

.register_modifier(plugin_instance, name, &blk) ⇒ Object



250
251
252
253
254
# File 'lib/discourse_plugin_registry.rb', line 250

def self.register_modifier(plugin_instance, name, &blk)
  @modifiers ||= {}
  modifiers = @modifiers[name] ||= []
  modifiers << [plugin_instance, blk]
end

.register_seed_data(key, value) ⇒ Object



203
204
205
# File 'lib/discourse_plugin_registry.rb', line 203

def self.register_seed_data(key, value)
  self.seed_data[key] = value
end

.register_seed_path_builder(&block) ⇒ Object



207
208
209
# File 'lib/discourse_plugin_registry.rb', line 207

def self.register_seed_path_builder(&block)
  seed_path_builders << block
end

.register_seedfu_filter(filter = nil) ⇒ Object



229
230
231
# File 'lib/discourse_plugin_registry.rb', line 229

def self.register_seedfu_filter(filter = nil)
  self.seedfu_filter << filter
end

.register_service_worker(filename, options = {}) ⇒ Object



144
145
146
# File 'lib/discourse_plugin_registry.rb', line 144

def self.register_service_worker(filename, options = {})
  self.service_workers << filename
end

.register_svg_icon(icon) ⇒ Object



148
149
150
# File 'lib/discourse_plugin_registry.rb', line 148

def self.register_svg_icon(icon)
  self.svg_icons << icon
end

.reset!Object



288
289
290
291
# File 'lib/discourse_plugin_registry.rb', line 288

def self.reset!
  @@register_names.each { |name| instance_variable_set(:"@#{name}", nil) }
  clear_modifiers!
end

.reset_register!(register_name) ⇒ Object



293
294
295
296
297
# File 'lib/discourse_plugin_registry.rb', line 293

def self.reset_register!(register_name)
  found_register = @@register_names.detect { |name| name == register_name }

  instance_variable_set(:"@#{found_register}", nil) if found_register
end

.seed_pathsObject



221
222
223
224
225
226
227
# File 'lib/discourse_plugin_registry.rb', line 221

def self.seed_paths
  result = SeedFu.fixture_paths.dup
  unless Rails.env.test? && ENV["LOAD_PLUGINS"] != "1"
    seed_path_builders.each { |b| result += b.call }
  end
  result.uniq
end

.stylesheets_exists?(plugin_directory_name, target = nil) ⇒ Boolean

Returns:

  • (Boolean)


192
193
194
195
196
197
198
199
200
201
# File 'lib/discourse_plugin_registry.rb', line 192

def self.stylesheets_exists?(plugin_directory_name, target = nil)
  case target
  when :desktop
    self.desktop_stylesheets[plugin_directory_name].present?
  when :mobile
    self.mobile_stylesheets[plugin_directory_name].present?
  else
    self.stylesheets[plugin_directory_name].present?
  end
end

.unregister_modifier(plugin_instance, name, &blk) ⇒ Object



256
257
258
259
260
261
262
263
264
265
266
# File 'lib/discourse_plugin_registry.rb', line 256

def self.unregister_modifier(plugin_instance, name, &blk)
  raise "unregister_modifier can only be used in tests" if !Rails.env.test?

  modifiers_for_name = @modifiers&.[](name)
  raise "no #{name} modifiers found" if !modifiers_for_name

  i = modifiers_for_name.find_index { |info| info == [plugin_instance, blk] }
  raise "no modifier found for that plugin/block combination" if !i

  modifiers_for_name.delete_at(i)
end

Instance Method Details

#register_archetype(name, options = {}) ⇒ Object



161
162
163
# File 'lib/discourse_plugin_registry.rb', line 161

def register_archetype(name, options = {})
  Archetype.register(name, options)
end

#register_css(filename, plugin_directory_name) ⇒ Object



152
153
154
155
# File 'lib/discourse_plugin_registry.rb', line 152

def register_css(filename, plugin_directory_name)
  self.class.stylesheets[plugin_directory_name] ||= Set.new
  self.class.stylesheets[plugin_directory_name] << filename
end

#register_js(filename, options = {}) ⇒ Object



139
140
141
142
# File 'lib/discourse_plugin_registry.rb', line 139

def register_js(filename, options = {})
  # If we have a server side option, add that too.
  self.class.javascripts << filename
end