telegem 1.0.4 → 1.0.5

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: 30803f9ebb55570bae838e9db45dd199763fe54878341d5fed9c32cc204b169c
4
- data.tar.gz: 1e87a27402e8b205d2fefc1fb1ac85aa161a7138166391d5d7cd9804188215d7
3
+ metadata.gz: 962341055439e51fd1eafe1d15cffffb8d3c7b752f962e66cc16394e3950ae68
4
+ data.tar.gz: 8dcf816cf6311a294668100ad7cdc4f12e5127fd1b6fd592842c8514e2962177
5
5
  SHA512:
6
- metadata.gz: 57ddfbe1edd755e30be1e854fda4c390ea25b3976655de59f0b5e6befa5e2ace3ed135aa463a7b897a179f12f40c10d644e877baf8f4966a7deac99de7ec6d85
7
- data.tar.gz: d3aaab61e1faddc352f8702f7c85c5d7db5ef28a72c2ce70c73b08202b7245429deb9ed2b167f9bfb467172fcd69215ea3ede5907c84b090837f8cad13339536
6
+ metadata.gz: 8e02edba543e2bf5939a008f192c8149b1be2f28e949dee12956fa4d7f0dd7e0466f429c9a7fc16d26839e05adac0f182755fd2778e483489d057a7d2ab192ab
7
+ data.tar.gz: 155c9426032522dd6f604d1e7e9235c3a4ab2052a2d0c5bc03164cfc4b70f00341914352c69ffa9d0c73ff6ea66ce7ee7d5269ec79b70ede7b97fe831d53f262
data/Readme.md CHANGED
@@ -10,15 +10,15 @@ Blazing-fast, modern Telegram Bot framework for Ruby. Inspired by Telegraf.js, b
10
10
 
11
11
  ✨ Features
12
12
 
13
- · ⚡ True Async I/O - Built on async gem, not blocking threads
14
- · 🎯 Telegraf-style DSL - Familiar API for JavaScript developers
15
- · 🔌 Middleware System - Compose behavior like Express.js
16
- · 🧙 Scene System - Multi-step conversations (wizards/forms)
17
- · 💾 Session Management - Redis, memory, or custom stores
18
- · ⌨️ Keyboard DSL - Clean markup builders with fluent API
19
- · 🌐 Webhook Server - Production-ready async HTTP server
20
- · 🏗️ Type-Safe Objects - Ruby classes for all Telegram types
21
- · 📦 Minimal Dependencies - Just async gems + mime-types
13
+ - ⚡ True httpx(Async) I/O - Built on async gem, not blocking threads
14
+ - 🎯 Telegraf-style DSL - Familiar API for JavaScript developers
15
+ - 🔌 Middleware System - Compose behavior like Express.js
16
+ - 🧙 Scene System - Multi-step conversations (wizards/forms)
17
+ - 💾 Session Management - Redis, memory, or custom stores
18
+ - ⌨️ Keyboard DSL - Clean markup builders with fluent API
19
+ - 🌐 Webhook Server - Production-ready async HTTP server
20
+ - 🏗️ Type-Safe Objects - Ruby classes for all Telegram types
21
+ - 📦 Minimal Dependencies - Just async gems + mime-types
22
22
 
23
23
  ---
24
24
 
@@ -87,13 +87,14 @@ Example bot with interactive keyboard and scene-based ordering flow
87
87
 
88
88
  vs. Other Ruby Telegram Libraries
89
89
 
90
- Feature Telegem telegram-bot-ruby Others
91
- Async Architecture True async/await ❌ Thread-based ❌ Blocking
92
- Middleware System ✅ Express.js-style ❌ Limited ❌ None
93
- Scene Management Built-in ❌ Manual ❌ None
94
- Session Stores Multiple Basic ❌ None
95
- Modern DSL Clean & fluent ❌ Verbose ⚠️ Varies
96
- Performance Non-blocking ⚠️ OK ❌ Poor
90
+ | Telegem | telegram-bot-ruby |
91
+ | ------ | ------ |
92
+ | fast async | multiple thread |
93
+ | non blocking request | slow thread based |
94
+ | clean telegraf dsl | no dsl |
95
+ | scene management. | verbose |
96
+ | middleware | raw json |
97
+ | clean markup dsl|. |
97
98
 
98
99
  Perfect For:
99
100
 
