1
0
зеркало из https://github.com/glebtv/telegram-bot.git synced 2026-09-03 17:55:52 +03:00

Сравнить коммиты

..

20 Коммитов

Автор SHA1 Сообщение Дата
Max Melentiev
b40e4b432d Merge pull request #198 from telegram-bot-rb/nested_files
Add support for editMessageMedia similar to sendMediaGroup
2023-01-14 13:18:38 +00:00
Max Melentiev
ef5ec81386 Add support for editMessageMedia similar to sendMediaGroup 2023-01-13 20:33:30 +00:00
Max Melentiev
7d8a19d3c8 Pass action parameter to RequestBodyFormatter 2022-03-13 21:39:55 +00:00
Max Melentiev
380f6686fc Update to Bot API 5.7 2022-03-12 19:37:53 +00:00
Max Melentiev
ea64230eab Merge pull request #168 from telegram-bot-rb/nested_files
Fix sending File objects in nested objects (ex., in sendMediaGroup)
2022-03-12 19:34:57 +00:00
Max Melentiev
5b9706ed47 Fix sending File objects in nested objects in sendMediaGroup 2022-03-12 19:33:17 +00:00
Max Melentiev
2d73d1c879 Merge pull request #174 from telegram-bot-rb/rails-7
Rails 7.0 support
2022-01-04 22:54:17 +00:00
Max Melentiev
88af1152cf Rails 7.0 support 2022-01-04 22:49:53 +00:00
Max Melentiev
586217585a Merge pull request #164 from KonstantinReido/patch-1
Fix typo in README.md
2021-08-20 12:36:46 +01:00
Konstantin Reido
f83bf92601 Fix typo in README.md 2021-08-20 11:26:00 +03:00
Max Melentiev
3049ced903 Fix tests 2021-06-26 21:25:43 +01:00
Max Melentiev
07faf87ed7 Merge pull request #163 from telegram-bot-rb/update_api
Update to Bot API 5.3
2021-06-25 19:43:17 +01:00
Max Melentiev
ac45940937 Switch from travis-ci.org to travis-ci.com 2021-06-25 19:42:59 +01:00
Max Melentiev
a49ef51da9 Update to Bot API 5.3 2021-06-25 19:31:28 +01:00
Max Melentiev
4f669fccc4 Merge pull request #157 from AlexVPopov/table-of-contents
Add a table of contents to README
2021-03-31 20:56:59 +01:00
Alexander Popov
e06252907a Add a table of contents to README 2021-03-31 21:11:08 +03:00
Max Melentiev
af229c8bcc Fix typos in readme, make some points more clear 2021-02-19 09:38:54 +00:00
Max Melentiev
a7cf3754be v0.15.3 2021-02-15 13:54:10 +00:00
Max Melentiev
783d9c13e9 Merge pull request #156 from telegram-bot-rb/ruby-3
Fix translation helpers to support ruby 3
2021-02-15 13:52:09 +00:00
Max Melentiev
5417511f06 Fix translation helpers to support ruby 3 2021-02-15 09:44:19 +00:00
22 изменённых файлов: 343 добавлений и 75 удалений

Просмотреть файл

@@ -1,3 +1,8 @@
appraise 'rails-70' do
gem 'actionpack', '~> 7.0.0'
gem 'railties', '~> 7.0.0'
end
appraise 'rails-61' do appraise 'rails-61' do
gem 'actionpack', '~> 6.1.0' gem 'actionpack', '~> 6.1.0'
gem 'railties', '~> 6.1.0' gem 'railties', '~> 6.1.0'

Просмотреть файл

@@ -1,5 +1,23 @@
# Unreleased # Unreleased
# 0.15.7
- Add support for editMessageMedia similar to sendMediaGroup.
# 0.15.6
- Rails 7.0 support.
- Fix sending File objects in nested objects in sendMediaGroup.
- Update to Bot API 5.7
# 0.15.4
- Update to Bot API 5.3
# 0.15.3
- Ruby 3.0 support: fix translation helpers.
# 0.15.2 # 0.15.2
- Ruby 3.0 support. Drop support for Ruby < 2.4. - Ruby 3.0 support. Drop support for Ruby < 2.4.

