Knapsack class in Ruby











up vote
1
down vote

favorite












This is a simple implementation of a knapsack written in Ruby. I've included all the relevant code here, but my question is concerning the contents setter .contents=



## item.rb
class Item
attr_accessor :weight
attr_accessor :data

def initialize(weight:, data: nil)
@weight = weight
@data = data
end

end




## knapsack.rb
class KnapsackCapacityExceededError < StandardError; end
class KnapsackWeightExceededError < StandardError; end
class KnapsackContentError < StandardError; end

require_relative('./item')

class Knapsack
attr_reader :capacity
attr_reader :weight
attr_reader :contents

def initialize(capacity:, weight:)
@capacity = capacity
@weight = weight
@contents = Array.new(@capacity) { nil }
end

def contents=(new_contents)
raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

@contents = new_contents
end

def fit?(contents)
return false if self.exceeds_weight?(contents) || self.exceeds_capacity?(contents)
true
end
alias_method :fits?, :fit?

def fits_weight?(contents)
new_weight = contents.map { |item| item.weight }.sum
return true if new_weight <= self.weight
false
end

def exceeds_weight?(contents)
return true if !fits_weight? contents
false
end

def fits_capacity?(contents)
return true if contents.length <= self.capacity
false
end

def exceeds_capacity?(contents)
return true if !fits_capacity? contents
false
end

end

# k = Knapsack.new(capacity: 10, weight: 50)


In this method there are three conditions where an exception is raised, is this a code smell?



Any other feedback also appreciated.










