diff --git a/bin/prism b/bin/prism new file mode 100755 index 0000000..6b94b08 --- /dev/null +++ b/bin/prism @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +$LOAD_PATH.unshift(File.expand_path('../lib', __dir__)) +require 'prism' + +begin + Prism::Cli.new.run(ARGV) +rescue Prism::Cli::UsageError => e + warn "error: #{e.message}" + exit 1 +end diff --git a/lib/prism/cli.rb b/lib/prism/cli.rb new file mode 100644 index 0000000..42f2f0e --- /dev/null +++ b/lib/prism/cli.rb @@ -0,0 +1,181 @@ +require 'fileutils' +require 'time' + +module Prism + class Cli + class UsageError < StandardError; end + + ServerScript = <<~'RUBY' + require_relative '../app' + + server = Prism::Server.new(APP_CLASS, port: (ARGV[0] || 3000).to_i).start + puts "listening on #{server.url}" + trap('INT') { server.stop; exit } + sleep + RUBY + + def initialize(root = Dir.pwd) + @root = root + end + + def run(argv) + command, *rest = argv + case command + when 'new' then new_app(rest.first || raise(UsageError, 'usage: prism new APP_NAME')) + when 'generate', 'g' then generate(rest) + else raise UsageError, "unknown command #{command.inspect}" + end + end + + def new_app(name) + app_dir = File.join(@root, name) + raise UsageError, "#{app_dir} already exists" if Dir.exist?(app_dir) + + %w[app/controllers app/models app/views/layouts db/migrate public bin].each do |subdir| + FileUtils.mkdir_p(File.join(app_dir, subdir)) + end + + write_file(File.join(app_dir, 'app', 'views', 'layouts', 'application.erb'), layout_template) + write_file(File.join(app_dir, 'app.rb'), app_boot_template(name)) + write_file(File.join(app_dir, 'config.ru'), config_ru_template(name)) + write_file(File.join(app_dir, 'bin', 'server'), ServerScript.sub('APP_CLASS', Inflector.camelize(name))) + File.chmod(0o755, File.join(app_dir, 'bin', 'server')) + app_dir + end + + def generate_migration(name, fields = []) + raise UsageError, 'usage: prism generate migration NAME [field:type ...]' unless name + version = next_migration_version + class_name = Inflector.camelize(name) + path = File.join(@root, 'db', 'migrate', "#{version}_#{Inflector.underscore(name)}.rb") + write_file(path, migration_template(class_name, name, fields)) + path + end + + def generate_model(name, fields = []) + raise UsageError, 'usage: prism generate model NAME [field:type ...]' unless name + class_name = Inflector.camelize(name) + model_path = File.join(@root, 'app', 'models', "#{Inflector.underscore(name)}.rb") + write_file(model_path, model_template(class_name)) + migration_path = generate_migration("create_#{Inflector.tableize(class_name)}", fields) + [model_path, migration_path] + end + + private + + def generate(rest) + kind, name, *fields = rest + case kind + when 'migration' then generate_migration(name, fields) + when 'model' then generate_model(name, fields) + else raise UsageError, "unknown generator #{kind.inspect}" + end + end + + def next_migration_version + version = Time.now.utc.strftime('%Y%m%d%H%M%S') + version = (version.to_i + 1).to_s while File.exist?(File.join(@root, 'db', 'migrate')) && + Dir.glob(File.join(@root, 'db', 'migrate', "#{version}_*.rb")).any? + version + end + + def write_file(path, content) + FileUtils.mkdir_p(File.dirname(path)) + File.write(path, content) + end + + def layout_template + <<~ERB + + +