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/
HANDLEBARS_REGEX =
/\.(hb[rs]|js\.handlebars)\z/
VENDORED_CORE_PRETTY_TEXT_MAP =
{
  "moment.js" => "vendor/assets/javascripts/moment.js",
  "moment-timezone.js" => "vendor/assets/javascripts/moment-timezone-with-data.js",
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

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



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/discourse_plugin_registry.rb', line 281

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



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

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



256
257
258
259
260
261
# File 'lib/discourse_plugin_registry.rb', line 256

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)


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

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!


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

def self.define_filtered_register(register_name)
  define_register(register_name, Array)

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

  define_singleton_method(register_name) do
    unfiltered = public_send(:"_raw_#{register_name}")
    unfiltered.filter { |v| v[:plugin].enabled? }.map { |v| v[:value] }.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!


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

def self.define_register(register_name, type)
  @@register_names ||= Set.new
  @@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

.each_globbed_asset(each_options = nil) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/discourse_plugin_registry.rb', line 157

def self.each_globbed_asset(each_options = nil)
  each_options ||= {}

  self.asset_globs.each do |g|
    root, ext, options = *g

    if options[:admin]
      next unless each_options[:admin]
    else
      next if each_options[:admin]
    end

    Dir.glob("#{root}/**/*.#{ext}") { |f| yield f }
  end
end

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



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/discourse_plugin_registry.rb', line 176

def self.register_asset(asset, opts = nil, plugin_directory_name = nil)
  if asset =~ JS_REGEX
    if opts == :admin
      self.admin_javascripts << asset
    elsif 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
  elsif asset =~ HANDLEBARS_REGEX
    self.handlebars << asset
  end
end

.register_auth_provider(auth_provider) ⇒ Object



119
120
121
# File 'lib/discourse_plugin_registry.rb', line 119

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

.register_glob(root, extension, options = nil) ⇒ Object



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

def self.register_glob(root, extension, options = nil)
  self.asset_globs << [root, extension, options || {}]
end

.register_html_builder(name, &block) ⇒ Object



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

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

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



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

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

.register_mail_poller(mail_poller) ⇒ Object



123
124
125
# File 'lib/discourse_plugin_registry.rb', line 123

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

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



263
264
265
266
267
# File 'lib/discourse_plugin_registry.rb', line 263

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

.register_seed_data(key, value) ⇒ Object



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

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

.register_seed_path_builder(&block) ⇒ Object



220
221
222
# File 'lib/discourse_plugin_registry.rb', line 220

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

.register_seedfu_filter(filter = nil) ⇒ Object



242
243
244
# File 'lib/discourse_plugin_registry.rb', line 242

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

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



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

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

.register_svg_icon(icon) ⇒ Object



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

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

.reset!Object



301
302
303
304
# File 'lib/discourse_plugin_registry.rb', line 301

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

.reset_register!(register_name) ⇒ Object



306
307
308
309
310
# File 'lib/discourse_plugin_registry.rb', line 306

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



234
235
236
237
238
239
240
# File 'lib/discourse_plugin_registry.rb', line 234

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)


205
206
207
208
209
210
211
212
213
214
# File 'lib/discourse_plugin_registry.rb', line 205

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



269
270
271
272
273
274
275
276
277
278
279
# File 'lib/discourse_plugin_registry.rb', line 269

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



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

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

#register_css(filename, plugin_directory_name) ⇒ Object



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

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



127
128
129
130
# File 'lib/discourse_plugin_registry.rb', line 127

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