share|improve this question




























    up vote
    1
    down vote

    favorite












    This is a simple implementation of a knapsack written in Ruby. I've included all the relevant code here, but my question is concerning the contents setter .contents=



    ## item.rb
    class Item
    attr_accessor :weight
    attr_accessor :data

    def initialize(weight:, data: nil)
    @weight = weight
    @data = data
    end

    end




    ## knapsack.rb
    class KnapsackCapacityExceededError < StandardError; end
    class KnapsackWeightExceededError < StandardError; end
    class KnapsackContentError < StandardError; end

    require_relative('./item')

    class Knapsack
    attr_reader :capacity
    attr_reader :weight
    attr_reader :contents

    def initialize(capacity:, weight:)
    @capacity = capacity
    @weight = weight
    @contents = Array.new(@capacity) { nil }
    end

    def contents=(new_contents)
    raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
    raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
    raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

    @contents = new_contents
    end

    def fit?(contents)
    return false if self.exceeds_weight?(contents) || self.exceeds_capacity?(contents)
    true
    end
    alias_method :fits?, :fit?

    def fits_weight?(contents)
    new_weight = contents.map { |item| item.weight }.sum
    return true if new_weight <= self.weight
    false
    end

    def exceeds_weight?(contents)
    return true if !fits_weight? contents
    false
    end

    def fits_capacity?(contents)
    return true if contents.length <= self.capacity
    false
    end

    def exceeds_capacity?(contents)
    return true if !fits_capacity? contents
    false
    end

    end

    # k = Knapsack.new(capacity: 10, weight: 50)


    In this method there are three conditions where an exception is raised, is this a code smell?



    Any other feedback also appreciated.










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      This is a simple implementation of a knapsack written in Ruby. I've included all the relevant code here, but my question is concerning the contents setter .contents=



      ## item.rb
      class Item
      attr_accessor :weight
      attr_accessor :data

      def initialize(weight:, data: nil)
      @weight = weight
      @data = data
      end

      end




      ## knapsack.rb
      class KnapsackCapacityExceededError < StandardError; end
      class KnapsackWeightExceededError < StandardError; end
      class KnapsackContentError < StandardError; end

      require_relative('./item')

      class Knapsack
      attr_reader :capacity
      attr_reader :weight
      attr_reader :contents

      def initialize(capacity:, weight:)
      @capacity = capacity
      @weight = weight
      @contents = Array.new(@capacity) { nil }
      end

      def contents=(new_contents)
      raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
      raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
      raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

      @contents = new_contents
      end

      def fit?(contents)
      return false if self.exceeds_weight?(contents) || self.exceeds_capacity?(contents)
      true
      end
      alias_method :fits?, :fit?

      def fits_weight?(contents)
      new_weight = contents.map { |item| item.weight }.sum
      return true if new_weight <= self.weight
      false
      end

      def exceeds_weight?(contents)
      return true if !fits_weight? contents
      false
      end

      def fits_capacity?(contents)
      return true if contents.length <= self.capacity
      false
      end

      def exceeds_capacity?(contents)
      return true if !fits_capacity? contents
      false
      end

      end

      # k = Knapsack.new(capacity: 10, weight: 50)


      In this method there are three conditions where an exception is raised, is this a code smell?



      Any other feedback also appreciated.










      share|improve this question















      This is a simple implementation of a knapsack written in Ruby. I've included all the relevant code here, but my question is concerning the contents setter .contents=



      ## item.rb
      class Item
      attr_accessor :weight
      attr_accessor :data

      def initialize(weight:, data: nil)
      @weight = weight
      @data = data
      end

      end




      ## knapsack.rb
      class KnapsackCapacityExceededError < StandardError; end
      class KnapsackWeightExceededError < StandardError; end
      class KnapsackContentError < StandardError; end

      require_relative('./item')

      class Knapsack
      attr_reader :capacity
      attr_reader :weight
      attr_reader :contents

      def initialize(capacity:, weight:)
      @capacity = capacity
      @weight = weight
      @contents = Array.new(@capacity) { nil }
      end

      def contents=(new_contents)
      raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
      raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
      raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

      @contents = new_contents
      end

      def fit?(contents)
      return false if self.exceeds_weight?(contents) || self.exceeds_capacity?(contents)
      true
      end
      alias_method :fits?, :fit?

      def fits_weight?(contents)
      new_weight = contents.map { |item| item.weight }.sum
      return true if new_weight <= self.weight
      false
      end

      def exceeds_weight?(contents)
      return true if !fits_weight? contents
      false
      end

      def fits_capacity?(contents)
      return true if contents.length <= self.capacity
      false
      end

      def exceeds_capacity?(contents)
      return true if !fits_capacity? contents
      false
      end

      end

      # k = Knapsack.new(capacity: 10, weight: 50)


      In this method there are three conditions where an exception is raised, is this a code smell?



      Any other feedback also appreciated.







      ruby knapsack-problem






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 16 at 17:27

























      asked Nov 16 at 16:11









      0112

      1427




      1427






















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          2
          down vote













          So there are multiple things. First of all I'll share the code refactoring related suggestions and then we can look at the performance improvements of code.



          Refactoring





          1. You don't really need to pass a block to Array.new to initialize the array with nil values.



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity) { nil }
            end


            can be refactored to:



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity)
            end



          2. def contents=(new_contents)
            raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
            raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

            @contents = new_contents
            end


            can be refactored to:



            def contents=(new_contents)
            raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if exceeds_weight? new_contents
            raise KnapsackContentError if has_non_items? new_contents

            @contents = new_contents
            end

            def has_non_items?(contents)
            contents.any? { |content| !content.is_a?(Item) }
            end


            -> Notice that usage of self keyword has been removed.



            -> Moved the logic of checking any non-items in contents to a separate method. That makes the if conditions more readable and it replaces the unless with if to make it consistent with rest of the conditions.




          3. Method fit? can be refactored to:



            def fit?(contents)
            fits_weight?(contents) && fits_capacity?(contents)
            end



          4. Method fits_weight? can be refactored as well.



            def fits_weight?(contents)
            contents.map(&:weight).sum <= weight
            end



          Performance Tuning



          You don't need to initialize the @contents array with nil elements. You can just write @contents = to save some extra used memory.






          share|improve this answer










          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
            – Graipher
            7 hours ago












          • All good points. Thanks for your feedback.
            – 0112
            6 hours ago


















          up vote
          1
          down vote













          First of all return true if ... else false is not necessary. Just return the original condition. For example:



            def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end




          Next, self. is not necessary in most cases, including every case it is used in this program. self.weight should be replaced with @weight.





          knapsack.rb should look more like:



          class KnapsackCapacityExceededError < StandardError; end
          class KnapsackWeightExceededError < StandardError; end
          class KnapsackContentError < StandardError; end

          require_relative('./item')

          class Knapsack
          attr_reader :capacity
          attr_reader :weight
          attr_reader :contents

          def initialize(capacity:, weight:)
          @capacity = capacity
          @weight = weight
          @contents = Array.new(@capacity) { nil }
          end

          def contents=(new_contents)
          raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
          raise KnapsackWeightExceededError if exceeds_weight? new_contents
          raise KnapsackContentError if new_contents.any? { |e| !e.is_a? Item }

          @contents = new_contents
          end

          def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end
          alias_method :fits?, :fit?

          def fits_weight?(contents)
          new_weight = contents.map { |item| item.weight }.sum
          new_weight <= @weight
          end

          def exceeds_weight?(contents)
          !fits_weight? contents
          end

          def fits_capacity?(contents)
          contents.length <= @capacity
          end

          def exceeds_capacity?(contents)
          !fits_capacity? contents
          end

          end




          I do not think that three raise conditions are a problem. That code is clear and simple. The three exception classes may be a bit much.






          share|improve this answer























          • Thanks for the feedback.
            – 0112
            Nov 16 at 21:03










          • Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
            – David Aldridge
            18 hours ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207817%2fknapsack-class-in-ruby%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote













          So there are multiple things. First of all I'll share the code refactoring related suggestions and then we can look at the performance improvements of code.



          Refactoring





          1. You don't really need to pass a block to Array.new to initialize the array with nil values.



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity) { nil }
            end


            can be refactored to:



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity)
            end



          2. def contents=(new_contents)
            raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
            raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

            @contents = new_contents
            end


            can be refactored to:



            def contents=(new_contents)
            raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if exceeds_weight? new_contents
            raise KnapsackContentError if has_non_items? new_contents

            @contents = new_contents
            end

            def has_non_items?(contents)
            contents.any? { |content| !content.is_a?(Item) }
            end


            -> Notice that usage of self keyword has been removed.



            -> Moved the logic of checking any non-items in contents to a separate method. That makes the if conditions more readable and it replaces the unless with if to make it consistent with rest of the conditions.




          3. Method fit? can be refactored to:



            def fit?(contents)
            fits_weight?(contents) && fits_capacity?(contents)
            end



          4. Method fits_weight? can be refactored as well.



            def fits_weight?(contents)
            contents.map(&:weight).sum <= weight
            end



          Performance Tuning



          You don't need to initialize the @contents array with nil elements. You can just write @contents = to save some extra used memory.






          share|improve this answer










          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
            – Graipher
            7 hours ago












          • All good points. Thanks for your feedback.
            – 0112
            6 hours ago















          up vote
          2
          down vote













          So there are multiple things. First of all I'll share the code refactoring related suggestions and then we can look at the performance improvements of code.



          Refactoring





          1. You don't really need to pass a block to Array.new to initialize the array with nil values.



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity) { nil }
            end


            can be refactored to:



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity)
            end



          2. def contents=(new_contents)
            raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
            raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

            @contents = new_contents
            end


            can be refactored to:



            def contents=(new_contents)
            raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if exceeds_weight? new_contents
            raise KnapsackContentError if has_non_items? new_contents

            @contents = new_contents
            end

            def has_non_items?(contents)
            contents.any? { |content| !content.is_a?(Item) }
            end


            -> Notice that usage of self keyword has been removed.



            -> Moved the logic of checking any non-items in contents to a separate method. That makes the if conditions more readable and it replaces the unless with if to make it consistent with rest of the conditions.




          3. Method fit? can be refactored to:



            def fit?(contents)
            fits_weight?(contents) && fits_capacity?(contents)
            end



          4. Method fits_weight? can be refactored as well.



            def fits_weight?(contents)
            contents.map(&:weight).sum <= weight
            end



          Performance Tuning



          You don't need to initialize the @contents array with nil elements. You can just write @contents = to save some extra used memory.






          share|improve this answer










          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.


















          • I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
            – Graipher
            7 hours ago












          • All good points. Thanks for your feedback.
            – 0112
            6 hours ago













          up vote
          2
          down vote










          up vote
          2
          down vote









          So there are multiple things. First of all I'll share the code refactoring related suggestions and then we can look at the performance improvements of code.



          Refactoring





          1. You don't really need to pass a block to Array.new to initialize the array with nil values.



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity) { nil }
            end


            can be refactored to:



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity)
            end



          2. def contents=(new_contents)
            raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
            raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

            @contents = new_contents
            end


            can be refactored to:



            def contents=(new_contents)
            raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if exceeds_weight? new_contents
            raise KnapsackContentError if has_non_items? new_contents

            @contents = new_contents
            end

            def has_non_items?(contents)
            contents.any? { |content| !content.is_a?(Item) }
            end


            -> Notice that usage of self keyword has been removed.



            -> Moved the logic of checking any non-items in contents to a separate method. That makes the if conditions more readable and it replaces the unless with if to make it consistent with rest of the conditions.




          3. Method fit? can be refactored to:



            def fit?(contents)
            fits_weight?(contents) && fits_capacity?(contents)
            end



          4. Method fits_weight? can be refactored as well.



            def fits_weight?(contents)
            contents.map(&:weight).sum <= weight
            end



          Performance Tuning



          You don't need to initialize the @contents array with nil elements. You can just write @contents = to save some extra used memory.






          share|improve this answer










          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          So there are multiple things. First of all I'll share the code refactoring related suggestions and then we can look at the performance improvements of code.



          Refactoring





          1. You don't really need to pass a block to Array.new to initialize the array with nil values.



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity) { nil }
            end


            can be refactored to:



            def initialize(capacity:, weight:)
            @capacity = capacity
            @weight = weight
            @contents = Array.new(@capacity)
            end



          2. def contents=(new_contents)
            raise KnapsackCapacityExceededError if self.exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if self.exceeds_weight? new_contents
            raise KnapsackContentError unless new_contents.all? { |e| e.is_a? Item }

            @contents = new_contents
            end


            can be refactored to:



            def contents=(new_contents)
            raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
            raise KnapsackWeightExceededError if exceeds_weight? new_contents
            raise KnapsackContentError if has_non_items? new_contents

            @contents = new_contents
            end

            def has_non_items?(contents)
            contents.any? { |content| !content.is_a?(Item) }
            end


            -> Notice that usage of self keyword has been removed.



            -> Moved the logic of checking any non-items in contents to a separate method. That makes the if conditions more readable and it replaces the unless with if to make it consistent with rest of the conditions.




          3. Method fit? can be refactored to:



            def fit?(contents)
            fits_weight?(contents) && fits_capacity?(contents)
            end



          4. Method fits_weight? can be refactored as well.



            def fits_weight?(contents)
            contents.map(&:weight).sum <= weight
            end



          Performance Tuning



          You don't need to initialize the @contents array with nil elements. You can just write @contents = to save some extra used memory.







          share|improve this answer










          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          share|improve this answer



          share|improve this answer








          edited 7 hours ago









          Graipher

          22.1k53183




          22.1k53183






          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          answered 7 hours ago









          KULKING

          1214




          1214




          New contributor




          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.





          New contributor





          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.






          KULKING is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.












          • I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
            – Graipher
            7 hours ago












          • All good points. Thanks for your feedback.
            – 0112
            6 hours ago


















          • I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
            – Graipher
            7 hours ago












          • All good points. Thanks for your feedback.
            – 0112
            6 hours ago
















          I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
          – Graipher
          7 hours ago






          I edited your answer so that your enumeration is an actual enumeration (in markdown). For this basically everything is indented one level further. If you prefer the old style, you can always roll back the edit here.
          – Graipher
          7 hours ago














          All good points. Thanks for your feedback.
          – 0112
          6 hours ago




          All good points. Thanks for your feedback.
          – 0112
          6 hours ago












          up vote
          1
          down vote













          First of all return true if ... else false is not necessary. Just return the original condition. For example:



            def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end




          Next, self. is not necessary in most cases, including every case it is used in this program. self.weight should be replaced with @weight.





          knapsack.rb should look more like:



          class KnapsackCapacityExceededError < StandardError; end
          class KnapsackWeightExceededError < StandardError; end
          class KnapsackContentError < StandardError; end

          require_relative('./item')

          class Knapsack
          attr_reader :capacity
          attr_reader :weight
          attr_reader :contents

          def initialize(capacity:, weight:)
          @capacity = capacity
          @weight = weight
          @contents = Array.new(@capacity) { nil }
          end

          def contents=(new_contents)
          raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
          raise KnapsackWeightExceededError if exceeds_weight? new_contents
          raise KnapsackContentError if new_contents.any? { |e| !e.is_a? Item }

          @contents = new_contents
          end

          def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end
          alias_method :fits?, :fit?

          def fits_weight?(contents)
          new_weight = contents.map { |item| item.weight }.sum
          new_weight <= @weight
          end

          def exceeds_weight?(contents)
          !fits_weight? contents
          end

          def fits_capacity?(contents)
          contents.length <= @capacity
          end

          def exceeds_capacity?(contents)
          !fits_capacity? contents
          end

          end




          I do not think that three raise conditions are a problem. That code is clear and simple. The three exception classes may be a bit much.






          share|improve this answer























          • Thanks for the feedback.
            – 0112
            Nov 16 at 21:03










          • Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
            – David Aldridge
            18 hours ago















          up vote
          1
          down vote













          First of all return true if ... else false is not necessary. Just return the original condition. For example:



            def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end




          Next, self. is not necessary in most cases, including every case it is used in this program. self.weight should be replaced with @weight.





          knapsack.rb should look more like:



          class KnapsackCapacityExceededError < StandardError; end
          class KnapsackWeightExceededError < StandardError; end
          class KnapsackContentError < StandardError; end

          require_relative('./item')

          class Knapsack
          attr_reader :capacity
          attr_reader :weight
          attr_reader :contents

          def initialize(capacity:, weight:)
          @capacity = capacity
          @weight = weight
          @contents = Array.new(@capacity) { nil }
          end

          def contents=(new_contents)
          raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
          raise KnapsackWeightExceededError if exceeds_weight? new_contents
          raise KnapsackContentError if new_contents.any? { |e| !e.is_a? Item }

          @contents = new_contents
          end

          def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end
          alias_method :fits?, :fit?

          def fits_weight?(contents)
          new_weight = contents.map { |item| item.weight }.sum
          new_weight <= @weight
          end

          def exceeds_weight?(contents)
          !fits_weight? contents
          end

          def fits_capacity?(contents)
          contents.length <= @capacity
          end

          def exceeds_capacity?(contents)
          !fits_capacity? contents
          end

          end




          I do not think that three raise conditions are a problem. That code is clear and simple. The three exception classes may be a bit much.






          share|improve this answer























          • Thanks for the feedback.
            – 0112
            Nov 16 at 21:03










          • Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
            – David Aldridge
            18 hours ago













          up vote
          1
          down vote










          up vote
          1
          down vote









          First of all return true if ... else false is not necessary. Just return the original condition. For example:



            def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end




          Next, self. is not necessary in most cases, including every case it is used in this program. self.weight should be replaced with @weight.





          knapsack.rb should look more like:



          class KnapsackCapacityExceededError < StandardError; end
          class KnapsackWeightExceededError < StandardError; end
          class KnapsackContentError < StandardError; end

          require_relative('./item')

          class Knapsack
          attr_reader :capacity
          attr_reader :weight
          attr_reader :contents

          def initialize(capacity:, weight:)
          @capacity = capacity
          @weight = weight
          @contents = Array.new(@capacity) { nil }
          end

          def contents=(new_contents)
          raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
          raise KnapsackWeightExceededError if exceeds_weight? new_contents
          raise KnapsackContentError if new_contents.any? { |e| !e.is_a? Item }

          @contents = new_contents
          end

          def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end
          alias_method :fits?, :fit?

          def fits_weight?(contents)
          new_weight = contents.map { |item| item.weight }.sum
          new_weight <= @weight
          end

          def exceeds_weight?(contents)
          !fits_weight? contents
          end

          def fits_capacity?(contents)
          contents.length <= @capacity
          end

          def exceeds_capacity?(contents)
          !fits_capacity? contents
          end

          end




          I do not think that three raise conditions are a problem. That code is clear and simple. The three exception classes may be a bit much.






          share|improve this answer














          First of all return true if ... else false is not necessary. Just return the original condition. For example:



            def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end




          Next, self. is not necessary in most cases, including every case it is used in this program. self.weight should be replaced with @weight.





          knapsack.rb should look more like:



          class KnapsackCapacityExceededError < StandardError; end
          class KnapsackWeightExceededError < StandardError; end
          class KnapsackContentError < StandardError; end

          require_relative('./item')

          class Knapsack
          attr_reader :capacity
          attr_reader :weight
          attr_reader :contents

          def initialize(capacity:, weight:)
          @capacity = capacity
          @weight = weight
          @contents = Array.new(@capacity) { nil }
          end

          def contents=(new_contents)
          raise KnapsackCapacityExceededError if exceeds_capacity? new_contents
          raise KnapsackWeightExceededError if exceeds_weight? new_contents
          raise KnapsackContentError if new_contents.any? { |e| !e.is_a? Item }

          @contents = new_contents
          end

          def fit?(contents)
          fits_weight?(contents) && fits_capacity?(contents)
          end
          alias_method :fits?, :fit?

          def fits_weight?(contents)
          new_weight = contents.map { |item| item.weight }.sum
          new_weight <= @weight
          end

          def exceeds_weight?(contents)
          !fits_weight? contents
          end

          def fits_capacity?(contents)
          contents.length <= @capacity
          end

          def exceeds_capacity?(contents)
          !fits_capacity? contents
          end

          end




          I do not think that three raise conditions are a problem. That code is clear and simple. The three exception classes may be a bit much.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 16 at 20:45

























          answered Nov 16 at 20:36









          MegaTom

          1864




          1864












          • Thanks for the feedback.
            – 0112
            Nov 16 at 21:03










          • Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
            – David Aldridge
            18 hours ago


















          • Thanks for the feedback.
            – 0112
            Nov 16 at 21:03










          • Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
            – David Aldridge
            18 hours ago
















          Thanks for the feedback.
          – 0112
          Nov 16 at 21:03




          Thanks for the feedback.
          – 0112
          Nov 16 at 21:03












          Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
          – David Aldridge
          18 hours ago




          Bit off topic, but maybe replace contents.map { |item| item.weight }.sum with contents.sum(&:weight). I'd be tempted to replace new_contents.any? { |e| !e.is_a? Item } with new_contents.all? { |e| e.is_a? Item } also.
          – David Aldridge
          18 hours ago


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207817%2fknapsack-class-in-ruby%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          Refactoring coordinates for Minecraft Pi buildings written in Python