ioquatix-engines 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/CHANGELOG +280 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +95 -0
  4. data/Rakefile +199 -0
  5. data/about.yml +7 -0
  6. data/bin/rails_engines +103 -0
  7. data/generators/plugin_migration/USAGE +45 -0
  8. data/generators/plugin_migration/plugin_migration_generator.rb +78 -0
  9. data/generators/plugin_migration/templates/plugin_migration.erb +13 -0
  10. data/lib/engines.rb +185 -0
  11. data/lib/engines/assets.rb +38 -0
  12. data/lib/engines/load_engine_tasks.rake +6 -0
  13. data/lib/engines/plugin.rb +173 -0
  14. data/lib/engines/plugin/list.rb +57 -0
  15. data/lib/engines/plugin/migrator.rb +45 -0
  16. data/lib/engines/rails_extensions/action_mailer.rb +85 -0
  17. data/lib/engines/rails_extensions/asset_helpers.rb +149 -0
  18. data/lib/engines/rails_extensions/dependencies.rb +151 -0
  19. data/lib/engines/rails_extensions/routing.rb +88 -0
  20. data/lib/engines/testing.rb +87 -0
  21. data/lib/engines/version.rb +10 -0
  22. data/rails/init.rb +6 -0
  23. data/tasks/engines.rake +249 -0
  24. data/test/app/controllers/app_and_plugin_controller.rb +5 -0
  25. data/test/app/controllers/application.rb +18 -0
  26. data/test/app/controllers/namespace/app_and_plugin_controller.rb +5 -0
  27. data/test/app/helpers/mail_helper.rb +5 -0
  28. data/test/app/models/app_and_plugin_model.rb +3 -0
  29. data/test/app/models/notify_mail.rb +26 -0
  30. data/test/app/things/thing.rb +3 -0
  31. data/test/app/views/app_and_plugin/a_view.html.erb +1 -0
  32. data/test/app/views/namespace/app_and_plugin/a_view.html.erb +1 -0
  33. data/test/app/views/notify_mail/implicit_multipart.text.html.erb +1 -0
  34. data/test/app/views/notify_mail/implicit_multipart.text.plain.erb +1 -0
  35. data/test/app/views/notify_mail/multipart_html.html.erb +1 -0
  36. data/test/app/views/notify_mail/multipart_plain.html.erb +1 -0
  37. data/test/app/views/notify_mail/signup.text.plain.erb +5 -0
  38. data/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb +1 -0
  39. data/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +1 -0
  40. data/test/functional/controller_loading_test.rb +51 -0
  41. data/test/functional/exception_notification_compatibility_test.rb +29 -0
  42. data/test/functional/routes_test.rb +33 -0
  43. data/test/functional/view_helpers_test.rb +32 -0
  44. data/test/functional/view_loading_test.rb +60 -0
  45. data/test/lib/app_and_plugin_lib_model.rb +3 -0
  46. data/test/lib/engines_test_helper.rb +36 -0
  47. data/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb +8 -0
  48. data/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb +5 -0
  49. data/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb +5 -0
  50. data/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb +5 -0
  51. data/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb +5 -0
  52. data/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb +5 -0
  53. data/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb +3 -0
  54. data/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb +7 -0
  55. data/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb +3 -0
  56. data/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb +1 -0
  57. data/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb +1 -0
  58. data/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb +1 -0
  59. data/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb +1 -0
  60. data/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb +1 -0
  61. data/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb +1 -0
  62. data/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb +1 -0
  63. data/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb +3 -0
  64. data/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb +7 -0
  65. data/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb +5 -0
  66. data/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb +5 -0
  67. data/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb +5 -0
  68. data/test/plugins/beta_plugin/app/models/shared_plugin_model.rb +3 -0
  69. data/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb +1 -0
  70. data/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb +1 -0
  71. data/test/plugins/beta_plugin/init.rb +1 -0
  72. data/test/plugins/not_a_plugin/public/should_not_be_copied.txt +0 -0
  73. data/test/plugins/test_assets/app/controllers/assets_controller.rb +2 -0
  74. data/test/plugins/test_assets/app/views/assets/index.html.erb +3 -0
  75. data/test/plugins/test_assets/app/views/layouts/assets.html.erb +3 -0
  76. data/test/plugins/test_assets/init.rb +0 -0
  77. data/test/plugins/test_assets/public/file.txt +0 -0
  78. data/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt +0 -0
  79. data/test/plugins/test_assets_with_assets_directory/assets/file.txt +0 -0
  80. data/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt +0 -0
  81. data/test/plugins/test_assets_with_assets_directory/init.rb +0 -0
  82. data/test/plugins/test_assets_with_no_subdirectory/assets/file.txt +0 -0
  83. data/test/plugins/test_assets_with_no_subdirectory/init.rb +0 -0
  84. data/test/plugins/test_code_mixing/app/things/thing.rb +3 -0
  85. data/test/plugins/test_code_mixing/init.rb +1 -0
  86. data/test/plugins/test_load_path/init.rb +0 -0
  87. data/test/plugins/test_migration/db/migrate/001_create_tests.rb +11 -0
  88. data/test/plugins/test_migration/db/migrate/002_create_others.rb +11 -0
  89. data/test/plugins/test_migration/db/migrate/003_create_extras.rb +11 -0
  90. data/test/plugins/test_migration/init.rb +0 -0
  91. data/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb +26 -0
  92. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.text.plain.erb +1 -0
  93. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb +1 -0
  94. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb +1 -0
  95. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb +1 -0
  96. data/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +1 -0
  97. data/test/plugins/test_plugin_mailing/init.rb +0 -0
  98. data/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb +5 -0
  99. data/test/plugins/test_routing/app/controllers/test_routing_controller.rb +9 -0
  100. data/test/plugins/test_routing/init.rb +0 -0
  101. data/test/plugins/test_routing/routes.rb +2 -0
  102. data/test/plugins/test_testing/init.rb +0 -0
  103. data/test/plugins/test_testing/test/fixtures/testing_fixtures.yml +0 -0
  104. data/test/unit/action_mailer_test.rb +54 -0
  105. data/test/unit/arbitrary_code_mixing_test.rb +41 -0
  106. data/test/unit/assets_test.rb +48 -0
  107. data/test/unit/load_path_test.rb +58 -0
  108. data/test/unit/migration_test.rb +63 -0
  109. data/test/unit/model_and_lib_test.rb +37 -0
  110. data/test/unit/plugins_test.rb +11 -0
  111. data/test/unit/testing_test.rb +18 -0
  112. metadata +259 -0
