aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/rails/engine.rb
blob: aaa669ef32437d2d2db12f503394bb5d78d77bdd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
require 'active_support/core_ext/module/delegation'

module Rails
  class Engine < Railtie
    class << self
      attr_accessor :called_from

      def original_root
        @original_root ||= find_root_with_file_flag("lib")
      end

      def config
        @config ||= Configuration.new(original_root)
      end

      def inherited(base)
        base.called_from = begin
          call_stack = caller.map { |p| p.split(':').first }
          File.dirname(call_stack.detect { |p| p !~ %r[railties/lib/rails|rack/lib/rack] })
        end

        super
      end

    protected

      def find_root_with_file_flag(flag, default=nil)
        root_path = self.called_from

        while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
          parent = File.dirname(root_path)
          root_path = parent != root_path && parent
        end

        root = File.exist?("#{root_path}/#{flag}") ? root_path : default

        raise "Could not find root path for #{self}" unless root

        RUBY_PLATFORM =~ /(:?mswin|mingw)/ ?
          Pathname.new(root).expand_path :
          Pathname.new(root).realpath
      end
    end

    delegate :config, :to => :'self.class'
    delegate :middleware, :root, :to => :config

    # Add configured load paths to ruby load paths and remove duplicates.
    initializer :set_load_path do
      config.load_paths.reverse_each do |path|
        $LOAD_PATH.unshift(path) if File.directory?(path)
      end
      $LOAD_PATH.uniq!
    end

    # Set the paths from which Rails will automatically load source files,
    # and the load_once paths.
    initializer :set_autoload_paths do
      ActiveSupport::Dependencies.load_paths.concat(config.load_paths)
      ActiveSupport::Dependencies.load_once_paths.concat(config.load_once_paths)

      extra = ActiveSupport::Dependencies.load_once_paths -
              ActiveSupport::Dependencies.load_paths

      unless extra.empty?
        abort <<-end_error
          load_once_paths must be a subset of the load_paths.
          Extra items in load_once_paths: #{extra * ','}
        end_error
      end

      # Freeze so future modifications will fail rather than do nothing mysteriously
      config.load_once_paths.freeze
    end

    initializer :add_routing_files do
      config.paths.config.routes.to_a.each do |route|
        config.action_dispatch.route_files.unshift(route) if File.exists?(route)
      end
    end

    initializer :add_locales do
      config.i18n.load_path.unshift(*config.paths.config.locales.to_a)
    end

    initializer :add_view_paths do
      views = config.paths.app.views.to_a
      ActionController::Base.view_paths.concat(views) if defined?(ActionController)
      ActionMailer::Base.view_paths.concat(views)     if defined?(ActionMailer)
    end

    initializer :load_application_initializers do
      config.paths.config.initializers.each do |initializer|
        load(initializer)
      end
    end

    initializer :load_application_classes do |app|
      next if $rails_rake_task

      if app.config.cache_classes
        config.eager_load_paths.each do |load_path|
          matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
          Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
            require_dependency file.sub(matcher, '\1')
          end
        end
      end
    end
  end
end