telegram-bot 0.13.1 → 0.14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +73 -45
- data/lib/telegram/bot.rb +2 -2
- data/lib/telegram/bot/middleware.rb +1 -2
- data/lib/telegram/bot/routes_helper.rb +0 -27
- data/lib/telegram/bot/rspec.rb +9 -0
- data/lib/telegram/bot/rspec/callback_query_helpers.rb +39 -0
- data/lib/telegram/bot/rspec/integration.rb +9 -84
- data/lib/telegram/bot/rspec/integration/poller.rb +14 -0
- data/lib/telegram/bot/rspec/integration/rack.rb +24 -0
- data/lib/telegram/bot/rspec/integration/rails.rb +28 -0
- data/lib/telegram/bot/rspec/integration/shared.rb +14 -0
- data/lib/telegram/bot/rspec/message_helpers.rb +26 -0
- data/lib/telegram/bot/updates_controller.rb +46 -54
- data/lib/telegram/bot/updates_controller/callback_query_context.rb +6 -2
- data/lib/telegram/bot/updates_controller/commands.rb +44 -0
- data/lib/telegram/bot/updates_controller/message_context.rb +39 -60
- data/lib/telegram/bot/updates_controller/rspec_helpers.rb +15 -27
- data/lib/telegram/bot/updates_controller/translation.rb +47 -0
- data/lib/telegram/bot/version.rb +1 -1
- data/telegram-bot.gemspec +3 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a35f4302d428cf24b66fa6122bcb5852b8680b85259bd2dd070a6a8e9aff5b74
|
4
|
+
data.tar.gz: 53fa7c7a14b637cbcae403b87786e93c2b685fa2461cbef9edd9e68c869f9206
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d788d67fcc120b5f4ce0ac6299a3e6ab1015213b1a8710f1f7ea4311deca27381befae700ff708813f1c2d47dfbc9144c6cd901b5a39d8ca4843b405c7b2124
|
7
|
+
data.tar.gz: '09b511503e001cd6fe9a25072a384ac04b7c0de2a4e728894d3c4c10a5badcbb7872072fb9f3d10cf3c5cbae0edc14d7bb3ee70966ecaa01f09d6c8844edbf01'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
# Unreleased
|
2
|
+
|
3
|
+
# 0.14.0
|
4
|
+
|
5
|
+
- Make integration & controller specs consistent.
|
6
|
+
__Breaking changes__ for controller specs:
|
7
|
+
- Changed signature `dispatch(bot, update) => dispatch(update, bot)`.
|
8
|
+
- `update` helper is symbolized by default.
|
9
|
+
- `build_update(type, data)` is dropped in favor of `deep_stringify(type => data)`.
|
10
|
+
- Provide support for integration testing of bots in poller mode and non-Rails apps.
|
11
|
+
__Breaking changes__:
|
12
|
+
- Requiring `telegram/bot/rspec/integration` is deprecated in favor of
|
13
|
+
`telegram/bot/rspec/integration/rails`.
|
14
|
+
- `:telegram_bot` rspec tag is replaced with `telegram_bot: :rails`.
|
15
|
+
- __Breaking change__. Use bang-methods as actions for commands.
|
16
|
+
This prevents calling context contextual actions and payload specific actions with commands.
|
17
|
+
Translation helper strips `!` from action name for lazy translations.
|
18
|
+
- __Breaking change__. Drop `.context_handler`, `.context_to_action!` methods.
|
19
|
+
Use pass action name directly to `#save_context`.
|
20
|
+
It's the same as `.context_to_action!` is enabled by default.
|
21
|
+
- Class-level helper for lazy translations.
|
22
|
+
|
1
23
|
# 0.13.1
|
2
24
|
|
3
25
|
- Extracted typed response mappings to telegram-bot-types gem.
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
[](https://codeclimate.com/github/telegram-bot-rb/telegram-bot)
|
5
5
|
[](https://travis-ci.org/telegram-bot-rb/telegram-bot)
|
6
6
|
|
7
|
+
__Breaking changes in v0.14!__ See [upgrading guide](https://github.com/telegram-bot-rb/telegram-bot/wiki/Upgrading-to-0.14).
|
8
|
+
|
7
9
|
Tools for developing Telegram bots. Best used with Rails, but can be used in
|
8
10
|
[standalone app](https://github.com/telegram-bot-rb/telegram-bot/wiki/Not-rails-application).
|
9
11
|
Supposed to be used in webhook-mode in production, and poller-mode
|
@@ -154,14 +156,11 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|
154
156
|
# chosen_inline_result(result_id, query)
|
155
157
|
# callback_query(data)
|
156
158
|
|
157
|
-
# Define public methods
|
159
|
+
# Define public methods ending with `!` to handle commands.
|
158
160
|
# Command arguments will be parsed and passed to the method.
|
159
161
|
# Be sure to use splat args and default values to not get errors when
|
160
162
|
# someone passed more or less arguments in the message.
|
161
|
-
|
162
|
-
# For some commands like /message or /123 method names should start with
|
163
|
-
# `on_` to avoid conflicts.
|
164
|
-
def start(data = nil, *)
|
163
|
+
def start!(data = nil, *)
|
165
164
|
# do_smth_with(data)
|
166
165
|
|
167
166
|
# There are `chat` & `from` shortcut methods.
|
@@ -192,8 +191,9 @@ end
|
|
192
191
|
#### Reply helpers
|
193
192
|
|
194
193
|
There are helpers to respond for basic actions. They just set chat/message/query
|
195
|
-
identifiers from update. See
|
196
|
-
|
194
|
+
identifiers from update. See
|
195
|
+
[`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb)
|
196
|
+
module for more information. Here are this methods signatures:
|
197
197
|
|
198
198
|
```ruby
|
199
199
|
def respond_with(type, params); end
|
@@ -256,11 +256,11 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|
256
256
|
# You can override global config for this controller.
|
257
257
|
self.session_store = :file_store
|
258
258
|
|
259
|
-
def write(text = nil, *)
|
259
|
+
def write!(text = nil, *)
|
260
260
|
session[:text] = text
|
261
261
|
end
|
262
262
|
|
263
|
-
def read(*)
|
263
|
+
def read!(*)
|
264
264
|
respond_with :message, text: session[:text]
|
265
265
|
end
|
266
266
|
|
@@ -283,35 +283,28 @@ it asks you for additional argument. There is `MessageContext` for this:
|
|
283
283
|
class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
284
284
|
include Telegram::Bot::UpdatesController::MessageContext
|
285
285
|
|
286
|
-
def rename(*)
|
286
|
+
def rename!(*)
|
287
287
|
# set context for the next message
|
288
|
-
save_context :
|
288
|
+
save_context :rename_from_message
|
289
289
|
respond_with :message, text: 'What name do you like?'
|
290
290
|
end
|
291
291
|
|
292
292
|
# register context handlers to handle this context
|
293
|
-
|
293
|
+
def rename_from_message(*words)
|
294
294
|
update_name words[0]
|
295
295
|
respond_with :message, text: 'Renamed!'
|
296
296
|
end
|
297
297
|
|
298
|
-
# You can
|
299
|
-
def rename(name = nil, *)
|
298
|
+
# You can use same action name as context name:
|
299
|
+
def rename!(name = nil, *)
|
300
300
|
if name
|
301
301
|
update_name name
|
302
302
|
respond_with :message, text: 'Renamed!'
|
303
303
|
else
|
304
|
-
save_context :rename
|
304
|
+
save_context :rename!
|
305
305
|
respond_with :message, text: 'What name do you like?'
|
306
306
|
end
|
307
307
|
end
|
308
|
-
|
309
|
-
# This will call #rename like if it is called with message '/rename %text%'
|
310
|
-
context_handler :rename
|
311
|
-
|
312
|
-
# If you have a lot of such methods you can call this method
|
313
|
-
# to use context value as action name for all contexts which miss handlers:
|
314
|
-
context_to_action!
|
315
308
|
end
|
316
309
|
```
|
317
310
|
|
@@ -394,11 +387,11 @@ Telegram::Bot::UpdatesPoller.start(bot, controller_class)
|
|
394
387
|
|
395
388
|
### Testing
|
396
389
|
|
397
|
-
There is `Telegram::Bot::ClientStub` class to stub client for tests.
|
398
|
-
Instead of performing API requests it stores them in `requests` hash.
|
390
|
+
There is a `Telegram::Bot::ClientStub` class to stub client for tests.
|
391
|
+
Instead of performing API requests it stores them in a `requests` hash.
|
399
392
|
|
400
393
|
To stub all possible clients use `Telegram::Bot::ClientStub.stub_all!` before
|
401
|
-
initializing clients. Here is template for RSpec:
|
394
|
+
initializing clients. Here is a template for RSpec:
|
402
395
|
|
403
396
|
```ruby
|
404
397
|
# environments/test.rb
|
@@ -416,48 +409,83 @@ RSpec.configure do |config|
|
|
416
409
|
end
|
417
410
|
```
|
418
411
|
|
419
|
-
|
412
|
+
RSpec contexts and helpers are included automatically for groups and examples with matching
|
413
|
+
tags. In RSpec < 3.4 it's required to use `include_context` explicitly.
|
414
|
+
See [list of available helpers](https://github.com/telegram-bot-rb/telegram-bot/tree/master/lib/telegram/bot/rspec)
|
415
|
+
for details.
|
416
|
+
|
417
|
+
There are 3 types of integration tests:
|
418
|
+
|
419
|
+
- `:rails` - for testing bot in webhooks-mode in Rails application.
|
420
|
+
It simulates webhook requests POSTing data to controller's endpoint.
|
421
|
+
It works on the top of requests specs, so `rspec-rails` gem is required.
|
422
|
+
- `:rack` - For testing bot in webhooks-mode in non-Rails application.
|
423
|
+
It uses `rack-test` gem to POST requests to bot's endpoint.
|
424
|
+
- `:poller` - Calls `.dispatch` directly on controller class.
|
425
|
+
|
426
|
+
Pick the appropriate one, then require `telegram/bot/rspec/integration/#{type}`
|
427
|
+
and mark spec group with tag `telegram_bot: type`. See configuration options
|
428
|
+
for each type in
|
429
|
+
[telegram/bot/rspec/integration/](https://github.com/telegram-bot-rb/telegram-bot/tree/master/lib/telegram/bot/rspec/integration).
|
430
|
+
|
431
|
+
Here is an example test for a Rails app:
|
420
432
|
|
421
433
|
```ruby
|
422
434
|
# spec/requests/telegram_webhooks_spec.rb
|
423
|
-
require 'telegram/bot/rspec/integration'
|
435
|
+
require 'telegram/bot/rspec/integration/rails'
|
436
|
+
|
437
|
+
RSpec.describe TelegramWebhooksController, telegram_bot: :rails do
|
438
|
+
# for old RSpec:
|
439
|
+
# include_context 'telegram/bot/integration/rails'
|
440
|
+
|
441
|
+
# Main method is #dispatch(update). Some helpers are:
|
442
|
+
# dispatch_message(text, options = {})
|
443
|
+
# dispatch_command(cmd, *args)
|
424
444
|
|
425
|
-
|
426
|
-
|
427
|
-
|
445
|
+
# Available matchers can be found in Telegram::Bot::RSpec::ClientMatchers.
|
446
|
+
it 'shows usage of basic matchers'
|
447
|
+
# The most basic one is #make_telegram_request(bot, endpoint, params_matcher)
|
448
|
+
expect { dispatch_command(:start) }.
|
449
|
+
to make_telegram_request(bot, :sendMessage, hash_including(text: 'msg text'))
|
428
450
|
|
429
|
-
|
451
|
+
# There are some shortcuts for dispatching basic updates and testing responses.
|
452
|
+
expect { dispatch_message('Hi') }.to send_telegram_message(bot, /msg regexp/, some: :option)
|
453
|
+
end
|
454
|
+
|
455
|
+
describe '#start!' do
|
430
456
|
subject { -> { dispatch_command :start } }
|
457
|
+
# Using built in matcher for `respond_to`:
|
431
458
|
it { should respond_with_message 'Hi there!' }
|
432
459
|
end
|
433
460
|
|
434
|
-
# There is context for callback queries with related matchers
|
461
|
+
# There is context for callback queries with related matchers,
|
462
|
+
# use :callback_query tag to include it.
|
435
463
|
describe '#hey_callback_query', :callback_query do
|
436
464
|
let(:data) { "hey:#{name}" }
|
437
465
|
let(:name) { 'Joe' }
|
438
466
|
it { should answer_callback_query('Hey Joe') }
|
439
467
|
it { should edit_current_message :text, text: 'Done' }
|
468
|
+
end
|
440
469
|
end
|
470
|
+
```
|
471
|
+
|
472
|
+
There is a context for testing bot controller in the way similar to Rails controller tests.
|
473
|
+
It's supposed to be a low-level alternative for integration tests. Among the differences is
|
474
|
+
that controller tests use a single controller instance for all dispatches in specific exaple,
|
475
|
+
session is stubbed (does not use configured store engine), and update is not serialized
|
476
|
+
so it also supports mocks. This can be useful for unit testing, but should not be used as
|
477
|
+
the default way to test the bot.
|
441
478
|
|
442
|
-
|
479
|
+
```ruby
|
443
480
|
require 'telegram/bot/updates_controller/rspec_helpers'
|
444
481
|
RSpec.describe TelegramWebhooksController, type: :telegram_bot_controller do
|
445
|
-
# for old
|
482
|
+
# for old RSpec:
|
446
483
|
# include_context 'telegram/bot/updates_controller'
|
447
|
-
end
|
448
|
-
|
449
|
-
# Matchers are available for custom specs:
|
450
|
-
include Telegram::Bot::RSpec::ClientMatchers
|
451
484
|
|
452
|
-
|
453
|
-
|
454
|
-
to make_telegram_request(bot, :sendMessage, hash_including(text: 'msg text'))
|
485
|
+
# Same helpers and matchers like dispatch_command, answer_callback_query are available here.
|
486
|
+
end
|
455
487
|
```
|
456
488
|
|
457
|
-
Place integration tests inside `spec/requests`
|
458
|
-
when using RSpec's `infer_spec_type_from_file_location!`,
|
459
|
-
or just add `type: :request` to `describe`.
|
460
|
-
|
461
489
|
See sample app for more examples.
|
462
490
|
|
463
491
|
### Deployment
|
data/lib/telegram/bot.rb
CHANGED
@@ -14,10 +14,10 @@ module Telegram
|
|
14
14
|
|
15
15
|
module_function
|
16
16
|
|
17
|
-
def
|
17
|
+
def deprecation_0_15
|
18
18
|
@deprecation ||= begin
|
19
19
|
require 'active_support/deprecation'
|
20
|
-
ActiveSupport::Deprecation.new('0.
|
20
|
+
ActiveSupport::Deprecation.new('0.15', 'Telegram::Bot')
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/core_ext/hash/indifferent_access'
|
3
3
|
require 'active_support/json'
|
4
|
-
require 'action_dispatch
|
5
|
-
require 'action_dispatch/http/request'
|
4
|
+
require 'action_dispatch'
|
6
5
|
|
7
6
|
module Telegram
|
8
7
|
module Bot
|
@@ -24,33 +24,6 @@ module Telegram
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
# # Create routes for all Telegram.bots to use same controller:
|
28
|
-
# telegram_webhooks TelegramController
|
29
|
-
#
|
30
|
-
# # Or pass custom bots usin any of supported config options:
|
31
|
-
# telegram_webhooks TelegramController, [
|
32
|
-
# bot,
|
33
|
-
# {token: token, username: username},
|
34
|
-
# other_bot_token,
|
35
|
-
# ]
|
36
|
-
def telegram_webhooks(controllers, bots = nil, **options)
|
37
|
-
Bot.deprecation_0_14.deprecation_warning(:telegram_webhooks, <<-TXT.strip_heredoc)
|
38
|
-
It brings unnecessary complexity and encourages writeng less readable code.
|
39
|
-
Please use telegram_webhook method instead.
|
40
|
-
It's signature `telegram_webhook(controller, bot = :default, **options)`.
|
41
|
-
Multiple-bot environments now requires calling this method in a loop
|
42
|
-
or using statement for each bot.
|
43
|
-
TXT
|
44
|
-
unless controllers.is_a?(Hash)
|
45
|
-
bots = bots ? Array.wrap(bots) : Telegram.bots.values
|
46
|
-
controllers = Hash[bots.map { |x| [x, controllers] }]
|
47
|
-
end
|
48
|
-
controllers.each do |bot, controller|
|
49
|
-
controller, bot_options = controller if controller.is_a?(Array)
|
50
|
-
telegram_webhook(controller, bot, options.merge(bot_options || {}))
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
27
|
# Define route which processes requests using given controller and bot.
|
55
28
|
#
|
56
29
|
# telegram_webhook TelegramController, bot
|
data/lib/telegram/bot/rspec.rb
CHANGED
@@ -2,6 +2,15 @@ module Telegram
|
|
2
2
|
module Bot
|
3
3
|
module RSpec
|
4
4
|
autoload :ClientMatchers, 'telegram/bot/rspec/client_matchers'
|
5
|
+
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Yelds a block if `include_context` is supported.
|
9
|
+
def with_include_context
|
10
|
+
::RSpec.configure do |config|
|
11
|
+
yield(config) if config.respond_to?(:include_context)
|
12
|
+
end
|
13
|
+
end
|
5
14
|
end
|
6
15
|
end
|
7
16
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'telegram/bot/rspec'
|
2
|
+
require 'telegram/bot/rspec/message_helpers'
|
3
|
+
|
4
|
+
# Shared helpers for testing callback query updates.
|
5
|
+
RSpec.shared_context 'telegram/bot/callback_query' do
|
6
|
+
include_context 'telegram/bot/message_helpers'
|
7
|
+
|
8
|
+
subject { -> { dispatch callback_query: payload } }
|
9
|
+
let(:payload) { {id: callback_query_id, from: from, message: message, data: data} }
|
10
|
+
let(:callback_query_id) { 11 }
|
11
|
+
let(:message_id) { 22 }
|
12
|
+
let(:message) { {message_id: message_id, chat: chat, text: 'message text'} }
|
13
|
+
let(:data) { raise '`let(:data) { "callback query data here" }` is required' }
|
14
|
+
|
15
|
+
# Matcher to check that origin message got edited.
|
16
|
+
def edit_current_message(type, options = {})
|
17
|
+
description = 'edit current message'
|
18
|
+
options = options.merge(
|
19
|
+
message_id: message[:message_id],
|
20
|
+
chat_id: chat_id,
|
21
|
+
)
|
22
|
+
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
23
|
+
bot, :"editMessage#{type.to_s.camelize}", description: description
|
24
|
+
).with(hash_including(options))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Matcher to check that callback query is answered.
|
28
|
+
def answer_callback_query(text = Regexp.new(''), options = {})
|
29
|
+
description = "answer callback query with #{text.inspect}"
|
30
|
+
text = a_string_matching(text) if text.is_a?(Regexp)
|
31
|
+
options = options.merge(
|
32
|
+
callback_query_id: payload[:id],
|
33
|
+
text: text,
|
34
|
+
)
|
35
|
+
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
36
|
+
bot, :answerCallbackQuery, description: description
|
37
|
+
).with(hash_including(options))
|
38
|
+
end
|
39
|
+
end
|
@@ -1,85 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Rails.application.routes.url_helpers.public_send("#{route_name}_path")
|
11
|
-
end
|
12
|
-
let(:request_headers) do
|
13
|
-
{
|
14
|
-
'ACCEPT' => 'application/json',
|
15
|
-
'Content-Type' => 'application/json',
|
16
|
-
}
|
17
|
-
end
|
18
|
-
let(:clear_session?) { described_class.respond_to?(:session_store) }
|
19
|
-
before { described_class.session_store.try!(:clear) if clear_session? }
|
20
|
-
|
21
|
-
include Telegram::Bot::RSpec::ClientMatchers
|
22
|
-
|
23
|
-
def dispatch(update)
|
24
|
-
if ActionPack::VERSION::MAJOR >= 5
|
25
|
-
post(controller_path, params: update.to_json, headers: request_headers)
|
26
|
-
else
|
27
|
-
post(controller_path, update.to_json, request_headers)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def dispatch_message(text, options = {})
|
32
|
-
dispatch message: default_message_options.merge(options).merge(text: text)
|
33
|
-
end
|
34
|
-
|
35
|
-
def dispatch_command(*args)
|
36
|
-
options = args.last.is_a?(Hash) ? args.pop : {}
|
37
|
-
dispatch_message("/#{args.join ' '}", options)
|
38
|
-
end
|
39
|
-
|
40
|
-
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
41
|
-
def respond_with_message(expected = Regexp.new(''))
|
42
|
-
raise 'Define chat_id to use respond_with_message' unless defined?(chat_id)
|
43
|
-
send_telegram_message(bot, expected, chat_id: chat_id)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
RSpec.shared_context 'telegram/bot/callback_query', callback_query: true do
|
48
|
-
include_context 'telegram/bot/integration'
|
49
|
-
|
50
|
-
subject { -> { dispatch callback_query: payload } }
|
51
|
-
let(:payload) { {id: 11, from: from, message: message, data: data} }
|
52
|
-
let(:message) { {message_id: 22, chat: chat, text: 'message text'} }
|
53
|
-
|
54
|
-
# Matcher to check that origin message got edited.
|
55
|
-
def edit_current_message(type, options = {})
|
56
|
-
description = 'edit current message'
|
57
|
-
options = options.merge(
|
58
|
-
message_id: message[:message_id],
|
59
|
-
chat_id: chat_id,
|
60
|
-
)
|
61
|
-
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
62
|
-
bot, :"editMessage#{type.to_s.camelize}", description: description
|
63
|
-
).with(hash_including(options))
|
64
|
-
end
|
65
|
-
|
66
|
-
# Matcher to check that callback query is answered.
|
67
|
-
def answer_callback_query(text = Regexp.new(''), options = {})
|
68
|
-
description = "answer callback query with #{text.inspect}"
|
69
|
-
text = a_string_matching(text) if text.is_a?(Regexp)
|
70
|
-
options = options.merge(
|
71
|
-
callback_query_id: payload[:id],
|
72
|
-
text: text,
|
73
|
-
)
|
74
|
-
Telegram::Bot::RSpec::ClientMatchers::MakeTelegramRequest.new(
|
75
|
-
bot, :answerCallbackQuery, description: description
|
76
|
-
).with(hash_including(options))
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
RSpec.configure do |config|
|
81
|
-
if config.respond_to?(:include_context)
|
82
|
-
config.include_context 'telegram/bot/integration', :telegram_bot
|
83
|
-
config.include_context 'telegram/bot/callback_query', :telegram_bot, :callback_query
|
84
|
-
end
|
1
|
+
require 'telegram/bot'
|
2
|
+
Telegram::Bot.deprecation_0_15.warn(
|
3
|
+
"`require 'telegram/bot/rspec/integration'` is deprecated in favor of " \
|
4
|
+
"`require 'telegram/bot/rspec/integration/rails'`"
|
5
|
+
)
|
6
|
+
require 'telegram/bot/rspec/integration/rails'
|
7
|
+
|
8
|
+
Telegram::Bot::RSpec.with_include_context do |config|
|
9
|
+
config.include_context 'telegram/bot/integration/rails', telegram_bot: true
|
85
10
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'telegram/bot/rspec/integration/shared'
|
2
|
+
|
3
|
+
RSpec.shared_context 'telegram/bot/integration/poller' do
|
4
|
+
include_context 'telegram/bot/integration/shared'
|
5
|
+
let(:controller_class) { described_class }
|
6
|
+
|
7
|
+
def dispatch(update)
|
8
|
+
controller_class.dispatch(bot, update.as_json)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Telegram::Bot::RSpec.with_include_context do |config|
|
13
|
+
config.include_context 'telegram/bot/integration/poller', telegram_bot: :poller
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'telegram/bot/rspec/integration/shared'
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
RSpec.shared_context 'telegram/bot/integration/rack' do
|
5
|
+
include_context 'telegram/bot/integration/shared'
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
let(:request_path) { raise '`let(:request_path) { path to bot }` is required' }
|
9
|
+
let(:app) { raise '`let(:app) { your rack app here }` is required' }
|
10
|
+
let(:request_headers) do
|
11
|
+
{
|
12
|
+
'ACCEPT' => 'application/json',
|
13
|
+
'CONTENT_TYPE' => 'application/json',
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def dispatch(update)
|
18
|
+
post request_path, update.to_json, request_headers
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Telegram::Bot::RSpec.with_include_context do |config|
|
23
|
+
config.include_context 'telegram/bot/integration/rack', telegram_bot: :rack
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'telegram/bot/rspec/integration/shared'
|
2
|
+
|
3
|
+
RSpec.shared_context 'telegram/bot/integration/rails', type: :request do
|
4
|
+
include_context 'telegram/bot/integration/shared'
|
5
|
+
|
6
|
+
let(:controller_path) do
|
7
|
+
route_name = Telegram::Bot::RoutesHelper.route_name_for_bot(bot)
|
8
|
+
Rails.application.routes.url_helpers.public_send("#{route_name}_path")
|
9
|
+
end
|
10
|
+
let(:request_headers) do
|
11
|
+
{
|
12
|
+
'Accept' => 'application/json',
|
13
|
+
'Content-Type' => 'application/json',
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def dispatch(update)
|
18
|
+
if ActionPack::VERSION::MAJOR >= 5
|
19
|
+
post(controller_path, params: update.to_json, headers: request_headers)
|
20
|
+
else
|
21
|
+
post(controller_path, update.to_json, request_headers)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Telegram::Bot::RSpec.with_include_context do |config|
|
27
|
+
config.include_context 'telegram/bot/integration/rails', telegram_bot: :rails
|
28
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
require 'telegram/bot'
|
3
|
+
require 'telegram/bot/rspec/message_helpers'
|
4
|
+
require 'telegram/bot/rspec/callback_query_helpers'
|
5
|
+
|
6
|
+
RSpec.shared_context 'telegram/bot/integration/shared' do
|
7
|
+
include Telegram::Bot::RSpec::ClientMatchers
|
8
|
+
include_context 'telegram/bot/message_helpers'
|
9
|
+
include_context 'telegram/bot/callback_query', :callback_query
|
10
|
+
|
11
|
+
let(:bot) { Telegram.bot }
|
12
|
+
let(:clear_session?) { described_class.respond_to?(:session_store) }
|
13
|
+
before { described_class.session_store.try!(:clear) if clear_session? }
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Shared helpers for testing message updates.
|
2
|
+
RSpec.shared_context 'telegram/bot/message_helpers' do
|
3
|
+
let(:default_message_options) { {from: from, chat: chat} }
|
4
|
+
let(:from) { {id: from_id} }
|
5
|
+
let(:from_id) { 123 }
|
6
|
+
let(:chat) { {id: chat_id} }
|
7
|
+
let(:chat_id) { 456 }
|
8
|
+
|
9
|
+
# Shortcut for dispatching messages with default params.
|
10
|
+
def dispatch_message(text, options = {})
|
11
|
+
dispatch message: default_message_options.merge(options).merge(text: text)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Dispatch command message.
|
15
|
+
def dispatch_command(cmd, *args)
|
16
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
17
|
+
args.unshift("/#{cmd}")
|
18
|
+
dispatch_message(args.join(' '), options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
22
|
+
def respond_with_message(expected = Regexp.new(''))
|
23
|
+
raise 'Define chat_id to use respond_with_message' unless defined?(chat_id)
|
24
|
+
send_telegram_message(bot, expected, chat_id: chat_id)
|
25
|
+
end
|
26
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'abstract_controller'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
2
3
|
require 'active_support/callbacks'
|
3
4
|
require 'active_support/version'
|
4
5
|
|
@@ -54,12 +55,14 @@ module Telegram
|
|
54
55
|
abstract!
|
55
56
|
|
56
57
|
%w[
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
Commands
|
59
|
+
Instrumentation
|
60
|
+
LogSubscriber
|
61
|
+
ReplyHelpers
|
62
|
+
Rescue
|
63
|
+
Session
|
64
|
+
Translation
|
65
|
+
].each { |name| require "telegram/bot/updates_controller/#{name.underscore}" }
|
63
66
|
|
64
67
|
%w[
|
65
68
|
CallbackQueryContext
|
@@ -78,9 +81,12 @@ module Telegram
|
|
78
81
|
skip_after_callbacks_if_terminated: true
|
79
82
|
end
|
80
83
|
|
81
|
-
include
|
84
|
+
include Commands
|
82
85
|
include Rescue
|
83
86
|
include ReplyHelpers
|
87
|
+
include Translation
|
88
|
+
# Add instrumentations hooks at the bottom, to ensure they instrument
|
89
|
+
# all the methods properly.
|
84
90
|
include Instrumentation
|
85
91
|
|
86
92
|
extend Session::ConfigMethods
|
@@ -96,8 +102,6 @@ module Telegram
|
|
96
102
|
shipping_query
|
97
103
|
pre_checkout_query
|
98
104
|
].freeze
|
99
|
-
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
|
100
|
-
CONFLICT_CMD_REGEX = Regexp.new("^(#{PAYLOAD_TYPES.join('|')}|\\d)")
|
101
105
|
|
102
106
|
class << self
|
103
107
|
# Initialize controller and process update.
|
@@ -105,27 +109,6 @@ module Telegram
|
|
105
109
|
new(*args).dispatch
|
106
110
|
end
|
107
111
|
|
108
|
-
# Overrid it to filter or transform commands.
|
109
|
-
# Default implementation is to convert to downcase and add `on_` prefix
|
110
|
-
# for conflicting commands.
|
111
|
-
def action_for_command(cmd)
|
112
|
-
cmd.downcase!
|
113
|
-
cmd.match(CONFLICT_CMD_REGEX) ? "on_#{cmd}" : cmd
|
114
|
-
end
|
115
|
-
|
116
|
-
# Fetches command from text message. All subsequent words are returned
|
117
|
-
# as arguments.
|
118
|
-
# If command has mention (eg. `/test@SomeBot`), it returns commands only
|
119
|
-
# for specified username. Set `username` to `true` to accept
|
120
|
-
# any commands.
|
121
|
-
def command_from_text(text, username = nil)
|
122
|
-
return unless text
|
123
|
-
match = text.match(CMD_REGEX)
|
124
|
-
return unless match
|
125
|
-
mention = match[3]
|
126
|
-
[match[1], text.split.drop(1)] if username == true || !mention || mention == username
|
127
|
-
end
|
128
|
-
|
129
112
|
def payload_from_update(update)
|
130
113
|
update && PAYLOAD_TYPES.find do |type|
|
131
114
|
item = update[type]
|
@@ -134,8 +117,7 @@ module Telegram
|
|
134
117
|
end
|
135
118
|
end
|
136
119
|
|
137
|
-
attr_internal_reader :update, :bot, :payload, :payload_type
|
138
|
-
alias_method :command?, :is_command
|
120
|
+
attr_internal_reader :update, :bot, :payload, :payload_type
|
139
121
|
delegate :username, to: :bot, prefix: true, allow_nil: true
|
140
122
|
|
141
123
|
# Second argument can be either update object with hash access & string
|
@@ -175,54 +157,64 @@ module Telegram
|
|
175
157
|
|
176
158
|
# Processes current update.
|
177
159
|
def dispatch
|
178
|
-
|
160
|
+
action, args = action_for_payload
|
179
161
|
process(action, *args)
|
180
162
|
end
|
181
163
|
|
164
|
+
attr_internal_reader :action_options
|
165
|
+
|
166
|
+
# It provides support for passing array as action, where first vaule
|
167
|
+
# is action name and second is action metadata.
|
168
|
+
# This metadata is stored inside action_options
|
169
|
+
def process(action, *args)
|
170
|
+
action, options = action if action.is_a?(Array)
|
171
|
+
@_action_options = options || {}
|
172
|
+
super
|
173
|
+
end
|
174
|
+
|
175
|
+
# There are multiple ways how action name is calculated for update
|
176
|
+
# (see Commands, MessageContext, etc.). This method represents the
|
177
|
+
# way how action was calculated for current udpate.
|
178
|
+
#
|
179
|
+
# Some of possible values are `:payload, :command, :message_context`.
|
180
|
+
def action_type
|
181
|
+
action_options[:type] || :payload
|
182
|
+
end
|
183
|
+
|
182
184
|
# Calculates action name and args for payload.
|
183
185
|
# Uses `action_for_#{payload_type}` methods.
|
184
186
|
# If this method doesn't return anything
|
185
187
|
# it uses fallback with action same as payload type.
|
186
|
-
# Returns array `[
|
188
|
+
# Returns array `[action, args]`.
|
187
189
|
def action_for_payload
|
188
190
|
if payload_type
|
189
191
|
send("action_for_#{payload_type}") || action_for_default_payload
|
190
192
|
else
|
191
|
-
[
|
193
|
+
[:unsupported_payload_type, []]
|
192
194
|
end
|
193
195
|
end
|
194
196
|
|
195
197
|
def action_for_default_payload
|
196
|
-
[
|
197
|
-
end
|
198
|
-
|
199
|
-
# If payload is a message with command, then returned action is an
|
200
|
-
# action for this command.
|
201
|
-
# Separate method, so it can be easily overriden (ex. MessageContext).
|
202
|
-
#
|
203
|
-
# This is not used for edited messages/posts. It process them as basic updates.
|
204
|
-
def action_for_message
|
205
|
-
cmd, args = self.class.command_from_text(payload['text'], bot_username)
|
206
|
-
cmd &&= self.class.action_for_command(cmd)
|
207
|
-
[true, cmd, args] if cmd
|
198
|
+
[payload_type, [payload]]
|
208
199
|
end
|
209
|
-
alias_method :action_for_channel_post, :action_for_message
|
210
200
|
|
211
201
|
def action_for_inline_query
|
212
|
-
[
|
202
|
+
[payload_type, [payload['query'], payload['offset']]]
|
213
203
|
end
|
214
204
|
|
215
205
|
def action_for_chosen_inline_result
|
216
|
-
[
|
206
|
+
[payload_type, [payload['result_id'], payload['query']]]
|
217
207
|
end
|
218
208
|
|
219
209
|
def action_for_callback_query
|
220
|
-
[
|
210
|
+
[payload_type, [payload['data']]]
|
221
211
|
end
|
222
212
|
|
223
|
-
# Silently ignore unsupported messages
|
224
|
-
#
|
225
|
-
def action_missing(*)
|
213
|
+
# Silently ignore unsupported messages to not fail when user crafts
|
214
|
+
# an update with usupported command, callback query context, etc.
|
215
|
+
def action_missing(action, *_args)
|
216
|
+
logger.debug { "The action '#{action}' is not defined in #{self.class.name}" } if logger
|
217
|
+
nil
|
226
218
|
end
|
227
219
|
|
228
220
|
PAYLOAD_TYPES.each do |type|
|
@@ -17,8 +17,12 @@ module Telegram
|
|
17
17
|
context, new_data = context_from_callback_query
|
18
18
|
if context
|
19
19
|
action_name = "#{context}_callback_query"
|
20
|
-
|
21
|
-
|
20
|
+
if action_method?(action_name)
|
21
|
+
action_options = {type: :callback_query_context, context: context}
|
22
|
+
return [[action_name, action_options], [new_data]]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
super
|
22
26
|
end
|
23
27
|
|
24
28
|
def context_from_callback_query
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Telegram
|
2
|
+
module Bot
|
3
|
+
class UpdatesController
|
4
|
+
# Support for parsing commands
|
5
|
+
module Commands
|
6
|
+
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# Fetches command from text message. All subsequent words are returned
|
10
|
+
# as arguments.
|
11
|
+
# If command has mention (eg. `/test@SomeBot`), it returns commands only
|
12
|
+
# for specified username. Set `username` to `true` to accept
|
13
|
+
# any commands.
|
14
|
+
def command_from_text(text, username = nil)
|
15
|
+
return unless text
|
16
|
+
match = text.match(CMD_REGEX)
|
17
|
+
return unless match
|
18
|
+
mention = match[3]
|
19
|
+
[match[1], text.split.drop(1)] if username == true || !mention || mention == username
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Override it to filter or transform commands.
|
24
|
+
# Default implementation is to downcase and add `!` suffix.
|
25
|
+
def action_for_command(cmd)
|
26
|
+
"#{cmd.downcase}!"
|
27
|
+
end
|
28
|
+
|
29
|
+
# If payload is a message with command, then returned action is an
|
30
|
+
# action for this command.
|
31
|
+
# Separate method, so it can be easily overriden (ex. MessageContext).
|
32
|
+
#
|
33
|
+
# This is not used for edited messages/posts. It process them as basic updates.
|
34
|
+
def action_for_message
|
35
|
+
cmd, args = Commands.command_from_text(payload['text'], bot_username)
|
36
|
+
return unless cmd
|
37
|
+
[[action_for_command(cmd), type: :command, command: cmd], args]
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :action_for_channel_post, :action_for_message
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -2,62 +2,42 @@ module Telegram
|
|
2
2
|
module Bot
|
3
3
|
class UpdatesController
|
4
4
|
# Allows to store context in session and treat next message according to this context.
|
5
|
+
#
|
6
|
+
# It provides `save_context` method to store method name
|
7
|
+
# to be used as action for next update:
|
8
|
+
#
|
9
|
+
# def set_location!(*)
|
10
|
+
# save_context(:set_location_from_message)
|
11
|
+
# respond_with :message, text: 'Where are you?'
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def set_location_from_messge(city = nil, *)
|
15
|
+
# # update
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # OR
|
19
|
+
# # This will support both `/set_location city_name`, and `/set_location`
|
20
|
+
# # with subsequent refinement.
|
21
|
+
# def set_location!(city = nil, *)
|
22
|
+
# if city
|
23
|
+
# # update
|
24
|
+
# else
|
25
|
+
# save_context(:set_location!)
|
26
|
+
# respond_with :message, text: 'Where are you?'
|
27
|
+
# end
|
28
|
+
# end
|
5
29
|
module MessageContext
|
6
30
|
extend ActiveSupport::Concern
|
7
31
|
|
8
32
|
include Session
|
9
33
|
|
10
|
-
module ClassMethods
|
11
|
-
def context_handlers
|
12
|
-
@_context_handlers ||= {}
|
13
|
-
end
|
14
|
-
|
15
|
-
# Registers handler for context.
|
16
|
-
#
|
17
|
-
# context_handler :rename do |*|
|
18
|
-
# resource.update!(name: payload['text'])
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# # To run other action with all the callbacks:
|
22
|
-
# context_handler :rename do |*words|
|
23
|
-
# process(:rename, *words)
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# # Or just
|
27
|
-
# context_handler :rename, :your_action_to_call
|
28
|
-
# context_handler :rename # to call :rename
|
29
|
-
#
|
30
|
-
def context_handler(context = nil, action = nil, &block)
|
31
|
-
context &&= context.to_sym
|
32
|
-
if block
|
33
|
-
action = "_context_handler_#{context}"
|
34
|
-
define_method(action, &block)
|
35
|
-
end
|
36
|
-
context_handlers[context] = action || context
|
37
|
-
end
|
38
|
-
|
39
|
-
attr_reader :context_to_action
|
40
|
-
|
41
|
-
# Use it to use context value as action name for all contexts
|
42
|
-
# which miss handlers.
|
43
|
-
# For security reasons it supports only action methods and will
|
44
|
-
# raise AbstractController::ActionNotFound if context is invalid.
|
45
|
-
def context_to_action!
|
46
|
-
@context_to_action = true
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
34
|
# Action to clear context.
|
51
|
-
def cancel
|
35
|
+
def cancel!
|
52
36
|
# Context is already cleared in action_for_message
|
53
37
|
end
|
54
38
|
|
55
39
|
private
|
56
40
|
|
57
|
-
# Context is read from the session to treat messages
|
58
|
-
# according to previous request.
|
59
|
-
attr_reader :context
|
60
|
-
|
61
41
|
# Controller may have multiple sessions, let it be possible
|
62
42
|
# to select session for message context.
|
63
43
|
def message_context_session
|
@@ -68,10 +48,11 @@ module Telegram
|
|
68
48
|
# it has higher priority than contextual action.
|
69
49
|
def action_for_message
|
70
50
|
val = message_context_session.delete(:context)
|
71
|
-
|
51
|
+
context = val && val.to_s
|
72
52
|
super || context && begin
|
73
|
-
|
74
|
-
|
53
|
+
args = payload['text'].try!(:split) || []
|
54
|
+
action = action_for_message_context(context)
|
55
|
+
[[action, type: :message_context, context: context], args]
|
75
56
|
end
|
76
57
|
end
|
77
58
|
|
@@ -80,18 +61,16 @@ module Telegram
|
|
80
61
|
message_context_session[:context] = context
|
81
62
|
end
|
82
63
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
action_name
|
94
|
-
end
|
64
|
+
# Returns action name for message context. By default it's the same as context name.
|
65
|
+
# Raises AbstractController::ActionNotFound if action is not available.
|
66
|
+
# This differs from other cases where invalid actions are silently ignored,
|
67
|
+
# because message context is controlled by developer, and users are not able
|
68
|
+
# to construct update to run any specific context.
|
69
|
+
def action_for_message_context(context)
|
70
|
+
action = context.to_s
|
71
|
+
return action if action_method?(action)
|
72
|
+
raise AbstractController::ActionNotFound,
|
73
|
+
"The context action '#{action}' is not found in #{self.class.name}"
|
95
74
|
end
|
96
75
|
end
|
97
76
|
end
|
@@ -1,37 +1,32 @@
|
|
1
1
|
require 'telegram/bot/updates_controller/testing'
|
2
|
+
require 'telegram/bot/rspec/message_helpers'
|
3
|
+
require 'telegram/bot/rspec/callback_query_helpers'
|
2
4
|
|
3
5
|
RSpec.shared_context 'telegram/bot/updates_controller' do
|
6
|
+
include Telegram::Bot::RSpec::ClientMatchers
|
7
|
+
include_context 'telegram/bot/message_helpers'
|
8
|
+
include_context 'telegram/bot/callback_query', :callback_query
|
9
|
+
|
4
10
|
let(:controller_class) { described_class }
|
5
11
|
let(:controller) do
|
6
|
-
controller_class.new(
|
12
|
+
controller_class.new(*controller_args).tap do |x|
|
7
13
|
x.extend Telegram::Bot::UpdatesController::Testing
|
8
14
|
end
|
9
15
|
end
|
10
|
-
let(:
|
16
|
+
let(:controller_args) { [bot, deep_stringify(update)] }
|
17
|
+
let(:update) { {payload_type => payload} }
|
11
18
|
let(:payload_type) { :some_type }
|
12
19
|
let(:payload) { double(:payload) }
|
13
20
|
let(:bot) { Telegram::Bot::ClientStub.new(bot_name) }
|
14
21
|
let(:bot_name) { 'bot' }
|
15
22
|
let(:session) { controller.send(:session) }
|
16
|
-
let(:from_id) { 123 }
|
17
|
-
let(:chat_id) { 456 }
|
18
|
-
let(:default_message_options) { {from: {id: from_id}, chat: {id: chat_id}} }
|
19
|
-
|
20
|
-
include Telegram::Bot::RSpec::ClientMatchers
|
21
|
-
|
22
|
-
def dispatch(bot = self.bot, update = self.update)
|
23
|
-
controller.dispatch_again(bot, update)
|
24
|
-
end
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def build_update(type, content)
|
32
|
-
deep_stringify type => content
|
24
|
+
# Process update.
|
25
|
+
def dispatch(update = self.update, bot = self.bot)
|
26
|
+
controller.dispatch_again(bot, deep_stringify(update))
|
33
27
|
end
|
34
28
|
|
29
|
+
# Same as `.as_json` but mocks-friendly.
|
35
30
|
def deep_stringify(input)
|
36
31
|
case input
|
37
32
|
when Array then input.map(&method(__callee__))
|
@@ -39,15 +34,8 @@ RSpec.shared_context 'telegram/bot/updates_controller' do
|
|
39
34
|
else input
|
40
35
|
end
|
41
36
|
end
|
42
|
-
|
43
|
-
# Matcher to check response. Make sure to define `let(:chat_id)`.
|
44
|
-
def respond_with_message(expected)
|
45
|
-
send_telegram_message(bot, expected, chat_id: chat_id)
|
46
|
-
end
|
47
37
|
end
|
48
38
|
|
49
|
-
RSpec.
|
50
|
-
|
51
|
-
config.include_context 'telegram/bot/updates_controller', type: :telegram_bot_controller
|
52
|
-
end
|
39
|
+
Telegram::Bot::RSpec.with_include_context do |config|
|
40
|
+
config.include_context 'telegram/bot/updates_controller', type: :telegram_bot_controller
|
53
41
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Telegram
|
2
|
+
module Bot
|
3
|
+
class UpdatesController
|
4
|
+
# Provides helpers similar to AbstractController::Translation
|
5
|
+
# but by default uses `action_name_i18n_key` in lazy translation keys
|
6
|
+
# which strips `!` from action names by default. This makes translating
|
7
|
+
# strings for commands more convenient.
|
8
|
+
#
|
9
|
+
# To disable this behaviour use `alias_method :action_name_i18n_key, :action_name`.
|
10
|
+
module Translation
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
# Class-level helper for lazy translations.
|
15
|
+
def translate(key, options = {})
|
16
|
+
key = "#{controller_path.tr('/', '.')}#{key}" if key.to_s.start_with?('.')
|
17
|
+
I18n.translate(key, options)
|
18
|
+
end
|
19
|
+
alias :t :translate
|
20
|
+
end
|
21
|
+
|
22
|
+
# See toplevel description.
|
23
|
+
def translate(key, options = {})
|
24
|
+
if key.to_s.start_with?('.')
|
25
|
+
path = controller_path.tr('/', '.')
|
26
|
+
defaults = [:"#{path}#{key}"]
|
27
|
+
defaults << options[:default] if options[:default]
|
28
|
+
options[:default] = defaults.flatten
|
29
|
+
key = "#{path}.#{action_name_i18n_key}#{key}"
|
30
|
+
end
|
31
|
+
I18n.translate(key, options)
|
32
|
+
end
|
33
|
+
alias :t :translate
|
34
|
+
|
35
|
+
# Strips trailing `!` from action_name.
|
36
|
+
def action_name_i18n_key
|
37
|
+
action_name.chomp('!')
|
38
|
+
end
|
39
|
+
|
40
|
+
def localize(*args)
|
41
|
+
I18n.localize(*args)
|
42
|
+
end
|
43
|
+
alias :l :localize
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/telegram/bot/version.rb
CHANGED
data/telegram-bot.gemspec
CHANGED
@@ -17,6 +17,9 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
+
spec.post_install_message = 'Breaking changes in v0.14! ' \
|
21
|
+
'See upgrade guide at https://github.com/telegram-bot-rb/telegram-bot/wiki/Upgrading-to-0.14'
|
22
|
+
|
20
23
|
spec.required_ruby_version = '~> 2.0'
|
21
24
|
|
22
25
|
spec.add_dependency 'actionpack', '>= 4.0', '< 6.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: telegram-bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Melentiev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -138,10 +138,17 @@ files:
|
|
138
138
|
- lib/telegram/bot/railtie.rb
|
139
139
|
- lib/telegram/bot/routes_helper.rb
|
140
140
|
- lib/telegram/bot/rspec.rb
|
141
|
+
- lib/telegram/bot/rspec/callback_query_helpers.rb
|
141
142
|
- lib/telegram/bot/rspec/client_matchers.rb
|
142
143
|
- lib/telegram/bot/rspec/integration.rb
|
144
|
+
- lib/telegram/bot/rspec/integration/poller.rb
|
145
|
+
- lib/telegram/bot/rspec/integration/rack.rb
|
146
|
+
- lib/telegram/bot/rspec/integration/rails.rb
|
147
|
+
- lib/telegram/bot/rspec/integration/shared.rb
|
148
|
+
- lib/telegram/bot/rspec/message_helpers.rb
|
143
149
|
- lib/telegram/bot/updates_controller.rb
|
144
150
|
- lib/telegram/bot/updates_controller/callback_query_context.rb
|
151
|
+
- lib/telegram/bot/updates_controller/commands.rb
|
145
152
|
- lib/telegram/bot/updates_controller/instrumentation.rb
|
146
153
|
- lib/telegram/bot/updates_controller/log_subscriber.rb
|
147
154
|
- lib/telegram/bot/updates_controller/message_context.rb
|
@@ -150,6 +157,7 @@ files:
|
|
150
157
|
- lib/telegram/bot/updates_controller/rspec_helpers.rb
|
151
158
|
- lib/telegram/bot/updates_controller/session.rb
|
152
159
|
- lib/telegram/bot/updates_controller/testing.rb
|
160
|
+
- lib/telegram/bot/updates_controller/translation.rb
|
153
161
|
- lib/telegram/bot/updates_controller/typed_update.rb
|
154
162
|
- lib/telegram/bot/updates_poller.rb
|
155
163
|
- lib/telegram/bot/version.rb
|
@@ -158,7 +166,7 @@ homepage: https://github.com/telegram-bot-rb/telegram-bot
|
|
158
166
|
licenses:
|
159
167
|
- MIT
|
160
168
|
metadata: {}
|
161
|
-
post_install_message:
|
169
|
+
post_install_message: Breaking changes in v0.14! See upgrade guide at https://github.com/telegram-bot-rb/telegram-bot/wiki/Upgrading-to-0.14
|
162
170
|
rdoc_options: []
|
163
171
|
require_paths:
|
164
172
|
- lib
|