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






















          1 Answer
          1






          active

          oldest

          votes

















          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











          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

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          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















          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













          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


















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
















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




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


















           

          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

          Ellipse (mathématiques)

          Quarter-circle Tiles

          Mont Emei