telegem 3.2.4 → 3.3.1

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: 64cc027dc87d2e24f181a24705a85243f95c7f498a44f70fcb175d8a9b2dd597
4
- data.tar.gz: 37310a9a9c973f31f3dfd5b93e8347843a50c8218475b90a7f055df116c8353e
3
+ metadata.gz: 0d2afc9e262ffced76a28974a69c6e652bf433b2b6da80c6827d45e6da43002a
4
+ data.tar.gz: 61f440f2523473e3f5435075bfece0519c374f4aa498d789cc6752c5ce285abf
5
5
  SHA512:
6
- metadata.gz: 9cd4708d09629445cf1398677521270c22991eee81b45204d2384570ba14876c937888cf86fc9ba8bfdad78138a48ea9bee6fed6e019a12ae89b29433f91e881
7
- data.tar.gz: ee85cb0026f096291a1700d825e68cf21f08385e1c7eaf5396763e00fbe4edecfb574b4ed1017293e4e41a06d60b98be5963893b6b0ba2e53f8816396ae33dfc
6
+ metadata.gz: 378d55910d0b38b255b35ea357af4cb88f45000362b9d16688dff82a02fe3e5119e71e591c2cec61556d9c9cc82c0edd914ba7cd153ba1cae04c0e97b3f6d229
7
+ data.tar.gz: 527cb2833282c03d7f19145d7421e6df5d867ffbb479846ac9e969a8be339450c7358fdefaced5952dfc7d96b999348253a2494b2a2fe3d9c55480073587a421
data/CHANGELOG.md ADDED
@@ -0,0 +1,103 @@
1
+ # Telegem Changelog
2
+
3
+ ## v3.3.1(lastest)
4
+ ### Features
5
+ - improved memeorystore to include diskbackup
6
+ - added 'telegem-init' cli
7
+
8
+
9
+ ## v3.1.1
10
+
11
+ ### New Features
12
+
13
+ -FileExtractor Plugin: New plugin for extracting content from various file types (PDF, JSON, HTML, TXT)
14
+ - Async File Download: Added download method to API client for downloading Telegram files
15
+ - Context File Helpers: Added download_file, download_photo, download_document methods to Context
16
+ - Extended File Support: Plugin supports PDF text extraction, JSON parsing, HTML/raw text processing
17
+ - Async/Sync Dual Mode: All file operations available in both sync (download) and async (download!) modes
18
+
19
+ ## v3.1.0
20
+
21
+ ### features
22
+ - BREAKING: Rewrote polling system to prevent duplicate messages
23
+ - Fixed thread deadlock in async polling loop
24
+ - Added scene_middleware.rb for scene-based conversations
25
+ - Improved MemoryStore with TTL and thread safety
26
+ - Enhanced keyboard markup builder with web_app support
27
+ - Added message reaction and chat boost update types
28
+ - Fixed callback query handling for inline keyboards
29
+
30
+ ## v3.0.0
31
+ ### features
32
+
33
+ - BREAKING: Complete async rewrite with async gem
34
+ - New HTTP client using HTTPX with proper async/await pattern
35
+ - Added scene system for multi-step conversations
36
+ - Middleware composer system for plugin architecture
37
+ - Type system with dynamic accessors for Telegram objects
38
+ - Session management with memory store
39
+ - Rate limiting middleware
40
+ - File upload support via multipart forms
41
+
42
+ ## v2.0.0
43
+
44
+ - BREAKING: Ruby 3.0+ requirement
45
+ - Added webhook support with Rack middleware
46
+ - Inline query and callback query handlers
47
+ - Location, contact, and poll answer handlers
48
+ - Keyboard markup helpers (Telegem::Markup)
49
+ - Improved error handling with custom error classes
50
+ - Logging integration with configurable loggers
51
+
52
+ ## v1.5.0
53
+
54
+ - Added command argument parsing (ctx.command_args)
55
+ - Message entity parsing (mentions, hashtags, bot commands)
56
+ - Chat member update handlers
57
+ - Pre-checkout and shipping query support
58
+ - File download helper methods
59
+ - Context helper methods for common API calls
60
+
61
+ ## v1.0.0
62
+
63
+ - Stable API release
64
+ - Message handlers with text pattern matching
65
+ - Command handlers with regex support
66
+ - Basic context object with chat/message accessors
67
+ - Simple API client with error handling
68
+ - Polling and webhook modes
69
+ - Configuration options for timeout and limits
70
+
71
+ ## v0.5.0
72
+
73
+ - Added callback query support
74
+ - Inline keyboard builder
75
+ - Message editing and deletion helpers
76
+ - Media sending methods (photo, document, audio, video)
77
+ - Chat action methods (typing, upload indicators)
78
+
79
+ ## v0.3.0
80
+
81
+ - Middleware system with bot.use
82
+ - Session management foundation
83
+ - Basic rate limiting
84
+ - Command filtering by chat type
85
+ - Improved logging with debug levels
86
+
87
+ ## v0.2.0
88
+
89
+ - Basic polling implementation
90
+ - Message type detection (text, photo, document)
91
+ - Command parsing with arguments
92
+ - Simple reply methods
93
+ - Error handling for API calls
94
+
95
+ ## v0.1.0 (Initial Release)
96
+
97
+ - Basic Telegram Bot API wrapper
98
+ - Send/receive messages
99
+ - Simple command handling
100
+ - Minimal dependencies (just httparty)
101
+ - Support for basic message types
102
+
103
+ ---
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
  group :development do
