Class: Dry::Rails::Railtie

Inherits:
Rails::Railtie
  • Object
show all
Defined in:
lib/dry/rails/railtie.rb

Overview

The railtie is responsible for setting up a container and handling reloading in dev mode

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#container_const_nameObject (readonly)



11
12
13
# File 'lib/dry/rails/railtie.rb', line 11

def container_const_name
  @container_const_name
end

Instance Method Details

#app_namespaceModule

Infer the default application namespace

TODO: we had to rename namespace=>app_namespace because

Rake::DSL's Kernel#namespace *sometimes* breaks things.
Currently we are missing specs verifying that rake tasks work
correctly and those must be added!

Returns:

  • (Module)


120
121
122
123
124
125
# File 'lib/dry/rails/railtie.rb', line 120

def app_namespace
  @app_namespace ||= begin
    top_level_namespace = ::Rails.application.class.to_s.split("::").first
    Object.const_get(top_level_namespace)
  end
end

#containerDry::Rails::Container

Exposes the container constant



87
88
89
# File 'lib/dry/rails/railtie.rb', line 87

def container
  app_namespace.const_get(container_const_name, false)
end

#default_inflectorObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Sets or reloads a constant within the application namespace



130
131
132
# File 'lib/dry/rails/railtie.rb', line 130

def default_inflector
  ActiveSupport::Inflector
end

#finalize!Object Also known as: reload

Code-reloading-aware finalization process

This sets up ‘Container` and `Deps` constants, reloads them if this is in reloading mode, and registers default components like the railtie itself or the inflector

rubocop:disable Metrics/AbcSize



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/dry/rails/railtie.rb', line 27

def finalize!
  @container_const_name ||= Dry::Rails::Container.container_constant

  stop_features if reloading?

  root_path = ::Rails.root

  container = Dry::Rails.create_container(
    root: root_path,
    inflector: default_inflector,
    provider_dirs: [root_path.join("config/system/boot")]
  )

  # Enable :env plugin by default because it is a very common requirement
  container.use :env, inferrer: -> { ::Rails.env }

  container.register(:railtie, self)
  container.register(:inflector, default_inflector)

  # Remove previously defined constants, if any, so we don't end up with
  # unsused constants in app's namespace when a name change happens.
  remove_constant(container.auto_inject_constant)
  remove_constant(container.container_constant)

  Dry::Rails.evaluate_initializer(container)

  @container_const_name = container.container_constant

  set_or_reload(container.container_constant, container)
  set_or_reload(container.auto_inject_constant, container.injector)

  container.features.each do |feature|
    container.register_provider(feature, from: :rails)
  end

  container.refresh_provider_files if reloading?

  container.finalize!(freeze: !::Rails.env.test?)
end

#nameSymbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return the default system name

In the dry-system world containers are explicitly named using symbols, so that you can refer to them easily when ie importing one container into another

Returns:

  • (Symbol)


106
107
108
# File 'lib/dry/rails/railtie.rb', line 106

def name
  app_namespace.name.underscore.to_sym
end

#reloading?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return true if we’re in code-reloading mode

Returns:

  • (Boolean)


94
95
96
# File 'lib/dry/rails/railtie.rb', line 94

def reloading?
  app_namespace.const_defined?(container_const_name, false)
end

#remove_constant(const_name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



141
142
143
144
145
# File 'lib/dry/rails/railtie.rb', line 141

def remove_constant(const_name)
  if app_namespace.const_defined?(const_name, false)
    app_namespace.__send__(:remove_const, const_name)
  end
end

#set_or_reload(const_name, const) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



135
136
137
138
# File 'lib/dry/rails/railtie.rb', line 135

def set_or_reload(const_name, const)
  remove_constant(const_name)
  app_namespace.const_set(const_name, const)
end

#stop_featuresObject

Stops all configured features (bootable components)

This is crucial when reloading code in development mode. Every bootable component should be able to clear the runtime from any constants that it created in its ‘stop` lifecycle step



76
77
78
79
80
# File 'lib/dry/rails/railtie.rb', line 76

def stop_features
  container.features.each do |feature|
    container.stop(feature) if container.started?(feature)
  end
end