auxiliary_rails 0.1.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +26 -0
- data/.rubocop.yml +27 -2
- data/.rubocop_todo.yml +5 -15
- data/.yardopts +5 -0
- data/CHANGELOG.md +39 -3
- data/CONTRIBUTING.md +0 -6
- data/Gemfile.lock +116 -92
- data/README.md +213 -6
- data/auxiliary_rails.gemspec +13 -12
- data/bin/rubocop +29 -0
- data/bitbucket-pipelines.yml +35 -0
- data/lib/auxiliary_rails.rb +5 -3
- data/lib/auxiliary_rails/application/command.rb +56 -0
- data/lib/auxiliary_rails/application/error.rb +10 -0
- data/lib/auxiliary_rails/application/form.rb +30 -0
- data/lib/auxiliary_rails/application/query.rb +71 -0
- data/lib/auxiliary_rails/cli.rb +18 -5
- data/lib/auxiliary_rails/concerns/errorable.rb +22 -0
- data/lib/auxiliary_rails/concerns/performable.rb +128 -0
- data/lib/auxiliary_rails/version.rb +1 -1
- data/lib/generators/auxiliary_rails/api_resource_generator.rb +10 -1
- data/lib/generators/auxiliary_rails/command_generator.rb +44 -0
- data/lib/generators/auxiliary_rails/install_commands_generator.rb +6 -1
- data/lib/generators/auxiliary_rails/install_generator.rb +0 -1
- data/lib/generators/auxiliary_rails/templates/apis/api_entity_template.rb.erb +2 -1
- data/lib/generators/auxiliary_rails/templates/apis/api_resource_spec_template.rb.erb +36 -9
- data/lib/generators/auxiliary_rails/templates/apis/api_resource_template.rb.erb +12 -6
- data/lib/generators/auxiliary_rails/templates/application_error_template.rb +1 -1
- data/lib/generators/auxiliary_rails/templates/commands/application_command_template.rb +2 -0
- data/lib/generators/auxiliary_rails/templates/commands/command_spec_template.rb +11 -0
- data/lib/generators/auxiliary_rails/templates/commands/command_template.rb +6 -0
- data/lib/generators/auxiliary_rails/templates/commands/commands.en_template.yml +5 -0
- data/templates/rails/elementary.rb +40 -10
- metadata +81 -24
- data/lib/auxiliary_rails/abstract_command.rb +0 -96
- data/lib/auxiliary_rails/abstract_error.rb +0 -7
- data/lib/generators/auxiliary_rails/install_rubocop_generator.rb +0 -29
- data/lib/generators/auxiliary_rails/templates/application_command_template.rb +0 -2
- data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_auxiliary_rails_template.yml +0 -51
- data/lib/generators/auxiliary_rails/templates/rubocop/rubocop_template.yml +0 -7
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'auxiliary_rails/concerns/errorable'
|
2
|
+
require 'dry/core/class_attributes'
|
3
|
+
require 'dry-initializer'
|
4
|
+
|
5
|
+
module AuxiliaryRails
|
6
|
+
module Application
|
7
|
+
class Query
|
8
|
+
extend Dry::Core::ClassAttributes
|
9
|
+
extend Dry::Initializer
|
10
|
+
include AuxiliaryRails::Concerns::Errorable
|
11
|
+
|
12
|
+
defines :default_relation
|
13
|
+
|
14
|
+
option :relation, default: proc { nil }
|
15
|
+
|
16
|
+
def self.call(*args)
|
17
|
+
new(*args).call
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
ensure_proper_relation_types!
|
22
|
+
|
23
|
+
perform
|
24
|
+
|
25
|
+
query
|
26
|
+
end
|
27
|
+
|
28
|
+
def perform
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(method_name, *args, &block)
|
33
|
+
super unless query.respond_to?(method_name)
|
34
|
+
|
35
|
+
query.send(method_name, *args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def respond_to_missing?(method_name, include_private = false)
|
39
|
+
query.respond_to?(method_name) || super
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# rubocop:disable Metrics/AbcSize, Style/GuardClause
|
45
|
+
def ensure_proper_relation_types!
|
46
|
+
if self.class.default_relation.nil?
|
47
|
+
error!('Undefined `default_relation`')
|
48
|
+
end
|
49
|
+
if !queriable_object?(self.class.default_relation)
|
50
|
+
error!('Invalid class of `default_relation`')
|
51
|
+
end
|
52
|
+
if !relation.nil? && !queriable_object?(relation)
|
53
|
+
error!('Invalid class of `relation` option')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
# rubocop:enable Metrics/AbcSize, Style/GuardClause
|
57
|
+
|
58
|
+
def queriable_object?(object)
|
59
|
+
object.is_a?(ActiveRecord::Relation)
|
60
|
+
end
|
61
|
+
|
62
|
+
def query(scoped_query = nil)
|
63
|
+
@query ||= (relation || self.class.default_relation)
|
64
|
+
|
65
|
+
@query = scoped_query unless scoped_query.nil?
|
66
|
+
|
67
|
+
@query
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/auxiliary_rails/cli.rb
CHANGED
@@ -6,6 +6,10 @@ module AuxiliaryRails
|
|
6
6
|
|
7
7
|
TEMPLATES_DIR =
|
8
8
|
File.expand_path("#{__dir__}/../../templates/")
|
9
|
+
REPOSITORY_URL =
|
10
|
+
'https://raw.githubusercontent.com/ergoserv/' \
|
11
|
+
'auxiliary_rails/develop/templates'
|
12
|
+
.freeze
|
9
13
|
|
10
14
|
desc 'new APP_PATH', 'Create Rails application from template'
|
11
15
|
long_desc <<-LONGDESC
|
@@ -17,20 +21,29 @@ module AuxiliaryRails
|
|
17
21
|
option :database,
|
18
22
|
default: 'postgresql',
|
19
23
|
type: :string
|
20
|
-
option :
|
24
|
+
option :template,
|
21
25
|
default: 'elementary',
|
22
26
|
type: :string
|
27
|
+
option :develop,
|
28
|
+
default: false,
|
29
|
+
type: :boolean
|
23
30
|
def new(app_path)
|
24
31
|
run "rails new #{app_path} " \
|
25
|
-
'--skip-action-cable --skip-coffee --skip-test ' \
|
26
32
|
"--database=#{options[:database]} " \
|
27
|
-
"--template=#{rails_template_path(options[:
|
33
|
+
"--template=#{rails_template_path(options[:template])} " \
|
34
|
+
'--skip-action-cable ' \
|
35
|
+
'--skip-coffee ' \
|
36
|
+
'--skip-test '
|
28
37
|
end
|
29
38
|
|
30
39
|
private
|
31
40
|
|
32
|
-
def rails_template_path(
|
33
|
-
|
41
|
+
def rails_template_path(template)
|
42
|
+
if options[:develop] == true
|
43
|
+
"#{REPOSITORY_URL}/rails/#{template}.rb"
|
44
|
+
else
|
45
|
+
"#{TEMPLATES_DIR}/rails/#{template}.rb"
|
46
|
+
end
|
34
47
|
end
|
35
48
|
end
|
36
49
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AuxiliaryRails
|
2
|
+
module Concerns
|
3
|
+
module Errorable
|
4
|
+
# extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def error!(message = nil)
|
7
|
+
message ||= "`#{self.class}` raised error."
|
8
|
+
raise error_class, message
|
9
|
+
end
|
10
|
+
|
11
|
+
if defined?(ApplicationError)
|
12
|
+
def error_class
|
13
|
+
ApplicationError
|
14
|
+
end
|
15
|
+
else
|
16
|
+
def error_class
|
17
|
+
AuxiliaryRails::Application::Error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'auxiliary_rails/concerns/errorable'
|
3
|
+
|
4
|
+
module AuxiliaryRails
|
5
|
+
module Concerns
|
6
|
+
module Performable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include ActiveModel::Validations
|
9
|
+
include AuxiliaryRails::Concerns::Errorable
|
10
|
+
|
11
|
+
class_methods do
|
12
|
+
def call(*args)
|
13
|
+
new(*args).call
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(options = {})
|
18
|
+
ensure_empty_status!
|
19
|
+
|
20
|
+
if options[:validate!] == true
|
21
|
+
validate!
|
22
|
+
elsif options[:validate] != false && invalid?
|
23
|
+
return failure!
|
24
|
+
end
|
25
|
+
|
26
|
+
perform
|
27
|
+
|
28
|
+
ensure_execution!
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Describes business logic.
|
33
|
+
#
|
34
|
+
# Method <b>should always</b> return <tt>success!</tt>
|
35
|
+
# or <tt>failure!</tt> methods in order pro provide further
|
36
|
+
# correct method chaining.
|
37
|
+
#
|
38
|
+
# @abstract
|
39
|
+
# @return [self]
|
40
|
+
def perform
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def failure?
|
45
|
+
status?(:failure)
|
46
|
+
end
|
47
|
+
|
48
|
+
def status?(value)
|
49
|
+
ensure_execution!
|
50
|
+
|
51
|
+
performable_status == value&.to_sym
|
52
|
+
end
|
53
|
+
|
54
|
+
def success?
|
55
|
+
status?(:success)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Provides ability to execude block of the code depending on
|
59
|
+
# command execution status
|
60
|
+
#
|
61
|
+
# @param status [Symol] Desired command status
|
62
|
+
# @param &_block Code to be executed if status matches
|
63
|
+
# @return [self]
|
64
|
+
def on(status, &_block)
|
65
|
+
ensure_execution!
|
66
|
+
|
67
|
+
return self unless status?(status)
|
68
|
+
|
69
|
+
yield(self) if block_given?
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Shortcut for <tt>ActiveRecord::Base.transaction</tt>
|
75
|
+
def transaction(&block)
|
76
|
+
ActiveRecord::Base.transaction(&block) if block_given?
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
attr_accessor :performable_status
|
82
|
+
|
83
|
+
# @raise [AuxiliaryRails::Application::Error]
|
84
|
+
# Error happens if command contains any errors.
|
85
|
+
# @return [nil]
|
86
|
+
def ensure_empty_errors!
|
87
|
+
return if errors.empty?
|
88
|
+
|
89
|
+
error!("`#{self.class}` contains errors.")
|
90
|
+
end
|
91
|
+
|
92
|
+
def ensure_empty_status!
|
93
|
+
return if performable_status.nil?
|
94
|
+
|
95
|
+
error!("`#{self.class}` was already executed.")
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_execution!
|
99
|
+
return if performable_status.present?
|
100
|
+
|
101
|
+
error!("`#{self.class}` was not executed yet.")
|
102
|
+
end
|
103
|
+
|
104
|
+
# Sets command's status to <tt>failure</tt>.
|
105
|
+
#
|
106
|
+
# @return [self]
|
107
|
+
def failure!(message = nil, options = {})
|
108
|
+
ensure_empty_status!
|
109
|
+
|
110
|
+
errors.add(:base, message, options) if message.present?
|
111
|
+
|
112
|
+
self.performable_status = :failure
|
113
|
+
self
|
114
|
+
end
|
115
|
+
|
116
|
+
# Sets command's status to <tt>success</tt>.
|
117
|
+
#
|
118
|
+
# @return [self]
|
119
|
+
def success!
|
120
|
+
ensure_empty_errors!
|
121
|
+
ensure_empty_status!
|
122
|
+
|
123
|
+
self.performable_status = :success
|
124
|
+
self
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -37,7 +37,12 @@ module AuxiliaryRails
|
|
37
37
|
|
38
38
|
def create_api_resource_spec_file
|
39
39
|
template 'api_resource_spec_template.rb.erb',
|
40
|
-
"spec/#{api_module_path}/#{plural_file_name}_resource_spec.rb"
|
40
|
+
"spec/#{api_module_path}/resources/#{plural_file_name}_resource_spec.rb"
|
41
|
+
end
|
42
|
+
|
43
|
+
def say_instructions
|
44
|
+
say "Mount resource in #{api_module_name}:"
|
45
|
+
say " mount #{resource_class_name}"
|
41
46
|
end
|
42
47
|
|
43
48
|
private
|
@@ -59,5 +64,9 @@ module AuxiliaryRails
|
|
59
64
|
def entity_class_name
|
60
65
|
"#{api_module_name}::Entities::#{class_name}Entity"
|
61
66
|
end
|
67
|
+
|
68
|
+
def resource_class_name
|
69
|
+
"#{api_module_name}::Resources::#{plural_name.camelize}Resource"
|
70
|
+
end
|
62
71
|
end
|
63
72
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module AuxiliaryRails
|
4
|
+
class CommandGenerator < ::Rails::Generators::NamedBase
|
5
|
+
desc 'Stubs out a new Command and spec.'
|
6
|
+
|
7
|
+
source_root File.expand_path('templates/commands', __dir__)
|
8
|
+
|
9
|
+
class_option :path,
|
10
|
+
type: :string,
|
11
|
+
default: 'app/commands',
|
12
|
+
desc: 'Command location'
|
13
|
+
|
14
|
+
def create_command_file
|
15
|
+
FileUtils.mkdir_p(command_file_path)
|
16
|
+
template 'command_template.rb',
|
17
|
+
"#{command_file_path}/#{command_file_name}.rb"
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_command_spec_file
|
21
|
+
FileUtils.mkdir_p(command_spec_path)
|
22
|
+
template 'command_spec_template.rb',
|
23
|
+
"#{command_spec_path}/#{command_file_name}_spec.rb"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def command_class_name
|
29
|
+
"#{class_name.gsub(/Command$/, '')}Command"
|
30
|
+
end
|
31
|
+
|
32
|
+
def command_file_name
|
33
|
+
command_class_name.underscore
|
34
|
+
end
|
35
|
+
|
36
|
+
def command_file_path
|
37
|
+
options[:path]
|
38
|
+
end
|
39
|
+
|
40
|
+
def command_spec_path
|
41
|
+
command_file_path.gsub(%r{^app/}, 'spec/')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -2,11 +2,16 @@ require 'rails'
|
|
2
2
|
|
3
3
|
module AuxiliaryRails
|
4
4
|
class InstallCommandsGenerator < ::Rails::Generators::Base
|
5
|
-
source_root File.expand_path('templates', __dir__)
|
5
|
+
source_root File.expand_path('templates/commands', __dir__)
|
6
6
|
|
7
7
|
def copy_application_command_file
|
8
8
|
copy_file 'application_command_template.rb',
|
9
9
|
'app/commands/application_command.rb'
|
10
10
|
end
|
11
|
+
|
12
|
+
def copy_locale_command_file
|
13
|
+
copy_file 'commands.en_template.yml',
|
14
|
+
'config/locales/commands.en.yml'
|
15
|
+
end
|
11
16
|
end
|
12
17
|
end
|
@@ -1,11 +1,18 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
|
-
RSpec.describe <%=
|
3
|
+
RSpec.describe <%= resource_class_name %>, type: :request do
|
4
4
|
describe 'GET <%= api_url_path %>' do
|
5
5
|
subject { get '<%= api_url_path %>' }
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
it 'returns a list of <%= plural_name %>' do
|
8
|
+
create_list(:<%= singular_name %>, 2)
|
9
|
+
|
10
|
+
subject
|
11
|
+
|
12
|
+
expect_status :ok
|
13
|
+
expect_json_sizes 2
|
14
|
+
expect_json '0', id: <%= class_name %> %>.first.id
|
15
|
+
end
|
9
16
|
end
|
10
17
|
|
11
18
|
describe 'POST <%= api_url_path %>' do
|
@@ -16,17 +23,37 @@ RSpec.describe <%= api_module_name %>::Resources::<%= plural_name.camelize %>Res
|
|
16
23
|
end
|
17
24
|
|
18
25
|
describe 'GET <%= api_url_path %>/:id' do
|
19
|
-
|
20
|
-
|
26
|
+
subject { get "<%= api_url_path %>/#{<%= singular_name %>.id}" }
|
27
|
+
|
28
|
+
let(:<%= singular_name %>) { create(:<%= singular_name %>) }
|
29
|
+
|
30
|
+
it 'returns a <%= singular_name %> by ID' do
|
31
|
+
subject
|
32
|
+
|
33
|
+
expect_status :ok
|
34
|
+
expect_json id: <%= singular_name %>.id
|
35
|
+
end
|
21
36
|
end
|
22
37
|
|
23
38
|
describe 'PUT <%= api_url_path %>/:id' do
|
24
|
-
|
25
|
-
|
39
|
+
subject { put "<%= api_url_path %>/#{<%= singular_name %>.id}" }
|
40
|
+
|
41
|
+
let(:<%= singular_name %>) { create(:<%= singular_name %>) }
|
42
|
+
|
43
|
+
it 'updates a <%= singular_name %> by ID' do
|
44
|
+
skip
|
45
|
+
end
|
26
46
|
end
|
27
47
|
|
28
48
|
describe 'DELETE <%= api_url_path %>/:id' do
|
29
|
-
|
30
|
-
|
49
|
+
subject { delete "<%= api_url_path %>/#{<%= singular_name %>.id}" }
|
50
|
+
|
51
|
+
let!(:<%= singular_name %>) { create(:<%= singular_name %>) }
|
52
|
+
|
53
|
+
it 'deletes a <%= singular_name %> by ID' do
|
54
|
+
expect { subject }.to change(<%= class_name %>, :count).by -1
|
55
|
+
expect_status 204
|
56
|
+
expect(response.body).to be_blank
|
57
|
+
end
|
31
58
|
end
|
32
59
|
end
|