telegem 3.0.3 → 3.0.4
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 +15 -0
- data/examples/.gitkeep +0 -0
- data/lib/api/client.rb +8 -22
- data/lib/core/bot.rb +91 -4
- data/lib/telegem.rb +2 -2
- metadata +4 -5
- data/Test-Projects/bot.md +0 -145
- data/Test-Projects/bot1.rb +0 -91
- data/public/index.html +0 -481
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9e796af1eab96fc25ece5e1dfdd0913451f66087d3181ae54f7375b10be4ebfa
|
|
4
|
+
data.tar.gz: e7fdc50d3d8e1bcb570fdb03bd0e301ddcbae3702f4e03a40ba06e12fc0941f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5719f4e1d5d4ef7c865c3a08abc459712637e24a33d98d954c546a442c70a473878e501ef15f44714c1f574802325940f2d2431b863c07c353a19484e5852da5
|
|
7
|
+
data.tar.gz: 36035a791dca055bb171003ab43e6e0229de75dee1ec02fd5d61cd0b0e8c97f9e385b221333a68f2f6867ad9912c4faf63b3eaaf070b4a59c614e13bd33d1a17
|
data/CHANGELOG
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## v3.0.4 (2026-01-17)
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
- **Critical**: Fixed `NoMethodError: undefined method 'wait'` for HTTPX responses
|
|
5
|
+
- Unified HTTPX client usage across all API methods
|
|
6
|
+
- Proper async/await pattern implementation
|
|
7
|
+
- Improved error handling for network timeouts
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- `API::Client#call` now uses async/await instead of blocking `.wait`
|
|
11
|
+
- Better timeout handling for all Telegram API calls
|
|
12
|
+
|
|
13
|
+
### Notes
|
|
14
|
+
- This release fixes compatibility with HTTPX >= 0.23.0
|
|
15
|
+
- All async operations now use `.await` instead of deprecated `.wait`
|
data/examples/.gitkeep
ADDED
|
File without changes
|
data/lib/api/client.rb
CHANGED
|
@@ -27,26 +27,12 @@ module Telegem
|
|
|
27
27
|
}
|
|
28
28
|
)
|
|
29
29
|
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
request_timeout: 30,
|
|
37
|
-
connect_timeout: 10,
|
|
38
|
-
write_timeout: 10,
|
|
39
|
-
read_timeout: 30
|
|
40
|
-
},
|
|
41
|
-
headers: {
|
|
42
|
-
'Content-Type' => 'application/json',
|
|
43
|
-
'User-Agent' => "Telegem/#{Telegem::VERSION}"
|
|
44
|
-
}
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
response = http_sync.post(url, json: params.compact).wait
|
|
48
|
-
response.json
|
|
49
|
-
end
|
|
30
|
+
def call(method, params = {})
|
|
31
|
+
url = "#{BASE_URL}/bot#{@token}/#{method}"
|
|
32
|
+
@logger.debug("Api call #{method}") if @logger
|
|
33
|
+
response = @http.post(url, json: params.compact).await
|
|
34
|
+
response.json
|
|
35
|
+
end
|
|
50
36
|
def call!(method, params = {}, &callback)
|
|
51
37
|
url = "#{BASE_URL}/bot#{@token}/#{method}"
|
|
52
38
|
|
|
@@ -112,8 +98,8 @@ end
|
|
|
112
98
|
[key.to_s, value.to_s]
|
|
113
99
|
end
|
|
114
100
|
end
|
|
115
|
-
|
|
116
|
-
|
|
101
|
+
response = @http.post(url, form: form).await
|
|
102
|
+
response.json
|
|
117
103
|
end
|
|
118
104
|
|
|
119
105
|
def get_updates(offset: nil, timeout: 30, limit: 100, allowed_updates: nil)
|
data/lib/core/bot.rb
CHANGED
|
@@ -19,7 +19,13 @@ module Telegem
|
|
|
19
19
|
chat_member: [],
|
|
20
20
|
poll: [],
|
|
21
21
|
pre_checkout_query: [],
|
|
22
|
-
shipping_query: []
|
|
22
|
+
shipping_query: [],
|
|
23
|
+
poll_answer: [],
|
|
24
|
+
chat_join_request: [],
|
|
25
|
+
chat_boost: [],
|
|
26
|
+
removed_chat_boost: [],
|
|
27
|
+
message_reaction: [],
|
|
28
|
+
message_reaction_count: []
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
@middleware = []
|
|
@@ -69,6 +75,71 @@ module Telegem
|
|
|
69
75
|
end
|
|
70
76
|
end
|
|
71
77
|
|
|
78
|
+
def contact(**options, &block)
|
|
79
|
+
on(:message, contact: true) do |ctx|
|
|
80
|
+
block.call(ctx)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def poll_answer(&block)
|
|
85
|
+
on(:poll_answer) do |ctx|
|
|
86
|
+
block.call(ctx)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def pre_checkout_query(&block)
|
|
91
|
+
on(:pre_checkout_query) do |ctx|
|
|
92
|
+
block.call(ctx)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def shipping_query(&block)
|
|
97
|
+
on(:shipping_query) do |ctx|
|
|
98
|
+
block.call(ctx)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def chat_join_request(&block)
|
|
103
|
+
on(:chat_join_request) do |ctx|
|
|
104
|
+
block.call(ctx)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def chat_boost(&block)
|
|
109
|
+
on(:chat_boost) do |ctx|
|
|
110
|
+
block.call(ctx)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def removed_chat_boost(&block)
|
|
115
|
+
on(:removed_chat_boost) do |ctx|
|
|
116
|
+
block.call(ctx)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def message_reaction(&block)
|
|
121
|
+
on(:message_reaction) do |ctx|
|
|
122
|
+
block.call(ctx)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def message_reaction_count(&block)
|
|
127
|
+
on(:message_reaction_count) do |ctx|
|
|
128
|
+
block.call(ctx)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
def web_app_data(&block)
|
|
132
|
+
on(:message, web_app_data: true) do |ctx|
|
|
133
|
+
block.call(ctx)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def location(&block)
|
|
138
|
+
on(:message, location: true) do |ctx|
|
|
139
|
+
block.call(ctx)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
72
143
|
def on(type, filters = {}, &block)
|
|
73
144
|
@handlers[type] << { filters: filters, handler: block }
|
|
74
145
|
end
|
|
@@ -240,6 +311,12 @@ module Telegem
|
|
|
240
311
|
return :poll if update.poll
|
|
241
312
|
return :pre_checkout_query if update.pre_checkout_query
|
|
242
313
|
return :shipping_query if update.shipping_query
|
|
314
|
+
return :poll_answer if update.poll_answer
|
|
315
|
+
return :chat_join_request if update.chat_join_request
|
|
316
|
+
return :chat_boost if update.chat_boost
|
|
317
|
+
return :removed_chat_boost if update.removed_chat_boost
|
|
318
|
+
return :message_reaction if update.message_reaction
|
|
319
|
+
return :message_reaction_count if update.message_reaction_count
|
|
243
320
|
:unknown
|
|
244
321
|
end
|
|
245
322
|
|
|
@@ -254,10 +331,20 @@ module Telegem
|
|
|
254
331
|
matches_chat_type_filter(ctx, value)
|
|
255
332
|
when :command
|
|
256
333
|
matches_command_filter(ctx, value)
|
|
257
|
-
|
|
334
|
+
when :location
|
|
335
|
+
ctx.message&.location != nil
|
|
336
|
+
when :contact
|
|
337
|
+
ctx.message&.contact != nil
|
|
338
|
+
when :web_app_data
|
|
339
|
+
ctx.message&.web_app_data != nil
|
|
340
|
+
else
|
|
341
|
+
if ctx.update.respond_to?(key)
|
|
258
342
|
ctx.update.send(key) == value
|
|
259
|
-
|
|
260
|
-
|
|
343
|
+
else
|
|
344
|
+
false
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
end
|
|
261
348
|
end
|
|
262
349
|
|
|
263
350
|
def matches_text_filter(ctx, pattern)
|
data/lib/telegem.rb
CHANGED
|
@@ -3,7 +3,7 @@ require 'logger'
|
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
5
|
module Telegem
|
|
6
|
-
VERSION = "3.0.
|
|
6
|
+
VERSION = "3.0.4".freeze
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
# Load core components
|
|
@@ -80,4 +80,4 @@ if ENV['TELEGEM_GLOBAL'] == 'true'
|
|
|
80
80
|
def Telegem(token, **options)
|
|
81
81
|
::Telegem.new(token, **options)
|
|
82
82
|
end
|
|
83
|
-
end
|
|
83
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: telegem
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- sick_phantom
|
|
@@ -173,14 +173,13 @@ extensions: []
|
|
|
173
173
|
extra_rdoc_files: []
|
|
174
174
|
files:
|
|
175
175
|
- ".replit"
|
|
176
|
+
- CHANGELOG
|
|
176
177
|
- Contributing.md
|
|
177
178
|
- Gemfile
|
|
178
179
|
- Gemfile.lock
|
|
179
180
|
- LICENSE
|
|
180
181
|
- Readme.md
|
|
181
182
|
- Starts_HallofFame.md
|
|
182
|
-
- Test-Projects/bot.md
|
|
183
|
-
- Test-Projects/bot1.rb
|
|
184
183
|
- bin/.gitkeep
|
|
185
184
|
- bin/telegem-ssl
|
|
186
185
|
- docs-src/.gitkeep
|
|
@@ -192,6 +191,7 @@ files:
|
|
|
192
191
|
- docs-src/keyboard_inline.md
|
|
193
192
|
- docs-src/scene.md
|
|
194
193
|
- docs-src/webhook.md
|
|
194
|
+
- examples/.gitkeep
|
|
195
195
|
- lib/api/client.rb
|
|
196
196
|
- lib/api/types.rb
|
|
197
197
|
- lib/core/bot.rb
|
|
@@ -206,7 +206,6 @@ files:
|
|
|
206
206
|
- lib/webhook/.gitkeep
|
|
207
207
|
- lib/webhook/server.rb
|
|
208
208
|
- public/.gitkeep
|
|
209
|
-
- public/index.html
|
|
210
209
|
homepage: https://gitlab.com/ruby-telegem/telegem
|
|
211
210
|
licenses:
|
|
212
211
|
- MIT
|
|
@@ -217,7 +216,7 @@ metadata:
|
|
|
217
216
|
bug_tracker_uri: https://gitlab.com/ruby-telegem/telegem/-/issues
|
|
218
217
|
documentation_uri: https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs-src?ref_type=heads
|
|
219
218
|
rubygems_mfa_required: 'false'
|
|
220
|
-
post_install_message: "Thanks for installing Telegem 3.0.
|
|
219
|
+
post_install_message: "Thanks for installing Telegem 3.0.4!\n\n\U0001F4DA Documentation:
|
|
221
220
|
https://gitlab.com/ruby-telegem/telegem\n\n\U0001F510 For SSL Webhooks:\nRun: telegem-ssl
|
|
222
221
|
your-domain.com\nThis sets up Let's Encrypt certificates automatically.\n\n\U0001F916
|
|
223
222
|
Happy bot building!\n"
|
data/Test-Projects/bot.md
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
bot1.md - Telegem Response Patterns
|
|
2
|
-
|
|
3
|
-
How Telegem Returns API Responses
|
|
4
|
-
|
|
5
|
-
All ctx methods return HTTPX::Response objects, not JSON hashes.
|
|
6
|
-
|
|
7
|
-
Pattern 1: Fire-and-Forget
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
ctx.reply("Hello!")
|
|
11
|
-
ctx.photo("image.jpg")
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Pattern 2: Get Message ID
|
|
15
|
-
|
|
16
|
-
```ruby
|
|
17
|
-
response = ctx.reply("Sending...")
|
|
18
|
-
|
|
19
|
-
if response && response.status == 200
|
|
20
|
-
data = response.json
|
|
21
|
-
if data && data['ok']
|
|
22
|
-
message_id = data['result']['message_id']
|
|
23
|
-
ctx.session[:msg_id] = message_id
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Pattern 3: Check for Errors
|
|
29
|
-
|
|
30
|
-
```ruby
|
|
31
|
-
response = ctx.reply("Testing...")
|
|
32
|
-
|
|
33
|
-
if response && response.status != 200
|
|
34
|
-
error = response.json rescue nil
|
|
35
|
-
error_msg = error['description'] if error
|
|
36
|
-
ctx.reply("Failed: #{error_msg}")
|
|
37
|
-
end
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Pattern 4: Edit Messages
|
|
41
|
-
|
|
42
|
-
```ruby
|
|
43
|
-
edit_response = ctx.edit_message_text(
|
|
44
|
-
"Updated!",
|
|
45
|
-
message_id: ctx.session[:msg_id]
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
if edit_response && edit_response.status == 200
|
|
49
|
-
ctx.reply("Edit succeeded!")
|
|
50
|
-
end
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Pattern 5: Send Media
|
|
54
|
-
|
|
55
|
-
```ruby
|
|
56
|
-
photo_response = ctx.photo(
|
|
57
|
-
"https://example.com/image.jpg",
|
|
58
|
-
caption: "My photo"
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
if photo_response && photo_response.status == 200
|
|
62
|
-
ctx.reply("Photo sent!")
|
|
63
|
-
end
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Pattern 6: Handle Callbacks
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
bot.on(:callback_query) do |ctx|
|
|
70
|
-
ctx.answer_callback_query(text: "Clicked: #{ctx.data}")
|
|
71
|
-
|
|
72
|
-
if ctx.data == 'test'
|
|
73
|
-
ctx.edit_message_text("Updated after click!")
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Pattern 7: Error Wrapping
|
|
79
|
-
|
|
80
|
-
```ruby
|
|
81
|
-
begin
|
|
82
|
-
response = ctx.reply(some_text)
|
|
83
|
-
# Process response
|
|
84
|
-
rescue => e
|
|
85
|
-
ctx.reply("Error: #{e.message}")
|
|
86
|
-
end
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Complete bot1.rb Explained
|
|
90
|
-
|
|
91
|
-
Setup
|
|
92
|
-
|
|
93
|
-
```ruby
|
|
94
|
-
require 'telegem'
|
|
95
|
-
require 'dotenv/load'
|
|
96
|
-
bot = Telegem.new(ENV['BOT_TOKEN'])
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
/start Command
|
|
100
|
-
|
|
101
|
-
Sends welcome, stores message ID in session.
|
|
102
|
-
|
|
103
|
-
/help Command
|
|
104
|
-
|
|
105
|
-
Simple reply with command list.
|
|
106
|
-
|
|
107
|
-
/edit Command
|
|
108
|
-
|
|
109
|
-
Edits the stored message, checks edit response.
|
|
110
|
-
|
|
111
|
-
/photo Command
|
|
112
|
-
|
|
113
|
-
Sends photo, confirms delivery.
|
|
114
|
-
|
|
115
|
-
/error Command
|
|
116
|
-
|
|
117
|
-
Demonstrates error handling.
|
|
118
|
-
|
|
119
|
-
Callback Handler
|
|
120
|
-
|
|
121
|
-
Answers inline button clicks.
|
|
122
|
-
|
|
123
|
-
Startup Logic
|
|
124
|
-
|
|
125
|
-
```ruby
|
|
126
|
-
if ENV['RACK_ENV'] == 'production'
|
|
127
|
-
# Webhook mode
|
|
128
|
-
server = bot.webhook(port: ENV['PORT'] || 3000)
|
|
129
|
-
server.run
|
|
130
|
-
server.set_webhook
|
|
131
|
-
else
|
|
132
|
-
# Polling mode (development)
|
|
133
|
-
bot.start_polling(timeout: 30, limit: 100)
|
|
134
|
-
end
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
Key Takeaways
|
|
138
|
-
|
|
139
|
-
1. Always check response.status (200 = success)
|
|
140
|
-
2. Call .json to get data from response
|
|
141
|
-
3. Check data['ok'] before using result
|
|
142
|
-
4. Store message_id for later editing
|
|
143
|
-
5. Wrap in begin/rescue for network issues
|
|
144
|
-
|
|
145
|
-
This pattern ensures your bot handles all API scenarios correctly.
|
data/Test-Projects/bot1.rb
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
require 'telegem'
|
|
2
|
-
require 'dotenv/load'
|
|
3
|
-
|
|
4
|
-
bot = Telegem.new(ENV['BOT_TOKEN'])
|
|
5
|
-
|
|
6
|
-
bot.command('start') do |ctx|
|
|
7
|
-
ctx.reply("Welcome! Use /help for commands.")
|
|
8
|
-
|
|
9
|
-
response = ctx.reply("Processing your request...")
|
|
10
|
-
|
|
11
|
-
if response && response.status == 200
|
|
12
|
-
data = response.json
|
|
13
|
-
if data && data['ok']
|
|
14
|
-
ctx.session[:start_msg_id] = data['result']['message_id']
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
bot.command('help') do |ctx|
|
|
20
|
-
help_text = <<~HELP
|
|
21
|
-
Available commands:
|
|
22
|
-
/start - Start the bot
|
|
23
|
-
/help - This help message
|
|
24
|
-
/edit - Edit the start message
|
|
25
|
-
/error - Test error handling
|
|
26
|
-
/photo - Send a photo
|
|
27
|
-
HELP
|
|
28
|
-
|
|
29
|
-
ctx.reply(help_text)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
bot.command('edit') do |ctx|
|
|
33
|
-
if ctx.session[:start_msg_id]
|
|
34
|
-
edit_response = ctx.edit_message_text(
|
|
35
|
-
"✅ Updated at #{Time.now.strftime('%H:%M:%S')}",
|
|
36
|
-
message_id: ctx.session[:start_msg_id]
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
if edit_response && edit_response.status == 200
|
|
40
|
-
ctx.reply("Message edited successfully!")
|
|
41
|
-
else
|
|
42
|
-
status = edit_response ? edit_response.status : 'no response'
|
|
43
|
-
ctx.reply("Edit failed (status: #{status})")
|
|
44
|
-
end
|
|
45
|
-
else
|
|
46
|
-
ctx.reply("Send /start first to create a message to edit.")
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
bot.command('photo') do |ctx|
|
|
51
|
-
photo_response = ctx.photo(
|
|
52
|
-
"https://picsum.photos/400/300",
|
|
53
|
-
caption: "Random image - #{Time.now.strftime('%H:%M:%S')}"
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
if photo_response && photo_response.status == 200
|
|
57
|
-
ctx.reply("Photo sent successfully!")
|
|
58
|
-
else
|
|
59
|
-
ctx.reply("Failed to send photo.")
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
bot.command('error') do |ctx|
|
|
64
|
-
begin
|
|
65
|
-
invalid_response = ctx.reply(nil)
|
|
66
|
-
|
|
67
|
-
if invalid_response && invalid_response.status != 200
|
|
68
|
-
error_data = invalid_response.json rescue nil
|
|
69
|
-
error_msg = error_data ? error_data['description'] : "Unknown error"
|
|
70
|
-
ctx.reply("API Error: #{error_msg}")
|
|
71
|
-
end
|
|
72
|
-
rescue => e
|
|
73
|
-
ctx.reply("Ruby Error: #{e.message}")
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
bot.on(:callback_query) do |ctx|
|
|
78
|
-
ctx.answer_callback_query(text: "Button clicked: #{ctx.data}")
|
|
79
|
-
|
|
80
|
-
if ctx.data == 'test'
|
|
81
|
-
ctx.edit_message_text("You clicked the test button!")
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
if ENV['RACK_ENV'] == 'production'
|
|
86
|
-
server = bot.webhook(port: ENV['PORT'] || 3000)
|
|
87
|
-
server.run
|
|
88
|
-
server.set_webhook
|
|
89
|
-
else
|
|
90
|
-
bot.start_polling(timeout: 30, limit: 100)
|
|
91
|
-
end
|
data/public/index.html
DELETED
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Telegem Docs - Telegram Bot Framework for Ruby</title>
|
|
7
|
-
<style>
|
|
8
|
-
* {
|
|
9
|
-
margin: 0;
|
|
10
|
-
padding: 0;
|
|
11
|
-
box-sizing: border-box;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
body {
|
|
15
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16
|
-
line-height: 1.6;
|
|
17
|
-
color: #1a1a1a;
|
|
18
|
-
background: #fafafa;
|
|
19
|
-
padding: 0;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.container {
|
|
23
|
-
max-width: 900px;
|
|
24
|
-
margin: 0 auto;
|
|
25
|
-
padding: 2rem 1.5rem;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
.header {
|
|
29
|
-
padding-bottom: 2rem;
|
|
30
|
-
margin-bottom: 2rem;
|
|
31
|
-
border-bottom: 1px solid #eaeaea;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
.header h1 {
|
|
35
|
-
font-size: 2.2rem;
|
|
36
|
-
color: #2c3e50;
|
|
37
|
-
margin-bottom: 0.25rem;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.tagline {
|
|
41
|
-
font-size: 1.1rem;
|
|
42
|
-
color: #7f8c8d;
|
|
43
|
-
margin-bottom: 1.5rem;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.stats {
|
|
47
|
-
display: flex;
|
|
48
|
-
gap: 1.5rem;
|
|
49
|
-
margin-top: 1rem;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.stat {
|
|
53
|
-
background: white;
|
|
54
|
-
padding: 0.75rem 1rem;
|
|
55
|
-
border-radius: 6px;
|
|
56
|
-
border: 1px solid #eaeaea;
|
|
57
|
-
min-width: 120px;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.stat-label {
|
|
61
|
-
font-size: 0.8rem;
|
|
62
|
-
color: #95a5a6;
|
|
63
|
-
text-transform: uppercase;
|
|
64
|
-
letter-spacing: 0.5px;
|
|
65
|
-
margin-bottom: 0.25rem;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.stat-value {
|
|
69
|
-
font-size: 1.1rem;
|
|
70
|
-
font-weight: 600;
|
|
71
|
-
color: #2c3e50;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.doc-nav {
|
|
75
|
-
display: flex;
|
|
76
|
-
gap: 0.5rem;
|
|
77
|
-
margin: 2rem 0;
|
|
78
|
-
flex-wrap: wrap;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.nav-btn {
|
|
82
|
-
background: white;
|
|
83
|
-
border: 1px solid #ddd;
|
|
84
|
-
padding: 0.5rem 1rem;
|
|
85
|
-
border-radius: 4px;
|
|
86
|
-
font-size: 0.9rem;
|
|
87
|
-
color: #555;
|
|
88
|
-
cursor: pointer;
|
|
89
|
-
transition: all 0.2s;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.nav-btn:hover {
|
|
93
|
-
border-color: #3498db;
|
|
94
|
-
color: #3498db;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.nav-btn.active {
|
|
98
|
-
background: #3498db;
|
|
99
|
-
border-color: #3498db;
|
|
100
|
-
color: white;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.doc-section {
|
|
104
|
-
background: white;
|
|
105
|
-
border-radius: 8px;
|
|
106
|
-
padding: 2rem;
|
|
107
|
-
margin-bottom: 1.5rem;
|
|
108
|
-
border: 1px solid #eaeaea;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
.doc-section h2 {
|
|
112
|
-
font-size: 1.5rem;
|
|
113
|
-
color: #2c3e50;
|
|
114
|
-
margin-bottom: 1rem;
|
|
115
|
-
padding-bottom: 0.5rem;
|
|
116
|
-
border-bottom: 2px solid #f0f0f0;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.doc-section h3 {
|
|
120
|
-
font-size: 1.1rem;
|
|
121
|
-
color: #34495e;
|
|
122
|
-
margin: 1.5rem 0 0.75rem;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.doc-section p {
|
|
126
|
-
margin-bottom: 1rem;
|
|
127
|
-
color: #555;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.method-list {
|
|
131
|
-
list-style: none;
|
|
132
|
-
margin: 1rem 0;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.method-item {
|
|
136
|
-
margin-bottom: 0.75rem;
|
|
137
|
-
padding: 0.75rem;
|
|
138
|
-
background: #f8f9fa;
|
|
139
|
-
border-radius: 4px;
|
|
140
|
-
border-left: 3px solid #3498db;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.method-name {
|
|
144
|
-
font-family: 'SF Mono', Monaco, Consolas, monospace;
|
|
145
|
-
font-weight: 600;
|
|
146
|
-
color: #2c3e50;
|
|
147
|
-
margin-bottom: 0.25rem;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
.method-desc {
|
|
151
|
-
color: #7f8c8d;
|
|
152
|
-
font-size: 0.9rem;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.code-block {
|
|
156
|
-
background: #2c3e50;
|
|
157
|
-
color: #ecf0f1;
|
|
158
|
-
padding: 1.25rem;
|
|
159
|
-
border-radius: 6px;
|
|
160
|
-
margin: 1rem 0;
|
|
161
|
-
font-family: 'SF Mono', Monaco, Consolas, monospace;
|
|
162
|
-
font-size: 0.9rem;
|
|
163
|
-
line-height: 1.5;
|
|
164
|
-
overflow-x: auto;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.code-block::selection {
|
|
168
|
-
background: #3498db;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.links {
|
|
172
|
-
display: flex;
|
|
173
|
-
gap: 1rem;
|
|
174
|
-
margin-top: 2rem;
|
|
175
|
-
padding-top: 1.5rem;
|
|
176
|
-
border-top: 1px solid #eaeaea;
|
|
177
|
-
flex-wrap: wrap;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.link-btn {
|
|
181
|
-
display: inline-flex;
|
|
182
|
-
align-items: center;
|
|
183
|
-
gap: 0.5rem;
|
|
184
|
-
padding: 0.6rem 1.2rem;
|
|
185
|
-
background: #3498db;
|
|
186
|
-
color: white;
|
|
187
|
-
text-decoration: none;
|
|
188
|
-
border-radius: 4px;
|
|
189
|
-
font-size: 0.9rem;
|
|
190
|
-
transition: background 0.2s;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
.link-btn:hover {
|
|
194
|
-
background: #2980b9;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
.link-btn.secondary {
|
|
198
|
-
background: white;
|
|
199
|
-
color: #555;
|
|
200
|
-
border: 1px solid #ddd;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
.link-btn.secondary:hover {
|
|
204
|
-
background: #f8f9fa;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.note {
|
|
208
|
-
background: #f8f9fa;
|
|
209
|
-
padding: 1rem;
|
|
210
|
-
border-left: 3px solid #3498db;
|
|
211
|
-
margin: 1rem 0;
|
|
212
|
-
border-radius: 0 4px 4px 0;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
@media (max-width: 768px) {
|
|
216
|
-
.container {
|
|
217
|
-
padding: 1rem;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
.doc-section {
|
|
221
|
-
padding: 1.5rem;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
.stats {
|
|
225
|
-
flex-direction: column;
|
|
226
|
-
gap: 0.75rem;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
.stat {
|
|
230
|
-
min-width: auto;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
</style>
|
|
234
|
-
</head>
|
|
235
|
-
<body>
|
|
236
|
-
<div class="container">
|
|
237
|
-
<header class="header">
|
|
238
|
-
<div>
|
|
239
|
-
<h1>Telegem</h1>
|
|
240
|
-
<p class="tagline">Telegram Bot Framework for Ruby</p>
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
<div class="stats">
|
|
244
|
-
<div class="stat">
|
|
245
|
-
<div class="stat-label">Version</div>
|
|
246
|
-
<div class="stat-value" id="gem-version">Loading...</div>
|
|
247
|
-
</div>
|
|
248
|
-
<div class="stat">
|
|
249
|
-
<div class="stat-label">Downloads</div>
|
|
250
|
-
<div class="stat-value" id="gem-downloads">Loading...</div>
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
|
|
254
|
-
<div class="doc-nav">
|
|
255
|
-
<button class="nav-btn active" onclick="showDoc('quickstart')">Quick Start</button>
|
|
256
|
-
<button class="nav-btn" onclick="showDoc('ctx')">Context API</button>
|
|
257
|
-
<button class="nav-btn" onclick="showDoc('bot')">Bot API</button>
|
|
258
|
-
<button class="nav-btn" onclick="showDoc('scenes')">Scenes</button>
|
|
259
|
-
<button class="nav-btn" onclick="showDoc('webhook')">Webhook</button>
|
|
260
|
-
</div>
|
|
261
|
-
</header>
|
|
262
|
-
|
|
263
|
-
<!-- Quick Start -->
|
|
264
|
-
<section id="quickstart-doc" class="doc-section">
|
|
265
|
-
<h2>Quick Start</h2>
|
|
266
|
-
|
|
267
|
-
<h3>Installation</h3>
|
|
268
|
-
<div class="code-block">
|
|
269
|
-
# Add to Gemfile
|
|
270
|
-
gem 'telegem'
|
|
271
|
-
|
|
272
|
-
# Or install directly
|
|
273
|
-
$ gem install telegem
|
|
274
|
-
</div>
|
|
275
|
-
|
|
276
|
-
<h3>Basic Usage</h3>
|
|
277
|
-
<div class="code-block">
|
|
278
|
-
require 'telegem'
|
|
279
|
-
|
|
280
|
-
bot = Telegem.new("YOUR_BOT_TOKEN")
|
|
281
|
-
|
|
282
|
-
bot.command('start') do |ctx|
|
|
283
|
-
ctx.reply("Welcome to Telegem!")
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
bot.command('help') do |ctx|
|
|
287
|
-
ctx.reply("Available commands: /start, /help")
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
# Start the bot
|
|
291
|
-
bot.start_polling
|
|
292
|
-
</div>
|
|
293
|
-
|
|
294
|
-
<div class="note">
|
|
295
|
-
Replace <code>YOUR_BOT_TOKEN</code> with your actual Telegram Bot token from @BotFather
|
|
296
|
-
</div>
|
|
297
|
-
|
|
298
|
-
<div class="links">
|
|
299
|
-
<a href="https://rubygems.org/gems/telegem" class="link-btn">📦 View on RubyGems</a>
|
|
300
|
-
<a href="https://gitlab.com/ruby-telegem/telegem" class="link-btn secondary">🐱 GitLab Repository</a>
|
|
301
|
-
</div>
|
|
302
|
-
</section>
|
|
303
|
-
|
|
304
|
-
<!-- ctx API -->
|
|
305
|
-
<section id="ctx-doc" class="doc-section" style="display: none;">
|
|
306
|
-
<h2>Context API</h2>
|
|
307
|
-
<p>The context object provides access to the current update and response methods.</p>
|
|
308
|
-
|
|
309
|
-
<h3>Properties</h3>
|
|
310
|
-
<ul class="method-list">
|
|
311
|
-
<li class="method-item">
|
|
312
|
-
<div class="method-name">ctx.message</div>
|
|
313
|
-
<div class="method-desc">Current message object</div>
|
|
314
|
-
</li>
|
|
315
|
-
<li class="method-item">
|
|
316
|
-
<div class="method-name">ctx.from</div>
|
|
317
|
-
<div class="method-desc">User who sent the message</div>
|
|
318
|
-
</li>
|
|
319
|
-
<li class="method-item">
|
|
320
|
-
<div class="method-name">ctx.chat</div>
|
|
321
|
-
<div class="method-desc">Chat information</div>
|
|
322
|
-
</li>
|
|
323
|
-
<li class="method-item">
|
|
324
|
-
<div class="method-name">ctx.session</div>
|
|
325
|
-
<div class="method-desc">Persistent user storage</div>
|
|
326
|
-
</li>
|
|
327
|
-
</ul>
|
|
328
|
-
|
|
329
|
-
<h3>Methods</h3>
|
|
330
|
-
<div class="code-block">
|
|
331
|
-
# Send message
|
|
332
|
-
ctx.reply("Hello!")
|
|
333
|
-
|
|
334
|
-
# Send photo
|
|
335
|
-
ctx.photo("photo.jpg", caption: "My photo")
|
|
336
|
-
|
|
337
|
-
# Edit message
|
|
338
|
-
ctx.edit_message_text("Updated text")
|
|
339
|
-
|
|
340
|
-
# Delete message
|
|
341
|
-
ctx.delete_message(message_id)
|
|
342
|
-
</div>
|
|
343
|
-
|
|
344
|
-
<div class="links">
|
|
345
|
-
<a href="https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs/context.md" class="link-btn">📄 Full Context Docs</a>
|
|
346
|
-
</div>
|
|
347
|
-
</section>
|
|
348
|
-
|
|
349
|
-
<!-- Bot API -->
|
|
350
|
-
<section id="bot-doc" class="doc-section" style="display: none;">
|
|
351
|
-
<h2>Bot API</h2>
|
|
352
|
-
<p>Configure handlers and control bot lifecycle.</p>
|
|
353
|
-
|
|
354
|
-
<div class="code-block">
|
|
355
|
-
# Handle commands
|
|
356
|
-
bot.command('start') { |ctx| ctx.reply("Welcome") }
|
|
357
|
-
|
|
358
|
-
# Handle text patterns
|
|
359
|
-
bot.hears(/hello/i) { |ctx| ctx.reply("Hi there!") }
|
|
360
|
-
|
|
361
|
-
# Handle specific update types
|
|
362
|
-
bot.on(:photo) { |ctx| ctx.reply("Nice photo!") }
|
|
363
|
-
bot.on(:callback_query) { |ctx| ctx.answer_callback_query }
|
|
364
|
-
|
|
365
|
-
# Start bot
|
|
366
|
-
bot.start_polling
|
|
367
|
-
# or
|
|
368
|
-
bot.webhook.run
|
|
369
|
-
</div>
|
|
370
|
-
|
|
371
|
-
<div class="links">
|
|
372
|
-
<a href="https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs/bot.md" class="link-btn">📄 Bot API Reference</a>
|
|
373
|
-
</div>
|
|
374
|
-
</section>
|
|
375
|
-
|
|
376
|
-
<!-- Scenes -->
|
|
377
|
-
<section id="scenes-doc" class="doc-section" style="display: none;">
|
|
378
|
-
<h2>Scenes</h2>
|
|
379
|
-
<p>Multi-step conversations for complex interactions.</p>
|
|
380
|
-
|
|
381
|
-
<div class="code-block">
|
|
382
|
-
bot.scene :registration do
|
|
383
|
-
step :ask_name do |ctx|
|
|
384
|
-
ctx.reply("What is your name?")
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
step :save_name do |ctx|
|
|
388
|
-
ctx.session[:name] = ctx.message.text
|
|
389
|
-
ctx.reply("Hello #{ctx.session[:name]}!")
|
|
390
|
-
ctx.leave_scene
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
# Enter scene
|
|
395
|
-
bot.command('register') { |ctx| ctx.enter_scene(:registration) }
|
|
396
|
-
</div>
|
|
397
|
-
|
|
398
|
-
<div class="links">
|
|
399
|
-
<a href="https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs/scenes.md" class="link-btn">📄 Scenes Guide</a>
|
|
400
|
-
</div>
|
|
401
|
-
</section>
|
|
402
|
-
|
|
403
|
-
<!-- Webhook -->
|
|
404
|
-
<section id="webhook-doc" class="doc-section" style="display: none;">
|
|
405
|
-
<h2>Webhook Deployment</h2>
|
|
406
|
-
<p>Production deployment with webhooks.</p>
|
|
407
|
-
|
|
408
|
-
<div class="code-block">
|
|
409
|
-
# Production setup
|
|
410
|
-
bot = Telegem.new("TOKEN")
|
|
411
|
-
|
|
412
|
-
# Configure webhook
|
|
413
|
-
bot.webhook(
|
|
414
|
-
url: 'https://your-domain.com/webhook',
|
|
415
|
-
port: 3000
|
|
416
|
-
).run
|
|
417
|
-
|
|
418
|
-
# For cloud platforms
|
|
419
|
-
bot.webhook.run # Auto-detects platform
|
|
420
|
-
</div>
|
|
421
|
-
|
|
422
|
-
<div class="note">
|
|
423
|
-
Webhook mode is recommended for production. Uses less resources than polling.
|
|
424
|
-
</div>
|
|
425
|
-
|
|
426
|
-
<div class="links">
|
|
427
|
-
<a href="https://gitlab.com/ruby-telegem/telegem/-/tree/main/docs/deployment.md" class="link-btn">📄 Deployment Guide</a>
|
|
428
|
-
</div>
|
|
429
|
-
</section>
|
|
430
|
-
|
|
431
|
-
<!-- Footer -->
|
|
432
|
-
<div class="doc-section">
|
|
433
|
-
<div class="links">
|
|
434
|
-
<a href="https://gitlab.com/ruby-telegem/telegem" class="link-btn">🏠 Main Repository</a>
|
|
435
|
-
<a href="https://rubygems.org/gems/telegem" class="link-btn secondary">💎 RubyGems</a>
|
|
436
|
-
<a href="https://gitlab.com/ruby-telegem/telegem/-/issues" class="link-btn secondary">🐛 Issue Tracker</a>
|
|
437
|
-
</div>
|
|
438
|
-
</div>
|
|
439
|
-
</div>
|
|
440
|
-
|
|
441
|
-
<script>
|
|
442
|
-
async function fetchGemStats() {
|
|
443
|
-
try {
|
|
444
|
-
const response = await fetch('https://rubygems.org/api/v1/gems/telegem.json');
|
|
445
|
-
const data = await response.json();
|
|
446
|
-
|
|
447
|
-
if (data.version) {
|
|
448
|
-
document.getElementById('gem-version').textContent = `v${data.version}`;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (data.downloads) {
|
|
452
|
-
document.getElementById('gem-downloads').textContent =
|
|
453
|
-
data.downloads.toLocaleString();
|
|
454
|
-
}
|
|
455
|
-
} catch (error) {
|
|
456
|
-
document.getElementById('gem-version').textContent = 'v3.0.0';
|
|
457
|
-
document.getElementById('gem-downloads').textContent = 'N/A';
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
function showDoc(section) {
|
|
462
|
-
document.querySelectorAll('.doc-section').forEach(el => {
|
|
463
|
-
el.style.display = 'none';
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
document.getElementById(`${section}-doc`).style.display = 'block';
|
|
467
|
-
|
|
468
|
-
document.querySelectorAll('.nav-btn').forEach(btn => {
|
|
469
|
-
btn.classList.remove('active');
|
|
470
|
-
});
|
|
471
|
-
event.target.classList.add('active');
|
|
472
|
-
|
|
473
|
-
window.scrollTo(0, 0);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
477
|
-
fetchGemStats();
|
|
478
|
-
});
|
|
479
|
-
</script>
|
|
480
|
-
</body>
|
|
481
|
-
</html>
|