rails_2_preload 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.
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: []