Module: OpenProject::Plugins::ActsAsOpEngine

Defined in:
lib/open_project/plugins/acts_as_op_engine.rb

Class Method Summary collapse

Class Method Details

.included(base) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/open_project/plugins/acts_as_op_engine.rb', line 18

def self.included(base)
  base.send(:define_method, :name) do
    ActiveSupport::Inflector.demodulize(base).downcase
  end

  # Don't use the PatchRegistry for now, as the core classes doesn't notify of class loading
  # Use the old config.to_prepare method, but we can hopefully someday switch to on-demand
  # patching once the PatchRegistry works.

  # base.send(:define_method, :patch) do |target, patch|
  #   OpenProject::Plugins::PatchRegistry.register(target, patch)
  # end

  # Disable LoadDependency for the same reason
  # base.send(:define_method, :load_dependent) do |target, *dependencies|
  #   OpenProject::Plugins::LoadDependency.register(target, *dependencies)
  # end

  # Patch classes
  #
  # Looks for patches via autoloading in
  # <plugin root>/lib/openproject/<plugin name>/patches/<patched_class>_patch.rb
  # Make sure the patch module has the name the Rails autoloading expects.
  #
  # Example:
  #  patches [:IssuesController]
  # This looks for OpenProject::XlsExport::Patches::IssuesControllerPatch
  #  in openproject/xls_export/patches/issues_controller_patch.rb
  base.send(:define_method, :patches) do |patched_classes|
    plugin_name = engine_name
    base.config.to_prepare do
      patched_classes.each do |klass_name|
        plugin_module = plugin_name.sub(/^openproject_/, '').camelcase
        patch = "OpenProject::#{plugin_module}::Patches::#{klass_name.to_s}Patch".constantize
        klass = klass_name.to_s.constantize
        klass.send(:include, patch) unless klass.included_modules.include?(patch)
      end
    end
  end

  # Define assets provided by the plugin
  base.send(:define_method, :assets) do |assets|
    base.initializer '#{engine_name}.precompile_assets' do |app|
      app.config.assets.precompile += assets.to_a
    end
  end

  # Register a plugin with OpenProject
  #
  # Uses Gem specification for plugin name, author etc.
  #
  # gem_name:      The gem name, used for querying the gem for metadata like author
  # options:       An options Hash, at least :requires_openproject is recommended to
  #                define the minimal version of OpenProject the plugin is compatible with
  #                Another common option is :author_url.
  base.send(:define_method, :register) do |gem_name, options|
    base.initializer "#{engine_name}.register_plugin" do
      spec = Bundler.environment.specs[gem_name][0]

      Redmine::Plugin.register engine_name.to_sym do
        name spec.summary
        author spec.authors.kind_of?(Array) ? spec.authors[0] : spec.authors
        description spec.description
        version spec.version
        url spec.homepage

        options.each do |name, value|
          send(name, value)
        end
      end
    end

    # Workaround to ensure settings are available after unloading in development mode
    plugin_name = engine_name
    if options.include? :settings
      base.class_eval do
        config.to_prepare do
          Setting.create_setting("plugin_#{plugin_name}",
                                 { 'serialized' => true }.merge(options[:settings]))
          Setting.create_setting_accessors("plugin_#{plugin_name}")
        end
      end
    end
  end

  base.class_eval do
    config.autoload_paths += Dir["#{config.root}/lib/"]

    config.before_configuration do |app|
      # This is required for the routes to be loaded first
      # as the routes should be prepended so they take precedence over the core.
      app.config.paths['config/routes'].unshift File.join(config.root, "config", "routes.rb")
    end

    initializer "#{engine_name}.remove_duplicate_routes", :after => "add_routing_paths" do |app|
      # removes duplicate entry from app.routes_reloader
      # As we prepend the plugin's routes to the load_path up front and rails
      # adds all engines' config/routes.rb later, we have double loaded the routes
      # This is not harmful as such but leads to duplicate routes which decreases performance
      app.routes_reloader.paths.uniq!
    end

    initializer "#{engine_name}.register_test_paths" do |app|
      app.config.plugins_to_test_paths << self.root
    end

    # adds our factories to factory girl's load path
    initializer "#{engine_name}.register_factories", :after => "factory_girl.set_factory_paths" do |app|
      FactoryGirl.definition_file_paths << File.expand_path(self.root.to_s + '/spec/factories') if defined?(FactoryGirl)
    end
  end
end