parlement 0.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 +709 -0
- data/COPYING +223 -0
- data/README +20 -0
- data/Rakefile +136 -0
- data/app/controllers/account_controller.rb +181 -0
- data/app/controllers/application.rb +30 -0
- data/app/controllers/elt_controller.rb +83 -0
- data/app/helpers/account_helper.rb +2 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/elt_helper.rb +37 -0
- data/app/helpers/live_tree.rb +238 -0
- data/app/helpers/mailman.rb +96 -0
- data/app/models/attachment.rb +4 -0
- data/app/models/elt.rb +17 -0
- data/app/models/mail.rb +4 -0
- data/app/models/notifier.rb +13 -0
- data/app/models/person.rb +9 -0
- data/app/models/user.rb +7 -0
- data/app/models/user_notify.rb +75 -0
- data/app/views/account/_help.rhtml +23 -0
- data/app/views/account/_login.rhtml +57 -0
- data/app/views/account/_show.rhtml +31 -0
- data/app/views/account/logout.rhtml +10 -0
- data/app/views/account/signup.rhtml +17 -0
- data/app/views/account/welcome.rhtml +13 -0
- data/app/views/elt/_elt.rhtml +105 -0
- data/app/views/elt/_form.rhtml +31 -0
- data/app/views/elt/_list.rhtml +28 -0
- data/app/views/elt/new.rhtml +102 -0
- data/app/views/elt/rss.rxml +31 -0
- data/app/views/elt/show.rhtml +46 -0
- data/app/views/elt/show_tree.rhtml +8 -0
- data/app/views/layouts/scaffold.rhtml +13 -0
- data/app/views/layouts/top.rhtml +45 -0
- data/app/views/notifier/changeEmail.rhtml +10 -0
- data/config/boot.rb +17 -0
- data/config/database.yml +82 -0
- data/config/environment.rb +92 -0
- data/config/environments/development.rb +17 -0
- data/config/environments/production.rb +17 -0
- data/config/environments/test.rb +17 -0
- data/config/environments/user_environment.rb +1 -0
- data/config/routes.rb +28 -0
- data/db/ROOT/CV.txt +166 -0
- data/db/ROOT/IP.txt +3 -0
- data/db/ROOT/parleR.txt +3 -0
- data/db/ROOT/parlement/security.txt +34 -0
- data/db/ROOT/parlement/test.txt +4 -0
- data/db/ROOT/parlement.txt +51 -0
- data/db/ROOT/perso.txt +215 -0
- data/db/schema.sql +127 -0
- data/lib/data_import.rb +54 -0
- data/lib/file_column.rb +263 -0
- data/lib/file_column_helper.rb +45 -0
- data/lib/localization.rb +88 -0
- data/lib/localizer.rb +88 -0
- data/lib/login_system.rb +87 -0
- data/lib/rails_file_column.rb +19 -0
- data/lib/user_system.rb +101 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/engine_files/README +5 -0
- data/public/engine_files/login_engine/stylesheets/login_engine.css +81 -0
- data/public/favicon.ico +0 -0
- data/public/favicon.png +0 -0
- data/public/images/live_tree_branch_collapsed_icon.gif +0 -0
- data/public/images/live_tree_branch_expanded_icon.gif +0 -0
- data/public/images/live_tree_leaf_icon.gif +0 -0
- data/public/images/live_tree_loading_spinner.gif +0 -0
- data/public/images/webfeed.gif +0 -0
- data/public/javascripts/controls.js +721 -0
- data/public/javascripts/dragdrop.js +519 -0
- data/public/javascripts/effects.js +992 -0
- data/public/javascripts/live_tree.js +749 -0
- data/public/javascripts/prototype.js +1726 -0
- data/public/javascripts/scriptaculous.js +47 -0
- data/public/javascripts/slider.js +258 -0
- data/public/oldREADME +190 -0
- data/public/oldindex.html +78 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/default.css +238 -0
- data/public/stylesheets/live_tree.css +62 -0
- data/public/stylesheets/scaffold.css +74 -0
- data/script/about +3 -0
- data/script/benchmarker +19 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/create_db +7 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/profiler +34 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/test/fixtures/attachments.yml +10 -0
- data/test/fixtures/elts.yml +15 -0
- data/test/fixtures/mails.yml +7 -0
- data/test/fixtures/people.yml +49 -0
- data/test/fixtures/users.yml +41 -0
- data/test/functional/account_controller_test.rb +239 -0
- data/test/functional/elt_controller_test.rb +18 -0
- data/test/mocks/test/time.rb +17 -0
- data/test/mocks/test/user_notify.rb +16 -0
- data/test/test_helper.rb +28 -0
- data/test/unit/attachment_test.rb +14 -0
- data/test/unit/elt_test.rb +14 -0
- data/test/unit/mail_test.rb +14 -0
- data/test/unit/notifier_test.rb +31 -0
- data/test/unit/person_test.rb +24 -0
- data/test/unit/user_test.rb +94 -0
- data/vendor/plugins/engines/CHANGELOG +7 -0
- data/vendor/plugins/engines/README +128 -0
- data/vendor/plugins/engines/init.rb +33 -0
- data/vendor/plugins/engines/lib/action_mailer_extensions.rb +160 -0
- data/vendor/plugins/engines/lib/action_view_extensions.rb +130 -0
- data/vendor/plugins/engines/lib/dependencies_extensions.rb +56 -0
- data/vendor/plugins/engines/lib/engines.rb +292 -0
- data/vendor/plugins/engines/lib/ruby_extensions.rb +127 -0
- data/vendor/plugins/engines/lib/testing_extensions.rb +33 -0
- data/vendor/plugins/engines/test/ruby_extensions_test.rb +94 -0
- data/vendor/plugins/login_engine/README +258 -0
- data/vendor/plugins/login_engine/app/controllers/user_controller.rb +248 -0
- data/vendor/plugins/login_engine/app/helpers/user_helper.rb +88 -0
- data/vendor/plugins/login_engine/app/models/user.rb +7 -0
- data/vendor/plugins/login_engine/app/models/user_notify.rb +75 -0
- data/vendor/plugins/login_engine/app/views/user/_edit.rhtml +11 -0
- data/vendor/plugins/login_engine/app/views/user/_password.rhtml +9 -0
- data/vendor/plugins/login_engine/app/views/user/change_password.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user/edit.rhtml +23 -0
- data/vendor/plugins/login_engine/app/views/user/forgot_password.rhtml +18 -0
- data/vendor/plugins/login_engine/app/views/user/home.rhtml +7 -0
- data/vendor/plugins/login_engine/app/views/user/login.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user/logout.rhtml +8 -0
- data/vendor/plugins/login_engine/app/views/user/signup.rhtml +17 -0
- data/vendor/plugins/login_engine/app/views/user_notify/change_password.rhtml +10 -0
- data/vendor/plugins/login_engine/app/views/user_notify/delete.rhtml +5 -0
- data/vendor/plugins/login_engine/app/views/user_notify/forgot_password.rhtml +11 -0
- data/vendor/plugins/login_engine/app/views/user_notify/pending_delete.rhtml +9 -0
- data/vendor/plugins/login_engine/app/views/user_notify/signup.rhtml +12 -0
- data/vendor/plugins/login_engine/db/schema.rb +25 -0
- data/vendor/plugins/login_engine/init_engine.rb +10 -0
- data/vendor/plugins/login_engine/lib/login_engine/authenticated_system.rb +107 -0
- data/vendor/plugins/login_engine/lib/login_engine/authenticated_user.rb +149 -0
- data/vendor/plugins/login_engine/lib/login_engine.rb +58 -0
- data/vendor/plugins/login_engine/public/stylesheets/login_engine.css +81 -0
- data/vendor/plugins/login_engine/tasks/tasks.rake +4 -0
- data/vendor/plugins/login_engine/test/fixtures/templates/users.yml +41 -0
- data/vendor/plugins/login_engine/test/fixtures/users.yml +41 -0
- data/vendor/plugins/login_engine/test/functional/user_controller_test.rb +533 -0
- data/vendor/plugins/login_engine/test/mocks/mail.rb +14 -0
- data/vendor/plugins/login_engine/test/mocks/time.rb +19 -0
- data/vendor/plugins/login_engine/test/test_helper.rb +15 -0
- data/vendor/plugins/login_engine/test/unit/user_test.rb +94 -0
- metadata +276 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2005 James Adam
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#++
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
require 'engines'
|
|
26
|
+
|
|
27
|
+
#--
|
|
28
|
+
# Create the Engines directory if it isn't present
|
|
29
|
+
#++
|
|
30
|
+
if !File.exist?(Engines.config(:root))
|
|
31
|
+
RAILS_DEFAULT_LOGGER.debug "Creating engines directory in /vendor"
|
|
32
|
+
FileUtils.mkdir_p(Engines.config(:root))
|
|
33
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2004 David Heinemeier Hansson
|
|
3
|
+
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
# Engine Hacks by James Adam, 2005.
|
|
24
|
+
#++
|
|
25
|
+
|
|
26
|
+
# Overriding ActionMailer to teach it about Engines...
|
|
27
|
+
module ActionMailer
|
|
28
|
+
class Base
|
|
29
|
+
|
|
30
|
+
# Initialize the mailer via the given +method_name+. The body will be
|
|
31
|
+
# rendered and a new TMail::Mail object created.
|
|
32
|
+
def create!(method_name, *parameters) #:nodoc:
|
|
33
|
+
initialize_defaults(method_name)
|
|
34
|
+
send(method_name, *parameters)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# If an explicit, textual body has not been set, we check assumptions.
|
|
38
|
+
unless String === @body
|
|
39
|
+
# First, we look to see if there are any likely templates that match,
|
|
40
|
+
# which include the content-type in their file name (i.e.,
|
|
41
|
+
# "the_template_file.text.html.rhtml", etc.). Only do this if parts
|
|
42
|
+
# have not already been specified manually.
|
|
43
|
+
|
|
44
|
+
templates = get_all_templates_for_action(@template)
|
|
45
|
+
|
|
46
|
+
#RAILS_DEFAULT_LOGGER.debug "template: #{@template}; templates: #{templates.inspect}"
|
|
47
|
+
|
|
48
|
+
if @parts.empty?
|
|
49
|
+
|
|
50
|
+
# /app/views/<mailer object name> / <action>.something.rhtml
|
|
51
|
+
|
|
52
|
+
#templates = Dir.glob("#{template_path}/#{@template}.*")
|
|
53
|
+
|
|
54
|
+
# this loop expects an array of paths to actual template files which match
|
|
55
|
+
# the given action name
|
|
56
|
+
templates.each do |path|
|
|
57
|
+
type = (File.basename(path).split(".")[1..-2] || []).join("/")
|
|
58
|
+
#RAILS_DEFAULT_LOGGER.debug "type: #{type}"
|
|
59
|
+
next if type.empty?
|
|
60
|
+
#RAILS_DEFAULT_LOGGER.debug "other bit: #{File.basename(path).split(".")[0..-2].join('.')}"
|
|
61
|
+
@parts << Part.new(:content_type => type,
|
|
62
|
+
:disposition => "inline", :charset => charset,
|
|
63
|
+
:body => render_message(File.basename(path).split(".")[0..-2].join('.'), @body))
|
|
64
|
+
end
|
|
65
|
+
unless @parts.empty?
|
|
66
|
+
@content_type = "multipart/alternative"
|
|
67
|
+
@charset = nil
|
|
68
|
+
@parts = sort_parts(@parts, @implicit_parts_order)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Then, if there were such templates, we check to see if we ought to
|
|
73
|
+
# also render a "normal" template (without the content type). If a
|
|
74
|
+
# normal template exists (or if there were no implicit parts) we render
|
|
75
|
+
# it.
|
|
76
|
+
template_exists = @parts.empty?
|
|
77
|
+
#template_exists ||= Dir.glob("#{template_path}/#{@template}.*").any? { |i| i.split(".").length == 2 }
|
|
78
|
+
template_exists ||= templates.any? { |i| File.basename(i).split(".").length == 2 }
|
|
79
|
+
#RAILS_DEFAULT_LOGGER.debug "template_exists? #{template_exists}"
|
|
80
|
+
@body = render_message(@template, @body) if template_exists
|
|
81
|
+
|
|
82
|
+
# Finally, if there are other message parts and a textual body exists,
|
|
83
|
+
# we shift it onto the front of the parts and set the body to nil (so
|
|
84
|
+
# that create_mail doesn't try to render it in addition to the parts).
|
|
85
|
+
if !@parts.empty? && String === @body
|
|
86
|
+
@parts.unshift Part.new(:charset => charset, :body => @body)
|
|
87
|
+
@body = nil
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# If this is a multipart e-mail add the mime_version if it is not
|
|
92
|
+
# already set.
|
|
93
|
+
@mime_version ||= "1.0" if !@parts.empty?
|
|
94
|
+
|
|
95
|
+
# build the mail object itself
|
|
96
|
+
@mail = create_mail
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# JGA - Modified to pass the method name to initialize_template_class
|
|
103
|
+
def render(opts)
|
|
104
|
+
body = opts.delete(:body)
|
|
105
|
+
initialize_template_class(body, opts[:file]).render(opts)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Return all ActionView template paths from the app and all Engines
|
|
110
|
+
def template_paths
|
|
111
|
+
paths = [template_path]
|
|
112
|
+
Engines::ActiveEngines.each { |engine|
|
|
113
|
+
# add a path for every engine if one exists.
|
|
114
|
+
engine_template_path = File.join(engine.root, "app", "views", mailer_name)
|
|
115
|
+
paths << engine_template_path if File.exists?(engine_template_path)
|
|
116
|
+
}
|
|
117
|
+
paths
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Returns a list of all template paths in the app and Engines
|
|
121
|
+
# which contain templates that might be used for the given action
|
|
122
|
+
def get_all_templates_for_action(action)
|
|
123
|
+
# can we trust uniq! to do this? i'm not sure...
|
|
124
|
+
templates = []
|
|
125
|
+
seen_names = []
|
|
126
|
+
template_paths.each { |path|
|
|
127
|
+
all_templates_for_path = Dir.glob(File.join(path, "#{action}.*"))
|
|
128
|
+
all_templates_for_path.each { |template|
|
|
129
|
+
name = File.basename(template)
|
|
130
|
+
if !seen_names.include?(name)
|
|
131
|
+
seen_names << name
|
|
132
|
+
templates << template
|
|
133
|
+
end
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
templates
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Returns the first path to the given template in our
|
|
140
|
+
# app/Engine 'chain'.
|
|
141
|
+
def find_template_root_for(template)
|
|
142
|
+
all_paths = get_all_templates_for_action(template)
|
|
143
|
+
if all_paths.empty?
|
|
144
|
+
return template_path
|
|
145
|
+
else
|
|
146
|
+
return File.dirname(all_paths[0])
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# JGA - changed here to include the method name that we
|
|
151
|
+
# are interested in, so that we can re-locate the proper
|
|
152
|
+
# template root
|
|
153
|
+
def initialize_template_class(assigns, method_name)
|
|
154
|
+
engine_template = find_template_root_for(method_name)
|
|
155
|
+
ActionView::Base.new(engine_template, assigns, self)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2004 David Heinemeier Hansson
|
|
3
|
+
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
# Engine Hacks by James Adam, 2005.
|
|
24
|
+
#++
|
|
25
|
+
|
|
26
|
+
require 'fileutils'
|
|
27
|
+
|
|
28
|
+
module ::ActionView
|
|
29
|
+
class Base
|
|
30
|
+
private
|
|
31
|
+
def full_template_path(template_path, extension)
|
|
32
|
+
|
|
33
|
+
# If the template exists in the normal application directory,
|
|
34
|
+
# return that path
|
|
35
|
+
default_template = "#{@base_path}/#{template_path}.#{extension}"
|
|
36
|
+
return default_template if File.exist?(default_template)
|
|
37
|
+
|
|
38
|
+
# Otherwise, check in the engines to see if the template can be found there.
|
|
39
|
+
# Load this in order so that more recently started Engines will take priority.
|
|
40
|
+
Engines::ActiveEngines.each do |engine|
|
|
41
|
+
site_specific_path = File.join(engine.root, 'app', 'views', template_path.to_s + '.' + extension.to_s)
|
|
42
|
+
return site_specific_path if File.exist?(site_specific_path)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# If it cannot be found anywhere, return the default path, where the
|
|
46
|
+
# user *should* have put it.
|
|
47
|
+
return "#{@base_path}/#{template_path}.#{extension}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# add methods to handle including javascripts and stylesheets
|
|
53
|
+
module Helpers
|
|
54
|
+
module AssetTagHelper
|
|
55
|
+
# Returns a stylesheet link tag to the named stylesheet(s) for the given
|
|
56
|
+
# engine. A stylesheet with the same name as the engine is included automatically.
|
|
57
|
+
# If other names are supplied, those stylesheets from within the same engine
|
|
58
|
+
# will be linked too.
|
|
59
|
+
#
|
|
60
|
+
# engine_stylesheet "my_engine" =>
|
|
61
|
+
# <link href="/engine_files/my_engine/stylesheets/my_engine.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
62
|
+
#
|
|
63
|
+
# engine_stylesheet "my_engine", "another_file", "one_more" =>
|
|
64
|
+
# <link href="/engine_files/my_engine/stylesheets/my_engine.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
65
|
+
# <link href="/engine_files/my_engine/stylesheets/another_file.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
66
|
+
# <link href="/engine_files/my_engine/stylesheets/one_more.css" media="screen" rel="Stylesheet" type="text/css" />
|
|
67
|
+
#
|
|
68
|
+
# Any options supplied as a Hash as the last argument will be processed as in
|
|
69
|
+
# stylesheet_link_tag.
|
|
70
|
+
#
|
|
71
|
+
def engine_stylesheet(engine_name, *sources)
|
|
72
|
+
stylesheet_link_tag(*convert_public_sources(engine_name, :stylesheet, sources))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Returns a javascript link tag to the named stylesheet(s) for the given
|
|
76
|
+
# engine. A javascript file with the same name as the engine is included automatically.
|
|
77
|
+
# If other names are supplied, those javascript from within the same engine
|
|
78
|
+
# will be linked too.
|
|
79
|
+
#
|
|
80
|
+
# engine_javascript "my_engine" =>
|
|
81
|
+
# <script type="text/javascript" src="/engine_files/my_engine/javascripts/my_engine.js"></script>
|
|
82
|
+
#
|
|
83
|
+
# engine_javascript "my_engine", "another_file", "one_more" =>
|
|
84
|
+
# <script type="text/javascript" src="/engine_files/my_engine/javascripts/my_engine.js"></script>
|
|
85
|
+
# <script type="text/javascript" src="/engine_files/my_engine/javascripts/another_file.js"></script>
|
|
86
|
+
# <script type="text/javascript" src="/engine_files/my_engine/javascripts/one_more.js"></script>
|
|
87
|
+
#
|
|
88
|
+
# Any options supplied as a Hash as the last argument will be processed as in
|
|
89
|
+
# javascript_include_tag.
|
|
90
|
+
#
|
|
91
|
+
def engine_javascript(engine_name, *sources)
|
|
92
|
+
javascript_include_tag(*convert_public_sources(engine_name, :javascript, sources))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
# convert the engine public file sources into actual public paths
|
|
97
|
+
# type:
|
|
98
|
+
# :stylesheet
|
|
99
|
+
# :javascript
|
|
100
|
+
# if engine_name does not end in engine, "_engine" is appended automatically.
|
|
101
|
+
def convert_public_sources(engine_name, type, sources)
|
|
102
|
+
options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { }
|
|
103
|
+
new_sources = []
|
|
104
|
+
|
|
105
|
+
full_engine_name = engine_name
|
|
106
|
+
full_engine_name += "_engine" if !(engine_name =~ /\_engine$/)
|
|
107
|
+
|
|
108
|
+
case type
|
|
109
|
+
when :javascript
|
|
110
|
+
type_dir = "javascripts"
|
|
111
|
+
ext = "js"
|
|
112
|
+
when :stylesheet
|
|
113
|
+
type_dir = "stylesheets"
|
|
114
|
+
ext = "css"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
default = "/#{Engines.config(:public_dir)}/#{full_engine_name}/#{type_dir}/#{engine_name}"
|
|
118
|
+
if defined?(RAILS_ROOT) && File.exists?(File.join(RAILS_ROOT, "public", "#{default}.#{ext}"))
|
|
119
|
+
new_sources << default
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
sources.each { |name|
|
|
123
|
+
new_sources << "/#{Engines.config(:public_dir)}/#{full_engine_name}/#{type_dir}/#{name}"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
new_sources << options
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2004 David Heinemeier Hansson
|
|
3
|
+
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
# Engine Hacks by James Adam, 2005.
|
|
24
|
+
#++
|
|
25
|
+
|
|
26
|
+
module ::Dependencies
|
|
27
|
+
def require_or_load(file_name)
|
|
28
|
+
# try and load the framework code first
|
|
29
|
+
# can't use model, as there's nothing in the name to indicate that the file is a 'model' file
|
|
30
|
+
# rather than a library or anything else.
|
|
31
|
+
['controller', 'helper'].each do |type|
|
|
32
|
+
if file_name.include?('_' + type)
|
|
33
|
+
Engines::ActiveEngines.reverse.each do |engine|
|
|
34
|
+
engine_file_name = File.join(engine.root, 'app', "#{type}s", File.basename(file_name))
|
|
35
|
+
engine_file_name += '.rb' unless engine_file_name[-3..-1] == '.rb'
|
|
36
|
+
if File.exist? engine_file_name
|
|
37
|
+
load? ? load(engine_file_name) : require(engine_file_name)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# finally, load any application-specific controller classes.
|
|
44
|
+
file_name = "#{file_name}.rb" unless ! load? || file_name [-3..-1] == '.rb'
|
|
45
|
+
load? ? load(file_name) : require(file_name)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class RootLoadingModule < LoadingModule
|
|
49
|
+
# hack to allow adding to the load paths within the Rails Dependencies mechanism.
|
|
50
|
+
# this allows Engine classes to be unloaded and loaded along with standard
|
|
51
|
+
# Rails application classes.
|
|
52
|
+
def add_path(path)
|
|
53
|
+
@load_paths << (path.kind_of?(ConstantLoadPath) ? path : ConstantLoadPath.new(path))
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Copyright (c) 2005 James Adam
|
|
3
|
+
#
|
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
5
|
+
# a copy of this software and associated documentation files (the
|
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
10
|
+
# the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be
|
|
13
|
+
# included in all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
#++
|
|
23
|
+
|
|
24
|
+
require 'ruby_extensions'
|
|
25
|
+
require 'dependencies_extensions'
|
|
26
|
+
require 'action_view_extensions'
|
|
27
|
+
require 'action_mailer_extensions'
|
|
28
|
+
require 'testing_extensions'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Holds the Rails Engine loading logic and default constants
|
|
32
|
+
module ::Engines
|
|
33
|
+
|
|
34
|
+
# An array of active engines (actually paths to active engines)
|
|
35
|
+
ActiveEngines = []
|
|
36
|
+
|
|
37
|
+
# The root directory for engines
|
|
38
|
+
config :root, File.join(RAILS_ROOT, "vendor", "plugins")
|
|
39
|
+
|
|
40
|
+
# The name of the public folder under which engine files are copied
|
|
41
|
+
config :public_dir, "engine_files"
|
|
42
|
+
|
|
43
|
+
class << self
|
|
44
|
+
|
|
45
|
+
# Initializes a Rails Engine by loading the engine's init.rb file and
|
|
46
|
+
# ensuring that any engine controllers are added to the load path.
|
|
47
|
+
# This will also copy any files in a directory named 'public'
|
|
48
|
+
# into the public webserver directory. Example usage:
|
|
49
|
+
#
|
|
50
|
+
# Engines.start :login
|
|
51
|
+
# Engines.start :login_engine # equivalent
|
|
52
|
+
#
|
|
53
|
+
# A list of engine names can be specified:
|
|
54
|
+
#
|
|
55
|
+
# Engines.start :login, :user, :wiki
|
|
56
|
+
#
|
|
57
|
+
# The engines will be loaded in the order given.
|
|
58
|
+
# If no engine names are given, all engines will be started.
|
|
59
|
+
#
|
|
60
|
+
# Options can include:
|
|
61
|
+
# * :copy_files => true | false
|
|
62
|
+
# * :engine_name => the name within the plugins directory this engine resides, if
|
|
63
|
+
# different from the first parameter
|
|
64
|
+
#
|
|
65
|
+
# Note that if a list of engines is given, the options will apply to ALL engines.
|
|
66
|
+
def start(*args)
|
|
67
|
+
|
|
68
|
+
options = (args.last.is_a? Hash) ? args.pop : {}
|
|
69
|
+
|
|
70
|
+
if args.empty?
|
|
71
|
+
start_all
|
|
72
|
+
return
|
|
73
|
+
else
|
|
74
|
+
args.each do |engine_name|
|
|
75
|
+
start_engine(engine_name, options)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Starts all available engines. Plugins are considered engines if they
|
|
81
|
+
# include an init_engine.rb file, or they are named <something>_engine.
|
|
82
|
+
def start_all()
|
|
83
|
+
plugins = Dir[File.join(config(:root), "*")]
|
|
84
|
+
RAILS_DEFAULT_LOGGER.debug "considering plugins: #{plugins.inspect}"
|
|
85
|
+
plugins.each { |plugin|
|
|
86
|
+
engine_name = File.basename(plugin)
|
|
87
|
+
if File.exist?(File.join(plugin, "init_engine.rb")) or
|
|
88
|
+
(engine_name =~ /_engine$/)
|
|
89
|
+
# start the engine...
|
|
90
|
+
start(engine_name)
|
|
91
|
+
end
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def start_engine(engine_name, options={})
|
|
96
|
+
|
|
97
|
+
current_engine = Engine.new
|
|
98
|
+
current_engine.name = options[:engine_name] || engine_name
|
|
99
|
+
current_engine.root = get_engine_dir(engine_name)
|
|
100
|
+
|
|
101
|
+
#engine_name = options[:engine_name] || engine
|
|
102
|
+
#engine_dir = get_engine_dir(engine_name)
|
|
103
|
+
|
|
104
|
+
RAILS_DEFAULT_LOGGER.debug "Trying to start engine '#{current_engine.name}' from '#{File.expand_path(current_engine.root)}'"
|
|
105
|
+
|
|
106
|
+
# put this engine at the front of the ActiveEngines list
|
|
107
|
+
Engines::ActiveEngines.unshift current_engine #engine_dir
|
|
108
|
+
|
|
109
|
+
# add the code directories of this engine to the load path
|
|
110
|
+
add_engine_to_load_path(current_engine) #engine_dir)
|
|
111
|
+
|
|
112
|
+
# load the engine's init.rb file
|
|
113
|
+
startup_file = File.join(current_engine.root, "init_engine.rb")
|
|
114
|
+
if File.exist?(startup_file)
|
|
115
|
+
eval(IO.read(startup_file), binding, startup_file)
|
|
116
|
+
#require startup_file
|
|
117
|
+
else
|
|
118
|
+
RAILS_DEFAULT_LOGGER.warn "WARNING: No init_engines.rb file found for engine '#{current_engine.name}'..."
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# add the controller path to the Dependency system
|
|
122
|
+
Controllers.add_path(File.join(current_engine.root, 'app', 'controllers'))
|
|
123
|
+
|
|
124
|
+
# copy the files unless indicated otherwise
|
|
125
|
+
if options[:copy_files] != false
|
|
126
|
+
copy_engine_files(current_engine)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Adds all directories in the /app and /lib directories within the engine
|
|
131
|
+
# to the load path
|
|
132
|
+
def add_engine_to_load_path(engine)
|
|
133
|
+
# Add ALL paths under the engine root to the load path
|
|
134
|
+
app_dirs = [engine.root + "/app/controllers", engine.root + "/app/models",
|
|
135
|
+
engine.root + "/app/helpers"]
|
|
136
|
+
lib_dirs = Dir[engine.root + "/lib/**/*"] + [engine.root, "lib"]
|
|
137
|
+
load_paths = (app_dirs + lib_dirs).select { |d|
|
|
138
|
+
File.directory?(d)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Remove other engines from the $LOAD_PATH bby matching against the engine.root values
|
|
142
|
+
# in ActiveEngines. Store the removed engines in the order they came off.
|
|
143
|
+
#
|
|
144
|
+
# This is a hack - if Ticket http://dev.rubyonrails.com/ticket/2817 is accepted, then
|
|
145
|
+
# a new Engines system can be developed which only modifies load paths in one sweep,
|
|
146
|
+
# thus avoiding this.
|
|
147
|
+
#
|
|
148
|
+
|
|
149
|
+
old_plugin_paths = []
|
|
150
|
+
# assumes that all engines are at the bottom of the $LOAD_PATH
|
|
151
|
+
while (File.expand_path($LOAD_PATH.last).index(File.expand_path(Engines.config(:root))) == 0) do
|
|
152
|
+
old_plugin_paths.unshift($LOAD_PATH.pop)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# add these LAST on the load path.
|
|
157
|
+
load_paths.reverse.each { |dir|
|
|
158
|
+
if File.directory?(dir)
|
|
159
|
+
RAILS_DEFAULT_LOGGER.debug "adding #{File.expand_path(dir)} to the load path"
|
|
160
|
+
$LOAD_PATH.push(File.expand_path(dir))
|
|
161
|
+
end
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# Add the other engines back onto the bottom of the $LOAD_PATH. Put them back on in
|
|
165
|
+
# the same order.
|
|
166
|
+
$LOAD_PATH.push(*old_plugin_paths)
|
|
167
|
+
$LOAD_PATH.uniq!
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Replicates the subdirectories under the engine's /public directory into
|
|
171
|
+
# the corresponding public directory.
|
|
172
|
+
def copy_engine_files(engine)
|
|
173
|
+
|
|
174
|
+
#engine_dir = get_engine_dir(engine)
|
|
175
|
+
|
|
176
|
+
# create the /public/frameworks directory if it doesn't exist
|
|
177
|
+
public_engine_dir = File.expand_path(File.join(RAILS_ROOT, "public", Engines.config(:public_dir)))
|
|
178
|
+
|
|
179
|
+
if !File.exists?(public_engine_dir)
|
|
180
|
+
# create the public/engines directory, with a warning message in it.
|
|
181
|
+
RAILS_DEFAULT_LOGGER.debug "Creating public engine files directory '#{public_engine_dir}'"
|
|
182
|
+
FileUtils.mkdir(public_engine_dir)
|
|
183
|
+
File.open(File.join(public_engine_dir, "README"), "w") do |f|
|
|
184
|
+
f.puts <<EOS
|
|
185
|
+
Files in this directory are automatically generated from your Rails Engines.
|
|
186
|
+
They are copied from the 'public' directories of each engine into this directory
|
|
187
|
+
each time Rails starts (server, console... any time 'start_engine' is called).
|
|
188
|
+
Any edits you make will NOT persist across the next server restart; instead you
|
|
189
|
+
should edit the files within the <engine_name>/public directory itself.
|
|
190
|
+
EOS
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
source = File.join(engine.root, "public") #engine_dir, "public")
|
|
195
|
+
RAILS_DEFAULT_LOGGER.debug "Attempting to copy public engine files from '#{source}'"
|
|
196
|
+
|
|
197
|
+
# if there is no public directory, just return after this file
|
|
198
|
+
return if !File.exist?(source)
|
|
199
|
+
|
|
200
|
+
source_files = Dir[source + "/**/*"]
|
|
201
|
+
source_dirs = source_files.select { |d| File.directory?(d) }
|
|
202
|
+
source_files -= source_dirs
|
|
203
|
+
|
|
204
|
+
RAILS_DEFAULT_LOGGER.debug "source dirs: #{source_dirs.inspect}"
|
|
205
|
+
|
|
206
|
+
# ensure that we are copying to <something>_engine, whatever the user gives us
|
|
207
|
+
full_engine_name = engine.name
|
|
208
|
+
full_engine_name += "_engine" if !(full_engine_name =~ /\_engine$/)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# create all the directories, transforming the old path into the new path
|
|
212
|
+
source_dirs.uniq.each { |dir|
|
|
213
|
+
begin
|
|
214
|
+
|
|
215
|
+
# strip out the base path and add the result to the public path
|
|
216
|
+
relative_dir = dir.gsub(File.join(engine.root, "public"), full_engine_name)
|
|
217
|
+
target_dir = File.join(public_engine_dir, relative_dir)
|
|
218
|
+
unless File.exist?(target_dir)
|
|
219
|
+
RAILS_DEFAULT_LOGGER.debug "creating directory '#{target_dir}'"
|
|
220
|
+
FileUtils.mkdir_p(File.join(public_engine_dir, relative_dir))
|
|
221
|
+
end
|
|
222
|
+
rescue Exception => e
|
|
223
|
+
raise "Could not create directory #{target_dir}: \n" + e
|
|
224
|
+
end
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# copy all the files, transforming the old path into the new path
|
|
230
|
+
source_files.uniq.each { |file|
|
|
231
|
+
begin
|
|
232
|
+
# change the path from the ENGINE ROOT to the public directory root for this engine
|
|
233
|
+
target = file.gsub(File.join(engine.root, "public"),
|
|
234
|
+
File.join(public_engine_dir, full_engine_name))
|
|
235
|
+
unless File.exist?(target) && FileUtils.identical?(file, target)
|
|
236
|
+
RAILS_DEFAULT_LOGGER.debug "copying file '#{file}' to '#{target}'"
|
|
237
|
+
FileUtils.cp(file, target)
|
|
238
|
+
end
|
|
239
|
+
rescue Exception => e
|
|
240
|
+
raise "Could not copy #{file} to #{target}: \n" + e
|
|
241
|
+
end
|
|
242
|
+
}
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
#private
|
|
247
|
+
# Return the directory in which this engine is present
|
|
248
|
+
def get_engine_dir(engine_name)
|
|
249
|
+
engine_dir=File.join(Engines.config(:root), engine_name.to_s)
|
|
250
|
+
|
|
251
|
+
if !File.exist?(engine_dir)
|
|
252
|
+
# try adding "_engine" to the end of the path.
|
|
253
|
+
engine_dir += "_engine"
|
|
254
|
+
if !File.exist?(engine_dir)
|
|
255
|
+
raise "Cannot find the engine '#{engine_name}' in either /vendor/plugins/#{engine} or /vendor/plugins/#{engine}_engine..."
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
engine_dir
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Returns the Engine object for the specified engine, e.g.:
|
|
263
|
+
# Engines.get(:login)
|
|
264
|
+
def get(name)
|
|
265
|
+
ActiveEngines.find { |e| e.name == name.to_s || e.name == "#{name}_engine" }
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Returns the Engine object for the current engine, i.e. the engine
|
|
269
|
+
# in which the currently executing code lies.
|
|
270
|
+
def current()
|
|
271
|
+
#puts caller.inspect
|
|
272
|
+
#puts ">>> " + caller[0]
|
|
273
|
+
current_file = caller[0]
|
|
274
|
+
ActiveEngines.find do |engine|
|
|
275
|
+
File.expand_path(current_file).index(File.expand_path(engine.root)) == 0
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# A simple class for holding information about loaded engines
|
|
282
|
+
class Engine
|
|
283
|
+
|
|
284
|
+
# Returns the base path of this engine
|
|
285
|
+
attr_accessor :root
|
|
286
|
+
|
|
287
|
+
# Returns the name of this engine
|
|
288
|
+
attr_reader :name
|
|
289
|
+
|
|
290
|
+
def name=(val) @name = val.to_s end
|
|
291
|
+
def to_s() "Engine<#{@name}>" end
|
|
292
|
+
end
|