slk 0.11.0 → 0.11.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7db83e915de4b86bafd0cc62e8a67fdaee0dcd9209cb94a1f8fd6a5a2704c46
4
- data.tar.gz: eb25d2aafaa23a51016e64c2f5eb40c0117aeacb829d784caff9a50078946992
3
+ metadata.gz: 6377478c56d25efc2b234bcd4ab2118bbe394520ff4f48aed0da0db5bb6c2cea
4
+ data.tar.gz: 869096e0ca163dc27042e199e5b2f4f44c81cbdc176ad00ed8546b59cdac7553
5
5
  SHA512:
6
- metadata.gz: 2d928dbf2906c22dc3ad108503c6ef4bfaeb68c29c0ed562dcd27e3515cf1468df426801dc6f7e73a3c2f9bb47d79fd7bf90054b3a9fc424453a35e8f60fd75d
7
- data.tar.gz: 93850e6e114cd1634ce2546631b1c370eb94731ff284eb29c05c458a533f16fb1229afde2ca27f60e6ea2e00d12828d6db17342f1d336350cc59d5ae788cc1bb
6
+ metadata.gz: c5ce6c57a9978ad2152a3267e9892274883a0980ee33f2648fe7ca14718f870ea3a0a7ecfa2420abffdea18b565c500bfda1524f2efc29bb73a35eaa9de56318
7
+ data.tar.gz: ffb2bd3791481c90223a9050760769868194e8044ffc0750704965180b5dfb750cdad1dd4a297f17e1688fc7e9e41c07a231f0b87d85e0af485a2c221e518f2b
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.1] - 2026-09-23
11
+
12
+ ### Fixed
13
+
14
+ - `slk sent` and URL-based message history now use built-in rational arithmetic for exact Slack timestamps instead of requiring the optional `bigdecimal` gem. A standalone install on Ruby 3.4+ works without development dependencies; CI checks the packaged gem in an isolated gem home.
15
+
10
16
  ## [0.11.0] - 2026-09-23
11
17
 
12
18
  ### Changed
@@ -228,8 +228,7 @@ module Slk
228
228
 
229
229
  # Adjust a Slack timestamp by a small amount while preserving precision
230
230
  def adjust_timestamp(timestamp, delta)
231
- require 'bigdecimal'
232
- (BigDecimal(timestamp) + BigDecimal(delta.to_s)).to_s('F')
231
+ Support::DecimalTimestamp.add(timestamp, delta)
233
232
  end
234
233
 
235
234
  def fetch_all_thread_replies(api, channel_id, thread_ts)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bigdecimal'
4
-
5
3
  module Slk
6
4
  module Services
7
5
  # Stateless diff of watched sent conversations. Search discovers what to
@@ -32,7 +30,7 @@ module Slk
32
30
  conversation = change.conversation
33
31
  # Put the most recently active conversation last. Trailing identity
34
32
  # keys make ties deterministic across platforms (including Windows).
35
- [BigDecimal(conversation.messages.last.ts), conversation.workspace.name.to_s,
33
+ [Support::DecimalTimestamp.parse(conversation.messages.last.ts), conversation.workspace.name.to_s,
36
34
  conversation.channel_id.to_s, conversation.thread_ts.to_s]
37
35
  end
38
36
  end
@@ -90,8 +88,8 @@ module Slk
90
88
  cursor = nil
91
89
  loop do
92
90
  response = @api.history(channel: hits.first.channel_id,
93
- oldest: roots.min_by { |root| BigDecimal(root) }, inclusive: true,
94
- limit: 200, cursor: cursor)
91
+ oldest: roots.min_by { |root| Support::DecimalTimestamp.parse(root) },
92
+ inclusive: true, limit: 200, cursor: cursor)
95
93
  response.fetch('messages', []).each do |message|
96
94
  found[message['ts']] = message if wanted[message['ts']]
97
95
  end
@@ -253,7 +251,7 @@ module Slk
253
251
 
254
252
  def normalize(raw, channel_id)
255
253
  raw.map { |row| row.is_a?(Models::Message) ? row : Models::Message.from_api(row, channel_id: channel_id) }
256
- .uniq(&:ts).sort_by { |message| BigDecimal(message.ts) }
254
+ .uniq(&:ts).sort_by { |message| Support::DecimalTimestamp.parse(message.ts) }
257
255
  end
258
256
 
259
257
  def after_cutoff(raw)
@@ -265,7 +263,7 @@ module Slk
265
263
  end
266
264
 
267
265
  def newer?(timestamp)