Просмотреть файл

@@ -8,7 +8,7 @@ group :development do
gem 'pry-byebug', '~> 3.9.0' gem 'pry-byebug', '~> 3.9.0'
gem 'sdoc', '~> 2.0.3' gem 'sdoc', '~> 2.0.3'
gem 'telegram-bot-types', '~> 0.6.2' gem 'telegram-bot-types', '~> 0.6.3'
gem 'rspec', '~> 3.10.0' gem 'rspec', '~> 3.10.0'
gem 'rspec-its', '~> 1.3.0' gem 'rspec-its', '~> 1.3.0'

Просмотреть файл

@@ -2,7 +2,7 @@
[![Gem Version](https://badge.fury.io/rb/telegram-bot.svg)](http://badge.fury.io/rb/telegram-bot) [![Gem Version](https://badge.fury.io/rb/telegram-bot.svg)](http://badge.fury.io/rb/telegram-bot)
[![Code Climate](https://codeclimate.com/github/telegram-bot-rb/telegram-bot/badges/gpa.svg)](https://codeclimate.com/github/telegram-bot-rb/telegram-bot) [![Code Climate](https://codeclimate.com/github/telegram-bot-rb/telegram-bot/badges/gpa.svg)](https://codeclimate.com/github/telegram-bot-rb/telegram-bot)
[![Build Status](https://travis-ci.org/telegram-bot-rb/telegram-bot.svg)](https://travis-ci.org/telegram-bot-rb/telegram-bot) [![Build Status](https://app.travis-ci.com/telegram-bot-rb/telegram-bot.svg)](https://app.travis-ci.com/github/telegram-bot-rb/telegram-bot)
Tools for developing Telegram bots. Best used with Rails, but can be used in Tools for developing Telegram bots. Best used with Rails, but can be used in
[standalone app](https://github.com/telegram-bot-rb/telegram-bot/wiki/Not-rails-application). [standalone app](https://github.com/telegram-bot-rb/telegram-bot/wiki/Not-rails-application).
@@ -25,9 +25,33 @@ with session, keyboards and inline queries.
Run it on your local machine in 1 minute! Run it on your local machine in 1 minute!
And here is [app template](https://github.com/telegram-bot-rb/rails_template) And here is [app template](https://github.com/telegram-bot-rb/rails_template)
to generate clean app in seconds. to generate new rails app in seconds.
Examples and cookbook in [wiki](https://github.com/telegram-bot-rb/telegram-bot/wiki). See examples and cookbook in [the wiki](https://github.com/telegram-bot-rb/telegram-bot/wiki).
## Table of Contents
* [Installation](#installation)
* [Usage](#usage)
* [Configuration](#configuration)
* [Configuration in Rails app](#configuration-in-rails-app)
* [Client](#client)
* [Typed responses](#typed-responses)
* [Controller](#controller)
* [Reply helpers](#reply-helpers)
* [Optional typecasting](#optional-typecasting)
* [Session](#session)
* [Message context](#message-context)
* [Callback queries](#callback-queries)
* [Routes in Rails app](#routes-in-rails-app)
* [Processing updates](#processing-updates)
* [Development & Debugging](#development--debugging)
* [Testing](#testing)
* [Deployment](#deployment)
* [Async mode](#async-mode)
* [Limitations](#limitations)
* [Development](#development)
* [Contributing](#contributing)
## Installation ## Installation
@@ -39,11 +63,15 @@ gem 'telegram-bot'
And then execute: And then execute:
$ bundle ```
bundle
```
Or install it yourself as: Or install it yourself as:
$ gem install telegram-bot ```
gem install telegram-bot
```
Require if necessary: Require if necessary:
@@ -170,19 +198,18 @@ Bot controllers like usual rails controllers provides features like callbacks,
```ruby ```ruby
class Telegram::WebhookController < Telegram::Bot::UpdatesController class Telegram::WebhookController < Telegram::Bot::UpdatesController
# use callbacks like in any other controllers # use callbacks like in any other controller
around_action :with_locale around_action :with_locale
# Every update can have one of: message, inline_query, chosen_inline_result, # Every update has one of: message, inline_query, chosen_inline_result,
# callback_query, etc. # callback_query, etc.
# Define method with same name to respond to this updates. # Define method with the same name to handle this type of update.
def message(message) def message(message)
# message can be also accessed via instance method
message == self.payload # true
# store_message(message['text']) # store_message(message['text'])
end end
# This basic methods receives commonly used params: # For the following types of updates commonly used params are passed as arguments,
# full payload object is available with `payload` instance method.
# #
# message(payload) # message(payload)
# inline_query(query, offset) # inline_query(query, offset)
@@ -193,14 +220,19 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
# Command arguments will be parsed and passed to the method. # Command arguments will be parsed and passed to the method.
# Be sure to use splat args and default values to not get errors when # Be sure to use splat args and default values to not get errors when
# someone passed more or less arguments in the message. # someone passed more or less arguments in the message.
def start!(data = nil, *) def start!(word = nil, *other_words)
# do_smth_with(data) # do_smth_with(word)
# full message object is also available via `payload` instance method:
# process_raw_message(payload['text'])
# There are `chat` & `from` shortcut methods. # There are `chat` & `from` shortcut methods.
# For callback queries `chat` if taken from `message` when it's available. # For callback queries `chat` is taken from `message` when it's available.
response = from ? "Hello #{from['username']}!" : 'Hi there!' response = from ? "Hello #{from['username']}!" : 'Hi there!'
# There is `respond_with` helper to set `chat_id` from received message: # There is `respond_with` helper to set `chat_id` from received message:
respond_with :message, text: response respond_with :message, text: response
# `reply_with` also sets `reply_to_message_id`: # `reply_with` also sets `reply_to_message_id`:
reply_with :photo, photo: File.open('party.jpg') reply_with :photo, photo: File.open('party.jpg')
end end
@@ -223,10 +255,10 @@ end
#### Reply helpers #### Reply helpers
There are helpers to respond for basic actions. They just set chat/message/query There are helpers for basic responses. They just set chat/message/query
identifiers from update. See identifiers from the update. See
[`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb) [`ReplyHelpers`](https://github.com/telegram-bot-rb/telegram-bot/blob/master/lib/telegram/bot/updates_controller/reply_helpers.rb)
module for more information. Here are this methods signatures: module for more information. Here are these methods signatures:
```ruby ```ruby
def respond_with(type, params); end def respond_with(type, params); end
@@ -389,7 +421,7 @@ telegram_webhook TelegramAuctionController, :auction
telegram_webhook TelegramController, as: :custom_telegram_webhook telegram_webhook TelegramController, as: :custom_telegram_webhook
``` ```
#### Processesing updates #### Processing updates
To process update with controller call `.dispatch(bot, update)` on it. To process update with controller call `.dispatch(bot, update)` on it.
There are several options to run it automatically: There are several options to run it automatically:
@@ -507,7 +539,7 @@ end
There is a context for testing bot controller in the way similar to Rails controller tests. There is a context for testing bot controller in the way similar to Rails controller tests.
It's supposed to be a low-level alternative for integration tests. Among the differences is It's supposed to be a low-level alternative for integration tests. Among the differences is
that controller tests use a single controller instance for all dispatches in specific exaple, that controller tests use a single controller instance for all dispatches in specific example,
session is stubbed (does not use configured store engine), and update is not serialized session is stubbed (does not use configured store engine), and update is not serialized
so it also supports mocks. This can be useful for unit testing, but should not be used as so it also supports mocks. This can be useful for unit testing, but should not be used as
the default way to test the bot. the default way to test the bot.

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

Просмотреть файл

@@ -10,7 +10,7 @@ group :development do
gem "pry", "~> 0.13.1" gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0" gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3" gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.2" gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0" gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0" gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2" gem "rspec-rails", "~> 4.0.2"

21
gemfiles/rails_70.gemfile Обычный файл
Просмотреть файл

@@ -0,0 +1,21 @@
# This file was generated by Appraisal
source "https://rubygems.org"
gem "actionpack", "~> 7.0.0"
gem "railties", "~> 7.0.0"
group :development do
gem "appraisal", "~> 2.2"
gem "pry", "~> 0.13.1"
gem "pry-byebug", "~> 3.9.0"
gem "sdoc", "~> 2.0.3"
gem "telegram-bot-types", "~> 0.6.3"
gem "rspec", "~> 3.10.0"
gem "rspec-its", "~> 1.3.0"
gem "rspec-rails", "~> 4.0.2"
gem "rubocop", "~> 0.52.1"
gem "coveralls", "~> 0.8.23", require: false
end
gemspec path: "../"

Просмотреть файл

@@ -1,5 +1,4 @@
require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/hash/keys'
require 'json'
require 'httpclient' require 'httpclient'
module Telegram module Telegram
@@ -8,7 +7,9 @@ module Telegram
SERVER = 'https://api.telegram.org'.freeze SERVER = 'https://api.telegram.org'.freeze
URL_TEMPLATE = '%<server>s/bot%<token>s/'.freeze URL_TEMPLATE = '%<server>s/bot%<token>s/'.freeze
autoload :RequestBodyFormatter, 'telegram/bot/client/request_body_formatter'
autoload :TypedResponse, 'telegram/bot/client/typed_response' autoload :TypedResponse, 'telegram/bot/client/typed_response'
prepend Async prepend Async
include DebugClient include DebugClient
@@ -35,16 +36,8 @@ module Telegram
prepend TypedResponse prepend TypedResponse
end end
# Encodes nested hashes as json.
def prepare_body(body)
body = body.dup
body.each do |k, val|
body[k] = val.to_json if val.is_a?(Hash) || val.is_a?(Array)
end
end
def prepare_async_args(action, body = {}) def prepare_async_args(action, body = {})
[action.to_s, Async.prepare_hash(prepare_body(body))] [action.to_s, Async.prepare_hash(RequestBodyFormatter.format(body, action))]
end end
def error_for_response(response) def error_for_response(response)
@@ -70,7 +63,7 @@ module Telegram
end end
def request(action, body = {}) def request(action, body = {})
response = http_request("#{base_uri}#{action}", self.class.prepare_body(body)) response = http_request("#{base_uri}#{action}", RequestBodyFormatter.format(body, action))
raise self.class.error_for_response(response) if response.status >= 300 raise self.class.error_for_response(response) if response.status >= 300
JSON.parse(response.body) JSON.parse(response.body)
end end

Просмотреть файл

@@ -1,5 +1,5 @@
# Generated with bin/fetch-telegram-methods # Generated with bin/fetch-telegram-methods
# Bot API 5.0 # Bot API 5.7
getUpdates getUpdates
setWebhook setWebhook
@@ -30,13 +30,20 @@ sendDice
sendChatAction sendChatAction
getUserProfilePhotos getUserProfilePhotos
getFile getFile
kickChatMember banChatMember
unbanChatMember unbanChatMember
restrictChatMember restrictChatMember
promoteChatMember promoteChatMember
setChatAdministratorCustomTitle setChatAdministratorCustomTitle
banChatSenderChat
unbanChatSenderChat
setChatPermissions setChatPermissions
exportChatInviteLink exportChatInviteLink
createChatInviteLink
editChatInviteLink
revokeChatInviteLink
approveChatJoinRequest
declineChatJoinRequest
setChatPhoto setChatPhoto
deleteChatPhoto deleteChatPhoto
setChatTitle setChatTitle
@@ -47,12 +54,13 @@ unpinAllChatMessages
leaveChat leaveChat
getChat getChat
getChatAdministrators getChatAdministrators
getChatMembersCount getChatMemberCount
getChatMember getChatMember
setChatStickerSet setChatStickerSet
deleteChatStickerSet deleteChatStickerSet
answerCallbackQuery answerCallbackQuery
setMyCommands setMyCommands
deleteMyCommands
getMyCommands getMyCommands
editMessageText editMessageText

Просмотреть файл

@@ -0,0 +1,61 @@
require 'json'
module Telegram
module Bot
class Client
# Encodes nested hashes and arrays as json and extract File objects from them
# to the top level. Top-level File objects are handled by httpclient.
# More details: https://core.telegram.org/bots/api#sending-files
module RequestBodyFormatter
extend self
def format(body, action)
body = body.dup
case action.to_s
when 'sendMediaGroup'
extract_files_from_array!(body, :media)
when 'editMessageMedia'
replace_field(body, :media) do |value|
files = {}
extract_files_from_hash(value, files).tap { body.merge!(files) }
end
end
body.each do |key, val|
body[key] = val.to_json if val.is_a?(Hash) || val.is_a?(Array)
end
end
private
# Detects field by symbol or string name and replaces it with mapped value.
def replace_field(hash, field_name)
field_name = [field_name.to_sym, field_name.to_s].find { |x| hash.key?(x) }
hash[field_name] = yield hash[field_name] if field_name
end
def extract_files_from_array!(hash, field_name)
replace_field(hash, field_name) do |value|
break value unless value.is_a?(Array)
files = {}
value.map { |x| extract_files_from_hash(x, files) }.
tap { hash.merge!(files) }
end
end
# Replace File objects with `attach` URIs. File objects are added into `files` hash.
def extract_files_from_hash(hash, files)
return hash unless hash.is_a?(Hash)
hash.transform_values do |value|
if value.is_a?(File)
arg_name = "_file#{files.size}"
files[arg_name] = value
"attach://#{arg_name}"
else
value
end
end
end
end
end
end
end

Просмотреть файл

@@ -99,6 +99,8 @@ module Telegram
pre_checkout_query pre_checkout_query
poll poll
poll_answer poll_answer
my_chat_member
chat_member
].freeze ].freeze
class << self class << self

Просмотреть файл

@@ -12,15 +12,15 @@ module Telegram
module ClassMethods module ClassMethods
# Class-level helper for lazy translations. # Class-level helper for lazy translations.
def translate(key, options = {}) def translate(key, **options)
key = "#{controller_path.tr('/', '.')}#{key}" if key.to_s.start_with?('.') key = "#{controller_path.tr('/', '.')}#{key}" if key.to_s.start_with?('.')
I18n.translate(key, options) I18n.translate(key, **options)
end end
alias :t :translate alias :t :translate
end end
# See toplevel description. # See toplevel description.
def translate(key, options = {}) def translate(key, **options)
if key.to_s.start_with?('.') if key.to_s.start_with?('.')
path = controller_path.tr('/', '.') path = controller_path.tr('/', '.')
defaults = [:"#{path}#{key}"] defaults = [:"#{path}#{key}"]
@@ -28,7 +28,7 @@ module Telegram
options[:default] = defaults.flatten options[:default] = defaults.flatten
key = "#{path}.#{action_name_i18n_key}#{key}" key = "#{path}.#{action_name_i18n_key}#{key}"
end end
I18n.translate(key, options) I18n.translate(key, **options)
end end
alias :t :translate alias :t :translate

Просмотреть файл

@@ -1,6 +1,6 @@
module Telegram module Telegram
module Bot module Bot
VERSION = '0.15.2'.freeze VERSION = '0.15.7'.freeze
def self.gem_version def self.gem_version
Gem::Version.new VERSION Gem::Version.new VERSION

Просмотреть файл

@@ -0,0 +1,92 @@
RSpec.describe Telegram::Bot::Client::RequestBodyFormatter do
describe '.format' do
subject { described_class.format(input, action) }
let(:action) { :sendMessage }
context 'when plain hash is given' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
context 'when nested hash is given' do
let(:input) { {a: 1, b: '2', c: [1, 2], d: {a: 1}, e: {b: []}} }
it 'encodes nested hashes to json' do
expected = input.dup
%i[c d e].each { |x| expected[x] = expected[x].to_json }
should eq expected
end
end
context 'with sendMediaGroup action' do
let(:action) { :sendMediaGroup }
let(:input) { {media: [{a: file_1}, {'b' => file_2, c: 123}, {d: 456}], x: 789} }
let(:file_1) { File.new(__FILE__) }
let(:file_2) { File.new(__FILE__) }
it 'extracts files to the top-level' do
should eq(
media: [
{a: 'attach://_file0'},
{b: 'attach://_file1', c: 123},
{d: 456},
].to_json,
x: 789,
'_file0' => file_1,
'_file1' => file_2,
)
end
context 'and input has string keys' do
let(:input) { super().stringify_keys }
it 'extracts files to the top-level' do
should eq(
'media' => [
{a: 'attach://_file0'},
{b: 'attach://_file1', c: 123},
{d: 456},
].to_json,
'x' => 789,
'_file0' => file_1,
'_file1' => file_2,
)
end
end
context 'without media' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
end
context 'with editMessageMedia action' do
let(:action) { :editMessageMedia }
let(:input) { {media: {a: file, b: 123}, x: 789} }
let(:file) { File.new(__FILE__) }
it 'extracts files to the top-level' do
should eq(
media: {a: 'attach://_file0', b: 123}.to_json,
x: 789,
'_file0' => file,
)
end
context 'and input has string keys' do
let(:input) { super().stringify_keys }
it 'extracts files to the top-level' do
should eq(
'media' => {a: 'attach://_file0', b: 123}.to_json,
'x' => 789,
'_file0' => file,
)
end
end
context 'without media' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
end
end
end

Просмотреть файл

@@ -71,25 +71,6 @@ RSpec.describe Telegram::Bot::Client do
end end
end end
describe '.prepare_body' do
subject { described_class.prepare_body(input) }
context 'when plain hash is given' do
let(:input) { {a: 1, b: '2', c: nil} }
it { should eq input }
end
context 'when nested hash is given' do
let(:input) { {a: 1, b: '2', c: [1, 2], d: {a: 1}, e: {b: []}} }
it 'encodes nested hashes to json' do
expected = input.dup
%i[c d e].each { |x| expected[x] = expected[x].to_json }
should eq expected
end
end
end
describe '.prepare_async_args' do describe '.prepare_async_args' do
subject { described_class.prepare_async_args(*input) } subject { described_class.prepare_async_args(*input) }
let(:input) { [:action, a: 1, b: :sym, c: [:other], 'd' => 'str'] } let(:input) { [:action, a: 1, b: :sym, c: [:other], 'd' => 'str'] }
@@ -148,7 +129,8 @@ RSpec.describe Telegram::Bot::Client do
let(:body) { body_json.to_json } let(:body) { body_json.to_json }
let(:body_json) { {'param' => 'val', 'description' => 'some description'} } let(:body_json) { {'param' => 'val', 'description' => 'some description'} }
before do before do
expect(described_class).to receive(:prepare_body).with(request_body) { prepared_body } expect(Telegram::Bot::Client::RequestBodyFormatter).
to receive(:format).with(request_body, action) { prepared_body }
expect(instance).to receive(:http_request).with(url, prepared_body) { response } expect(instance).to receive(:http_request).with(url, prepared_body) { response }
end end
around { |ex| Telegram::Bot::ClientStub.stub_all!(false) { ex.run } } around { |ex| Telegram::Bot::ClientStub.stub_all!(false) { ex.run } }

Просмотреть файл

@@ -1,5 +1,26 @@
RSpec.describe Telegram::Bot::UpdatesController::Translation do RSpec.describe Telegram::Bot::UpdatesController::Translation do
def self.stub_translations(translations)
around do |ex|
backend = I18n.backend
I18n.backend = I18n::Backend::Simple.new
begin
I18n.backend.store_translations 'en', telegram: {webhooks: translations}
ex.run
ensure
I18n.backend = backend
end
end
end
let(:result) { double(:result) }
describe '#translate' do describe '#translate' do
stub_translations(
start: {
hello: 'Hello from start!',
hi: 'Hi %{name} from start', # rubocop:disable Style/FormatStringToken
},
)
let(:controller) do let(:controller) do
double( double(
controller_path: 'telegram/webhooks', controller_path: 'telegram/webhooks',
@@ -10,12 +31,28 @@ RSpec.describe Telegram::Bot::UpdatesController::Translation do
it 'uses action_name without ! for lazy translations' do it 'uses action_name without ! for lazy translations' do
expect(I18n).to receive(:translate).with('telegram.webhooks.start.hello', expect(I18n).to receive(:translate).with('telegram.webhooks.start.hello',
default: [:'telegram.webhooks.hello'], default: [:'telegram.webhooks.hello'],
) ) { result }
controller.t('.hello') expect(controller.t('.hello')).to eq(result)
expect(I18n).to receive(:translate).with('telegram.webhooks.start.hi',
default: [:'telegram.webhooks.hi'],
name: 'Dude',
) { result }
expect(controller.t('.hi', name: 'Dude')).to eq(result)
end
it 'translates' do
expect(controller.t('.hello')).to eq('Hello from start!')
expect(controller.t('.hi', name: 'Dude')).to eq('Hi Dude from start')
end end
end end
describe described_class::ClassMethods do describe described_class::ClassMethods do
stub_translations(
hello: 'Hello!',
hi: 'Hi %{name}', # rubocop:disable Style/FormatStringToken
)
describe '#translate' do describe '#translate' do
let(:controller_class) do let(:controller_class) do
double(controller_path: 'telegram/webhooks'). double(controller_path: 'telegram/webhooks').
@@ -23,8 +60,20 @@ RSpec.describe Telegram::Bot::UpdatesController::Translation do
end end
it 'uses controller_path for lazy translations' do it 'uses controller_path for lazy translations' do
expect(I18n).to receive(:translate).with('telegram.webhooks.hello', {}) expect(I18n).to receive(:translate) do |*args, **kwargs|
controller_class.t('.hello') # not using .with to support ruby 2.x and 3.x
expect([*args, kwargs]).to eq(['telegram.webhooks.hello', {}])
result
end
expect(controller_class.t('.hello')).to eq(result)
expect(I18n).to receive(:translate).with('telegram.webhooks.hi', name: 'Dude') { result }
expect(controller_class.t('.hi', name: 'Dude')).to eq(result)
end
it 'translates' do
expect(controller_class.t('.hello')).to eq('Hello!')
expect(controller_class.t('.hi', name: 'Dude')).to eq('Hi Dude')
end end
end end
end end

Просмотреть файл

@@ -9,14 +9,19 @@ RSpec.describe Telegram::Bot::UpdatesController::TypedUpdate do
context 'when `update` is a virtus model' do context 'when `update` is a virtus model' do
subject { controller } subject { controller }
unique_types = Telegram::Bot::UpdatesController::PAYLOAD_TYPES - %w[ unique_types = (Telegram::Bot::UpdatesController::PAYLOAD_TYPES - %w[
edited_message edited_message
channel_post channel_post
edited_channel_post edited_channel_post
] my_chat_member
unique_types.each do |type| chat_member
]).
map { |x| [x, Telegram::Bot::Types.const_get(x.camelize)] }.to_h.
merge(
'chat_member' => Telegram::Bot::Types::ChatMemberUpdated
)
unique_types.each do |type, type_class|
context "with #{type}" do context "with #{type}" do
type_class = Telegram::Bot::Types.const_get(type.camelize)
let(:payload_type) { type } let(:payload_type) { type }
let(:payload) do let(:payload) do
{}.tap do |result| {}.tap do |result|

Просмотреть файл

@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = '>= 2.4' spec.required_ruby_version = '>= 2.4'
spec.add_dependency 'actionpack', '>= 4.0', '< 6.2' spec.add_dependency 'actionpack', '>= 4.0', '< 7.1'
spec.add_dependency 'activesupport', '>= 4.0', '< 6.2' spec.add_dependency 'activesupport', '>= 4.0', '< 7.1'
spec.add_dependency 'httpclient', '~> 2.7' spec.add_dependency 'httpclient', '~> 2.7'
spec.add_development_dependency 'bundler', '> 1.16' spec.add_development_dependency 'bundler', '> 1.16'