Skip to content

Commit

Permalink
Merge pull request #35 from leoamigood/la_queue_assert
Browse files Browse the repository at this point in the history
Introduce command queue assertion
  • Loading branch information
leoamigood authored Mar 2, 2017
2 parents bfe541b + b38c794 commit 348c20d
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 62 deletions.
1 change: 1 addition & 0 deletions app/services/telegram/command/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def ask(channel)

def execute(channel, message, options)
Telegram::CommandQueue.clear

case options[:strategy]
when :by_word
game = GameEngineService.create_by_word(Realm::Telegram.new(channel, message.from.id), options[:word])
Expand Down
2 changes: 2 additions & 0 deletions app/services/telegram/command/language.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def ask(channel)
end

def execute(channel, language)
Telegram::CommandQueue.assert(self)

language = GameEngineService.language(language.upcase)
dictionary = Dictionary.where(lang: language).order('RANDOM()').first

Expand Down
2 changes: 2 additions & 0 deletions app/services/telegram/command/level.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def ask(channel)
end

def execute(channel, level)
Telegram::CommandQueue.assert(self)

GameEngineService.settings(channel, { complexity: level })
TelegramMessenger.level(level)
end
Expand Down
5 changes: 3 additions & 2 deletions app/services/telegram/command/start.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ module Command
class Start
class << self
def execute(channel)
Telegram::CommandQueue.clear
TelegramMessenger.welcome(channel)
TelegramMessenger.ask_language(channel)

Telegram::CommandQueue.push{ TelegramMessenger.ask_level(channel) }
Telegram::CommandQueue.push{ TelegramMessenger.ask_language(channel) }.callback { |cls| cls == Telegram::Command::Language }
Telegram::CommandQueue.push{ TelegramMessenger.ask_level(channel) }.callback { |cls| cls == Telegram::Command::Level }
Telegram::CommandQueue.push{ TelegramMessenger.ask_length(channel) }
end
end
Expand Down
47 changes: 39 additions & 8 deletions app/services/telegram/command_queue.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,50 @@
module Telegram

class CommandBlock < Proc
attr_accessor :callback
end

class CommandQueue
@queue = []
@asserted = true

class << self
def push(&block)
@queue.push(block)
def push(&command)
@queue.push(CommandBlock.new(&command))
self
end

def pop
@queue.pop
def callback(&callback)
@queue.last.callback = callback
end

def execute
shift.try(:call)
def assert(cls)
return if empty?

@asserted = !!(peek.callback.try(:call, cls) && shift)
end

def shift
@queue.shift
def asserted?
@asserted
end

def execute
return unless present? && asserted?

if peek.callback.present?
@asserted = false
peek.call
else
shift.call
end
end

def size
@queue.size
end

def clear
@asserted = true
@queue.clear
end

Expand All @@ -34,6 +55,16 @@ def empty?
def present?
@queue.present?
end

private

def peek
@queue.first
end

def shift
@queue.shift
end
end
end
end
2 changes: 1 addition & 1 deletion app/services/telegram/command_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class CommandRoute
CREATE_ALPHA = /^#{Telegram::Command::Action::CREATE}#{BOT_REGEXP}\s+(?<secret>[[:alpha:]]+)$/i
CREATE_DIGIT = /^#{Telegram::Command::Action::CREATE}#{BOT_REGEXP}\s+(?<number>[[:digit:]]+)$/i
GUESS = /^#{Telegram::Command::Action::GUESS}#{BOT_REGEXP}\s+(?<guess>[[:alpha:]]+)$/i
WORD = /^(?<guess>[[:alpha:]]+)$/i
WORD = /\A(?<guess>[[:alpha:]]+)\z/im
HELP = /^#{Telegram::Command::Action::HELP}#{BOT_REGEXP}$/i
HINT_ALPHA = /^#{Telegram::Command::Action::HINT}#{BOT_REGEXP}\s*(?<letter>[[:alpha:]])?$/i
HINT_DIGIT = /^#{Telegram::Command::Action::HINT}#{BOT_REGEXP}\s+(?<number>[[:digit:]])$/i
Expand Down
1 change: 1 addition & 0 deletions app/services/telegram_dispatcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def execute(command, channel, message)
case command
when Telegram::CommandRoute::START
Telegram::Command::Start.execute(channel)
Telegram::CommandQueue.execute

