kriangle 0.1.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/.gitignore +9 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +216 -0
- data/LICENSE.txt +21 -0
- data/README.md +307 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/kriangle.gemspec +42 -0
- data/lib/generators/kriangle/generator_helpers.rb +95 -0
- data/lib/generators/kriangle/install_generator.rb +149 -0
- data/lib/generators/kriangle/module_generator.rb +273 -0
- data/lib/generators/kriangle/templates/active_serializer.rb +9 -0
- data/lib/generators/kriangle/templates/application_record.rb +9 -0
- data/lib/generators/kriangle/templates/auth.rb +138 -0
- data/lib/generators/kriangle/templates/authentication.rb +7 -0
- data/lib/generators/kriangle/templates/authenticator.rb +70 -0
- data/lib/generators/kriangle/templates/avatar.rb +5 -0
- data/lib/generators/kriangle/templates/avatar_uploader.rb +49 -0
- data/lib/generators/kriangle/templates/base.rb +6 -0
- data/lib/generators/kriangle/templates/controller.rb +241 -0
- data/lib/generators/kriangle/templates/controllers.rb +21 -0
- data/lib/generators/kriangle/templates/counter_cache_migration.rb +5 -0
- data/lib/generators/kriangle/templates/create_authentications.rb +10 -0
- data/lib/generators/kriangle/templates/create_avatars.rb +10 -0
- data/lib/generators/kriangle/templates/create_users.rb.erb +48 -0
- data/lib/generators/kriangle/templates/custom_description.rb +30 -0
- data/lib/generators/kriangle/templates/defaults.rb +29 -0
- data/lib/generators/kriangle/templates/kriangle.rb +5 -0
- data/lib/generators/kriangle/templates/model.rb +33 -0
- data/lib/generators/kriangle/templates/module_migration.rb +33 -0
- data/lib/generators/kriangle/templates/responder.rb +170 -0
- data/lib/generators/kriangle/templates/serializer.rb +35 -0
- data/lib/generators/kriangle/templates/swagger.rb +8 -0
- data/lib/generators/kriangle/templates/user.rb +35 -0
- data/lib/kriangle.rb +36 -0
- data/lib/kriangle/version.rb +5 -0
- metadata +355 -0
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'kriangle'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/kriangle.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'kriangle/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'kriangle'
|
9
|
+
spec.version = Kriangle::VERSION
|
10
|
+
spec.authors = ['Lalit Kumar Maurya']
|
11
|
+
spec.email = ['lalit.logical@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'Scaffold module (including REST API with documentation) with help of Grape and Swagger.'
|
14
|
+
spec.description = 'Scaffold module (including REST API with documentation) with help of Grape and Swagger.'
|
15
|
+
spec.homepage = 'https://github.com/lalitlogical/kriangle'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.bindir = 'exe'
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
26
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
27
|
+
|
28
|
+
spec.add_dependency('sqlite3', '~> 1.4', '>= 1.4.2')
|
29
|
+
spec.add_dependency('bcrypt', '~> 3.1.7')
|
30
|
+
spec.add_dependency('devise', '~> 4.4', '>= 4.4.3')
|
31
|
+
spec.add_dependency('dotenv-rails', '~> 2.7', '>= 2.7.6')
|
32
|
+
spec.add_dependency('grape', '~> 1.2', '>= 1.2.4')
|
33
|
+
spec.add_dependency('grape-active_model_serializers', '~> 1.5', '>= 1.5.2')
|
34
|
+
spec.add_dependency('grape-rails-cache', '~> 0.1.2')
|
35
|
+
spec.add_dependency('grape-swagger', '~> 1.4')
|
36
|
+
spec.add_dependency('grape-swagger-rails', '~> 0.3.1')
|
37
|
+
spec.add_dependency('api-pagination', '~> 4.7')
|
38
|
+
spec.add_dependency('kaminari', '~> 1.0', '>= 1.0.1')
|
39
|
+
spec.add_dependency('rack-cors', '~> 1.1', '>= 1.1.1')
|
40
|
+
spec.add_dependency('ransack', '~> 2.3')
|
41
|
+
spec.add_dependency('carrierwave', '~> 2.0', '>= 2.0.2')
|
42
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kriangle
|
4
|
+
module Generators
|
5
|
+
# Some helpers for generating scaffolding
|
6
|
+
module GeneratorHelpers
|
7
|
+
attr_accessor :options, :attributes
|
8
|
+
|
9
|
+
Attribute = Struct.new(:name, :type, :validate_presence, :search_by, :default)
|
10
|
+
Association = Struct.new(:association_type, :association_name, :dependent_type, :validate_presence, :counter_cache, :touch_record, :accepts_nested_attributes, :foreign_key, :class_name, :reference) do
|
11
|
+
def association_type_with_name
|
12
|
+
"#{association_type} :#{association_name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def association
|
16
|
+
txt = "#{association_type} :#{association_name}"
|
17
|
+
txt += ', counter_cache: true' if counter_cache == 'true'
|
18
|
+
txt += ', optional: true' if association_type == 'belongs_to' && validate_presence == 'false'
|
19
|
+
txt += ', touch: true' if touch_record == 'true'
|
20
|
+
txt += ", foreign_key: '#{foreign_key}'" if foreign_key.present?
|
21
|
+
txt += ", class_name: '#{class_name}'" if class_name.present?
|
22
|
+
txt += ", dependent: :#{dependent_type}" if association_type.match('has_') && dependent_type.present?
|
23
|
+
txt += "\n\t#{accepts_nested_attributes_text}" if association_type != 'belongs_to' && accepts_nested_attributes == 'true'
|
24
|
+
txt
|
25
|
+
end
|
26
|
+
|
27
|
+
def accepts_nested_attributes_text
|
28
|
+
"accepts_nested_attributes_for :#{association_name}, allow_destroy: true"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
@@column_types = {
|
33
|
+
'references': 'Integer',
|
34
|
+
'text': 'String',
|
35
|
+
'datetime': 'DateTime',
|
36
|
+
'attachment': 'File',
|
37
|
+
'jsonb': 'JSON',
|
38
|
+
'json': 'JSON'
|
39
|
+
}
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def model_columns_for_attributes
|
44
|
+
class_name.constantize.columns.reject do |column|
|
45
|
+
column.name.to_s =~ /^(id|user_id|created_at|updated_at)$/
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def editable_attributes
|
50
|
+
attributes ||= model_columns_for_attributes.map do |column|
|
51
|
+
Rails::Generators::GeneratedAttribute.new(column.name.to_s, column.type.to_s)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_template(template_fname, fname, **options)
|
56
|
+
@options = options
|
57
|
+
if @options[:skip_if_exist] && File.exist?(File.join(destination_root, fname))
|
58
|
+
say_status 'skipped', fname
|
59
|
+
else
|
60
|
+
template template_fname, fname
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_migration_file(migration_fname, fname, **options)
|
65
|
+
@options = options
|
66
|
+
if @options[:skip_if_exist] && self.class.migration_exists?('db/migrate', fname.split('/').last.gsub('.rb', ''))
|
67
|
+
say_status('skipped', "Migration '#{fname}' already exists")
|
68
|
+
else
|
69
|
+
migration_template migration_fname, fname, options
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_record_not_found_exception
|
74
|
+
custom_orm == 'Mongoid' ? 'Mongoid::Errors::DocumentNotFound' : 'ActiveRecord::RecordNotFound'
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_record_invalid_exception
|
78
|
+
custom_orm == 'Mongoid' ? 'Mongoid::Errors::InvalidFind' : 'ActiveRecord::RecordInvalid'
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_attribute_name(name, attribute_type)
|
82
|
+
attribute_type == 'references' ? "#{name}_id" : name
|
83
|
+
end
|
84
|
+
|
85
|
+
def require_or_optional(attribute)
|
86
|
+
attribute.validate_presence == 'true' ? 'requires' : 'optional'
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_attribute_type(attribute_type)
|
90
|
+
column_type = @@column_types[attribute_type.to_sym]
|
91
|
+
column_type.present? ? column_type : attribute_type.to_s.camelcase
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/migration'
|
5
|
+
require 'rails/generators/active_record'
|
6
|
+
require 'generators/kriangle/generator_helpers'
|
7
|
+
|
8
|
+
module Kriangle
|
9
|
+
module Generators
|
10
|
+
# Custom scaffolding generator
|
11
|
+
class InstallGenerator < Rails::Generators::Base
|
12
|
+
include Rails::Generators::Migration
|
13
|
+
include Kriangle::Generators::GeneratorHelpers
|
14
|
+
|
15
|
+
no_tasks do
|
16
|
+
attr_accessor :underscored_user_class,
|
17
|
+
:column_types,
|
18
|
+
:model_attributes,
|
19
|
+
:model_associations,
|
20
|
+
:controller_actions,
|
21
|
+
:wrapper,
|
22
|
+
:controller_path,
|
23
|
+
:custom_orm,
|
24
|
+
:self_reference,
|
25
|
+
:skip_tips,
|
26
|
+
:skip_swagger,
|
27
|
+
:skip_avatar,
|
28
|
+
:skip_migration,
|
29
|
+
:skip_authentication,
|
30
|
+
:database
|
31
|
+
end
|
32
|
+
|
33
|
+
# arguments
|
34
|
+
argument :user_class, type: :string, default: 'User'
|
35
|
+
# argument :mount_path, type: :string, default: 'User'
|
36
|
+
argument :args_for_c_m, type: :array, default: [], banner: 'model:attributes'
|
37
|
+
|
38
|
+
class_option :database, type: :string, default: 'sqlite3', desc: "database i.e. postgresql, mysql, sqlite3"
|
39
|
+
|
40
|
+
class_option :wrapper, type: :string, default: 'V1', desc: 'Skip "Swagger UI"'
|
41
|
+
class_option :controller_path, type: :string, desc: "controller's path"
|
42
|
+
class_option :skip_tips, type: :boolean, default: false, desc: 'Skip "Tips from different files i.e. model, serializer, etc."'
|
43
|
+
class_option :skip_swagger, type: :boolean, default: false, desc: 'Skip "Swagger UI"'
|
44
|
+
class_option :skip_avatar, type: :boolean, default: true, desc: 'Skip "Avatar Feature"'
|
45
|
+
class_option :skip_migration, desc: 'Don\'t generate migration file for model.', type: :boolean, default: false
|
46
|
+
class_option :custom_orm, type: :string, default: 'ActiveRecord', desc: 'ORM i.e. ActiveRecord, Mongoid'
|
47
|
+
|
48
|
+
source_root File.expand_path('templates', __dir__)
|
49
|
+
|
50
|
+
def initialize(*args, &block)
|
51
|
+
super
|
52
|
+
@model_attributes = []
|
53
|
+
@model_associations = []
|
54
|
+
@underscored_user_class = user_class.underscore
|
55
|
+
@wrapper = options.wrapper
|
56
|
+
@database = options.database
|
57
|
+
@custom_orm = 'ActiveRecord' # Kriangle.custom_orm
|
58
|
+
@skip_tips = options.skip_tips?
|
59
|
+
@skip_swagger = options.skip_swagger?
|
60
|
+
@skip_avatar = options.skip_avatar?
|
61
|
+
@skip_migration = options.skip_migration?
|
62
|
+
@skip_authentication = false
|
63
|
+
@controller_path = options.controller_path&.classify&.pluralize || user_class.classify&.pluralize
|
64
|
+
|
65
|
+
args_for_c_m.each do |arg|
|
66
|
+
next unless arg.include?(':')
|
67
|
+
|
68
|
+
options = arg.split(':')
|
69
|
+
if arg.match(/^ma:/).present?
|
70
|
+
options.shift
|
71
|
+
@model_associations << Association.new(*options)
|
72
|
+
else
|
73
|
+
@model_attributes << Attribute.new(*options)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
if @model_attributes.blank?
|
78
|
+
default_attributes = ['first_name:string', 'last_name:string', 'about:text', 'age:integer', 'dob:datetime', 'gender:string']
|
79
|
+
@model_attributes = default_attributes.map { |arg| Attribute.new(*arg.split(':')) }
|
80
|
+
end
|
81
|
+
@model_attributes.uniq!(&:name)
|
82
|
+
|
83
|
+
@attributes = %i[id email]
|
84
|
+
@attributes += @model_attributes.map { |a| a.name.to_sym }
|
85
|
+
@attributes.uniq!
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.next_migration_number(_path)
|
89
|
+
if @prev_migration_nr
|
90
|
+
@prev_migration_nr += 1
|
91
|
+
else
|
92
|
+
@prev_migration_nr = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i
|
93
|
+
end
|
94
|
+
@prev_migration_nr.to_s
|
95
|
+
end
|
96
|
+
|
97
|
+
def copy_initializer
|
98
|
+
create_template 'kriangle.rb', 'config/initializers/kriangle.rb', skip_if_exist: true
|
99
|
+
create_template 'application_record.rb', 'app/models/application_record.rb', skip_if_exist: true
|
100
|
+
create_template 'swagger.rb', 'config/initializers/swagger.rb', skip_if_exist: true unless skip_swagger
|
101
|
+
end
|
102
|
+
|
103
|
+
def copy_migrations
|
104
|
+
if custom_orm == 'ActiveRecord' && !skip_migration
|
105
|
+
create_migration_file 'create_users.rb.erb', "db/migrate/create_#{user_class.pluralize.underscore}.rb"
|
106
|
+
create_migration_file 'create_authentications.rb', 'db/migrate/create_authentications.rb'
|
107
|
+
create_migration_file 'create_avatars.rb', 'db/migrate/create_avatars.rb' unless skip_avatar
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_model_file
|
112
|
+
create_template 'user.rb', "app/models/#{user_class.underscore}.rb"
|
113
|
+
create_template 'authentication.rb', 'app/models/authentication.rb'
|
114
|
+
create_template 'avatar.rb', 'app/models/avatar.rb' unless skip_avatar
|
115
|
+
|
116
|
+
create_template 'active_serializer.rb', 'app/serializers/active_serializer.rb', skip_if_exist: true
|
117
|
+
create_template 'serializer.rb', "app/serializers/#{underscored_user_class}_serializer.rb", class_name: user_class, attributes: @attributes
|
118
|
+
create_template 'serializer.rb', 'app/serializers/avatar_serializer.rb', class_name: 'Avatar', attributes: %i[id image_url] unless skip_avatar
|
119
|
+
|
120
|
+
# Uploader File
|
121
|
+
create_template 'avatar_uploader.rb', 'app/uploaders/avatar_uploader.rb' unless skip_avatar
|
122
|
+
end
|
123
|
+
|
124
|
+
desc 'Generates required files.'
|
125
|
+
def copy_controller_and_spec_files
|
126
|
+
# Main base files
|
127
|
+
create_template 'base.rb', 'app/controllers/api/base.rb', skip_if_exist: true
|
128
|
+
inject_into_file 'app/controllers/api/base.rb', "\n\t\t\tmount Api::#{wrapper.capitalize}::Controllers", after: /Grape::API.*/
|
129
|
+
|
130
|
+
# All new controllers will go here
|
131
|
+
create_template 'controllers.rb', "app/controllers/api/#{@wrapper.underscore}/controllers.rb", skip_if_exist: true
|
132
|
+
inject_into_file "app/controllers/api/#{@wrapper.underscore}/controllers.rb", "\n\t\t\tmount Api::#{@wrapper.capitalize}::#{controller_path}", after: /Grape::API.*/
|
133
|
+
|
134
|
+
# Authentications related things will go there
|
135
|
+
create_template 'defaults.rb', "app/controllers/api/#{@wrapper.underscore}/defaults.rb", skip_if_exist: true
|
136
|
+
create_template 'custom_description.rb', 'app/controllers/api/custom_description.rb'
|
137
|
+
create_template 'authenticator.rb', 'app/controllers/api/authenticator.rb'
|
138
|
+
create_template 'responder.rb', 'app/controllers/api/responder.rb'
|
139
|
+
|
140
|
+
# Authentication i.e. login, register, logout
|
141
|
+
template 'auth.rb', "app/controllers/api/#{@wrapper.underscore}/#{controller_path.underscore}.rb"
|
142
|
+
|
143
|
+
# setup routes
|
144
|
+
inject_into_file 'config/routes.rb', "\n\tmount GrapeSwaggerRails::Engine => '/swagger'", after: /routes.draw.*/ unless skip_swagger
|
145
|
+
inject_into_file 'config/routes.rb', "\n\tmount Api::Base, at: '/'", after: /routes.draw.*/
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'rails/generators/migration'
|
5
|
+
require 'rails/generators/active_record'
|
6
|
+
require 'generators/kriangle/generator_helpers'
|
7
|
+
|
8
|
+
module Kriangle
|
9
|
+
module Generators
|
10
|
+
# Custom scaffolding generator
|
11
|
+
class ModuleGenerator < Rails::Generators::NamedBase
|
12
|
+
include Rails::Generators::ResourceHelpers
|
13
|
+
include Rails::Generators::Migration
|
14
|
+
include Kriangle::Generators::GeneratorHelpers
|
15
|
+
|
16
|
+
CONTROLLER_ACTIONS = %w[index show new create edit update destroy create_or_destroy].freeze
|
17
|
+
|
18
|
+
no_tasks do
|
19
|
+
attr_accessor :user_class,
|
20
|
+
:wrapper,
|
21
|
+
:controller_path,
|
22
|
+
:column_types,
|
23
|
+
:attributes,
|
24
|
+
:model_attributes,
|
25
|
+
:model_associations,
|
26
|
+
:controller_actions,
|
27
|
+
:custom_orm,
|
28
|
+
:initial_setup,
|
29
|
+
:skip_tips,
|
30
|
+
:skip_authentication,
|
31
|
+
:skip_model,
|
32
|
+
:skip_migration,
|
33
|
+
:skip_serializer,
|
34
|
+
:skip_timestamps,
|
35
|
+
:skip_controller,
|
36
|
+
:skip_pagination,
|
37
|
+
:skip_swagger,
|
38
|
+
:reference,
|
39
|
+
:reference_name,
|
40
|
+
:reference_name_create_update,
|
41
|
+
:association_type,
|
42
|
+
:touch_record,
|
43
|
+
:accepts_nested_attributes,
|
44
|
+
:counter_cache,
|
45
|
+
:self_reference,
|
46
|
+
:parent_association_name,
|
47
|
+
:child_association_name,
|
48
|
+
:additional_where_clause,
|
49
|
+
:reference_id_param,
|
50
|
+
:creation_method,
|
51
|
+
:like_dislike,
|
52
|
+
:resources,
|
53
|
+
:description_method_name,
|
54
|
+
:search_by,
|
55
|
+
:database,
|
56
|
+
:force
|
57
|
+
end
|
58
|
+
|
59
|
+
argument :args_for_c_m, type: :array, default: [], banner: 'model:attributes'
|
60
|
+
|
61
|
+
class_option :user_class, type: :string, desc: "User's model name"
|
62
|
+
class_option :wrapper, type: :string, default: 'V1', desc: 'Skip "Swagger UI"'
|
63
|
+
class_option :controller_path, type: :string, desc: "controller's path"
|
64
|
+
|
65
|
+
class_option :reference, desc: 'Reference to user', type: :boolean, default: false
|
66
|
+
class_option :reference_name, type: :string, default: 'current_user', desc: 'Reference Name'
|
67
|
+
class_option :association_type, desc: 'Association with any model', type: :string
|
68
|
+
class_option :touch_record, desc: 'Touch the updated_at column', type: :boolean, default: false
|
69
|
+
class_option :accepts_nested_attributes, desc: 'accepts nested attributes', type: :boolean, default: false
|
70
|
+
class_option :counter_cache, desc: 'Counter cache support', type: :boolean, default: false
|
71
|
+
|
72
|
+
class_option :self_reference, desc: 'Counter cache support', type: :boolean, default: false
|
73
|
+
class_option :parent_association_name, type: :string, default: 'parent', desc: 'Parent Association Name'
|
74
|
+
class_option :child_association_name, type: :string, default: 'children', desc: 'Child Association Name'
|
75
|
+
|
76
|
+
class_option :creation_method, type: :string, default: 'new', desc: 'Creation Method'
|
77
|
+
class_option :like_dislike, desc: 'Like Dislike', type: :boolean, default: false
|
78
|
+
|
79
|
+
class_option :resources, desc: 'Resources routes', type: :boolean, default: true
|
80
|
+
class_option :initial_setup, type: :boolean, default: false, desc: 'Skip "Initial Setup i.e. Routes, Base models, etc."'
|
81
|
+
|
82
|
+
class_option :skip_swagger, type: :boolean, default: false, desc: 'Skip "Swagger UI"'
|
83
|
+
class_option :skip_tips, type: :boolean, default: false, desc: 'Skip "Tips from different files i.e. model, serializer, etc."'
|
84
|
+
class_option :skip_model, desc: 'Don\'t generate a model or migration file.', type: :boolean, default: false
|
85
|
+
class_option :skip_controller, desc: 'Don\'t generate a controller.', type: :boolean, default: false
|
86
|
+
class_option :skip_migration, desc: 'Don\'t generate migration file for model.', type: :boolean, default: false
|
87
|
+
class_option :skip_serializer, desc: 'Don\'t generate serializer file for model.', type: :boolean, default: false
|
88
|
+
class_option :skip_timestamps, desc: 'Don\'t add timestamps to migration file.', type: :boolean, default: false
|
89
|
+
class_option :skip_pagination, desc: 'Don\'t add pagination to index method.', type: :boolean, default: false
|
90
|
+
class_option :skip_authentication, desc: 'Don\'t require authentication for this controller.', type: :boolean, default: false
|
91
|
+
class_option :description_method_name, type: :string, default: 'desc', desc: 'desc or description'
|
92
|
+
class_option :force, desc: 'Force', type: :boolean, default: false
|
93
|
+
|
94
|
+
source_root File.expand_path('templates', __dir__)
|
95
|
+
|
96
|
+
def initialize(*args, &block)
|
97
|
+
super
|
98
|
+
@controller_actions = []
|
99
|
+
@model_attributes = []
|
100
|
+
@model_associations = []
|
101
|
+
@attributes = []
|
102
|
+
@references = []
|
103
|
+
@polymorphics = []
|
104
|
+
|
105
|
+
@user_class = options.user_class&.underscore
|
106
|
+
@wrapper = options.wrapper
|
107
|
+
@database = Kriangle.database
|
108
|
+
@controller_path = options.controller_path&.classify&.pluralize || controller_class_name
|
109
|
+
@force = options.force
|
110
|
+
@resources = options.resources?
|
111
|
+
|
112
|
+
@reference = options.reference?
|
113
|
+
if @reference
|
114
|
+
@association_type = options.association_type
|
115
|
+
@touch_record = options.touch_record?
|
116
|
+
@accepts_nested_attributes = options.accepts_nested_attributes?
|
117
|
+
@counter_cache = options.counter_cache?
|
118
|
+
|
119
|
+
@reference_name = options.reference_name
|
120
|
+
if @reference_name.match(/current_/)
|
121
|
+
@reference_name_create_update = @reference_name
|
122
|
+
@user_class ||= @reference_name.gsub(/current_/, '').underscore
|
123
|
+
else
|
124
|
+
@user_class ||= @reference_name.underscore
|
125
|
+
@reference_id_param = get_attribute_name(@reference_name.underscore, 'references')
|
126
|
+
@reference_name_create_update = "#{@reference_name}.find(params[:#{reference_id_param}])"
|
127
|
+
@reference_name = "#{@reference_name}.find(params[:#{reference_id_param}])"
|
128
|
+
end
|
129
|
+
@model_associations << Association.new('belongs_to', user_class, nil, 'true', counter_cache.to_s, touch_record.to_s, accepts_nested_attributes.to_s, '', '', true)
|
130
|
+
end
|
131
|
+
|
132
|
+
@self_reference = options.self_reference?
|
133
|
+
if @self_reference
|
134
|
+
@parent_association_name = options.parent_association_name
|
135
|
+
@child_association_name = options.child_association_name
|
136
|
+
@additional_where_clause = @self_reference ? '.only_parent' : ''
|
137
|
+
end
|
138
|
+
@creation_method = options.creation_method
|
139
|
+
@like_dislike = options.like_dislike
|
140
|
+
|
141
|
+
@custom_orm = 'ActiveRecord' # Kriangle.custom_orm
|
142
|
+
@initial_setup = options.initial_setup?
|
143
|
+
@skip_tips = options.skip_tips?
|
144
|
+
@skip_swagger = options.skip_swagger?
|
145
|
+
@skip_model = options.skip_model?
|
146
|
+
@skip_controller = options.skip_controller?
|
147
|
+
@skip_migration = options.skip_migration?
|
148
|
+
@skip_serializer = options.skip_serializer?
|
149
|
+
@skip_timestamps = options.skip_timestamps?
|
150
|
+
@skip_pagination = options.skip_pagination?
|
151
|
+
|
152
|
+
# skip authentication if authenticator not found
|
153
|
+
@skip_authentication = options.skip_authentication?
|
154
|
+
@skip_authentication = true unless File.exist?(File.join(destination_root, 'app/controllers/api/authenticator.rb'))
|
155
|
+
@description_method_name = @skip_authentication ? 'desc' : 'description'
|
156
|
+
|
157
|
+
args_for_c_m.each do |arg|
|
158
|
+
if arg.include?(':') || !CONTROLLER_ACTIONS.include?(arg)
|
159
|
+
options = arg.split(':')
|
160
|
+
if arg.match(/^ma:/).present?
|
161
|
+
options.shift
|
162
|
+
@model_associations << Association.new(*options)
|
163
|
+
else
|
164
|
+
@model_attributes << Attribute.new(*options)
|
165
|
+
end
|
166
|
+
else
|
167
|
+
@controller_actions << arg
|
168
|
+
@controller_actions << 'create' if arg == 'new'
|
169
|
+
@controller_actions << 'update' if arg == 'edit'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Default controller actions
|
174
|
+
if @controller_actions.blank?
|
175
|
+
@controller_actions = %w[show create update destroy]
|
176
|
+
@controller_actions << 'index' if @resources
|
177
|
+
end
|
178
|
+
|
179
|
+
# Get attribute's name
|
180
|
+
@search_by = model_attributes.any? { |ma| ma.search_by.present? }
|
181
|
+
|
182
|
+
# get different types of attributes
|
183
|
+
@model_attributes.uniq!(&:name)
|
184
|
+
@model_attributes.each do |attribute|
|
185
|
+
if attribute.type.match('polymorphic').present?
|
186
|
+
@polymorphics << attribute
|
187
|
+
elsif attribute.type.match('references').present?
|
188
|
+
@references << attribute
|
189
|
+
else
|
190
|
+
@attributes << attribute
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.next_migration_number(_path)
|
196
|
+
if @prev_migration_nr
|
197
|
+
@prev_migration_nr += 1
|
198
|
+
else
|
199
|
+
@prev_migration_nr = Time.now.utc.strftime('%Y%m%d%H%M%S').to_i
|
200
|
+
end
|
201
|
+
@prev_migration_nr.to_s
|
202
|
+
end
|
203
|
+
|
204
|
+
def copy_initializer
|
205
|
+
create_template 'application_record.rb', 'app/models/application_record.rb', skip_if_exist: true
|
206
|
+
create_template 'swagger.rb', 'config/initializers/swagger.rb', skip_if_exist: true unless skip_swagger
|
207
|
+
|
208
|
+
create_template 'base.rb', 'app/controllers/api/base.rb', skip_if_exist: true
|
209
|
+
create_template 'custom_description.rb', 'app/controllers/api/custom_description.rb', skip_if_exist: true
|
210
|
+
create_template 'responder.rb', 'app/controllers/api/responder.rb'
|
211
|
+
|
212
|
+
create_template 'controllers.rb', "app/controllers/api/#{@wrapper.underscore}/controllers.rb", skip_if_exist: true unless skip_controller
|
213
|
+
create_template 'defaults.rb', "app/controllers/api/#{@wrapper.underscore}/defaults.rb", skip_if_exist: true
|
214
|
+
|
215
|
+
inject_into_file 'app/controllers/api/base.rb', "\n\t\t\tmount Api::#{wrapper.capitalize}::Controllers", after: /Grape::API.*/
|
216
|
+
|
217
|
+
if initial_setup
|
218
|
+
inject_into_file 'config/routes.rb', "\n\tmount GrapeSwaggerRails::Engine => '/swagger'", after: /routes.draw.*/ unless skip_swagger
|
219
|
+
inject_into_file 'config/routes.rb', "\n\tmount Api::Base, at: '/'", after: /routes.draw.*/
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
desc 'Generates model with the given NAME.'
|
224
|
+
def create_model_file
|
225
|
+
# default options
|
226
|
+
options = { references: @references.map(&:name), polymorphics: @polymorphics.map(&:name) }
|
227
|
+
|
228
|
+
# create module model & migration
|
229
|
+
unless skip_model
|
230
|
+
options[:attributes] = @attributes.select { |a| a.validate_presence == 'true' }.map(&:name)
|
231
|
+
create_template 'model.rb', "app/models/#{singular_name}.rb", options
|
232
|
+
end
|
233
|
+
|
234
|
+
unless skip_model
|
235
|
+
model_associations.select { |ma| ma.association_type == 'belongs_to' }.each do |ma|
|
236
|
+
regex = "has_many :#{plural_name}"
|
237
|
+
file_path = ma.class_name.present? ? "app/models/#{ma.class_name.underscore}.rb" : "app/models/#{ma.association_name}.rb"
|
238
|
+
contents = File.foreach(file_path).grep /#{regex}/
|
239
|
+
next if contents.count != 0
|
240
|
+
|
241
|
+
association = "\n\thas_many :#{plural_name}, dependent: :destroy"
|
242
|
+
association += "\n\taccepts_nested_attributes_for :#{plural_name}, allow_destroy: true" if ma.accepts_nested_attributes == 'true'
|
243
|
+
belongs_to = ma.class_name.present? ? ma.class_name : ma.association_name.classify
|
244
|
+
inject_into_file file_path, association, after: /class #{belongs_to} < ApplicationRecord.*/
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
create_migration_file 'module_migration.rb', "db/migrate/create_#{plural_name}.rb", force: force if !skip_migration && custom_orm == 'ActiveRecord'
|
249
|
+
if custom_orm == 'ActiveRecord'
|
250
|
+
model_associations.select { |ma| ma.association_type == 'belongs_to' && ma.counter_cache == 'true' }.uniq { |ma| ma.association_name.classify && ma.class_name }.each do |ma|
|
251
|
+
belongs_to = ma.class_name.present? ? ma.class_name.underscore : ma.association_name
|
252
|
+
create_migration_file 'counter_cache_migration.rb', "db/migrate/add_#{class_name.pluralize.underscore}_count_to_#{belongs_to.pluralize}.rb", force: force, belongs_to: belongs_to
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# create active serializer & module serializer
|
257
|
+
unless skip_serializer
|
258
|
+
create_template 'active_serializer.rb', 'app/serializers/active_serializer.rb', skip_if_exist: true
|
259
|
+
options[:attributes] = [:id] + @attributes.map(&:name)
|
260
|
+
create_template 'serializer.rb', "app/serializers/#{singular_name}_serializer.rb", options
|
261
|
+
inject_into_file "app/serializers/#{user_class}_serializer.rb", "\n\tattributes :#{class_name.pluralize.underscore}_count", after: /class #{user_class.classify}Serializer < ActiveSerializer*/ if counter_cache && custom_orm == 'ActiveRecord'
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
desc 'Generates controller with the given NAME.'
|
266
|
+
def copy_controller_and_spec_files
|
267
|
+
template 'controller.rb', "app/controllers/api/#{@wrapper.underscore}/#{controller_path.underscore}.rb" unless skip_controller
|
268
|
+
|
269
|
+
inject_into_file "app/controllers/api/#{@wrapper.underscore}/controllers.rb", "\n\t\t\tmount Api::#{@wrapper.capitalize}::#{controller_path}", after: /Grape::API.*/ unless skip_controller
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|