telegram-bot 0.13.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Code Climate](https://codeclimate.com/github/telegram-bot-rb/telegram-bot/badges/gpa.svg)](https://codeclimate.com/github/telegram-bot-rb/telegram-bot)
|
5
5
|
[![Build Status](https://travis-ci.org/telegram-bot-rb/telegram-bot.svg)](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
|