diff --git a/README.md b/README.md index 2573c69c..464f9165 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,15 @@ customizations include: - heading: a string that by default adds "# This file was generated by Appraisal" to the top of each Gemfile, (the string will be commented for you) - single_quotes: a boolean that controls if strings are single quoted in each Gemfile, defaults to false +You can also provide variables for substitution in the heading, based on each appraisal. Currently supported variables: +- `%{appraisal}`: Becomes the name of each appraisal, e.g. `rails-3` +- `%{gemfile}`: Becomes the filename of each gemfile, e.g. `rails-3.gemfile` +- `%{gemfile_path}`: Becomes the full path of each gemfile, e.g. `/path/to/project/gemfiles/rails-3.gemfile` +- `%{lockfile}`: Becomes the filename of each lockfile, e.g. `rails-3.gemfile.lock` +- `%{lockfile_path}`: Becomes the full path of each lockfile, e.g. `/path/to/project/gemfiles/rails-3.gemfile.lock` +- `%{relative_gemfile_path}`: Becomes the relative path of each gemfile, e.g. `gemfiles/rails-3.gemfile` +- `%{relative_lockfile_path}`: Becomes the relative path of each lockfile, e.g. `gemfiles/rails-3.gemfile.lock` + ### Example Usage **Appraisals** @@ -169,8 +178,8 @@ customize_gemfiles do heading: <<~HEADING frozen_string_literal: true - File has been generated by Appraisal, do NOT modify it directly! - See the conventions at https://example.com/ + `%{gemfile}` has been generated by Appraisal, do NOT modify it or `%{lockfile}` directly! + Make the changes to the "%{appraisal}" block in `Appraisals` instead. See the conventions at https://example.com/ HEADING } end @@ -184,8 +193,8 @@ Using the `Appraisals` file defined above, this is what the resulting `Gemfile` ```ruby # frozen_string_literal: true -# File has been generated by Appraisal, do NOT modify it directly! -# See the conventions at https://example.com/ +# `rails-3.gemfile` has been generated by Appraisal, do NOT modify it or `rails-3.gemfile.lock` directly! +# Make the changes to the "rails-3" block in `Appraisals` instead. See the conventions at https://example.com/ gem 'rails', '3.2.14' ``` diff --git a/lib/appraisal/appraisal.rb b/lib/appraisal/appraisal.rb index b75dbd4b..7d7634d0 100644 --- a/lib/appraisal/appraisal.rb +++ b/lib/appraisal/appraisal.rb @@ -63,7 +63,8 @@ def git_source(*args, &block) def write_gemfile File.open(gemfile_path, "w") do |file| - signature = Customize.heading || "This file was generated by Appraisal" + signature = + Customize.heading(self) || "This file was generated by Appraisal" file.puts([comment_lines(signature), quoted_gemfile].join("\n\n")) end end diff --git a/lib/appraisal/customize.rb b/lib/appraisal/customize.rb index a1aab51d..0de1a78e 100644 --- a/lib/appraisal/customize.rb +++ b/lib/appraisal/customize.rb @@ -5,12 +5,30 @@ def initialize(heading: nil, single_quotes: false) @@single_quotes = single_quotes end - def self.heading + def self.heading(gemfile) @@heading ||= nil + customize(@@heading, gemfile) end def self.single_quotes @@single_quotes ||= false end + + def self.customize(heading, gemfile) + return nil unless heading + + format( + heading.to_s, + appraisal: gemfile.send("clean_name"), + gemfile: gemfile.send("gemfile_name"), + gemfile_path: gemfile.gemfile_path, + lockfile: "#{gemfile.send('gemfile_name')}.lock", + lockfile_path: gemfile.send("lockfile_path"), + relative_gemfile_path: gemfile.relative_gemfile_path, + relative_lockfile_path: "#{gemfile.relative_gemfile_path}.lock", + ) + end + + private_class_method :customize end end diff --git a/spec/appraisal/customize_spec.rb b/spec/appraisal/customize_spec.rb index de2e93d8..bb334543 100644 --- a/spec/appraisal/customize_spec.rb +++ b/spec/appraisal/customize_spec.rb @@ -1,18 +1,139 @@ require "spec_helper" +require "appraisal/appraisal" require "appraisal/customize" describe Appraisal::Customize do - it "has defaults" do - expect(described_class.heading).to eq nil - expect(described_class.single_quotes).to eq false - expect { described_class.new }.to_not(change do - [described_class.heading, described_class.single_quotes] - end) + let(:appraisal) { Appraisal::Appraisal.new("test", "Gemfile") } + let(:single_line_heading) { "This file was generated with a custom heading!" } + let(:multi_line_heading) do + <<~HEADING + frozen_string_literal: true + + This file was generated with a custom heading! + HEADING + end + let(:subject) { described_class.new } + let(:single_line_subject) do + described_class.new(heading: single_line_heading) + end + let(:multi_line_single_quotes_subject) do + described_class.new(heading: multi_line_heading, single_quotes: true) + end + + describe ".heading" do + it "returns nil if no heading is set" do + subject + expect(described_class.heading(appraisal)).to eq(nil) + end + + it "returns the heading if set" do + single_line_subject + expect(described_class.heading(appraisal)).to eq(single_line_heading) + end + + it "returns the heading without an trailing newline" do + multi_line_single_quotes_subject + expect(described_class.heading(appraisal)).to eq(multi_line_heading.chomp) + expect(described_class.heading(appraisal)).to_not end_with("\n") + end + end + + describe ".single_quotes" do + it "returns false if not set" do + subject + expect(described_class.single_quotes).to eq(false) + end + + it "returns true if set" do + multi_line_single_quotes_subject + expect(described_class.single_quotes).to eq(true) + end end - it "can override defaults" do - described_class.new(single_quotes: true, heading: "foo") - expect(described_class.heading).to eq "foo" - expect(described_class.single_quotes).to eq true + describe ".customize" do + let(:appraisal_name) { "test" } + let(:gemfile) { "test.gemfile" } + let(:lockfile) { "#{gemfile}.lock" } + let(:gemfile_relative_path) { "gemfiles/#{gemfile}" } + let(:lockfile_relative_path) { "gemfiles/#{lockfile}" } + let(:gemfile_full_path) { "/path/to/project/#{gemfile_relative_path}" } + let(:lockfile_full_path) { "/path/to/project/#{lockfile_relative_path}" } + before do + allow(appraisal).to receive(:gemfile_name).and_return(gemfile) + allow(appraisal).to receive(:gemfile_path).and_return(gemfile_full_path) + allow(appraisal).to receive(:lockfile_path).and_return(lockfile_full_path) + allow(appraisal).to receive(:relative_gemfile_path). + and_return(gemfile_relative_path) + end + + it "returns nil if no heading is set" do + subject + expect(described_class.send(:customize, nil, appraisal)).to eq(nil) + end + + it "returns the heading unchanged" do + single_line_subject + expect(described_class.send( + :customize, + single_line_heading, + appraisal, + )).to eq(single_line_heading) + end + + it "returns the heading with the appraisal name" do + expect(described_class.send( + :customize, + "Appraisal: %{appraisal}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Appraisal: #{appraisal_name}") + end + + it "returns the heading with the gemfile name" do + expect(described_class.send( + :customize, + "Gemfile: %{gemfile}", # rubocop:disable Style/FormatStringToken + appraisal, + )).to eq("Gemfile: #{gemfile}") + end + + it "returns the heading with the gemfile path" do + expect(described_class.send( + :customize, + "Gemfile: %{gemfile_path}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Gemfile: #{gemfile_full_path}") + end + + it "returns the heading with the lockfile name" do + expect(described_class.send( + :customize, + "Lockfile: %{lockfile}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Lockfile: #{lockfile}") + end + + it "returns the heading with the lockfile path" do + expect(described_class.send( + :customize, + "Lockfile: %{lockfile_path}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Lockfile: #{lockfile_full_path}") + end + + it "returns the heading with the relative gemfile path" do + expect(described_class.send( + :customize, + "Gemfile: %{relative_gemfile_path}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Gemfile: #{gemfile_relative_path}") + end + + it "returns the heading with the relative lockfile path" do + expect(described_class.send( + :customize, + "Gemfile: %{relative_lockfile_path}", # rubocop:disable Style/FormatStringToken, Metrics/LineLength + appraisal, + )).to eq("Gemfile: #{lockfile_relative_path}") + end end end