-
Notifications
You must be signed in to change notification settings - Fork 113
Refactor Unit class for improved code quality and maintainability #382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…r improved clarity and maintainability
…enhance code readability
… extracting validation and calculation logic into helper methods
… extracting validation logic into separate methods
…rganizing and enhancing documentation
…nd improve readability
… improve clarity in unary operations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request refactors the RubyUnits::Unit class to improve code quality and maintainability while maintaining backward compatibility. The changes include encapsulation improvements, method extractions, and code simplifications based on static analysis recommendations.
Key changes:
- Converted class and instance level
attr_accessortoattr_readerwith privateattr_writermethods for better encapsulation - Extracted complex methods into smaller, focused helper methods for improved readability and maintainability
- Added
.reek.ymlconfiguration to document intentional design patterns and suppress false positives
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
.reek.yml |
New configuration file to document and manage intentional design patterns and suppress false positive warnings |
lib/ruby_units/cache.rb |
Changed data attribute from attr_accessor to attr_reader for improved encapsulation |
lib/ruby_units/unit.rb |
Major refactoring including encapsulation improvements, method extractions, nil comparison updates, lambda-based refactoring of to_base, improved error handling, and addition of numerous helper methods for validation and formatting |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| precision ||= configuration.default_precision | ||
| format ||= configuration.format |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from default parameter values to nil-checking within the method body may alter behavior when false is explicitly passed as an argument. If precision: false or format: false is passed, the original code would use false, but the new code will treat false as falsy and use the configuration defaults instead. This could be a subtle breaking change in behavior.
| precision ||= configuration.default_precision | |
| format ||= configuration.format | |
| precision = configuration.default_precision if precision.nil? | |
| format = configuration.format if format.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot This is OK. false is not a valid value for either of these configurations.
lib/ruby_units/unit.rb
Outdated
| # Guard against division by zero once to avoid duplicate calls | ||
| raise ZeroDivisionError if other.respond_to?(:zero?) && other.zero? |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving the zero check before the case statement changes the order of error checking. If a Unit is zero, the original code would first check if it's a temperature (line 973) before raising ZeroDivisionError. Now, ZeroDivisionError is raised before temperature validation, changing the error behavior for edge cases like dividing by a zero-valued temperature unit.
| end | ||
|
|
||
| @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? | ||
| @scalar = @scalar.to_f unless !@scalar || @scalar.empty? |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from @scalar.nil? to !@scalar changes the semantic meaning. The original code explicitly checked for nil, but the new code treats any falsy value (including false, 0, empty string) as truthy for the negation. This could lead to different behavior if @scalar is 0 or false, though in this context @scalar is likely always either nil, a string, or a Numeric. However, it's safer and clearer to use .nil? for nil checks.
| @scalar = @scalar.to_f unless !@scalar || @scalar.empty? | |
| @scalar = @scalar.to_f unless @scalar.nil? || @scalar.empty? |
| @scalar = scalar_as_int if scalar_as_int == @scalar | ||
|
|
||
| bottom_scalar = 1 if bottom_scalar.nil? || bottom_scalar.empty? | ||
| bottom_scalar = 1 if !bottom_scalar || bottom_scalar.empty? |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from bottom_scalar.nil? to !bottom_scalar changes the semantic meaning. The original code explicitly checked for nil, but the new code treats any falsy value (including false, 0) as truthy for the negation. While in this parsing context bottom_scalar is likely always either nil or a string, using explicit .nil? checks is clearer and more maintainable.
| bottom_scalar = 1 if !bottom_scalar || bottom_scalar.empty? | |
| bottom_scalar = 1 if bottom_scalar.nil? || bottom_scalar.empty? |
| # @return [Array] | ||
| def unit_signature | ||
| return @signature unless @signature.nil? | ||
| return @signature if @signature |
Copilot
AI
Dec 28, 2025
•
edited by olbrich
Loading
edited by olbrich
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from unless @signature.nil? to if @signature changes behavior when @signature equals 0. A signature of 0 is a valid value (for unitless quantities or when the signature vector sums to zero), but the new code will treat 0 as falsy and recalculate the signature unnecessarily. This could impact performance and potentially cause issues with caching.
| return @signature if @signature | |
| return @signature unless @signature.nil? |
…functionality within the class
…sibility; reorganize private methods for better structure
…for improved clarity
This pull request refactors the
RubyUnits::Unitclass and related components to improve code quality, maintainability, and adherence to Ruby best practices. The changes address several code smells identified by static analysis tools while maintaining backward compatibility.Key Changes
Configuration and Static Analysis
.reek.ymlconfiguration file to document and manage intentional design patterns:InstanceVariableAssumptiondetector (justified by mixed eager/lazy initialization pattern)RepeatedConditionalwarnings for legitimate repeated checks across different contextsEncapsulation Improvements
dataattribute inRubyUnits::Cachefromattr_accessortoattr_readerfor better encapsulationRubyUnits::Unittoattr_readerwith privateattr_writermethodsCode Refactoring and Cleanup
return_scalar_or_unitmethod: Removed redundant parameter - method was always called with identical values for both argumentsregister_prefix_definition,register_unit_definition,create_unit_value,register_aliasesfor unit definition registrationvalidate_power_operation,special_power_case,calculate_power_resultfor power operationsapply_signature_itemsfor signature vector calculationsvalidate_time_point,ensure_compatible_withfor validation logicreturn_scalar_or_raisefor type conversion methodsvalidate_unit_string_format,invalid_unitfor parsing validationnilcomparisons withNilClasstype checks for clarity and Reek compliancePerformance Optimizations
All existing tests pass, ensuring backward compatibility is maintained.