telegram-bot-ruby 1.0.0.rc1 → 2.0.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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +10 -0
  3. data/.github/workflows/ci.yml +2 -5
  4. data/.github/workflows/stale.yml +19 -0
  5. data/.gitignore +1 -0
  6. data/.rspec +1 -0
  7. data/.rubocop.yml +12 -7
  8. data/CHANGELOG.md +17 -0
  9. data/Gemfile +13 -0
  10. data/LICENSE +0 -1
  11. data/README.md +78 -19
  12. data/Rakefile +10 -8
  13. data/bin/console +4 -1
  14. data/lib/telegram/bot/api/endpoints.rb +114 -0
  15. data/lib/telegram/bot/api.rb +20 -44
  16. data/lib/telegram/bot/client.rb +8 -9
  17. data/lib/telegram/bot/exceptions/response_error.rb +2 -8
  18. data/lib/telegram/bot/types/animation.rb +1 -1
  19. data/lib/telegram/bot/types/audio.rb +1 -1
  20. data/lib/telegram/bot/types/bot_command_scope_all_chat_administrators.rb +1 -1
  21. data/lib/telegram/bot/types/bot_command_scope_all_group_chats.rb +1 -1
  22. data/lib/telegram/bot/types/bot_command_scope_all_private_chats.rb +1 -1
  23. data/lib/telegram/bot/types/bot_command_scope_chat.rb +2 -2
  24. data/lib/telegram/bot/types/bot_command_scope_chat_administrators.rb +2 -2
  25. data/lib/telegram/bot/types/bot_command_scope_chat_member.rb +2 -2
  26. data/lib/telegram/bot/types/bot_command_scope_default.rb +1 -1
  27. data/lib/telegram/bot/types/bot_description.rb +11 -0
  28. data/lib/telegram/bot/types/bot_name.rb +11 -0
  29. data/lib/telegram/bot/types/bot_short_description.rb +11 -0
  30. data/lib/telegram/bot/types/callback_query.rb +1 -1
  31. data/lib/telegram/bot/types/chat.rb +16 -9
  32. data/lib/telegram/bot/types/chat_administrator_rights.rb +3 -0
  33. data/lib/telegram/bot/types/chat_boost.rb +14 -0
  34. data/lib/telegram/bot/types/chat_boost_removed.rb +14 -0
  35. data/lib/telegram/bot/types/chat_boost_source.rb +13 -0
  36. data/lib/telegram/bot/types/chat_boost_source_gift_code.rb +12 -0
  37. data/lib/telegram/bot/types/chat_boost_source_giveaway.rb +14 -0
  38. data/lib/telegram/bot/types/chat_boost_source_premium.rb +12 -0
  39. data/lib/telegram/bot/types/chat_boost_updated.rb +12 -0
  40. data/lib/telegram/bot/types/chat_join_request.rb +1 -0
  41. data/lib/telegram/bot/types/chat_member.rb +11 -2
  42. data/lib/telegram/bot/types/chat_member_administrator.rb +8 -5
  43. data/lib/telegram/bot/types/chat_member_banned.rb +2 -2
  44. data/lib/telegram/bot/types/chat_member_left.rb +2 -2
  45. data/lib/telegram/bot/types/chat_member_member.rb +2 -2
  46. data/lib/telegram/bot/types/chat_member_owner.rb +2 -2
  47. data/lib/telegram/bot/types/chat_member_restricted.rb +12 -7
  48. data/lib/telegram/bot/types/chat_member_updated.rb +1 -0
  49. data/lib/telegram/bot/types/chat_permissions.rb +6 -1
  50. data/lib/telegram/bot/types/chat_shared.rb +12 -0
  51. data/lib/telegram/bot/types/compactable.rb +2 -7
  52. data/lib/telegram/bot/types/document.rb +1 -1
  53. data/lib/telegram/bot/types/external_reply_info.rb +33 -0
  54. data/lib/telegram/bot/types/force_reply.rb +1 -1
  55. data/lib/telegram/bot/types/giveaway.rb +18 -0
  56. data/lib/telegram/bot/types/giveaway_completed.rb +13 -0
  57. data/lib/telegram/bot/types/giveaway_created.rb +10 -0
  58. data/lib/telegram/bot/types/giveaway_winners.rb +21 -0
  59. data/lib/telegram/bot/types/inaccessible_message.rb +13 -0
  60. data/lib/telegram/bot/types/inline_keyboard_button.rb +1 -0
  61. data/lib/telegram/bot/types/inline_query_result_article.rb +4 -4
  62. data/lib/telegram/bot/types/inline_query_result_audio.rb +1 -1
  63. data/lib/telegram/bot/types/inline_query_result_cached_audio.rb +1 -1
  64. data/lib/telegram/bot/types/inline_query_result_cached_document.rb +1 -1
  65. data/lib/telegram/bot/types/inline_query_result_cached_gif.rb +1 -1
  66. data/lib/telegram/bot/types/inline_query_result_cached_mpeg4_gif.rb +1 -1
  67. data/lib/telegram/bot/types/inline_query_result_cached_photo.rb +1 -1
  68. data/lib/telegram/bot/types/inline_query_result_cached_sticker.rb +1 -1
  69. data/lib/telegram/bot/types/inline_query_result_cached_video.rb +1 -1
  70. data/lib/telegram/bot/types/inline_query_result_cached_voice.rb +1 -1
  71. data/lib/telegram/bot/types/inline_query_result_contact.rb +4 -4
  72. data/lib/telegram/bot/types/inline_query_result_document.rb +4 -4
  73. data/lib/telegram/bot/types/inline_query_result_game.rb +1 -1
  74. data/lib/telegram/bot/types/inline_query_result_gif.rb +3 -3
  75. data/lib/telegram/bot/types/inline_query_result_location.rb +4 -4
  76. data/lib/telegram/bot/types/inline_query_result_mpeg4_gif.rb +3 -3
  77. data/lib/telegram/bot/types/inline_query_result_photo.rb +2 -2
  78. data/lib/telegram/bot/types/inline_query_result_venue.rb +4 -4
  79. data/lib/telegram/bot/types/inline_query_result_video.rb +2 -2
  80. data/lib/telegram/bot/types/inline_query_result_voice.rb +1 -1
  81. data/lib/telegram/bot/types/input_media_animation.rb +2 -2
  82. data/lib/telegram/bot/types/input_media_audio.rb +2 -2
  83. data/lib/telegram/bot/types/input_media_document.rb +2 -2
  84. data/lib/telegram/bot/types/input_media_photo.rb +1 -1
  85. data/lib/telegram/bot/types/input_media_video.rb +2 -2
  86. data/lib/telegram/bot/types/input_text_message_content.rb +1 -1
  87. data/lib/telegram/bot/types/keyboard_button.rb +2 -0
  88. data/lib/telegram/bot/types/keyboard_button_request_chat.rb +18 -0
  89. data/lib/telegram/bot/types/keyboard_button_request_users.rb +14 -0
  90. data/lib/telegram/bot/types/link_preview_options.rb +15 -0
  91. data/lib/telegram/bot/types/maybe_inaccessible_message.rb +12 -0
  92. data/lib/telegram/bot/types/menu_button_commands.rb +1 -1
  93. data/lib/telegram/bot/types/menu_button_default.rb +1 -1
  94. data/lib/telegram/bot/types/menu_button_web_app.rb +1 -1
  95. data/lib/telegram/bot/types/message.rb +20 -15
  96. data/lib/telegram/bot/types/message_id.rb +11 -0
  97. data/lib/telegram/bot/types/message_origin.rb +14 -0
  98. data/lib/telegram/bot/types/message_origin_channel.rb +15 -0
  99. data/lib/telegram/bot/types/message_origin_chat.rb +14 -0
  100. data/lib/telegram/bot/types/message_origin_hidden_user.rb +13 -0
  101. data/lib/telegram/bot/types/message_origin_user.rb +13 -0
  102. data/lib/telegram/bot/types/message_reaction_count_updated.rb +14 -0
  103. data/lib/telegram/bot/types/message_reaction_updated.rb +17 -0
  104. data/lib/telegram/bot/types/passport_element_error_data_field.rb +1 -1
  105. data/lib/telegram/bot/types/passport_element_error_file.rb +1 -1
  106. data/lib/telegram/bot/types/passport_element_error_files.rb +2 -2
  107. data/lib/telegram/bot/types/passport_element_error_front_side.rb +1 -1
  108. data/lib/telegram/bot/types/passport_element_error_reverse_side.rb +1 -1
  109. data/lib/telegram/bot/types/passport_element_error_selfie.rb +1 -1
  110. data/lib/telegram/bot/types/passport_element_error_translation_file.rb +1 -1
  111. data/lib/telegram/bot/types/passport_element_error_translation_files.rb +2 -2
  112. data/lib/telegram/bot/types/passport_element_error_unspecified.rb +1 -1
  113. data/lib/telegram/bot/types/poll_answer.rb +2 -1
  114. data/lib/telegram/bot/types/reaction_count.rb +12 -0
  115. data/lib/telegram/bot/types/reaction_type.rb +12 -0
  116. data/lib/telegram/bot/types/reaction_type_custom_emoji.rb +12 -0
  117. data/lib/telegram/bot/types/reaction_type_emoji.rb +12 -0
  118. data/lib/telegram/bot/types/reply_keyboard_remove.rb +1 -1
  119. data/lib/telegram/bot/types/reply_parameters.rb +17 -0
  120. data/lib/telegram/bot/types/sticker.rb +2 -1
  121. data/lib/telegram/bot/types/sticker_set.rb +1 -1
  122. data/lib/telegram/bot/types/story.rb +9 -0
  123. data/lib/telegram/bot/types/switch_inline_query_chosen_chat.rb +15 -0
  124. data/lib/telegram/bot/types/text_quote.rb +14 -0
  125. data/lib/telegram/bot/types/update.rb +4 -0
  126. data/lib/telegram/bot/types/user.rb +2 -2
  127. data/lib/telegram/bot/types/user_chat_boosts.rb +11 -0
  128. data/lib/telegram/bot/types/users_shared.rb +12 -0
  129. data/lib/telegram/bot/types/video.rb +1 -1
  130. data/lib/telegram/bot/types/video_note.rb +1 -1
  131. data/lib/telegram/bot/types/webhook_info.rb +1 -1
  132. data/lib/telegram/bot/types/write_access_allowed.rb +3 -0
  133. data/lib/telegram/bot/version.rb +1 -1
  134. data/lib/telegram/bot.rb +1 -0
  135. data/telegram-bot-ruby.gemspec +1 -13
  136. metadata +47 -117
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d6220dcbd9e12cc3ab22702dfbff66853f8cdc83fcf78ed59d63f2740051c29
4
- data.tar.gz: 1b50037b1b26470cdbbc7624d484ac38403f23eccfc7586788232a391ac0c6bf
3
+ metadata.gz: 5b61e5af1f53cd133496f945bc7642b2a79e12a1d2be92faca3e45246b51dba5
4
+ data.tar.gz: de0024292072dfa7dcc74ffa6c66ba4e30d470652bcdcd5d9b193a8cea66f420
5
5
  SHA512:
