blob: d303212f52b80c27a018debcf9c2e3633c6eeaa8 (
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 | require 'set'
module Rails
  module Paths
    module PathParent
      attr_reader :children
      def method_missing(id, *args)
        name = id.to_s
        if name =~ /^(.*)=$/ || args.any?
          @children[$1 || name] = Path.new(@root, *args)
        elsif path = @children[name]
          path
        else
          super
        end
      end
    end
    class Root
      include PathParent
      attr_accessor :path
      def initialize(path)
        raise if path.is_a?(Array)
        @children = {}
        @path = path
        @root = self
        @all_paths = []
      end
      def all_paths
        @all_paths.uniq!
        @all_paths
      end
      def autoload_once
        filter_by(:autoload_once?)
      end
      def eager_load
        filter_by(:eager_load?)
      end
      def autoload_paths
        filter_by(:autoload?)
      end
      def load_paths
        filter_by(:load_path?)
      end
      def push(*)
        raise "Application root can only have one physical path"
      end
      alias unshift push
      alias << push
      alias concat push
    protected
      def filter_by(constraint)
        all = []
        all_paths.each do |path|
          if path.send(constraint)
            paths  = path.paths
            paths -= path.children.values.map { |p| p.send(constraint) ? [] : p.paths }.flatten
            all.concat(paths)
          end
        end
        all.uniq!
        all.reject! { |p| !File.exists?(p) }
        all
      end
    end
    class Path
      include PathParent, Enumerable
      attr_reader :path
      attr_accessor :glob
      def initialize(root, *paths)
        options   = paths.last.is_a?(::Hash) ? paths.pop : {}
        @children = {}
        @root     = root
        @paths    = paths.flatten
        @glob     = options[:glob]
        autoload_once! if options[:autoload_once]
        eager_load!    if options[:eager_load]
        autoload!      if options[:autoload]
        load_path!     if options[:load_path]
        @root.all_paths << self
      end
      def each
        to_a.each { |p| yield p }
      end
      def push(path)
        @paths.push path
      end
      alias << push
      def unshift(path)
        @paths.unshift path
      end
      def concat(paths)
        @paths.concat paths
      end
      %w(autoload_once eager_load autoload load_path).each do |m|
        class_eval <<-RUBY, __FILE__, __LINE__ + 1
          def #{m}!
            @#{m} = true
          end
          def skip_#{m}!
            @#{m} = false
          end
          def #{m}?
            @#{m}
          end
        RUBY
      end
      def paths
        raise "You need to set a path root" unless @root.path
        result = @paths.map do |p|
          path = File.expand_path(p, @root.path)
          @glob ? Dir[File.join(path, @glob)] : path
        end
        result.flatten!
        result.uniq!
        result
      end
      alias to_a paths
    end
  end
end
 |