1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
require 'active_support'
require File.join(File.dirname(__FILE__), 'engines/plugin')
require File.join(File.dirname(__FILE__), 'engines/plugin/list')
require File.join(File.dirname(__FILE__), 'engines/plugin/loader')
require File.join(File.dirname(__FILE__), 'engines/plugin/locator')
require File.join(File.dirname(__FILE__), 'engines/assets')
require File.join(File.dirname(__FILE__), 'engines/rails_extensions/rails')
# == Parameters
#
# The Engines module has a number of public configuration parameters:
#
# [+public_directory+] The directory into which plugin assets should be
# mirrored. Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.
# [+schema_info_table+] The table to use when storing plugin migration
# version information. Defaults to +plugin_schema_info+.
#
# Additionally, there are a few flags which control the behaviour of
# some of the features the engines plugin adds to Rails:
#
# [+disable_application_view_loading+] A boolean flag determining whether
# or not views should be loaded from
# the main <tt>app/views</tt> directory.
# Defaults to false; probably only
# useful when testing your plugin.
# [+disable_application_code_loading+] A boolean flag determining whether
# or not to load controllers/helpers
# from the main +app+ directory,
# if corresponding code exists within
# a plugin. Defaults to false; again,
# probably only useful when testing
# your plugin.
# [+disable_code_mixing+] A boolean flag indicating whether all plugin
# copies of a particular controller/helper should
# be loaded and allowed to override each other,
# or if the first matching file should be loaded
# instead. Defaults to false.
#
module Engines
# The set of all loaded plugins
mattr_accessor :plugins
self.plugins = Engines::Plugin::List.new
# List of extensions to load, can be changed in init.rb before calling Engines.init
mattr_accessor :rails_extensions
self.rails_extensions = %w(action_mailer asset_helpers routing migrations dependencies)
# The name of the public directory to mirror public engine assets into.
# Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.
mattr_accessor :public_directory
self.public_directory = File.join(RAILS_ROOT, 'public', 'plugin_assets')
# The table in which to store plugin schema information. Defaults to
# "plugin_schema_info".
mattr_accessor :schema_info_table
self.schema_info_table = "plugin_schema_info"
#--
# These attributes control the behaviour of the engines extensions
#++
# Set this to true if views should *only* be loaded from plugins
mattr_accessor :disable_application_view_loading
self.disable_application_view_loading = false
# Set this to true if controller/helper code shouldn't be loaded
# from the application
mattr_accessor :disable_application_code_loading
self.disable_application_code_loading = false
# Set this ti true if code should not be mixed (i.e. it will be loaded
# from the first valid path on $LOAD_PATH)
mattr_accessor :disable_code_mixing
self.disable_code_mixing = false
# This is used to determine which files are candidates for the "code
# mixing" feature that the engines plugin provides, where classes from
# plugins can be loaded, and then code from the application loaded
# on top of that code to override certain methods.
mattr_accessor :code_mixing_file_types
self.code_mixing_file_types = %w(controller helper)
class << self
def init
load_extensions
Engines::Assets.initialize_base_public_directory
end
def logger
RAILS_DEFAULT_LOGGER
end
def load_extensions
rails_extensions.each { |name| require "engines/rails_extensions/#{name}" }
# load the testing extensions, if we are in the test environment.
require "engines/testing" if RAILS_ENV == "test"
end
def select_existing_paths(paths)
paths.select { |path| File.directory?(path) }
end
# The engines plugin will, by default, mix code from controllers and helpers,
# allowing application code to override specific methods in the corresponding
# controller or helper classes and modules. However, if other file types should
# also be mixed like this, they can be added by calling this method. For example,
# if you want to include "things" within your plugin and override them from
# your applications, you should use the following layout:
#
# app/
# +-- things/
# | +-- one_thing.rb
# | +-- another_thing.rb
# ...
# vendor/
# +-- plugins/
# +-- my_plugin/
# +-- app/
# +-- things/
# +-- one_thing.rb
# +-- another_thing.rb
#
# The important point here is that your "things" are named <whatever>_thing.rb,
# and that they are placed within plugin/app/things (the pluralized form of 'thing').
#
# It's important to note that you'll also want to ensure that the "things" are
# on your load path in your plugin's init.rb:
#
# Rails.plugins[:my_plugin].code_paths << "app/things"
#
def mix_code_from(*types)
self.code_mixing_file_types += types.map { |x| x.to_s.singularize }
end
# A general purpose method to mirror a directory (+source+) into a destination
# directory, including all files and subdirectories. Files will not be mirrored
# if they are identical already (checked via FileUtils#identical?).
def mirror_files_from(source, destination)
return unless File.directory?(source)
# TODO: use Rake::FileList#pathmap?
source_files = Dir[source + "/**/*"]
source_dirs = source_files.select { |d| File.directory?(d) }
source_files -= source_dirs
source_dirs.each do |dir|
# strip down these paths so we have simple, relative paths we can
# add to the destination
target_dir = File.join(destination, dir.gsub(source, ''))
begin
FileUtils.mkdir_p(target_dir)
rescue Exception => e
raise "Could not create directory #{target_dir}: \n" + e
end
end
source_files.each do |file|
begin
target = File.join(destination, file.gsub(source, ''))
unless File.exist?(target) && FileUtils.identical?(file, target)
FileUtils.cp(file, target)
end
rescue Exception => e
raise "Could not copy #{file} to #{target}: \n" + e
end
end
end
end
end
|