Ruby课程类初始化方法如何限定星期参数days的合法取值?
Great question! Let's break this down step by step to make your Course class robust and enforce valid day values properly.
Step 1: Define Valid Days as a Class Constant
The best place to store your list of valid day symbols is as a class constant inside the Course class. This keeps the valid values centralized, easy to update, and accessible to all instances of the class. Add this right after opening the class:
VALID_DAYS = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].freeze
Using .freeze prevents accidental modification of the list later—this is a good practice for constants that shouldn’t change.
If you also need to enforce valid values for time_block, you can add a similar constant (customize the values to match your use case):
VALID_TIME_BLOCKS = [:early_morning, :morning, :afternoon, :evening].freeze
Step 2: Validate the days Parameter in initialize
Next, add validation logic to your constructor to ensure any provided days are valid. We’ll handle two cases:
- If
daysisnil(the default), skip validation since it’s allowed - If
daysis an array, verify every element is inVALID_DAYS
Here’s how to update your initialize method:
def initialize(course_name, department, credits, time_block = nil, days = nil) # Validate days if days invalid_days = days - VALID_DAYS unless invalid_days.empty? raise ArgumentError, "Invalid day(s): #{invalid_days.join(', ')}. Valid days are: #{VALID_DAYS.join(', ')}" end end # Validate time_block (optional—remove if you don't need this) if time_block && !VALID_TIME_BLOCKS.include?(time_block) raise ArgumentError, "Invalid time block: #{time_block}. Valid blocks are: #{VALID_TIME_BLOCKS.join(', ')}" end @course_name = course_name @department = department @credits = credits @students = [] @days = days @time_block = time_block end
Step 3: Fix Edge Cases in conflicts_with?
Your current conflicts_with? method will throw an error if either course has nil for days (since you can’t call any? on nil). Let’s update it to handle nil gracefully:
def conflicts_with?(course2) return false if self.time_block != course2.time_block return false unless self.days && course2.days # No conflict if either course has no days set self.days.any? do |day| course2.days.include?(day) end end
Full Updated Course Class
Putting it all together (plus a cleanup of redundant methods), here’s your revised class:
class Course VALID_DAYS = [:mon, :tue, :wed, :thu, :fri, :sat, :sun].freeze VALID_TIME_BLOCKS = [:early_morning, :morning, :afternoon, :evening].freeze # Customize as needed attr_reader :department, :name, :credits, :time_block, :days, :students def initialize(course_name, department, credits, time_block = nil, days = nil) # Validate days parameter if days invalid_days = days - VALID_DAYS unless invalid_days.empty? raise ArgumentError, "Invalid day(s): #{invalid_days.join(', ')}. Valid days are: #{VALID_DAYS.join(', ')}" end end # Validate time_block parameter (optional) if time_block && !VALID_TIME_BLOCKS.include?(time_block) raise ArgumentError, "Invalid time block: #{time_block}. Valid blocks are: #{VALID_TIME_BLOCKS.join(', ')}" end @course_name = course_name @department = department @credits = credits @students = [] @days = days @time_block = time_block end # Note: Your attr_reader already covers these, so we can remove the redundant methods! # def name # @course_name # end # def department # @department # end # def credits # @credits # end def add_student(student) return if @students.include?(student) student.enroll(self) end def conflicts_with?(course2) return false if self.time_block != course2.time_block return false unless self.days && course2.days self.days.any? do |day| course2.days.include?(day) end end end
Quick Tips:
- I removed your redundant
name,department, andcreditsmethods since yourattr_readeralready handles these attributes—no need to redefine them! - Raising an
ArgumentErroris the standard Ruby way to signal invalid input to a constructor, making it clear when someone uses invalid values. - Using class constants makes updating valid values later a breeze (e.g., if you need to change
:wedsto:wed, you only edit one place).
内容的提问来源于stack exchange,提问作者Monique

