Class: Bundler::Dsl
Relationships & Source Files | |
Namespace Children | |
Exceptions:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
RubyDsl
|
|
Inherits: | Object |
Defined in: | lib/bundler/dsl.rb |
Constant Summary
-
GITHUB_PULL_REQUEST_URL =
# File 'lib/bundler/dsl.rb', line 21%r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]/[A-Za-z0-9_\-\.])/pull/(\d+)\z}.freeze
-
VALID_KEYS =
# File 'lib/bundler/dsl.rb', line 18%w[group groups git path glob name branch ref tag require submodules platform platforms type source install_if gemfile].freeze
-
VALID_PLATFORMS =
# File 'lib/bundler/dsl.rb', line 16Bundler::Dependency::PLATFORM_MAP.keys.freeze
Class Method Summary
- .evaluate(gemfile, lockfile, unlock)
- .new ⇒ Dsl constructor
Instance Attribute Summary
- #dependencies rw
- #gemspecs readonly
Instance Method Summary
- #check_primary_source_safety
- #env(name)
- #eval_gemfile(gemfile, contents = nil)
- #gem(name, *args) (also: #_gem)
- #gemfile_root
- #gemspec(opts = nil)
- #git(uri, options = {}, &blk)
- #git_source(name, &block)
- #github(repo, options = {})
- #group(*args, &blk)
- #install_if(*args)
- #method_missing(name, *args)
- #path(path, options = {}, &blk)
-
#platform(*platforms)
Alias for #platforms.
- #platforms(*platforms) (also: #platform)
- #plugin(*args)
- #source(source, *args, &blk)
- #to_definition(lockfile, unlock)
- #add_git_sources private
- #check_path_source_safety private
- #check_rubygems_source_safety private
- #implicit_global_source_warning private
- #multiple_global_source_warning private
- #normalize_group_options(opts, groups) private
- #normalize_hash(opts) private
- #normalize_options(name, version, opts) private
- #normalize_source(source) private
- #valid_keys private
- #validate_keys(command, opts, valid_keys) private
- #warn_deprecated_git_source(name, replacement, additional_message = nil) private
- #with_source(source) private
RubyDsl
- Included
Constructor Details
.new ⇒ Dsl
# File 'lib/bundler/dsl.rb', line 26
def initialize @source = nil @sources = SourceList.new @git_sources = {} @dependencies = [] @groups = [] @install_conditionals = [] @optional_groups = [] @platforms = [] @env = nil @ruby_version = nil @gemspecs = [] @gemfile = nil @gemfiles = [] add_git_sources end
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args)
# File 'lib/bundler/dsl.rb', line 267
def method_missing(name, *args) raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" end
Class Method Details
.evaluate(gemfile, lockfile, unlock)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 10
def self.evaluate(gemfile, lockfile, unlock) builder = new builder.eval_gemfile(gemfile) builder.to_definition(lockfile, unlock) end
Instance Attribute Details
#dependencies (rw)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 24
attr_accessor :dependencies
#gemspecs (readonly)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 23
attr_reader :gemspecs
Instance Method Details
#add_git_sources (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 278
def add_git_sources git_source(:github) do |repo_name| warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".') "https://github.com/#{repo_name}.git" RUBY if repo_name =~ GITHUB_PULL_REQUEST_URL { "git" => "https://github.com/#{$1}.git", "branch" => "refs/pull/#{$2}/head", "ref" => nil, "tag" => nil, } else repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") "https://github.com/#{repo_name}.git" end end 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 git_source(:bitbucket) do |repo_name| warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip) user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" RUBY user_name, repo_name = repo_name.split("/") repo_name ||= user_name "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git" end end
#check_path_source_safety (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 450
def check_path_source_safety return if @sources.global_path_source.nil? msg = "You can no longer specify a path source by itself. Instead, \n" \ "either use the :path option on a gem, or specify the gems that \n" \ "bundler should find in the path source by passing a block to \n" \ "the path method, like: \n\n" \ " path 'dir/containing/rails' do\n" \ " gem 'rails'\n" \ " end\n\n" SharedHelpers.major_deprecation(2, msg.strip) end
#check_primary_source_safety
[ GitHub ]# File 'lib/bundler/dsl.rb', line 271
def check_primary_source_safety check_path_source_safety check_rubygems_source_safety end
#check_rubygems_source_safety (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 464
def check_rubygems_source_safety if @sources.implicit_global_source? implicit_global_source_warning elsif @sources.aggregate_global_source? multiple_global_source_warning end end
#env(name)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 255
def env(name) old = @env @env = name yield ensure @env = old end
#eval_gemfile(gemfile, contents = nil)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 43
def eval_gemfile(gemfile, contents = nil) = Pathname.new(gemfile). (@gemfile && @gemfile.parent) original_gemfile = @gemfile @gemfile = @gemfiles << contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) rescue Exception => e # rubocop:disable Lint/RescueException = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ "`#{File.basename gemfile.to_s}`: #{e.}" raise DSLError.new(, gemfile, e.backtrace, contents) ensure @gemfile = original_gemfile end
#gem(name, *args) Also known as: #_gem
[ GitHub ]# File 'lib/bundler/dsl.rb', line 95
def gem(name, *args) = args.last.is_a?(Hash) ? args.pop.dup : {} ["gemfile"] = @gemfile version = args || [">= 0"] (name, version, ) dep = Dependency.new(name, version, ) # if there's already a dependency with this name we try to prefer one if current = @dependencies.find {|d| d.name == dep.name } deleted_dep = @dependencies.delete(current) if current.type == :development unless deleted_dep if current.requirement != dep.requirement return if dep.type == :development update_prompt = "" if File.basename(@gemfile) == Injector::INJECTED_GEMS if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0") update_prompt = ". Gem already added" else update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`" update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0") end end 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})" \ "#{update_prompt}" 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" \ "Remove any duplicate entries and specify the gem only once.\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 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
#gemfile_root
[ GitHub ]# File 'lib/bundler/dsl.rb', line 610
def gemfile_root @gemfile ||= Bundler.default_gemfile @gemfile.dirname end
#gemspec(opts = nil)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 60
def gemspec(opts = nil) opts ||= {} path = opts[:path] || "." glob = opts[:glob] name = opts[:name] development_group = opts[:development_group] || :development = gemfile_root.join(path) gemspecs = Gem::Util.glob_files_in_dir("{,*}.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 spec.name, :name => spec.name, :path => path, :glob => glob 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 #{}" else raise InvalidOption, "There are multiple gemspecs at #{}. " \ "Please use the :name option to specify which one should be used" end end
#git(uri, options = {}, &blk)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 196
def git(uri, = {}, &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( ).merge("uri" => uri)), &blk) end
#git_source(name, &block)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 170
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 = {})
# File 'lib/bundler/dsl.rb', line 211
def github(repo, = {}) raise ArgumentError, "GitHub sources require a block" unless block_given? github_uri = @git_sources["github"].call(repo) = normalize_hash( ).merge("uri" => github_uri) git_source = @sources.add_git_source( ) with_source(git_source) { yield } end
#group(*args, &blk)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 224
def group(*args, &blk) = args.last.is_a?(Hash) ? args.pop.dup : {} (, args) @groups.concat args if ["optional"] optional_groups = args - @optional_groups @optional_groups.concat optional_groups end yield ensure args.each { @groups.pop } end
#implicit_global_source_warning (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 472
def implicit_global_source_warning Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \ "Not using an explicit global source may result in a different lockfile being generated depending on " \ "the gems you have installed locally before bundler is run. " \ "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"." end
#install_if(*args)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 240
def install_if(*args) @install_conditionals.concat args yield ensure args.each { @install_conditionals.pop } end
#multiple_global_source_warning (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 479
def multiple_global_source_warning if Bundler.feature_flag.bundler_3_mode? msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ "should come from that source" raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation 2, "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." end end
#normalize_group_options(opts, groups) (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 404
def (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) (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 326
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) (private)
# File 'lib/bundler/dsl.rb', line 337
def (name, version, opts) if name.is_a?(Symbol) raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead) end if name =~ /\s/ raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace) end raise GemfileError, %(an empty gem name is not valid) if name.empty? 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] git_opts = @git_sources[git_name].call(opts[git_name]) git_opts = { "git" => git_opts } if git_opts.is_a?(String) opts.merge!(git_opts) do |key, _gemfile_value, _git_source_value| raise GemfileError, %(The :#{key} option can't be used with `#{git_name}: #{opts[git_name].inspect}`) end end %w[git path].each do |type| next unless param = opts[type] if version.first && version.first =~ /^\s*=?\s*(\d[^\s]*)\s*$/ = opts.merge("name" => name, "version" => $1) else = opts.dup end source = send(type, param, ) {} 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) (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 436
def normalize_source(source) case source when :gemcutter, :rubygems, :rubyforge Bundler::SharedHelpers.major_deprecation 2, "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
#path(path, options = {}, &blk)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 183
def path(path, = {}, &blk) = normalize_hash( ).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, "gemspec" => gemspecs.find {|g| g.name == ["name"] } ) ["global"] = true unless block_given? source = @sources.add_path_source( ) with_source(source, &blk) end
#platform(*platforms)
Alias for #platforms.
# File 'lib/bundler/dsl.rb', line 253
alias_method :platform, :platforms
#platforms(*platforms) Also known as: #platform
[ GitHub ]# File 'lib/bundler/dsl.rb', line 247
def platforms(*platforms) @platforms.concat platforms yield ensure platforms.each { @platforms.pop } end
#plugin(*args)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 263
def plugin(*args) # Pass on end
#source(source, *args, &blk)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 146
def source(source, *args, &blk) = args.last.is_a?(Hash) ? args.pop.dup : {} = normalize_hash( ) source = normalize_source(source) if .key?("type") ["type"] = ["type"].to_s unless Plugin.source?( ["type"]) raise InvalidOption, "No plugin sources available for #{ ["type"]}" end unless block_given? raise InvalidOption, "You need to pass a block to #source with :type option" end source_opts = .merge("uri" => source) with_source(@sources.add_plugin_source( ["type"], source_opts), &blk) elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else @sources.add_global_rubygems_remote(source) end end
#to_definition(lockfile, unlock)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 219
def to_definition(lockfile, unlock) check_primary_source_safety Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles) end
#valid_keys (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 333
def valid_keys @valid_keys ||= VALID_KEYS end
#validate_keys(command, opts, valid_keys) (private)
# File 'lib/bundler/dsl.rb', line 413
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, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch) end return true unless invalid_keys.any? = String.new << "You passed #{invalid_keys.map {|k| ":" + k }.join(", ")} " << if invalid_keys.size > 1 "as options for #{command}, but they are invalid." else "as an option for #{command}, but it is invalid." end << " Valid options are: #{valid_keys.join(", ")}." << " You may be able to resolve this by upgrading Bundler to the newest version." raise InvalidOption, end
#warn_deprecated_git_source(name, replacement, additional_message = nil) (private)
[ GitHub ]# File 'lib/bundler/dsl.rb', line 493
def warn_deprecated_git_source(name, replacement, = nil) &&= " #{}" replacement = if replacement.count("\n").zero? "{|repo_name| #{replacement} }" else "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end" end Bundler::SharedHelpers.major_deprecation 3, <<-EOS The :#{name} git source is deprecated, and will be removed in the future.#{} Add this code to the top of your Gemfile to ensure it continues to work: git_source(:#{name}) #{replacement} EOS end