1
0
зеркало из https://github.com/glebtv/telegram-bot.git synced 2026-09-04 10:15:50 +03:00
* Update rubopcop [WIP]

* Further rubocop fixes

* Fix rubocop-rails cops

* Fix spec

* Disable rubocop suggestions

* Run rubocop in github actions rather than in codeclimate
Этот коммит содержится в:
Max Melentiev
2023-12-30 15:20:27 +00:00
коммит произвёл GitHub
родитель 7bcb0caded
Коммит 57b17f068c
82 изменённых файлов: 303 добавлений и 134 удалений

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
namespace :telegram do
namespace :bot do
desc 'Run poller. It broadcasts Rails.logger to STDOUT in dev like `rails s` do. ' \
@@ -6,14 +8,14 @@ namespace :telegram do
ENV['BOT_POLLER_MODE'] = 'true'
Rake::Task['environment'].invoke
if ENV.fetch('LOG_TO_STDOUT') { Rails.env.development? }.present?
console = ActiveSupport::Logger.new(STDERR)
if ::Rails.logger.respond_to?(:broadcast_to)
::Rails.logger.broadcast_to(console)
console = ActiveSupport::Logger.new($stderr)
if Rails.logger.respond_to?(:broadcast_to)
Rails.logger.broadcast_to(console)
else
Rails.logger.extend ActiveSupport::Logger.broadcast console
end
end
Telegram::Bot::UpdatesPoller.start(ENV['BOT'].try!(:to_sym) || :default)
Telegram::Bot::UpdatesPoller.start(ENV['BOT']&.to_sym || :default)
end
desc 'Set webhook urls for all bots'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/config_methods'
module Telegram
@@ -12,15 +14,6 @@ module Telegram
# Raised for valid telegram response with 404 status code.
class NotFound < Error; end
module_function
def deprecation_0_16
@deprecation ||= begin
require 'active_support/deprecation'
ActiveSupport::Deprecation.new('0.16', 'Telegram::Bot')
end
end
autoload :Async, 'telegram/bot/async'
autoload :Client, 'telegram/bot/client'
autoload :ClientStub, 'telegram/bot/client_stub'
@@ -30,6 +23,7 @@ module Telegram
autoload :Tasks, 'telegram/bot/tasks'
autoload :UpdatesController, 'telegram/bot/updates_controller'
autoload :UpdatesPoller, 'telegram/bot/updates_poller'
autoload :VERSION, 'telegram/bot/version'
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
# Telegram clients can perform requests in async way with
@@ -128,7 +130,7 @@ module Telegram
#
# If no block is given returns previously set value or the global one,
# set by #async=.
def async(val = true)
def async(val = true) # rubocop:disable Style/OptionalBooleanParameter
thread_key = object_id
thread_store = Async.thread_store
return thread_store.fetch(thread_key) { @async } unless block_given?
@@ -137,7 +139,7 @@ module Telegram
thread_store[thread_key] = self.class.prepare_async_val(val)
yield
ensure
if MISSING_VALUE == old_val
if old_val == MISSING_VALUE
thread_store.delete(thread_key)
else
thread_store[thread_key] = old_val

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

@@ -1,11 +1,13 @@
# frozen_string_literal: true
require 'active_support/core_ext/hash/keys'
require 'httpclient'
module Telegram
module Bot
class Client
SERVER = 'https://api.telegram.org'.freeze
URL_TEMPLATE = '%<server>s/bot%<token>s/'.freeze
SERVER = 'https://api.telegram.org'
URL_TEMPLATE = '%<server>s/bot%<token>s/'
autoload :RequestBodyFormatter, 'telegram/bot/client/request_body_formatter'
autoload :TypedResponse, 'telegram/bot/client/typed_response'
@@ -41,7 +43,7 @@ module Telegram
end
def error_for_response(response)
result = JSON.parse(response.body) rescue nil # rubocop:disable RescueModifier
result = JSON.parse(response.body) rescue nil # rubocop:disable Style/RescueModifier
return Error.new(response.reason) unless result
message = result['description'] || '-'
# This errors are raised only for valid responses from Telegram

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

