class Bundler::Dsl - bundler-1.15.4 Documentation

# class Bundler::Dsl

### Constants

VALID_PLATFORMS

### Attributes

dependencies[RW]
gemspecs[R]

### Public Class Methods

evaluate(gemfile, lockfile, unlock) click to toggle source

    # File lib/bundler/dsl.rb, line 8
    def self.evaluate(gemfile, lockfile, unlock)
      builder = new
      builder.eval_gemfile(gemfile)
      builder.to_definition(lockfile, unlock)
    end

new() click to toggle source

    # File lib/bundler/dsl.rb, line 19
    def initialize
      @source               = nil
      @sources              = SourceList.new
      @git_sources          = {}
      @dependencies         = []
      @groups               = []
      @install_conditionals = []
      @optional_groups      = []
      @platforms            = []
      @env                  = nil
      @ruby_version         = nil
      @gemspecs             = []
      @gemfile              = nil
      add_git_sources
    end

### Public Instance Methods

env(name) { || ... } click to toggle source

    # File lib/bundler/dsl.rb, line 233
    def env(name)
      old = @env
      @env = name
      yield
    ensure
      @env = old
    end

eval_gemfile(gemfile, contents = nil) click to toggle source

    # File lib/bundler/dsl.rb, line 35
    def eval_gemfile(gemfile, contents = nil)
      expanded_gemfile_path = Pathname.new(gemfile).expand_path
      original_gemfile = @gemfile
      @gemfile = expanded_gemfile_path
      contents ||= Bundler.read_file(gemfile.to_s)
      instance_eval(contents.dup.untaint, gemfile.to_s, 1)
    rescue Exception => e
      message = "There was an error "          "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} "          "`#{File.basename gemfile.to_s}`: #{e.message}"

      raise DSLError.new(message, gemfile, e.backtrace, contents)
    ensure
      @gemfile = original_gemfile
    end

gem(name, *args) click to toggle source

    # File lib/bundler/dsl.rb, line 87
    def gem(name, *args)
      options = args.last.is_a?(Hash) ? args.pop.dup : {}
      version = args || [">= 0"]

      normalize_options(name, version, options)

      dep = Dependency.new(name, version, options)

      # if there's already a dependency with this name we try to prefer one
      if current = @dependencies.find {|d| d.name == dep.name }
        if current.requirement != dep.requirement
          if current.type == :development
            @dependencies.delete current
          else
            return if dep.type == :development
            raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n"                              "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})"
          end

        else
          Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n"                            "You should probably keep only one of them.\n"                            "While it's not a problem now, it could cause errors if you change the version of one of them later."
        end

        if current.source != dep.source
          if current.type == :development
            @dependencies.delete current
          else
            return if dep.type == :development
            raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n"                              "You specified that #{dep.name} (#{dep.requirement}) should come from "                              "#{current.source || "an unspecified source"} and #{dep.source}\n"
          end
        end
      end

      @dependencies << dep
    end

gemspec(opts = nil) click to toggle source

    # File lib/bundler/dsl.rb, line 51
    def gemspec(opts = nil)
      opts ||= {}
      path              = opts[:path] || "."
      glob              = opts[:glob]
      name              = opts[:name]
      development_group = opts[:development_group] || :development
      expanded_path     = gemfile_root.join(path)

      gemspecs = Dir[File.join(expanded_path, "{,*}.gemspec")].map {|g| Bundler.load_gemspec(g) }.compact
      gemspecs.reject! {|s| s.name != name } if name
      Index.sort_specs(gemspecs)
      specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] }

      case specs_by_name_and_version.size
      when 1
        specs = specs_by_name_and_version.values.first
        spec = specs.find {|s| s.match_platform(Bundler.local_platform) } || specs.first

        @gemspecs << spec

        gem_platforms = Bundler::Dependency::REVERSE_PLATFORM_MAP[Bundler::GemHelpers.generic_local_platform]
        gem spec.name, :name => spec.name, :path => path, :glob => glob, :platforms => gem_platforms

        group(development_group) do
          spec.development_dependencies.each do |dep|
            gem dep.name, *(dep.requirement.as_list + [:type => :development])
          end
        end
      when 0
        raise InvalidOption, "There are no gemspecs at #{expanded_path}"
      else
        raise InvalidOption, "There are multiple gemspecs at #{expanded_path}. "            "Please use the :name option to specify which one should be used"
      end
    end