when Telegram::CommandRoute::LANG
Telegram::Command::Language.ask(channel)
Expand Down
6 changes: 4 additions & 2 deletions spec/controllers/hooks/telegram_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
context 'when receives telegram message with /start command' do
before do
allow(TelegramMessenger).to receive(:send_message)
allow(Telegram::CommandQueue).to receive(:push)
allow(Telegram::CommandQueue).to receive(:callback)
allow(Telegram::CommandQueue).to receive(:push).and_return(Telegram::CommandQueue)
end

let!(:command) {
Expand Down Expand Up @@ -59,7 +60,8 @@
expect(response).to be_success
expect(response).to have_http_status(200)

expect(Telegram::CommandQueue).to have_received(:push).twice
expect(Telegram::CommandQueue).to have_received(:push).thrice
expect(Telegram::CommandQueue).to have_received(:callback).twice

expect(json).to be
expect(json['text']).to eq('')
Expand Down
92 changes: 92 additions & 0 deletions spec/services/telegram/command_queue_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
require 'rails_helper'

describe Telegram::CommandQueue, type: :service do
let!(:channel) { Random.rand(@MAX_INT_VALUE) }

before do
allow(TelegramMessenger).to receive(:ask_level)
end

context 'given empty queue' do
after do
Telegram::CommandQueue.clear
end

it 'verify queue size' do
expect(Telegram::CommandQueue.size).to eq(0)
end

it 'verify queue empty state' do
expect(Telegram::CommandQueue.empty?).to be true
end

it 'verify clear succeeds' do
expect(Telegram::CommandQueue.clear).to eq([])
end

it 'verify not present state' do
expect(Telegram::CommandQueue.present?).to eq false
end

it 'verify not present state' do
expect(Telegram::CommandQueue.present?).to eq false
end

it 'verify push increments queue size' do
expect{
Telegram::CommandQueue.push{ TelegramMessenger.ask_level(channel) }
}.to change(Telegram::CommandQueue, :size).by(1)
end
end

context 'given one command with assertion in a queue' do
before do
allow(GameEngineService).to receive(:settings)
allow(TelegramMessenger).to receive(:level)

Telegram::CommandQueue.push{ TelegramMessenger.ask_level(channel) }.callback { |cls| cls == Telegram::Command::Level }
end

after do
Telegram::CommandQueue.clear
end

it 'verify queue size' do
expect(Telegram::CommandQueue.size).to eq(1)
end

it 'verify queue not empty state' do
expect(Telegram::CommandQueue.empty?).to be false
end

it 'verify queue present state' do
expect(Telegram::CommandQueue.present?).to be true
end

context 'when command had executed' do
before do
Telegram::CommandQueue.execute
end

it 'verify queue false assertion state' do
expect(Telegram::CommandQueue.size).to eq(1)
end

let!(:dictionary) { create :dictionary, lang: 'RU'}
it 'verify queue /language command fails expected callback assertion' do
expect{
Telegram::Command::Language.execute(channel, 'RU')
expect(Telegram::CommandQueue.asserted?).to eq(false)
}.not_to change(Telegram::CommandQueue, :size)
end

it 'verify queue /level command executes with successful callback and assertion' do
expect{
Telegram::Command::Level.execute(channel, 'easy')
expect(Telegram::CommandQueue.asserted?).to eq(true)
}.to change(Telegram::CommandQueue, :size).by(-1)
end
end
end

end
76 changes: 27 additions & 49 deletions spec/services/telegram_dispatcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
expect(TelegramDispatcher.handle(message)).to be
expect(TelegramMessenger).to have_received(:send_message).with(channel, /Welcome to Bulls and Cows!/).once
expect(TelegramMessenger).to have_received(:send_message).with(channel, 'Select game language:', markup).once
}.to change(Telegram::CommandQueue, :size).by(2)
}.to change(Telegram::CommandQueue, :size).by(3)
end
end