@@ -1,10 +1,12 @@
# frozen_string_literal: true
require 'active_support/core_ext/string/inflections'
module Telegram
module Bot
class Client
module ApiHelper
METHODS_LIST_FILE = File.expand_path('../api_methods.txt', __FILE__)
METHODS_LIST_FILE = File.expand_path('api_methods.txt', __dir__)
class << self
def methods_list(file = METHODS_LIST_FILE)

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'json'
module Telegram

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/client/api_helper'
require 'active_support/core_ext/string/inflections'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
# Stubbed client for tests. Saves all requests into #requests hash.
@@ -17,7 +19,7 @@ module Telegram
class << self
# Any call to Client.new will return ClientStub instance when `enabled` is true.
# Can be used with a block.
def stub_all!(enabled = true)
def stub_all!(enabled = true) # rubocop:disable Style/OptionalBooleanParameter
Client.extend(StubbedConstructor) unless Client < StubbedConstructor
return @_stub_all = enabled unless block_given?
begin
@@ -34,7 +36,7 @@ module Telegram
end
end
def initialize(token = nil, username = nil, **options)
def initialize(token = nil, username = nil, **options) # rubocop:disable Lint/MissingSuper
@token = token || options[:token]
@username = username || options[:username] || token
reset

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/indifferent_access'
@@ -44,7 +46,7 @@ module Telegram
# from `secrets.yml` merging `telegram['bot']` at `:default` key.
#
# Can be overwritten with .bots_config=
def bots_config
def bots_config # rubocop:disable Metrics/PerceivedComplexity
@bots_config ||=
if defined?(Rails.application)
app = Rails.application

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

@@ -1,7 +1,9 @@
# frozen_string_literal: true
module Telegram
module Bot
module DebugClient
def debug!(dev = STDOUT)
def debug!(dev = $stdout)
if block_given?
begin
old_dev = client.debug_dev

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/concern'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/json'
@@ -21,7 +23,7 @@ module Telegram
end
def inspect
"#<#{self.class.name}(#{controller.try!(:name)})>"
"#<#{self.class.name}(#{controller&.name})>"
end
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/routes_helper'
module Telegram
@@ -10,7 +12,7 @@ module Telegram
end
config.before_initialize do
::ActionDispatch::Routing::Mapper.send(:include, RoutesHelper)
::ActionDispatch::Routing::Mapper.include RoutesHelper
end
initializer 'telegram.bot.updates_controller.set_config' do |app|

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'base64'
require 'openssl'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
module RSpec

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/rspec'
require 'telegram/bot/rspec/message_helpers'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
module RSpec
@@ -61,14 +63,14 @@ module Telegram
attr_reader :performed_requests, :description
def initialize(bot, action, description: nil)
def initialize(bot, action, description: nil) # rubocop:disable Lint/MissingSuper
@bot = bot
@action = action
@description = description || "make #{action} telegram request"
exactly(1)
end
def matches?(proc) # rubocop:disable AbcSize
def matches?(proc) # rubocop:disable Metrics/AbcSize
raise ArgumentError, 'matcher only supports block expectations' unless proc.is_a?(Proc)
original_requests_count = bot.requests[action].count
proc.call

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/rspec/integration/shared'
RSpec.shared_context 'telegram/bot/integration/poller' do

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/rspec/integration/shared'
require 'rack/test'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/rspec/integration/shared'
RSpec.shared_context 'telegram/bot/integration/rails', type: :request do

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/json'
require 'telegram/bot'
require 'telegram/bot/rspec/message_helpers'
@@ -10,5 +12,5 @@ RSpec.shared_context 'telegram/bot/integration/shared' do
let(:bot) { Telegram.bot }
let(:clear_session?) { described_class.respond_to?(:session_store) }
before { described_class.session_store.try!(:clear) if clear_session? }
before { described_class.session_store&.clear if clear_session? }
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
# Shared helpers for testing message updates.
RSpec.shared_context 'telegram/bot/message_helpers' do
let(:default_message_options) { {from: from, chat: chat} }

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

