rails_2_preload 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/rails_2_preload.rb +172 -0
  2. metadata +47 -0
@@ -0,0 +1,172 @@
1
+ require "benchmark"
2
+ require "pathname"
3
+
4
+ # The purpose of Rails2Preload is to optimize testing with Spin and Rails 2.
5
+ # It does this by splitting the Rails 2 initialization method
6
+ # (Rails::Initializer#process) into two phases: preload and postload. This
7
+ # gives us the capability of using Spin:
8
+ #
9
+ # * without having to reboot Rails every time a class is modified
10
+ #
11
+ # * without having to disable class caching
12
+ #
13
+ module Rails2Preload
14
+ # All of the methods of the Rails initialization process, in order.
15
+ METHODS = [
16
+ :check_ruby_version,
17
+ :install_gem_spec_stubs,
18
+ :set_load_path,
19
+ :add_gem_load_paths,
20
+ :require_frameworks,
21
+ :set_autoload_paths,
22
+ :add_plugin_load_paths,
23
+ :load_environment,
24
+ :preload_frameworks,
25
+ :initialize_encoding,
26
+ :initialize_database,
27
+ :initialize_cache,
28
+ :initialize_framework_caches,
29
+ :initialize_logger,
30
+ :initialize_framework_logging,
31
+ :initialize_dependency_mechanism,
32
+ :initialize_whiny_nils,
33
+ :initialize_time_zone,
34
+ :initialize_i18n,
35
+ :initialize_framework_settings,
36
+ :initialize_framework_views,
37
+ :initialize_metal,
38
+ :add_support_load_paths,
39
+ :check_for_unbuilt_gems,
40
+ :load_gems,
41
+ :load_plugins,
42
+ :add_gem_load_paths,
43
+ :load_gems,
44
+ :check_gem_dependencies,
45
+ :load_application_initializers,
46
+ :after_initialize,
47
+ :initialize_database_middleware,
48
+ :prepare_dispatcher,
49
+ :initialize_routing,
50
+ :load_observers,
51
+ :load_view_paths,
52
+ :load_application_classes,
53
+ :disable_dependency_loading
54
+ ]
55
+
56
+ class << self
57
+ # The methods run in the preload phase.
58
+ attr_reader :preload_methods
59
+ # The methods run in the postload phase.
60
+ attr_reader :postload_methods
61
+ end
62
+
63
+ # Given a method name, the methods of the Rails initialization process are
64
+ # split into two groups, preload and postload.
65
+ def self.preload_until(method)
66
+ index = METHODS.index(method)
67
+ raise(ArgumentError, method) if index.nil?
68
+
69
+ @preload_methods, @postload_methods = METHODS[0..index - 1], METHODS[index..-1]
70
+ end
71
+
72
+ # By default, we'll preload until the application classes (i.e. models) are
73
+ # loaded. This is optimal for unit testing.
74
+ self.preload_until(:load_application_classes)
75
+
76
+ # Called from .spin.rb to add all hooks necessary to integrate
77
+ # Rails2Preload.
78
+ def self.add_spin_hooks
79
+ Spin.hook(:before_preload) { Rails2Preload.prepare_rails }
80
+
81
+ Spin.hook(:after_preload) do
82
+ if Rails2Preload.preload_methods.include? :load_application_classes
83
+ # If classes are preloaded, empty the connection pool so forked
84
+ # processes are forced to establish new connections. Otherwise, the
85
+ # second time a test is run, an exception like this is raised:
86
+ # ActiveRecord::StatementInvalid PGError: no connection to the server
87
+ ActiveRecord::Base.connection_pool.disconnect!
88
+ end
89
+ end
90
+
91
+ Spin.hook(:after_fork) do
92
+ # Create a new initializer instance, but reuse the configuration already
93
+ # established by the preload phase.
94
+ initializer = Rails::Initializer.new(Rails.configuration)
95
+ initializer.postload
96
+ end
97
+ end
98
+
99
+ # Called by the Rails patch to run the preload phase.
100
+ def self.preload(initializer)
101
+ preload_methods.each { |method| benchmark(initializer, method) }
102
+ end
103
+
104
+ # Called by the Rails patch to run the postload phase.
105
+ def self.postload(initializer)
106
+ postload_methods.each { |method| benchmark(initializer, method) }
107
+ end
108
+
109
+ # Called by the :before_preload Spin hook to prepare Rails.
110
+ def self.prepare_rails
111
+ # We need to boot Rails before adding methods to Rails::Initializer.
112
+ # Otherwise, Rails.booted? returns true and Rails.boot! short-circuits.
113
+ boot_rails
114
+ apply_initializer_patch
115
+ end
116
+
117
+ private
118
+
119
+ # This is the monkey-patch that splits the Rails 2 initialization process
120
+ # (Rails::Initializer#process) into two phases, preload and postload.
121
+ def self.apply_initializer_patch
122
+ module_eval <<-RUBY , __FILE__, __LINE__ + 1
123
+ module ::Rails
124
+ class Initializer
125
+ # The run method *does* support calling an arbitrary method (the
126
+ # command parameter) to initialize Rails. However, my personal
127
+ # preference is to not change anything in the app (in this case,
128
+ # environment.rb) to support Spin.
129
+ def self.run(command = :preload, configuration = Configuration.new)
130
+ yield configuration if block_given?
131
+ initializer = new configuration
132
+ initializer.send(command)
133
+ initializer
134
+ end
135
+
136
+ # Runs the preload phase of the Rails initialization process.
137
+ def preload
138
+ Rails.configuration = configuration
139
+ Rails2Preload.preload(self)
140
+ end
141
+
142
+ # Runs the postload phase of the Rails initialization process.
143
+ def postload
144
+ Rails2Preload.postload(self)
145
+ Rails.initialized = true
146
+ end
147
+ end # Initializer
148
+ end # Rails
149
+ RUBY
150
+ end
151
+
152
+ # Returns a Pathname object. We'll use it to determine what the Rails root
153
+ # is before the Rails module is available.
154
+ def self.rails_root
155
+ Bundler.root
156
+ end
157
+
158
+ def self.boot_rails
159
+ require(rails_root + "config/boot")
160
+ end
161
+
162
+ def self.initialize_rails
163
+ require(rails_root + "config/environment")
164
+ end
165
+
166
+ # Benchmarks a method sent to an object and prints the result.
167
+ def self.benchmark(object, method, *args)
168
+ print "[Rails2Preload] #{method}"
169
+ seconds = Benchmark.realtime { object.send(method, *args) }
170
+ puts "#{"%0.3f" % seconds}s".rjust(40 - method.to_s.length)
171
+ end
172
+ end # Rails2Preload
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_2_preload
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Todd Mazierski
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-09 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "The purpose of Rails2Preload is to optimize testing with Spin\n and
15
+ Rails 2. It does this by splitting the Rails 2 initialization method\n (Rails::Initializer#process)
16
+ into two phases: preload and postload."
17
+ email: todd@paperlesspost.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/rails_2_preload.rb
23
+ homepage: https://github.com/paperlesspost/rails-2-preload
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.23
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: Preloads Rails 2 for testing with Spin
47
+ test_files: []