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
  inline_query
  chosen_inline_result
  callback_query
  edited_message
).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.



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

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.



100
101
102
103
# File 'lib/telegram/bot/updates_controller.rb', line 100

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.



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

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.



93
94
95
# File 'lib/telegram/bot/updates_controller.rb', line 93

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

Instance Method Details

#action_for_callback_queryObject



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

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

#action_for_chosen_inline_resultObject



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

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

#action_for_edited_messageObject

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



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

def action_for_edited_message
end

#action_for_inline_queryObject



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

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

#action_for_messageObject

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



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

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



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

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



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

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.



147
148
149
# File 'lib/telegram/bot/updates_controller.rb', line 147

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

#dispatchObject

Processes current update.



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

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.



153
154
155
# File 'lib/telegram/bot/updates_controller.rb', line 153

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