gris 0.0.2
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 +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +67 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +203 -0
- data/Guardfile +82 -0
- data/MIT-LICENSE +20 -0
- data/README.md +7 -0
- data/Rakefile +11 -0
- data/bin/gris +5 -0
- data/gris.gemspec +40 -0
- data/lib/gris.rb +37 -0
- data/lib/gris/cli.rb +71 -0
- data/lib/gris/deprecations.rb +9 -0
- data/lib/gris/deprecations/gris_setup.rb +14 -0
- data/lib/gris/generators.rb +3 -0
- data/lib/gris/generators/api_generator.rb +31 -0
- data/lib/gris/generators/migration_generator.rb +228 -0
- data/lib/gris/generators/scaffold_generator.rb +21 -0
- data/lib/gris/generators/templates/api/app/apis/%name_tableize%_endpoint.rb.tt +65 -0
- data/lib/gris/generators/templates/api/app/models/%name_underscore%.rb.tt +2 -0
- data/lib/gris/generators/templates/api/app/presenters/%name_tableize%_presenter.rb.tt +5 -0
- data/lib/gris/generators/templates/api/app/presenters/%name_underscore%_presenter.rb.tt +10 -0
- data/lib/gris/generators/templates/api/spec/apis/%name_tableize%_endpoint_spec.rb.tt +70 -0
- data/lib/gris/generators/templates/api/spec/fabricators/%name_tableize%_fabricator.rb.tt +2 -0
- data/lib/gris/generators/templates/api/spec/models/%name_underscore%_spec.rb.tt +7 -0
- data/lib/gris/generators/templates/create_table_migration/%migration_filename%.rb.tt +19 -0
- data/lib/gris/generators/templates/migration/%migration_filename%.rb.tt +39 -0
- data/lib/gris/generators/templates/scaffold/.Procfile.tt +1 -0
- data/lib/gris/generators/templates/scaffold/.env.test.tt +11 -0
- data/lib/gris/generators/templates/scaffold/.env.tt +10 -0
- data/lib/gris/generators/templates/scaffold/.gitignore.tt +11 -0
- data/lib/gris/generators/templates/scaffold/.rspec.tt +3 -0
- data/lib/gris/generators/templates/scaffold/.rubocop.yml +18 -0
- data/lib/gris/generators/templates/scaffold/.ruby-gemset.tt +1 -0
- data/lib/gris/generators/templates/scaffold/.ruby-version.tt +1 -0
- data/lib/gris/generators/templates/scaffold/Gemfile.tt +33 -0
- data/lib/gris/generators/templates/scaffold/README.md.tt +3 -0
- data/lib/gris/generators/templates/scaffold/Rakefile +9 -0
- data/lib/gris/generators/templates/scaffold/app.rb +57 -0
- data/lib/gris/generators/templates/scaffold/app/apis/application_endpoint.rb +9 -0
- data/lib/gris/generators/templates/scaffold/app/presenters/root_presenter.rb +20 -0
- data/lib/gris/generators/templates/scaffold/config.ru.tt +6 -0
- data/lib/gris/generators/templates/scaffold/config/database.yml.tt +19 -0
- data/lib/gris/generators/templates/scaffold/config/initializers/active_record.rb +4 -0
- data/lib/gris/generators/templates/scaffold/db/schema.rb +11 -0
- data/lib/gris/generators/templates/scaffold/public/errors/404.html +11 -0
- data/lib/gris/generators/templates/scaffold/public/errors/500.html +11 -0
- data/lib/gris/generators/templates/scaffold/spec/apis/cors_spec.rb +31 -0
- data/lib/gris/generators/templates/scaffold/spec/spec_helper.rb +26 -0
- data/lib/gris/generators/templates/scaffold/spec/support/app_helper.rb +3 -0
- data/lib/gris/grape_extensions/crud_helpers.rb +26 -0
- data/lib/gris/identity.rb +50 -0
- data/lib/gris/middleware/app_monitor.rb +17 -0
- data/lib/gris/output_formatters/paginated_presenter.rb +41 -0
- data/lib/gris/output_formatters/presenter.rb +15 -0
- data/lib/gris/rspec_extensions/response_helpers.rb +57 -0
- data/lib/gris/setup.rb +17 -0
- data/lib/gris/version.rb +38 -0
- data/lib/tasks/db.rake +81 -0
- data/lib/tasks/routes.rake +11 -0
- data/spec/generators/api_generator_spec.rb +76 -0
- data/spec/generators/migration_generator_spec.rb +96 -0
- data/spec/generators/scaffold_generator_spec.rb +119 -0
- data/spec/grape_extensions/crud_helpers_spec.rb +5 -0
- data/spec/identity_spec.rb +86 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/spec_generators_helper.rb +11 -0
- data/spec/version_spec.rb +40 -0
- metadata +426 -0
data/gris.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/gris/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'gris'
|
6
|
+
s.version = Gris::VERSION
|
7
|
+
s.summary = 'A simple api microservice generator.'
|
8
|
+
s.description = 'Gris is a generator for Grape, Roar, Hypermedia, PG API apps.'
|
9
|
+
s.email = 'email@dylanfareed.com'
|
10
|
+
s.homepage = 'http://github.com/dylanfareed/gris/'
|
11
|
+
s.authors = ['Dylan Fareed']
|
12
|
+
s.licenses = 'MIT-LICENSE'
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
15
|
+
s.executables << 'gris'
|
16
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
17
|
+
s.name = 'gris'
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
s.required_ruby_version = '>= 2.1.5'
|
20
|
+
|
21
|
+
s.add_runtime_dependency 'thor', '~> 0.19', '>= 0.19.1'
|
22
|
+
s.add_runtime_dependency 'activesupport', '~> 4.2', '>= 4.2.0'
|
23
|
+
s.add_runtime_dependency 'rake', '~> 10.4', '>= 10.4.2'
|
24
|
+
s.add_runtime_dependency 'git', '~> 1.2', '>= 1.2.8'
|
25
|
+
|
26
|
+
s.add_dependency 'logging'
|
27
|
+
s.add_dependency 'dotenv', '~> 1.0.2', '>= 1.0.2'
|
28
|
+
s.add_dependency 'grape', '~> 0.10.1', '>= 0.10.1'
|
29
|
+
s.add_dependency 'grape-roar', '~> 0.3.0', '>= 0.3.0'
|
30
|
+
|
31
|
+
s.add_dependency 'grape-swagger', '~> 0.9.0', '>= 0.9.0'
|
32
|
+
s.add_dependency 'roar', '~> 1.0.0', '>= 1.0.0'
|
33
|
+
s.add_dependency 'racksh', '~> 1.0'
|
34
|
+
|
35
|
+
s.add_development_dependency 'bundler', '~> 1.7.10', '>= 1.7.10'
|
36
|
+
s.add_development_dependency 'rspec', '~> 3.1', '>= 3.1.0'
|
37
|
+
s.add_development_dependency 'rubocop', '~> 0.28', '>= 0.28.0'
|
38
|
+
s.add_development_dependency 'activerecord', '~> 4.2', '>= 4.2.0'
|
39
|
+
s.add_development_dependency 'acts_as_fu', '~> 0'
|
40
|
+
end
|
data/lib/gris.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# require external libraries
|
2
|
+
require 'rake'
|
3
|
+
require 'dotenv'
|
4
|
+
require 'yaml'
|
5
|
+
require 'grape'
|
6
|
+
require 'json'
|
7
|
+
require 'roar'
|
8
|
+
require 'grape-roar'
|
9
|
+
require 'roar/representer'
|
10
|
+
require 'roar/json'
|
11
|
+
require 'roar/json/hal'
|
12
|
+
|
13
|
+
# require internal files
|
14
|
+
require 'gris/deprecations'
|
15
|
+
require 'gris/grape_extensions/crud_helpers'
|
16
|
+
require 'gris/identity'
|
17
|
+
require 'gris/middleware/app_monitor'
|
18
|
+
require 'gris/output_formatters/paginated_presenter'
|
19
|
+
require 'gris/output_formatters/presenter'
|
20
|
+
require 'gris/setup'
|
21
|
+
require 'gris/version'
|
22
|
+
|
23
|
+
# load rake tasks if Rake installed
|
24
|
+
if defined?(Rake)
|
25
|
+
load 'tasks/routes.rake'
|
26
|
+
load 'tasks/db.rake'
|
27
|
+
end
|
28
|
+
|
29
|
+
module Gris
|
30
|
+
class << self
|
31
|
+
def initialize
|
32
|
+
Gris::Deprecations.initialization_checks
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Gris.initialize
|
data/lib/gris/cli.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'gris/generators'
|
3
|
+
require 'gris/version'
|
4
|
+
|
5
|
+
Gris.load_environment if defined?(Dotenv)
|
6
|
+
|
7
|
+
module Gris
|
8
|
+
class CLI
|
9
|
+
class Generate < Thor
|
10
|
+
register(
|
11
|
+
Generators::ApiGenerator,
|
12
|
+
'api',
|
13
|
+
'api <api_name>',
|
14
|
+
'Create a Grape API, Model and Presenter'
|
15
|
+
)
|
16
|
+
|
17
|
+
register(
|
18
|
+
Generators::MigrationGenerator,
|
19
|
+
'migration',
|
20
|
+
'migration <migration_name> [field[:type][:index] field[:type][:index]]',
|
21
|
+
'Create a Database Migration'
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
class CLI
|
26
|
+
class Base < Thor
|
27
|
+
desc 'version', 'Returns the Gris version number'
|
28
|
+
def version
|
29
|
+
say Gris::VERSION
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'console [environment]', 'Start the Gris console'
|
33
|
+
options aliases: 'c'
|
34
|
+
def console(environment = nil)
|
35
|
+
ENV['RACK_ENV'] = environment || 'development'
|
36
|
+
|
37
|
+
require 'racksh/init'
|
38
|
+
|
39
|
+
begin
|
40
|
+
require 'pry'
|
41
|
+
interpreter = Pry
|
42
|
+
rescue LoadError
|
43
|
+
require 'irb'
|
44
|
+
require 'irb/completion'
|
45
|
+
interpreter = IRB
|
46
|
+
# IRB uses ARGV and does not expect these arguments.
|
47
|
+
ARGV.delete('console')
|
48
|
+
ARGV.delete(environment) if environment
|
49
|
+
end
|
50
|
+
|
51
|
+
Rack::Shell.init
|
52
|
+
|
53
|
+
$0 = "#{$PROGRAM_NAME} console"
|
54
|
+
interpreter.start
|
55
|
+
end
|
56
|
+
|
57
|
+
register(
|
58
|
+
Generators::ScaffoldGenerator,
|
59
|
+
'new',
|
60
|
+
'new <app_name> [app_path]',
|
61
|
+
'Creates a scaffold for a new Gris service'
|
62
|
+
)
|
63
|
+
|
64
|
+
desc 'generate api <api_name>', 'Create a Grape API, Model and Representer'
|
65
|
+
subcommand 'generate api', Gris::CLI::Generate
|
66
|
+
|
67
|
+
desc 'generate migration <migration_name> [field[:type][:index] field[:type][:index]]', 'Create a Database Migration'
|
68
|
+
subcommand 'generate', Gris::CLI::Generate
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Gris
|
2
|
+
class Deprecations
|
3
|
+
# TODO: Called when Gris appliation loads.
|
4
|
+
#
|
5
|
+
# Use this method to check that embedding applications
|
6
|
+
# follow current established best practices.
|
7
|
+
# cf. https://github.com/bellycard/napa/blob/master/lib/napa/deprecations.rb
|
8
|
+
# https://github.com/bellycard/napa/blob/master/lib/napa/deprecations/napa_setup.rb
|
9
|
+
# https://github.com/bellycard/napa/blob/master/lib/napa/deprecations/application_api.rb
|
10
|
+
#
|
11
|
+
def self.gris_setup_check
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
module Gris
|
5
|
+
module Generators
|
6
|
+
class ApiGenerator < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
argument :name
|
9
|
+
|
10
|
+
def name_underscore
|
11
|
+
name.underscore
|
12
|
+
end
|
13
|
+
|
14
|
+
def name_tableize
|
15
|
+
name.tableize
|
16
|
+
end
|
17
|
+
|
18
|
+
def output_directory
|
19
|
+
'.'
|
20
|
+
end
|
21
|
+
|
22
|
+
def api
|
23
|
+
self.class.source_root "#{File.dirname(__FILE__)}/templates/api"
|
24
|
+
say 'Generating api...'
|
25
|
+
directory '.', output_directory
|
26
|
+
say 'API files created!', :green
|
27
|
+
say 'Note that you will need to mount this new endpoint in your ApplicationEndpoint.', :green
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'active_support/all'
|
3
|
+
|
4
|
+
module Gris
|
5
|
+
module Generators
|
6
|
+
class MigrationGenerator < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
# largely ported over, with a few differences, from
|
9
|
+
# https://github.com/rails/rails/blob/76883f92374c6395f13c16628e1d87d40b6d2399/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb
|
10
|
+
argument :migration_name
|
11
|
+
argument :attributes, type: :array, default: []
|
12
|
+
|
13
|
+
attr_reader :migration_action, :join_tables, :table_name
|
14
|
+
|
15
|
+
def version
|
16
|
+
Time.now.utc.strftime('%Y%m%d%H%M%S')
|
17
|
+
end
|
18
|
+
|
19
|
+
def migration_filename
|
20
|
+
"#{version}_#{migration_name.underscore}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def output_directory
|
24
|
+
'./db/migrate'
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_attributes!
|
28
|
+
self.attributes = (attributes || []).map do |attr|
|
29
|
+
GeneratedAttribute.parse(attr)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_local_assigns!
|
34
|
+
@migration_template = 'migration'
|
35
|
+
filename = migration_name.underscore
|
36
|
+
case filename
|
37
|
+
when /^(add|remove)_.*_(?:to|from)_(.*)/
|
38
|
+
@migration_action = Regexp.last_match[1]
|
39
|
+
@table_name = Regexp.last_match[2].pluralize
|
40
|
+
when /join_table/
|
41
|
+
if attributes.length == 2
|
42
|
+
@migration_action = 'join'
|
43
|
+
@join_tables = attributes.map(&:plural_name)
|
44
|
+
|
45
|
+
set_index_names
|
46
|
+
end
|
47
|
+
when /^create_(.+)/
|
48
|
+
@table_name = Regexp.last_match[1].pluralize
|
49
|
+
@migration_template = 'create_table_migration'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def migration
|
54
|
+
self.class.source_root "#{File.dirname(__FILE__)}/templates/#{@migration_template}"
|
55
|
+
say 'Generating migration...'
|
56
|
+
directory '.', output_directory
|
57
|
+
say 'Done!', :green
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def attributes_with_index
|
63
|
+
attributes.select { |a| !a.reference? && a.has_index? }
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_index_names
|
67
|
+
attributes.each_with_index do |attr, i|
|
68
|
+
attr.index_name = [attr, attributes[i - 1]].map { |a| index_name_for(a) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def index_name_for(attribute)
|
73
|
+
if attribute.foreign_key?
|
74
|
+
attribute.name
|
75
|
+
else
|
76
|
+
attribute.name.singularize.foreign_key
|
77
|
+
end.to_sym
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# directly ported from
|
82
|
+
# https://github.com/rails/rails/blob/76883f92374c6395f13c16628e1d87d40b6d2399/railties/lib/rails/generators/generated_attribute.rb
|
83
|
+
class GeneratedAttribute # :nodoc:
|
84
|
+
INDEX_OPTIONS = %w(index uniq)
|
85
|
+
UNIQ_INDEX_OPTIONS = %w(uniq)
|
86
|
+
|
87
|
+
attr_accessor :name, :type
|
88
|
+
attr_reader :attr_options
|
89
|
+
attr_writer :index_name
|
90
|
+
|
91
|
+
class << self
|
92
|
+
def parse(column_definition)
|
93
|
+
name, type, has_index = column_definition.split(':')
|
94
|
+
|
95
|
+
# if user provided "name:index" instead of "name:string:index"
|
96
|
+
# type should be set blank so GeneratedAttribute's constructor
|
97
|
+
# could set it to :string
|
98
|
+
has_index, type = type, nil if INDEX_OPTIONS.include?(type)
|
99
|
+
|
100
|
+
type, attr_options = *parse_type_and_options(type)
|
101
|
+
type = type.to_sym if type
|
102
|
+
|
103
|
+
if type && reference?(type)
|
104
|
+
references_index = UNIQ_INDEX_OPTIONS.include?(has_index) ? { unique: true } : true
|
105
|
+
attr_options[:index] = references_index
|
106
|
+
end
|
107
|
+
|
108
|
+
new(name, type, has_index, attr_options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def reference?(type)
|
112
|
+
[:references, :belongs_to].include? type
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
# parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to
|
118
|
+
# when declaring options curly brackets should be used
|
119
|
+
def parse_type_and_options(type)
|
120
|
+
case type
|
121
|
+
when /(string|text|binary|integer)\{(\d+)\}/
|
122
|
+
return Regexp.last_match[1], limit: Regexp.last_match[2].to_i
|
123
|
+
when /decimal\{(\d+)[,.-](\d+)\}/
|
124
|
+
return :decimal, precision: Regexp.last_match[1].to_i, scale: Regexp.last_match[2].to_i
|
125
|
+
when /(references|belongs_to)\{polymorphic\}/
|
126
|
+
return Regexp.last_match[1], polymorphic: true
|
127
|
+
else
|
128
|
+
return type, {}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def initialize(name, type = nil, index_type = false, attr_options = {})
|
134
|
+
@name = name
|
135
|
+
@type = type || :string
|
136
|
+
@has_index = INDEX_OPTIONS.include?(index_type)
|
137
|
+
@has_uniq_index = UNIQ_INDEX_OPTIONS.include?(index_type)
|
138
|
+
@attr_options = attr_options
|
139
|
+
end
|
140
|
+
|
141
|
+
def field_type
|
142
|
+
@field_type ||= case type
|
143
|
+
when :integer then :number_field
|
144
|
+
when :float, :decimal then :text_field
|
145
|
+
when :time then :time_select
|
146
|
+
when :datetime, :timestamp then :datetime_select
|
147
|
+
when :date then :date_select
|
148
|
+
when :text then :text_area
|
149
|
+
when :boolean then :check_box
|
150
|
+
else
|
151
|
+
:text_field
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def default
|
156
|
+
@default ||= case type
|
157
|
+
when :integer then 1
|
158
|
+
when :float then 1.5
|
159
|
+
when :decimal then '9.99'
|
160
|
+
when :datetime, :timestamp, :time then Time.now.to_s(:db)
|
161
|
+
when :date then Date.today.to_s(:db)
|
162
|
+
when :string then name == 'type' ? '' : 'MyString'
|
163
|
+
when :text then 'MyText'
|
164
|
+
when :boolean then false
|
165
|
+
when :references, :belongs_to then nil
|
166
|
+
else
|
167
|
+
''
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def plural_name
|
172
|
+
name.sub(/_id$/, '').pluralize
|
173
|
+
end
|
174
|
+
|
175
|
+
def singular_name
|
176
|
+
name.sub(/_id$/, '').singularize
|
177
|
+
end
|
178
|
+
|
179
|
+
def human_name
|
180
|
+
name.humanize
|
181
|
+
end
|
182
|
+
|
183
|
+
def index_name
|
184
|
+
@index_name ||= if polymorphic?
|
185
|
+
%w(id type).map { |t| "#{name}_#{t}" }
|
186
|
+
else
|
187
|
+
column_name
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def column_name
|
192
|
+
@column_name ||= reference? ? "#{name}_id" : name
|
193
|
+
end
|
194
|
+
|
195
|
+
def foreign_key?
|
196
|
+
!!(name =~ /_id$/)
|
197
|
+
end
|
198
|
+
|
199
|
+
def reference?
|
200
|
+
self.class.reference?(type)
|
201
|
+
end
|
202
|
+
|
203
|
+
def polymorphic?
|
204
|
+
attr_options.key?(:polymorphic)
|
205
|
+
end
|
206
|
+
|
207
|
+
def has_index?
|
208
|
+
@has_index
|
209
|
+
end
|
210
|
+
|
211
|
+
def has_uniq_index?
|
212
|
+
@has_uniq_index
|
213
|
+
end
|
214
|
+
|
215
|
+
def password_digest?
|
216
|
+
name == 'password' && type == :digest
|
217
|
+
end
|
218
|
+
|
219
|
+
def inject_options
|
220
|
+
''.tap { |s| @attr_options.each { |k, v| s << ", #{k}: #{v.inspect}" } }
|
221
|
+
end
|
222
|
+
|
223
|
+
def inject_index_options
|
224
|
+
has_uniq_index? ? ', unique: true' : ''
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
|
4
|
+
module Gris
|
5
|
+
module Generators
|
6
|
+
class ScaffoldGenerator < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
source_root "#{File.dirname(__FILE__)}/templates/scaffold"
|
10
|
+
|
11
|
+
argument :app_name
|
12
|
+
argument :app_path, optional: true
|
13
|
+
|
14
|
+
def generate
|
15
|
+
say 'Generating scaffold...'
|
16
|
+
directory '.', (app_path || app_name)
|
17
|
+
say 'Done!', :green
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|