6
6
  gem 'rake', '~> 13.0'
7
7
  gem 'rspec', '~> 3.0'
8
- gem 'pry', '~> 0.14.0'
8
+ gem 'pry', '~> 0.16.0'
9
9
  end
data/Readme.md CHANGED
@@ -4,10 +4,6 @@ Modern, blazing-fast async Telegram Bot API for Ruby - Inspired by Telegraf, bui
4
4
 
5
5
  ![Gem Version](https://badge.fury.io/rb/telegem.svg) ![GitLab](https://img.shields.io/badge/gitlab-telegem-orange) ![Ruby Version](https://img.shields.io/badge/Ruby-3.0+-red.svg) ![License](https://img.shields.io/badge/License-MIT-blue.svg) ![Async I/O](https://img.shields.io/badge/Async-I/O-green.svg)
6
6
 
7
- ![GitLab stars](https://img.shields.io/gitlab/stars/ruby-telegem/telegem?style=for-the-badge&logo=gitlab&color=orange)
8
- ![GitLab contributors](https://img.shields.io/gitlab/contributors/ruby-telegem/telegem?style=for-the-badge&logo=gitlab)
9
- ![GitLab last commit](https://img.shields.io/gitlab/last-commit/ruby-telegem/telegem?style=for-the-badge&logo=gitlab)
10
- ![GitLab license](https://img.shields.io/gitlab/license/ruby-telegem/telegem?style=for-the-badge&logo=gitlab)
11
7
 
12
8
 
13
9
 
@@ -108,7 +104,7 @@ Perfect For:
108
104
 
109
105
  ---
110
106
 
111
- [📚 Documentation](https://rubydoc.info/gems/telegem/3.2.2/index)
107
+ [📚 Documentation](https://rubydoc.info/gems/telegem/3.2.3/index)
112
108
 
113
109
 
114
110
 
@@ -299,4 +295,4 @@ ruby -r telegem -e "puts 'Welcome to Telegem! 🚀'"
299
295
 
300
296
  ---
301
297
 
302
- Built with ❤️ for the Ruby community. Happy bot building! 🤖✨
298
+ Built with ❤️ for the Ruby community. Happy bot building! 🤖✨
data/bin/telegem-init ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # bin/telegem-init
3
+
4
+ require 'fileutils'
5
+
6
+ puts " Creating a telegem application..."
7
+
8
+ # Create the nested directory structure
9
+ FileUtils.mkdir_p("src/handlers")
10
+
11
+
12
+ code = <<~RUBY
13
+ require 'telegem'
14
+ require 'dotenv/load'
15
+
16
+ # Load all handlers from the handlers directory relative to this file
17
+ Dir[File.join(__dir__, 'handlers', '*.rb')].each { |file| require file }
18
+
19
+ bot = Telegem.new(ENV['BOT_TOKEN'])
20
+
21
+ puts "Bot is starting..."
22
+ bot.start_polling
23
+ RUBY
24
+
25
+ File.write('src/bot.rb', code)
26
+
27
+ # Optional: Create a blank .env file so the bot doesn't crash on load
28
+ File.write('.env', "BOT_TOKEN=your_token_here") unless File.exist?('.env')
29
+
30
+ puts "Successfully created src/bot.rb"
31
+ puts " Structure created: src/handlers/"
32
+ puts " Done working. Run your bot with: ruby src/bot.rb"
data/bin/telegem-ssl CHANGED
@@ -2,10 +2,17 @@
2
2
  # bin/telegem-ssl
3
3
 
4
4
  require 'fileutils'
5
+ require 'yaml'
5
6
 
6
7
  puts "🔐 Telegem SSL Setup"
7
8
  puts "=" * 10
8
9
 
10
+ if File.exist?('.telegem-ssl')
11
+ puts "🚫 SSL config already exists at .telegem-ssl"
12
+ print "Overwrite? (y/n): "
13
+ exit unless gets.chomp.downcase == 'y'
14
+ end
15
+
9
16
  # Get domain
10
17
  domain = ARGV[0]
11
18
  unless domain
data/lib/api/client.rb CHANGED
@@ -18,26 +18,19 @@ module Telegem
18
18
  end
19
19
 
20
20
  def call(method, params = {})
21
- Async do
22
21
  make_request(method, params)
23
- end.wait
24
22
  end
25
23
 
26
24
  def call!(method, params = {}, &callback)
27
25
  return unless callback
28
-
29
- Async do
30
26
  begin
31
27
  result = make_request(method, params)
32
28
  callback.call(result, nil)
33
29
  rescue => error
34
30
  callback.call(nil, error)
35
31
  end
36
- end
37
32
  end
38
-
39
33
  def upload(method, params)
40
- Async do
41
34
  url = "/bot#{@token}/#{method}"
42
35
 
43
36
  body = Async::HTTP::Body::Multipart.new
@@ -52,11 +45,10 @@ module Telegem
52
45
 
53
46
  response = @client.post(url, {}, body)
54
47
  handle_response(response)
55
- end.wait
48
+
56
49
  end
57
50
 
58
51
  def download(file_id, destination_path = nil)
59
- Async do
60
52
  file_info = call('getFile', file_id: file_id)
61
53
  return nil unless file_info && file_info['file_path']
62
54
 
@@ -76,7 +68,6 @@ module Telegem
76
68
  else
77
69
  raise NetworkError.new("Download failed: HTTP #{response.status}")
78
70
  end
79
- end.wait
80
71
  end
81
72
 
82
73
  def get_updates(offset: nil, timeout: 30, limit: 100, allowed_updates: nil)
data/lib/api/types.rb CHANGED
@@ -62,6 +62,21 @@ module Telegem
62
62
  @_accessors_defined[name] = true
63
63
  end
64
64
 
65
+ # helpers for converting nested objects
66
+ def wrap(key, klass)
67
+ if @_raw_data[key] && !@_raw_data[key].is_a?(klass)
68
+ @_raw_data[key] = klass.new(@_raw_data[key])
69
+ end
70
+ end
71
+
72
+ def wrap_array(key, klass)
73
+ if @_raw_data[key] && @_raw_data[key].is_a?(Array)
74
+ @_raw_data[key] = @_raw_data[key].map do |v|
75
+ v.is_a?(klass) ? v : klass.new(v)
76
+ end
77
+ end
78
+ end
79
+
65
80
  def snake_to_camel(str)
66
81
  str.gsub(/_([a-z])/) { $1.upcase }
67
82
  end
@@ -250,48 +265,104 @@ module Telegem
250
265
  private
251
266
 
252
267
  def convert_complex_fields
253
- if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
254
- @_raw_data['date'] = Time.at(@_raw_data['date'])
255
- end
256
-
257
- if @_raw_data['edit_date'] && !@_raw_data['edit_date'].is_a?(Time)
258
- @_raw_data['edit_date'] = Time.at(@_raw_data['edit_date'])
259
- end
260
-
261
- if @_raw_data['forward_date'] && !@_raw_data['forward_date'].is_a?(Time)
262
- @_raw_data['forward_date'] = Time.at(@_raw_data['forward_date'])
263
- end
264
-
265
- @_raw_data['from'] = User.new(@_raw_data['from']) if @_raw_data['from'] && !@_raw_data['from'].is_a?(User)
266
- @_raw_data['chat'] = Chat.new(@_raw_data['chat']) if @_raw_data['chat'] && !@_raw_data['chat'].is_a?(Chat)
267
- @_raw_data['via_bot'] = User.new(@_raw_data['via_bot']) if @_raw_data['via_bot'] && !@_raw_data['via_bot'].is_a?(User)
268
- @_raw_data['forward_from'] = User.new(@_raw_data['forward_from']) if @_raw_data['forward_from'] && !@_raw_data['forward_from'].is_a?(User)
269
- @_raw_data['forward_from_chat'] = Chat.new(@_raw_data['forward_from_chat']) if @_raw_data['forward_from_chat'] && !@_raw_data['forward_from_chat'].is_a?(Chat)
270
- @_raw_data['left_chat_member'] = User.new(@_raw_data['left_chat_member']) if @_raw_data['left_chat_member'] && !@_raw_data['left_chat_member'].is_a?(User)
271
-
272
- if @_raw_data['entities'] && @_raw_data['entities'].is_a?(Array)
273
- @_raw_data['entities'] = @_raw_data['entities'].map do |e|
274
- e.is_a?(MessageEntity) ? e : MessageEntity.new(e)
275
- end
276
- end
277
-
278
- if @_raw_data['caption_entities'] && @_raw_data['caption_entities'].is_a?(Array)
279
- @_raw_data['caption_entities'] = @_raw_data['caption_entities'].map do |e|
280
- e.is_a?(MessageEntity) ? e : MessageEntity.new(e)
268
+ # time conversions
269
+ @_raw_data['date'] = Time.at(@_raw_data['date']) if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
270
+ @_raw_data['edit_date'] = Time.at(@_raw_data['edit_date']) if @_raw_data['edit_date'] && !@_raw_data['edit_date'].is_a?(Time)
271
+ @_raw_data['forward_date'] = Time.at(@_raw_data['forward_date']) if @_raw_data['forward_date'] && !@_raw_data['forward_date'].is_a?(Time)
272
+
273
+ # basic object wrappers
274
+ wrap('from', User)
275
+ wrap('chat', Chat)
276
+ wrap('via_bot', User)
277
+ wrap('forward_from', User)
278
+ wrap('forward_from_chat', Chat)
279
+ wrap('left_chat_member', User)
280
+
281
+ wrap_array('entities', MessageEntity)
282
+ wrap_array('caption_entities', MessageEntity)
283
+
284
+ wrap('reply_to_message', Message)
285
+ wrap('pinned_message', Message)
286
+ wrap_array('new_chat_members', User)
287
+
288
+ # media and other nested types
289
+ wrap('contact', Contact)
290
+ wrap('location', Location)
291
+ wrap('venue', Venue)
292
+ wrap('dice', Dice)
293
+ wrap('poll', Poll)
294
+ wrap('proximity_alert_triggered', ProximityAlertTriggered)
295
+ wrap('web_app_data', WebAppData)
296
+
297
+ wrap('animation', Animation)
298
+ wrap('audio', Audio)
299
+ wrap('document', Document)
300
+ wrap('video', Video)
301
+ wrap('voice', Voice)
302
+ wrap('video_note', VideoNote)
303
+ wrap('sticker', Sticker)
304
+
305
+ wrap('invoice', Invoice)
306
+ wrap('successful_payment', SuccessfulPayment)
307
+ wrap('reply_markup', BaseType)
308
+
309
+ wrap('passport_data', PassportData)
310
+
311
+ wrap('video_chat_scheduled', VideoChatScheduled)
312
+ wrap('video_chat_started', VideoChatStarted)
313
+ wrap('video_chat_ended', VideoChatEnded)
314
+ wrap('video_chat_participants_invited', VideoChatParticipantsInvited)
315
+ wrap('video_chat_location', VideoChatLocation)
316
+
317
+ # new message event objects introduced in later API versions
318
+ wrap('message_auto_delete_timer_changed', MessageAutoDeleteTimerChanged)
319
+ wrap('forum_topic_created', ForumTopicCreated)
320
+ wrap('forum_topic_edited', ForumTopicEdited)
321
+ wrap('forum_topic_closed', ForumTopicClosed)
322
+ wrap('forum_topic_reopened', ForumTopicReopened)
323
+ wrap('general_forum_topic_hidden', GeneralForumTopicHidden)
324
+ wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
325
+ wrap('write_access_allowed', WriteAccessAllowed)
326
+
327
+ # arrays of sizes and photos
328
+ wrap_array('photo', PhotoSize)
329
+ wrap_array('new_chat_photo', PhotoSize)
330
+
331
+ # fall back to original media wrapper for backward compatibility
332
+ wrap_media_objects
333
+ end
334
+
335
+ def wrap_media_objects
336
+ # Media files (fall‑back to generic types if no specific class defined)
337
+ @_raw_data['document'] = Document.new(@_raw_data['document']) if @_raw_data['document'] && !@_raw_data['document'].is_a?(Document)
338
+ @_raw_data['animation'] = Animation.new(@_raw_data['animation']) if @_raw_data['animation'] && !@_raw_data['animation'].is_a?(Animation)
339
+ @_raw_data['audio'] = Audio.new(@_raw_data['audio']) if @_raw_data['audio'] && !@_raw_data['audio'].is_a?(Audio)
340
+ @_raw_data['video'] = Video.new(@_raw_data['video']) if @_raw_data['video'] && !@_raw_data['video'].is_a?(Video)
341
+ @_raw_data['voice'] = Voice.new(@_raw_data['voice']) if @_raw_data['voice'] && !@_raw_data['voice'].is_a?(Voice)
342
+ @_raw_data['video_note'] = VideoNote.new(@_raw_data['video_note']) if @_raw_data['video_note'] && !@_raw_data['video_note'].is_a?(VideoNote)
343
+ @_raw_data['sticker'] = Sticker.new(@_raw_data['sticker']) if @_raw_data['sticker'] && !@_raw_data['sticker'].is_a?(Sticker)
344
+
345
+ # Photo array
346
+ if @_raw_data['photo'] && @_raw_data['photo'].is_a?(Array)
347
+ @_raw_data['photo'] = @_raw_data['photo'].map do |p|
348
+ p.is_a?(PhotoSize) ? p : PhotoSize.new(p)
281
349
  end
282
350
  end
283
-
284
- if @_raw_data['reply_to_message'] && !@_raw_data['reply_to_message'].is_a?(Message)
285
- @_raw_data['reply_to_message'] = Message.new(@_raw_data['reply_to_message'])
286
- end
287
-
288
- if @_raw_data['pinned_message'] && !@_raw_data['pinned_message'].is_a?(Message)
289
- @_raw_data['pinned_message'] = Message.new(@_raw_data['pinned_message'])
290
- end
291
-
292
- if @_raw_data['new_chat_members'] && @_raw_data['new_chat_members'].is_a?(Array)
293
- @_raw_data['new_chat_members'] = @_raw_data['new_chat_members'].map do |u|
294
- u.is_a?(User) ? u : User.new(u)
351
+
352
+ # Contact, location, venue
353
+ @_raw_data['contact'] = Contact.new(@_raw_data['contact']) if @_raw_data['contact'] && !@_raw_data['contact'].is_a?(Contact)
354
+ @_raw_data['location'] = Location.new(@_raw_data['location']) if @_raw_data['location'] && !@_raw_data['location'].is_a?(Location)
355
+ @_raw_data['venue'] = Venue.new(@_raw_data['venue']) if @_raw_data['venue'] && !@_raw_data['venue'].is_a?(Venue)
356
+
357
+ # Payment & other
358
+ @_raw_data['invoice'] = Invoice.new(@_raw_data['invoice']) if @_raw_data['invoice'] && !@_raw_data['invoice'].is_a?(Invoice)
359
+ @_raw_data['successful_payment'] = SuccessfulPayment.new(@_raw_data['successful_payment']) if @_raw_data['successful_payment'] && !@_raw_data['successful_payment'].is_a?(SuccessfulPayment)
360
+ @_raw_data['reply_markup'] = BaseType.new(@_raw_data['reply_markup']) if @_raw_data['reply_markup'] && !@_raw_data['reply_markup'].is_a?(BaseType)
361
+
362
+ # Chat photo array
363
+ if @_raw_data['new_chat_photo'] && @_raw_data['new_chat_photo'].is_a?(Array)
364
+ @_raw_data['new_chat_photo'] = @_raw_data['new_chat_photo'].map do |p|
365
+ p.is_a?(PhotoSize) ? p : PhotoSize.new(p)
295
366
  end
296
367
  end
297
368
  end
@@ -392,15 +463,218 @@ module Telegem
392
463
  private
393
464
 
394
465
  def convert_update_objects
395
- @_raw_data['message'] = Message.new(@_raw_data['message']) if @_raw_data['message'] && !@_raw_data['message'].is_a?(Message)
396
- @_raw_data['edited_message'] = Message.new(@_raw_data['edited_message']) if @_raw_data['edited_message'] && !@_raw_data['edited_message'].is_a?(Message)
397
- @_raw_data['channel_post'] = Message.new(@_raw_data['channel_post']) if @_raw_data['channel_post'] && !@_raw_data['channel_post'].is_a?(Message)
398
- @_raw_data['edited_channel_post'] = Message.new(@_raw_data['edited_channel_post']) if @_raw_data['edited_channel_post'] && !@_raw_data['edited_channel_post'].is_a?(Message)
399
-
400
- if @_raw_data['callback_query'] && !@_raw_data['callback_query'].is_a?(CallbackQuery)
401
- @_raw_data['callback_query'] = CallbackQuery.new(@_raw_data['callback_query'])
466
+ wrap('message', Message)
467
+ wrap('edited_message', Message)
468
+ wrap('channel_post', Message)
469
+ wrap('edited_channel_post', Message)
470
+
471
+ wrap('inline_query', InlineQuery)
472
+ wrap('chosen_inline_result', ChosenInlineResult)
473
+ wrap('callback_query', CallbackQuery)
474
+ wrap('shipping_query', ShippingQuery)
475
+ wrap('pre_checkout_query', PreCheckoutQuery)
476
+ wrap('poll', Poll)
477
+ wrap('poll_answer', PollAnswer)
478
+ wrap('my_chat_member', ChatMemberUpdated)
479
+ wrap('chat_member', ChatMemberUpdated)
480
+ wrap('chat_join_request', ChatJoinRequest)
481
+ wrap('forum_topic_created', ForumTopicCreated)
482
+ wrap('forum_topic_edited', ForumTopicEdited)
483
+ wrap('forum_topic_closed', ForumTopicClosed)
484
+ wrap('forum_topic_reopened', ForumTopicReopened)
485
+ wrap('general_forum_topic_hidden', GeneralForumTopicHidden)
486
+ wrap('general_forum_topic_unhidden', GeneralForumTopicUnhidden)
487
+ wrap('write_access_allowed', WriteAccessAllowed)
488
+ end
489
+ end
490
+
491
+ # additional types returned by various methods / updates
492
+ class PhotoSize < BaseType; end
493
+ class Audio < BaseType; end
494
+ class Document < BaseType; end
495
+ class Video < BaseType; end
496
+ class Voice < BaseType; end
497
+ class VideoNote < BaseType; end
498
+ class Animation < BaseType; end
499
+ class Sticker < BaseType; end
500
+ class Contact < BaseType; end
501
+ class Dice < BaseType; end
502
+
503
+ class Location < BaseType; end
504
+ class Venue < BaseType; end
505
+ class ProximityAlertTriggered < BaseType; end
506
+ class WebAppData < BaseType; end
507
+ class PassportData < BaseType; end
508
+
509
+ class Invoice < BaseType; end
510
+ class SuccessfulPayment < BaseType; end
511
+ class ShippingAddress < BaseType; end
512
+ class OrderInfo < BaseType; end
513
+
514
+ class ShippingQuery < BaseType
515
+ def initialize(data)
516
+ super(data)
517
+ wrap('from', User)
518
+ wrap('shipping_address', ShippingAddress)
519
+ end
520
+ end
521
+
522
+ class PreCheckoutQuery < BaseType
523
+ def initialize(data)
524
+ super(data)
525
+ wrap('from', User)
526
+ wrap('shipping_address', ShippingAddress)
527
+ wrap('order_info', OrderInfo)
528
+ end
529
+ end
530
+
531
+ class PollOption < BaseType; end
532
+ class PollAnswer < BaseType; end
533
+
534
+ class Poll < BaseType
535
+ def initialize(data)
536
+ super(data)
537
+ wrap_array('options', PollOption)
538
+ wrap_array('explanation_entities', MessageEntity)
539
+ end
540
+ end
541
+
542
+ class ChatPermissions < BaseType; end
543
+ class ChatPhoto < BaseType; end
544
+ class ChatInviteLink < BaseType; end
545
+
546
+ # status-specific chat member objects. they inherit from ChatMember
547
+ class ChatMember < BaseType; end
548
+ class ChatMemberOwner < ChatMember; end
549
+ class ChatMemberAdministrator < ChatMember; end
550
+ class ChatMemberMember < ChatMember; end
551
+ class ChatMemberRestricted < ChatMember; end
552
+ class ChatMemberLeft < ChatMember; end
553
+ class ChatMemberBanned < ChatMember; end
554
+
555
+ class ChatAdministratorRights < BaseType; end
556
+
557
+ class ChatMemberUpdated < BaseType
558
+ def initialize(data)
559
+ super(data)
560
+ wrap('chat', Chat)
561
+ wrap('from', User)
562
+ wrap_member('old_chat_member')
563
+ wrap_member('new_chat_member')
564
+ wrap('invite_link', ChatInviteLink)
565
+ if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
566
+ @_raw_data['date'] = Time.at(@_raw_data['date'])
567
+ end
568
+ end
569
+
570
+ private
571
+
572
+ def wrap_member(key)
573
+ return unless @_raw_data[key]
574
+ status = @_raw_data[key]['status']
575
+ klass = case status
576
+ when 'creator' then ChatMemberOwner
577
+ when 'administrator' then ChatMemberAdministrator
578
+ when 'member' then ChatMemberMember
579
+ when 'restricted' then ChatMemberRestricted
580
+ when 'left' then ChatMemberLeft
581
+ when 'kicked' then ChatMemberBanned
582
+ else ChatMember
583
+ end
584
+ @_raw_data[key] = klass.new(@_raw_data[key])
585
+ end
586
+ end
587
+
588
+ class ChatJoinRequest < BaseType
589
+ def initialize(data)
590
+ super(data)
591
+ wrap('chat', Chat)
592
+ wrap('from', User)
593
+ wrap('invite_link', ChatInviteLink)
594
+ if @_raw_data['date'] && !@_raw_data['date'].is_a?(Time)
595
+ @_raw_data['date'] = Time.at(@_raw_data['date'])
402
596
  end
403
597
  end
404
598
  end
599
+
600
+ class InlineQuery < BaseType
601
+ def initialize(data)
602
+ super(data)
603
+ wrap('from', User)
604
+ wrap('location', Location)
605
+ end
606
+ end
607
+
608
+ class ChosenInlineResult < BaseType
609
+ def initialize(data)
610
+ super(data)
611
+ wrap('from', User)
612
+ wrap('location', Location)
613
+ end
614
+ end
615
+
616
+ class InlineQueryResult < BaseType; end
617
+ class InlineQueryResultArticle < InlineQueryResult; end
618
+ class InlineQueryResultPhoto < InlineQueryResult; end
619
+ class InlineQueryResultGif < InlineQueryResult; end
620
+ class InlineQueryResultMpeg4Gif < InlineQueryResult; end
621
+ class InlineQueryResultVideo < InlineQueryResult; end
622
+ class InlineQueryResultAudio < InlineQueryResult; end
623
+ class InlineQueryResultVoice < InlineQueryResult; end
624
+ class InlineQueryResultDocument < InlineQueryResult; end
625
+ class InlineQueryResultLocation < InlineQueryResult; end
626
+ class InlineQueryResultVenue < InlineQueryResult; end
627
+ class InlineQueryResultContact < InlineQueryResult; end
628
+ class InlineQueryResultGame < InlineQueryResult; end
629
+ class InlineQueryResultSticker < InlineQueryResult; end
630
+ class InlineQueryResultCachedPhoto < InlineQueryResult; end
631
+ class InlineQueryResultCachedGif < InlineQueryResult; end
632
+ class InlineQueryResultCachedMpeg4Gif < InlineQueryResult; end
633
+ class InlineQueryResultCachedSticker < InlineQueryResult; end
634
+ class InlineQueryResultCachedDocument < InlineQueryResult; end
635
+ class InlineQueryResultCachedVideo < InlineQueryResult; end
636
+ class InlineQueryResultCachedAudio < InlineQueryResult; end
637
+ class InlineQueryResultCachedVoice < InlineQueryResult; end
638
+
639
+ class UserProfilePhotos < BaseType
640
+ def initialize(data)
641
+ super(data)
642
+ wrap_array('photos', PhotoSize)
643
+ end
644
+ end
645
+
646
+ class UserProfileAudios < BaseType
647
+ def initialize(data)
648
+ super(data)
649
+ wrap_array('audios', Audio)
650
+ end
651
+ end
652
+
653
+ # generic utility objects returned by the API
654
+ class File < BaseType; end
655
+ class ResponseParameters < BaseType; end
656
+ class MaskPosition < BaseType; end
657
+ class StickerSet < BaseType; end
658
+
659
+ # new message event payloads (each a simple wrapper)
660
+ class MessageAutoDeleteTimerChanged < BaseType; end
661
+ class ForumTopicCreated < BaseType; end
662
+ class ForumTopicEdited < BaseType; end
663
+ class ForumTopicClosed < BaseType; end
664
+ class ForumTopicReopened < BaseType; end
665
+ class GeneralForumTopicHidden < BaseType; end
666
+ class GeneralForumTopicUnhidden < BaseType; end
667
+ class WriteAccessAllowed < BaseType; end
668
+
669
+ class BotCommand < BaseType; end
670
+ class BotCommandScope < BaseType; end
671
+ class WebhookInfo < BaseType; end
672
+
673
+ class VideoChatScheduled < BaseType; end
674
+ class VideoChatStarted < BaseType; end
675
+ class VideoChatEnded < BaseType; end
676
+ class VideoChatParticipantsInvited < BaseType; end
677
+ class VideoChatLocation < BaseType; end
678
+
405
679
  end
406
680
  end