Class: RedminePluginKit::Loader

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

Defined Under Namespace

Classes: ExistingControllerPatchForHelper

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(plugin_id:, debug: false) ⇒ Loader

Returns a new instance of Loader.



45
46
47
48
49
50
# File 'lib/redmine_plugin_kit/loader.rb', line 45

def initialize(plugin_id:, debug: false)
  self.plugin_id = plugin_id
  self.debug = debug

  apply_reset
end

Instance Attribute Details

#debugObject

Returns the value of attribute debug.



7
8
9
# File 'lib/redmine_plugin_kit/loader.rb', line 7

def debug
  @debug
end

#plugin_idObject

Returns the value of attribute plugin_id.



7
8
9
# File 'lib/redmine_plugin_kit/loader.rb', line 7

def plugin_id
  @plugin_id
end

Class Method Details

.after_initialize(&block) ⇒ Object



24
25
26
# File 'lib/redmine_plugin_kit/loader.rb', line 24

def after_initialize(&block)
  Rails.application.config.after_initialize(&block)
end

.persistingObject

same as in init.rb, but in future with more functionality - or for debugging



20
21
22
# File 'lib/redmine_plugin_kit/loader.rb', line 20

def persisting
  yield
end

.plugin_dir(plugin_id:) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/redmine_plugin_kit/loader.rb', line 36

def plugin_dir(plugin_id:)
  if Gem.loaded_specs[plugin_id].nil?
    File.join Redmine::Plugin.directory, plugin_id
  else
    Gem.loaded_specs[plugin_id].full_gem_path
  end
end

.redmine_database_ready?(with_table = nil) ⇒ Boolean

required multiple times because of this bug: https://www.redmine.org/issues/33290

Returns:

  • (Boolean)


29
30
31
32
33
34
# File 'lib/redmine_plugin_kit/loader.rb', line 29

def redmine_database_ready?(with_table = nil)
  ActiveRecord::Base.connection
  with_table.nil? || ActiveRecord::Base.connection.table_exists?(with_table)
rescue ActiveRecord::NoDatabaseError, ActiveRecord::ConnectionNotEstablished, ActiveRecord::StatementInvalid
  false
end

.to_prepareObject



10
11
12
13
14
15
16
17
# File 'lib/redmine_plugin_kit/loader.rb', line 10

def to_prepare(...)
  if Rails.version > '6.0'
    # INFO: https://www.redmine.org/issues/36245
    Rails.logger.info 'after_plugins_loaded hook should be used instead'
  else
    Rails.configuration.to_prepare(...)
  end
end

Instance Method Details

#add_global_helper(helper) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/redmine_plugin_kit/loader.rb', line 162

def add_global_helper(helper)
  if helper.is_a? Array
    @global_helpers += helper
  else
    @global_helpers << helper
  end
end

#add_helper(helper) ⇒ Object



154
155
156
157
158
159
160
# File 'lib/redmine_plugin_kit/loader.rb', line 154

def add_helper(helper)
  if helper.is_a? Array
    @helpers += helper
  else
    @helpers << helper
  end
end

#add_patch(patch) ⇒ Object



146
147
148
149
150
151
152
# File 'lib/redmine_plugin_kit/loader.rb', line 146

def add_patch(patch)
  if patch.is_a? Array
    @patches += patch
  else
    @patches << patch
  end
end

#apply!Object



170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/redmine_plugin_kit/loader.rb', line 170

def apply!
  validate_apply

  apply_patches!
  apply_helpers!
  apply_global_helpers!

  # reset patches and helpers
  apply_reset

  true
end

#apply_resetObject



70
71
72
73
74
# File 'lib/redmine_plugin_kit/loader.rb', line 70

def apply_reset
  @patches = []
  @helpers = []
  @global_helpers = []
end

#default_settingsObject



52
53
54
55
56
57
58
59
60
61
# File 'lib/redmine_plugin_kit/loader.rb', line 52