git(uri, options = {}, &blk) click to toggle source

    # File lib/bundler/dsl.rb, line 175
    def git(uri, options = {}, &blk)
      unless block_given?
        msg = "You can no longer specify a git source by itself. Instead, \n"                "either use the :git option on a gem, or specify the gems that \n"                "bundler should find in the git source by passing a block to \n"                "the git method, like: \n\n"                "  git 'git://github.com/rails/rails.git' do\n"                "    gem 'rails'\n"                "  end"
        raise DeprecatedError, msg
      end

      with_source(@sources.add_git_source(normalize_hash(options).merge("uri" => uri)), &blk)
    end

git_source(name, &block) click to toggle source

    # File lib/bundler/dsl.rb, line 152
    def git_source(name, &block)
      unless block_given?
        raise InvalidOption, "You need to pass a block to #git_source"
      end

      if valid_keys.include?(name.to_s)
        raise InvalidOption, "You cannot use #{name} as a git source. It "            "is a reserved key. Reserved keys are: #{valid_keys.join(", ")}"
      end

      @git_sources[name.to_s] = block
    end

github(repo, options = {}) { || ... } click to toggle source

    # File lib/bundler/dsl.rb, line 190
    def github(repo, options = {})
      raise ArgumentError, "GitHub sources require a block" unless block_given?
      github_uri  = @git_sources["github"].call(repo)
      git_options = normalize_hash(options).merge("uri" => github_uri)
      git_source  = @sources.add_git_source(git_options)
      with_source(git_source) { yield }
    end

group(*args) { || ... } click to toggle source

    # File lib/bundler/dsl.rb, line 202
    def group(*args, &blk)
      opts = Hash === args.last ? args.pop.dup : {}
      normalize_group_options(opts, args)

      @groups.concat args

      if opts["optional"]
        optional_groups = args - @optional_groups
        @optional_groups.concat optional_groups
      end

      yield
    ensure
      args.each { @groups.pop }
    end

install_if(*args, &blk) click to toggle source

    # File lib/bundler/dsl.rb, line 218
    def install_if(*args, &blk)
      @install_conditionals.concat args
      blk.call
    ensure
      args.each { @install_conditionals.pop }
    end

method_missing(name, *args) click to toggle source

    # File lib/bundler/dsl.rb, line 245
    def method_missing(name, *args)
      raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile"
    end

path(path, options = {}, &blk) click to toggle source

    # File lib/bundler/dsl.rb, line 165
    def path(path, options = {}, &blk)
      source_options = normalize_hash(options).merge(
        "path" => Pathname.new(path),
        "root_path" => gemfile_root,
        "gemspec" => gemspecs.find {|g| g.name == options["name"] }
      )
      source = @sources.add_path_source(source_options)
      with_source(source, &blk)
    end

platform(*platforms)
Alias for: platforms
platforms(*platforms) { || ... } click to toggle source

    # File lib/bundler/dsl.rb, line 225
    def platforms(*platforms)
      @platforms.concat platforms
      yield
    ensure
      platforms.each { @platforms.pop }
    end

Also aliased as: platform
plugin(*args) click to toggle source

    # File lib/bundler/dsl.rb, line 241
    def plugin(*args)
      # Pass on
    end

source(source, *args, &blk) click to toggle source

    # File lib/bundler/dsl.rb, line 127
    def source(source, *args, &blk)
      options = args.last.is_a?(Hash) ? args.pop.dup : {}
      options = normalize_hash(options)
      if options.key?("type")
        options["type"] = options["type"].to_s
        unless Plugin.source?(options["type"])
          raise "No sources available for #{options["type"]}"
        end

        unless block_given?
          raise InvalidOption, "You need to pass a block to #source with :type option"
        end

        source_opts = options.merge("uri" => source)
        with_source(@sources.add_plugin_source(options["type"], source_opts), &blk)
      elsif block_given?
        source = normalize_source(source)
        with_source(@sources.add_rubygems_source("remotes" => source), &blk)
      else
        source = normalize_source(source)
        check_primary_source_safety(@sources)
        @sources.add_rubygems_remote(source)
      end
    end

