Class: Telegram::Bot::UpdatesController

Inherits:
AbstractController::Base
  • Object
show all
Extended by:
Session::ConfigMethods
Includes:
AbstractController::Callbacks, AbstractController::Translation, Instrumentation, ReplyHelpers, Rescue
Defined in:
lib/telegram/bot/updates_controller.rb,
lib/telegram/bot/updates_controller/rescue.rb,
lib/telegram/bot/updates_controller/session.rb,
lib/telegram/bot/updates_controller/testing.rb,
lib/telegram/bot/updates_controller/typed_update.rb,
lib/telegram/bot/updates_controller/reply_helpers.rb,
lib/telegram/bot/updates_controller/log_subscriber.rb,
lib/telegram/bot/updates_controller/instrumentation.rb,
lib/telegram/bot/updates_controller/message_context.rb,
lib/telegram/bot/updates_controller/callback_query_context.rb

Overview

Base class to create update processors. With callbacks, session and helpers.

Define public methods for each command and they will be called when update has this command. Message is automatically parsed and words are passed as method arguments. Be sure to use default values and splat arguments in every action method to not get errors, when user sends command without necessary args / with extra args.

def start(token = nil, *)
  if token
    # ...
  else
    # ...
  end
end

def help(*)
  respond_with :message, text:
end

To process plain text messages (without commands) or other updates just define public method with name of payload type. They will receive payload as an argument.

def message(message)
  respond_with :message, text: "Echo: #{message['text']}"
end

def inline_query(query)
  answer_inline_query results_for_query(query), is_personal: true
end

# To process conflicting commands (`/message args`) just use `on_` prefix:
def on_message(*args)
  # ...
end

To process update run:

ControllerClass.dispatch(bot, update)

There is also ability to run action without update:

ControllerClass.new(bot, from: telegram_user, chat: telegram_chat).
  process(:help, *args)

Defined Under Namespace

Modules: CallbackQueryContext, Instrumentation, MessageContext, ReplyHelpers, Rescue, Session, Testing, TypedUpdate Classes: LogSubscriber

Constant Summary collapse

PAYLOAD_TYPES =
%w[
  message
  edited_message
  channel_post
  edited_channel_post
  inline_query
  chosen_inline_result
  callback_query
  shipping_query
  pre_checkout_query
].freeze
CMD_REGEX =
%r{\A/([a-z\d_]{,31})(@(\S+))?(\s|$)}i
CONFLICT_CMD_REGEX =
Regexp.new("^(#{PAYLOAD_TYPES.join('|')}|\\d)")

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Session::ConfigMethods

session_store=, use_session!

Methods included from Instrumentation

instrument, #process_action, #respond_with

Methods included from ReplyHelpers

#answer_callback_query, #answer_inline_query, #edit_message, #reply_with, #respond_with

Constructor Details

#initialize(bot = nil, update = nil) ⇒ UpdatesController

Second argument 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.



144
145
146
147
148
149
150
151
152
153
# File 'lib/telegram/bot/updates_controller.rb', line 144

def initialize(bot = nil, update = nil)
  if update.is_a?(Hash) && (update.key?(:from) || update.key?(:chat))
    options = update
    update = nil
  end
  @_update = update
  @_bot = bot
  @_chat, @_from = options && options.values_at(:chat, :from)
  @_payload, @_payload_type = self.class.payload_from_update(update)
end

Class Method Details

.action_for_command(cmd) ⇒ Object

Overrid it to filter or transform commands. Default implementation is to convert to downcase and add ‘on_` prefix for conflicting commands.



111
112
113
114
# File 'lib/telegram/bot/updates_controller.rb', line 111

def action_for_command(cmd)
  cmd.downcase!
  cmd.match(CONFLICT_CMD_REGEX) ? "on_#{cmd}" : cmd
end

.command_from_text(text, username = nil) ⇒ Object

Fetches command from text message. All subsequent words are returned as arguments. If command has mention (eg. ‘/test@SomeBot`), it returns commands only for specified username. Set `username` to `true` to accept any commands.



121
122
123
124
125
126
127
# File 'lib/telegram/bot/updates_controller.rb', line 121

def command_from_text(text, username = nil)
  return unless text
  match = text.match(CMD_REGEX)
  return unless match
  mention = match[3]
  [match[1], text.split.drop(1)] if username == true || !mention || mention == username
end

.dispatch(*args) ⇒ Object

Initialize controller and process update.



104
105
106
# File 'lib/telegram/bot/updates_controller.rb', line 104

def dispatch(*args)
  new(*args).dispatch
end

.payload_from_update(update) ⇒ Object



129
130
131
132
133
134
# File 'lib/telegram/bot/updates_controller.rb', line 129

def payload_from_update(update)
  update && PAYLOAD_TYPES.find do |type|
    item = update[type]
    return [item, type] if item
  end
end

Instance Method Details

#action_for_callback_queryObject



219
220
221
# File 'lib/telegram/bot/updates_controller.rb', line 219

def action_for_callback_query
  [false, payload_type, [payload['data']]]
end

#action_for_chosen_inline_resultObject



215
216
217
# File 'lib/telegram/bot/updates_controller.rb', line 215

def action_for_chosen_inline_result
  [false, payload_type, [payload['result_id'], payload['query']]]
end

#action_for_default_payloadObject



195
196
197
# File 'lib/telegram/bot/updates_controller.rb', line 195

def action_for_default_payload
  [false, payload_type, [payload]]
end

#action_for_inline_queryObject



211
212
213
# File 'lib/telegram/bot/updates_controller.rb', line 211

def action_for_inline_query
  [false, payload_type, [payload['query'], payload['offset']]]
end

#action_for_messageObject Also known as: action_for_channel_post

If payload is a message with command, then returned action is an action for this command. Separate method, so it can be easily overriden (ex. MessageContext).

This is not used for edited messages/posts. It process them as basic updates.



204
205
206
207
208
# File 'lib/telegram/bot/updates_controller.rb', line 204

def action_for_message
  cmd, args = self.class.command_from_text(payload['text'], bot_username)
  cmd &&= self.class.action_for_command(cmd)
  [true, cmd, args] if cmd
end

#action_for_payloadObject

Calculates action name and args for payload. Uses ‘action_for_#payload_type` methods. If this method doesn’t return anything it uses fallback with action same as payload type. Returns array ‘[is_command?, action, args]`.



187
188
189
190
191
192
193
# File 'lib/telegram/bot/updates_controller.rb', line 187

def action_for_payload
  if payload_type
    send("action_for_#{payload_type}") || action_for_default_payload
  else
    [false, :unsupported_payload_type, []]
  end
end

#action_missingObject

Silently ignore unsupported messages. Params are ‘action, *args`.



225
226
# File 'lib/telegram/bot/updates_controller.rb', line 225

def action_missing(*)
end

#chatObject

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.



159
160
161
162
163
164
165
166
167
168
# File 'lib/telegram/bot/updates_controller.rb', line 159

def chat
  @_chat ||=
    if payload
      if payload.is_a?(Hash)
        payload['chat'] || payload['message'] && payload['message']['chat']
      else
        payload.try(:chat) || payload.try(:message).try!(:chat)
      end
    end
end

#dispatchObject

Processes current update.



177
178
179
180
# File 'lib/telegram/bot/updates_controller.rb', line 177

def dispatch
  @_is_command, action, args = action_for_payload
  process(action, *args)
end

#fromObject

Accessor to ‘’from’‘ field of payload. Can be overriden with `from` option for #initialize.



172
173
174
# File 'lib/telegram/bot/updates_controller.rb', line 172

def from
  @_from ||= payload && payload['from']
end