Skip to content

Commit

Permalink
Command Object
Browse files Browse the repository at this point in the history
  • Loading branch information
stgeneral authored Aug 17, 2019
1 parent b09ebc5 commit 50f60f2
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 4 deletions.
5 changes: 2 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ Layout/AlignArguments:
#################### Metrics ##############################

Metrics/BlockLength:
Exclude:
- auxiliary_rails.gemspec
- 'spec/**/*_spec.rb'
ExcludedMethods:
- describe

#################### Style ###############################

Expand Down
106 changes: 106 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,110 @@ PATH
GEM
remote: https://rubygems.org/
specs:
actioncable (5.2.3)
actionpack (= 5.2.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.3)
actionview (= 5.2.3)
activesupport (= 5.2.3)
rack (~> 2.0)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.2.3)
activesupport (= 5.2.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.2.3)
activesupport (= 5.2.3)
globalid (>= 0.3.6)
activemodel (5.2.3)
activesupport (= 5.2.3)
activerecord (5.2.3)
activemodel (= 5.2.3)
activesupport (= 5.2.3)
arel (>= 9.0)
activestorage (5.2.3)
actionpack (= 5.2.3)
activerecord (= 5.2.3)
marcel (~> 0.3.1)
activesupport (5.2.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
ast (2.4.0)
builder (3.2.3)
coderay (1.1.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
diff-lcs (1.3)
erubi (1.8.0)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jaro_winkler (1.5.2)
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
method_source (0.9.2)
ast (~> 2.4.0)
mimemagic (0.3.3)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
nio4r (2.4.0)
nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
parallel (1.17.0)
parser (2.6.3.0)
ast (~> 2.4.0)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
psych (3.1.0)
rack (2.0.7)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.3)
actioncable (= 5.2.3)
actionmailer (= 5.2.3)
actionpack (= 5.2.3)
actionview (= 5.2.3)
activejob (= 5.2.3)
activemodel (= 5.2.3)
activerecord (= 5.2.3)
activestorage (= 5.2.3)
activesupport (= 5.2.3)
bundler (>= 1.3.0)
railties (= 5.2.3)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
railties (5.2.3)
actionpack (= 5.2.3)
activesupport (= 5.2.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (10.5.0)
rspec (3.8.0)
Expand Down Expand Up @@ -47,8 +139,21 @@ GEM
rubocop-rspec (1.32.0)
rubocop (>= 0.60.0)
ruby-progressbar (1.10.0)
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.20.3)
thread_safe (0.3.6)
tzinfo (1.2.5)
thread_safe (~> 0.1)
unicode-display_width (1.5.0)
websocket-driver (0.7.1)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.4)

PLATFORMS
ruby
Expand All @@ -57,6 +162,7 @@ DEPENDENCIES
auxiliary_rails!
bundler (~> 2.0)
pry
rails (~> 5.2)
rake (~> 10.0)
rspec (~> 3.0)
rubocop
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ rails new APP_PATH --skip-action-cable --skip-coffee --skip-test --database=post
### Generators

```sh
rails generate auxiliary_rails:api_resource
# install everything
rails generate auxiliary_rails:install

# install one by one
rails generate auxiliary_rails:install_commands
rails generate auxiliary_rails:install_errors
rails generate auxiliary_rails:install_rubocop
rails generate auxiliary_rails:install_rubocop --no-specify-gems
Expand Down
1 change: 1 addition & 0 deletions auxiliary_rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Gem::Specification.new do |spec|

spec.add_development_dependency 'bundler', '~> 2.0'
spec.add_development_dependency 'pry'
spec.add_development_dependency 'rails', '~> 5.2'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop'
Expand Down
1 change: 1 addition & 0 deletions lib/auxiliary_rails.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'auxiliary_rails/abstract_error'
require 'auxiliary_rails/abstract_command'
require 'auxiliary_rails/railtie' if defined?(Rails)
require 'auxiliary_rails/version'

Expand Down
96 changes: 96 additions & 0 deletions lib/auxiliary_rails/abstract_command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require 'active_model'

module AuxiliaryRails
class AbstractCommand
include ActiveModel::Model
include ActiveModel::Attributes

def self.call(*args)
new(*args).call
end

def call
raise NotImplementedError
end

def errors
@errors ||= ActiveModel::Errors.new(self)
end

def failure?
status?(:failure)
end

def status?(value)
ensure_execution!

status == value&.to_sym
end

def success?
status?(:success)
end

def transaction(&block)
ActiveRecord::Base.transaction(&block) if block_given?
end

# Method for ActiveModel::Errors
def read_attribute_for_validation(attr_name)
if attr_name == :command
self
else
attribute(attr_name)
end
end

# Method for ActiveModel::Translation
def self.i18n_scope
:commands
end

protected

attr_accessor :status

def ensure_empty_errors!
return if errors.empty?

error!("`#{self.class}` contains errors.")
end

