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)



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

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)


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

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



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

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



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

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



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
66
# File 'lib/dry/rails/railtie.rb', line 28

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)


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

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)


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

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.



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

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.



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

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



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

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