From 1f139a2b36036708a10fd9823ec16cc51dec8294 Mon Sep 17 00:00:00 2001 From: Max Melentiev Date: Thu, 12 May 2016 00:28:22 +0300 Subject: [PATCH] MessageContext doesnt use #process to run actions --- README.md | 4 +- lib/telegram/bot/updates_controller.rb | 11 +++-- .../bot/updates_controller/message_context.rb | 42 ++++++++----------- .../message_context_spec.rb | 24 +++++++++-- 4 files changed, 46 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 719dc60..dee6989 100644 --- a/README.md +++ b/README.md @@ -200,8 +200,8 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController end # register context handlers to handle this context - context_handler :rename do |message| - update_name message[:text] + context_handler :rename do |*words| + update_name words[0] reply_with :message, text: 'Renamed!' end diff --git a/lib/telegram/bot/updates_controller.rb b/lib/telegram/bot/updates_controller.rb index ebfdb0c..2a4fa95 100644 --- a/lib/telegram/bot/updates_controller.rb +++ b/lib/telegram/bot/updates_controller.rb @@ -159,13 +159,16 @@ module Telegram # Returns array `[is_command?, action, args]`. def action_for_payload case payload_type - when 'message' - cmd, args = self.class.command_from_text(payload['text'], bot_username) - cmd &&= self.class.action_for_command(cmd) - [true, cmd, args] if cmd + when 'message' then action_for_message end || [false, payload_type, [payload]] end + 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 + # Silently ignore unsupported messages. # Params are `action, *args`. def action_missing(*) diff --git a/lib/telegram/bot/updates_controller/message_context.rb b/lib/telegram/bot/updates_controller/message_context.rb index 4f3fead..bc3fbbf 100644 --- a/lib/telegram/bot/updates_controller/message_context.rb +++ b/lib/telegram/bot/updates_controller/message_context.rb @@ -10,7 +10,6 @@ module Telegram included do # As we use before_action context is cleared anyway, # no matter we used it or not. - before_action :fetch_context singleton_class.send :attr_reader, :context_handlers, :context_to_action @context_handlers = {} end @@ -18,26 +17,26 @@ module Telegram module ClassMethods # Registers handler for context. # - # context_handler :rename do |message| - # resource.update!(name: message['text']) + # context_handler :rename do |*| + # resource.update!(name: payload['text']) # end # # # To run other action with all the callbacks: - # context_handler :rename do |message| - # process(:rename, *m['text'].try!(:split)) # Message can be without text + # context_handler :rename do |*words| + # process(:rename, *words) # end # # # Or just # context_handler :rename, :your_action_to_call # context_handler :rename # to call :rename # - # # For messages without context use this instead of `message` method: - # context_handler do |message| - # end - # def context_handler(context = nil, action = nil, &block) context &&= context.to_sym - context_handlers[context] = block || action || context + if block + action = "_context_handler_#{context}" + define_method(action, &block) + end + context_handlers[context] = action || context end # Use it to use context value as action name for all contexts @@ -49,20 +48,9 @@ module Telegram end end - # Finds handler for current context and processes message with it. - def message(message) - handler = handler_for_context - return unless handler - if handler.respond_to?(:call) - instance_exec(message, &handler) - else - process(handler, *message['text'].try!(:split)) - end - end - # Action to clear context. def cancel - # Context is already cleared in before_action + # Context is already cleared in action_for_message end private @@ -71,11 +59,15 @@ module Telegram # according to previous request. attr_reader :context - # Fetches and removes context from session. - def fetch_context + # Fetches context and finds handler for it. If message has new command, + # it has higher priority than contextual action. + def action_for_message val = session.delete(:context) @context = val && val.to_sym - true # TODO: remove in Rails 5.0 + super || context && begin + handler = handler_for_context + [true, handler, payload['text'].try!(:split) || []] if handler + end end # Save context for the next request. diff --git a/spec/telegram/bot/updates_controller/message_context_spec.rb b/spec/telegram/bot/updates_controller/message_context_spec.rb index 11d821f..6a3bdc0 100644 --- a/spec/telegram/bot/updates_controller/message_context_spec.rb +++ b/spec/telegram/bot/updates_controller/message_context_spec.rb @@ -10,7 +10,10 @@ RSpec.describe Telegram::Bot::UpdatesController::MessageContext do self.filter_done = true end - context_handler do |*args| + attr_reader :callbacks_runs + before_action { @callbacks_runs = (@callbacks_runs || 0) + 1 } + + def message(*args) [:no_context, *args] end @@ -51,13 +54,19 @@ RSpec.describe Telegram::Bot::UpdatesController::MessageContext do context 'when context is handled by block' do before { session[:context] = :block } - its(:call) { should eq [:block_result, payload] } + its(:call) { should eq [:block_result, *text.split] } it { should_not change(controller, :filter_done) } it { should change { session[:context] }.to nil } context 'when message has no text' do let(:payload) { {'audio' => {'file_id' => 123}} } - its(:call) { should eq [:block_result, payload] } + its(:call) { should eq [:block_result] } + end + + context 'when message has new command' do + let(:text) { '/action a s d' } + its(:call) { should eq [:action_result, *%w(a s d)] } + it { should change { session[:context] }.to nil } end end @@ -66,6 +75,7 @@ RSpec.describe Telegram::Bot::UpdatesController::MessageContext do its(:call) { should eq [:method_result, *text.split] } it { should change(controller, :filter_done).to true } it { should change { session[:context] }.to nil } + it { should change(controller, :callbacks_runs).to 1 } context 'when message has no text' do let(:payload) { {'audio' => {'file_id' => 123}} } @@ -84,7 +94,7 @@ RSpec.describe Telegram::Bot::UpdatesController::MessageContext do context 'when context is action`s name but not mapped' do before { session[:context] = :action } - its(:call) { should eq nil } + its(:call) { should eq [:no_context, payload] } it { should_not change(controller, :filter_done) } it { should change { session[:context] }.to nil } end @@ -92,6 +102,12 @@ RSpec.describe Telegram::Bot::UpdatesController::MessageContext do context 'when context_to_action is true' do before { controller_class.context_to_action! } + context 'when context is not set' do + its(:call) { should eq [:no_context, payload] } + it { should_not change(controller, :filter_done) } + it { should_not change { session[:context] } } + end + context 'when context is action`s name but not mapped' do before { session[:context] = :action } its(:call) { should eq [:action_result, *text.split] }