# frozen_string_literal: true require_relative './eval_template' module DeclareSchema module Support class IndentedBuffer def initialize(indent: 0) @string = +"" @indent = indent @column = 0 @indent_amount = 2 end def to_string @string end def indent! @indent += @indent_amount yield @indent -= @indent_amount end def newline! @column = 0 @string << "\n" end def <<(str) if (difference = @indent - @column) > 0 @string << ' ' * difference end @column += difference @string << str newline! end end module Model class << self def included(base) base.class_eval do include EvalTemplate argument :attributes, type: :array, default: [], banner: "field:type field:type" class << self def banner "rails generate declare_schema:model #{arguments.map(&:usage).join(' ')} [options]" end end class_option :timestamps, type: :boolean def generate_model invoke "active_record:model", [name], { migration: false }.merge(options) end def inject_declare_schema_code_into_model_file gsub_file(model_path, / # attr_accessible :title, :body\n/m, "") inject_into_class(model_path, class_name) do declare_model_fields_and_associations end end private def declare_model_fields_and_associations buffer = ::DeclareSchema::Support::IndentedBuffer.new(indent: 2) buffer.newline! buffer << 'declare_schema do' buffer.indent! do field_attributes.each do |attribute| decl = "%-#{max_attribute_length}s" % attribute.type + ' ' + attribute.name.to_sym.inspect + case attribute.type.to_s when 'string' ', limit: 255' else '' end buffer << decl end if options[:timestamps] buffer.newline! buffer << 'timestamps' end end buffer << 'end' if bts.any? buffer.newline! bts.each do |bt| buffer << "belongs_to #{bt.to_sym.inspect}" end end if hms.any? buffer.newline hms.each do |hm| buffer << "has_many #{hm.to_sym.inspect}, dependent: :destroy" end end buffer.newline! buffer.to_string end protected def model_path @model_path ||= File.join("app", "models", "#{file_path}.rb") end def max_attribute_length attributes.map { |attribute| attribute.type.length }.max end def field_attributes attributes.reject { |a| a.name == "bt" || a.name == "hm" } end def accessible_attributes field_attributes.map(&:name) + bts.map { |bt| "#{bt}_id" } + bts + hms end def hms attributes.select { |a| a.name == "hm" }.map(&:type) end def bts attributes.select { |a| a.name == "bt" }.map(&:type) end end end end end end end