to_definition(lockfile, unlock) click to toggle source

    # File lib/bundler/dsl.rb, line 198
    def to_definition(lockfile, unlock)
      Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups)
    end

### Private Instance Methods

add_git_sources() click to toggle source

    # File lib/bundler/dsl.rb, line 251
    def add_git_sources
      git_source(:github) do |repo_name|
        # It would be better to use https instead of the git protocol, but this
        # can break deployment of existing locked bundles when switching between
        # different versions of Bundler. The change will be made in 2.0, which
        # does not guarantee compatibility with the 1.x series.
        #
        # See https://github.com/bundler/bundler/pull/2569 for discussion
        #
        # This can be overridden by adding this code to your Gemfiles:
        #
        #   git_source(:github) do |repo_name|
        #     repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
        #     "https://github.com/#{repo_name}.git"
        #   end
        repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
        # TODO: 2.0 upgrade this setting to the default
        if Bundler.settings["github.https"]
          "https://github.com/#{repo_name}.git"
        else
          warn_github_source_change(repo_name)
          "git://github.com/#{repo_name}.git"
        end
      end

      # TODO: 2.0 remove this deprecated git source
      git_source(:gist) do |repo_name|
        warn_deprecated_git_source(:gist, 'https://gist.github.com/#{repo_name}.git')
        "https://gist.github.com/#{repo_name}.git"
      end

      # TODO: 2.0 remove this deprecated git source
      git_source(:bitbucket) do |repo_name|
        user_name, repo_name = repo_name.split "/"
        warn_deprecated_git_source(:bitbucket, 'https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git')
        repo_name ||= user_name
        "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
      end
    end

check_primary_source_safety(source) click to toggle source

    # File lib/bundler/dsl.rb, line 421
    def check_primary_source_safety(source)
      return unless source.rubygems_primary_remotes.any?

      # TODO: 2.0 upgrade from setting to default
      if Bundler.settings[:disable_multisource]
        raise GemfileError, "Warning: this Gemfile contains multiple primary sources. "            "Each source after the first must include a block to indicate which gems "            "should come from that source. To downgrade this error to a warning, run "            "`bundle config --delete disable_multisource`"
      else
        Bundler::SharedHelpers.major_deprecation "Your Gemfile contains multiple primary sources. "            "Using `source` more than once without a block is a security risk, and "            "may result in installing unexpected gems. To resolve this warning, use "            "a block to indicate which gems should come from the secondary source. "            "To upgrade this warning to an error, run `bundle config "            "disable_multisource true`."
      end
    end

gemfile_root() click to toggle source

    # File lib/bundler/dsl.rb, line 558
    def gemfile_root
      @gemfile ||= Bundler.default_gemfile
      @gemfile.dirname
    end

normalize_group_options(opts, groups) click to toggle source

    # File lib/bundler/dsl.rb, line 375
    def normalize_group_options(opts, groups)
      normalize_hash(opts)

      groups = groups.map {|group| ":#{group}" }.join(", ")
      validate_keys("group #{groups}", opts, %w(optional))

      opts["optional"] ||= false
    end

normalize_hash(opts) click to toggle source

    # File lib/bundler/dsl.rb, line 302
    def normalize_hash(opts)
      opts.keys.each do |k|
        opts[k.to_s] = opts.delete(k) unless k.is_a?(String)
      end
      opts
    end

