rails_product 0.5

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.
Files changed (114) hide show
  1. data/CHANGELOG +619 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +195 -0
  4. data/Rakefile +413 -0
  5. data/bin/benchmarker +19 -0
  6. data/bin/breakpointer +3 -0
  7. data/bin/breakpointer_for_gem +4 -0
  8. data/bin/console +23 -0
  9. data/bin/console_sandbox +0 -0
  10. data/bin/destroy +7 -0
  11. data/bin/generate +7 -0
  12. data/bin/listener +86 -0
  13. data/bin/process/reaper +123 -0
  14. data/bin/process/spawner +54 -0
  15. data/bin/process/spinner +60 -0
  16. data/bin/profiler +34 -0
  17. data/bin/rails +17 -0
  18. data/bin/rails_product +17 -0
  19. data/bin/runner +28 -0
  20. data/bin/server +125 -0
  21. data/bin/tracker +69 -0
  22. data/bin/update +5 -0
  23. data/configs/apache/vhost.example.conf +42 -0
  24. data/configs/apache.conf +40 -0
  25. data/configs/database.yml +23 -0
  26. data/configs/empty.log +0 -0
  27. data/configs/routes.rb +19 -0
  28. data/dispatches/dispatch.fcgi +24 -0
  29. data/dispatches/dispatch.rb +10 -0
  30. data/dispatches/gateway.cgi +97 -0
  31. data/doc/README_FOR_APP +2 -0
  32. data/environments/development.rb +14 -0
  33. data/environments/environment.rb +101 -0
  34. data/environments/production.rb +8 -0
  35. data/environments/test.rb +17 -0
  36. data/fresh_rakefile +223 -0
  37. data/helpers/application.rb +4 -0
  38. data/helpers/application_helper.rb +3 -0
  39. data/helpers/test_helper.rb +26 -0
  40. data/html/404.html +8 -0
  41. data/html/500.html +8 -0
  42. data/html/favicon.ico +0 -0
  43. data/html/index.html +78 -0
  44. data/html/javascripts/controls.js +446 -0
  45. data/html/javascripts/dragdrop.js +537 -0
  46. data/html/javascripts/effects.js +612 -0
  47. data/html/javascripts/prototype.js +1038 -0
  48. data/html/robots.txt +1 -0
  49. data/lib/binding_of_caller.rb +83 -0
  50. data/lib/breakpoint.rb +523 -0
  51. data/lib/breakpoint_client.rb +196 -0
  52. data/lib/code_statistics.rb +104 -0
  53. data/lib/console_sandbox.rb +6 -0
  54. data/lib/dispatcher.rb +59 -0
  55. data/lib/fcgi_handler.rb +156 -0
  56. data/lib/productize.rb +116 -0
  57. data/lib/rails_generator/base.rb +203 -0
  58. data/lib/rails_generator/commands.rb +409 -0
  59. data/lib/rails_generator/generators/applications/app/USAGE +16 -0
  60. data/lib/rails_generator/generators/applications/app/app_generator.rb +126 -0
  61. data/lib/rails_generator/generators/applications/productized_app/USAGE +16 -0
  62. data/lib/rails_generator/generators/applications/productized_app/productized_app_generator.rb +133 -0
  63. data/lib/rails_generator/generators/components/controller/USAGE +30 -0
  64. data/lib/rails_generator/generators/components/controller/controller_generator.rb +38 -0
  65. data/lib/rails_generator/generators/components/controller/templates/controller.rb +10 -0
  66. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +18 -0
  67. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  68. data/lib/rails_generator/generators/components/controller/templates/view.rhtml +2 -0
  69. data/lib/rails_generator/generators/components/mailer/USAGE +19 -0
  70. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +32 -0
  71. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +3 -0
  72. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +13 -0
  73. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +37 -0
  74. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +3 -0
  75. data/lib/rails_generator/generators/components/migration/USAGE +14 -0
  76. data/lib/rails_generator/generators/components/migration/migration_generator.rb +9 -0
  77. data/lib/rails_generator/generators/components/migration/templates/migration.rb +7 -0
  78. data/lib/rails_generator/generators/components/model/USAGE +17 -0
  79. data/lib/rails_generator/generators/components/model/model_generator.rb +18 -0
  80. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +5 -0
  81. data/lib/rails_generator/generators/components/model/templates/model.rb +2 -0
  82. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +14 -0
  83. data/lib/rails_generator/generators/components/scaffold/USAGE +32 -0
  84. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +178 -0
  85. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +54 -0
  86. data/lib/rails_generator/generators/components/scaffold/templates/form.rhtml +3 -0
  87. data/lib/rails_generator/generators/components/scaffold/templates/form_scaffolding.rhtml +1 -0
  88. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +98 -0
  89. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  90. data/lib/rails_generator/generators/components/scaffold/templates/layout.rhtml +13 -0
  91. data/lib/rails_generator/generators/components/scaffold/templates/style.css +74 -0
  92. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.rhtml +9 -0
  93. data/lib/rails_generator/generators/components/scaffold/templates/view_list.rhtml +27 -0
  94. data/lib/rails_generator/generators/components/scaffold/templates/view_new.rhtml +8 -0
  95. data/lib/rails_generator/generators/components/scaffold/templates/view_show.rhtml +8 -0
  96. data/lib/rails_generator/generators/components/web_service/USAGE +28 -0
  97. data/lib/rails_generator/generators/components/web_service/templates/api_definition.rb +5 -0
  98. data/lib/rails_generator/generators/components/web_service/templates/controller.rb +8 -0
  99. data/lib/rails_generator/generators/components/web_service/templates/functional_test.rb +19 -0
  100. data/lib/rails_generator/generators/components/web_service/web_service_generator.rb +29 -0
  101. data/lib/rails_generator/lookup.rb +206 -0
  102. data/lib/rails_generator/manifest.rb +53 -0
  103. data/lib/rails_generator/options.rb +134 -0
  104. data/lib/rails_generator/scripts/destroy.rb +7 -0
  105. data/lib/rails_generator/scripts/generate.rb +7 -0
  106. data/lib/rails_generator/scripts/update.rb +12 -0
  107. data/lib/rails_generator/scripts.rb +83 -0
  108. data/lib/rails_generator/simple_logger.rb +46 -0
  109. data/lib/rails_generator/spec.rb +44 -0
  110. data/lib/rails_generator.rb +43 -0
  111. data/lib/rubyprof_ext.rb +35 -0
  112. data/lib/webrick_server.rb +148 -0
  113. data/sites/fresh_rakefile +176 -0
  114. metadata +250 -0
