telepost 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ce7fcf4f1c91fc69b689ecc87f50b6e73148288151135c0da1c1bbd7bdae8ff
4
- data.tar.gz: 4b4daa207bf50cc80e85a71f2ce646c1915d41026b8f04ff8bad7e5ec9f9f663
3
+ metadata.gz: 847510fbfea002fc65ee0a20dbc39dd2c5ede53aab590c5a8aa2ed66f2bdc50e
4
+ data.tar.gz: '086d01f73bff093ef51dbbcb67757d48d21a37211131ca6522e5b2f25901345b'
5
5
  SHA512:
6
- metadata.gz: 9e34a5b2bf917792c5ace84e188e1403b59b3dfd6ac018f7cee1cc676870ad78f70c2420bcd8eadc6064cd15caadcfdacbc4f66376367e4212dd498dee37f5ec
7
- data.tar.gz: 9c22f5ec9c6c372a611dcd5f468a74d46a0f2b191e87626b3945764fd59953a1b8bb92d9aaef8cb54850e0a43baa582e88bcf02c1ab97fd1dcb584e25a5f0760
6
+ metadata.gz: 77b5815fcaa702a9a0c422b7633e4992cb7824d79e0c0eb0a77ce03bd4e58464463eab5a3a154e47c4aad0704601d9fc7fa43c1c3fb2656401e88d1d4bd4df04
7
+ data.tar.gz: 4e9334873a9a5e0e9e7c92828b657fbc00b9f822e6c471f6c57bc7b582e3a54b6c6dde6a3c332de43614cffe7c31485678f8206f8fff7ee185ba9c6dc1f65142
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ gem 'minitest', '~>6.0', require: false
10
10
  gem 'minitest-reporters', '~>1.7', require: false
11
11
  gem 'rake', '~>13.2', require: false
12
12
  gem 'rubocop', '~>1.71', require: false
13
+ gem 'rubocop-elegant', '>=0.0.20', require: false
13
14
  gem 'rubocop-minitest', '~>0.38', require: false
14
15
  gem 'rubocop-performance', '~>1.25', require: false
15
16
  gem 'rubocop-rake', '~>0.7', require: false
data/Gemfile.lock CHANGED
@@ -11,25 +11,25 @@ GEM
11
11
  public_suffix (>= 2.0.2, < 8.0)
12
12
  ansi (1.6.0)
13
13
  ast (2.4.3)
14
- bigdecimal (4.1.0)
14
+ bigdecimal (4.1.2)
15
15
  builder (3.3.0)
16
- concurrent-ruby (1.3.5)
16
+ concurrent-ruby (1.3.6)
17
17
  crack (1.0.1)
18
18
  bigdecimal
19
19
  rexml
20
20
  docile (1.4.1)
21
21
  drb (2.2.3)
22
- dry-core (1.1.0)
22
+ dry-core (1.2.0)
23
23
  concurrent-ruby (~> 1.0)
24
24
  logger
25
25
  zeitwerk (~> 2.6)
26
- dry-inflector (1.2.0)
26
+ dry-inflector (1.3.1)
27
27
  dry-logic (1.6.0)
28
28
  bigdecimal
29
29
  concurrent-ruby (~> 1.0)
30
30
  dry-core (~> 1.1)
31
31
  zeitwerk (~> 2.6)
32
- dry-struct (1.8.0)
32
+ dry-struct (1.8.1)
33
33
  dry-core (~> 1.1)
34
34
  dry-types (~> 1.8, >= 1.8.2)
35
35
  ice_nine (~> 0.11)
@@ -41,26 +41,21 @@ GEM
41
41
  dry-inflector (~> 1.0)
42
42
  dry-logic (~> 1.4)
43
43
  zeitwerk (~> 2.6)
44
- faraday (2.13.2)
44
+ faraday (2.14.2)
45
45
  faraday-net_http (>= 2.0, < 3.5)
46
46
  json
47
47
  logger
48
- faraday-multipart (1.1.1)
48
+ faraday-multipart (1.2.0)
49
49
  multipart-post (~> 2.0)
50
- faraday-net_http (3.4.1)
51
- net-http (>= 0.5.0)
50
+ faraday-net_http (3.4.3)
51
+ net-http (~> 0.5)
52
52
  hashdiff (1.2.1)
