Class: RailsERD::Diagram

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_erd/diagram.rb,
lib/rails_erd/diagram/graphviz.rb

Overview

This class is an abstract class that will process a domain model and allows easy creation of diagrams. To implement a new diagram type, derive from this class and override process_entity, process_relationship, and (optionally) save.

As an example, a diagram class that generates code that can be used with yUML (yuml.me) can be as simple as:

require "rails_erd/diagram"

class YumlDiagram < RailsERD::Diagram
  setup { @edges = [] }

  each_relationship do |relationship|
    return if relationship.indirect?

    arrow = case
    when relationship.one_to_one?   then "1-1>"
    when relationship.one_to_many?  then "1-*>"
    when relationship.many_to_many? then "*-*>"
    end

    @edges << "[#{relationship.source}] #{arrow} [#{relationship.destination}]"
  end

  save { @edges * "\n" }
end

Then, to generate the diagram (example based on the domain model of Gemcutter):

YumlDiagram.create
#=> "[Rubygem] 1-*> [Ownership]
#    [Rubygem] 1-*> [Subscription]
#    [Rubygem] 1-*> [Version]
#    [Rubygem] 1-1> [Linkset]
#    [Rubygem] 1-*> [Dependency]
#    [Version] 1-*> [Dependency]
#    [User] 1-*> [Ownership]
#    [User] 1-*> [Subscription]
#    [User] 1-*> [WebHook]"

For another example implementation, see Diagram::Graphviz, which is the default (and currently only) diagram type that is used by Rails ERD.

Options

The following options are available and will by automatically used by any diagram generator inheriting from this class.

attributes

Selects which attributes to display. Can be any combination of :content, :primary_keys, :foreign_keys, :timestamps, or :inheritance.

disconnected

Set to false to exclude entities that are not connected to other entities. Defaults to false.

indirect

Set to false to exclude relationships that are indirect. Indirect relationships are defined in Active Record with has_many :through associations.

inheritance

Set to true to include specializations, which correspond to Rails single table inheritance.

polymorphism

Set to true to include generalizations, which correspond to Rails polymorphic associations.

warn

When set to false, no warnings are printed to the command line while processing the domain model. Defaults to true.

Direct Known Subclasses

Graphviz

Defined Under Namespace

Classes: Graphviz

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(domain, options = {}) ⇒ Diagram

Create a new diagram based on the given domain.



113
114
115
# File 'lib/rails_erd/diagram.rb', line 113

def initialize(domain, options = {})
  @domain, @options = domain, RailsERD.options.merge(options)
end

Instance Attribute Details

#domainObject (readonly)

The domain that this diagram represents.



110
111
112
# File 'lib/rails_erd/diagram.rb', line 110

def domain
  @domain
end

#optionsObject (readonly)

The options that are used to create this diagram.



107
108
109
# File 'lib/rails_erd/diagram.rb', line 107

def options
  @options
end

Class Method Details

.create(options = {}) ⇒ Object

Generates a new domain model based on all ActiveRecord::Base subclasses, and creates a new diagram. Use the given options for both the domain generation and the diagram generation.



73
74
75
# File 'lib/rails_erd/diagram.rb', line 73

def create(options = {})
  new(Domain.generate(options), options).create
end

Instance Method Details

#createObject

Generates and saves the diagram, returning the result of save.



118
119
120
121
# File 'lib/rails_erd/diagram.rb', line 118

def create
  generate
  save
end

#generateObject

Generates the diagram, but does not save the output. It is called internally by Diagram#create.



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rails_erd/diagram.rb', line 125

def generate
  instance_eval(&callbacks[:setup])
  if options.only_recursion_depth.present?
    depth = options.only_recursion_depth.to_s.to_i
    options[:only].dup.each do |class_name|
      options[:only]+= recurse_into_relationships(@domain.entity_by_name(class_name), depth)
    end
    options[:only].uniq!
  end

  filtered_entities.each do |entity|
    instance_exec entity, filtered_attributes(entity), &callbacks[:each_entity]
  end

  filtered_specializations.each do |specialization|
    instance_exec specialization, &callbacks[:each_specialization]
  end

  filtered_relationships.each do |relationship|
    instance_exec relationship, &callbacks[:each_relationship]
  end
end

#recurse_into_relationships(entity, max_level, current_level = 0) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/rails_erd/diagram.rb', line 148

def recurse_into_relationships(entity, max_level, current_level = 0)
  return [] unless entity
  return [] if max_level == current_level

  relationships = entity.relationships.reject{|r| r.indirect? || r.recursive?}

  relationships.map do |relationship|
    other_entitiy = if relationship.source == entity
                      relationship.destination
                    else
                      relationship.source
                    end
    if other_entitiy and !other_entitiy.generalized?
      [other_entitiy.name] + recurse_into_relationships(other_entitiy, max_level, current_level + 1)
    else
      []
    end
  end.flatten.uniq
end

#saveObject



168
169
170
# File 'lib/rails_erd/diagram.rb', line 168

def save
  instance_eval(&callbacks[:save])
end