Skip to content

Commit

Permalink
Write tests and fix implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
aldesantis committed Dec 19, 2016
1 parent 3c76d2f commit df83a36
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 17 deletions.
3 changes: 3 additions & 0 deletions lib/pragma/operation.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# frozen_string_literal: true
require 'interactor'

require 'pragma/operation/version'
require 'pragma/operation/base'

module Pragma
# Operations provide business logic encapsulation for your JSON API.
Expand Down
57 changes: 40 additions & 17 deletions lib/pragma/operation/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@ class Base
511 => :network_authentication_required
}.freeze

before :setup_context
def self.inherited(child)
child.class_eval do
before :setup_context

around :handle_halt
around :handle_halt

after :set_default_status
after :validate_status
after :consolidate_status
after :mark_result
after :mark_result
after :consolidate_status
after :validate_status
after :set_default_status
end
end

# Runs the operation.
def call
Expand Down Expand Up @@ -173,23 +177,42 @@ def consolidate_status
end

def mark_result
return if /\A(2|3)\d{2}\z/ =~ STATUSES.invert[context.status]
return if /\A(2|3)\d{2}\z/ =~ STATUSES.invert[context.status].to_s
context.fail!
end

# This error is raised when an invalid status is set for an operation.
#
# @author Alessandro Desantis
class InvalidStatusError < StandardError
# Initializes the error.
#
# @param [Integer|Symbol] an invalid HTTP status code
def initialize(status)
super "'#{status}' is not a valid HTTP status code."
def with_hooks
# This overrides the default behavior, which is not to run after hooks if an exception is
# raised either in +#call+ or one of the before hooks. See:
# https://github.com/collectiveidea/interactor/blob/master/lib/interactor/hooks.rb#L210)
run_around_hooks do
begin
run_before_hooks
yield
ensure
run_after_hooks
end
end
end
end

# This error is raised when an invalid status is set for an operation.
#
# @author Alessandro Desantis
class InvalidStatusError < StandardError
# Initializes the error.
#
# @param [Integer|Symbol] an invalid HTTP status code
def initialize(status)
super "'#{status}' is not a valid HTTP status code."
end
end

Halt = StandardError
# This error is raised when the operation's execution should be stopped. It is silently
# rescued by the operation.
#
# @author Alessandro Desantis
class Halt < StandardError
end
end
end
100 changes: 100 additions & 0 deletions spec/pragma/operation/base_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# frozen_string_literal: true
RSpec.describe Pragma::Operation::Base do
let(:operation) do
Class.new(described_class) do
before :validate_params

def call
respond_with(
status: 200,
resource: { pong: params[:pong] }
)
end

private

def validate_params
return unless params[:pong].empty?

respond_with!(
status: 422,
resource: {
error_type: :missing_pong,
error_message: "You must provide a 'pong' parameter."
}
)
end
end
end

let(:params) { { pong: 'HELLO' } }
let(:context) { operation.call(params: params) }

it 'converts numeric status codes into symbols' do
expect(context.status).to eq(:ok)
end

context 'when the response status is invalid' do
let(:operation) do
Class.new(described_class) do
def call
head :invalid
end
end
end

it 'raises an InvalidStatusError' do
expect { context }.to raise_error(Pragma::Operation::InvalidStatusError)
end
end

context 'when the operation does not set a status code' do
let(:operation) do
Class.new(described_class) do
def call
respond_with status: nil, resource: params[:resource]
end
end
end

context 'when a resource is set' do
let(:params) { { resource: 'HELLO' } }

it 'sets the 200 OK status code' do
expect(context.status).to eq(:ok)
end
end

context 'when a resource is not set' do
let(:params) { {} }

it 'sets the 204 No Content status code' do
expect(context.status).to eq(:no_content)
end
end
end

describe '#respond_with!' do
let(:params) { { pong: '' } }

it 'halts the execution' do
expect(context.status).to eq(:unprocessable_entity)
end
end

describe '#success?' do
context 'when the HTTP status code is successful' do
it 'returns true' do
expect(context).to be_success
end
end

context 'when the HTTP status code is not successful' do
let(:params) { { pong: '' } }

it 'returns false' do
expect(context).not_to be_success
end
end
end
end

0 comments on commit df83a36

Please sign in to comment.