desert 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGES ADDED
@@ -0,0 +1,7 @@
1
+ 0.1.1
2
+ - Works with edge Rails
3
+ - Fixed double loading issue with not fully expanded load_paths.
4
+
5
+ 0.1.0
6
+ - Fixed [#13346] ActionController::Base.helper raises error when helper is only in plugin
7
+ - Desert does not require files that have been required before Desert was loaded
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Pivotal Labs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,77 @@
1
+ = Desert
2
+
3
+ Desert is a component framework for Rails that allows you to seamlessly define in your plugins:
4
+ * Models
5
+ * Controllers
6
+ * Views
7
+ * Helpers
8
+ * Routes
9
+ * Migrations
10
+ * Plugin Dependencies
11
+
12
+ Classes are automatically mixed in with your own or other plugins' classes.
13
+ This allows you to make full featured composable components.
14
+ Desert is a replacement for Appable Plugins (http://wiki.pluginaweek.org/Appable_plugins).
15
+
16
+
17
+ == Using desert
18
+
19
+ To use Desert, you need to do only a few things:
20
+
21
+ * require 'desert' before Rails::Initializer.run in environment.rb
22
+
23
+ environment.rb
24
+ require 'desert'
25
+ Rails::Initializer.run do
26
+ end
27
+
28
+ * Install your desert plugin routes in routes.rb
29
+
30
+ map.routes_from_plugin(:spiffy)
31
+
32
+
33
+ == Example
34
+ Say you want to create a plugin named acts_as_spiffy.
35
+ Desert allows Spiffy to have a set of features that can be reused and extended in several projects.
36
+
37
+ The Spiffy project has a:
38
+ * SpiffyController
39
+ * Spiffy model
40
+ * SpiffyHelper
41
+ * spiffy.rhtml
42
+ * SpiffyLib library class
43
+
44
+ The Spiffy plugin acts as its own mini Rails application.
45
+ Here is the directory structure:
46
+ RAILS_ROOT/vendor/plugins/spiffy/app/controllers/spiffy_controller.rb
47
+ RAILS_ROOT/vendor/plugins/spiffy/app/models/spiffy.rb
48
+ RAILS_ROOT/vendor/plugins/spiffy/app/helpers/spiffy_helper.rb
49
+ RAILS_ROOT/vendor/plugins/spiffy/app/views/spiffy/spiffy.rhtml
50
+ RAILS_ROOT/vendor/plugins/spiffy/lib/spiffy_lib.rb
51
+
52
+ Now, say there is a Spiffy Store rails application that uses acts_as_spiffy.
53
+ The Rails app can open up any of the Spiffy classes and override any of the methods.
54
+
55
+ Say spiffy.rb in the Spiffy plugin is defined as:
56
+ class Spiffy < ActiveRecord::Base
57
+ def why?
58
+ "I just am Spiffy"
59
+ end
60
+ end
61
+
62
+ The Spiffy#why method can be overridden in RAILS_ROOT/app/models/spiffy.rb
63
+ class Spiffy < ActiveRecord::Base
64
+ def why?
65
+ "I sell Spiffy stuff"
66
+ end
67
+ end
68
+
69
+
70
+ == Running plugin tests
71
+
72
+ You can run your plugin tests/specs like so:
73
+
74
+ rake desert:testspec:plugins PLUGIN=spiffy
75
+
76
+ Leaving off the PLUGIN environment variable will cause it to run all the test/specs for
77
+ all installed plugins, which may not be what you want.
@@ -0,0 +1,71 @@
1
+ require "rake"
2
+ require 'rake/gempackagetask'
3
+ require 'rake/contrib/rubyforgepublisher'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/rdoctask'
7
+
8
+ desc "Runs the Rspec suite"
9
+ task(:default) do
10
+ run_suite
11
+ end
12
+
13
+ desc "Runs the Rspec suite"
14
+ task(:spec) do
15
+ run_suite
16
+ end
17
+
18
+ def run_suite
19
+ dir = File.dirname(__FILE__)
20
+ system("ruby #{dir}/spec/spec_suite.rb") || raise("Example Suite failed")
21
+ end
22
+
23
+ desc "Copies the trunk to a tag with the name of the current release"
24
+ task(:tag_release) do
25
+ tag_release
26
+ end
27
+
28
+ PKG_NAME = "desert"
29
+ PKG_VERSION = "0.1.1"
30
+ PKG_FILES = FileList[
31
+ '[A-Z]*',
32
+ '*.rb',
33
+ 'lib/**/*.rb',
34
+ 'lib/generators/**/*',
35
+ 'lib/generators/**/templates/*',
36
+ 'examples/**/*.rb'
37
+ ]
38
+
39
+ spec = Gem::Specification.new do |s|
40
+ s.name = PKG_NAME
41
+ s.version = PKG_VERSION
42
+ s.summary = "Desert is a component framework for Rails that allows your plugins to be packaged as mini Rails apps."
43
+ s.test_files = "examples/spec_suite.rb"
44
+ s.description = s.summary
45
+
46
+ s.files = PKG_FILES.to_a
47
+ s.require_path = 'lib'
48
+
49
+ s.has_rdoc = true
50
+ s.extra_rdoc_files = [ "README", "CHANGES" ]
51
+ s.rdoc_options = ["--main", "README", "--inline-source", "--line-numbers"]
52
+
53
+ s.test_files = Dir.glob('spec/*_spec.rb')
54
+ s.require_path = 'lib'
55
+ s.autorequire = 'desert'
56
+ s.author = "Pivotal Labs"
57
+ s.email = "opensource@pivotallabs.com"
58
+ s.homepage = "http://pivotallabs.com"
59
+ s.rubyforge_project = "pivotalrb"
60
+ end
61
+
62
+ Rake::GemPackageTask.new(spec) do |pkg|
63
+ pkg.need_zip = true
64
+ pkg.need_tar = true
65
+ end
66
+
67
+ def tag_release
68
+ dashed_version = PKG_VERSION.gsub('.', '-')
69
+ svn_user = "#{ENV["SVN_USER"]}@" || ""
70
+ `svn cp svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/desert/trunk svn+ssh://#{svn_user}rubyforge.org/var/svn/pivotalrb/desert/tags/REL-#{dashed_version} -m 'Version #{PKG_VERSION}'`
71
+ end
data/init.rb ADDED
File without changes
@@ -0,0 +1,32 @@
1
+ require "active_support"
2
+ require "active_record"
3
+ require "action_controller"
4
+ require "action_mailer"
5
+
6
+ dir = File.dirname(__FILE__)
7
+ require "#{dir}/desert/plugin"
8
+ require "#{dir}/desert/manager"
9
+ require "#{dir}/desert/version_checker"
10
+
11
+ if Desert::VersionChecker.rails_version_is_below_1990?
12
+ require "#{dir}/desert/rails/1.x/initializer"
13
+ else
14
+ require "#{dir}/desert/rails/2.x/plugin"
15
+ end
16
+ require "#{dir}/desert/rails/dependencies"
17
+ require "#{dir}/desert/rails/migration"
18
+ require "#{dir}/desert/rails/migrator"
19
+ require "#{dir}/desert/ruby/object"
20
+
21
+ require "#{dir}/desert/rails/route_set"
22
+
23
+ require "#{dir}/desert/plugin_migrations/migrator"
24
+ require "#{dir}/desert/plugin_migrations/extensions/schema_statements"
25
+
26
+ require "#{dir}/desert/plugin_templates/action_controller"
27
+ if Desert::VersionChecker.rails_version_is_below_rc2?
28
+ require "#{dir}/desert/plugin_templates/1.x/action_mailer"
29
+ else
30
+ require "#{dir}/desert/plugin_templates/2.x/action_mailer"
31
+ end
32
+ require "#{dir}/desert/plugin_templates/action_view"
@@ -0,0 +1,112 @@
1
+ module Desert
2
+ class Manager # nodoc
3
+ class << self
4
+ def instance
5
+ @instance ||= new
6
+ end
7
+ attr_writer :instance
8
+
9
+ protected
10
+ def method_missing(method_name, *args, &block)
11
+ instance.__send__(method_name, *args, &block)
12
+ end
13
+ end
14
+
15
+ attr_reader :loading_plugin, :plugins_in_registration
16
+
17
+ def initialize
18
+ @plugins = []
19
+ @plugins_in_registration = []
20
+ end
21
+
22
+ def plugins
23
+ @plugins.dup
24
+ end
25
+
26
+ def load_paths
27
+ paths = []
28
+ plugin_paths.each do |component_root|
29
+ paths << File.join(component_root, 'app')
30
+ paths << File.join(component_root, 'app','models')
31
+ paths << File.join(component_root, 'app','controllers')
32
+ paths << File.join(component_root, 'app','helpers')
33
+ paths << File.join(component_root, 'lib')
34
+ end
35
+ Dependencies.load_paths.reverse.each do |path|
36
+ paths << File.expand_path(path) unless paths.include?(File.expand_path(path))
37
+ end
38
+ paths
39
+ end
40
+
41
+ def register_plugin(plugin_path)
42
+ plugin = Plugin.new(plugin_path)
43
+ @plugins_in_registration << plugin
44
+
45
+ yield if block_given?
46
+
47
+ Dependencies.load_paths << plugin.models_path
48
+ Dependencies.load_paths << plugin.controllers_path
49
+ Dependencies.load_paths << plugin.helpers_path
50
+
51
+ @plugins_in_registration.pop
52
+
53
+ if existing_plugin = find_plugin(plugin.name)
54
+ return existing_plugin
55
+ end
56
+
57
+ @plugins << plugin
58
+ plugin
59
+ end
60
+
61
+ def find_plugin(name_or_directory)
62
+ name = File.basename(File.expand_path(name_or_directory))
63
+ plugins.find do |plugin|
64
+ plugin.name == name
65
+ end
66
+ end
67
+
68
+ def plugin_exists?(name_or_directory)
69
+ !find_plugin(name_or_directory).nil?
70
+ end
71
+
72
+ def plugin_path(name)
73
+ plugin = find_plugin(name)
74
+ return nil unless plugin
75
+ plugin.path
76
+ end
77
+
78
+ def files_on_load_path(file)
79
+ desert_file_exists = false
80
+ files = []
81
+ load_paths.each do |path|
82
+ full_path = File.join(path, file)
83
+ full_path << '.rb' unless File.extname(full_path) == '.rb'
84
+ files << full_path if File.exists?(full_path)
85
+ end
86
+ files
87
+ end
88
+
89
+ def directory_on_load_path?(dir_suffix)
90
+ Desert::Manager.load_paths.each do |path|
91
+ return true if File.directory?(File.join(path, dir_suffix))
92
+ end
93
+ return false
94
+ end
95
+
96
+ def layout_paths
97
+ layout_paths = plugins.reverse.collect do |plugin|
98
+ plugin.layouts_path
99
+ end
100
+ layout_paths
101
+ end
102
+
103
+ protected
104
+ def plugin_paths
105
+ plugins_and_app.collect { |plugin| plugin.path }
106
+ end
107
+
108
+ def plugins_and_app
109
+ plugins + @plugins_in_registration + [Plugin.new(RAILS_ROOT)]
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,80 @@
1
+ module Desert
2
+ class Plugin # nodoc
3
+ attr_reader :name, :path
4
+ def initialize(path)
5
+ @path = File.expand_path(path)
6
+ @name = File.basename(@path)
7
+ end
8
+
9
+ def migration_path
10
+ "#{@path}/db/migrate"
11
+ end
12
+
13
+ # The path to the views for this plugin
14
+ def templates_path
15
+ "#{@path}/app/views"
16
+ end
17
+
18
+ def controllers_path
19
+ "#{@path}/app/controllers"
20
+ end
21
+
22
+ # TODO: Test me
23
+ def models_path
24
+ "#{@path}/app/models"
25
+ end
26
+
27
+ # TODO: Test me
28
+ def helpers_path
29
+ "#{@path}/app/helpers"
30
+ end
31
+
32
+ # The path to the layout for this plugin
33
+ def layouts_path
34
+ "#{templates_path}/layouts"
35
+ end
36
+
37
+ # Finds a template with the specified path
38
+ def find_template(template)
39
+ template_path = "#{templates_path}/#{template}"
40
+ File.exists?(template_path) ? template_path : nil
41
+ end
42
+
43
+ def framework_paths
44
+ # TODO: Don't include dirs for frameworks that are not used
45
+ %w(
46
+ railties
47
+ railties/lib
48
+ actionpack/lib
49
+ activesupport/lib
50
+ activerecord/lib
51
+ actionmailer/lib
52
+ actionwebservice/lib
53
+ ).map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
54
+ end
55
+
56
+ def ==(other)
57
+ self.path == other.path
58
+ end
59
+
60
+ def migration
61
+ @migration ||= PluginAWeek::PluginMigrations::Migrator.new(:up, migration_path)
62
+ end
63
+
64
+ def up_to_date?
65
+ with_current_plugin do
66
+ migration.latest_version <= migration.current_version
67
+ end
68
+ end
69
+
70
+ def with_current_plugin
71
+ old_plugin = PluginAWeek::PluginMigrations::Migrator.current_plugin
72
+ begin
73
+ PluginAWeek::PluginMigrations::Migrator.current_plugin = self
74
+ yield
75
+ ensure
76
+ PluginAWeek::PluginMigrations::Migrator.current_plugin = old_plugin
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module SchemaStatements #:nodoc:
4
+ def initialize_schema_information_with_plugins
5
+ initialize_schema_information_without_plugins
6
+
7
+ begin
8
+ execute "CREATE TABLE #{PluginAWeek::PluginMigrations::Migrator.schema_info_table_name} (plugin_name #{type_to_sql(:string)}, version #{type_to_sql(:integer)})"
9
+ rescue ActiveRecord::StatementInvalid
10
+ # Schema has been initialized
11
+ end
12
+ end
13
+ alias_method_chain :initialize_schema_information, :plugins
14
+
15
+ def dump_schema_information_with_plugins
16
+ schema_information = []
17
+
18
+ dump = dump_schema_information_without_plugins
19
+ schema_information << dump if dump
20
+
21
+ begin
22
+ plugins = ActiveRecord::Base.connection.select_all("SELECT * FROM #{PluginAWeek::PluginMigrations::Migrator.schema_info_table_name}")
23
+ plugins.each do |plugin|
24
+ if (version = plugin['version'].to_i) > 0
25
+ plugin_name = ActiveRecord::Base.quote_value(plugin['plugin_name'])
26
+ schema_information << "INSERT INTO #{PluginAWeek::PluginMigrations::Migrator.schema_info_table_name} (plugin_name, version) VALUES (#{plugin_name}, #{version})"
27
+ end
28
+ end
29
+ rescue ActiveRecord::StatementInvalid
30
+ # No Schema Info
31
+ end
32
+
33
+ schema_information.join(";\n")
34
+ end
35
+ alias_method_chain :dump_schema_information, :plugins
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ module PluginAWeek #:nodoc:
2
+ module PluginMigrations
3
+ # Responsible for migrating plugins. PluginAWeek::PluginMigrations.Migrator.current_plugin
4
+ # indicates which plugin is currently being migrated
5
+ class Migrator < ActiveRecord::Migrator
6
+ # We need to be able to set the current plugin being migrated.
7
+ cattr_accessor :current_plugin
8
+
9
+ class << self
10
+ # Runs the migrations from a plugin, up (or down) to the version given
11
+ def migrate_plugin(plugin, version = nil)
12
+ self.current_plugin = plugin
13
+ migrate(plugin.migration_path, version)
14
+ end
15
+
16
+ def schema_info_table_name #:nodoc:
17
+ ActiveRecord::Base.table_name_prefix + 'plugin_schema_info' + ActiveRecord::Base.table_name_suffix
18
+ end
19
+
20
+ def current_version #:nodoc:
21
+ result = ActiveRecord::Base.connection.select_one("SELECT version FROM #{schema_info_table_name} WHERE plugin_name = '#{current_plugin.name}'")
22
+ if result
23
+ result['version'].to_i
24
+ else
25
+ # There probably isn't an entry for this plugin in the migration info table.
26
+ 0
27
+ end
28
+ end
29
+ end
30
+
31
+ def set_schema_version(version)
32
+ version = down? ? version.to_i - 1 : version.to_i
33
+
34
+ if ActiveRecord::Base.connection.select_one("SELECT version FROM #{self.class.schema_info_table_name} WHERE plugin_name = '#{current_plugin.name}'").nil?
35
+ # We need to create the entry since it doesn't exist
36
+ ActiveRecord::Base.connection.execute("INSERT INTO #{self.class.schema_info_table_name} (version, plugin_name) VALUES (#{version},'#{current_plugin.name}')")
37
+ else
38
+ ActiveRecord::Base.connection.update("UPDATE #{self.class.schema_info_table_name} SET version = #{version} WHERE plugin_name = '#{current_plugin.name}'")
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ module ActionMailer #:nodoc
2
+ class Base #:nodoc:
3
+ private
4
+ def template_path_with_plugin_routing
5
+ template_paths = [template_path_without_plugin_routing]
6
+ Desert::Manager.plugins.reverse.each do |plugin|
7
+ template_paths << "#{plugin.templates_path}/#{mailer_name}"
8
+ end
9
+ "{#{template_paths * ','}}"
10
+ end
11
+ alias_method_chain :template_path, :plugin_routing
12
+
13
+ def initialize_template_class(assigns)
14
+ base_path = Dir["#{template_path}/#{@template}.*"].first
15
+ returning(template = ActionView::Base.new(File.dirname(base_path), assigns, self)) do
16
+ template.extend ApplicationHelper
17
+ template.extend self.class.master_helper_module
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module ActionMailer #:nodoc
2
+ class Base #:nodoc:
3
+ private
4
+ def template_path_with_plugin_routing
5
+ template_paths = [template_path_without_plugin_routing]
6
+ Desert::Manager.plugins.reverse.each do |plugin|
7
+ template_paths << "#{plugin.templates_path}/#{mailer_name}"
8
+ end
9
+ "{#{template_paths * ','}}"
10
+ end
11
+ alias_method_chain :template_path, :plugin_routing
12
+
13
+ def initialize_template_class(assigns)
14
+ view_paths = Dir[template_path].collect do |path|
15
+ File.dirname(path)
16
+ end
17
+ returning(template = ActionView::Base.new(view_paths, assigns, self)) do
18
+ template.extend ApplicationHelper
19
+ template.extend self.class.master_helper_module
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ module ActionController #:nodoc:
2
+ module Layout #:nodoc:
3
+ module ClassMethods #:nodoc:
4
+ private
5
+ def layout_list_with_plugin_routing
6
+ plugin_layouts = Desert::Manager.layout_paths.join(",")
7
+ layout_list_without_plugin_routing + Dir["{#{plugin_layouts}}/**/*"]
8
+ end
9
+ alias_method_chain :layout_list, :plugin_routing
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ if ActionView.const_defined?(:TemplateFinder)
2
+ module ActionView #:nodoc:
3
+ class TemplateFinder #:nodoc:
4
+ def initialize_with_desert_plugins(*args)
5
+ initialize_without_desert_plugins *args
6
+
7
+ Desert::Manager.plugins.reverse.each do |plugin|
8
+ append_view_path plugin.templates_path
9
+ end
10
+ end
11
+ alias_method_chain :initialize, :desert_plugins
12
+ end
13
+ end
14
+ else
15
+ module ActionView #:nodoc:
16
+ class Base #:nodoc:
17
+ private
18
+ def full_template_path_with_plugin_routing(template_path, extension)
19
+ full_template_path = full_template_path_without_plugin_routing(template_path, extension)
20
+
21
+ unless File.exist?(full_template_path)
22
+ # Look through the plugins for the template
23
+ Desert::Manager.plugins.reverse.each do |plugin|
24
+ if plugin_template_path = plugin.find_template("#{template_path}.#{extension}")
25
+ full_template_path = plugin_template_path
26
+ break
27
+ end
28
+ end
29
+ end
30
+
31
+ full_template_path
32
+ end
33
+ alias_method_chain :full_template_path, :plugin_routing
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ module Rails
2
+ class Initializer
3
+ def load_plugin_with_desert(directory)
4
+ return if Desert::Manager.plugin_exists?(directory)
5
+ plugin = Desert::Manager.register_plugin(directory) do
6
+ load_plugin_without_desert(directory)
7
+ end
8
+ # TODO: Can we use Initializer::Configuration#default_load_paths to do this?
9
+ configuration.controller_paths << plugin.controllers_path
10
+ end
11
+ alias_method_chain :load_plugin, :desert
12
+
13
+ def require_plugin(plugin_name)
14
+ find_plugins(configuration.plugin_paths).sort.each do |path|
15
+ return load_plugin(path) if File.basename(path) == plugin_name
16
+ end
17
+ raise "Plugin '#{plugin_name}' does not exist"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ class Rails::Plugin
2
+ attr_accessor :initializer
3
+ def require_plugin(plugin_name)
4
+ initializer.configuration.plugin_locators.each do |locator|
5
+ locator.new(initializer).each do |plugin_loader|
6
+ return plugin_loader.load(initializer) if plugin_loader.name.to_s == plugin_name.to_s
7
+ end
8
+ end
9
+ raise "Plugin '#{plugin_name}' does not exist"
10
+ end
11
+
12
+ def load_with_desert(initializer)
13
+ @initializer = initializer
14
+ return if Desert::Manager.plugin_exists?(directory)
15
+ plugin = Desert::Manager.register_plugin(directory) do
16
+ load_without_desert(initializer)
17
+ end
18
+ # TODO: Can we use Initializer::Configuration#default_load_paths to do this?
19
+ initializer.configuration.controller_paths << plugin.controllers_path
20
+ end
21
+ alias_method_chain :load, :desert
22
+ end
@@ -0,0 +1,88 @@
1
+ module Dependencies
2
+ def load_missing_constant_with_desert(from_mod, const_name)
3
+ from_mod = guard_against_anonymous_module(from_mod)
4
+ qualified_name = qualified_name_for from_mod, const_name
5
+ path_suffix = qualified_name.underscore
6
+
7
+ if define_constant_with_desert_loading(from_mod, const_name, qualified_name, path_suffix)
8
+ return from_mod.const_get(const_name)
9
+ end
10
+
11
+ if has_parent_module?(from_mod)
12
+ look_for_constant_in_parent_module(from_mod, const_name, qualified_name, path_suffix)
13
+ else
14
+ raise NameError, "Constant #{qualified_name} from #{path_suffix}.rb not found"
15
+ end
16
+ end
17
+ alias_method_chain :load_missing_constant, :desert
18
+
19
+ def load_once_path?(path)
20
+ load_once_paths.any? { |base| File.expand_path(path).starts_with? File.expand_path(base) }
21
+ end
22
+
23
+ def depend_on_with_desert(file_name, swallow_load_errors = false)
24
+ successfully_loaded_in_plugin = false
25
+ Desert::Manager.files_on_load_path(file_name).each do |file|
26
+ require_or_load(file)
27
+ successfully_loaded_in_plugin = true
28
+ end
29
+ begin
30
+ unless successfully_loaded_in_plugin
31
+ require_or_load file_name
32
+ loaded << File.expand_path(file_name)
33
+ end
34
+ rescue LoadError
35
+ if !swallow_load_errors && !successfully_loaded_in_plugin
36
+ raise
37
+ end
38
+ end
39
+ end
40
+ alias_method_chain :depend_on, :desert
41
+
42
+ protected
43
+ def define_constant_with_desert_loading(from_mod, const_name, qualified_name, path_suffix)
44
+ define_constant_from_file(from_mod, const_name, qualified_name, path_suffix) ||
45
+ define_constant_from_directory(from_mod, const_name, qualified_name, path_suffix)
46
+ end
47
+
48
+ def has_parent_module?(mod)
49
+ mod != Object
50
+ end
51
+
52
+ def look_for_constant_in_parent_module(from_mod, const_name, qualified_name, path_suffix)
53
+ return from_mod.parent.const_missing(const_name)
54
+ rescue NameError => e
55
+ raise NameError, "Constant #{qualified_name} from #{path_suffix}.rb not found\n#{e.message}"
56
+ end
57
+
58
+ def guard_against_anonymous_module(from_mod)
59
+ return Object if from_mod.name.blank?
60
+ return from_mod
61
+ end
62
+
63
+ def define_constant_from_file(from_mod, const_name, qualified_name, path_suffix)
64
+ files = Desert::Manager.files_on_load_path(path_suffix)
65
+ files.each do |file|
66
+ # TODO: JLM/BT -- figure out why require_or_load does not work on Windows.
67
+ # require_or_load file
68
+ load file
69
+ loaded << file.gsub(/\.rb$/, '')
70
+ next if autoloaded_constants.include?(qualified_name)
71
+ next if load_once_path?(file)
72
+ autoloaded_constants << qualified_name
73
+ end
74
+ loaded << File.expand_path(path_suffix)
75
+ from_mod.const_defined?(const_name)
76
+ end
77
+
78
+ def define_constant_from_directory(from_mod, const_name, qualified_name, path_suffix)
79
+ return false unless Desert::Manager.directory_on_load_path?(path_suffix)
80
+
81
+ if autoloaded_constants.include?(qualified_name)
82
+ raise "Constant #{qualified_name} is already autoloaded but is not defined as a constant"
83
+ end
84
+ from_mod.const_set(const_name, Module.new)
85
+ autoloaded_constants << qualified_name
86
+ return true
87
+ end
88
+ end
@@ -0,0 +1,42 @@
1
+ class ActiveRecord::Migration
2
+ module DesertMigration
3
+ def migrate_plugin(plugin_name, version)
4
+ plugin = find_plugin(plugin_name)
5
+ PluginAWeek::PluginMigrations::Migrator.migrate_plugin(
6
+ plugin,
7
+ version
8
+ )
9
+ end
10
+
11
+ def schema_version_equivalent_to(plugin_name, version)
12
+ plugin = find_plugin(plugin_name)
13
+ PluginAWeek::PluginMigrations::Migrator.current_plugin = plugin
14
+ PluginAWeek::PluginMigrations::Migrator.allocate.set_schema_version(version)
15
+ end
16
+
17
+ protected
18
+ def find_plugin(plugin_name)
19
+ plugin = Desert::Manager.find_plugin(plugin_name)
20
+ return plugin if plugin
21
+ raise ArgumentError, "No plugin found named #{plugin_name}"
22
+ end
23
+
24
+ def table_exists?(table_name)
25
+ vals = select_all("DESC #{table_name}")
26
+ return true
27
+ rescue ActiveRecord::StatementInvalid
28
+ return false
29
+ end
30
+
31
+ def column_exists?(table_name, column_name)
32
+ val = select_one("select #{column_name} from #{table_name}")
33
+ return true
34
+ rescue ActiveRecord::StatementInvalid
35
+ return false
36
+ end
37
+ def table_exists?(table_name)
38
+ ActiveRecord::Base.connection.tables.include? table_name
39
+ end
40
+ end
41
+ extend DesertMigration
42
+ end
@@ -0,0 +1,14 @@
1
+ class ActiveRecord::Migrator
2
+ module DesertMigrator
3
+ def latest_version
4
+ return 0 if migration_classes.empty?
5
+ migration_classes.last.first
6
+ end
7
+
8
+ def migration_classes_with_caching
9
+ @migration_classes ||= migration_classes_without_caching
10
+ end
11
+ end
12
+ include DesertMigrator
13
+ alias_method_chain :migration_classes, :caching
14
+ end
@@ -0,0 +1,23 @@
1
+ module Desert
2
+ module Rails
3
+ module RouteSet
4
+ # Loads the set of routes from within a plugin and evaluates them at this
5
+ # point within an application's main <tt>routes.rb</tt> file.
6
+ #
7
+ # Plugin routes are loaded from <tt><plugin_root>/routes.rb</tt>.
8
+ def routes_from_plugin(name)
9
+ name = name.to_s
10
+ routes_path = File.join(
11
+ Desert::Manager.plugin_path(name),
12
+ "config/routes.rb"
13
+ )
14
+ RAILS_DEFAULT_LOGGER.debug "Loading routes from #{routes_path}."
15
+ eval(IO.read(routes_path), binding, routes_path) if File.file?(routes_path)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ class ActionController::Routing::RouteSet::Mapper
22
+ include Desert::Rails::RouteSet
23
+ end
@@ -0,0 +1,34 @@
1
+ class Object
2
+ def require_with_desert(path)
3
+ relative_include_path = (path =~ /\.rb$/) ? path : "#{path}.rb"
4
+ if $".include?(relative_include_path)
5
+ return false
6
+ else
7
+ __each_matching_file(path) do |expanded_path|
8
+ require_without_desert expanded_path
9
+ end
10
+ $" << relative_include_path
11
+ return true
12
+ end
13
+ end
14
+ alias_method_chain :require, :desert
15
+
16
+ def load_with_desert(file)
17
+ __each_matching_file(file) do |file|
18
+ load_without_desert file
19
+ end
20
+ end
21
+ alias_method_chain :load, :desert
22
+
23
+ private
24
+ def __each_matching_file(file)
25
+ files = Desert::Manager.instance.files_on_load_path(file)
26
+ desert_file_exists = files.empty? ? false : true
27
+ files.each do |component_file|
28
+ yield(component_file)
29
+ end
30
+
31
+ return true if desert_file_exists
32
+ yield(file)
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ module Desert
2
+ class VersionChecker
3
+ class << self
4
+ def current_rails_version_matches?(version_requirement)
5
+ version_matches?(::Rails::VERSION::STRING, version_requirement)
6
+ end
7
+
8
+ def version_matches?(version, version_requirement)
9
+ Gem::Version::Requirement.new([version_requirement]).satisfied_by?(Gem::Version.new(version))
10
+ end
11
+
12
+ def rails_version_is_below_1990?
13
+ result = current_rails_version_matches?('<1.99.0')
14
+ result
15
+ end
16
+
17
+ def rails_version_is_below_rc2?
18
+ current_rails_version_matches?('<1.99.1')
19
+ end
20
+
21
+ def rails_version_is_1991?
22
+ current_rails_version_matches?('=1.99.1')
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ NAME
2
+ desert_plugin - creates a directory structure and starter files for a new desert plugin
3
+
4
+ SYNOPSIS
5
+ desert_plugin [plugin name]
6
+
7
+ DESCRIPTION
8
+ |-- vendor
9
+ `-- plugins
10
+ `-- [plugin name]
11
+
12
+ EXAMPLE
13
+ ./script/generate desert_plugin spiffy
14
+
@@ -0,0 +1,40 @@
1
+ class DesertPluginGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ record do |m|
4
+ m.directory "vendor/plugins/#{file_name}"
5
+
6
+ m.directory "vendor/plugins/#{file_name}/app"
7
+ m.directory "vendor/plugins/#{file_name}/app/controllers"
8
+ m.directory "vendor/plugins/#{file_name}/app/helpers"
9
+ m.directory "vendor/plugins/#{file_name}/app/models"
10
+ m.directory "vendor/plugins/#{file_name}/app/views"
11
+
12
+ m.directory "vendor/plugins/#{file_name}/config"
13
+ m.template "routes.rb", "vendor/plugins/#{file_name}/config/routes.rb"
14
+ map_route_from_plugin(m)
15
+
16
+ m.directory "vendor/plugins/#{file_name}/db"
17
+ m.directory "vendor/plugins/#{file_name}/db/migrate"
18
+ m.template "plugin_migration.rb", "vendor/plugins/#{file_name}/db/migrate/001_init_#{file_name}_plugin.rb"
19
+
20
+ m.directory "vendor/plugins/#{file_name}/lib"
21
+
22
+ m.directory "vendor/plugins/#{file_name}/spec"
23
+ m.directory "vendor/plugins/#{file_name}/spec/controllers"
24
+ m.directory "vendor/plugins/#{file_name}/spec/fixtures"
25
+ m.directory "vendor/plugins/#{file_name}/spec/models"
26
+ m.directory "vendor/plugins/#{file_name}/spec/views"
27
+ m.file "spec_helper.rb", "vendor/plugins/#{file_name}/spec/spec_helper.rb"
28
+
29
+ m.file "empty_file", "vendor/plugins/#{file_name}/init.rb"
30
+ end
31
+ end
32
+
33
+ def map_route_from_plugin(m)
34
+ logger.route "adding map.routes_from_plugin(:#{file_name}) to top of routes.rb"
35
+ sentinel = 'ActionController::Routing::Routes.draw do |map|'
36
+ m.gsub_file 'config/routes.rb', /(#{Regexp.escape(sentinel)})/mi do |match|
37
+ "#{match}\n map.routes_from_plugin(:#{file_name})\n"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ class Init<%= class_name %>Plugin < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "<%= plural_name %>", :force => true do |t|
4
+ t.column "some_<%= file_name %>_column", :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :<%= plural_name %>
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ resources :<%= plural_name %>
@@ -0,0 +1,8 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
+ require 'spec'
4
+ require 'spec/rails'
5
+
6
+ Spec::Runner.configure do |config|
7
+ config.fixture_path = "#{File.dirname(__FILE__)}/../spec/fixtures"
8
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: desert
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.1
7
+ date: 2008-03-18 00:00:00 -07:00
8
+ summary: Desert is a component framework for Rails that allows your plugins to be packaged as mini Rails apps.
9
+ require_paths:
10
+ - lib
11
+ email: opensource@pivotallabs.com
12
+ homepage: http://pivotallabs.com
13
+ rubyforge_project: pivotalrb
14
+ description: Desert is a component framework for Rails that allows your plugins to be packaged as mini Rails apps.
15
+ autorequire: desert
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Pivotal Labs
31
+ files:
32
+ - CHANGES
33
+ - MIT-LICENSE
34
+ - README
35
+ - Rakefile
36
+ - init.rb
37
+ - lib/desert.rb
38
+ - lib/generators/desert_plugin/templates/routes.rb
39
+ - lib/generators/desert_plugin/templates/spec_helper.rb
40
+ - lib/generators/desert_plugin/templates/plugin_migration.rb
41
+ - lib/generators/desert_plugin/desert_plugin_generator.rb
42
+ - lib/desert/plugin_templates/1.x/action_mailer.rb
43
+ - lib/desert/plugin_templates/action_view.rb
44
+ - lib/desert/plugin_templates/2.x/action_mailer.rb
45
+ - lib/desert/plugin_templates/action_controller.rb
46
+ - lib/desert/manager.rb
47
+ - lib/desert/rails/1.x/initializer.rb
48
+ - lib/desert/rails/migration.rb
49
+ - lib/desert/rails/migrator.rb
50
+ - lib/desert/rails/2.x/plugin.rb
51
+ - lib/desert/rails/route_set.rb
52
+ - lib/desert/rails/dependencies.rb
53
+ - lib/desert/version_checker.rb
54
+ - lib/desert/ruby/object.rb
55
+ - lib/desert/plugin_migrations/migrator.rb
56
+ - lib/desert/plugin_migrations/extensions/schema_statements.rb
57
+ - lib/desert/plugin.rb
58
+ - lib/generators/desert_plugin
59
+ - lib/generators/desert_plugin/templates
60
+ - lib/generators/desert_plugin/templates/empty_file
61
+ - lib/generators/desert_plugin/USAGE
62
+ test_files: []
63
+
64
+ rdoc_options:
65
+ - --main
66
+ - README
67
+ - --inline-source
68
+ - --line-numbers
69
+ extra_rdoc_files:
70
+ - README
71
+ - CHANGES
72
+ executables: []
73
+
74
+ extensions: []
75
+
76
+ requirements: []
77
+
78
+ dependencies: []
79
+