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
).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, #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.



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

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.



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

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.



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

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.



95
96
97
# File 'lib/telegram/bot/updates_controller.rb', line 95

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

Instance Method Details

#action_for_callback_queryObject



202
203
204
# File 'lib/telegram/bot/updates_controller.rb', line 202

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

#action_for_chosen_inline_resultObject



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

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

#action_for_edited_messageObject Also known as: action_for_edited_channel_post

It doesn’t extract commands from edited messages. Just process them as usual ones.



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

def action_for_edited_message
end

#action_for_inline_queryObject



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

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



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

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



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

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

#action_missingObject

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



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

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.



149
150
151
# File 'lib/telegram/bot/updates_controller.rb', line 149

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

#dispatchObject

Processes current update.



160
161
162
163
# File 'lib/telegram/bot/updates_controller.rb', line 160

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.



155
156
157
# File 'lib/telegram/bot/updates_controller.rb', line 155

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