module Rails2use

Constants

VERSION

Attributes

writer[RW]

Public Class Methods

extract(options={}) click to toggle source
# File lib/rails2use.rb, line 10
def self.extract(options={})
  options[:writer] ||= 'PlantumlWriter'
  const_writer = options[:writer].constantize
  suffix = const_writer.suffix
  options[:file] ||= Rails.root.join('doc', 'uml', "output.#{suffix}")

  types = if options[:type]
            options[:type].split(',').map { |t| t.strip.downcase }
          else
            'class'
          end

  path = Rails.root.join ''
  sub_paths = (options[:file].to_s+'/').gsub(path.to_s, '').split('/')

  sub_paths.each do |subdir|
    path = path.join subdir
    Dir.mkdir(path.dirname) unless Dir.exists?(path.dirname)
  end
  #path

  abstract_classes = []
  subclasses = {}

  model_blacklist = defined?(Doorkeeper) ? [Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application] : []
  Rails.application.eager_load! #unless Rails.configuration.cache_classes
  all_models = (ActiveRecord::Base.descendants - model_blacklist)

  attribute_blacklist = %w(model)

  @writer = const_writer.new options[:file]

  @writer.write_head :class if types.include?('class')
  #abstract classes first
  all_models.each do |model|

    #belongs_to
    model.reflect_on_all_associations(:belongs_to).each do |association|
      #extract polymorphic classes and determine abstract class status
      class_name = association.name.to_s.camelcase
      if association.options.has_key?(:polymorphic)
        if !abstract_classes.include?(class_name)
          @writer.write_abstract_class class_name if types.include?('class')
          abstract_classes << class_name
        end
        subclasses[model.name] = [class_name]
      end
    end
  end

  all_models.each do |model|
    model_associations = {:has_many => {}, :has_one => {}}
    #def_abstract_class = abstract_classes.include?(model.name) ? 'abstract ' : ''
    def_super_classes = subclasses.has_key?(model.name) ? subclasses[model.name].join(',') : ''

    model_attributes = ''
    attribute_names = model.try(:attribute_names) rescue model.columns.map { |c| c.name }
    attribute_names.each do |attribute|
      model_attributes << " #{attribute} : #{@writer.types[model.columns_hash[attribute].type.to_s]}\n" if @writer.types.has_key?(model.columns_hash[attribute].type.to_s) && !attribute_blacklist.include?(attribute)
    end

    #has_many
    model.reflect_on_all_associations(:has_many).each do |association|
      #extract associations, also belongs_to are covered by this feature
      class_name = association.options.has_key?(:as) && abstract_classes.include?(association.options[:as].to_s.camelcase) ? association.options[:as].to_s.camelcase : association.class_name
      model_associations[:has_many][(model.name.to_s+'_'+association.name.to_s).camelcase] = {class_name: model.name, role_name: (association.name.to_s+model.name).underscore, foreign_class_name: class_name, foreign_role_name: association.name}
    end

    #has_and_belongs_to_many

    #has_one
    model.reflect_on_all_associations(:has_one).each do |association|
      #skip thorugh-associations
      unless association.options.has_key?(:through)
        model_associations[:has_one][(model.name.to_s+'_'+association.name.to_s).camelcase] = {class_name: model.name, role_name: (association.name.to_s+model.name).underscore, foreign_class_name: association.class_name, foreign_role_name: association.name}
      end
    end
    @writer.write_class model.name, def_super_classes, model_attributes, model_associations if types.include?('class')
  end
  @writer.write_class_end if types.include?('class')

  @writer.write_foot :class if types.include?('class')
  # end class diagram

  if types.include?('object')
    @writer.write_head :object
    all_instances = []
    all_models.each do |model|
      all_instances_by_model = model.unscoped.all
      all_instances += all_instances_by_model
      all_instances_by_model.each do |instance|
        instance_name = "#{model.name.underscore}#{instance.id.to_s}"
        attributes = {}
        attribute_names = model.try(:attribute_names) rescue model.columns.map { |c| c.name }
        attribute_names.each do |attribute|
          if @writer.types.has_key?(model.columns_hash[attribute].type.to_s) && !attribute_blacklist.include?(attribute)
            value = instance.send attribute
            attributes[attribute] = value if value.present?
          end
        end
        @writer.write_instance instance_name, model.name, attributes
      end
    end
    all_instances.each do |instance|
      model = instance.class
      instance_name = "#{model.name.underscore}#{instance.id.to_s}"
      (model.reflect_on_all_associations(:has_one) + model.reflect_on_all_associations(:has_many)).each do |association|
        unless association.options.keys.include?(:through)
          association_name = (model.name.to_s+'_'+association.name.to_s).camelcase
          foreign_instances = instance.send association.name
          foreign_instances = [foreign_instances] unless foreign_instances.is_a?(Enumerable)
          foreign_instances.compact.each do |foreign_instance|
            @writer.write_association association_name, instance_name, foreign_instance.class.to_s.underscore+foreign_instance.id.to_s
          end
        end
        #class_name = association.options.has_key?(:as) && association.options[:as].to_s.camelcase.in?(abstract_classes) ? association.options[:as].to_s.camelcase : association.class_name
      end
    end
    @writer.write_foot :object
  end
  @writer.close
  options[:file]
end
extract!(options={}) click to toggle source
# File lib/rails2use.rb, line 6
def self.extract!(options={})
  Rails2use.extract(options)
end