53
53
  ice_nine (0.11.2)
54
- json (2.19.2)
55
- json-schema (6.2.0)
56
- addressable (~> 2.8)
57
- bigdecimal (>= 3.1, < 5)
54
+ json (2.19.5)
58
55
  language_server-protocol (3.17.0.5)
59
56
  lint_roller (1.1.0)
60
57
  logger (1.7.0)
61
- mcp (0.9.2)
62
- json-schema (>= 4.1)
63
- minitest (6.0.5)
58
+ minitest (6.0.6)
64
59
  drb (~> 2.0)
65
60
  prism (~> 1.5)
66
61
  minitest-reporters (1.8.0)
@@ -69,10 +64,10 @@ GEM
69
64
  minitest (>= 5.0, < 7)
70
65
  ruby-progressbar
71
66
  multipart-post (2.4.1)
72
- net-http (0.6.0)
73
- uri
74
- parallel (1.27.0)
75
- parser (3.3.10.2)
67
+ net-http (0.9.1)
68
+ uri (>= 0.11.1)
69
+ parallel (2.1.0)
70
+ parser (3.3.11.1)
76
71
  ast (~> 2.4.1)
77
72
  racc
78
73
  prism (1.9.0)
@@ -80,14 +75,13 @@ GEM
80
75
  racc (1.8.1)
81
76
  rainbow (3.1.1)
82
77
  rake (13.4.2)
83
- regexp_parser (2.11.3)
78
+ regexp_parser (2.12.0)
84
79
  rexml (3.4.4)
85
- rubocop (1.85.1)
80
+ rubocop (1.86.2)
86
81
  json (~> 2.3)
87
82
  language_server-protocol (~> 3.17.0.2)
88
83
  lint_roller (~> 1.1.0)
89
- mcp (~> 0.6)
90
- parallel (~> 1.10)
84
+ parallel (>= 1.10)
91
85
  parser (>= 3.3.0.2)
92
86
  rainbow (>= 2.2.2, < 4.0)
93
87
  regexp_parser (>= 2.9.3, < 3.0)
@@ -97,6 +91,9 @@ GEM
97
91
  rubocop-ast (1.49.1)
98
92
  parser (>= 3.3.7.2)
99
93
  prism (~> 1.7)
94
+ rubocop-elegant (0.5.1)
95
+ lint_roller (~> 1.1)
96
+ rubocop (~> 1.75)
100
97
  rubocop-minitest (0.39.1)
101
98
  lint_roller (~> 1.1)
102
99
  rubocop (>= 1.75.0, < 2.0)
@@ -126,13 +123,13 @@ GEM
126
123
  unicode-display_width (3.2.0)
127
124
  unicode-emoji (~> 4.1)
128
125
  unicode-emoji (4.2.0)
129
- uri (1.0.4)
126
+ uri (1.1.1)
130
127
  webmock (3.26.2)
131
128
  addressable (>= 2.8.0)
132
129
  crack (>= 0.3.2)
133
130
  hashdiff (>= 0.4.0, < 2.0.0)
134
- yard (0.9.43)
135
- zeitwerk (2.7.3)
131
+ yard (0.9.44)
132
+ zeitwerk (2.8.2)
136
133
 
137
134
  PLATFORMS
138
135
  arm64-darwin-22
@@ -146,6 +143,7 @@ DEPENDENCIES
146
143
  minitest-reporters (~> 1.7)
147
144
  rake (~> 13.2)
148
145
  rubocop (~> 1.71)
146
+ rubocop-elegant (>= 0.0.20)
149
147
  rubocop-minitest (~> 0.38)
150
148
  rubocop-performance (~> 1.25)
151
149
  rubocop-rake (~> 0.7)
data/README.md CHANGED
@@ -37,7 +37,7 @@ tp.post(12345, 'How are you?', 'How are you doing?')
37
37
  All lines you provide to the `post()` method will be concatenated
38
38
  with a space between them.
39
39
 
40
- Or you can pre-configure it to talk to certain list of chats.
40
+ Or you can pre-configure it to talk to a certain list of chats.
41
41
  Your bot has to be an admin of the channel, in order to post there.
