astro_chart 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/README.md +417 -0
- data/astro_chart.gemspec +8 -4
- data/lib/astro_chart/aspects.rb +31 -2
- data/lib/astro_chart/chart.rb +94 -12
- data/lib/astro_chart/composite.rb +101 -0
- data/lib/astro_chart/dignities.rb +220 -0
- data/lib/astro_chart/draconic.rb +64 -0
- data/lib/astro_chart/ephemeris.rb +78 -29
- data/lib/astro_chart/houses.rb +2 -1
- data/lib/astro_chart/lunar_return.rb +90 -0
- data/lib/astro_chart/patterns.rb +248 -0
- data/lib/astro_chart/points.rb +82 -0
- data/lib/astro_chart/profection.rb +56 -0
- data/lib/astro_chart/progressions.rb +68 -0
- data/lib/astro_chart/pure/houses.rb +91 -6
- data/lib/astro_chart/pure.rb +11 -6
- data/lib/astro_chart/solar_arc.rb +59 -0
- data/lib/astro_chart/solar_return.rb +193 -0
- data/lib/astro_chart/stats.rb +34 -0
- data/lib/astro_chart/transit_timing.rb +186 -0
- data/lib/astro_chart/transits.rb +108 -0
- data/lib/astro_chart/version.rb +1 -1
- data/lib/astro_chart.rb +13 -0
- metadata +24 -7
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
require_relative "ephemeris"
|
|
2
|
+
require_relative "aspects"
|
|
3
|
+
require_relative "zodiac"
|
|
4
|
+
require_relative "synastry"
|
|
5
|
+
require_relative "solar_return"
|
|
6
|
+
|
|
7
|
+
module AstroChart
|
|
8
|
+
# Transit timing (行運精確時點): the exact UTC instants, within a date range,
|
|
9
|
+
# when a transiting body forms an exact aspect to a natal point.
|
|
10
|
+
#
|
|
11
|
+
# Where Transits.against is a single snapshot ("what aspects hold right
|
|
12
|
+
# now?"), this answers the question people actually ask — "*when* does
|
|
13
|
+
# transiting 土星 exactly square my natal 太陽?".
|
|
14
|
+
#
|
|
15
|
+
# natal = AstroChart::Chart.new(...).generate
|
|
16
|
+
# events = AstroChart::TransitTiming.events(natal, "2026-01-01", "2026-12-31")
|
|
17
|
+
# events.first
|
|
18
|
+
# #=> { "transit_planet" => "土星", "natal_planet" => "太陽",
|
|
19
|
+
# # "aspect_type" => "四分相", "jd" => 2461...,
|
|
20
|
+
# # "time_utc" => "2026-03-14T07:22:10Z", "transit_zodiac" => "牡羊座",
|
|
21
|
+
# # "retrograde" => false }
|
|
22
|
+
#
|
|
23
|
+
# Method: each transiting body's longitude is sampled across the range at
|
|
24
|
+
# `step_days`; for every natal point and aspect angle the signed separation
|
|
25
|
+
# is bracketed where it crosses exactness, then refined by bisection (robust
|
|
26
|
+
# through retrograde stations, unlike a pure Newton step). A step where the
|
|
27
|
+
# body moves < 90° guarantees no aliasing — 1 day is safe for all bodies
|
|
28
|
+
# (the Moon moves ~13°/day).
|
|
29
|
+
module TransitTiming
|
|
30
|
+
# Transiting bodies considered (12-body set minus 南交點, mirroring
|
|
31
|
+
# Synastry/Transits — a south-node hit merely mirrors a north-node one).
|
|
32
|
+
BODIES = Synastry::BODIES
|
|
33
|
+
|
|
34
|
+
# Major aspect angles. Each non-zero, non-opposition aspect is exact at two
|
|
35
|
+
# signed separations (applying from either side); 合相/對分相 have one.
|
|
36
|
+
MAJOR = { "合相" => 0, "六分相" => 60, "四分相" => 90, "三分相" => 120, "對分相" => 180 }.freeze
|
|
37
|
+
MINOR = { "十二分相" => 30, "半四分相" => 45, "補八分相" => 135, "補十二分相" => 150 }.freeze
|
|
38
|
+
|
|
39
|
+
CONVERGENCE_DAYS = 1e-6 # ~0.1 second of clock time
|
|
40
|
+
MAX_BISECT = 60
|
|
41
|
+
|
|
42
|
+
# natal_chart: a Chart#generate result hash.
|
|
43
|
+
# start_date / end_date: "YYYY-MM-DD" (interpreted at 00:00 UT).
|
|
44
|
+
# minor: also time the minor aspects (30/45/135/150).
|
|
45
|
+
# step_days: sampling stride (default 1.0 — safe for every body).
|
|
46
|
+
# bodies: restrict transiting bodies (default all BODIES; e.g. drop "月亮"
|
|
47
|
+
# to avoid the Moon's ~monthly hits flooding the list).
|
|
48
|
+
#
|
|
49
|
+
# Returns an Array of event hashes sorted by time (jd ascending).
|
|
50
|
+
def self.events(natal_chart, start_date, end_date, minor: false,
|
|
51
|
+
step_days: 1.0, bodies: nil)
|
|
52
|
+
natal = Synastry.positions_from_chart(natal_chart)
|
|
53
|
+
moving = (bodies || BODIES).select { |b| Ephemeris::PLANETS.key?(b) }
|
|
54
|
+
targets = signed_targets(minor)
|
|
55
|
+
|
|
56
|
+
jd_start = date_to_jd(start_date)
|
|
57
|
+
jd_end = date_to_jd(end_date)
|
|
58
|
+
|
|
59
|
+
events = []
|
|
60
|
+
moving.each do |body|
|
|
61
|
+
id = Ephemeris::PLANETS[body]
|
|
62
|
+
# Sample this body's longitude ONCE across the grid, then reuse the
|
|
63
|
+
# cached samples for every natal point × aspect target (calc_ut is the
|
|
64
|
+
# cost; the scan phase does zero extra ephemeris calls, only bisection
|
|
65
|
+
# refinement recomputes).
|
|
66
|
+
grid = sample_grid(id, jd_start, jd_end, step_days)
|
|
67
|
+
|
|
68
|
+
natal.each do |n_name, n_pos|
|
|
69
|
+
targets.each do |aspect_type, sep|
|
|
70
|
+
scan_grid(grid, n_pos, sep).each do |jd0, h0, jd1, h1|
|
|
71
|
+
jd = bisect(id, n_pos, sep, jd0, h0, jd1, h1)
|
|
72
|
+
events << build_event(body, id, n_name, aspect_type, jd)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
dedupe(events).sort_by { |e| e["jd"] }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# [[jd, lon], ...] samples of one body from jd_start to jd_end (inclusive).
|
|
82
|
+
def self.sample_grid(id, jd_start, jd_end, step)
|
|
83
|
+
grid = []
|
|
84
|
+
jd = jd_start
|
|
85
|
+
loop do
|
|
86
|
+
jd = jd_end if jd > jd_end
|
|
87
|
+
grid << [jd, Ephemeris.calc_ut(jd, id)]
|
|
88
|
+
break if jd >= jd_end
|
|
89
|
+
|
|
90
|
+
jd += step
|
|
91
|
+
end
|
|
92
|
+
grid
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Brackets where the signed separation crosses exactness, from cached
|
|
96
|
+
# longitudes. Returns [[jd0, h0, jd1, h1], ...] for bisection.
|
|
97
|
+
def self.scan_grid(grid, natal_pos, sep)
|
|
98
|
+
brackets = []
|
|
99
|
+
grid.each_cons(2) do |(jd0, l0), (jd1, l1)|
|
|
100
|
+
h0 = SolarReturn.angle_delta(l0 - natal_pos - sep)
|
|
101
|
+
h1 = SolarReturn.angle_delta(l1 - natal_pos - sep)
|
|
102
|
+
# A sign change with both endpoints near the target (|h| < 90°) is a
|
|
103
|
+
# real crossing; the |h| guard rejects the ±180° wrap discontinuity.
|
|
104
|
+
next unless h0 != 0 && (h0 <=> 0) != (h1 <=> 0) && h0.abs < 90 && h1.abs < 90
|
|
105
|
+
|
|
106
|
+
brackets << [jd0, h0, jd1, h1]
|
|
107
|
+
end
|
|
108
|
+
brackets
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Signed separations at which each aspect is exact. 合相 (0) and 對分相
|
|
112
|
+
# (180) have a single point; the rest have ±angle.
|
|
113
|
+
def self.signed_targets(minor)
|
|
114
|
+
table = minor ? MAJOR.merge(MINOR) : MAJOR
|
|
115
|
+
table.flat_map do |name, angle|
|
|
116
|
+
if angle.zero? || angle == 180
|
|
117
|
+
[[name, angle]]
|
|
118
|
+
else
|
|
119
|
+
[[name, angle], [name, -angle]]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.bisect(id, natal_pos, sep, a, ha, b, _hb)
|
|
125
|
+
MAX_BISECT.times do
|
|
126
|
+
break if (b - a) < CONVERGENCE_DAYS
|
|
127
|
+
|
|
128
|
+
mid = (a + b) / 2.0
|
|
129
|
+
hm = separation(id, mid, natal_pos, sep)
|
|
130
|
+
if hm == 0
|
|
131
|
+
return mid
|
|
132
|
+
elsif (ha <=> 0) != (hm <=> 0)
|
|
133
|
+
b = mid
|
|
134
|
+
else
|
|
135
|
+
a = mid
|
|
136
|
+
ha = hm
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
(a + b) / 2.0
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Signed distance (deg, [-180,180)) from exactness of this aspect.
|
|
143
|
+
def self.separation(id, jd, natal_pos, sep)
|
|
144
|
+
SolarReturn.angle_delta(Ephemeris.calc_ut(jd, id) - natal_pos - sep)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def self.build_event(body, id, natal_name, aspect_type, jd)
|
|
148
|
+
lon = Ephemeris.calc_ut(jd, id)
|
|
149
|
+
{
|
|
150
|
+
"transit_planet" => body,
|
|
151
|
+
"natal_planet" => natal_name,
|
|
152
|
+
"aspect_type" => aspect_type,
|
|
153
|
+
"jd" => jd,
|
|
154
|
+
"time_utc" => SolarReturn.jd_to_utc_iso8601(jd),
|
|
155
|
+
"transit_zodiac" => Zodiac.sign_name(lon),
|
|
156
|
+
"retrograde" => never_retrograde?(body) ? false : Ephemeris.retrograde?(jd, id),
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def self.never_retrograde?(body)
|
|
161
|
+
body == "太陽" || body == "月亮"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Two roots for the same contact found at adjacent brackets (a root landing
|
|
165
|
+
# on a sample boundary) collapse to one.
|
|
166
|
+
def self.dedupe(events)
|
|
167
|
+
events
|
|
168
|
+
.group_by { |e| [e["transit_planet"], e["natal_planet"], e["aspect_type"]] }
|
|
169
|
+
.flat_map do |_key, group|
|
|
170
|
+
group.sort_by { |e| e["jd"] }.chunk_while { |a, b| (b["jd"] - a["jd"]) < 1e-3 }
|
|
171
|
+
.map(&:first)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def self.date_to_jd(date)
|
|
176
|
+
y, m, d = date.split("-").map(&:to_i)
|
|
177
|
+
raise ArgumentError, "invalid date: #{date.inspect}" if y.nil? || m.nil? || d.nil?
|
|
178
|
+
|
|
179
|
+
Ephemeris.julday(y, m, d, 0.0)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private_class_method :signed_targets, :sample_grid, :scan_grid, :bisect,
|
|
183
|
+
:separation, :build_event, :never_retrograde?,
|
|
184
|
+
:dedupe, :date_to_jd
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require_relative "pure"
|
|
2
|
+
require_relative "ephemeris"
|
|
3
|
+
require_relative "zodiac"
|
|
4
|
+
require_relative "aspects"
|
|
5
|
+
require_relative "houses"
|
|
6
|
+
require_relative "planets"
|
|
7
|
+
require_relative "synastry"
|
|
8
|
+
|
|
9
|
+
module AstroChart
|
|
10
|
+
# Transits (行運): where the planets are in the sky right now (or at any
|
|
11
|
+
# moment), compared against a natal chart.
|
|
12
|
+
#
|
|
13
|
+
# Pure composition of existing modules — Planets.calculate_positions gives
|
|
14
|
+
# the sky positions for any JD, Houses.find_house places them into the
|
|
15
|
+
# natal houses, and Aspects.calculate scores transit-to-natal contacts.
|
|
16
|
+
#
|
|
17
|
+
# Typical usage with a Chart#generate result:
|
|
18
|
+
#
|
|
19
|
+
# jd = AstroChart::TimeConversion.to_julian_day("2026-07-24", "12:00", "Asia/Taipei")
|
|
20
|
+
# AstroChart::Transits.at(jd) # 天象快照 { "太陽" => 121.9, ... }
|
|
21
|
+
# AstroChart::Transits.against(natal_chart, jd) # 行運行星落入本命宮位 + 行運相位
|
|
22
|
+
module Transits
|
|
23
|
+
# Bodies used for transit-to-natal aspects. Mirrors Synastry: 南交點 is
|
|
24
|
+
# excluded because it sits exactly opposite 北交點 — every south-node
|
|
25
|
+
# aspect would just mirror a north-node one and double the noise.
|
|
26
|
+
ASPECT_BODIES = Synastry::BODIES
|
|
27
|
+
|
|
28
|
+
# Sky snapshot at a Julian Day.
|
|
29
|
+
#
|
|
30
|
+
# Returns { "太陽" => 123.45, ..., "南交點" => 303.45 } — ecliptic
|
|
31
|
+
# longitudes (total degrees 0-360) for the 12 bodies
|
|
32
|
+
# (Ephemeris::PLANETS + 南交點 = 北交點 + 180°).
|
|
33
|
+
def self.at(jd)
|
|
34
|
+
Planets.calculate_positions(jd)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Transits against a natal chart (a Chart#generate result hash).
|
|
38
|
+
#
|
|
39
|
+
# jd: Julian Day of the transit moment.
|
|
40
|
+
# orb_limit: keep only aspects with orb <= limit (default 3.0 — transit
|
|
41
|
+
# practice uses much tighter orbs than the natal defaults in Aspects).
|
|
42
|
+
#
|
|
43
|
+
# Returns:
|
|
44
|
+
# {
|
|
45
|
+
# "planets" => [ { "planet" => "木星", "zodiac" => "獅子座",
|
|
46
|
+
# "degree" => 5.1, "total_degree" => 125.1,
|
|
47
|
+
# "natal_house" => 7 }, ... 12 entries ],
|
|
48
|
+
# "aspects" => [ { "transit_planet" => "土星", "natal_planet" => "太陽",
|
|
49
|
+
# "aspect_type" => "四分相", "orb" => 1.23 }, ... ]
|
|
50
|
+
# }
|
|
51
|
+
#
|
|
52
|
+
# aspects are sorted by orb (tightest first).
|
|
53
|
+
def self.against(natal_chart, jd, orb_limit: 3.0)
|
|
54
|
+
transit_positions = at(jd)
|
|
55
|
+
natal_positions = Synastry.positions_from_chart(natal_chart)
|
|
56
|
+
natal_cusps = Synastry.cusps_from_chart(natal_chart)
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
"planets" => planet_details(transit_positions, natal_cusps),
|
|
60
|
+
"aspects" => aspects_to_natal(transit_positions, natal_positions,
|
|
61
|
+
orb_limit: orb_limit,
|
|
62
|
+
keys: %w[transit_planet natal_planet]),
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Build the per-planet detail list, placing each transiting body into
|
|
67
|
+
# the natal houses.
|
|
68
|
+
def self.planet_details(positions, natal_cusps)
|
|
69
|
+
positions.map do |name, pos|
|
|
70
|
+
{
|
|
71
|
+
"planet" => name,
|
|
72
|
+
"zodiac" => Zodiac.sign_name(pos),
|
|
73
|
+
"degree" => (pos % 30).round(4),
|
|
74
|
+
"total_degree" => pos.round(4),
|
|
75
|
+
"natal_house" => Houses.find_house(pos, natal_cusps),
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Aspects from moving positions to natal positions, filtered by
|
|
81
|
+
# orb_limit and sorted by orb. `keys` names the two hash keys so
|
|
82
|
+
# Progressions can reuse this with "progressed_planet".
|
|
83
|
+
def self.aspects_to_natal(moving_positions, natal_positions, orb_limit:,
|
|
84
|
+
keys: %w[transit_planet natal_planet])
|
|
85
|
+
moving_key, natal_key = keys
|
|
86
|
+
results = []
|
|
87
|
+
|
|
88
|
+
moving_positions.each do |m_name, m_pos|
|
|
89
|
+
next unless ASPECT_BODIES.include?(m_name)
|
|
90
|
+
|
|
91
|
+
natal_positions.each do |n_name, n_pos|
|
|
92
|
+
aspect_type, orb = Aspects.calculate(m_pos, n_pos)
|
|
93
|
+
next if aspect_type.nil?
|
|
94
|
+
next if orb_limit && orb > orb_limit
|
|
95
|
+
|
|
96
|
+
results << {
|
|
97
|
+
moving_key => m_name,
|
|
98
|
+
natal_key => n_name,
|
|
99
|
+
"aspect_type" => aspect_type,
|
|
100
|
+
"orb" => orb,
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
results.sort_by { |r| r["orb"] }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
data/lib/astro_chart/version.rb
CHANGED
data/lib/astro_chart.rb
CHANGED
|
@@ -10,8 +10,21 @@ require_relative "astro_chart/aspects"
|
|
|
10
10
|
require_relative "astro_chart/houses"
|
|
11
11
|
require_relative "astro_chart/time_conversion"
|
|
12
12
|
require_relative "astro_chart/planets"
|
|
13
|
+
require_relative "astro_chart/points"
|
|
14
|
+
require_relative "astro_chart/patterns"
|
|
15
|
+
require_relative "astro_chart/stats"
|
|
13
16
|
require_relative "astro_chart/synastry"
|
|
14
17
|
require_relative "astro_chart/chart"
|
|
18
|
+
require_relative "astro_chart/transits"
|
|
19
|
+
require_relative "astro_chart/progressions"
|
|
20
|
+
require_relative "astro_chart/composite"
|
|
21
|
+
require_relative "astro_chart/solar_return"
|
|
22
|
+
require_relative "astro_chart/draconic"
|
|
23
|
+
require_relative "astro_chart/dignities"
|
|
24
|
+
require_relative "astro_chart/profection"
|
|
25
|
+
require_relative "astro_chart/transit_timing"
|
|
26
|
+
require_relative "astro_chart/solar_arc"
|
|
27
|
+
require_relative "astro_chart/lunar_return"
|
|
15
28
|
|
|
16
29
|
module AstroChart
|
|
17
30
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: astro_chart
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Huang Yudi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: tzinfo
|
|
@@ -52,10 +52,12 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '13.0'
|
|
55
|
-
description: '
|
|
56
|
-
(VSOP87D, ELP-2000/82B moon, Meeus Pluto), Placidus houses,
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
description: 'Astrology chart calculation in pure Ruby: apparent planetary longitudes
|
|
56
|
+
(VSOP87D, ELP-2000/82B moon, Meeus Pluto), Placidus and whole-sign houses, retrograde
|
|
57
|
+
flags, aspects, derived points (Part of Fortune, mean Lilith), aspect-pattern detection
|
|
58
|
+
and element statistics, plus synastry, transits, secondary progressions, composite
|
|
59
|
+
charts and solar returns. No C extension, no external data files. Implemented from
|
|
60
|
+
public formulas (Meeus, Astronomical Algorithms 2nd ed.).'
|
|
59
61
|
email:
|
|
60
62
|
executables: []
|
|
61
63
|
extensions: []
|
|
@@ -63,13 +65,22 @@ extra_rdoc_files: []
|
|
|
63
65
|
files:
|
|
64
66
|
- CHANGELOG.md
|
|
65
67
|
- LICENSE
|
|
68
|
+
- README.md
|
|
66
69
|
- astro_chart.gemspec
|
|
67
70
|
- lib/astro_chart.rb
|
|
68
71
|
- lib/astro_chart/aspects.rb
|
|
69
72
|
- lib/astro_chart/chart.rb
|
|
73
|
+
- lib/astro_chart/composite.rb
|
|
74
|
+
- lib/astro_chart/dignities.rb
|
|
75
|
+
- lib/astro_chart/draconic.rb
|
|
70
76
|
- lib/astro_chart/ephemeris.rb
|
|
71
77
|
- lib/astro_chart/houses.rb
|
|
78
|
+
- lib/astro_chart/lunar_return.rb
|
|
79
|
+
- lib/astro_chart/patterns.rb
|
|
72
80
|
- lib/astro_chart/planets.rb
|
|
81
|
+
- lib/astro_chart/points.rb
|
|
82
|
+
- lib/astro_chart/profection.rb
|
|
83
|
+
- lib/astro_chart/progressions.rb
|
|
73
84
|
- lib/astro_chart/pure.rb
|
|
74
85
|
- lib/astro_chart/pure/core.rb
|
|
75
86
|
- lib/astro_chart/pure/houses.rb
|
|
@@ -78,8 +89,13 @@ files:
|
|
|
78
89
|
- lib/astro_chart/pure/pluto.rb
|
|
79
90
|
- lib/astro_chart/pure/vsop87.rb
|
|
80
91
|
- lib/astro_chart/pure/vsop87_data.rb
|
|
92
|
+
- lib/astro_chart/solar_arc.rb
|
|
93
|
+
- lib/astro_chart/solar_return.rb
|
|
94
|
+
- lib/astro_chart/stats.rb
|
|
81
95
|
- lib/astro_chart/synastry.rb
|
|
82
96
|
- lib/astro_chart/time_conversion.rb
|
|
97
|
+
- lib/astro_chart/transit_timing.rb
|
|
98
|
+
- lib/astro_chart/transits.rb
|
|
83
99
|
- lib/astro_chart/version.rb
|
|
84
100
|
- lib/astro_chart/zodiac.rb
|
|
85
101
|
homepage: https://github.com/morriedig/astro_chart
|
|
@@ -104,5 +120,6 @@ requirements: []
|
|
|
104
120
|
rubygems_version: 3.4.10
|
|
105
121
|
signing_key:
|
|
106
122
|
specification_version: 4
|
|
107
|
-
summary: Pure-Ruby
|
|
123
|
+
summary: Pure-Ruby astrology chart calculation (planets, Placidus/whole-sign houses,
|
|
124
|
+
aspects, synastry, transits, progressions, composite, solar returns)
|
|
108
125
|
test_files: []
|