def ensure_empty_status!
return if status.nil?

error!("`#{self.class}` was already executed.")
end

def ensure_execution!
return if status.present?

error!("`#{self.class}` was not executed yet.")
end

def error!(message = nil)
message ||= "`#{self.class}` raised error."
raise ApplicationError, message
end

def failure!(message = nil)
ensure_empty_status!

errors.add(:command, :failed, message: message) unless message.nil?

self.status = :failure
self
end

def success!
ensure_empty_errors!
ensure_empty_status!

self.status = :success
self
end
end
end
12 changes: 12 additions & 0 deletions lib/generators/auxiliary_rails/install_commands_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'rails'

module AuxiliaryRails
class InstallCommandsGenerator < ::Rails::Generators::Base
source_root File.expand_path('templates', __dir__)

def copy_application_command_file
copy_file 'application_command_template.rb',
'app/commands/application_command.rb'
end
end
end
11 changes: 11 additions & 0 deletions lib/generators/auxiliary_rails/install_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'rails'

module AuxiliaryRails
class InstallGenerator < ::Rails::Generators::Base
def install
generate 'auxiliary_rails:install_commands'
generate 'auxiliary_rails:install_errors'
generate 'auxiliary_rails:install_rubocop --no-specify-gems'
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ApplicationCommand < AuxiliaryRails::AbstractCommand
end
17 changes: 17 additions & 0 deletions spec/auxiliary_rails/abstract_command_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
RSpec.describe AuxiliaryRails::AbstractCommand do
describe '#call' do
subject(:cmd_class) { described_class }

it 'raises NotImplementedError exception' do
expect { cmd_class.call }.to raise_error NotImplementedError
end
end

describe '.call' do
subject(:cmd) { described_class.new }

it 'raises NotImplementedError exception' do
expect { cmd.call }.to raise_error NotImplementedError
end
end
end
61 changes: 61 additions & 0 deletions spec/sample_commands_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
require 'support/sample_classes/sample_commands'

RSpec.describe SampleCommands do
describe 'SuccessCommand' do
describe '#call' do
subject(:cmd_class) { SampleCommands::SuccessCommand }

it do
expect(cmd_class.call).to be_a cmd_class
end
end

describe '.call' do
subject(:cmd) { SampleCommands::SuccessCommand.new }

it 'returns self as a result' do
expect(cmd.call).to be cmd
end

it do
expect(cmd.call).to be_success
end
end
end

describe 'DoubleStatusSetCommand' do
subject(:cmd) { SampleCommands::DoubleStatusSetCommand.new }

describe '.call' do
it do
expect { cmd.call }.to raise_error ApplicationError,
'`SampleCommands::DoubleStatusSetCommand` was already executed.'
end
end
end

describe 'SuccessWithErrorsCommand' do
subject(:cmd) { SampleCommands::SuccessWithErrorsCommand.new }

describe '.call' do
it do
expect { cmd.call }.to raise_error ApplicationError,
'`SampleCommands::SuccessWithErrorsCommand` contains errors.'
end
end
end

describe 'FailureWithErrorsCommand' do
subject(:cmd) { SampleCommands::FailureWithErrorsCommand.new }

describe '.call' do
it do
expect { cmd.call }.to change(cmd.errors, :count).from(0).to(1)
end

it do
puts cmd.call.errors.full_messages
end
end
end
end
Loading

0 comments on commit 50f60f2

Please sign in to comment.