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
|
module Rails
# The Plugin class should be an object which provides the following methods:
#
# * +name+ - Used during initialisation to order the plugin (based on name and
# the contents of <tt>config.plugins</tt>).
# * +valid?+ - Returns true if this plugin can be loaded.
# * +load_paths+ - Each path within the returned array will be added to the <tt>$LOAD_PATH</tt>.
# * +load+ - Finally 'load' the plugin.
#
# These methods are expected by the Rails::Plugin::Locator and Rails::Plugin::Loader classes.
# The default implementation returns the <tt>lib</tt> directory as its <tt>load_paths</tt>,
# and evaluates <tt>init.rb</tt> when <tt>load</tt> is called.
#
# You can also inspect the about.yml data programmatically:
#
# plugin = Rails::Plugin.new(path_to_my_plugin)
# plugin.about["author"] # => "James Adam"
# plugin.about["url"] # => "http://interblah.net"
class Plugin
include Comparable
attr_reader :directory, :name
def initialize(directory)
@directory = directory
@name = File.basename(@directory) rescue nil
@loaded = false
end
def valid?
File.directory?(directory) && (has_app_directory? || has_lib_directory? || has_init_file?)
end
# Returns a list of paths this plugin wishes to make available in <tt>$LOAD_PATH</tt>.
def load_paths
report_nonexistant_or_empty_plugin! unless valid?
returning [] do |load_paths|
load_paths << lib_path if has_lib_directory?
load_paths << app_paths if has_app_directory?
end.flatten
end
# Evaluates a plugin's init.rb file.
def load(initializer)
return if loaded?
report_nonexistant_or_empty_plugin! unless valid?
evaluate_init_rb(initializer)
@loaded = true
end
def loaded?
@loaded
end
def <=>(other_plugin)
name <=> other_plugin.name
end
def about
@about ||= load_about_information
end
private
def load_about_information
about_yml_path = File.join(@directory, "about.yml")
parsed_yml = File.exist?(about_yml_path) ? YAML.load(File.read(about_yml_path)) : {}
parsed_yml || {}
rescue Exception
{}
end
def report_nonexistant_or_empty_plugin!
raise LoadError, "Can not find the plugin named: #{name}"
end
def app_paths
[
File.join(directory, 'app', 'models'),
File.join(directory, 'app', 'controllers'),
File.join(directory, 'app', 'helpers')
]
end
def lib_path
File.join(directory, 'lib')
end
def classic_init_path
File.join(directory, 'init.rb')
end
def gem_init_path
File.join(directory, 'rails', 'init.rb')
end
def init_path
File.file?(gem_init_path) ? gem_init_path : classic_init_path
end
def has_app_directory?
File.directory?(File.join(directory, 'app'))
end
def has_lib_directory?
File.directory?(lib_path)
end
def has_init_file?
File.file?(init_path)
end
def evaluate_init_rb(initializer)
if has_init_file?
silence_warnings do
# Allow plugins to reference the current configuration object
config = initializer.configuration
eval(IO.read(init_path), binding, init_path)
end
end
end
end
# This Plugin subclass represents a Gem plugin. Although RubyGems has already
# taken care of $LOAD_PATHs, it exposes its load_paths to add them
# to Dependencies.load_paths.
class GemPlugin < Plugin
# Initialize this plugin from a Gem::Specification.
def initialize(spec, gem)
directory = spec.full_gem_path
super(directory)
@name = spec.name
end
def init_path
File.join(directory, 'rails', 'init.rb')
end
end
end
|