Class: Telegram::Bot::UpdatesController

Inherits:
AbstractController::Base
  • Object
show all
Extended by:
Session::ConfigMethods
Includes:
AbstractController::Callbacks, AbstractController::Translation, Instrumentation, ReplyHelpers
Defined in:
lib/telegram/bot/updates_controller.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, 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 ReplyHelpers

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

Methods included from Instrumentation

instrument, prepended, #process_action, #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.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/telegram/bot/updates_controller.rb', line 130

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_data = nil
  update && PAYLOAD_TYPES.find do |type|
    item = update[type]
    payload_data = [item, type] if item
  end
  @_payload, @_payload_type = payload_data
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.



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

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.



114
115
116
117
118
119
120
# File 'lib/telegram/bot/updates_controller.rb', line 114

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

.dispatch(*args) ⇒ Object

Initialize controller and process update.



97
98
99
# File 'lib/telegram/bot/updates_controller.rb', line 97

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

Instance Method Details

#action_for_callback_queryObject



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

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

#action_for_chosen_inline_resultObject



200
201
202
# File 'lib/telegram/bot/updates_controller.rb', line 200

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

#action_for_default_payloadObject



180
181
182
# File 'lib/telegram/bot/updates_controller.rb', line 180

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

#action_for_inline_queryObject



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

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.



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

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



172
173
174
175
176
177
178
# File 'lib/telegram/bot/updates_controller.rb', line 172

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



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

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.



151
152
153
# File 'lib/telegram/bot/updates_controller.rb', line 151

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

#dispatchObject

Processes current update.



162
163
164
165
# File 'lib/telegram/bot/updates_controller.rb', line 162

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.



157
158
159
# File 'lib/telegram/bot/updates_controller.rb', line 157

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