268
- BigDecimal(timestamp) > BigDecimal(@since_ts)
266
+ Support::DecimalTimestamp.parse(timestamp) > Support::DecimalTimestamp.parse(@since_ts)
269
267
  end
270
268
 
271
269
  def page_through(endpoint, **params)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bigdecimal'
4
-
5
3
  module Slk
6
4
  module Services
7
5
  # Expands indexed from:me hits into bounded channel windows, full DM
@@ -42,7 +40,7 @@ module Slk
42
40
  def ordered_conversations(conversations)
43
41
  conversations.sort_by do |conversation|
44
42
  # Keep Slack's fractional timestamp precise; identity breaks ties regardless of input order or platform.
45
- [BigDecimal(conversation.first_sent_ts), conversation.workspace.name.to_s,
43
+ [Support::DecimalTimestamp.parse(conversation.first_sent_ts), conversation.workspace.name.to_s,
46
44
  conversation.channel_id.to_s, conversation.thread_ts.to_s]
47
45
  end
48
46
  end
@@ -115,7 +113,7 @@ module Slk
115
113
  def following_messages(channel_id, window)
116
114
  return [] if @after_seconds.zero?
117
115
 
118
- end_at = (BigDecimal(window.last.ts) + @after_seconds).to_s('F')
116
+ end_at = Support::DecimalTimestamp.add(window.last.ts, @after_seconds)
119
117
  page_through(:history, channel: channel_id, oldest: window.first.ts, latest: end_at, inclusive: true)
120
118
  end
121
119
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bigdecimal'
4
3
  require 'date'
5
4
  require 'time'
6
5
 
@@ -31,7 +30,7 @@ module Slk
31
30
  end
32
31
 
33
32
  def self.epoch_time(value)
34
- Time.at(BigDecimal(value).to_r)
33
+ Time.at(DecimalTimestamp.parse(value))
35
34
  rescue ArgumentError
36
35
  raise UsageError, "Invalid --changed-since time: #{value.inspect}."
37
36
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slk
4
+ module Support
5
+ # Exact decimal arithmetic for Slack timestamps without an optional gem.
6
+ module DecimalTimestamp
7
+ def self.parse(value)
8
+ Rational(value.to_s)
9
+ end
10
+
11
+ def self.add(timestamp, offset)
12
+ decimal(parse(timestamp) + parse(offset))
13
+ end
14
+
15
+ def self.decimal(value)
16
+ twos, remaining = factor(value.denominator, 2)
17
+ fives, remaining = factor(remaining, 5)
18
+ raise ArgumentError, 'Timestamp must have a finite decimal representation' unless remaining == 1
19
+
20
+ places = [twos, fives].max
21
+ scaled = value.numerator * ((10**places) / value.denominator)
22
+ format_digits(scaled, places)
23
+ end
24
+
25
+ def self.format_digits(scaled, places)
26
+ digits = scaled.abs.to_s.rjust(places + 1, '0')
27
+ sign = scaled.negative? ? '-' : ''
28
+ return "#{sign}#{digits}.0" if places.zero?
29
+
30
+ "#{sign}#{digits[0...-places]}.#{digits[-places..]}"
31
+ end
32
+ private_class_method :format_digits
33
+
34
+ def self.factor(number, divisor)
35
+ count = 0
36
+ while (number % divisor).zero?
37
+ number /= divisor
38
+ count += 1
39
+ end
40
+ [count, number]
41
+ end
42
+ private_class_method :factor
43
+ end
44
+ end
45
+ end
data/lib/slk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slk
4
- VERSION = '0.11.0'
4
+ VERSION = '0.11.1'
5
5
  end
data/lib/slk.rb CHANGED
@@ -200,6 +200,7 @@ module Slk
200
200
  autoload :InteractivePrompt, 'slk/support/interactive_prompt'
201
201
  autoload :DateParser, 'slk/support/date_parser'
202
202
  autoload :CheckInTime, 'slk/support/check_in_time'
203
+ autoload :DecimalTimestamp, 'slk/support/decimal_timestamp'
203
204
  autoload :TimeParser, 'slk/support/time_parser'
204
205
  autoload :TimeRangeParser, 'slk/support/time_range_parser'
205
206
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Boehs
@@ -137,6 +137,7 @@ files:
137
137
  - lib/slk/services/who_target_resolver.rb
138
138
  - lib/slk/support/check_in_time.rb
139
139
  - lib/slk/support/date_parser.rb
140
+ - lib/slk/support/decimal_timestamp.rb
140
141
  - lib/slk/support/error_logger.rb
141
142
  - lib/slk/support/help_formatter.rb
142
143
  - lib/slk/support/inline_images.rb