6
- metadata.gz: 8fc94125380ac64cd590da0ff841db37e7aaa4ee06d14bceb7a6a2d5a46e1747633479af81adeddfabd5a3006c79d5be331936417fda2aabb20a76de5d4fe211
7
- data.tar.gz: a4c09c3f00dae5d38f612f78fb70a24c6f2d6443be25da47b9fd45661dc3b9d2c5185e5f73c9aa5a7b71c6c74b57677ca53e9182d42b0396d372d4837a6af0f9
6
+ metadata.gz: dab03a9d65d7582dce03bb6f5a8aea981a507f8011e2e618264177182c132c4fda82d1fc80da0590d3196e07e145e586c665af1fa8e9fd5fdfbcd8c36439bad2
7
+ data.tar.gz: 1b165086c50ee02e77298c575712551462c58bdb3f963a70ab823d2c9cffffdf23551af8caa3ad484e47bca3d89505f5656ae05c15648b37e6e84cc73e308011
data/.editorconfig ADDED
@@ -0,0 +1,10 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_size = 2
7
+ indent_style = space
8
+ insert_final_newline = true
9
+ max_line_length = 120
10
+ trim_trailing_whitespace = true
@@ -13,7 +13,7 @@ jobs:
13
13
  matrix:
14
14
  ruby:
