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.
ruby knapsack-problem
add a comment |
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.
ruby knapsack-problem
add a comment |
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.
ruby knapsack-problem
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
ruby knapsack-problem
edited Nov 16 at 17:27
asked Nov 16 at 16:11
0112
1427
1427
add a comment |
add a comment |
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
You don't really need to pass a block to
Array.new
to initialize the array withnil
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
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
withif
to make it consistent with rest of the conditions.
Method
fit?
can be refactored to:
def fit?(contents)
fits_weight?(contents) && fits_capacity?(contents)
end
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.
New contributor
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
add a comment |
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.
Thanks for the feedback.
– 0112
Nov 16 at 21:03
Bit off topic, but maybe replacecontents.map { |item| item.weight }.sum
withcontents.sum(&:weight)
. I'd be tempted to replacenew_contents.any? { |e| !e.is_a? Item }
withnew_contents.all? { |e| e.is_a? Item }
also.
– David Aldridge
18 hours ago
add a comment |
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
You don't really need to pass a block to
Array.new
to initialize the array withnil
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
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
withif
to make it consistent with rest of the conditions.
Method
fit?
can be refactored to:
def fit?(contents)
fits_weight?(contents) && fits_capacity?(contents)
end
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.
New contributor
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
add a comment |
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
You don't really need to pass a block to
Array.new
to initialize the array withnil
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
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
withif
to make it consistent with rest of the conditions.
Method
fit?
can be refactored to:
def fit?(contents)
fits_weight?(contents) && fits_capacity?(contents)
end
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.
New contributor
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
add a comment |
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
You don't really need to pass a block to
Array.new
to initialize the array withnil
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
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
withif
to make it consistent with rest of the conditions.
Method
fit?
can be refactored to:
def fit?(contents)
fits_weight?(contents) && fits_capacity?(contents)
end
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.
New contributor
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
You don't really need to pass a block to
Array.new
to initialize the array withnil
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
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
withif
to make it consistent with rest of the conditions.
Method
fit?
can be refactored to:
def fit?(contents)
fits_weight?(contents) && fits_capacity?(contents)
end
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.
New contributor
edited 7 hours ago
Graipher
22.1k53183
22.1k53183
New contributor
answered 7 hours ago
KULKING
1214
1214
New contributor
New contributor
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
add a comment |
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
add a comment |
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.
Thanks for the feedback.
– 0112
Nov 16 at 21:03
Bit off topic, but maybe replacecontents.map { |item| item.weight }.sum
withcontents.sum(&:weight)
. I'd be tempted to replacenew_contents.any? { |e| !e.is_a? Item }
withnew_contents.all? { |e| e.is_a? Item }
also.
– David Aldridge
18 hours ago
add a comment |
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.
Thanks for the feedback.
– 0112
Nov 16 at 21:03
Bit off topic, but maybe replacecontents.map { |item| item.weight }.sum
withcontents.sum(&:weight)
. I'd be tempted to replacenew_contents.any? { |e| !e.is_a? Item }
withnew_contents.all? { |e| e.is_a? Item }
also.
– David Aldridge
18 hours ago
add a comment |
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.
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.
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 replacecontents.map { |item| item.weight }.sum
withcontents.sum(&:weight)
. I'd be tempted to replacenew_contents.any? { |e| !e.is_a? Item }
withnew_contents.all? { |e| e.is_a? Item }
also.
– David Aldridge
18 hours ago
add a comment |
Thanks for the feedback.
– 0112
Nov 16 at 21:03
Bit off topic, but maybe replacecontents.map { |item| item.weight }.sum
withcontents.sum(&:weight)
. I'd be tempted to replacenew_contents.any? { |e| !e.is_a? Item }
withnew_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
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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