Module: WhyClasses::Correctors::DataBucketCorrector
- Defined in:
- lib/why_classes/correctors/data_bucket_corrector.rb
Overview
Decides whether a data-bucket class can be mechanically rewritten to a Struct/Data one-liner, and generates the replacement source.
Conservative by design: anything it is unsure about is reported as advice-only (analysis returns nil) rather than rewritten incorrectly.
Defined Under Namespace
Classes: Analysis
Constant Summary collapse
- H =
AST::NodeHelpers
Class Method Summary collapse
-
.analyze(shape, prefer_data:) ⇒ Object
Returns an Analysis when the class is a safely-convertible data bucket, else nil (caller downgrades to advice-only).
- .fields_for(shape) ⇒ Object
-
.kind_for(shape, prefer_data) ⇒ Object
attr_accessor/attr_writer imply mutation -> Struct; otherwise Data.
- .superclass_ok?(shape) ⇒ Boolean
-
.viable?(shape) ⇒ Boolean
The structural preconditions for treating a class as a pure data bucket.
Class Method Details
.analyze(shape, prefer_data:) ⇒ Object
Returns an Analysis when the class is a safely-convertible data bucket, else nil (caller downgrades to advice-only).
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/why_classes/correctors/data_bucket_corrector.rb', line 31 def analyze(shape, prefer_data:) return nil unless viable?(shape) fields = fields_for(shape) return nil if fields.empty? init = shape.initialize_method # attr fields must be covered by the constructor's parameters. return nil unless shape.attr_fields.all? { |f| fields.include?(f) } keyword = init ? H.keyword_params?(init.children[1]) : false Analysis.new(fields: fields, kind: kind_for(shape, prefer_data), keyword: keyword) end |
.fields_for(shape) ⇒ Object
65 66 67 68 |
# File 'lib/why_classes/correctors/data_bucket_corrector.rb', line 65 def fields_for(shape) init = shape.initialize_method init ? H.param_names(init.children[1]) : shape.attr_fields end |
.kind_for(shape, prefer_data) ⇒ Object
attr_accessor/attr_writer imply mutation -> Struct; otherwise Data.
71 72 73 74 75 76 |
# File 'lib/why_classes/correctors/data_bucket_corrector.rb', line 71 def kind_for(shape, prefer_data) writable = !(shape.attr_macros[:attr_writer] + shape.attr_macros[:attr_accessor]).empty? return :struct if writable && !prefer_data :data end |
.superclass_ok?(shape) ⇒ Boolean
61 62 63 |
# File 'lib/why_classes/correctors/data_bucket_corrector.rb', line 61 def superclass_ok?(shape) shape.superclass.nil? || shape.superclass == "Object" end |
.viable?(shape) ⇒ Boolean
The structural preconditions for treating a class as a pure data bucket.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/why_classes/correctors/data_bucket_corrector.rb', line 46 def viable?(shape) return false if shape.module? return false if shape. return false unless superclass_ok?(shape) return false unless shape.behavior_methods.empty? return false unless shape.singleton_methods.empty? return false unless shape.other_statements.empty? init = shape.initialize_method # No initialize: a bare attr_* container still qualifies. return !shape.attr_fields.empty? if init.nil? H.initialize_only_assigns_params?(shape.node) end |