hmvc-rails 1.0.0
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 +7 -0
- data/.rubocop.yml +34 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +172 -0
- data/LICENSE.txt +21 -0
- data/README.md +302 -0
- data/Rakefile +14 -0
- data/lib/generators/hmvc_rails/hmvc_rails_generator.rb +155 -0
- data/lib/generators/hmvc_rails/install_generator.rb +84 -0
- data/lib/generators/hmvc_rails/templates/configures/hmvc_rails.rb.tt +27 -0
- data/lib/generators/hmvc_rails/templates/configures/hmvc_rails_api.rb.tt +27 -0
- data/lib/generators/hmvc_rails/templates/controllers/controller.rb.tt +10 -0
- data/lib/generators/hmvc_rails/templates/extras/error_resource.rb.tt +31 -0
- data/lib/generators/hmvc_rails/templates/extras/error_response.rb.tt +21 -0
- data/lib/generators/hmvc_rails/templates/extras/exception.rb.tt +59 -0
- data/lib/generators/hmvc_rails/templates/forms/application_form.rb.tt +32 -0
- data/lib/generators/hmvc_rails/templates/forms/form.rb.tt +5 -0
- data/lib/generators/hmvc_rails/templates/operations/application_operation.rb.tt +11 -0
- data/lib/generators/hmvc_rails/templates/operations/operation.rb.tt +6 -0
- data/lib/generators/hmvc_rails/templates/validators/email_validator.rb.tt +10 -0
- data/lib/generators/hmvc_rails/templates/validators/uniqueness_validator.rb.tt +29 -0
- data/lib/generators/hmvc_rails/templates/views/view.erb.tt +1 -0
- data/lib/generators/hmvc_rails/templates/views/view.haml.tt +1 -0
- data/lib/generators/hmvc_rails/templates/views/view.slim.tt +1 -0
- data/lib/hmvc/rails/version.rb +7 -0
- data/lib/hmvc/rails.rb +35 -0
- data/lib/rubocop/cop/hmvc_rails/formal_style.rb +16 -0
- data/lib/rubocop/cop/hmvc_rails/operating_style.rb +29 -0
- data/lib/rubocop/cop/hmvc_rails_cops.rb +4 -0
- data/sig/hmvc/rails.rbs +6 -0
- metadata +74 -0
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
class HmvcRailsGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
7
|
+
|
8
|
+
class_option :action, type: :array, default: Hmvc::Rails.configuration.action
|
9
|
+
class_option :form, type: :array, default: Hmvc::Rails.configuration.form
|
10
|
+
class_option :parent_controller, type: :string, default: Hmvc::Rails.configuration.parent_controller
|
11
|
+
class_option :skip_form, type: :boolean, default: false
|
12
|
+
class_option :skip_view, type: :boolean, default: false
|
13
|
+
|
14
|
+
def generate
|
15
|
+
validate_options
|
16
|
+
create_controller
|
17
|
+
create_operation
|
18
|
+
create_form
|
19
|
+
create_view
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def validate_options
|
25
|
+
return if behavior == :revoke
|
26
|
+
|
27
|
+
validate_name
|
28
|
+
validate_params
|
29
|
+
validate_form_option
|
30
|
+
validate_action_option
|
31
|
+
validate_parent_controller_option
|
32
|
+
validate_skip_form_option
|
33
|
+
validate_skip_view_option
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_controller
|
37
|
+
template "controllers/controller.rb",
|
38
|
+
File.join("app/controllers", class_path.join("/"), "#{file_name}_controller.rb")
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_operation
|
42
|
+
options[:action].each do |action|
|
43
|
+
@_action = action
|
44
|
+
template "operations/operation.rb", File.join("app/operations", file_path, "#{action}_operation.rb")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_form
|
49
|
+
return if options[:skip_form] || options[:form].blank?
|
50
|
+
|
51
|
+
forms = options[:form] & options[:action]
|
52
|
+
return puts "Warning: No forms created! Form and action controller does mismatch" if forms.blank?
|
53
|
+
|
54
|
+
forms.each do |action|
|
55
|
+
@_action = action
|
56
|
+
template "forms/form.rb", File.join("app/forms", file_path, "#{action}_form.rb")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_view
|
61
|
+
return if options[:skip_view] || Hmvc::Rails.configuration.view.blank?
|
62
|
+
|
63
|
+
views = Hmvc::Rails.configuration.view & options[:action]
|
64
|
+
return puts "Warning: No views created! View and action controller does mismatch" if views.blank?
|
65
|
+
|
66
|
+
view_engine = Rails.application&.config&.generators&.options&.dig(:rails, :template_engine) || "erb"
|
67
|
+
copy_view_template(views, view_engine)
|
68
|
+
rescue StandardError
|
69
|
+
copy_view_template(views, "erb")
|
70
|
+
end
|
71
|
+
|
72
|
+
def copy_view_template(views, view_engine)
|
73
|
+
views.each do |action|
|
74
|
+
@_action = action
|
75
|
+
template "views/view.#{view_engine}", File.join("app/views", file_path, "#{action}.html.#{view_engine}")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def argv
|
80
|
+
@argv ||= ARGV.map { |arg| arg.split("=") }.flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_name
|
84
|
+
show_error_message("Invalid name arguments '#{argv[1]}'") if argv[1] && !argv[1].start_with?("-")
|
85
|
+
end
|
86
|
+
|
87
|
+
def validate_params
|
88
|
+
option_params = argv.select { |arg| arg.include?("-") }
|
89
|
+
wrong_options = option_params - %w[--action --form --parent-controller --skip-form --skip-view]
|
90
|
+
show_error_message("Invalid optional arguments '#{wrong_options.join(", ")}'") if wrong_options.present?
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_action_option
|
94
|
+
action_options = argv.select { |arg| arg == "--action" }
|
95
|
+
show_error_message("Optional '--action' is duplicated") if action_options.size > 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_form_option
|
99
|
+
form_options = argv.select { |arg| arg == "--form" }
|
100
|
+
show_error_message("Optional '--form' is duplicated") if form_options.size > 1
|
101
|
+
end
|
102
|
+
|
103
|
+
def validate_parent_controller_option
|
104
|
+
parent_options = argv.select { |arg| arg == "--parent-controller" }
|
105
|
+
show_error_message("Optional '--parent-controller' is duplicated") if parent_options.size > 1
|
106
|
+
index = argv.index("--parent-controller")
|
107
|
+
return unless index
|
108
|
+
|
109
|
+
if argv[index + 1].blank? || argv[index + 1].start_with?("-") ||
|
110
|
+
(argv[index + 2] && !argv[index + 2].start_with?("-"))
|
111
|
+
show_error_message("Option '--parent-controller' is not valid")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def validate_skip_form_option
|
116
|
+
index = argv.index("--skip-form")
|
117
|
+
return if index.blank? || argv[index + 1].blank? || argv[index + 1].start_with?("-")
|
118
|
+
|
119
|
+
show_error_message("Option '--skip-form' is not valid")
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate_skip_view_option
|
123
|
+
index = argv.index("--skip-view")
|
124
|
+
return if index.blank? || argv[index + 1].blank? || argv[index + 1].start_with?("-")
|
125
|
+
|
126
|
+
show_error_message("Option '--skip-view' is not valid")
|
127
|
+
end
|
128
|
+
|
129
|
+
def show_error_message(message)
|
130
|
+
puts "Error:"
|
131
|
+
puts " #{message}"
|
132
|
+
puts "------"
|
133
|
+
puts `rails g hmvc_rails --help`
|
134
|
+
exit(1)
|
135
|
+
end
|
136
|
+
|
137
|
+
def path_notes(action)
|
138
|
+
case action
|
139
|
+
when "index" then "# [GET]..."
|
140
|
+
when "show" then "# [GET]..."
|
141
|
+
when "new" then "# [GET]..."
|
142
|
+
when "edit" then "# [GET]..."
|
143
|
+
when "create" then "# [POST]..."
|
144
|
+
when "update" then "# [PUT]..."
|
145
|
+
when "destroy" then "# [DELETE]..."
|
146
|
+
else "# [METHOD]..."
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_file_traces
|
151
|
+
return unless Hmvc::Rails.configuration.file_traces
|
152
|
+
|
153
|
+
"# Created at: #{Time.now.strftime("%Y-%m-%d %H:%M %z")}\n# Creator: #{`git config user.email`}"
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
require "rails/generators"
|
5
|
+
|
6
|
+
module HmvcRails
|
7
|
+
module Generators
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
9
|
+
desc "Generate base files of the HMVC structure"
|
10
|
+
|
11
|
+
class_option :api, type: :boolean, default: false
|
12
|
+
|
13
|
+
source_root File.expand_path("templates", __dir__)
|
14
|
+
|
15
|
+
def generate
|
16
|
+
copy_configuration
|
17
|
+
copy_application_operator
|
18
|
+
copy_application_form
|
19
|
+
copy_validator
|
20
|
+
copy_api_error_handler
|
21
|
+
add_config_api_error_response
|
22
|
+
add_api_error_response
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def copy_configuration
|
28
|
+
file_selected = options[:api] ? "configures/hmvc_rails_api.rb" : "configures/hmvc_rails.rb"
|
29
|
+
template file_selected, "config/initializers/hmvc_rails.rb"
|
30
|
+
end
|
31
|
+
|
32
|
+
def copy_application_operator
|
33
|
+
template "operations/application_operation.rb", "app/operations/application_operation.rb"
|
34
|
+
end
|
35
|
+
|
36
|
+
def copy_application_form
|
37
|
+
template "forms/application_form.rb", "app/forms/application_form.rb"
|
38
|
+
end
|
39
|
+
|
40
|
+
def copy_validator
|
41
|
+
template "validators/uniqueness_validator.rb", "app/validators/uniqueness_validator.rb"
|
42
|
+
template "validators/email_validator.rb", "app/validators/email_validator.rb"
|
43
|
+
end
|
44
|
+
|
45
|
+
def copy_api_error_handler
|
46
|
+
return unless options[:api]
|
47
|
+
|
48
|
+
template "extras/exception.rb", "lib/hmvc_rails/extras/exception.rb"
|
49
|
+
template "extras/error_resource.rb", "lib/hmvc_rails/extras/error_resource.rb"
|
50
|
+
template "extras/error_response.rb", "lib/hmvc_rails/extras/error_response.rb"
|
51
|
+
end
|
52
|
+
|
53
|
+
# rubocop:disable Layout/LineLength
|
54
|
+
def add_config_api_error_response
|
55
|
+
return if Rails.root.blank? || !options[:api] || behavior == :revoke
|
56
|
+
|
57
|
+
file_path = Rails.root.join("config", "application.rb")
|
58
|
+
if File.foreach(file_path).grep(/Application < Rails::Application/).any?
|
59
|
+
inject_into_file file_path, " # This setting to use the error handler of hmvc-rails\n config.eager_load_paths << Rails.root.join('lib', 'hmvc_rails')\n\n", after: "Application < Rails::Application\n"
|
60
|
+
else
|
61
|
+
puts "Warning: The hmvc_rails module could not be automatically loaded because the \"Application < Rails::Application\" flag was not found"
|
62
|
+
puts "Please manually add `config.eager_load_paths << Rails.root.join('lib', 'hmvc_rails')` to your `config/application.rb` to use hmvc-rails error response"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_api_error_response
|
67
|
+
return if Rails.root.blank? || !options[:api] || behavior == :revoke
|
68
|
+
|
69
|
+
file_path = Rails.root.join("app", "controllers", "application_controller.rb")
|
70
|
+
if File.foreach(file_path).grep(/ApplicationController < ActionController::API/).any?
|
71
|
+
inject_into_file file_path, " include Extras::ErrorResponse\n", after: "ApplicationController < ActionController::API\n"
|
72
|
+
else
|
73
|
+
puts "Warning: The error response module could not be automatically added because the \"ApplicationController < ActionController::API\" flag was not found"
|
74
|
+
puts "Please manually add `include Extras::ErrorResponse` to your application_controller.rb to use hmvc-rails error response"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# rubocop:enable Layout/LineLength
|
78
|
+
|
79
|
+
def add_file_traces
|
80
|
+
"# Created at: #{Time.now.strftime("%Y-%m-%d %H:%M %z")}\n# Creator: #{`git config user.email`}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
if Rails.env.development?
|
5
|
+
Hmvc::Rails.configure do |config|
|
6
|
+
# The controller files's parent class of controller. Default is ApplicationController
|
7
|
+
# config.parent_controller = "ApplicationController"
|
8
|
+
|
9
|
+
# Method when creating the controller files. Default is %w[index show new create edit update destroy]
|
10
|
+
# config.action = %w[index show new create edit update destroy]
|
11
|
+
|
12
|
+
# Method when creating the view files. Default is %w[index show new edit]
|
13
|
+
# config.view = %w[index show new edit]
|
14
|
+
|
15
|
+
# The form files's parent class. Default is ApplicationForm
|
16
|
+
# config.parent_form = "ApplicationForm"
|
17
|
+
|
18
|
+
# Method when creating the form files. Default is %w[new create edit update]
|
19
|
+
# config.form = %w[new create edit update]
|
20
|
+
|
21
|
+
# The operation files's parent class. Default is ApplicationOperation
|
22
|
+
# config.parent_operation = "ApplicationOperation"
|
23
|
+
|
24
|
+
# Save author name and timestamp to file. Default is true
|
25
|
+
# config.file_traces = true
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
if Rails.env.development?
|
5
|
+
Hmvc::Rails.configure do |config|
|
6
|
+
# The controller files's parent class of controller. Default is ApplicationController
|
7
|
+
# config.parent_controller = "ApplicationController"
|
8
|
+
|
9
|
+
# Method when creating the controller files. Default is %w[index show new create edit update destroy]
|
10
|
+
config.action = %w[index show create update destroy]
|
11
|
+
|
12
|
+
# Method when creating the view files. Default is %w[index show new edit]
|
13
|
+
config.view = %w[]
|
14
|
+
|
15
|
+
# The form files's parent class. Default is ApplicationForm
|
16
|
+
# config.parent_form = "ApplicationForm"
|
17
|
+
|
18
|
+
# Method when creating the form files. Default is %w[new create edit update]
|
19
|
+
config.form = %w[create update]
|
20
|
+
|
21
|
+
# The operation files's parent class. Default is ApplicationOperation
|
22
|
+
# config.parent_operation = "ApplicationOperation"
|
23
|
+
|
24
|
+
# Save author name and timestamp to file. Default is true
|
25
|
+
# config.file_traces = true
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
class <%= class_name %>Controller < <%= options[:parent_controller] %><% options[:action].each do |action| %>
|
5
|
+
<%= path_notes(action) %>
|
6
|
+
def <%= action %>
|
7
|
+
operator = <%= class_name %>::<%= action.humanize %>Operation.new(params)
|
8
|
+
operator.call
|
9
|
+
end
|
10
|
+
<% end %>end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
module Extras
|
5
|
+
class ErrorResource
|
6
|
+
include Exception
|
7
|
+
|
8
|
+
attr_reader :status, :code, :message
|
9
|
+
|
10
|
+
def initialize(exception)
|
11
|
+
hash = get_status_code(exception)
|
12
|
+
@code = hash[:code]
|
13
|
+
@status = hash[:status]
|
14
|
+
@message = exception.message
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_json
|
18
|
+
return { code: code, field_error: field_errors } if status == UNPROCESSABLE_ENTITY[:status]
|
19
|
+
|
20
|
+
{ code: code, message: message }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def field_errors
|
26
|
+
JSON.parse(message).map do |field, messages|
|
27
|
+
messages.map { |message_detail| { name: field, message: message_detail } }
|
28
|
+
end.flatten
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
module Extras
|
5
|
+
module ErrorResponse
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
rescue_from StandardError do |exception|
|
10
|
+
handle(exception)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def handle(exception)
|
16
|
+
error = ErrorResource.new(exception)
|
17
|
+
render json: error.as_json, status: error.status
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
module Extras
|
5
|
+
module Exception
|
6
|
+
BAD_REQUEST = { status: 400, code: :bad_request }.freeze
|
7
|
+
UNAUTHORIZED = { status: 401, code: :unauthorized }.freeze
|
8
|
+
FORBIDDEN = { status: 403, code: :forbidden }.freeze
|
9
|
+
NOT_FOUND = { status: 404, code: :not_found }.freeze
|
10
|
+
CONFLICT = { status: 409, code: :conflict }.freeze
|
11
|
+
UNPROCESSABLE_ENTITY = { status: 422, code: :unprocessable_entity }.freeze
|
12
|
+
INTERNAL_SERVER_ERROR = { status: 500, code: :internal_server_error }.freeze
|
13
|
+
NOT_IMPLEMENTED = { status: 501, code: :not_implemented }.freeze
|
14
|
+
SERVICE_UNAVAILABLE = { status: 503, code: :service_unavailable }.freeze
|
15
|
+
|
16
|
+
def get_status_code(exception)
|
17
|
+
case exception
|
18
|
+
when Exception::BadRequest, Exception::ResourceInvalid, ActionController::BadRequest
|
19
|
+
BAD_REQUEST
|
20
|
+
when Exception::SecurityError, Exception::Unauthorized
|
21
|
+
UNAUTHORIZED
|
22
|
+
when Exception::Forbidden, ActionController::InvalidAuthenticityToken
|
23
|
+
FORBIDDEN
|
24
|
+
when ActiveRecord::RecordNotFound
|
25
|
+
NOT_FOUND
|
26
|
+
when ActiveRecord::RecordNotUnique
|
27
|
+
CONFLICT
|
28
|
+
when Exception::UnprocessableEntity
|
29
|
+
UNPROCESSABLE_ENTITY
|
30
|
+
when Exception::NotImplemented
|
31
|
+
NOT_IMPLEMENTED
|
32
|
+
else
|
33
|
+
INTERNAL_SERVER_ERROR
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class BadRequest < StandardError; end
|
38
|
+
|
39
|
+
class ResourceInvalid < StandardError; end
|
40
|
+
|
41
|
+
class SecurityError < StandardError; end
|
42
|
+
|
43
|
+
class Unauthorized < StandardError; end
|
44
|
+
|
45
|
+
class Forbidden < StandardError; end
|
46
|
+
|
47
|
+
class NotFound < StandardError; end
|
48
|
+
|
49
|
+
class ResourceNotFound < StandardError; end
|
50
|
+
|
51
|
+
class Conflict < StandardError; end
|
52
|
+
|
53
|
+
class UnprocessableEntity < ActiveRecord::RecordInvalid; end
|
54
|
+
|
55
|
+
class InternalServerError < StandardError; end
|
56
|
+
|
57
|
+
class NotImplemented < StandardError; end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
class ApplicationForm
|
5
|
+
extend ActiveModel::Translation
|
6
|
+
|
7
|
+
include ActiveModel::Model
|
8
|
+
include ActiveModel::Attributes
|
9
|
+
include ActiveModel::Validations::Callbacks
|
10
|
+
|
11
|
+
def initialize(attributes = {})
|
12
|
+
self.class.attribute_names.each do |column|
|
13
|
+
self.class.attribute(column.to_sym)
|
14
|
+
end
|
15
|
+
|
16
|
+
super attributes
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid!
|
20
|
+
raise ExceptionError::UnprocessableEntity, error_messages.to_json unless valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def error_messages
|
26
|
+
errors.messages.map { |key, value| { key => value.first } }
|
27
|
+
end
|
28
|
+
|
29
|
+
def attribute_names
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
class EmailValidator < ActiveModel::EachValidator
|
5
|
+
def validate_each(record, attribute, value)
|
6
|
+
return if value.blank? || /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
|
7
|
+
|
8
|
+
record.errors.add(attribute, :invalid)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
<%= add_file_traces %>
|
4
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
5
|
+
def initialize(klass)
|
6
|
+
super
|
7
|
+
@klass = options[:model] if options[:model]
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_each(record, attribute)
|
11
|
+
record_org = record
|
12
|
+
attribute_org = attribute
|
13
|
+
attribute = options[:attribute].to_sym if options[:attribute]
|
14
|
+
base_attrs = {}
|
15
|
+
base_attrs[attribute] = record_org.send(attribute)
|
16
|
+
|
17
|
+
options[:scope]&.each do |scope_attribute|
|
18
|
+
base_attrs[scope_attribute] = record_org.send(scope_attribute)
|
19
|
+
end
|
20
|
+
|
21
|
+
record = if record_org.try(:record)
|
22
|
+
options[:model].where.not(id: record_org.send(:record).id).exists?(base_attrs)
|
23
|
+
else
|
24
|
+
options[:model].exists?(base_attrs)
|
25
|
+
end
|
26
|
+
|
27
|
+
record_org.errors.add(attribute_org, :taken) if record
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1><%= @_action.camelize %></h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
%h1= @_action.camelize
|
@@ -0,0 +1 @@
|
|
1
|
+
h1= @_action.camelize
|
data/lib/hmvc/rails.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "rails/version"
|
4
|
+
|
5
|
+
module Hmvc
|
6
|
+
module Rails
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_writer :configuration
|
11
|
+
|
12
|
+
def configuration
|
13
|
+
@configuration ||= Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure
|
17
|
+
yield(configuration)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Configuration
|
22
|
+
attr_accessor :parent_controller, :action, :view, :form, :parent_form, :parent_operation, :file_traces
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@parent_controller = "ApplicationController"
|
26
|
+
@action = %w[index show new create edit update destroy]
|
27
|
+
@view = %w[index show new edit]
|
28
|
+
@form = %w[new create edit update]
|
29
|
+
@parent_form = "ApplicationForm"
|
30
|
+
@parent_operation = "ApplicationOperation"
|
31
|
+
@file_traces = true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module HmvcRails
|
6
|
+
class FormalStyle < RuboCop::Cop::Base
|
7
|
+
def on_class(node)
|
8
|
+
class_name = node.children.first.children.last.to_s
|
9
|
+
return if class_name.end_with?("Form")
|
10
|
+
|
11
|
+
add_offense(node, message: "The form name does not match the desired format")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module HmvcRails
|
6
|
+
class OperatingStyle < RuboCop::Cop::Base
|
7
|
+
def on_class(node)
|
8
|
+
class_name = node.children.first.children.last.to_s
|
9
|
+
return if class_name.end_with?("Operation")
|
10
|
+
|
11
|
+
add_offense(node, message: "The operation name does not match the desired format")
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_def(node)
|
15
|
+
return unless node.children.first == :call
|
16
|
+
|
17
|
+
node.body.to_a.compact.each do |ast|
|
18
|
+
next if ast.is_a?(Symbol) && (ast.to_s.start_with?("step_") || ats.to_s == "super")
|
19
|
+
|
20
|
+
next if ast.is_a?(RuboCop::AST::SendNode) &&
|
21
|
+
(ast.children.last.to_s.start_with?("step_") || ast.children.last.to_s == "super")
|
22
|
+
|
23
|
+
add_offense(node, message: "Method works in \"call\" without prefix \"step_\"")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|