@@ -7,7 +7,7 @@ module Telegram
def set_webhook
routes = Rails.application.routes.url_helpers
cert_file = ENV['CERT']
cert_file = ENV.fetch('CERT', nil)
cert = File.open(cert_file) if cert_file
each_bot do |key, bot|
route_name = RoutesHelper.route_name_for_bot(bot)
@@ -16,7 +16,7 @@ module Telegram
bot.set_webhook(
url: url,
certificate: cert,
ip_address: ENV['IP_ADDRESS'],
ip_address: ENV.fetch('IP_ADDRESS', nil),
drop_pending_updates: drop_pending_updates,
)
end
@@ -50,13 +50,13 @@ module Telegram
end
def each_bot(&block)
id = ENV['BOT'].try!(:to_sym)
id = ENV['BOT']&.to_sym
bots = id ? {id => Client.by_id(id)} : Telegram.bots
bots.each { |key, bot| bot.async(false) { block[key, bot] } }
end
def drop_pending_updates
ENV['DROP_PENDING_UPDATES'].try!(:downcase) == 'true'
ENV['DROP_PENDING_UPDATES']&.downcase == 'true'
end
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'abstract_controller'
require 'active_support/core_ext/string/inflections'
require 'active_support/callbacks'
@@ -47,7 +49,7 @@ module Telegram
# ControllerClass.new(bot, from: telegram_user, chat: telegram_chat).
# process(:help, *args)
#
class UpdatesController < AbstractController::Base # rubocop:disable ClassLength
class UpdatesController < AbstractController::Base # rubocop:disable Metrics/ClassLength
abstract!
%w[
@@ -69,12 +71,12 @@ module Telegram
include AbstractController::Callbacks
# Redefine callbacks with default terminator.
if ActiveSupport::VERSION::MAJOR >= 5
define_callbacks :process_action,
skip_after_callbacks_if_terminated: true
define_callbacks :process_action,
skip_after_callbacks_if_terminated: true
else
define_callbacks :process_action,
terminator: ->(_, result) { result == false },
skip_after_callbacks_if_terminated: true
define_callbacks :process_action,
terminator: ->(_, result) { result == false },
skip_after_callbacks_if_terminated: true
end
include Commands
@@ -126,14 +128,14 @@ module Telegram
# that update is nil.
# ActionDispatch::Request object is passed in `webhook_request` when bot running
# in webhook mode.
def initialize(bot = nil, update = nil, webhook_request = nil)
def initialize(bot = nil, update = nil, webhook_request = nil) # rubocop:disable Lint/MissingSuper
if update.is_a?(Hash) && (update.key?(:from) || update.key?(:chat))
options = update
update = nil
end
@_bot = bot
@_update = update
@_chat, @_from = options && options.values_at(:chat, :from)
@_chat, @_from = options&.values_at(:chat, :from)
@_payload, @_payload_type = self.class.payload_from_update(update)
@_webhook_request = webhook_request
end
@@ -142,13 +144,13 @@ module Telegram
# when there is no such field in payload.
#
# Can be overriden with `chat` option for #initialize.
def chat
@_chat ||=
def chat # rubocop:disable Metrics/PerceivedComplexity
@_chat ||= # rubocop:disable Naming/MemoizedInstanceVariableName
if payload
if payload.is_a?(Hash)
payload['chat'] || payload['message'] && payload['message']['chat']
payload['chat'] || (payload['message'] && payload['message']['chat'])
else
payload.try(:chat) || payload.try(:message).try!(:chat)
payload.try(:chat) || payload.try(:message)&.chat
end
end
end
@@ -156,7 +158,8 @@ module Telegram
# Accessor to `'from'` field of payload. Can be overriden with `from` option
# for #initialize.
def from
@_from ||= payload.is_a?(Hash) ? payload['from'] : payload.try(:from)
@_from ||= # rubocop:disable Naming/MemoizedInstanceVariableName
payload.is_a?(Hash) ? payload['from'] : payload.try(:from)
end
# Processes current update.
@@ -221,7 +224,7 @@ module Telegram
# Silently ignore unsupported messages to not fail when user crafts
# an update with usupported command, callback query context, etc.
def action_missing(action, *_args)
logger.debug { "The action '#{action}' is not defined in #{self.class.name}" } if logger
logger&.debug { "The action '#{action}' is not defined in #{self.class.name}" }
nil
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController

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

@@ -1,9 +1,11 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController
# Support for parsing commands
module Commands
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
CMD_REGEX = %r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i.freeze
class << self
# Fetches command from text message. All subsequent words are returned
@@ -34,7 +36,7 @@ module Telegram
def action_for_message
cmd, args = Commands.command_from_text(payload['text'], bot_username)
return unless cmd
[[action_for_command(cmd), type: :command, command: cmd], args]
[[action_for_command(cmd), {type: :command, command: cmd}], args]
end
alias_method :action_for_channel_post, :action_for_message

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController
@@ -23,8 +25,8 @@ module Telegram
def process_action(*args)
raw_payload = {
controller: self.class.name,
action: action_name,
update: update,
action: action_name,
update: update,
}
Instrumentation.instrument(:start_processing, raw_payload.dup)
Instrumentation.instrument(:process_action, raw_payload) do |payload|
@@ -61,14 +63,14 @@ module Telegram
# end
#
# :api: plugin
def cleanup_view_runtime #:nodoc:
def cleanup_view_runtime # :nodoc:
yield
end
# Every time after an action is processed, this method is invoked
# with the payload, so you can add more information.
# :api: plugin
def append_info_to_payload(_payload) #:nodoc:
def append_info_to_payload(_payload) # :nodoc:
end
module ClassMethods
@@ -76,7 +78,7 @@ module Telegram
# controller process action. This method should return an array
# with the messages to be added.
# :api: plugin
def log_process_action(_payload) #:nodoc:
def log_process_action(_payload) # :nodoc:
[]
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/log_subscriber'
module Telegram
@@ -8,7 +10,7 @@ module Telegram
info do
payload = event.payload
"Processing by #{payload[:controller]}##{payload[:action]}\n" \
" Update: #{payload[:update].to_json}"
" Update: #{payload[:update].to_json}"
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController
@@ -48,12 +50,12 @@ module Telegram
# it has higher priority than contextual action.
def action_for_message
val = message_context_session.delete(:context)
context = val && val.to_s
super || context && begin
args = payload['text'].try!(:split) || []
context = val&.to_s
super || (context && begin
args = payload['text']&.split || []
action = action_for_message_context(context)
[[action, type: :message_context, context: context], args]
end
[[action, {type: :message_context, context: context}], args]
end)
end
# Save context for the next request.

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController
@@ -59,9 +61,9 @@ module Telegram
# Edit message from callback query.
def edit_message(type, params = {})
params =
if message_id = payload['inline_message_id'] # rubocop:disable AssignmentInCondition
if message_id = payload['inline_message_id'] # rubocop:disable Lint/AssignmentInCondition
params.merge(inline_message_id: message_id)
elsif message = payload['message'] # rubocop:disable AssignmentInCondition
elsif message = payload['message'] # rubocop:disable Lint/AssignmentInCondition
params.merge(chat_id: message['chat']['id'], message_id: message['message_id'])
else
raise 'Can not edit message without `inline_message_id` or `message`'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/rescuable'
module Telegram
@@ -11,7 +13,7 @@ module Telegram
def process_action(*)
super
rescue Exception => exception # rubocop:disable RescueException
rescue Exception => exception # rubocop:disable Lint/RescueException
rescue_with_handler(exception) || raise
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'telegram/bot/updates_controller/testing'
require 'telegram/bot/rspec/message_helpers'
require 'telegram/bot/rspec/callback_query_helpers'

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rack/session/abstract/id'
require 'active_support/cache'
@@ -27,7 +29,8 @@ module Telegram
protected
def session
@_session ||= self.class.build_session(session_key)
@_session ||= # rubocop:disable Naming/MemoizedInstanceVariableName
self.class.build_session(session_key)
end
def session_key
@@ -41,7 +44,7 @@ module Telegram
class SessionHash < Rack::Session::Abstract::SessionHash
attr_reader :id
def initialize(store, id)
def initialize(store, id) # rubocop:disable Lint/MissingSuper
@store = store
@id = id
end
@@ -65,13 +68,13 @@ module Telegram
def commit
return unless loaded?
data = to_hash.delete_if { |_, v| v.nil? }
data = to_hash.compact
@store.write(id, data)
end
end
class NullSessionHash < Session::SessionHash
def initialize
def initialize # rubocop:disable Lint/MissingSuper
@data = {}
@loaded = true
@exists = true

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController
@@ -16,7 +18,7 @@ module Telegram
# everything will be rewriten with #initialize.
#
# With `full` set to `true` it'll clear all cached instance variables.
def recycle!(full = false)
def recycle!(full = false) # rubocop:disable Style/OptionalBooleanParameter
return unless full
(instance_variables - IVARS_TO_KEEP).each do |ivar|
remove_instance_variable(ivar)
@@ -27,7 +29,8 @@ module Telegram
# Stubs session.
def session
@_session ||= Session::NullSessionHash.new
@_session ||= # rubocop:disable Naming/MemoizedInstanceVariableName
Session::NullSessionHash.new
end
end
end

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController

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

@@ -1,3 +1,5 @@
# frozen_string_literal: true
module Telegram
module Bot
class UpdatesController

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

@@ -1,9 +1,11 @@
# frozen_string_literal: true
module Telegram
module Bot
# Supposed to be used in development environments only.
class UpdatesPoller
class << self
@@instances = {} # rubocop:disable ClassVars
@@instances = {} # rubocop:disable Style/ClassVars
def instances
@@instances
@@ -36,7 +38,7 @@ module Telegram
end
def log(&block)
logger.info(&block) if logger
logger&.info(&block)
end
def start
@@ -56,7 +58,7 @@ module Telegram
def run
while running
updates = fetch_updates
process_updates(updates) if updates && updates.any?
process_updates(updates) if updates&.any?
end
end
@@ -82,8 +84,8 @@ module Telegram
process_update(update)
end
end
rescue StandardError => e
logger.error { ([e.message] + e.backtrace).join("\n") } if logger
rescue StandardError => exception
logger&.error { ([exception.message] + exception.backtrace).join("\n") }
end
# Override this method to setup custom error collector.
@@ -102,10 +104,8 @@ module Telegram
end
if defined?(Rails.application) && Rails.application.respond_to?(:reloader)
def reloading_code
Rails.application.reloader.wrap do
yield
end
def reloading_code(&block)
Rails.application.reloader.wrap(&block)
end
else
def reloading_code

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

@@ -1,6 +1,8 @@
# frozen_string_literal: true
module Telegram
module Bot
VERSION = '0.16.1'.freeze
VERSION = '0.16.1'
def self.gem_version
Gem::Version.new VERSION