lib/telegram/bot/updates_controller.rb in telegram-bot-0.16.1 vs lib/telegram/bot/updates_controller.rb in telegram-bot-0.16.3

- old
+ new

@@ -1,5 +1,7 @@ +# frozen_string_literal: true + require 'abstract_controller' require 'active_support/core_ext/string/inflections' require 'active_support/callbacks' require 'active_support/version' @@ -45,11 +47,11 @@ # There is also ability to run action without update: # # 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[ Commands Instrumentation @@ -67,16 +69,16 @@ ].each { |mod| autoload mod, "telegram/bot/updates_controller/#{mod.underscore}" } 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 include Rescue include ReplyHelpers @@ -85,80 +87,109 @@ # all the methods properly. include Instrumentation extend Session::ConfigMethods - PAYLOAD_TYPES = %w[ + PAYLOAD_TYPES = Set.new(%w[ message edited_message channel_post edited_channel_post + business_connection + business_message + edited_business_message + deleted_business_messages + message_reaction + message_reaction_count inline_query chosen_inline_result callback_query shipping_query pre_checkout_query poll poll_answer my_chat_member chat_member chat_join_request - ].freeze + chat_boost + removed_chat_boost + pre_checkout_query + ].freeze) class << self # Initialize controller and process update. def dispatch(*args) new(*args).dispatch end def payload_from_update(update) - update && PAYLOAD_TYPES.find do |type| - item = update[type] - return [item, type] if item + case update + when nil then nil + when Hash + # faster lookup for the case when telegram-bot-types is not used + update.find do |type, item| + return [item, type] if PAYLOAD_TYPES.include?(type) + end + else + payload_from_typed_update(update) end end + + private + + def payload_from_typed_update(update) + PAYLOAD_TYPES.find do |type| + begin + item = update[type] + return [item, type] if item + rescue Exception # rubocop:disable Lint/RescueException + # dry-rb raises exception if field is not defined in schema + end + end + end end attr_internal_reader :bot, :payload, :payload_type, :update, :webhook_request delegate :username, to: :bot, prefix: true, allow_nil: true # `update` can be either update object with hash access & string # keys or Hash with `:from` or `:chat` to override this values and assume # 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 # Accessor to `'chat'` field of payload. Also tries `'chat'` in `'message'` # 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 # 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. def dispatch action, args = action_for_payload @@ -219,10 +250,10 @@ end # 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 PAYLOAD_TYPES.each do |type| method = :"action_for_#{type}"