aboutsummaryrefslogtreecommitdiffstats
path: root/lib/bundler/dsl.rb
blob: 6de9acce9352854448c4e929d4b3b595e2bae9b1 (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
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
152
153
module Bundler
  class DslError < StandardError; end

  class Dsl
    def self.evaluate(gemfile)
      builder = new
      builder.instance_eval(File.read(gemfile.to_s), gemfile.to_s, 1)
      builder.to_definition
    end

    def initialize
      @source  = nil
      @sources = []
      @dependencies = []
      @group = [:default]
    end

    def gem(name, *args)
      options = Hash === args.last ? args.pop : {}
      version = args.last || ">= 0"
      if group = options[:groups] || options[:group]
        options[:group] = group
      end

      _deprecated_options(options)
      _normalize_options(name, version, options)

      @dependencies << Dependency.new(name, version, options)
    end

    def source(source, options = {})
      @source = case source
      when :gemcutter, :rubygems, :rubyforge then Source::Rubygems.new("uri" => "http://gemcutter.org")
      when String then Source::Rubygems.new("uri" => source)
      else source
      end

      options[:prepend] ? @sources.unshift(@source) : @sources << @source

      yield if block_given?
      @source
    ensure
      @source = nil
    end

    def path(path, options = {}, source_options = {}, &blk)
      source Source::Path.new(_normalize_hash(options).merge("path" => Pathname.new(path))), source_options, &blk
    end

    def git(uri, options = {}, source_options = {}, &blk)
      source Source::Git.new(_normalize_hash(options).merge("uri" => uri)), source_options, &blk
    end

    def to_definition
      Definition.new(@dependencies, @sources)
    end

    # TODO: obvious
    def to_flex_definition(lockfile)
      Flex::Definition.new(lockfile, @dependencies, @sources)
    end

    def group(*args, &blk)
      old, @group = @group, args
      yield
    ensure
      @group = old
    end

    # Deprecated methods

    def self.deprecate(name, replacement = nil)
      define_method(name) do |*|
        message = "'#{name}' has been removed from the Gemfile DSL, "
        if replacement
          message << "and has been replaced with '#{replacement}'."
        else
          message << "and is no longer supported."
        end
        message << "\nSee the README for more information on upgrading from Bundler 0.8."
        raise DeprecatedMethod, message
      end
    end

    deprecate :only, :group
    deprecate :except
    deprecate :disable_system_gems
    deprecate :disable_rubygems
    deprecate :clear_sources
    deprecate :bundle_path
    deprecate :bin_path

  private

    def _version?(version)
      version && Gem::Version.new(version) rescue false
    end

    def _normalize_hash(opts)
      # Cannot modify a hash during an iteration in 1.9
      opts.keys.each do |k|
        next if String === k
        v = opts[k]
        opts.delete(k)
        opts[k.to_s] = v
      end
      opts
    end

    def _normalize_options(name, version, opts)
      _normalize_hash(opts)

      invalid_keys = opts.keys - %w(group git path name branch ref tag require)
      if invalid_keys.any?
        plural = invalid_keys.size > 1
        message = "You passed #{invalid_keys.map{|k| ':'+k }.join(", ")} "
        if plural
          message << "as options for gem '#{name}', but they are invalid."
        else
          message << "as an option for gem '#{name}', but it is invalid."
        end
        raise InvalidOption, message
      end

      group = opts.delete("group") || @group

      # Normalize git and path options
      ["git", "path"].each do |type|
        if param = opts[type]
          options = _version?(version) ? opts.merge("name" => name, "version" => version) : opts.dup
          source = send(type, param, options, :prepend => true)
          opts["source"] = source
        end
      end

      opts["source"] ||= @source

      opts["group"] = group
    end

    def _deprecated_options(options)
      if options.include?(:require_as)
        raise DeprecatedOption, "Please replace :require_as with :require"
      elsif options.include?(:vendored_at)
        raise DeprecatedOption, "Please replace :vendored_at with :path"
      elsif options.include?(:only)
        raise DeprecatedOption, "Please replace :only with :group"
      elsif options.include?(:except)
        raise DeprecatedOption, "The :except option is no longer supported"
      end
    end
  end
end