def default_settings
  cached_settings_name = "@default_settings_#{plugin_id}"
  cached_settings = instance_variable_get cached_settings_name
  if cached_settings.nil?
    data = yaml_config_load 'settings.yml', with_erb: true
    instance_variable_set cached_settings_name, data.symbolize_keys
  else
    cached_settings
  end
end

#incompatible?(plugins = []) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
# File 'lib/redmine_plugin_kit/loader.rb', line 120

def incompatible?(plugins = [])
  plugins.each do |plugin|
    raise "\n\033[31m#{plugin_id} plugin cannot be used with #{plugin} plugin.\033[0m" if Redmine::Plugin.installed? plugin
  end
end

#load_custom_field_format!(reverse: false) ⇒ Object



140
141
142
143
144
# File 'lib/redmine_plugin_kit/loader.rb', line 140

def load_custom_field_format!(reverse: false)
  require_files File.join('custom_field_formats', '**/*_format.rb'),
                reverse: reverse,
                ignore_autoload: true
end

#load_macros!Object



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

def load_macros!
  require_files File.join('wiki_macros', '**/*_macro.rb')
end

#load_model_hooks!Object



126
127
128
129
# File 'lib/redmine_plugin_kit/loader.rb', line 126

def load_model_hooks!
  target = plugin_id.camelize.constantize
  target::Hooks::ModelHook
end

#load_view_hooks!Object



131
132
133
134
# File 'lib/redmine_plugin_kit/loader.rb', line 131

def load_view_hooks!
  target = plugin_id.camelize.constantize
  target::Hooks::ViewHook
end

#plugin_dirObject



76
77
78
# File 'lib/redmine_plugin_kit/loader.rb', line 76

def plugin_dir
  @plugin_dir ||= self.class.plugin_dir plugin_id: plugin_id
end

#reload_on_prepare(file) ⇒ Object

Load the file again after every code reload.

The block keeps the order of the surrounding loop, which matters because formats may inherit from each other (CompanyFormat < ContactFormat) - a subclass loaded before its parent raises NameError.



116
117
118
# File 'lib/redmine_plugin_kit/loader.rb', line 116

def reload_on_prepare(file)
  ActiveSupport::Reloader.to_prepare { load file }
end

#require_files(spec, use_app: false, reverse: false, ignore_autoload: false) ⇒ Object

use_app: false => :plugin_dir/lib/:plugin_id directory



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/redmine_plugin_kit/loader.rb', line 81

def require_files(spec, use_app: false, reverse: false, ignore_autoload: false)
  dir = if use_app
          File.join plugin_dir, 'app', spec
        else
          File.join plugin_dir, 'lib', plugin_id, spec
        end

  files = Dir[dir].sort

  files.reverse! if reverse
  files.each do |f|
    if Rails.version > '6.0' && ignore_autoload
      Rails.autoloaders.main.ignore << f
      # Such a file registers itself in a registry that lives on a module
      # Zeitwerk rebuilds on every reload (Redmine::FieldFormat). The
      # registration is lost with the old module, and require would be a
      # no-op the second time round - the custom field then falls back to a
      # plain text field showing the raw id. Reloading the file restores it.
      #
      # NOTE: the require below stays as it is, so booting behaves exactly as
      # before and does not depend on when to_prepare runs. Loading the file
      # again in the first prepare run is harmless: these files only define a
      # class and register it under a fixed name.
      reload_on_prepare f
    end

    require f
  end
end

#yaml_config_load(yaml_file, with_erb: false) ⇒ Object



63
64
65
66
67
68
# File 'lib/redmine_plugin_kit/loader.rb', line 63

def yaml_config_load(yaml_file, with_erb: false)
  file_to_load = File.read File.join(plugin_dir, 'config', yaml_file)
  file_to_load = ERB.new(file_to_load).result if with_erb

  YAML.safe_load(file_to_load) || {}
end