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



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

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

#action_for_chosen_inline_resultObject



208
209
210
# File 'lib/telegram/bot/updates_controller.rb', line 208

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

#action_for_default_payloadObject



188
189
190
# File 'lib/telegram/bot/updates_controller.rb', line 188

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

#action_for_inline_queryObject



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

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.



197
198
199
200
201
# File 'lib/telegram/bot/updates_controller.rb', line 197

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]`.



180
181
182
183
184
185
186
# File 'lib/telegram/bot/updates_controller.rb', line 180

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`.



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

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
# File 'lib/telegram/bot/updates_controller.rb', line 159

def chat
  @_chat ||= payload.try! { |x| x['chat'] || x['message'] && x['message']['chat'] }
end

#dispatchObject

Processes current update.



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

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.



165
166
167
# File 'lib/telegram/bot/updates_controller.rb', line 165

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