@@ -194,8 +195,7 @@ server = bot.webhook_server(
194
195
  )
195
196
 
196
197
  # Set webhook automatically
197
- Async do
198
- await bot.set_webhook(
198
+ bot.set_webhook(
199
199
  url: "https://#{ENV['DOMAIN']}/webhook/#{bot.token}",
200
200
  max_connections: 40
201
201
  )
@@ -302,7 +302,7 @@ Coming Soon
302
302
 
303
303
  In Progress
304
304
 
305
- - Async Core - Non-blocking I/O
305
+ - httpx(Async) - Non-blocking I/O
306
306
  - Scene System - Multi-step conversations
307
307
  - Middleware Pipeline - Extensible architecture
308
308
  - Webhook Server - Production deployment
@@ -0,0 +1,241 @@
1
+ 📡 Setting Up Webhooks - Complete Beginner's Guide
2
+
3
+ Webhooks sound complicated, but they're actually simple. Let me explain with an analogy:
4
+
5
+ 🍕 The Pizza Delivery Analogy
6
+
7
+ Polling (The Old Way)
8
+
9
+ You call the pizza shop every minute: "Is my pizza ready yet? No? OK, I'll call again in a minute..."
10
+
11
+ Code: bot.start_polling() - Your bot calls Telegram every second asking for new messages.
12
+
13
+ Webhooks (The Smart Way)
14
+
15
+ You give the pizza shop your address. When pizza is ready, they deliver it to you.
16
+
17
+ Code: bot.set_webhook(url) - You give Telegram your server's address. When there's a message, they send it to you.
18
+
19
+ 🚀 Quick Examples
20
+
21
+ Example 1: Polling (Easiest for Beginners)
22
+
23
+ ```ruby
24
+ require 'telegem'
25
+
26
+ bot = Telegem.new('YOUR_TOKEN')
27
+
28
+ bot.command('start') do |ctx|
29
+ ctx.reply("Hello! I'm using polling 🍕")
30
+ end
31
+
32
+ # Just ONE line - that's it!
33
+ bot.start_polling
34
+ ```
35
+
36
+ Run it:
37
+
38
+ ```bash
39
+ ruby bot.rb
40
+ # Bot starts checking for messages every second
41
+ ```
42
+
43
+ Example 2: Webhook (For Production)
44
+
45
+ ```ruby
46
+ require 'telegem'
47
+
48
+ bot = Telegem.new('YOUR_TOKEN')
49
+
50
+ bot.command('start') do |ctx|
51
+ ctx.reply("Hello! I'm using webhooks 🚚")
52
+ end
53
+
54
+ # Step 1: Start your "delivery address" (server)
55
+ server = bot.webhook(port: 3000)
56
+ server.run
57
+
58
+ # Step 2: Tell Telegram your address
59
+ bot.set_webhook!("https://your-domain.com/webhook/#{bot.token}")
60
+ ```
61
+
62
+ Run it:
63
+
64
+ ```bash
65
+ ruby bot.rb
66
+ # Bot waits for Telegram to deliver messages
67
+ ```
68
+
69
+ 🔄 Hot-Swap Between Polling & Webhooks
70
+
71
+ Here's how to switch while your bot is running:
72
+
73
+ ```ruby
74
+ require 'telegem'
75
+
76
+ bot = Telegem.new('YOUR_TOKEN')
77
+
78
+ bot.command('mode') do |ctx|
79
+ ctx.reply("Use /polling or /webhook to switch modes")
80
+ end
81
+
82
+ bot.command('polling') do |ctx|
83
+ # Switch TO polling
84
+ bot.shutdown # Stop current mode
85
+ bot.start_polling # Start polling
86
+ ctx.reply("✅ Switched to polling mode")
87
+ end
88
+
89
+ bot.command('webhook') do |ctx|
90
+ # Switch TO webhook
91
+ bot.shutdown # Stop current mode
92
+
93
+ server = bot.webhook(port: 3000)
94
+ server.run
95
+
96
+ # For demo, use ngrok URL (get yours at ngrok.com)
97
+ bot.set_webhook!("https://abc123.ngrok.io/webhook/#{bot.token}")
98
+
99
+ ctx.reply("✅ Switched to webhook mode")
100
+ end
101
+
102
+ # Start with polling by default
103
+ bot.start_polling
104
+ ```
105
+
106
+ 📊 Polling vs Webhooks: Side-by-Side Comparison
107
+
108
+ |Polling 🍕| Webhooks 🚚 |
109
+ | ------- | ------- |
110
+ | Bot asks Telegram: "New messages?" | Telegram sends messages to bot |
111
+ | Setup bot.start_polling() | Server + set_webhook() |
112
+ | Best for Development, testing | Production, high traffic |
113
+ | Speed Up to 1-second delay | Instant delivery |
114
+ | SSL Required? ❌ No | ✅ Yes (Telegram requires HTTPS) |
115
+ | Server Needed? ❌ No | ✅ Yes |
116
+ | Battery/CPU ⚠️ Uses more (always checking) | ✅ Efficient (sleeps until delivery) |
117
+ | Can Switch? ✅ Yes (hot-swap) | ✅ Yes (hot-swap) |
118
+
119
+ 🎯 When to Use Which?
120
+
121
+ Use Polling When:
122
+
123
+ · 👶 You're learning - Keep it simple
124
+ · 💻 Developing locally - No server setup needed
125
+ · 🧪 Testing new features - Quick restarts
126
+ · 📱 Running on your laptop - No public URL needed
127
+
128
+ Use Webhooks When:
129
+
130
+ · 🚀 Going to production - Better performance
131
+ · 📈 Expecting many users - Handles traffic better
132
+ · ☁️ Hosting on a server - You have a public URL
133
+ · 🔋 Saving resources - Uses less CPU/battery
134
+
135
+ 🔧 Webhook Setup for Beginners
136
+
137
+ Step 1: Get a Public URL (Development)
138
+
139
+ For development, use ngrok (free):
140
+
141
+ ```bash
142
+ # Install ngrok, then run:
143
+ ngrok http 3000
144
+ ```
145
+
146
+ You'll get a URL like: https://abc123.ngrok.io
147
+
148
+ Step 2: Simple Webhook Bot
149
+
150
+ ```ruby
151
+ # webhook_bot.rb
152
+ require 'telegem'
153
+
154
+ bot = Telegem.new('YOUR_TOKEN')
155
+
156
+ bot.command('start') do |ctx|
157
+ ctx.reply("I'm using webhooks! Try /info")
158
+ end
159
+
160
+ bot.command('info') do |ctx|
161
+ info = bot.get_webhook_info!
162
+ ctx.reply("Webhook info: #{info}")
163
+ end
164
+
165
+ # Start server
166
+ server = bot.webhook(port: 3000)
167
+ server.run
168
+
169
+ puts "🚀 Server running! Set webhook to:"
170
+ puts "https://YOUR_NGROK_URL.ngrok.io/webhook/#{bot.token}"
171
+ puts ""
172
+ puts "Run this command to set webhook:"
173
+ puts "bot.set_webhook!('https://YOUR_NGROK_URL.ngrok.io/webhook/#{bot.token}')"
174
+ ```
175
+
176
+ Step 3: Set the Webhook
177
+
178
+ Open IRB in another terminal:
179
+
180
+ ```ruby
181
+ require 'telegem'
182
+ bot = Telegem.new('YOUR_TOKEN')
183
+ bot.set_webhook!('https://abc123.ngrok.io/webhook/YOUR_TOKEN')
184
+ # => true (means success!)
185
+ ```
186
+
187
+ ❓ Common Questions
188
+
189
+ "Do I need to keep my computer on?"
190
+
191
+ · Polling: ❌ Yes, bot must keep asking
192
+ · Webhook: ✅ No, your SERVER needs to be on
193
+
194
+ "Can I use webhook without a server?"
195
+
196
+ No, you need somewhere for Telegram to deliver messages. But many free options:
197
+
198
+ · Railway (free tier) - railway.app
199
+ · Render (free tier) - render.com
200
+ · Heroku (free tier) - heroku.com
201
+
202
+ "Which is faster?"
203
+
204
+ Webhooks! Messages arrive instantly instead of up to 1-second delay.
205
+
206
+ 🎮 Try It Yourself Exercise
207
+
208
+ Create mode_demo.rb:
209
+
210
+ ```ruby
211
+ require 'telegem'
212
+
213
+ bot = Telegem.new('YOUR_TOKEN')
214
+
215
+ bot.command('help') do |ctx|
216
+ ctx.reply(<<~TEXT
217
+ 🤖 Mode Demo Bot
218
+
219
+ /polling - Switch to polling mode
220
+ /webhook - Switch to webhook mode
221
+ /current - Show current mode
222
+ /test - Send test message
223
+ TEXT
224
+ )
225
+ end
226
+
227
+ # Start in polling mode (easiest)
228
+ bot.start_polling
229
+ puts "Bot started in polling mode. Try /help"
230
+ ```
231
+
232
+ Run it and try switching modes while the bot is running!
233
+
234
+ 📚 Remember This:
235
+
236
+ · Start with polling - It's easier
237
+ · Switch to webhooks when going to production
238
+ · You can always switch back - It's not permanent
239
+ · Your bot code stays the same - Only the delivery method changes
240
+
241
+ Happy bot building! 🎉
@@ -0,0 +1,434 @@
1
+ 🧠 Telegem Scenes: The Complete Guide (Without the Confusion)
2
+
3
+ Scenes are conversation flows in Telegem. They handle back-and-forth interactions like forms, surveys, or onboarding. Let's remove all confusion.
4
+
5
+ 📖 The Two-Step Dance: Define vs. Start
6
+
7
+ Scenes work in two distinct phases:
8
+
9
+ ```ruby
10
+ # PHASE 1: DEFINE (Write the script)
11
+ bot.scene :registration do
12
+ step :ask_name { |ctx| ctx.reply "What's your name?" }
13
+ step :ask_email { |ctx| ctx.reply "What's your email?" }
14
+ end
15
+
16
+ # PHASE 2: START (Run the script)
17
+ bot.command('register') do |ctx|
18
+ ctx.enter_scene(:registration) # This actually begins the scene
19
+ end
20
+ ```
21
+
22
+ 🎯 The Analogy That Makes Sense
23
+
24
+ · bot.scene = Writing a movie script
25
+ · ctx.enter_scene = Yelling "Action!" on set
26
+ · The scene steps = What the actors actually do
27
+
28
+ 🔧 The Complete Working Template
29
+
30
+ ```ruby
31
+ require 'telegem'
32
+
33
+ bot = Telegem.new('YOUR_BOT_TOKEN')
34
+
35
+ # =============== DEFINE THE SCENE ===============
36
+ bot.scene :feedback do
37
+ # Optional: Runs when scene starts
38
+ on_enter do |ctx|
39
+ ctx.session[:feedback] = { user_id: ctx.from.id }
40
+ ctx.reply "📝 Let's collect your feedback!"
41
+ end
42
+
43
+ # Step 1: Ask for rating
44
+ step :ask_rating do |ctx|
45
+ keyboard = Telegem::Markup.inline do
46
+ row callback("⭐️ 1", "rating_1"), callback("⭐️ 2", "rating_2")
47
+ row callback("⭐️ 3", "rating_3"), callback("⭐️ 4", "rating_4"), callback("⭐️ 5", "rating_5")
48
+ end
49
+ ctx.reply "How would you rate us? (1-5 stars)", reply_markup: keyboard
50
+ end
51
+
52
+ # Step 2: Handle rating choice
53
+ step :handle_rating do |ctx|
54
+ if ctx.data&.start_with?('rating_')
55
+ rating = ctx.data.split('_').last.to_i
56
+ ctx.session[:feedback][:rating] = rating
57
+ ctx.reply "Thanks! Now please share your comments:"
58
+ else
59
+ ctx.reply "Please use the buttons above ⬆️"
60
+ return # Stay on this step
61
+ end
62
+ end
63
+
64
+ # Step 3: Collect comments
65
+ step :collect_comments do |ctx|
66
+ if ctx.message.text
67
+ ctx.session[:feedback][:comments] = ctx.message.text
68
+
69
+ # Show summary
70
+ summary = <<~SUMMARY
71
+ 📋 **Feedback Summary:**
72
+
73
+ Rating: #{ctx.session[:feedback][:rating]} stars
74
+ Comments: #{ctx.session[:feedback][:comments]}
75
+
76
+ Submit? (yes/no)
77
+ SUMMARY
78
+
79
+ ctx.reply summary, parse_mode: 'Markdown'
80
+ end
81
+ end
82
+
83
+ # Step 4: Final confirmation
84
+ step :confirm do |ctx|
85
+ if ctx.message.text&.downcase == 'yes'
86
+ save_feedback(ctx.session[:feedback])
87
+ ctx.reply "✅ Feedback submitted! Thank you."
88
+ else
89
+ ctx.reply "❌ Feedback cancelled."
90
+ end
91
+ ctx.leave_scene
92
+ end
93
+
94
+ # Optional: Runs when scene ends (success or cancel)
95
+ on_leave do |ctx|
96
+ ctx.session.delete(:feedback)
97
+ ctx.reply "Back to main menu!"
98
+ end
99
+ end
100
+
101
+ # =============== START THE SCENE ===============
102
+ bot.command('feedback') do |ctx|
103
+ ctx.enter_scene(:feedback) # THIS actually starts it
104
+ end
105
+
106
+ # Start the bot
107
+ bot.start_polling
108
+ ```
109
+
110
+ 📦 4 Production-Ready Scene Templates
111
+
112
+ Template 1: Simple Form (Beginner Friendly)
113
+
114
+ Perfect for basic data collection.
115
+
116
+ ```ruby
117
+ bot.scene :quick_survey do
118
+ on_enter { |ctx| ctx.reply "Quick 3-question survey:" }
119
+
120
+ step :q1 do |ctx|
121
+ ctx.reply "1. What's your favorite language? (Ruby/JS/Python)"
122
+ end
123
+
124
+ step :q2 do |ctx|
125
+ ctx.session[:lang] = ctx.message.text
126
+ ctx.reply "2. How many years experience?"
127
+ end
128
+
129
+ step :q3 do |ctx|
130
+ ctx.session[:exp] = ctx.message.text
131
+ ctx.reply "3. What's your biggest challenge?"
132
+ end
133
+
134
+ step :finish do |ctx|
135
+ ctx.session[:challenge] = ctx.message.text
136
+ save_survey(ctx.session)
137
+ ctx.reply "✅ Survey complete! Thanks for sharing."
138
+ ctx.leave_scene
139
+ end
140
+ end
141
+
142
+ # Usage: /survey
143
+ bot.command('survey') { |ctx| ctx.enter_scene(:quick_survey) }
144
+ ```
145
+
146
+ Template 2: Menu Navigator (With Branching)
147
+
148
+ For complex flows with different paths.
149
+
150
+ ```ruby
151
+ bot.scene :support_ticket do
152
+ step :ask_type do |ctx|
153
+ keyboard = Telegem::Markup.keyboard do
154
+ row "🐛 Bug Report", "✨ Feature Request"
155
+ row "❓ Question", "🔧 Technical Issue"
156
+ end
157
+ ctx.reply "What type of support do you need?", reply_markup: keyboard
158
+ end
159
+
160
+ step :collect_details do |ctx|
161
+ type = ctx.message.text
162
+ ctx.session[:ticket_type] = type
163
+
164
+ case type
165
+ when "🐛 Bug Report"
166
+ ctx.reply "Describe the bug (steps to reproduce):"
167
+ ctx.session[:next_action] = :save_bug
168
+ when "✨ Feature Request"
169
+ ctx.reply "Describe the feature you'd like:"
170
+ ctx.session[:next_action] = :save_feature
171
+ else
172
+ ctx.reply "Describe your issue:"
173
+ ctx.session[:next_action] = :save_general
174
+ end
175
+ end
176
+
177
+ step :process_ticket do |ctx|
178
+ description = ctx.message.text
179
+ ticket_id = "TICKET-#{SecureRandom.hex(4).upcase}"
180
+
181
+ case ctx.session[:next_action]
182
+ when :save_bug
183
+ save_to_database(type: 'bug', desc: description, id: ticket_id)
184
+ ctx.reply "🐛 Bug logged as #{ticket_id}"
185
+ when :save_feature
186
+ save_to_database(type: 'feature', desc: description, id: ticket_id)
187
+ ctx.reply "✨ Feature requested as #{ticket_id}"
188
+ end
189
+
190
+ ctx.leave_scene
191
+ end
192
+
193
+ on_leave do |ctx|
194
+ ctx.reply "Support will contact you soon. Use /status to check ticket."
195
+ end
196
+ end
197
+
198
+ # Usage: /support
199
+ bot.command('support') { |ctx| ctx.enter_scene(:support_ticket) }
200
+ ```
201
+
202
+ Template 3: Async Data Fetching (Advanced)
203
+
204
+ For scenes that need to fetch external data.
205
+
206
+ ```ruby
207
+ bot.scene :github_analyzer do
208
+ step :ask_repo do |ctx|
209
+ ctx.reply "Enter a GitHub repo URL (e.g., https://github.com/user/repo):"
210
+ end
211
+
212
+ step :fetch_data do |ctx|
213
+ url = ctx.message.text
214
+
215
+ # Show loading
216
+ ctx.reply "⏳ Fetching repo data..."
217
+
218
+ # Async HTTP request
219
+ Async do
220
+ begin
221
+ # Fetch from GitHub API using httpx
222
+ data = await fetch_github_data(url)
223
+
224
+ # Show results
225
+ info = <<~INFO
226
+ 📊 **Repo Analysis:**
227
+
228
+ Name: #{data[:name]}
229
+ Stars: #{data[:stars]}
230
+ Language: #{data[:language]}
231
+ Description: #{data[:description]}
232
+
233
+ Last updated: #{data[:updated_at]}
234
+ INFO
235
+
236
+ ctx.reply info, parse_mode: 'Markdown'
237
+
238
+ rescue => e
239
+ ctx.reply "❌ Error: #{e.message}"
240
+ ensure
241
+ ctx.leave_scene
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ # Usage: /analyze
248
+ bot.command('analyze') { |ctx| ctx.enter_scene(:github_analyzer) }
249
+ ```
250
+
251
+ Template 4: Multi-Step With Validation (Production Ready)
252
+
253
+ Includes proper error handling and validation.
254
+
255
+ ```ruby
256
+ bot.scene :user_registration, timeout: 300 do # 5 minute timeout
257
+ on_enter do |ctx|
258
+ ctx.session[:registration] = {
259
+ started_at: Time.now,
260
+ attempts: 0,
261
+ data: {}
262
+ }
263
+ ctx.reply "👤 Registration Process\n\nLet's get started!"
264
+ end
265
+
266
+ step :ask_email do |ctx|
267
+ ctx.reply "Enter your email address:"
268
+ end
269
+
270
+ step :validate_email do |ctx|
271
+ email = ctx.message.text.strip
272
+
273
+ unless email.include?('@') && email.include?('.')
274
+ ctx.session[:registration][:attempts] += 1
275
+
276
+ if ctx.session[:registration][:attempts] >= 3
277
+ ctx.reply "❌ Too many attempts. Registration cancelled."
278
+ ctx.leave_scene
279
+ return
280
+ end
281
+
282
+ ctx.reply "❌ Invalid email format. Please try again:"
283
+ return # Stay on this step
284
+ end
285
+
286
+ # Email is valid
287
+ ctx.session[:registration][:data][:email] = email
288
+ ctx.session[:registration][:attempts] = 0
289
+ ctx.reply "✅ Email accepted!"
290
+ ctx.reply "Enter your full name:"
291
+ end
292
+
293
+ step :ask_password do |ctx|
294
+ ctx.session[:registration][:data][:name] = ctx.message.text
295
+ ctx.reply "Create a password (min 8 characters):"
296
+ end
297
+
298
+ step :confirm_registration do |ctx|
299
+ password = ctx.message.text
300
+
301
+ if password.length < 8
302
+ ctx.reply "❌ Password too short. Min 8 characters:"
303
+ return
304
+ end
305
+
306
+ ctx.session[:registration][:data][:password] = password
307
+
308
+ # Show summary
309
+ summary = <<~SUMMARY
310
+ 📋 **Registration Summary:**
311
+
312
+ Email: #{ctx.session[:registration][:data][:email]}
313
+ Name: #{ctx.session[:registration][:data][:name]}
314
+
315
+ Confirm registration? (yes/no)
316
+ SUMMARY
317
+
318
+ ctx.reply summary, parse_mode: 'Markdown'
319
+ end
320
+
321
+ step :finalize do |ctx|
322
+ if ctx.message.text&.downcase == 'yes'
323
+ # Save to database
324
+ user_id = create_user(ctx.session[:registration][:data])
325
+ ctx.reply "✅ Registration complete!\nYour ID: #{user_id}"
326
+ else
327
+ ctx.reply "❌ Registration cancelled."
328
+ end
329
+ ctx.leave_scene
330
+ end
331
+
332
+ on_timeout do |ctx|
333
+ ctx.reply "⏰ Registration timed out. Please start over with /register."
334
+ ctx.session.delete(:registration)
335
+ end
336
+
337
+ on_leave do |ctx|
338
+ # Cleanup
339
+ ctx.session.delete(:registration)
340
+ end
341
+ end
342
+
343
+ # Usage: /register
344
+ bot.command('register') { |ctx| ctx.enter_scene(:user_registration) }
345
+ ```
346
+
347
+ 🚀 Common Patterns Cheat Sheet
348
+
349
+ Pattern 1: Basic Form Flow
350
+
351
+ ```ruby
352
+ bot.scene :simple_form
353
+ bot.command('start_form') { |ctx| ctx.enter_scene(:simple_form) }
354
+ ```
355
+
356
+ Pattern 2: Inline Button Navigation
357
+
358
+ ```ruby
359
+ bot.scene :menu_driven
360
+ # Uses callback buttons for choices
361
+ ```
362
+
363
+ Pattern 3: Async Operations
364
+
365
+ ```ruby
366
+ bot.scene :async_task
367
+ # Uses Async { } for HTTP/DB operations
368
+ ```
369
+
370
+ Pattern 4: Validated Input
371
+
372
+ ```ruby
373
+ bot.scene :validated_input
374
+ # Uses return to stay on step when validation fails
375
+ ```
376
+
377
+ 🔧 Debugging Scenes: Quick Fixes
378
+
379
+ ❌ "Scene doesn't start!"
380
+
381
+ Check: Did you call ctx.enter_scene?
382
+
383
+ ```ruby
384
+ bot.command('start') do |ctx|
385
+ ctx.enter_scene(:your_scene) # ← MUST BE PRESENT
386
+ end
387
+ ```
388
+
389
+ ❌ "Steps skip unexpectedly!"
390
+
391
+ Cause: Missing return on validation failure
392
+ Fix:
393
+
394
+ ```ruby
395
+ step :collect_age do |ctx|
396
+ age = ctx.message.text.to_i
397
+ if age < 18
398
+ ctx.reply "Must be 18+. Try again:"
399
+ return # ← THIS keeps you on the same step
400
+ end
401
+ # Continues only if age >= 18
402
+ end
403
+ ```
404
+
405
+ ❌ "Data lost between steps!"
406
+
407
+ Solution: Use ctx.session
408
+
409
+ ```ruby
410
+ step :one do |ctx|
411
+ ctx.session[:temp] = "saved data" # ← Save
412
+ end
413
+
414
+ step :two do |ctx|
415
+ data = ctx.session[:temp] # ← Retrieve
416
+ end
417
+ ```
418
+
419
+ 📝 Remember This Mental Model
420
+
421
+ 1. Define once (bot.scene) - Teach the bot a conversation pattern
422
+ 2. Start many times (ctx.enter_scene) - Begin that conversation with users
423
+ 3. Steps auto-advance - After user responds, Telegem moves to next step
424
+ 4. Use ctx.session - Store data between steps
425
+ 5. Clean up in on_leave - Remove session data when done
426
+
427
+ 🎯 Your Homework (Test Understanding)
428
+
429
+ 1. Create a pizza ordering scene with size and toppings
430
+ 2. Add validation (size must be S/M/L, max 3 toppings)
431
+ 3. Add a timeout of 10 minutes
432
+ 4. Test it with /order_pizza
433
+
434
+ You now have everything you need to build robust scenes. The key is practice—start simple, then add complexity one piece at a time.
data/lib/core/bot.rb CHANGED
@@ -80,7 +80,7 @@ module Telegem
80
80
  end
81
81
 
82
82
  def webhook(app = nil, &block)
83
- require 'telegem/webhook/server'
83
+ require 'webhook/server'
84
84
 
85
85
  if block_given?
86
86
  Webhook::Server.new(self, &block)
data/lib/telegem.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  require 'logger'
3
3
  require 'json'
4
4
  module Telegem
5
- VERSION = "1.0.4".freeze
5
+ VERSION = "1.0.5".freeze
6
6
  end
7
7
 
8
8
  # Load core components
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: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Your Name
@@ -87,6 +87,8 @@ files:
87
87
  - docs/Cookbook.md
88
88
  - docs/How_to_use.md
89
89
  - docs/QuickStart.md
90
+ - docs/UNDERSTANDING-WEBHOOK-n-POLLING.md
91
+ - docs/Understanding_Scene.md
90
92
  - docs/Usage.md
91
93
  - lib/api/client.rb
92
94
  - lib/api/types.rb