@@ -0,0 +1,196 @@
1
+ require 'breakpoint'
2
+ require 'optparse'
3
+ require 'timeout'
4
+
5
+ Options = {
6
+ :ClientURI => nil,
7
+ :ServerURI => "druby://localhost:42531",
8
+ :RetryDelay => 2,
9
+ :Permanent => true,
10
+ :Verbose => false
11
+ }
12
+
13
+ ARGV.options do |opts|
14
+ script_name = File.basename($0)
15
+ opts.banner = [
16
+ "Usage: ruby #{script_name} [Options] [server uri]",
17
+ "",
18
+ "This tool lets you connect to a breakpoint service ",
19
+ "which was started via Breakpoint.activate_drb.",
20
+ "",
21
+ "The server uri defaults to druby://localhost:42531"
22
+ ].join("\n")
23
+
24
+ opts.separator ""
25
+
26
+ opts.on("-c", "--client-uri=uri",
27
+ "Run the client on the specified uri.",
28
+ "This can be used to specify the port",
29
+ "that the client uses to allow for back",
30
+ "connections from the server.",
31
+ "Default: Find a good URI automatically.",
32
+ "Example: -c druby://localhost:12345"
33
+ ) { |Options[:ClientURI]| }
34
+
35
+ opts.on("-s", "--server-uri=uri",
36
+ "Connect to the server specified at the",
37
+ "specified uri.",
38
+ "Default: druby://localhost:42531"
39
+ ) { |Options[:ServerURI]| }
40
+
41
+ opts.on("-R", "--retry-delay=delay", Integer,
42
+ "Automatically try to reconnect to the",
43
+ "server after delay seconds when the",
44
+ "connection failed or timed out.",
45
+ "A value of 0 disables automatical",
46
+ "reconnecting completely.",
47
+ "Default: 10"
48
+ ) { |Options[:RetryDelay]| }
49
+
50
+ opts.on("-P", "--[no-]permanent",
51
+ "Run the breakpoint client in permanent mode.",
52
+ "This means that the client will keep continue",
53
+ "running even after the server has closed the",
54
+ "connection. Useful for example in Rails."
55
+ ) { |Options[:Permanent]| }
56
+
57
+ opts.on("-V", "--[no-]verbose",
58
+ "Run the breakpoint client in verbose mode.",
59
+ "Will produce more messages, for example between",
60
+ "individual breakpoints. This might help in seeing",
61
+ "that the breakpoint client is still alive, but adds",
62
+ "quite a bit of clutter."
63
+ ) { |Options[:Verbose]| }
64
+
65
+ opts.separator ""
66
+
67
+ opts.on("-h", "--help",
68
+ "Show this help message."
69
+ ) { puts opts; exit }
70
+ opts.on("-v", "--version",
71
+ "Display the version information."
72
+ ) do
73
+ id = %q$Id: breakpoint_client.rb 91 2005-02-04 22:34:08Z flgr $
74
+ puts id.sub("Id: ", "")
75
+ puts "(Breakpoint::Version = #{Breakpoint::Version})"
76
+ exit
77
+ end
78
+
79
+ opts.parse!
80
+ end
81
+
82
+ Options[:ServerURI] = ARGV[0] if ARGV[0]
83
+
84
+ module Handlers
85
+ extend self
86
+
87
+ def breakpoint_handler(workspace, message)
88
+ puts message
89
+ IRB.start(nil, nil, workspace)
90
+
91
+ puts ""
92
+ if Options[:Verbose] then
93
+ puts "Resumed execution. Waiting for next breakpoint...", ""
94
+ end
95
+ end
96
+
97
+ def eval_handler(code)
98
+ result = eval(code, TOPLEVEL_BINDING)
99
+ if result then
100
+ DRbObject.new(result)
101
+ else
102
+ result
103
+ end
104
+ end
105
+
106
+ def collision_handler()
107
+ msg = [
108
+ " *** Breakpoint service collision ***",
109
+ " Another Breakpoint service tried to use the",
110
+ " port already occupied by this one. It will",
111
+ " keep waiting until this Breakpoint service",
112
+ " is shut down.",
113
+ " ",
114
+ " If you are using the Breakpoint library for",
115
+ " debugging a Rails or other CGI application",
116
+ " this likely means that this Breakpoint",
117
+ " session belongs to an earlier, outdated",
118
+ " request and should be shut down via 'exit'."
119
+ ].join("\n")
120
+
121
+ if RUBY_PLATFORM["win"] then
122
+ # This sucks. Sorry, I'm not doing this because
123
+ # I like funky message boxes -- I need to do this
124
+ # because on Windows I have no way of displaying
125
+ # my notification via puts() when gets() is still
126
+ # being performed on STDIN. I have not found a
127
+ # better solution.
128
+ begin
129
+ require 'tk'
130
+ root = TkRoot.new { withdraw }
131
+ Tk.messageBox('message' => msg, 'type' => 'ok')
132
+ root.destroy
133
+ rescue Exception
134
+ puts "", msg, ""
135
+ end
136
+ else
137
+ puts "", msg, ""
138
+ end
139
+ end
140
+ end
141
+
142
+ # Used for checking whether we are currently in the reconnecting loop.
143
+ reconnecting = false
144
+
145
+ loop do
146
+ DRb.start_service(Options[:ClientURI])
147
+
148
+ begin
149
+ service = DRbObject.new(nil, Options[:ServerURI])
150
+
151
+ begin
152
+ ehandler = Handlers.method(:eval_handler)
153
+ chandler = Handlers.method(:collision_handler)
154
+ handler = Handlers.method(:breakpoint_handler)
155
+ service.eval_handler = ehandler
156
+ service.collision_handler = chandler
157
+ service.handler = handler
158
+
159
+ reconnecting = false
160
+ if Options[:Verbose] then
161
+ puts "Connection established. Waiting for breakpoint...", ""
162
+ end
163
+
164
+ loop do
165
+ begin
166
+ service.ping
167
+ rescue DRb::DRbConnError => error
168
+ puts "Server exited. Closing connection...", ""
169
+ exit! unless Options[:Permanent]
170
+ break
171
+ end
172
+
173
+ sleep(0.5)
174
+ end
175
+ ensure
176
+ service.eval_handler = nil
177
+ service.collision_handler = nil
178
+ service.handler = nil
179
+ end
180
+ rescue Exception => error
181
+ if Options[:RetryDelay] > 0 then
182
+ if not reconnecting then
183
+ reconnecting = true
184
+ puts "No connection to breakpoint service at #{Options[:ServerURI]} " +
185
+ "(#{error.class})"
186
+ puts error.backtrace if $DEBUG
187
+ puts "Tries to connect will be made every #{Options[:RetryDelay]} seconds..."
188
+ end
189
+
190
+ sleep Options[:RetryDelay]
191
+ retry
192
+ else
193
+ raise
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,104 @@
1
+ class CodeStatistics
2
+ def initialize(*pairs)
3
+ @pairs = pairs
4
+ @statistics = calculate_statistics
5
+ @total = calculate_total if pairs.length > 1
6
+ end
7
+
8
+ def to_s
9
+ print_header
10
+ @pairs.each { |pair| print_line(pair.first, @statistics[pair.first]) }
11
+ print_splitter
12
+
13
+ if @total
14
+ print_line("Total", @total)
15
+ print_splitter
16
+ end
17
+
18
+ print_code_test_stats
19
+ end
20
+
21
+ private
22
+ def calculate_statistics
23
+ @pairs.inject({}) { |stats, pair| stats[pair.first] = calculate_directory_statistics(pair.last); stats }
24
+ end
25
+
26
+ def calculate_directory_statistics(directory, pattern = /.*\.rb$/)
27
+ stats = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
28
+
29
+ Dir.foreach(directory) do |file_name|
30
+ if File.stat(directory + "/" + file_name).directory? and (/^\./ !~ file_name)
31
+ newstats = calculate_directory_statistics(directory + "/" + file_name, pattern)
32
+ stats.each { |k, v| stats[k] += newstats[k] }
33
+ end
34
+
35
+ next unless file_name =~ pattern
36
+
37
+ f = File.open(directory + "/" + file_name)
38
+
39
+ while line = f.gets
40
+ stats["lines"] += 1
41
+ stats["classes"] += 1 if line =~ /class [A-Z]/
42
+ stats["methods"] += 1 if line =~ /def [a-z]/
43
+ stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
44
+ end
45
+ end
46
+
47
+ stats
48
+ end
49
+
50
+ def calculate_total
51
+ total = { "lines" => 0, "codelines" => 0, "classes" => 0, "methods" => 0 }
52
+ @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
53
+ total
54
+ end
55
+
56
+ def calculate_code
57
+ code_loc = 0
58
+ @statistics.each { |k, v| code_loc += v['codelines'] unless ['Units', 'Functionals'].include? k }
59
+ code_loc
60
+ end
61
+
62
+ def calculate_tests
63
+ test_loc = 0
64
+ @statistics.each { |k, v| test_loc += v['codelines'] if ['Units', 'Functionals'].include? k }
65
+ test_loc
66
+ end
67
+
68
+ def print_header
69
+ print_splitter
70
+ puts "| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |"
71
+ print_splitter
72
+ end
73
+
74
+ def print_splitter
75
+ puts "+----------------------+-------+-------+---------+---------+-----+-------+"
76
+ end
77
+
78
+ def print_line(name, statistics)
79
+ m_over_c = (statistics["methods"] / statistics["classes"]) rescue m_over_c = 0
80
+ loc_over_m = (statistics["codelines"] / statistics["methods"]) - 2 rescue loc_over_m = 0
81
+
82
+ start = if ['Units', 'Functionals'].include? name
83
+ "| #{name.ljust(18)} "
84
+ else
85
+ "| #{name.ljust(20)} "
86
+ end
87
+
88
+ puts start +
89
+ "| #{statistics["lines"].to_s.rjust(5)} " +
90
+ "| #{statistics["codelines"].to_s.rjust(5)} " +
91
+ "| #{statistics["classes"].to_s.rjust(7)} " +
92
+ "| #{statistics["methods"].to_s.rjust(7)} " +
93
+ "| #{m_over_c.to_s.rjust(3)} " +
94
+ "| #{loc_over_m.to_s.rjust(5)} |"
95
+ end
96
+
97
+ def print_code_test_stats
98
+ code = calculate_code
99
+ tests = calculate_tests
100
+
101
+ puts " Code LOC: #{code} Test LOC: #{tests} Code to Test Ratio: 1:#{sprintf("%.1f", tests.to_f/code)}"
102
+ puts ""
103
+ end
104
+ end
@@ -0,0 +1,6 @@
1
+ ActiveRecord::Base.lock_mutex
2
+ ActiveRecord::Base.connection.begin_db_transaction
3
+ at_exit do
4
+ ActiveRecord::Base.connection.rollback_db_transaction
5
+ ActiveRecord::Base.unlock_mutex
6
+ end
data/lib/dispatcher.rb ADDED
@@ -0,0 +1,59 @@
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
+
24
+ require 'breakpoint'
25
+
26
+ class Dispatcher
27
+ class << self
28
+ def dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
29
+ begin
30
+ request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
31
+ prepare_application
32
+ ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
33
+ rescue Object => exception
34
+ ActionController::Base.process_with_exception(request, response, exception).out(output)
35
+ ensure
36
+ reset_after_dispatch
37
+ end
38
+ end
39
+
40
+ def reset_application!
41
+ Controllers.clear!
42
+ Dependencies.clear
43
+ Dependencies.remove_subclasses_for(ActiveRecord::Base, ActiveRecord::Observer, ActionController::Base)
44
+ Dependencies.remove_subclasses_for(ActionMailer::Base) if defined?(ActionMailer::Base)
45
+ end
46
+
47
+ private
48
+ def prepare_application
49
+ ActionController::Routing::Routes.reload if Dependencies.load?
50
+ Breakpoint.activate_drb("druby://localhost:#{BREAKPOINT_SERVER_PORT}", nil, !defined?(FastCGI)) if defined?(BREAKPOINT_SERVER_PORT) rescue nil
51
+ Controllers.const_load!(:ApplicationController, "application") unless Controllers.const_defined?(:ApplicationController)
52
+ end
53
+
54
+ def reset_after_dispatch
55
+ reset_application! if Dependencies.load?
56
+ Breakpoint.deactivate_drb if defined?(BREAKPOINT_SERVER_PORT)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,156 @@
1
+ require 'fcgi'
2
+ require 'logger'
3
+ require 'dispatcher'
4
+
5
+ class RailsFCGIHandler
6
+ SIGNALS = {
7
+ 'HUP' => :reload,
8
+ 'TERM' => :graceful_exit,
9
+ 'USR1' => :graceful_exit
10
+ }
11
+
12
+ attr_reader :when_ready
13
+
14
+ attr_accessor :log_file_path
15
+ attr_accessor :gc_request_period
16
+
17
+
18
+ # Initialize and run the FastCGI instance, passing arguments through to new.
19
+ def self.process!(*args, &block)
20
+ new(*args, &block).process!
21
+ end
22
+
23
+ # Initialize the FastCGI instance with the path to a crash log
24
+ # detailing unhandled exceptions (default RAILS_ROOT/log/fastcgi.crash.log)
25
+ # and the number of requests to process between garbage collection runs
26
+ # (default nil for normal GC behavior.) Optionally, pass a block which
27
+ # takes this instance as an argument for further configuration.
28
+ def initialize(log_file_path = nil, gc_request_period = nil)
29
+ @when_ready = nil
30
+
31
+ self.log_file_path = log_file_path || "#{RAILS_ROOT}/log/fastcgi.crash.log"
32
+ self.gc_request_period = gc_request_period
33
+
34
+ # Yield for additional configuration.
35
+ yield self if block_given?
36
+
37
+ # Safely install signal handlers.
38
+ install_signal_handlers
39
+
40
+ # Start error timestamp at 11 seconds ago.
41
+ @last_error_on = Time.now - 11
42
+
43
+ dispatcher_log(:info, "starting")
44
+ end
45
+
46
+ def process!(provider = FCGI)
47
+ # Make a note of $" so we can safely reload this instance.
48
+ mark!
49
+
50
+ # Begin countdown to garbage collection.
51
+ run_gc! if gc_request_period
52
+
53
+ provider.each_cgi do |cgi|
54
+ # Safely reload this instance if requested.
55
+ if when_ready == :reload
56
+ run_gc! if gc_request_period
57
+ restore!
58
+ @when_ready = nil
59
+ dispatcher_log(:info, "reloaded")
60
+ end
61
+
62
+ process_request(cgi)
63
+
64
+ # Break if graceful exit requested.
65
+ break if when_ready == :exit
66
+
67
+ # Garbage collection countdown.
68
+ if gc_request_period
69
+ @gc_request_countdown -= 1
70
+ run_gc! if @gc_request_countdown <= 0
71
+ end
72
+ end
73
+
74
+ GC.enable
75
+ dispatcher_log(:info, "terminated gracefully")
76
+
77
+ rescue SystemExit => exit_error
78
+ dispatcher_log(:info, "terminated by explicit exit")
79
+
80
+ rescue Object => fcgi_error
81
+ # retry on errors that would otherwise have terminated the FCGI process,
82
+ # but only if they occur more than 10 seconds apart.
83
+ if !(SignalException === fcgi_error) && Time.now - @last_error_on > 10
84
+ @last_error_on = Time.now
85
+ dispatcher_error(fcgi_error, "almost killed by this error")
86
+ retry
87
+ else
88
+ dispatcher_error(fcgi_error, "killed by this error")
89
+ end
90
+ end
91
+
92
+
93
+ private
94
+ def logger
95
+ @logger ||= Logger.new(@log_file_path)
96
+ end
97
+
98
+ def dispatcher_log(level, msg)
99
+ time_str = Time.now.strftime("%d/%b/%Y:%H:%M:%S")
100
+ logger.send(level, "[#{time_str} :: #{$$}] #{msg}")
101
+ rescue Object => log_error
102
+ STDERR << "Couldn't write to #{@log_file_path.inspect}: #{msg}\n"
103
+ STDERR << " #{log_error.class}: #{log_error.message}\n"
104
+ end
105
+
106
+ def dispatcher_error(e,msg="")
107
+ error_message =
108
+ "Dispatcher failed to catch: #{e} (#{e.class})\n" +
109
+ " #{e.backtrace.join("\n ")}\n#{msg}"
110
+ dispatcher_log(:error, error_message)
111
+ end
112
+
113
+ def install_signal_handlers
114
+ SIGNALS.each do |signal, handler_name|
115
+ install_signal_handler signal, method("#{handler_name}_handler").to_proc
116
+ end
117
+ end
118
+
119
+ def install_signal_handler(signal, handler)
120
+ trap signal, handler
121
+ rescue ArgumentError
122
+ dispatcher_log :warn, "Ignoring unsupported signal #{signal}."
123
+ end
124
+
125
+ def graceful_exit_handler(signal)
126
+ dispatcher_log :info, "asked to terminate ASAP"
127
+ @when_ready = :exit
128
+ end
129
+
130
+ def reload_handler(signal)
131
+ @when_ready = :reload
132
+ dispatcher_log :info, "asked to reload ASAP"
133
+ end
134
+
135
+ def process_request(cgi)
136
+ Dispatcher.dispatch(cgi)
137
+ rescue Object => e
138
+ raise if SignalException === e
139
+ dispatcher_error(e)
140
+ end
141
+
142
+ def mark!
143
+ @features = $".clone
144
+ end
145
+
146
+ def restore!
147
+ $".replace @features
148
+ Dispatcher.reset_application!
149
+ ActionController::Routing::Routes.reload
150
+ end
151
+
152
+ def run_gc!
153
+ @gc_request_countdown = gc_request_period
154
+ GC.enable; GC.start; GC.disable
155
+ end
156
+ end
data/lib/productize.rb ADDED
@@ -0,0 +1,116 @@
1
+ SITE_ROOT = File.join(RAILS_ROOT, 'sites', SITE)
2
+
3
+ # Load site-specific controllers and let them re-open their corresponding class
4
+ module Dependencies
5
+ def require_or_load(file_name)
6
+ file_name = "#{file_name}.rb" unless ! load? || file_name[-3..-1] == '.rb'
7
+ load? ? load(file_name) : require(file_name)
8
+ if file_name.include? 'controller'
9
+ file_name = File.join(SITE_ROOT, 'app', 'controllers', File.basename(file_name))
10
+ if File.exist? file_name
11
+ load? ? load(file_name) : require(file_name)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ # Prefer site-specific templates, partials etc. if they exist. Otherwise, use the base
18
+ # application's generic files.
19
+ module ActionView
20
+ class Base
21
+ private
22
+ def full_template_path(template_path, extension)
23
+ # Check to see if the partial exists in our 'sites' folder first
24
+ site_specific_path = File.join(SITE_ROOT, 'app', 'views', template_path + '.' + extension)
25
+
26
+ if File.exist?(site_specific_path)
27
+ site_specific_path
28
+ else
29
+ "#{@base_path}/#{template_path}.#{extension}"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # Scoop up both the base's migration files (those that should apply to ALL sites), plus
36
+ # the site-specific migration files. Sort them. Apply them in turn.
37
+ module ActiveRecord
38
+ class Migrator
39
+ private
40
+ def migration_files
41
+ generic_files = Dir["#{@migrations_path}/[0-9]*_*.rb"].sort
42
+ puts generic_files.inspect
43
+ # Include the site-specific files in our complete list of migration files
44
+ if defined? SITE_ROOT and File.exist?("#{SITE_ROOT}/db/migrate")
45
+ # Note that a tilde (~) is used intentionally because its ascii value
46
+ # is greater than both the lower-case and upper-case alphabets (thereby
47
+ # causing the sort! below to behave as expected).
48
+ site_specific_files = Dir["#{SITE_ROOT}/db/migrate/[0-9]*\.[0-9]*_*.rb"]
49
+ files = generic_files + site_specific_files
50
+ # Sort by filename, ignoring the path to get there. Also convert '.'
51
+ # to '~' so that sorting occurs in the correct order.
52
+ files.sort! { |a,b| a.gsub(".", "~").match(/.+[\/\\](.+)/)[1] <=> b.gsub(".", "~").match(/.+[\/\\](.+)/)[1] }
53
+ else
54
+ files = generic_files
55
+ end
56
+ down? ? files.reverse : files
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ # Make routes site-specific for sites whose config/routes.rb exists
63
+ module ActionController
64
+ module Routing #:nodoc:
65
+ class RouteSet
66
+ def replace(*args)
67
+ new_route = Route.new(*args)
68
+ # Remove the old route that we're replacing
69
+ @routes.delete_if { |r| r.path == args[0] }
70
+ # Add the new one back
71
+ @routes << new_route
72
+ return new_route
73
+ end
74
+
75
+ def draw_append
76
+ yield self
77
+ write_generation
78
+ write_recognition
79
+ end
80
+
81
+ # Get both the base routes.rb file AND the site-specific routes.rb file
82
+ def reload
83
+ NamedRoutes.clear
84
+
85
+ loaded_routes = false
86
+
87
+ # Load the initial set of routes for the base application
88
+ if defined?(RAILS_ROOT) and File.exist?(File.join(RAILS_ROOT, 'config', 'routes.rb'))
89
+ load(File.join(RAILS_ROOT, 'config', 'routes.rb'))
90
+ loaded_routes = true
91
+ end
92
+
93
+ # Add on site-specific routes
94
+ if defined?(SITE_ROOT) and File.exist?(File.join(SITE_ROOT, 'config', 'routes.rb'))
95
+ load(File.join(SITE_ROOT, 'config', 'routes.rb'))
96
+ loaded_routes = true
97
+ end
98
+
99
+ # Use a sensible default if nothing could be loaded
100
+ unless loaded_routes
101
+ connect(':controller/:action/:id', :action => 'index', :id => nil)
102
+ end
103
+
104
+ NamedRoutes.install
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ # Put cached pages in the site-specific public folder
111
+ ActionController::Base.page_cache_directory = "#{SITE_ROOT}/public"
112
+
113
+ # Load any site-specific models
114
+ # TODO: Make site-specific models re-open classes rather than
115
+ # this temporary either/or hack
116
+ ADDITIONAL_LOAD_PATHS.concat(Dir["#{SITE_ROOT}/app/models/[_a-z]*"])