Expand Down Expand Up @@ -704,14 +704,29 @@
end
end

context 'when non command multiple words is received with exact guess' do
context 'when non command multiple words is received' do
let!(:message) { Telegram::Bot::Types::Message.new(text: 'hello world') }

before do
message.stub_chain(:chat, :id).and_return(channel)
message.stub_chain(:from, :username).and_return(user.name)
end

it 'ignore the message' do
expect {
TelegramDispatcher.handle(message)
}.not_to change(Guess, :count)
end
end

context 'when multiline non command words is received' do
let!(:message) { Telegram::Bot::Types::Message.new(text: "line\nanother line\nthird") }

before do
message.stub_chain(:chat, :id).and_return(channel)
message.stub_chain(:from, :username).and_return(user.name)
end

it 'ignore the message' do
expect {
expect(TelegramDispatcher.handle(message)).to be_nil
Expand Down Expand Up @@ -977,11 +992,15 @@

describe Telegram::CommandQueue do

context 'given empty command queue' do
after do
Telegram::CommandQueue.clear
end
before do
Telegram::CommandQueue.clear
end

after do
Telegram::CommandQueue.clear
end

context 'given empty command queue' do
it 'checks if queue is empty' do
expect{
expect(Telegram::CommandQueue.empty?).to be true
Expand All @@ -996,35 +1015,16 @@
expect(Telegram::CommandQueue.present?).to be true
}.to change(Telegram::CommandQueue, :size).by(1)
end

it 'fails to remove code block from empty queue' do
expect{
expect(Telegram::CommandQueue.pop).not_to be
}.not_to change(Telegram::CommandQueue, :size)
end

end

context 'given one code block in command queue' do
before do
Telegram::CommandQueue.push{ 'block to pop' }
end

after do
Telegram::CommandQueue.clear
Telegram::CommandQueue.push{ 'block' + ' to execute' }
end

it 'executes and removed code block' do
expect{
expect(Telegram::CommandQueue.execute).to eq('block to pop')
}.to change(Telegram::CommandQueue, :size).by(-1)
end

it 'removes code block' do
expect{
block = Telegram::CommandQueue.pop
expect(block).to be
expect(block.call).to eq('block to pop')
expect(Telegram::CommandQueue.execute).to eq('block' + ' to execute')
}.to change(Telegram::CommandQueue, :size).by(-1)
end
end
Expand All @@ -1035,32 +1035,12 @@
Telegram::CommandQueue.push{ 'code block 2' }
end

after do
Telegram::CommandQueue.clear
end

it 'gives total amount of blocks' do
expect{
expect(Telegram::CommandQueue.size).to eq(2)
}.not_to change(Telegram::CommandQueue, :size)
end

it 'gets and removes first pushed code block (FIFO)' do
expect{
block = Telegram::CommandQueue.pop
expect(block).to be
expect(block.call).to eq('code block 2')
}.to change(Telegram::CommandQueue, :size).by(-1)
end

it 'gets and removes first pushed code block (LIFO)' do
expect{
block = Telegram::CommandQueue.shift
expect(block).to be
expect(block.call).to eq('code block 1')
}.to change(Telegram::CommandQueue, :size).by(-1)
end

it 'removes all code blocks' do
expect{
expect(Telegram::CommandQueue.clear).to be_empty
Expand All @@ -1078,8 +1058,6 @@
expect(Telegram::CommandQueue.execute).to eq('code block 1')
}.to change(Telegram::CommandQueue, :size).by(-1)
end

end


end

0 comments on commit 348c20d

Please sign in to comment.