telegem 3.3.1 → 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.
@@ -0,0 +1,151 @@
1
+ # Getting Started with Telegem
2
+
3
+ This guide will walk you through creating your first Telegram bot with Telegem.
4
+
5
+ ## Prerequisites
6
+
7
+ - Ruby 3.0 or higher
8
+ - A Telegram account
9
+ - Basic knowledge of Ruby
10
+
11
+ ## Step 1: Create a Telegram Bot
12
+
13
+ 1. Open Telegram and search for [@BotFather](https://t.me/botfather)
14
+ 2. Send `/newbot` and follow the instructions
15
+ 3. Save your bot token (something like `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`)
16
+
17
+ ## Step 2: Install Telegem
18
+
19
+ ```bash
20
+ gem install telegem
21
+ ```
22
+
23
+ Or add to your Gemfile:
24
+
25
+ ```ruby
26
+ source 'https://rubygems.org'
27
+
28
+ gem 'telegem'
29
+ ```
30
+
31
+ ## Step 3: Create Your First Bot
32
+
33
+ Create a file called `bot.rb`:
34
+
35
+ ```ruby
36
+ require 'telegem'
37
+
38
+ # Initialize bot with your token
39
+ bot = Telegem.new('YOUR_BOT_TOKEN')
40
+
41
+ # Handle /start command
42
+ bot.command('start') do |ctx|
43
+ ctx.reply("Hello, #{ctx.from.first_name}! 👋")
44
+ end
45
+
46
+ # Handle /help command
47
+ bot.command('help') do |ctx|
48
+ ctx.reply("I'm your friendly Telegem bot! Send /start to begin.")
49
+ end
50
+
51
+ # Handle any text message
52
+ bot.hears(/.+/) do |ctx|
53
+ ctx.reply("You said: #{ctx.message.text}")
54
+ end
55
+
56
+ # Start the bot
57
+ puts "🤖 Bot is running..."
58
+ bot.start_polling
59
+ ```
60
+
61
+ ## Step 4: Run Your Bot
62
+
63
+ ```bash
64
+ ruby bot.rb
65
+ ```
66
+
67
+ ## Step 5: Test Your Bot
68
+
69
+ 1. Open Telegram
70
+ 2. Find your bot by username
71
+ 3. Send `/start` and see the response
72
+
73
+ ## Understanding the Code
74
+
75
+ ### Bot Initialization
76
+
77
+ ```ruby
78
+ bot = Telegem.new('YOUR_BOT_TOKEN')
79
+ ```
80
+
81
+ This creates a new bot instance with your token.
82
+
83
+ ### Command Handlers
84
+
85
+ ```ruby
86
+ bot.command('start') do |ctx|
87
+ # Handle /start command
88
+ end
89
+ ```
90
+
91
+ Commands are messages starting with `/`. The `ctx` object contains information about the update.
92
+
93
+ ### Text Message Handlers
94
+
95
+ ```ruby
96
+ bot.hears(/.+/) do |ctx|
97
+ # Handle any text message
98
+ end
99
+ ```
100
+
101
+ `hears` matches messages using regular expressions.
102
+
103
+ ### Context Object
104
+
105
+ The `ctx` (context) object provides access to:
106
+
107
+ - `ctx.message` - The message object
108
+ - `ctx.from` - The user who sent the message
109
+ - `ctx.chat` - The chat where the message was sent
110
+ - `ctx.reply(text)` - Send a reply
111
+
112
+ ## Next Steps
113
+
114
+ - Learn about [handlers](handlers.md) for more routing options
115
+ - Explore [middleware](middleware.md) for request processing
116
+ - Check out [scenes](scenes.md) for multi-step conversations
117
+ - See [examples](examples.md) for more complex bots
118
+
119
+ ## Common Issues
120
+
121
+ ### "Bot token is invalid"
122
+
123
+ - Double-check your token from @BotFather
124
+ - Make sure there are no extra spaces
125
+
126
+ ### "Connection refused"
127
+
128
+ - Check your internet connection
129
+ - Verify the bot token is correct
130
+
131
+ ### Bot doesn't respond
132
+
133
+ - Make sure the bot is running (`ruby bot.rb`)
134
+ - Check that you've started a conversation with the bot first
135
+ - Look at the console output for errors
136
+
137
+ ## Development Tips
138
+
139
+ - Use `puts` statements for debugging
140
+ - Check the [API reference](api.md) for available methods
141
+ - Join the [Telegram Bot Community](https://t.me/botcommunity) for help
142
+
143
+ ## Production Deployment
144
+
145
+ For production use, consider:
146
+
147
+ - [Webhook deployment](webhooks.md) instead of polling
148
+ - [Session storage](sessions.md) for user data
149
+ - [Error handling](error_handling.md) for reliability
150
+ - [Rate limiting](middleware.md) for performance</content>
151
+ <parameter name="filePath">/home/slick/telegem/docs/getting_started.md
data/docs/handlers.md ADDED
@@ -0,0 +1,580 @@
1
+ # Handlers and Routing
2
+
3
+ Handlers are functions that process specific types of updates from Telegram. Telegem provides a flexible routing system to match updates to handlers.
4
+
5
+ ## Handler Types
6
+
7
+ ### Command Handlers
8
+
9
+ Commands are messages starting with `/`. They automatically handle bot mentions.
10
+
11
+ ```ruby
12
+ bot.command('start') do |ctx|
13
+ ctx.reply("Welcome!")
14
+ end
15
+
16
+ bot.command('help') do |ctx|
17
+ ctx.reply("Available commands: /start, /help")
18
+ end
19
+
20
+ # Commands with arguments
21
+ bot.command('echo') do |ctx|
22
+ args = ctx.command_args
23
+ ctx.reply(args || "No arguments provided")
24
+ end
25
+ ```
26
+
27
+ Command matching:
28
+ - `/start` matches
29
+ - `/start@mybot` matches (if bot username is @mybot)
30
+ - `start` doesn't match (no slash)
31
+
32
+ ### Text Pattern Handlers
33
+
34
+ Match messages using strings or regular expressions.
35
+
36
+ ```ruby
37
+ # Exact string match
38
+ bot.hears('hello') do |ctx|
39
+ ctx.reply("Hi there!")
40
+ end
41
+
42
+ # Case-insensitive match
43
+ bot.hears(/^hello$/i) do |ctx|
44
+ ctx.reply("Hello to you!")
45
+ end
46
+
47
+ # Any message containing word
48
+ bot.hears(/bot/i) do |ctx|
49
+ ctx.reply("You mentioned bot!")
50
+ end
51
+
52
+ # Catch-all for text messages
53
+ bot.hears(/.+/) do |ctx|
54
+ ctx.reply("You said: #{ctx.message.text}")
55
+ end
56
+ ```
57
+
58
+ ### Update Type Handlers
59
+
60
+ Handle specific update types directly.
61
+
62
+ ```ruby
63
+ # Callback queries (button presses)
64
+ bot.callback_query do |ctx|
65
+ data = ctx.data
66
+ ctx.answer_callback_query("Button pressed: #{data}")
67
+ end
68
+
69
+ # Inline queries (inline search)
70
+ bot.inline_query do |ctx|
71
+ query = ctx.query
72
+ # Return search results
73
+ results = search_results_for(query)
74
+ ctx.answer_inline_query(results)
75
+ end
76
+
77
+ # Poll answers
78
+ bot.poll_answer do |ctx|
79
+ answer = ctx.poll_answer
80
+ # Process poll response
81
+ end
82
+
83
+ # Chat join requests
84
+ bot.chat_join_request do |ctx|
85
+ # Approve or deny join request
86
+ ctx.approve_chat_join_request()
87
+ end
88
+ ```
89
+
90
+ ### Media Handlers
91
+
92
+ Specialized handlers for different media types.
93
+
94
+ ```ruby
95
+ # Photos
96
+ bot.photo do |ctx|
97
+ ctx.reply("Nice photo! 📸")
98
+ end
99
+
100
+ # Documents
101
+ bot.document do |ctx|
102
+ filename = ctx.message.document.file_name
103
+ ctx.reply("Received document: #{filename}")
104
+ end
105
+
106
+ # Audio files
107
+ bot.audio do |ctx|
108
+ title = ctx.message.audio.title
109
+ ctx.reply("Playing: #{title}")
110
+ end
111
+
112
+ # Videos
113
+ bot.video do |ctx|
114
+ ctx.reply("Video received!")
115
+ end
116
+
117
+ # Voice messages
118
+ bot.voice do |ctx|
119
+ duration = ctx.message.voice.duration
120
+ ctx.reply("Voice message (#{duration}s)")
121
+ end
122
+
123
+ # Stickers
124
+ bot.sticker do |ctx|
125
+ emoji = ctx.message.sticker.emoji
126
+ ctx.reply("Sticker: #{emoji}")
127
+ end
128
+
129
+ # Locations
130
+ bot.location do |ctx|
131
+ lat = ctx.message.location.latitude
132
+ lng = ctx.message.location.longitude
133
+ ctx.reply("Location: #{lat}, #{lng}")
134
+ end
135
+
136
+ # Contacts
137
+ bot.contact do |ctx|
138
+ contact = ctx.message.contact
139
+ ctx.reply("Contact: #{contact.first_name}")
140
+ end
141
+ ```
142
+
143
+ ### Generic Handlers
144
+
145
+ Use `on()` for any update type with optional filters.
146
+
147
+ ```ruby
148
+ # Handle all messages
149
+ bot.on(:message) do |ctx|
150
+ puts "Message received"
151
+ end
152
+
153
+ # Messages in private chats only
154
+ bot.on(:message, chat_type: 'private') do |ctx|
155
+ ctx.reply("This is private")
156
+ end
157
+
158
+ # Messages containing specific text
159
+ bot.on(:message, text: /urgent/i) do |ctx|
160
+ ctx.reply("🚨 Urgent message!")
161
+ end
162
+
163
+ # Edited messages
164
+ bot.on(:edited_message) do |ctx|
165
+ ctx.reply("Message edited")
166
+ end
167
+
168
+ # Channel posts
169
+ bot.on(:channel_post) do |ctx|
170
+ # Handle channel posts
171
+ end
172
+ ```
173
+
174
+ ## Handler Priority and Order
175
+
176
+ Handlers are checked in registration order. More specific handlers should be registered first.
177
+
178
+ ```ruby
179
+ # Bad: catch-all first
180
+ bot.hears(/.+/) do |ctx|
181
+ ctx.reply("Catch-all")
182
+ end
183
+
184
+ bot.command('start') do |ctx| # Never reached
185
+ ctx.reply("Start")
186
+ end
187
+
188
+ # Good: specific first
189
+ bot.command('start') do |ctx|
190
+ ctx.reply("Start")
191
+ end
192
+
193
+ bot.hears(/.+/) do |ctx|
194
+ ctx.reply("Catch-all")
195
+ end
196
+ ```
197
+
198
+ ## Filters
199
+
200
+ Use filters to match specific conditions.
201
+
202
+ ### Chat Type Filters
203
+
204
+ ```ruby
205
+ bot.on(:message, chat_type: 'private') do |ctx|
206
+ # Private messages only
207
+ end
208
+
209
+ bot.on(:message, chat_type: 'group') do |ctx|
210
+ # Group messages only
211
+ end
212
+
213
+ bot.on(:message, chat_type: 'supergroup') do |ctx|
214
+ # Supergroup messages only
215
+ end
216
+ ```
217
+
218
+ ### User Filters
219
+
220
+ ```ruby
221
+ # Messages from specific user
222
+ bot.on(:message, user_id: 123456) do |ctx|
223
+ ctx.reply("Hello admin!")
224
+ end
225
+
226
+ # Messages from bots
227
+ bot.on(:message, is_bot: true) do |ctx|
228
+ ctx.reply("Bot detected")
229
+ end
230
+ ```
231
+
232
+ ### Content Filters
233
+
234
+ ```ruby
235
+ # Messages with photos
236
+ bot.on(:message, has_photo: true) do |ctx|
237
+ ctx.reply("Photo received")
238
+ end
239
+
240
+ # Messages with documents
241
+ bot.on(:message, has_document: true) do |ctx|
242
+ ctx.reply("Document received")
243
+ end
244
+
245
+ # Forwarded messages
246
+ bot.on(:message, forwarded: true) do |ctx|
247
+ ctx.reply("Forwarded message")
248
+ end
249
+
250
+ # Reply messages
251
+ bot.on(:message, reply: true) do |ctx|
252
+ ctx.reply("This is a reply")
253
+ end
254
+ ```
255
+
256
+ ### Custom Filters
257
+
258
+ ```ruby
259
+ # Custom filter function
260
+ bot.on(:message, ->(ctx) { ctx.from&.username == 'admin' }) do |ctx|
261
+ ctx.reply("Admin command")
262
+ end
263
+
264
+ # Multiple conditions
265
+ bot.on(:message, chat_type: 'group', text: /admin/i) do |ctx|
266
+ # Admin commands in groups
267
+ end
268
+ ```
269
+
270
+ ## Handler Context
271
+
272
+ ### Match Data
273
+
274
+ For regex handlers, match data is available.
275
+
276
+ ```ruby
277
+ bot.hears(/hello (\w+)/) do |ctx|
278
+ name = ctx.match[1] # Captured group
279
+ ctx.reply("Hello #{name}!")
280
+ end
281
+
282
+ bot.hears(/^\/greet (\w+) (\w+)/) do |ctx|
283
+ first_name = ctx.match[1]
284
+ last_name = ctx.match[2]
285
+ ctx.reply("Greetings #{first_name} #{last_name}!")
286
+ end
287
+ ```
288
+
289
+ ### State and Session
290
+
291
+ Handlers have access to state and session.
292
+
293
+ ```ruby
294
+ bot.hears(/set name (.+)/) do |ctx|
295
+ name = ctx.match[1]
296
+ ctx.session[:name] = name
297
+ ctx.reply("Name set to #{name}")
298
+ end
299
+
300
+ bot.hears('my name') do |ctx|
301
+ name = ctx.session[:name] || 'unknown'
302
+ ctx.reply("Your name is #{name}")
303
+ end
304
+ ```
305
+
306
+ ## Dynamic Handlers
307
+
308
+ Register handlers at runtime.
309
+
310
+ ```ruby
311
+ # Add command dynamically
312
+ bot.command('dynamic') do |ctx|
313
+ ctx.reply("Dynamic command!")
314
+ end
315
+
316
+ # Conditional handlers
317
+ if ENV['ADMIN_MODE']
318
+ bot.command('admin') do |ctx|
319
+ # Admin commands
320
+ end
321
+ end
322
+
323
+ # Handler factories
324
+ def create_counter_handler(name)
325
+ bot.command(name) do |ctx|
326
+ ctx.session[name] ||= 0
327
+ ctx.session[name] += 1
328
+ ctx.reply("#{name}: #{ctx.session[name]}")
329
+ end
330
+ end
331
+
332
+ create_counter_handler('count1')
333
+ create_counter_handler('count2')
334
+ ```
335
+
336
+ ## Handler Removal
337
+
338
+ Handlers cannot be removed individually. To change handlers:
339
+
340
+ 1. Create a new bot instance
341
+ 2. Use conditional registration
342
+ 3. Use middleware to filter
343
+
344
+ ```ruby
345
+ # Conditional handler
346
+ bot.use do |ctx, next_middleware|
347
+ if should_skip_handler?(ctx)
348
+ return # Skip handler
349
+ end
350
+ next_middleware.call(ctx)
351
+ end
352
+
353
+ bot.command('conditional') do |ctx|
354
+ # Only reached if middleware allows
355
+ end
356
+ ```
357
+
358
+ ## Error Handling in Handlers
359
+
360
+ ```ruby
361
+ bot.command('risky') do |ctx|
362
+ begin
363
+ risky_operation(ctx.text)
364
+ ctx.reply("Success!")
365
+ rescue => e
366
+ ctx.logger.error("Handler error: #{e.message}")
367
+ ctx.reply("Something went wrong")
368
+ end
369
+ end
370
+ ```
371
+
372
+ ## Async Handlers
373
+
374
+ For long-running operations, use async.
375
+
376
+ ```ruby
377
+ bot.command('long_task') do |ctx|
378
+ ctx.reply("Processing...")
379
+
380
+ Async do
381
+ result = long_running_operation()
382
+ ctx.reply("Done: #{result}")
383
+ end
384
+ end
385
+ ```
386
+
387
+ ## Handler Best Practices
388
+
389
+ ### 1. Keep Handlers Small
390
+
391
+ ```ruby
392
+ # Bad
393
+ bot.command('process') do |ctx|
394
+ # 50 lines of processing code
395
+ end
396
+
397
+ # Good
398
+ bot.command('process') do |ctx|
399
+ result = process_data(ctx.text)
400
+ ctx.reply(result)
401
+ end
402
+ ```
403
+
404
+ ### 2. Use Appropriate Handler Types
405
+
406
+ ```ruby
407
+ # Use command for commands
408
+ bot.command('start')
409
+
410
+ # Use hears for text patterns
411
+ bot.hears(/hello/)
412
+
413
+ # Use on() for complex conditions
414
+ bot.on(:message, chat_type: 'private', has_photo: true)
415
+ ```
416
+
417
+ ### 3. Validate Input
418
+
419
+ ```ruby
420
+ bot.command('calculate') do |ctx|
421
+ number = ctx.command_args&.to_i
422
+ if number.nil? || number < 0
423
+ ctx.reply("Please provide a positive number")
424
+ return
425
+ end
426
+
427
+ result = calculate(number)
428
+ ctx.reply("Result: #{result}")
429
+ end
430
+ ```
431
+
432
+ ### 4. Handle Edge Cases
433
+
434
+ ```ruby
435
+ bot.photo do |ctx|
436
+ unless ctx.message.photo&.any?
437
+ ctx.reply("No photo found")
438
+ return
439
+ end
440
+
441
+ # Process photo
442
+ end
443
+ ```
444
+
445
+ ### 5. Use Sessions for State
446
+
447
+ ```ruby
448
+ bot.hears('start quiz') do |ctx|
449
+ ctx.session[:quiz_active] = true
450
+ ctx.session[:question] = 1
451
+ ctx.reply("Quiz started! Question 1...")
452
+ end
453
+
454
+ bot.hears(/.+/) do |ctx|
455
+ if ctx.session[:quiz_active]
456
+ # Handle quiz answer
457
+ end
458
+ end
459
+ ```
460
+
461
+ ### 6. Log Important Actions
462
+
463
+ ```ruby
464
+ bot.command('delete') do |ctx|
465
+ ctx.logger.info("User #{ctx.from.id} deleting data")
466
+ delete_user_data(ctx.from.id)
467
+ ctx.reply("Data deleted")
468
+ end
469
+ ```
470
+
471
+ ## Common Patterns
472
+
473
+ ### Menu Systems
474
+
475
+ ```ruby
476
+ bot.command('menu') do |ctx|
477
+ keyboard = Telegem.keyboard do
478
+ row "📊 Stats", "⚙️ Settings"
479
+ row "❓ Help", "🚪 Exit"
480
+ end
481
+
482
+ ctx.reply("Choose option:", reply_markup: keyboard)
483
+ end
484
+
485
+ bot.hears('Stats') do |ctx|
486
+ stats = get_user_stats(ctx.from.id)
487
+ ctx.reply("Your stats: #{stats}")
488
+ end
489
+ ```
490
+
491
+ ### Admin Commands
492
+
493
+ ```ruby
494
+ ADMIN_IDS = [123456, 789012]
495
+
496
+ bot.command('admin') do |ctx|
497
+ unless ADMIN_IDS.include?(ctx.from.id)
498
+ ctx.reply("Access denied")
499
+ return
500
+ end
501
+
502
+ # Admin functionality
503
+ ctx.reply("Admin panel")
504
+ end
505
+ ```
506
+
507
+ ### Rate Limiting
508
+
509
+ ```ruby
510
+ bot.use do |ctx, next_middleware|
511
+ user_id = ctx.from&.id
512
+ if user_id
513
+ key = "rate_limit:#{user_id}"
514
+ count = ctx.session[key] ||= 0
515
+
516
+ if count > 10
517
+ ctx.reply("Too many requests")
518
+ return
519
+ end
520
+
521
+ ctx.session[key] = count + 1
522
+ end
523
+
524
+ next_middleware.call(ctx)
525
+ end
526
+ ```
527
+
528
+ ### Command Aliases
529
+
530
+ ```ruby
531
+ ['start', 'begin', 'hello'].each do |cmd|
532
+ bot.command(cmd) do |ctx|
533
+ ctx.reply("Welcome!")
534
+ end
535
+ end
536
+ ```
537
+
538
+ ### Fallback Handlers
539
+
540
+ ```ruby
541
+ # Handle unknown commands
542
+ bot.on(:message, ->(ctx) { ctx.message&.text&.start_with?('/') }) do |ctx|
543
+ ctx.reply("Unknown command. Try /help")
544
+ end
545
+
546
+ # Handle non-text messages
547
+ bot.on(:message) do |ctx|
548
+ unless ctx.message&.text
549
+ ctx.reply("I only understand text messages")
550
+ end
551
+ end
552
+ ```
553
+
554
+ ## Testing Handlers
555
+
556
+ ```ruby
557
+ # Test helper
558
+ def simulate_message(bot, text, from_id: 123)
559
+ update = Telegem::Types::Update.new({
560
+ update_id: 1,
561
+ message: {
562
+ message_id: 1,
563
+ from: { id: from_id, first_name: 'Test' },
564
+ chat: { id: from_id, type: 'private' },
565
+ date: Time.now.to_i,
566
+ text: text
567
+ }
568
+ })
569
+
570
+ ctx = Telegem::Core::Context.new(update, bot)
571
+ bot.process_update(update)
572
+ end
573
+
574
+ # Usage
575
+ simulate_message(bot, '/start')
576
+ simulate_message(bot, 'hello world')
577
+ ```
578
+
579
+ Understanding handlers is crucial for building interactive bots. Choose the right handler type and use filters to create precise routing logic.</content>
580
+ <parameter name="filePath">/home/slick/telegem/docs/handlers.md