summaryrefslogtreecommitdiff
path: root/lib/rubygems/stub_specification.rb
blob: c2910c1bbabe1a6de434b2c0a397bbeb6df1fdb3 (plain)
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
module Gem
  # Gem::StubSpecification reads the stub: line from the gemspec
  # This prevents us having to eval the entire gemspec in order to
  # find out certain information.
  class StubSpecification < BasicSpecification
    # :nodoc:
    PREFIX = "# stub: "

    OPEN_MODE = # :nodoc:
      if Object.const_defined? :Encoding then
        'r:UTF-8:-'
      else
        'r'
      end

    # :nodoc:
    class StubLine
      attr_reader :parts

      def initialize(data)
        @parts = data[PREFIX.length..-1].split(" ")
      end

      def name
        @parts[0]
      end

      def version
        Gem::Version.new @parts[1]
      end

      def platform
        Gem::Platform.new @parts[2]
      end

      def require_paths
        @parts[3..-1].join(" ").split("\0")
      end
    end

    def initialize(filename)
      self.filename = filename
      @data         = nil
      @spec         = nil
    end

    ##
    # Name of the gem

    def name
      @name ||= data.name
    end

    ##
    # Version of the gem

    def version
      @version ||= data.version
    end

    ##
    # Platform of the gem

    def platform
      @platform ||= data.platform
    end

    ##
    # Require paths of the gem

    def require_paths
      @require_paths ||= data.require_paths
    end

    ##
    # The full Gem::Specification for this gem, loaded from evalling its gemspec

    def to_spec
      @spec ||= Gem::Specification.load(filename)
    end

    ##
    # True when this gem has been activated

    def activated?
      loaded = Gem.loaded_specs[name]
      loaded && loaded.version == version
    end

    ##
    # Is this StubSpecification valid? i.e. have we found a stub line, OR does
    # the filename contain a valid gemspec?

    def valid?
      data
    end

    private

    ##
    # If the gemspec contains a stubline, returns a StubLine instance. Otherwise
    # returns the full Gem::Specification.

    def data
      unless @data
        open filename, OPEN_MODE do |file|
          begin
            file.readline # discard encoding line
            stubline = file.readline.chomp
            @data = StubLine.new(stubline) if stubline.start_with?(PREFIX)
          rescue EOFError
          end
        end
      end

      @data ||= to_spec
    end
  end
end