@@ -0,0 +1,7 @@
1
+ author: Samuel Williams
2
+ email: samuel.williams@oriontransfer.co.nz
3
+ homepage: http://wiki.oriontransfer.org/?rails:engines
4
+ summary: Gemified version of engines plugin. Enhances the plugin mechanism to perform more flexible sharing.
5
+ description: The Rails Engines plugin was originally created by James Adam and allows the sharing of almost any type of code or asset that you could use in a Rails application, including controllers, models, stylesheets, and views.
6
+ license: MIT
7
+ version: 2.1.0
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ require 'optparse'
5
+
6
+ class Array
7
+ # Not optimized at all!
8
+ def matches_sequence? other
9
+ return true if other.size == 0
10
+
11
+ i = index(other.first)
12
+
13
+ if i
14
+ other.each_with_index do |v,p|
15
+ return false if self[i+p] != v
16
+ end
17
+
18
+ return i
19
+ else
20
+ return false
21
+ end
22
+ end
23
+ end
24
+
25
+ def insert_lines(lines_to_insert, options)
26
+ lines_to_insert = lines_to_insert.collect { |l| l.chomp + "\n" }
27
+
28
+ target_file = File.join(options[:into])
29
+
30
+ lines = File.readlines(target_file)
31
+
32
+ return if lines.matches_sequence?(lines_to_insert)
33
+
34
+ if options[:after]
35
+ if options[:after].is_a?(String)
36
+ after_line = options[:after] + "\n"
37
+ else
38
+ after_line = lines.find { |l| l =~ options[:after] }
39
+ raise "couldn't find a line matching #{options[:after].inspect} in #{target_file}" unless after_line
40
+ end
41
+ index = lines.index(after_line)
42
+ raise "couldn't find line '#{after_line}' in #{target_file}" unless index
43
+ lines[index+1,0] = lines_to_insert
44
+ else
45
+ lines << line
46
+ end
47
+
48
+ File.open(target_file, 'w') { |f| f.write lines.join }
49
+ end
50
+
51
+ OPTIONS = {
52
+ :Setup => false
53
+ }
54
+
55
+ ARGV.options do |o|
56
+ script_name = File.basename($0)
57
+
58
+ o.set_summary_indent(' ')
59
+ o.banner = "Usage: #{script_name} [options]"
60
+ o.define_head "This script is used to set up the engines plugin for rails."
61
+
62
+ o.separator ""
63
+ o.separator "Help and Copyright information"
64
+
65
+ o.on("--setup [rails root path]") { |path| OPTIONS[:Setup] = path || "./" }
66
+
67
+ o.on_tail("--copy", "Display copyright information") {
68
+ puts "#{script_name} v#{Engines::VERSION::STRING}. Released under the MIT license."
69
+ puts "See http://wiki.oriontransfer.org/?rails:engines for more information."
70
+
71
+ exit
72
+ }
73
+
74
+ o.on_tail("-h", "--help", "Show this help message.") { puts o; exit }
75
+
76
+ o
77
+ end.parse!
78
+
79
+ if OPTIONS[:Setup]
80
+ config_path = File.join(OPTIONS[:Setup], "config", "environment.rb")
81
+ abort "#{config_path} does not exist. Is #{OPTIONS[:Setup]} a rails root directory?" unless File.exist? config_path
82
+
83
+ rake_text = <<EOF
84
+
85
+ require RAILS_ROOT + "/config/environment"
86
+
87
+ if defined? Engines
88
+ Engines.load_plugin_tasks
89
+ end
90
+
91
+ EOF
92
+
93
+ rake_path = File.join(OPTIONS[:Setup], "lib", "tasks", "load_plugin_tasks.rake")
94
+ unless File.exists?(rake_path)
95
+ File.open(rake_path, "w") { |f| f.write(rake_text) }
96
+ else
97
+ puts "#{rake_path} already exists, not overwriting."
98
+ end
99
+
100
+ insert_lines(["gem 'ioquatix-engines', Rails::VERSION::STRING", "require 'engines'"],
101
+ :into => 'config/environment.rb',
102
+ :after => "require File.join(File.dirname(__FILE__), 'boot')")
103
+ end
@@ -0,0 +1,45 @@
1
+ Description:
2
+ The plugin migration generator assists in working with schema additions
3
+ required by plugins. Instead of running migrations from plugins directly,
4
+ the generator creates a regular Rails migration which will be responsible
5
+ for migrating the plugins from their current version to the latest version
6
+ installed.
7
+
8
+ This is important because the set of application migrations remains an
9
+ accurate record of the state of the database, even as plugins are installed
10
+ and removed during the development process.
11
+
12
+ Example:
13
+ ./script/generate plugin_migration [<plugin_name> <another_plugin_name> ...]
14
+
15
+ This will generate:
16
+
17
+ RAILS_ROOT
18
+ |- db
19
+ |-migrate
20
+ |- xxx_plugin_migrations.rb
21
+
22
+ which contains the migrations for the given plugin(s).
23
+
24
+
25
+ Advanced Usage:
26
+
27
+ There may be situations where you need *complete* control over the migrations
28
+ of plugins in your application, migrating a certainly plugin down to X, and
29
+ another plugin up to Y, where neither X or Y are the latest migrations for those
30
+ plugins.
31
+
32
+ For those unfortunate few, I have two pieces of advice:
33
+
34
+ 1. Why? This is a code smell [http://c2.com/xp/CodeSmell.html].
35
+
36
+ 2. Well, OK. Don't panic. You can completely control plugin migrations by
37
+ creating your own migrations. To manually migrate a plugin to a specific
38
+ version, simply use
39
+
40
+ Engines.plugins[:your_plugin_name].migrate(version)
41
+
42
+ where version is the integer of the migration this plugin should end
43
+ up at.
44
+
45
+ With great power comes great responsibility. Use this wisely.
@@ -0,0 +1,78 @@
1
+ # Generates a migration which migrates all plugins to their latest versions
2
+ # within the database.
3
+ class PluginMigrationGenerator < Rails::Generator::Base
4
+
5
+ def initialize(runtime_args, runtime_options={})
6
+ super
7
+ @options = {:assigns => {}}
8
+ ensure_schema_table_exists
9
+ get_plugins_to_migrate(runtime_args)
10
+
11
+ if @plugins_to_migrate.empty?
12
+ puts "All plugins are migrated to their latest versions"
13
+ exit(0)
14
+ end
15
+
16
+ @options[:migration_file_name] = build_migration_name
17
+ @options[:assigns][:class_name] = build_migration_name.classify
18
+ end
19
+
20
+ def manifest
21
+ record do |m|
22
+ m.migration_template 'plugin_migration.erb', 'db/migrate', @options
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Create the schema table if it doesn't already exist.
29
+ def ensure_schema_table_exists
30
+ ActiveRecord::Base.connection.initialize_schema_migrations_table
31
+ end
32
+
33
+ # Determine all the plugins which have migrations that aren't present
34
+ # according to the plugin schema information from the database.
35
+ def get_plugins_to_migrate(plugin_names)
36
+
37
+ # First, grab all the plugins which exist and have migrations
38
+ @plugins_to_migrate = if plugin_names.empty?
39
+ Engines.plugins
40
+ else
41
+ plugin_names.map do |name|
42
+ Engines.plugins[name] ? Engines.plugins[name] : raise("Cannot find the plugin '#{name}'")
43
+ end
44
+ end
45
+
46
+ @plugins_to_migrate.reject! { |p| p.latest_migration.nil? }
47
+
48
+ # Then find the current versions from the database
49
+ @current_versions = {}
50
+ @plugins_to_migrate.each do |plugin|
51
+ @current_versions[plugin.name] = Engines::Plugin::Migrator.current_version(plugin)
52
+ end
53
+
54
+ # Then find the latest versions from their migration directories
55
+ @new_versions = {}
56
+ @plugins_to_migrate.each do |plugin|
57
+ @new_versions[plugin.name] = plugin.latest_migration
58
+ end
59
+
60
+ # Remove any plugins that don't need migration
61
+ @plugins_to_migrate.map { |p| p.name }.each do |name|
62
+ @plugins_to_migrate.delete(Engines.plugins[name]) if @current_versions[name] == @new_versions[name]
63
+ end
64
+
65
+ @options[:assigns][:plugins] = @plugins_to_migrate
66
+ @options[:assigns][:new_versions] = @new_versions
67
+ @options[:assigns][:current_versions] = @current_versions
68
+ end
69
+
70
+ # Construct a unique migration name based on the plugins involved and the
71
+ # versions they should reach after this migration is run. The name constructed
72
+ # needs to be lowercase
73
+ def build_migration_name
74
+ @plugins_to_migrate.map do |plugin|
75
+ "#{plugin.name}_to_version_#{@new_versions[plugin.name]}"
76
+ end.join("_and_").downcase
77
+ end
78
+ end
@@ -0,0 +1,13 @@
1
+ class <%= class_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ <%- plugins.each do |plugin| -%>
4
+ Engines.plugins["<%= plugin.name %>"].migrate(<%= new_versions[plugin.name] %>)
5
+ <%- end -%>
6
+ end
7
+
8
+ def self.down
9
+ <%- plugins.each do |plugin| -%>
10
+ Engines.plugins["<%= plugin.name %>"].migrate(<%= current_versions[plugin.name] %>)
11
+ <%- end -%>
12
+ end
13
+ end
@@ -0,0 +1,185 @@
1
+ begin
2
+ require 'rails/version'
3
+
4
+ unless Rails::VERSION::STRING == "2.1.0"
5
+ raise "This version of the engines plugin requires Rails 2.1.0! Sorry!"
6
+ end
7
+ end
8
+
9
+ require 'set'
10
+ require 'active_support'
11
+ require File.join(File.dirname(__FILE__), 'engines/version')
12
+ require File.join(File.dirname(__FILE__), 'engines/plugin')
13
+ require File.join(File.dirname(__FILE__), 'engines/plugin/list')
14
+ require File.join(File.dirname(__FILE__), 'engines/assets')
15
+ require File.join(File.dirname(__FILE__), 'engines/rails_extensions/routing')
16
+
17
+ # == Parameters
18
+ #
19
+ # The Engines module has a number of public configuration parameters:
20
+ #
21
+ # [+public_directory+] The directory into which plugin assets should be
22
+ # mirrored. Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.
23
+ # [+schema_info_table+] The table to use when storing plugin migration
24
+ # version information. Defaults to +plugin_schema_info+.
25
+ #
26
+ # Additionally, there are a few flags which control the behaviour of
27
+ # some of the features the engines plugin adds to Rails:
28
+ #
29
+ # [+disable_application_view_loading+] A boolean flag determining whether
30
+ # or not views should be loaded from
31
+ # the main <tt>app/views</tt> directory.
32
+ # Defaults to false; probably only
33
+ # useful when testing your plugin.
34
+ # [+disable_application_code_loading+] A boolean flag determining whether
35
+ # or not to load controllers/helpers
36
+ # from the main +app+ directory,
37
+ # if corresponding code exists within
38
+ # a plugin. Defaults to false; again,
39
+ # probably only useful when testing
40
+ # your plugin.
41
+ # [+disable_code_mixing+] A boolean flag indicating whether all plugin
42
+ # copies of a particular controller/helper should
43
+ # be loaded and allowed to override each other,
44
+ # or if the first matching file should be loaded
45
+ # instead. Defaults to false.
46
+ #
47
+ module Engines
48
+ # The set of all loaded plugins
49
+ mattr_accessor :plugins
50
+ self.plugins = Engines::Plugin::List.new
51
+
52
+ # List of extensions to load, can be changed in init.rb before calling Engines.init
53
+ mattr_accessor :rails_extensions
54
+ self.rails_extensions = %w(action_mailer asset_helpers dependencies)
55
+
56
+ # The name of the public directory to mirror public engine assets into.
57
+ # Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>.
58
+ mattr_accessor :public_directory
59
+ self.public_directory = File.join(RAILS_ROOT, 'public', 'plugin_assets')
60
+
61
+ # The table in which to store plugin schema information. Defaults to
62
+ # "plugin_schema_info".
63
+ mattr_accessor :schema_info_table
64
+ self.schema_info_table = "plugin_schema_info"
65
+
66
+ #--
67
+ # These attributes control the behaviour of the engines extensions
68
+ #++
69
+
70
+ # Set this to true if views should *only* be loaded from plugins
71
+ mattr_accessor :disable_application_view_loading
72
+ self.disable_application_view_loading = false
73
+
74
+ # Set this to true if controller/helper code shouldn't be loaded
75
+ # from the application
76
+ mattr_accessor :disable_application_code_loading
77
+ self.disable_application_code_loading = false
78
+
79
+ # Set this ti true if code should not be mixed (i.e. it will be loaded
80
+ # from the first valid path on $LOAD_PATH)
81
+ mattr_accessor :disable_code_mixing
82
+ self.disable_code_mixing = false
83
+
84
+ # This is used to determine which files are candidates for the "code
85
+ # mixing" feature that the engines plugin provides, where classes from
86
+ # plugins can be loaded, and then code from the application loaded
87
+ # on top of that code to override certain methods.
88
+ mattr_accessor :code_mixing_file_types
89
+ self.code_mixing_file_types = %w(controller helper)
90
+
91
+ class << self
92
+ def init
93
+ load_extensions
94
+ Engines::Assets.initialize_base_public_directory
95
+ end
96
+
97
+ def load_plugin_tasks
98
+ # Load any rake tasks that may not have been loaded from external plugins.
99
+ Engines.plugins.each do |plugin|
100
+ Dir["#{plugin.tasks_path}/**/*.rake"].sort.each { |ext| load ext }
101
+ end
102
+ end
103
+
104
+ def logger
105
+ RAILS_DEFAULT_LOGGER
106
+ end
107
+
108
+ def load_extensions
109
+ rails_extensions.each { |name| require "engines/rails_extensions/#{name}" }
110
+ # load the testing extensions, if we are in the test environment.
111
+ require "engines/testing" if RAILS_ENV == "test"
112
+ end
113
+
114
+ def select_existing_paths(paths)
115
+ paths.select { |path| File.directory?(path) }
116
+ end
117
+
118
+ # The engines plugin will, by default, mix code from controllers and helpers,
119
+ # allowing application code to override specific methods in the corresponding
120
+ # controller or helper classes and modules. However, if other file types should
121
+ # also be mixed like this, they can be added by calling this method. For example,
122
+ # if you want to include "things" within your plugin and override them from
123
+ # your applications, you should use the following layout:
124
+ #
125
+ # app/
126
+ # +-- things/
127
+ # | +-- one_thing.rb
128
+ # | +-- another_thing.rb
129
+ # ...
130
+ # vendor/
131
+ # +-- plugins/
132
+ # +-- my_plugin/
133
+ # +-- app/
134
+ # +-- things/
135
+ # +-- one_thing.rb
136
+ # +-- another_thing.rb
137
+ #
138
+ # The important point here is that your "things" are named <whatever>_thing.rb,
139
+ # and that they are placed within plugin/app/things (the pluralized form of 'thing').
140
+ #
141
+ # It's important to note that you'll also want to ensure that the "things" are
142
+ # on your load path in your plugin's init.rb:
143
+ #
144
+ # Engines.plugins[:my_plugin].code_paths << "app/things"
145
+ #
146
+ def mix_code_from(*types)
147
+ self.code_mixing_file_types += types.map { |x| x.to_s.singularize }
148
+ end
149
+
150
+ # A general purpose method to mirror a directory (+source+) into a destination
151
+ # directory, including all files and subdirectories. Files will not be mirrored
152
+ # if they are identical already (checked via FileUtils#identical?).
153
+ def mirror_files_from(source, destination)
154
+ return unless File.directory?(source)
155
+
156
+ # TODO: use Rake::FileList#pathmap?
157
+ source_files = Dir[source + "/**/*"]
158
+ source_dirs = source_files.select { |d| File.directory?(d) }
159
+ source_files -= source_dirs
160
+
161
+ source_dirs.each do |dir|
162
+ # strip down these paths so we have simple, relative paths we can
163
+ # add to the destination
164
+ target_dir = File.join(destination, dir.gsub(source, ''))
165
+
166
+ begin
167
+ FileUtils.mkdir_p(target_dir)
168
+ rescue Exception => e
169
+ raise "Could not create directory #{target_dir}: \n" + e
170
+ end
171
+ end
172
+
173
+ source_files.each do |file|
174
+ begin
175
+ target = File.join(destination, file.gsub(source, ''))
176
+ unless File.exist?(target) && FileUtils.identical?(file, target)
177
+ FileUtils.cp(file, target)
178
+ end
179
+ rescue Exception => e
180
+ raise "Could not copy #{file} to #{target}: \n" + e
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,38 @@
1
+ module Engines
2
+ module Assets
3
+ class << self
4
+ @@readme = %{Files in this directory are automatically generated from your plugins.
5
+ They are copied from the 'assets' directories of each plugin into this directory
6
+ each time Rails starts (script/server, script/console... and so on).
7
+ Any edits you make will NOT persist across the next server restart; instead you
8
+ should edit the files within the <plugin_name>/assets/ directory itself.}
9
+
10
+ # Ensure that the plugin asset subdirectory of RAILS_ROOT/public exists, and
11
+ # that we've added a little warning message to instruct developers not to mess with
12
+ # the files inside, since they're automatically generated.
13
+ def initialize_base_public_directory
14
+ dir = Engines.public_directory
15
+ unless File.exist?(dir)
16
+ Engines.logger.debug "Creating public engine files directory '#{dir}'"
17
+ FileUtils.mkdir_p(dir)
18
+ end
19
+ readme = File.join(dir, "README")
20
+ File.open(readme, 'w') { |f| f.puts @@readme } unless File.exist?(readme)
21
+ end
22
+
23
+ # Replicates the subdirectories under the plugins's +assets+ (or +public+)
24
+ # directory into the corresponding public directory. See also
25
+ # Plugin#public_directory for more.
26
+ def mirror_files_for(plugin)
27
+ return if plugin.public_directory.nil?
28
+ begin
29
+ Engines.logger.debug "Attempting to copy plugin assets from '#{plugin.public_directory}' to '#{Engines.public_directory}'"
30
+ Engines.mirror_files_from(plugin.public_directory, File.join(Engines.public_directory, plugin.name))
31
+ rescue Exception => e
32
+ Engines.logger.warn "WARNING: Couldn't create the public file structure for plugin '#{plugin.name}'; Error follows:"
33
+ Engines.logger.warn e
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end