独立Ruby坐标导航应用优化及RSpec测试方案咨询
Hey there! Let's break down your questions about optimizing your Ruby navigation app and testing it with RSpec.
Your current code works, but we can make it cleaner, more maintainable, and slightly more efficient by leaning into Ruby's idioms and better data structure management:
Key Improvements:
- Encapsulate coordinates with a Struct: Avoid repeated string splitting and type conversion by wrapping coordinates in a reusable structure.
- Extract core logic to a method: This separates business logic from command-line input handling, making testing easier.
- Preprocess all destinations upfront: Convert all coordinate strings to integer-based coordinates once, instead of doing it per iteration.
- Use array joining for instructions: While
<<is efficient for string building, using an array andjoinmakes the code more readable without sacrificing performance.
Optimized Code Example:
#!/home/eamonn/.rbenv/shims/ruby # Struct to handle coordinate data cleanly Coordinate = Struct.new(:x, :y) do def self.from_string(str) x_str, y_str = str.split(", ") raise ArgumentError, "Invalid coordinate format: #{str}" unless x_str && y_str new(x_str.to_i, y_str.to_i) end end def generate_navigation_instructions(start, destinations) instructions = [] current = start destinations.each do |dest| # Handle X-axis movement x_diff = dest.x - current.x instructions << 'E' * x_diff if x_diff > 0 instructions << 'W' * x_diff.abs if x_diff < 0 # Handle Y-axis movement y_diff = dest.y - current.y instructions << 'N' * y_diff if y_diff > 0 instructions << 'S' * y_diff.abs if y_diff < 0 instructions << 'D' current = dest end instructions.join end # Command-line input handling with error checking begin input = ARGV.first raise ArgumentError, "Please provide input in format '5x5 (x,y) (x,y)'" unless input # Extract destinations and grid bounds (if provided) address_strings = input.scan(/\(([^\)]+)\)/).flatten raise ArgumentError, "No destination coordinates found" if address_strings.empty? destinations = address_strings.map { |str| Coordinate.from_string(str) } # Optional: Validate coordinates against grid bounds if (grid_match = input.match(/(\d+)x(\d+)/)) max_x, max_y = grid_match[1].to_i, grid_match[2].to_i destinations.each do |coord| if coord.x < 0 || coord.x > max_x || coord.y < 0 || coord.y > max_y raise ArgumentError, "Coordinate (#{coord.x}, #{coord.y}) is outside 0x0 to #{max_x}x#{max_y} grid" end end end start_point = Coordinate.new(0, 0) puts generate_navigation_instructions(start_point, destinations) rescue ArgumentError, TypeError => e puts "Error: #{e.message}" exit 1 end
Your initial test idea is on the right track, but we need to adjust it to work with the extracted core method (and yes, you absolutely should test for invalid inputs—here's why and how):
Why Test Invalid Inputs?
Testing edge cases and invalid inputs ensures your app is robust. Error handling in the command-line layer gives users friendly feedback, but tests validate that those error handling rules actually work as expected.
RSpec Test Example
Create a spec/navigation_spec.rb file:
require_relative '../your_app_filename' # Replace with your actual app file name RSpec.describe '#generate_navigation_instructions' do let(:start_point) { Coordinate.new(0, 0) } it 'generates correct instructions for the sample input' do destinations = [Coordinate.new(2, 2), Coordinate.new(3, 5)] expect(generate_navigation_instructions(start_point, destinations)).to eq('EENNDENNND') end it 'handles west and south movements' do destinations = [Coordinate.new(-1, -2)] expect(generate_navigation_instructions(start_point, destinations)).to eq('WSSD') end it 'returns an empty string when there are no destinations' do expect(generate_navigation_instructions(start_point, [])).to eq('') end context 'with invalid coordinate data' do it 'raises an error for malformed coordinate strings' do expect { Coordinate.from_string('2,') }.to raise_error(ArgumentError) end it 'raises an error for non-numeric coordinates' do expect { Coordinate.from_string('a, 3') }.to raise_error(TypeError) end end end
Running the Tests
Install RSpec if you haven't already:
gem install rspec
Then run the tests with:
rspec spec/navigation_spec.rb
内容的提问来源于stack exchange,提问作者EamonnMcElroy