normalize_options(name, version, opts) click to toggle source

    # File lib/bundler/dsl.rb, line 313
    def normalize_options(name, version, opts)
      if name.is_a?(Symbol)
        raise GemfileError, %Q(You need to specify gem names as Strings. Use 'gem "#{name}"' instead)
      end
      if name =~ /\s/
        raise GemfileError, %Q('#{name}' is not a valid gem name because it contains whitespace)
      end

      normalize_hash(opts)

      git_names = @git_sources.keys.map(&:to_s)
      validate_keys("gem '#{name}'", opts, valid_keys + git_names)

      groups = @groups.dup
      opts["group"] = opts.delete("groups") || opts["group"]
      groups.concat Array(opts.delete("group"))
      groups = [:default] if groups.empty?

      install_if = @install_conditionals.dup
      install_if.concat Array(opts.delete("install_if"))
      install_if = install_if.reduce(true) do |memo, val|
        memo && (val.respond_to?(:call) ? val.call : val)
      end

      platforms = @platforms.dup
      opts["platforms"] = opts["platform"] || opts["platforms"]
      platforms.concat Array(opts.delete("platforms"))
      platforms.map!(&:to_sym)
      platforms.each do |p|
        next if VALID_PLATFORMS.include?(p)
        raise GemfileError, "`#{p}` is not a valid platform. The available options are: #{VALID_PLATFORMS.inspect}"
      end

      # Save sources passed in a key
      if opts.key?("source")
        source = normalize_source(opts["source"])
        opts["source"] = @sources.add_rubygems_source("remotes" => source)
      end

      git_name = (git_names & opts.keys).last
      if @git_sources[git_name]
        opts["git"] = @git_sources[git_name].call(opts[git_name])
      end

      %w(git path).each do |type|
        next unless param = opts[type]
        if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/
          options = opts.merge("name" => name, "version" => $1)
        else
          options = opts.dup
        end
        source = send(type, param, options) {}
        opts["source"] = source
      end

      opts["source"] ||= @source
      opts["env"] ||= @env
      opts["platforms"]      = platforms.dup
      opts["group"]          = groups
      opts["should_include"] = install_if
    end

normalize_source(source) click to toggle source

    # File lib/bundler/dsl.rb, line 407
    def normalize_source(source)
      case source
      when :gemcutter, :rubygems, :rubyforge
        Bundler::SharedHelpers.major_deprecation "The source :#{source} is deprecated because HTTP "            "requests are insecure.\nPlease change your source to 'https://"            "rubygems.org' if possible, or 'http://rubygems.org' if not."
        "http://rubygems.org"
      when String
        source
      else
        raise GemfileError, "Unknown source '#{source}'"
      end
    end

valid_keys() click to toggle source

    # File lib/bundler/dsl.rb, line 309
    def valid_keys
      @valid_keys ||= %w(group groups git path glob name branch ref tag require submodules platform platforms type source install_if)
    end

validate_keys(command, opts, valid_keys) click to toggle source

    # File lib/bundler/dsl.rb, line 384
    def validate_keys(command, opts, valid_keys)
      invalid_keys = opts.keys - valid_keys

      git_source = opts.keys & @git_sources.keys.map(&:to_s)
      if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?)
        raise GemfileError, %Q(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch)
      end

      if invalid_keys.any?
        message = String.new
        message << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} "
        message << if invalid_keys.size > 1
                     "as options for #{command}, but they are invalid."
                   else
                     "as an option for #{command}, but it is invalid."
                   end

        message << " Valid options are: #{valid_keys.join(", ")}."
        message << " You may be able to resolve this by upgrading Bundler to the newest version."
        raise InvalidOption, message
      end
    end

warn_deprecated_git_source(name, repo_string) click to toggle source

    # File lib/bundler/dsl.rb, line 447
        def warn_deprecated_git_source(name, repo_string)
          # TODO: 2.0 remove deprecation
          Bundler::SharedHelpers.major_deprecation <<-EOS
    The :#{name} git source is deprecated, and will be removed in Bundler 2.0. Add this code to your Gemfile to ensure it continues to work:
        git_source(:#{name}) do |repo_name|
          "#{repo_string}"
        end
          EOS
        end

warn_github_source_change(repo_name) click to toggle source

    # File lib/bundler/dsl.rb, line 440
    def warn_github_source_change(repo_name)
      # TODO: 2.0 remove deprecation
      Bundler::SharedHelpers.major_deprecation "The :github option uses the git: protocol, which is not secure. "          "Bundler 2.0 will use the https: protocol, which is secure. Enable this change now by "          "running `bundle config github.https true`."
    end

with_source(source) { || ... } click to toggle source

    # File lib/bundler/dsl.rb, line 291
    def with_source(source)
      old_source = @source
      if block_given?
        @source = source
        yield
      end
      source
    ensure
      @source = old_source
    end