diff --git a/lib/warbler/config.rb b/lib/warbler/config.rb index 01dad970..f5f26d98 100644 --- a/lib/warbler/config.rb +++ b/lib/warbler/config.rb @@ -31,7 +31,7 @@ class Config # Traits: an array of trait classes corresponding to # characteristics of the project that are either auto-detected or # configured. - attr_accessor :traits + attr_reader :traits # Directory where the war file will be written. Can be used to direct # Warbler to place your war file directly in your application server's @@ -183,8 +183,8 @@ class Config attr_reader :warbler_templates attr_reader :warbler_scripts - def initialize(warbler_home = WARBLER_HOME) - super() + def initialize(warbler_home = WARBLER_HOME, forced_traits: []) + super(forced_traits) @warbler_home = warbler_home @warbler_templates = "#{WARBLER_HOME}/lib/warbler/templates" diff --git a/lib/warbler/traits.rb b/lib/warbler/traits.rb index 17d3499a..78c5abc9 100644 --- a/lib/warbler/traits.rb +++ b/lib/warbler/traits.rb @@ -15,14 +15,28 @@ module Warbler # the kind of project and how it should be packed into the jar or # war file. module Traits - attr_accessor :traits - - def initialize + def initialize(forced_traits = []) + @forced_traits = forced_traits @traits = auto_detect_traits end def auto_detect_traits - TraitsDependencyArray.new(Traits.constants.map {|t| Traits.const_get(t)}).tsort.select {|tc| tc.detect? } + all_trait_classes = Traits.constants.map { |t| Traits.const_get(t) } + sorted = TraitsDependencyArray.new(all_trait_classes).tsort + + conflicts = @forced_traits.flat_map { |ft| ft.conflicts }.uniq + + sorted.select do |tc| + if @forced_traits.include?(tc) + true + elsif conflicts.include?(tc) + false + elsif tc.requirements.any? && tc.requirements.all? { |req| conflicts.include?(req) } + false + else + tc.detect? + end + end end def before_configure @@ -53,6 +67,10 @@ module ClassMethods def requirements [] end + + def conflicts + [] + end end def self.included(base) diff --git a/lib/warbler/traits/jar.rb b/lib/warbler/traits/jar.rb index b9690403..e6ac5ef6 100644 --- a/lib/warbler/traits/jar.rb +++ b/lib/warbler/traits/jar.rb @@ -20,6 +20,10 @@ def self.detect? !War.detect? end + def self.conflicts + [War] + end + def before_configure config.gem_path = '/' config.pathmaps = default_pathmaps diff --git a/lib/warbler/traits/war.rb b/lib/warbler/traits/war.rb index a94af5cd..bd74a01b 100644 --- a/lib/warbler/traits/war.rb +++ b/lib/warbler/traits/war.rb @@ -18,7 +18,11 @@ class War DEFAULT_GEM_PATH = '/WEB-INF/gems' def self.detect? - Traits::Rails.detect? || Traits::Rack.detect? + Rails.detect? || Rack.detect? + end + + def self.conflicts + [Jar] end def before_configure diff --git a/spec/warbler/traits_spec.rb b/spec/warbler/traits_spec.rb index 0e3ff8e3..0401b85f 100644 --- a/spec/warbler/traits_spec.rb +++ b/spec/warbler/traits_spec.rb @@ -18,4 +18,62 @@ end end end + + describe "conflicts" do + it "Jar conflicts with War" do + expect(Warbler::Traits::Jar.conflicts).to include(Warbler::Traits::War) + end + + it "War conflicts with Jar" do + expect(Warbler::Traits::War.conflicts).to include(Warbler::Traits::Jar) + end + + it "traits with no declared conflicts return an empty array" do + expect(Warbler::Traits::Bundler.conflicts).to eq([]) + end + end + + describe "forced_traits" do + context "in a Rack project with Bundler" do + run_in_directory 'spec/sample_bundler' + + it "auto-detects War trait by default" do + config = Warbler::Config.new + expect(config.traits).to include(Warbler::Traits::War) + expect(config.traits).to include(Warbler::Traits::Rack) + expect(config.traits).to_not include(Warbler::Traits::Jar) + end + + it "forces Jar and excludes War when Jar is forced" do + config = Warbler::Config.new(forced_traits: [Warbler::Traits::Jar]) + expect(config.traits).to include(Warbler::Traits::Jar) + expect(config.traits).to_not include(Warbler::Traits::War) + end + + it "excludes traits that require an excluded trait" do + config = Warbler::Config.new(forced_traits: [Warbler::Traits::Jar]) + expect(config.traits).to_not include(Warbler::Traits::Rack) + end + + it "preserves non-conflicting auto-detected traits" do + config = Warbler::Config.new(forced_traits: [Warbler::Traits::Jar]) + expect(config.traits).to include(Warbler::Traits::Bundler) + end + + it "runs before_configure with forced traits" do + config = Warbler::Config.new(forced_traits: [Warbler::Traits::Jar]) + expect(config.jar_extension).to eq('jar') + end + end + + context "with no forced traits" do + run_in_directory 'spec/sample_jar' + + it "behaves identically to auto-detection" do + default_config = Warbler::Config.new + forced_config = Warbler::Config.new(forced_traits: []) + expect(forced_config.traits).to eq(default_config.traits) + end + end + end end