Introduce Center, Body and Position domain objects#270
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces three new domain abstractions—Astronoby::Center, Astronoby::Body, and Astronoby::Position—to formalize previously incidental contracts around reference-frame centers and “targets resolved at an instant”. It refactors the reference frame chain to use Center instead of the center_identifier union, and standardizes how frames expose their target_body across solar-system and deep-sky targets.
Changes:
- Replace
ReferenceFrame#center_identifierwith#centerreturning a newAstronoby::Centervalue object, and update all frame builders accordingly. - Introduce
Astronoby::Body(marker role) andAstronoby::Position(sharedobserved_bybehavior), wiring them into solar-system bodies and deep-sky objects/positions. - Update specs and documentation (
UPGRADING.md, reference frame docs, glossary) to reflect the new contracts.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| UPGRADING.md | Documents the breaking change from center_identifier to center and Astronoby::Center semantics. |
| docs/reference_frames.md | Adds #center to the documented reference-frame interface. |
| docs/glossary.md | Defines the new “Body”, “Centre/Center”, and “Position” concepts for user-facing docs. |
| lib/astronoby.rb | Requires the new center, body, and position definitions. |
| lib/astronoby/center.rb | Adds the Astronoby::Center value object (barycentric/geocentric/topocentric). |
| lib/astronoby/body.rb | Adds the Astronoby::Body marker module. |
| lib/astronoby/position.rb | Adds the Astronoby::Position role with shared observed_by implementation. |
| lib/astronoby/reference_frame.rb | Swaps center_identifier for center and compares centers via value semantics in separation_from. |
| lib/astronoby/reference_frames/topocentric.rb | Threads Center.topocentric(observer) through the Topocentric frame construction and initializer. |
| lib/astronoby/reference_frames/teme.rb | Migrates TEME frames to use Center (geocentric/topocentric) instead of center_identifier. |
| lib/astronoby/reference_frames/mean_of_date.rb | Migrates MeanOfDate builder to use Center.geocentric. |
| lib/astronoby/reference_frames/geometric.rb | Migrates Geometric frame to use Center.barycentric. |
| lib/astronoby/reference_frames/astrometric.rb | Migrates Astrometric builder to use Center.geocentric. |
| lib/astronoby/reference_frames/apparent.rb | Migrates Apparent builder to use Center.geocentric. |
| lib/astronoby/bodies/solar_system_body.rb | Makes solar-system body instances Position, body classes Body, and threads target_body as the body definition. |
| lib/astronoby/bodies/deep_sky_object.rb | Makes DeepSkyObject instances fulfill Body and threads the definition into DeepSkyObjectPosition. |
| lib/astronoby/bodies/deep_sky_object_position.rb | Makes deep-sky positions fulfill Position and changes frames to carry the body definition as target_body. |
| spec/astronoby/reference_frames/teme_spec.rb | Updates expectations to assert center == Astronoby::Center.geocentric. |
| spec/astronoby/reference_frames/mean_of_date_spec.rb | Updates argument expectations from center_identifier: to center:. |
| spec/astronoby/reference_frames/astrometric_spec.rb | Updates argument expectations from center_identifier: to center:. |
| spec/astronoby/reference_frame_spec.rb | Adds a comparison test asserting differing-elevation observers yield incompatible centers. |
| spec/astronoby/position_spec.rb | Adds tests for the Position role and target_body being a Body throughout the chain. |
| spec/astronoby/center_spec.rb | Adds tests for Center constructors, equality, and hashing semantics. |
| spec/astronoby/body_spec.rb | Adds tests asserting solar-system body classes and deep-sky objects fulfill Body. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR improves three existing concepts in model, turning incidental behaviour into a guaranteed, documented contract:
Astronoby::Center: a value object replacing the ad-hoccenter_identifierunion on reference frames.Astronoby::Body: a role for a catalog definition that can position itself at an instant.Astronoby::Position: a role for a target resolved at an instant, yielding the reference frame chain.Motivation
Two concepts leaked through the otherwise clean value-object design.
First, the centre of a frame was a primitive union. Frames carried
center_identifier, anInteger(SolarSystemBody::EARTH/SOLAR_SYSTEM_BARYCENTER) for barycentric/geocentric frames or an[longitude, latitude]array for topocentric frames.Second, "an observable target" was implicit.
SolarSystemBodyandDeepSkyObjectPositionboth produced the frame chain but shared no abstraction, so cross-type operations worked only by coincidence.Changes
Centervalue objectAstronoby::Centerwithbarycentric/geocentric(memoized singletons) andtopocentric(observer)constructors, plus#barycentric?,#geocentric?,#topocentric?,#observer_dependent?and#observer.ReferenceFrame#separation_fromnow compares frames withcenter == other.center.Geometric,Astrometric,MeanOfDate,Apparent,Topocentric,Teme) andDeepSkyObjectPositionupdated accordingly.BodyroleAstronoby::Bodyfor a definition that responds toat(instant, ephem:)and returns aPosition.SolarSystemBodyextends it (the body classes themselves areBodys);DeepSkyObjectincludes it (instances areBodys).PositionroleAstronoby::Position, included bySolarSystemBodyandDeepSkyObjectPosition, holding the sharedobserved_byimplementation (previously duplicated in both classes).target_bodymade consistentReferenceFrame#target_bodyis now always aBody: solar system body frames carry the class, deep-sky object frames carry theDeepSkyObjectdefinition (threaded intoDeepSkyObjectPosition).LightTimeDelayis unchanged. It readstarget_body.geometric(ephem:, instant:)only offGeometricframes, which already carried the class. What used to be an implicit reliance is now a documented role contract.Breaking changes
ReferenceFrame#center_identifieris replaced by#center, which returns anAstronoby::Centerinstead of anInteger/Array. SeeUPGRADING.md.ReferenceFrame#target_bodyis now consistently anAstronoby::Body(previously a class or an instance depending on the frame).