telegem 3.3.0 → 3.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.
data/docs/context.md ADDED
@@ -0,0 +1,554 @@
1
+ # Context Object (ctx)
2
+
3
+ The Context object is the heart of every Telegem bot handler. It encapsulates the current update and provides methods to interact with Telegram's API.
4
+
5
+ ## Overview
6
+
7
+ Every handler receives a `ctx` (context) parameter containing:
8
+
9
+ - Current update information
10
+ - Bot instance reference
11
+ - User and chat data
12
+ - Session data
13
+ - Response methods
14
+ - Utility helpers
15
+
16
+ ## Core Properties
17
+
18
+ ### Update Information
19
+
20
+ ```ruby
21
+ ctx.update # Raw Update object (Telegem::Types::Update)
22
+ ctx.update_id # Unique update identifier
23
+ ctx.update_type # :message, :callback_query, :inline_query, etc.
24
+ ```
25
+
26
+ ### Bot Reference
27
+
28
+ ```ruby
29
+ ctx.bot # Bot instance
30
+ ctx.api # Direct API client access
31
+ ctx.logger # Bot's logger
32
+ ```
33
+
34
+ ### State Management
35
+
36
+ ```ruby
37
+ ctx.state # Temporary state (cleared after handler)
38
+ ctx.session # Persistent user session
39
+ ctx.match # Regex match data from hears/command
40
+ ctx.scene # Current scene data
41
+ ```
42
+
43
+ ## User and Chat Information
44
+
45
+ ### User Data
46
+
47
+ ```ruby
48
+ ctx.from # User object (Telegem::Types::User)
49
+ ctx.from.id # User ID (integer)
50
+ ctx.from.username # Username (string, may be nil)
51
+ ctx.from.first_name # First name
52
+ ctx.from.last_name # Last name (may be nil)
53
+ ctx.from.language_code # User's language ('en', 'es', etc.)
54
+ ctx.from.is_bot # Boolean: is this user a bot?
55
+ ctx.from.is_premium # Boolean: has Telegram Premium?
56
+
57
+ # Convenience methods
58
+ ctx.user_id # Shortcut for ctx.from&.id
59
+ ```
60
+
61
+ ### Chat Data
62
+
63
+ ```ruby
64
+ ctx.chat # Chat object (Telegem::Types::Chat)
65
+ ctx.chat.id # Chat ID
66
+ ctx.chat.type # 'private', 'group', 'supergroup', 'channel'
67
+ ctx.chat.title # Chat title (for groups/channels)
68
+ ctx.chat.username # Chat username (for public chats)
69
+
70
+ # Type checking
71
+ ctx.chat.private? # Is private chat?
72
+ ctx.chat.group? # Is group?
73
+ ctx.chat.supergroup? # Is supergroup?
74
+ ctx.chat.channel? # Is channel?
75
+ ```
76
+
77
+ ## Message Access
78
+
79
+ ### Basic Message Properties
80
+
81
+ ```ruby
82
+ ctx.message # Message object (Telegem::Types::Message)
83
+ ctx.message.message_id # Message ID
84
+ ctx.message.date # Send date (Time object)
85
+ ctx.message.edit_date # Edit date (Time object, if edited)
86
+ ctx.message.text # Message text
87
+ ctx.message.caption # Media caption
88
+
89
+ # Convenience shortcuts
90
+ ctx.text # ctx.message&.text
91
+ ctx.caption # ctx.message&.caption
92
+ ctx.message_id # ctx.message&.message_id
93
+ ```
94
+
95
+ ### Message Metadata
96
+
97
+ ```ruby
98
+ ctx.message.from # Sender (same as ctx.from)
99
+ ctx.message.chat # Chat (same as ctx.chat)
100
+ ctx.message.reply_to_message # Replied-to message
101
+ ctx.message.forward_from # Original sender (if forwarded)
102
+ ctx.message.entities # Text formatting entities
103
+ ctx.message.caption_entities # Caption formatting entities
104
+ ```
105
+
106
+ ### Reply Information
107
+
108
+ ```ruby
109
+ ctx.reply? # Is this a reply?
110
+ ctx.replied_message # Message being replied to
111
+ ctx.replied_text # Text of replied message
112
+ ctx.replied_from # User who sent replied message
113
+ ctx.replied_chat # Chat of replied message
114
+ ```
115
+
116
+ ### Command Processing
117
+
118
+ ```ruby
119
+ ctx.command? # Is message a command?
120
+ ctx.command_name # Command name ('start', 'help')
121
+ ctx.command_args # Arguments string after command
122
+
123
+ # Example: /ban @user reason
124
+ ctx.command_name # => 'ban'
125
+ ctx.command_args # => '@user reason'
126
+ ```
127
+
128
+ ### Media Detection
129
+
130
+ ```ruby
131
+ ctx.has_media? # Has any media attachment?
132
+ ctx.media_type # :photo, :document, :audio, :video, :voice, :sticker
133
+
134
+ # Specific media
135
+ ctx.message.photo # Array of PhotoSize objects
136
+ ctx.message.document # Document object
137
+ ctx.message.audio # Audio object
138
+ ctx.message.video # Video object
139
+ ctx.message.voice # Voice object
140
+ ctx.message.sticker # Sticker object
141
+ ctx.message.animation # Animation object
142
+ ctx.message.video_note # VideoNote object
143
+ ```
144
+
145
+ ## Update Type Detection
146
+
147
+ ### Callback Queries
148
+
149
+ ```ruby
150
+ ctx.callback_query? # Is callback query update?
151
+ ctx.callback_query # CallbackQuery object
152
+ ctx.data # Callback data string
153
+ ```
154
+
155
+ ### Inline Queries
156
+
157
+ ```ruby
158
+ ctx.inline_query? # Is inline query update?
159
+ ctx.inline_query # InlineQuery object
160
+ ctx.query # Search query string
161
+ ```
162
+
163
+ ### Other Update Types
164
+
165
+ ```ruby
166
+ ctx.poll? # Poll update
167
+ ctx.poll_answer? # Poll answer update
168
+ ctx.chat_member? # Chat member update
169
+ ctx.my_chat_member? # Bot's membership update
170
+ ctx.chat_join_request? # Join request update
171
+ ```
172
+
173
+ ## Sending Messages
174
+
175
+ ### Basic Text Replies
176
+
177
+ ```ruby
178
+ ctx.reply("Hello world!")
179
+ ctx.reply("Hello", parse_mode: "Markdown")
180
+ ctx.reply("Hello", disable_web_page_preview: true)
181
+ ctx.reply("Hello", reply_to_message_id: 123)
182
+ ```
183
+
184
+ ### Media Messages
185
+
186
+ ```ruby
187
+ # Photos
188
+ ctx.photo("https://example.com/image.jpg")
189
+ ctx.photo(File.open("local.jpg"))
190
+ ctx.photo(file_id, caption: "Caption")
191
+
192
+ # Documents
193
+ ctx.document("file.pdf", caption: "Report")
194
+ ctx.document(File.open("report.pdf"))
195
+
196
+ # Audio/Video
197
+ ctx.audio("song.mp3", title: "Song", performer: "Artist")
198
+ ctx.video("video.mp4", caption: "Video")
199
+ ctx.voice("voice.ogg")
200
+ ctx.sticker(sticker_file_id)
201
+ ```
202
+
203
+ ### Location and Contact
204
+
205
+ ```ruby
206
+ ctx.location(37.7749, -122.4194) # Latitude, longitude
207
+ ctx.contact("+1234567890", "John", last_name: "Doe")
208
+ ```
209
+
210
+ ### Chat Actions
211
+
212
+ ```ruby
213
+ ctx.typing
214
+ ctx.uploading_photo
215
+ ctx.uploading_video
216
+ ctx.uploading_document
217
+ ctx.find_location
218
+ ctx.record_video
219
+ ctx.record_audio
220
+ ```
221
+
222
+ ## Keyboard Markup
223
+
224
+ ### Reply Keyboards
225
+
226
+ ```ruby
227
+ keyboard = Telegem.keyboard do
228
+ row "Button 1", "Button 2"
229
+ row "Button 3"
230
+ end.resize.one_time
231
+
232
+ ctx.reply("Choose:", reply_markup: keyboard)
233
+ ```
234
+
235
+ ### Inline Keyboards
236
+
237
+ ```ruby
238
+ inline = Telegem.inline do
239
+ row callback("Yes", "yes"), callback("No", "no")
240
+ row url("Visit", "https://example.com")
241
+ end
242
+
243
+ ctx.reply("Confirm?", reply_markup: inline)
244
+ ```
245
+
246
+ ### Removing Keyboards
247
+
248
+ ```ruby
249
+ ctx.remove_keyboard
250
+ ctx.remove_keyboard("Done!")
251
+ ctx.remove_keyboard(selective: true)
252
+ ```
253
+
254
+ ## Message Editing
255
+
256
+ ```ruby
257
+ ctx.edit_message_text("New text")
258
+ ctx.edit_message_text("New text", message_id: 123)
259
+ ctx.edit_message_caption("New caption")
260
+ ctx.edit_message_reply_markup(new_keyboard)
261
+ ```
262
+
263
+ ## Message Deletion
264
+
265
+ ```ruby
266
+ ctx.delete_message # Delete current message
267
+ ctx.delete_message(123) # Delete specific message
268
+ ```
269
+
270
+ ## Callback Query Responses
271
+
272
+ ```ruby
273
+ ctx.answer_callback_query("Done!")
274
+ ctx.answer_callback_query("Error!", show_alert: true)
275
+ ctx.answer_callback_query(url: "https://example.com")
276
+ ```
277
+
278
+ ## Inline Query Responses
279
+
280
+ ```ruby
281
+ results = [
282
+ Telegem::Types::InlineQueryResultArticle.new(
283
+ id: "1",
284
+ title: "Article",
285
+ input_message_content: { message_text: "Content" }
286
+ )
287
+ ]
288
+
289
+ ctx.answer_inline_query(results)
290
+ ```
291
+
292
+ ## File Operations
293
+
294
+ ```ruby
295
+ # Download files
296
+ ctx.download_file(file_id) # Returns content
297
+ ctx.download_file(file_id, "path/to/file") # Saves to file
298
+
299
+ # Get file info
300
+ file_info = ctx.api.call('getFile', file_id: file_id)
301
+ file_path = file_info['file_path']
302
+ ```
303
+
304
+ ## Chat Management
305
+
306
+ ### Member Management
307
+
308
+ ```ruby
309
+ ctx.kick_chat_member(user_id)
310
+ ctx.ban_chat_member(user_id, until_date: future_time)
311
+ ctx.unban_chat_member(user_id)
312
+ ctx.restrict_chat_member(user_id, permissions: { can_send_messages: false })
313
+ ctx.promote_chat_member(user_id, can_invite_users: true)
314
+ ```
315
+
316
+ ### Chat Information
317
+
318
+ ```ruby
319
+ admins = ctx.get_chat_administrators
320
+ member = ctx.get_chat_member(user_id)
321
+ count = ctx.get_chat_members_count
322
+ chat_info = ctx.get_chat
323
+ ```
324
+
325
+ ### Message Pinning
326
+
327
+ ```ruby
328
+ ctx.pin_message(message_id)
329
+ ctx.unpin_message(message_id)
330
+ ctx.unpin_all_messages
331
+ ```
332
+
333
+ ## Forwarding and Copying
334
+
335
+ ```ruby
336
+ ctx.forward_message(from_chat_id, message_id)
337
+ ctx.copy_message(from_chat_id, message_id, caption: "New caption")
338
+ ```
339
+
340
+ ## Scene Management
341
+
342
+ ```ruby
343
+ ctx.enter_scene(:scene_name)
344
+ ctx.leave_scene
345
+ ctx.leave_scene(reason: :completed)
346
+ ctx.in_scene?
347
+ ctx.current_scene
348
+ ctx.scene_data
349
+ ctx.ask("Question?")
350
+ ctx.next_step
351
+ ctx.next_step(:specific_step)
352
+ ```
353
+
354
+ ## Session Management
355
+
356
+ ```ruby
357
+ # Store data
358
+ ctx.session[:user_data] = "value"
359
+ ctx.session[:preferences] = { theme: "dark" }
360
+
361
+ # Retrieve data
362
+ data = ctx.session[:user_data]
363
+ prefs = ctx.session[:preferences]
364
+
365
+ # Modify data
366
+ ctx.session[:counter] ||= 0
367
+ ctx.session[:counter] += 1
368
+
369
+ # Clean up
370
+ ctx.session.delete(:temp_key)
371
+ ctx.session.clear
372
+ ```
373
+
374
+ ## Polls
375
+
376
+ ```ruby
377
+ ctx.send_poll("Question?", ["Option 1", "Option 2"])
378
+ ctx.stop_poll(message_id)
379
+ ```
380
+
381
+ ## Web Apps
382
+
383
+ ```ruby
384
+ ctx.web_app_data # Data from web app interactions
385
+ ```
386
+
387
+ ## Advanced Usage
388
+
389
+ ### Conditional Responses
390
+
391
+ ```ruby
392
+ if ctx.chat.private?
393
+ ctx.reply("This is private")
394
+ elsif ctx.chat.group?
395
+ ctx.reply("This is a group", reply_to_message_id: ctx.message_id)
396
+ end
397
+ ```
398
+
399
+ ### Error Handling in Handlers
400
+
401
+ ```ruby
402
+ bot.command('process') do |ctx|
403
+ begin
404
+ # Process something risky
405
+ result = process_data(ctx.text)
406
+ ctx.reply("Result: #{result}")
407
+ rescue => e
408
+ ctx.logger.error("Processing error: #{e.message}")
409
+ ctx.reply("Sorry, processing failed. Try again.")
410
+ end
411
+ end
412
+ ```
413
+
414
+ ### Complex Keyboard Building
415
+
416
+ ```ruby
417
+ keyboard = Telegem.keyboard do
418
+ row "📅 Today", "📅 Tomorrow"
419
+ row "⚙️ Settings", "❓ Help"
420
+ request_location "📍 Location"
421
+ request_contact "📞 Contact"
422
+ end.resize.selective
423
+
424
+ ctx.reply("What would you like to do?", reply_markup: keyboard)
425
+ ```
426
+
427
+ ### Session-Based Personalization
428
+
429
+ ```ruby
430
+ bot.command('start') do |ctx|
431
+ ctx.session[:name] ||= ctx.from.first_name
432
+ ctx.session[:visit_count] ||= 0
433
+ ctx.session[:visit_count] += 1
434
+
435
+ greeting = if ctx.session[:visit_count] == 1
436
+ "Welcome, #{ctx.session[:name]}!"
437
+ else
438
+ "Welcome back, #{ctx.session[:name]}! (Visit ##{ctx.session[:visit_count]})"
439
+ end
440
+
441
+ ctx.reply(greeting)
442
+ end
443
+ ```
444
+
445
+ ## Edge Cases and Error Handling
446
+
447
+ ### Missing Data
448
+
449
+ ```ruby
450
+ # Handle missing user
451
+ if ctx.from
452
+ ctx.reply("Hello #{ctx.from.first_name}")
453
+ else
454
+ ctx.reply("Hello anonymous user")
455
+ end
456
+
457
+ # Handle missing message text
458
+ text = ctx.text || "no text"
459
+ ctx.reply("You said: #{text}")
460
+ ```
461
+
462
+ ### Media Validation
463
+
464
+ ```ruby
465
+ bot.on(:message) do |ctx|
466
+ if ctx.has_media?
467
+ case ctx.media_type
468
+ when :photo
469
+ ctx.reply("Nice photo!")
470
+ when :document
471
+ if ctx.message.document.mime_type&.start_with?('application/pdf')
472
+ ctx.reply("PDF received")
473
+ else
474
+ ctx.reply("Unsupported document type")
475
+ end
476
+ else
477
+ ctx.reply("Unsupported media type")
478
+ end
479
+ end
480
+ end
481
+ ```
482
+
483
+ ### Rate Limiting
484
+
485
+ ```ruby
486
+ bot.use do |ctx, next_middleware|
487
+ user_id = ctx.from&.id
488
+ if user_id
489
+ # Implement rate limiting logic
490
+ # ...
491
+ end
492
+ next_middleware.call(ctx)
493
+ end
494
+ ```
495
+
496
+ ### Large Messages
497
+
498
+ Telegram has limits:
499
+ - Text messages: 4096 characters
500
+ - Captions: 1024 characters
501
+ - Handle truncation:
502
+
503
+ ```ruby
504
+ def truncate_text(text, max_length = 4000)
505
+ if text.length > max_length
506
+ text[0...max_length] + "..."
507
+ else
508
+ text
509
+ end
510
+ end
511
+
512
+ ctx.reply(truncate_text(long_text))
513
+ ```
514
+
515
+ ### File Size Limits
516
+
517
+ ```ruby
518
+ bot.document do |ctx|
519
+ doc = ctx.message.document
520
+ if doc.file_size > 50 * 1024 * 1024 # 50MB
521
+ ctx.reply("File too large (max 50MB)")
522
+ else
523
+ # Process file
524
+ end
525
+ end
526
+ ```
527
+
528
+ ### Timeouts and Async Operations
529
+
530
+ ```ruby
531
+ bot.command('long_process') do |ctx|
532
+ ctx.reply("Processing...")
533
+
534
+ # For long operations, use async
535
+ Async do
536
+ result = long_running_task(ctx.text)
537
+ ctx.reply("Done: #{result}")
538
+ end
539
+ end
540
+ ```
541
+
542
+ ## Best Practices
543
+
544
+ 1. **Always check for nil values** before accessing properties
545
+ 2. **Use convenience methods** when available (ctx.text vs ctx.message&.text)
546
+ 3. **Handle errors gracefully** in handlers
547
+ 4. **Validate user input** before processing
548
+ 5. **Use sessions sparingly** and with TTL
549
+ 6. **Implement rate limiting** for intensive operations
550
+ 7. **Log important actions** for debugging
551
+ 8. **Test with different update types** and edge cases
552
+
553
+ The Context object is your primary interface to Telegram's API. Understanding its properties and methods is essential for building robust bots.</content>
554
+ <parameter name="filePath">/home/slick/telegem/docs/context.md