kriangle 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|