Class: Reactive::Initializer

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/reactive-core/initializer.rb

Overview

Handles Reactive initialization process.

The initialization process is sliced in short parts named stages. Each stage is responsible for a specific initialization. Plugins will also register stages in this system.

Running the application is a three steps process:

  1. Booting: loads the reactive-core gem (see config/boot.rb)

  2. Initialization (the #run method is called)

  3. Dispatching the initial request (as configured in config/config.rb)

The application developer may also register initialization stages by example in the files under config/initializers/*.rb like so:

Reactive::Initializer.init :donuts do
  require 'donuts'
  Donuts.setup_factory
end

Registering stages is done with the general #register method or the more conveniant methods: #configure, #before_init, #init and #after_init.

The application or any plugin may observe the initilization process by registering an observer with #add_observer. It acts like a callback triggered before processing each stage.

The stages are left visible with the #stages accessor, but be careful with it.

Direct Known Subclasses

Default

Defined Under Namespace

Classes: Default, Stage

Constant Summary collapse

STAGE_LEVELS =
{:configure => -400, :before_init => -200, :init => 0, :init_rails_plugin => 100, :after_init => 200}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeInitializer

:nodoc:



283
284
285
286
287
# File 'lib/reactive-core/initializer.rb', line 283

def initialize # :nodoc:
  @stages = []
  @finished = []
  @observers = []
end

Instance Attribute Details

#observersObject (readonly)

:nodoc:



281
282
283
# File 'lib/reactive-core/initializer.rb', line 281

def observers
  @observers
end

#stagesObject (readonly)

:nodoc:



281
282
283
# File 'lib/reactive-core/initializer.rb', line 281

def stages
  @stages
end

Class Method Details

.add_observer(proc = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


258
259
260
261
262
# File 'lib/reactive-core/initializer.rb', line 258

def add_observer(proc = nil, &block)
  raise ArgumentError, "Pass either a proc or a block, not both!" unless proc.nil? ^ block.nil?
  raise ArgumentError, "Passed object is not callable!" if proc && !proc.respond_to?(:call)
  Initializer.instance.observers << (proc || block)
end

.after_init(name, options = {}, &block) ⇒ Object



243
244
245
246
# File 'lib/reactive-core/initializer.rb', line 243

def after_init(name, options = {}, &block)
  name = "after_init_#{name}" unless name.to_s =~ /^after_init_/
  register(name, :after_init, &block)
end

.before_init(name, options = {}, &block) ⇒ Object



233
234
235
236
# File 'lib/reactive-core/initializer.rb', line 233

def before_init(name, options = {}, &block)
  name = "before_init_#{name}" unless name.to_s =~ /^before_init_/
  register(name, :before_init, &block)
end

.configure(name, options = {}, &block) ⇒ Object

convenience aliases for standard priorities



228
229
230
231
# File 'lib/reactive-core/initializer.rb', line 228

def configure(name, options = {}, &block)
  name = "configure_#{name}" unless name.to_s =~ /^configure_/
  register(name, :configure, &block)
end

.init(name, options = {}, &block) ⇒ Object



238
239
240
241
# File 'lib/reactive-core/initializer.rb', line 238

def init(name, options = {}, &block)
  name = "init_#{name}" unless name.to_s =~ /^init_/
  register(name, :init, &block)
end

.register(name, options = {}, &block) ⇒ Object

Registers an initialization stage. Pass a name, then either a level or an option to specify the relation against another stage.

register(:mvc_configure, -100) { some_code }
register(:mvc_configure, :before => :init_logger) { some_code }
register(:mvc_configure, :after => :wx_configure, :proc => a_proc)


223
224
225
# File 'lib/reactive-core/initializer.rb', line 223

def register(name, options = {}, &block)
  Initializer.instance.register(name, options, &block)
end

.run(stage = :final, configuration = Reactive.configuration || Configuration.new) {|configuration| ... } ⇒ Object

Runs the initialization process.

stage is either a level which will also be processed or a stage name that will also be processed.

Yields:



252
253
254
255
256
# File 'lib/reactive-core/initializer.rb', line 252

def run(stage = :final, configuration = Reactive.configuration || Configuration.new) # :yields: configuration
  yield configuration if block_given?
  Reactive.configuration = configuration
  Initializer.instance.run_stages(stage)
end

.stagesObject



264
265
266
# File 'lib/reactive-core/initializer.rb', line 264

def stages
  Initializer.instance.stages
end

Instance Method Details

#register(name, options, &block) ⇒ Object

:nodoc:

Raises:

  • (ArgumentError)


289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/reactive-core/initializer.rb', line 289

def register(name, options, &block) # :nodoc:
  options = options.is_a?(Hash) ? options : {:level => STAGE_LEVELS[options] || options}
  proc = options[:proc]
  raise ArgumentError, "Pass either a proc or a block, not both!" unless proc.nil? ^ block.nil?
  raise ArgumentError, "Proc object is not callable!" if proc && !proc.respond_to?(:call)
  block ||= proc
#      raise ArgumentError, "register options are mutually exclusive!" if options[:level]
  case
    when level = options[:level]
      insert_index = stages.index(stages.find {|item| item.level > level}) || -1
    when before = options[:before]
      insert_index = stages.index(stages.find{|item| item.name == before.to_sym})
      raise ArgumentError, "Can't insert before '#{before}', no stage of that name!" unless insert_index
      items = [insert_index-1 < 0 ? nil : insert_index-1, insert_index].compact
      level = stages.values_at(*items).inject {|sum, stage| sum + stage.level} / items.size
    when after = options[:after]
      insert_index = stages.index(stages.find{|item| item.name == after.to_sym})
      raise ArgumentError, "Can't insert after '#{after}', no stage of that name!" unless insert_index
      items = stages.values_at([index, index+1]).compact
      level = items.inject {|sum, stage| sum + stage.level} / items.size
  end
  
  stages.insert(insert_index, Stage.new(name, level, block))
end

#run_stages(last_stage) ⇒ Object

last_stage is either a level which WILL also be processed or a stage name that WILL also be processed.



316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/reactive-core/initializer.rb', line 316

def run_stages(last_stage) # :nodoc:
  last_stage = STAGE_LEVELS[last_stage] || last_stage
  stage = stages.first
  while stage
    break if last_stage.is_a?(Integer) && stage.level > last_stage
    unless @finished.include? stage
      observers.each {|block| block.call(stage) }
      benchlog("Stage: #{stage.name}") { stage.proc.call }
      @finished << stage
      break if stage.name == last_stage
    end
    stage = stages[stages.index(stage).succ]
  end
end