15
15
  - 2.7
16
- - 3.1
16
+ - 3.2
17
17
  steps:
18
18
  - name: Checkout
19
19
  uses: actions/checkout@v3
@@ -31,10 +31,7 @@ jobs:
31
31
  matrix:
32
32
  ruby:
33
33
  - 2.7
34
- - 3.1
35
- env:
36
- BOT_API_ENV: test
37
- BOT_API_TOKEN: ${{ secrets.BOT_API_TOKEN }}
34
+ - 3.2
38
35
  steps:
39
36
  - name: Checkout
40
37
  uses: actions/checkout@v3
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: Close stale issues and PRs
3
+ on:
4
+ schedule:
5
+ - cron: 40 * * * *
6
+
7
+ jobs:
8
+ stale:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/stale@v7
12
+ with:
13
+ days-before-close: 7
14
+ days-before-stale: 60
15
+ stale-issue-label: stale
16
+ stale-issue-message: This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.
17
+ stale-pr-label: stale
18
+ stale-pr-message: This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.
19
+ operations-per-run: 500
data/.gitignore CHANGED
@@ -3,4 +3,5 @@ Gemfile.lock
3
3
  .bundle/
4
4
  .env
5
5
  pkg/
6
+ tmp/
6
7
  vendor/bundle/
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --require spec_helper
2
2
  --color
3
+ --warnings
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@
2
2
  require:
3
3
  - rubocop-rake
4
4
  - rubocop-rspec
5
+ - rubocop-performance
5
6
 
6
7
  AllCops:
7
8
  NewCops: enable
@@ -10,18 +11,22 @@ AllCops:
10
11
  Style/Documentation:
11
12
  Enabled: false
12
13
 
13
- Style/FrozenStringLiteralComment:
14
- Exclude:
15
- - bin/console
16
-
17
14
  Metrics/BlockLength:
18
15
  AllowedMethods:
19
16
  - context
20
17
  - describe
21
18
  - task
19
+ Metrics/ClassLength:
20
+ Exclude:
21
+ - lib/telegram/bot/api/endpoints.rb
22
+ Metrics/MethodLength:
23
+ Exclude:
24
+ - spec/**/*
22
25
 
23
26
  Layout/LineLength:
24
27
  Max: 120
