如何在方法链中传入整数?以7.cars.2.doors为例的技术问询
7.cars.2.doors in Ruby Absolutely! Ruby’s flexible metaprogramming features make this method chain pattern totally feasible. Here’s a step-by-step implementation that matches your requirements:
Step 1: Extend Integer to Add the cars Method
First, we’ll add a cars method to the Integer class that returns a custom handler object (we’ll call it CarBuilding). This object will manage the rest of the method chain.
class Integer def cars CarBuilding.new(self) end end
Step 2: Build the CarBuilding Handler Class
This class needs to:
- Store the initial integer value (e.g.,
7from7.cars) - Capture numeric method calls (like
2in.2.doors) and retain that value - Provide a
doorsmethod to compute the final result
We’ll use method_missing to intercept numeric method names (since you can’t predefine methods for every possible integer) and respond_to_missing? to follow Ruby’s best practices for metaprogramming.
class CarBuilding attr_accessor :total_cars, :doors_per_car def initialize(total_cars) @total_cars = total_cars end # Intercept method calls to capture numeric values def method_missing(name, *args, &block) # Check if the method name is a valid integer string if name.to_s.match?(/^\d+$/) @doors_per_car = name.to_i self # Return self to keep the method chain alive else super # Pass through any unhandled methods to avoid breaking behavior end end # Tell Ruby we can handle numeric method calls def respond_to_missing?(name, include_private = false) name.to_s.match?(/^\d+$/) || super end # Calculate the total number of doors def doors total_cars * doors_per_car end end
Step 3: Test the Method Chain
Now you can use the exact syntax you wanted:
puts 7.cars.2.doors # Output: 14
Bonus: Make It More Flexible
If you want to support longer chains (e.g., 7.cars.3.4.doors to represent 7 garages, 3 cars per garage, 4 doors per car), modify the CarBuilding class to track a list of values instead of just two:
class CarBuilding attr_accessor :values def initialize(initial_value) @values = [initial_value] end def method_missing(name, *args, &block) if name.to_s.match?(/^\d+$/) @values << name.to_i self else super end end def respond_to_missing?(name, include_private = false) name.to_s.match?(/^\d+$/) || super end def doors values.inject(:*) # Multiply all values in the chain end end # Test longer chain puts 7.cars.3.4.doors # Output: 84
Key Notes
method_missingis powerful but should be used selectively—we only handle numeric method names to avoid interfering with other methods.respond_to_missing?ensures that calls like7.cars.respond_to?(:2)returntrue, which is important for compatibility with Ruby’s introspection features.
内容的提问来源于stack exchange,提问作者slindsey3000

