Class: WhyClasses::Rules::InvalidInitialState
- Inherits:
-
WhyClasses::Rule
- Object
- WhyClasses::Rule
- WhyClasses::Rules::InvalidInitialState
- Defined in:
- lib/why_classes/rules/invalid_initial_state.rb
Overview
A red-flag pattern: initialize leaves a field nil, so the object is invalid
until a setter is called after .new. A signal the "object" is really a
sequence of function calls in disguise.
Constant Summary
Constants inherited from WhyClasses::Rule
Class Method Summary collapse
Instance Method Summary collapse
Methods inherited from WhyClasses::Rule
autocorrectable?, #call, inherited, #initialize, rule_name, tier
Constructor Details
This class inherits a constructor from WhyClasses::Rule
Class Method Details
.description ⇒ Object
11 12 13 |
# File 'lib/why_classes/rules/invalid_initial_state.rb', line 11 def self.description "Object constructed in an invalid state (initialize sets a field to nil, needs a setter first)." end |
Instance Method Details
#on_class(node) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/why_classes/rules/invalid_initial_state.rb', line 15 def on_class(node) s = shape(node) return if s.name.nil? init = s.initialize_method return if init.nil? writers = s.attr_macros[:attr_writer] + s.attr_macros[:attr_accessor] nils = nil_assigned_ivars(init) return if nils.empty? nils.each do |ivar| field = ivar.to_s.delete_prefix("@").to_sym next unless writers.include?(field) next unless field_read_in_behavior?(s, ivar) add_offense( node, message: "#{s.name}#initialize sets #{ivar} = nil and exposes a setter, so a " \ "#{s.name} is invalid until `#{field}=` is called.", suggestion: "Require #{field} up front instead:\n" \ " def initialize(#{field})\n @#{field} = #{field}\n end\n" \ " or drop the object entirely and pass #{field} to a module function." ) end end |