25
- Exclude:
26
- - telegram-bot-ruby.gemspec
27
- - examples/*.rb
28
+
29
+ RSpec/MultipleMemoizedHelpers:
30
+ Enabled: false
31
+ RSpec/NestedGroups:
32
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Added
6
+
7
+ - [Bot API 7.0](https://core.telegram.org/bots/api#december-29-2023)
8
+
9
+ ### Changed
10
+
11
+ - API method calls now return corresponding response objects ([#285](https://github.com/atipugin/telegram-bot-ruby/pull/285), thx [@AlexWayfer](https://github.com/AlexWayfer))
12
+
13
+ ## 1.0.0
14
+
15
+ - Replace [virtus](https://github.com/solnic/virtus) with [dry-struct](https://github.com/dry-rb/dry-struct)
16
+ - Use [zeitwerk](https://github.com/fxn/zeitwerk) for code loading
17
+ - Implement [Bot API 6.4](https://core.telegram.org/bots/api#december-30-2022)
18
+ - Implement [Bot API 6.5](https://core.telegram.org/bots/api#february-3-2023)
19
+
3
20
  ## 0.23.0
4
21
 
5
22
  - Rename `Telegram::Bot.configuration` options:
data/Gemfile CHANGED
@@ -3,3 +3,16 @@
3
3
  source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
+
7
+ gem 'dotenv', '~> 2.8'
8
+ gem 'nokogiri', '~> 1.13'
9
+ gem 'pry'
10
+ gem 'rake', '~> 13.0'
11
+
12
+ gem 'rspec', '~> 3.4'
13
+ gem 'vcr', '~> 6.0'
14
+
15
+ gem 'rubocop', '~> 1.54.1'
16
+ gem 'rubocop-performance', '~> 1.18'
17
+ gem 'rubocop-rake', '~> 0.6.0'
18
+ gem 'rubocop-rspec', '~> 2.22.0'
data/LICENSE CHANGED
@@ -11,4 +11,3 @@
11
11
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
12
 
13
13
  0. You just DO WHAT THE FUCK YOU WANT TO.
14
-
data/README.md CHANGED
@@ -7,12 +7,29 @@ Ruby wrapper for [Telegram's Bot API](https://core.telegram.org/bots/api).
7
7
  [![Maintainability](https://api.codeclimate.com/v1/badges/7e61fbf5bec86e118fb1/maintainability)](https://codeclimate.com/github/atipugin/telegram-bot-ruby/maintainability)
8
8
  [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks!-🦉-1EAEDB.svg)](https://saythanks.io/to/atipugin)
9
9
 
10
+ ## 🚧 Upgrading to 1.0
11
+
12
+ Since v1.0 `telegram-bot-ruby` uses [`dry-struct`](https://github.com/dry-rb/dry-struct)
13
+ instead of [`virtus`](https://github.com/solnic/virtus).
14
+ This means that type objects are now immutable and you can't change them after initialization:
15
+
16
+ ```ruby
17
+ # This won't work
18
+ kb = Telegram::Bot::Types::ReplyKeyboardRemove.new
19
+ kb.remove_keyboard = true
20
+
21
+ # You have to set attributes in constructor instead
22
+ kb = Telegram::Bot::Types::ReplyKeyboardRemove.new(remove_keyboard: true)
23
+ ```
24
+
25
+ Please make sure it doesn't break your existing code before upgrading to 1.0.
26
+
10
27
  ## Installation
11
28
 
12
29
  Add following line to your Gemfile:
13
30
 
14
31
  ```ruby
15
- gem 'telegram-bot-ruby'
32
+ gem 'telegram-bot-ruby', '~> 1.0'
16
33
  ```
17
34
 
18
35
  And then execute:
@@ -29,7 +46,8 @@ gem install telegram-bot-ruby
29
46
 
30
47
  ## Usage
31
48
 
32
- First things first, you need to [obtain a token](https://core.telegram.org/bots#6-botfather) for your bot. Then create your Telegram bot like this:
49
+ First things first, you need to [obtain a token](https://core.telegram.org/bots#6-botfather) for your bot.
50
+ Then create your Telegram bot like this:
33
51
 
34
52
  ```ruby
35
53
  require 'telegram/bot'
@@ -48,7 +66,10 @@ Telegram::Bot::Client.run(token) do |bot|
48
66
  end
49
67
  ```
50
68
 
51
- Note that `bot.api` object implements [Telegram Bot API methods](https://core.telegram.org/bots/api#available-methods) as is. So you can invoke any method inside the block without any problems. All methods are available in both *snake_case* and *camelCase* notations.
69
+ Note that `bot.api` object implements
70
+ [Telegram Bot API methods](https://core.telegram.org/bots/api#available-methods) as is.
71
+ So you can invoke any method inside the block without any problems.
72
+ All methods are available in both *snake_case* and *camelCase* notations.
52
73
 
53
74
  If you need to start a bot in development mode you have to pass `environment: :test`:
54
75
 
@@ -58,15 +79,35 @@ Telegram::Bot::Client.run(token, environment: :test) do |bot|
58
79
  end
59
80
  ```
60
81
 
61
- Same thing about `message` object - it implements [Message](https://core.telegram.org/bots/api#message) spec, so you always know what to expect from it.
82
+ Same thing about `message` object: it implements [Message](https://core.telegram.org/bots/api#message) spec,
83
+ so you always know what to expect from it.
84
+
85
+ To gracefully stop the bot, for example by `INT` signal (Ctrl-C), call the `bot.stop` method:
86
+
87
+ ```ruby
88
+ bot = Telegram::Bot::Client.new(token)
89
+
90
+ Signal.trap('INT') do
91
+ bot.stop
92
+ end
93
+
94
+ bot.listen do |message|
95
+ # it will be in an infinity loop until `bot.stop` command
96
+ # (with a small delay for the current `fetch_updates` request)
97
+ end
98
+ ```
62
99
 
63
100
  ## Webhooks
64
101
 
65
- If you are going to use [webhooks](https://core.telegram.org/bots/api#setwebhook) instead of [long polling](https://core.telegram.org/bots/api#getupdates), you need to implement your own webhook callbacks server. Take a look at [this repo](https://github.com/solyaris/BOTServer) as an example.
102
+ If you are going to use [webhooks](https://core.telegram.org/bots/api#setwebhook)
103
+ instead of [long polling](https://core.telegram.org/bots/api#getupdates),
104
+ you need to implement your own webhook callbacks server.
105
+ Take a look at [this repo](https://github.com/solyaris/BOTServer) as an example.
66
106
 
67
107
  ## Proxy
68
108
 
69
- As some countries block access to Telegram, you can set up your own proxy and use it to access Telegram API. In this case you need to configure API url:
109
+ As some countries block access to Telegram, you can set up your own proxy and use it to access Telegram API.
110
+ In this case you need to configure API URL:
70
111
 
71
112
  ```ruby
72
113
  Telegram::Bot::Client.run(token, url: 'https://proxy.example.com') do |bot|
@@ -76,7 +117,8 @@ end
76
117
 
77
118
  ## Custom keyboards
78
119
 
79
- You can use your own [custom keyboards](https://core.telegram.org/bots#keyboards). Here is an example:
120
+ You can use your own [custom keyboards](https://core.telegram.org/bots#keyboards).
121
+ Here is an example:
80
122
 
81
123
  ```ruby
82
124
  bot.listen do |message|
@@ -116,7 +158,8 @@ end
116
158
 
117
159
  ## Inline keyboards
118
160
 
119
- [Bot API 2.0](https://core.telegram.org/bots/2-0-intro) brought us new inline keyboards. Example:
161
+ [Bot API 2.0](https://core.telegram.org/bots/2-0-intro) brought us new inline keyboards.
162
+ Example:
120
163
 
121
164
  ```ruby
122
165
  bot.listen do |message|
@@ -164,13 +207,25 @@ bot.listen do |message|
164
207
  end
165
208
  ```
166
209
 
167
- Now, with `inline` mode enabled, your `message` object can be an instance of [Message](https://core.telegram.org/bots/api#message), [InlineQuery](https://core.telegram.org/bots/api#inlinequery) or [ChosenInlineResult](https://core.telegram.org/bots/api#choseninlineresult). That's why you need to check type of each message and decide how to handle it.
210
+ Now, with `inline` mode enabled, your `message` object can be an instance of
211
+ [Message](https://core.telegram.org/bots/api#message),
212
+ [InlineQuery](https://core.telegram.org/bots/api#inlinequery) or
213
+ [ChosenInlineResult](https://core.telegram.org/bots/api#choseninlineresult).
214
+ That's why you need to check type of each message and decide how to handle it.
168
215
 
169
- Using `answer_inline_query` you can send query results to user. `results` field must be an array of [query result objects](https://core.telegram.org/bots/api#inlinequeryresult).
216
+ Using `answer_inline_query` you can send query results to user.
217
+ `results` field must be an array of [query result objects](https://core.telegram.org/bots/api#inlinequeryresult).
170
218
 
171
219
  ## File upload
172
220
 
173
- Your bot can even upload files ([photos](https://core.telegram.org/bots/api#sendphoto), [audio](https://core.telegram.org/bots/api#sendaudio), [documents](https://core.telegram.org/bots/api#senddocument), [stickers](https://core.telegram.org/bots/api#sendsticker), [video](https://core.telegram.org/bots/api#sendvideo)) to Telegram servers. Just like this:
221
+ Your bot can even upload files
222
+ ([photos](https://core.telegram.org/bots/api#sendphoto),
223
+ [audio](https://core.telegram.org/bots/api#sendaudio),
224
+ [documents](https://core.telegram.org/bots/api#senddocument),
225
+ [stickers](https://core.telegram.org/bots/api#sendsticker),
226
+ [video](https://core.telegram.org/bots/api#sendvideo))
227
+ to Telegram servers.
228
+ Just like this:
174
229
 
175
230
  ```ruby
176
231
  bot.listen do |message|
@@ -184,7 +239,9 @@ end
184
239
 
185
240
  ## Logging
186
241
 
187
- By default, bot doesn't log anything (uses `NullLoger`). You can change this behavior and provide your own logger class. See example below:
242
+ By default, bot doesn't log anything (uses `NullLoger`).
243
+ You can change this behavior and provide your own logger class.
244
+ See example below:
188
245
 
189
246
  ```ruby
190
247
  Telegram::Bot::Client.run(token, logger: Logger.new($stderr)) do |bot|
@@ -197,7 +254,8 @@ end
197
254
 
198
255
  ## Connection adapters
199
256
 
200
- Since version `0.5.0` we rely on [faraday](https://github.com/lostisland/faraday) under the hood. You can use any of supported adapters (for example, `net/http/persistent`):
257
+ Since version `0.5.0` we rely on [faraday](https://github.com/lostisland/faraday) under the hood.
258
+ You can use any of supported adapters (for example, `net/http/persistent`):
201
259
 
202
260
  ```ruby
203
261
  require 'net/http/persistent'
@@ -209,14 +267,15 @@ end
209
267
 
210
268
  ## Boilerplates
211
269
 
212
- If you don't know how to setup database for your bot or how to use it with different languages here are some boilerplates which can help you to start faster:
270
+ If you don't know how to setup database for your bot or how to use it with different languages
271
+ here are some boilerplates which can help you to start faster:
213
272
 
214
273
  - [Ruby Telegram Bot boilerplate](https://github.com/telegram-bots/ruby-telegram-bot-boilerplate)
215
274
 
216
275
  ## Contributing
217
276
 
218
- 1. Fork it
219
- 2. Create your feature branch (git checkout -b my-new-feature)
220
- 3. Commit your changes (git commit -am 'Add some feature')
221
- 4. Push to the branch (git push origin my-new-feature)
222
- 5. Create new Pull Request
277
+ 1. Fork it.
278
+ 2. Create your feature branch (`git checkout -b my-new-feature`).
279
+ 3. Commit your changes (`git commit -am 'Add some feature'`).
280
+ 4. Push to the branch (`git push origin my-new-feature`).
281
+ 5. Create a new Pull Request.
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ task default: :spec
18
18
 
19
19
  desc 'Dump type definitions from docs to YAML'
20
20
  task :dump_type_attributes do
21
- require File.expand_path('lib/telegram/bot', __dir__)
21
+ require_relative 'lib/telegram/bot'
22
22
  require 'nokogiri'
23
23
  require 'open-uri'
24
24
  require 'yaml'
@@ -30,6 +30,8 @@ task :dump_type_attributes do
30
30
  # Fetch and parse docs
31
31
  doc = Nokogiri::HTML(URI.open('https://core.telegram.org/bots/api').read)
32
32
 
33
+ next_type_element_names = %w[table h4]
34
+
33
35
  result = types.to_h do |type|
34
36
  # This is very hacky but working way to find table containing attributes for
35
37
  # given type. Basic idea is to find heading with type and then iterate until
@@ -38,23 +40,23 @@ task :dump_type_attributes do
38
40
  element = doc.at_xpath(%{//h4[text() = "#{type}"]})
39
41
  loop do
40
42
  element = element.next_element
41
- break if %w[table h4].include?(element.name)
43
+ break if next_type_element_names.include?(element.name)
42
44
  end
43
45
 
44
46
  attributes = element.xpath('.//tbody//tr').map do |el|
45
47
  cells = el.children.select { |c| c.name == 'td' }
46
48
  {
47
49
  'name' => cells[0].text,
48
- 'required' => !cells[2].text.start_with?('Optional.')
49
- }
50
+ 'type' => cells[1].text,
51
+ 'required' => !cells[2].text.start_with?('Optional.'),
52
+ 'required_value' =>
53
+ cells[2].text.match(/^.+, (?:must be (?<found_type>\w+)|always “(?<found_type>\w+)”)$/)&.[](:found_type)
54
+ }.compact
50
55
  end
51
56
 
52
57
  [type, attributes]
53
58
  end
54
59
 
55
60
  # Write everything to fixture file
56
- File.write(
57
- File.expand_path('spec/support/type_attributes.yml', __dir__),
58
- result.to_yaml
59
- )
61
+ File.write "#{__dir__}/spec/support/type_attributes.yml", result.to_yaml
60
62
  end
data/bin/console CHANGED
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
2
5
  require 'bundler/setup'
3
6
  require 'pry'
4
7
 
5
- require File.expand_path('../lib/telegram/bot', __dir__)
8
+ require_relative '../lib/telegram/bot'
6
9
 
7
10
  Pry.start
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Telegram
4
+ module Bot
5
+ class Api
6
+ ENDPOINTS = {
7
+ 'getUpdates' => Types::Array.of(Types::Update),
8
+ 'setWebhook' => Types::Bool,
9
+ 'deleteWebhook' => Types::Bool,
10
+ 'getWebhookInfo' => Types::WebhookInfo,
11
+ 'getMe' => Types::User,
12
+ 'sendMessage' => Types::Message,
13
+ 'forwardMessage' => Types::Message,
14
+ 'forwardMessages' => Types::Array.of(Types::MessageId),
15
+ 'sendPhoto' => Types::Message,
16
+ 'sendAudio' => Types::Message,
17
+ 'sendDocument' => Types::Message,
18
+ 'sendVideo' => Types::Message,
19
+ 'sendVoice' => Types::Message,
20
+ 'sendVideoNote' => Types::Message,
21
+ 'sendMediaGroup' => Types::Array.of(Types::Message),
22
+ 'sendLocation' => Types::Message,
23
+ 'editMessageLiveLocation' => Types::Message | Types::Bool,
24
+ 'stopMessageLiveLocation' => Types::Message | Types::Bool,
25
+ 'sendVenue' => Types::Message,
26
+ 'sendContact' => Types::Message,
27
+ 'sendChatAction' => Types::Bool,
28
+ 'setMessageReaction' => Types::Bool,
29
+ 'getUserProfilePhotos' => Types::UserProfilePhotos,
30
+ 'getFile' => Types::File,
31
+ 'banChatMember' => Types::Bool,
32
+ 'unbanChatMember' => Types::Bool,
33
+ 'restrictChatMember' => Types::Bool,
34
+ 'promoteChatMember' => Types::Bool,
35
+ 'leaveChat' => Types::Bool,
36
+ 'getChat' => Types::Chat,
37
+ 'getChatAdministrators' => Types::Array.of(Types::ChatMember),
38
+ 'exportChatInviteLink' => Types::String,
39
+ 'setChatPhoto' => Types::Bool,
40
+ 'deleteChatPhoto' => Types::Bool,
41
+ 'setChatTitle' => Types::Bool,
42
+ 'setChatDescription' => Types::Bool,
43
+ 'pinChatMessage' => Types::Bool,
44
+ 'unpinChatMessage' => Types::Bool,
45
+ 'getChatMembersCount' => Types::Integer,
46
+ 'getChatMember' => Types::ChatMember,
47
+ 'setChatStickerSet' => Types::Bool,
48
+ 'deleteChatStickerSet' => Types::Bool,
49
+ 'answerCallbackQuery' => Types::Bool,
50
+ 'getUserChatBoosts' => Types::UserChatBoosts,
51
+ 'editMessageText' => Types::Message | Types::Bool,
52
+ 'editMessageCaption' => Types::Message | Types::Bool,
53
+ 'editMessageReplyMarkup' => Types::Message | Types::Bool,
54
+ 'deleteMessage' => Types::Bool,
55
+ 'deleteMessages' => Types::Bool,
56
+ 'sendSticker' => Types::Message,
57
+ 'getStickerSet' => Types::StickerSet,
58
+ 'uploadStickerFile' => Types::File,
59
+ 'createNewStickerSet' => Types::Bool,
60
+ 'addStickerToSet' => Types::Bool,
61
+ 'setStickerPositionInSet' => Types::Bool,
62
+ 'deleteStickerFromSet' => Types::Bool,
63
+ 'answerInlineQuery' => Types::Bool,
64
+ 'sendInvoice' => Types::Message,
65
+ 'answerShippingQuery' => Types::Bool,
66
+ 'answerPreCheckoutQuery' => Types::Bool,
67
+ 'sendGame' => Types::Message,
68
+ 'setGameScore' => Types::Message | Types::Bool,
69
+ 'getGameHighScores' => Types::Array.of(Types::GameHighScore),
70
+ 'setPassportDataErrors' => Types::Bool,
71
+ 'editMessageMedia' => Types::Message | Types::Bool,
72
+ 'sendAnimation' => Types::Message,
73
+ 'sendPoll' => Types::Message,
74
+ 'stopPoll' => Types::Poll,
75
+ 'setChatPermissions' => Types::Bool,
76
+ 'setChatAdministratorCustomTitle' => Types::Bool,
77
+ 'sendDice' => Types::Message,
78
+ 'getMyCommands' => Types::Array.of(Types::BotCommand),
79
+ 'setMyCommands' => Types::Bool,
80
+ 'deleteMyCommands' => Types::Bool,
81
+ 'setStickerSetThumbnail' => Types::Bool,
82
+ 'logOut' => Types::Bool,
83
+ 'close' => Types::Bool,
84
+ 'copyMessage' => Types::MessageId,
85
+ 'copyMessages' => Types::Array.of(Types::MessageId),
86
+ 'createChatInviteLink' => Types::ChatInviteLink,
87
+ 'editChatInviteLink' => Types::ChatInviteLink,
88
+ 'revokeChatInviteLink' => Types::ChatInviteLink,
89
+ 'approveChatJoinRequest' => Types::Bool,
90
+ 'declineChatJoinRequest' => Types::Bool,
91
+ 'banChatSenderChat' => Types::Bool,
92
+ 'unbanChatSenderChat' => Types::Bool,
93
+ 'answerWebAppQuery' => Types::SentWebAppMessage,
94
+ 'setChatMenuButton' => Types::Bool,
95
+ 'getChatMenuButton' => Types::MenuButtonDefault | Types::MenuButtonCommands | Types::MenuButtonWebApp,
96
+ 'setMyDefaultAdministratorRights' => Types::Bool,
97
+ 'getMyDefaultAdministratorRights' => Types::ChatAdministratorRights,
98
+ 'createInvoiceLink' => Types::String,
99
+ 'editGeneralForumTopic' => Types::Bool,
100
+ 'closeGeneralForumTopic' => Types::Bool,
101
+ 'reopenGeneralForumTopic' => Types::Bool,
102
+ 'hideGeneralForumTopic' => Types::Bool,
103
+ 'unhideGeneralForumTopic' => Types::Bool,
104
+ 'unpinAllGeneralForumTopicMessages' => Types::Bool,
105
+ 'setMyName' => Types::Bool,
106
+ 'getMyName' => Types::BotName,
107
+ 'setMyDescription' => Types::Bool,
108
+ 'getMyDescription' => Types::BotDescription,
109
+ 'setMyShortDescription' => Types::Bool,
110
+ 'getMyShortDescription' => Types::BotShortDescription
111
+ }.freeze
112
+ end
113
+ end
114
+ end
@@ -3,34 +3,6 @@
3
3
  module Telegram
4
4
  module Bot
5
5
  class Api
6
- ENDPOINTS = %w[
7
- getUpdates setWebhook deleteWebhook getWebhookInfo getMe sendMessage
8
- forwardMessage sendPhoto sendAudio sendDocument sendVideo sendVoice
9
- sendVideoNote sendMediaGroup sendLocation editMessageLiveLocation
10
- stopMessageLiveLocation sendVenue sendContact sendChatAction
11
- getUserProfilePhotos getFile kickChatMember unbanChatMember
12
- restrictChatMember promoteChatMember leaveChat getChat
13
- getChatAdministrators exportChatInviteLink setChatPhoto deleteChatPhoto
14
- setChatTitle setChatDescription pinChatMessage unpinChatMessage
15
- getChatMembersCount getChatMember setChatStickerSet deleteChatStickerSet
16
- answerCallbackQuery editMessageText editMessageCaption
17
- editMessageReplyMarkup deleteMessage sendSticker getStickerSet
18
- uploadStickerFile createNewStickerSet addStickerToSet
19
- setStickerPositionInSet deleteStickerFromSet answerInlineQuery
20
- sendInvoice answerShippingQuery answerPreCheckoutQuery
21
- sendGame setGameScore getGameHighScores setPassportDataErrors
22
- editMessageMedia sendAnimation sendPoll stopPoll setChatPermissions
23
- setChatAdministratorCustomTitle sendDice getMyCommands setMyCommands
24
- deleteMyCommands setStickerSetThumb logOut close copyMessage
25
- createChatInviteLink editChatInviteLink revokeChatInviteLink
26
- approveChatJoinRequest declineChatJoinRequest banChatSenderChat
27
- unbanChatSenderChat answerWebAppQuery setChatMenuButton
28
- getChatMenuButton setMyDefaultAdministratorRights
29
- getMyDefaultAdministratorRights createInvoiceLink editGeneralForumTopic
30
- closeGeneralForumTopic reopenGeneralForumTopic hideGeneralForumTopic
31
- unhideGeneralForumTopic
32
- ].freeze
33
-
34
6
  attr_reader :token, :url, :environment
35
7
 
36
8
  def initialize(token, url: 'https://api.telegram.org', environment: :production)
@@ -39,27 +11,41 @@ module Telegram
39
11
  @environment = environment.downcase.to_sym
40
12
  end
41
13
 
14
+ def connection
15
+ @connection ||= Faraday.new(url: url) do |faraday|
16
+ faraday.request :multipart
17
+ faraday.request :url_encoded
18
+ faraday.adapter Telegram::Bot.configuration.adapter
19
+ faraday.options.timeout = Telegram::Bot.configuration.connection_timeout
20
+ faraday.options.open_timeout = Telegram::Bot.configuration.connection_open_timeout
21
+ end
22
+ end
23
+
42
24
  def method_missing(method_name, *args, &block)
43
25
  endpoint = method_name.to_s
44
26
  endpoint = camelize(endpoint) if endpoint.include?('_')
45
27
 
46
- ENDPOINTS.include?(endpoint) ? call(endpoint, *args) : super
28
+ return super unless ENDPOINTS.key?(endpoint)
29
+
30
+ result = call(endpoint, *args)
31
+
32
+ return result['ok'] unless (result = result['result'])
33
+
34
+ ENDPOINTS[endpoint].call(result)
47
35
  end
48
36
 
49
37
  def respond_to_missing?(*args)
50
38
  method_name = args[0].to_s
51
39
  method_name = camelize(method_name) if method_name.include?('_')
52
40
 
53
- ENDPOINTS.include?(method_name) || super
41
+ ENDPOINTS.key?(method_name) || super
54
42
  end
55
43
 
56
44
  def call(endpoint, raw_params = {})
57
45
  params = build_params(raw_params)
58
46
  path = build_path(endpoint)
59
- response = conn.post(path, params)
60
- unless response.status == 200
61
- raise Exceptions::ResponseError.new(response), 'Telegram API has returned the error.'
62
- end
47
+ response = connection.post(path, params)
48
+ raise Exceptions::ResponseError.new(response: response) unless response.status == 200
63
49
 
64
50
  JSON.parse(response.body)
65
51
  end
@@ -95,16 +81,6 @@ module Telegram
95
81
  words.drop(1).map(&:capitalize!)
96
82
  words.join
97
83
  end
98
-
99
- def conn
100
- @conn ||= Faraday.new(url: url) do |faraday|
101
- faraday.request :multipart
102
- faraday.request :url_encoded
103
- faraday.adapter Telegram::Bot.configuration.adapter
104
- faraday.options.timeout = Telegram::Bot.configuration.connection_timeout
105
- faraday.options.open_timeout = Telegram::Bot.configuration.connection_open_timeout
106
- end
107
- end
108
84
  end
109
85
  end
110
86
  end
@@ -22,18 +22,17 @@ module Telegram
22
22
 
23
23
  def listen(&block)
24
24
  logger.info('Starting bot')
25
- running = true
26
- Signal.trap('INT') { running = false }
27
- fetch_updates(&block) while running
28
- exit
25
+ @running = true
26
+ fetch_updates(&block) while @running
29
27
  end
30
28
 
31
- def fetch_updates
32
- response = api.getUpdates(options)
33
- return unless response['ok']
29
+ def stop
30
+ @running = false
31
+ end
34
32
 
35
- response['result'].each do |data|
36
- yield handle_update(Types::Update.new(data))
33
+ def fetch_updates
34
+ api.getUpdates(options).each do |update|
35
+ yield handle_update(update)
37
36
  end
38
37
  rescue Faraday::TimeoutError, Faraday::ConnectionFailed
39
38
  retry