42
42
  Here is how you "spam":
43
43
 
@@ -55,6 +55,16 @@ tp = Telepost.new('..token..')
55
55
  tp.attach(12345, '/tmp/dump.sql', caption: 'Today is dump')
56
56
  ```
57
57
 
58
+ You can also pass an array of files, to post them all as a single
59
+ grouped message (a Telegram "album"). Files with an image extension
60
+ are sent as photos, the rest as documents, and the `caption:` is
61
+ shown once, on the first item:
62
+
63
+ ```ruby
64
+ tp = Telepost.new('..token..')
65
+ tp.attach(12345, ['/tmp/a.png', '/tmp/b.png'], caption: 'Two shots')
66
+ ```
67
+
58
68
  That's it.
59
69
 
60
70
  ## How to contribute
data/Rakefile CHANGED
@@ -3,9 +3,9 @@
3
3
  # SPDX-FileCopyrightText: Copyright (c) 2018-2026 Yegor Bugayenko
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
- require 'rubygems'
7
6
  require 'rake'
8
7
  require 'rake/clean'
8
+ require 'rubygems'
9
9
 
10
10
  CLEAN = FileList['coverage']
11
11
 
data/lib/telepost.rb CHANGED
@@ -31,9 +31,7 @@ class Telepost
31
31
  @sent = []
32
32
  end
33
33
 
34
- def run
35
- # Nothing to do here
36
- end
34
+ def run; end
37
35
 
38
36
  def spam(*lines)
39
37
  post(0, lines)
@@ -44,9 +42,22 @@ class Telepost
44
42
  end
45
43
 
46
44
  def attach(chat, file, caption: nil)
47
- path = file.is_a?(String) ? file : file.path
48
- tail = caption.nil? ? '' : " caption=#{caption}"
49
- @sent << "#{chat}: [attach:#{File.basename(path)}#{tail}]"
45
+ @sent <<
46
+ if file.is_a?(Array)
47
+ "#{chat}: [attach-group:#{names(file)}#{cap(caption)}]"
48
+ else
49
+ "#{chat}: [attach:#{names([file])}#{cap(caption)}]"
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def names(files)
56
+ files.map { |f| File.basename(f.is_a?(String) ? f : f.path) }.join(',')
57
+ end
58
+
59
+ def cap(caption)
60
+ caption.nil? ? '' : " caption=#{caption}"
50
61
  end
51
62
  end
52
63
 
@@ -55,9 +66,6 @@ class Telepost
55
66
  # @note Raised when message posting fails
56
67
  class CantPost < StandardError; end
57
68
 
58
- # To make it possible to get the client.
59
- #
60
- # @return [Telegram::Bot::Client] The Telegram bot client
61
69
  attr_reader :client
62
70
 
63
71
  # Makes a new object. To obtain a token you should talk
@@ -78,8 +86,10 @@ class Telepost
78
86
  # @return [void]
79
87
  # @raise [RuntimeError] If no block is given
80
88
  def run
81
- raise 'Block must be given' unless block_given?
89
+ raise(RuntimeError, 'Block must be given') unless block_given?
82
90
  @bot.listen do |message|
91
+ next unless message.respond_to?(:chat)
92
+ next if message.chat.nil?
83
93
  yield(message.chat.id, message.respond_to?(:text) ? message.text : '')
84
94
  end
85
95
  rescue Net::OpenTimeout
@@ -108,35 +118,66 @@ class Telepost
108
118
  # @param lines [Array<String>] Message lines to send
109
119
  # @return [Telegram::Bot::Types::Message] The sent message object
110
120
  def post(chat, *lines, parse_mode: 'Markdown')
111
- @bot.api.send_message(
112
- chat_id: chat,
113
- parse_mode:,
114
- disable_web_page_preview: true,
115
- text: lines.join(' ')
116
- )
121
+ @bot.api.send_message(chat_id: chat, parse_mode:, disable_web_page_preview: true, text: lines.join(' '))
117
122
  end
118
123
 
119
124
  # Attach a file (as a Telegram document) to the chat. The file
120
125
  # argument can either be a path (String) or an open IO/File. The
121
126
  # filename shown in Telegram comes from the basename of the path.
122
127
  #
128
+ # When +file+ is an +Array+, all of its items are posted as a single
129
+ # grouped message (a Telegram "album") via +sendMediaGroup+. Items
130
+ # with an image extension are wrapped in +InputMediaPhoto+, the rest
131
+ # in +InputMediaDocument+. The +caption+ is attached to the first
132
+ # item only, so the album shows one caption.
133
+ #
123
134
  # @param chat [Integer, String] Chat ID or channel name
124
- # @param file [String, File, IO] Path to the file or an open IO
135
+ # @param file [String, File, IO, Array] File (or array of files) to attach
125
136
  # @param caption [String, nil] Optional caption for the attachment
126
137
  # @param parse_mode [String] Parse mode used for the caption
127
138
  # @return [Telegram::Bot::Types::Message] The sent message object
128
139
  def attach(chat, file, caption: nil, parse_mode: 'Markdown')
129
- document =
130
- if file.is_a?(String)
131
- Faraday::UploadIO.new(file, 'application/octet-stream', File.basename(file))
132
- else
133
- file
140
+ return album(chat, file, caption:, parse_mode:) if file.is_a?(Array)
141
+ io = upload(file)
142
+ @bot.api.send_document(chat_id: chat, document: io, caption:, parse_mode:)
143
+ ensure
144
+ io.close if file.is_a?(String) && io.respond_to?(:close)
145
+ end
146
+
147
+ PHOTO_EXTENSIONS = %w[.jpg .jpeg .png .gif .webp].freeze
148
+
149
+ private
150
+
151
+ def album(chat, files, caption: nil, parse_mode: 'Markdown')
152
+ opened = []
153
+ params = { chat_id: chat }
154
+ params[:media] =
155
+ files.each_with_index.map do |file, idx|
156
+ io = upload(file)
157
+ opened << io if file.is_a?(String)
158
+ params[:"file#{idx}"] = io
159
+ attrs = { media: "attach://file#{idx}" }
160
+ if idx.zero? && !caption.nil?
161
+ attrs[:caption] = caption
162
+ attrs[:parse_mode] = parse_mode
163
+ end
164
+ klass(file).new(**attrs)
134
165
  end
135
- @bot.api.send_document(
136
- chat_id: chat,
137
- document:,
138
- caption:,
139
- parse_mode:
140
- )
166
+ @bot.api.send_media_group(**params)
167
+ ensure
168
+ opened.each(&:close)
169
+ end
170
+
171
+ def upload(file)
172
+ return file unless file.is_a?(String)
173
+ Faraday::UploadIO.new(file, 'application/octet-stream', File.basename(file))
174
+ end
175
+
176
+ def klass(file)
177
+ photo?(file) ? Telegram::Bot::Types::InputMediaPhoto : Telegram::Bot::Types::InputMediaDocument
178
+ end
179
+
180
+ def photo?(file)
181
+ PHOTO_EXTENSIONS.include?(File.extname(file.is_a?(String) ? file : file.path).downcase)
141
182
  end
142
183
  end
data/telepost.gemspec CHANGED
@@ -6,10 +6,10 @@
6
6
  require 'English'
7
7
 
8
8
  Gem::Specification.new do |s|
9
- s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
9
+ s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?(:required_rubygems_version=)
10
10
  s.required_ruby_version = '>=3.2'
11
11
  s.name = 'telepost'
12
- s.version = '0.8.0'
12
+ s.version = '0.9.0'
13
13
  s.license = 'MIT'
14
14
  s.summary = 'Simple Telegram posting Ruby gem'
15
15
  s.description = 'Simple Telegram posting Ruby gem'
@@ -19,6 +19,6 @@ Gem::Specification.new do |s|
19
19
  s.files = `git ls-files | grep -v -E '^(test/|\\.|renovate)'`.split($RS)
20
20
  s.rdoc_options = ['--charset=UTF-8']
21
21
  s.extra_rdoc_files = ['README.md']
22
- s.add_dependency 'telegram-bot-ruby', '~> 1.0'
22
+ s.add_dependency('telegram-bot-ruby', '~> 1.0')
23
23
  s.metadata['rubygems_mfa_required'] = 'true'
24
24
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telepost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko