Class: ModelsDiagram
- Inherits:
-
AppDiagram
- Object
- AppDiagram
- ModelsDiagram
- Defined in:
- lib/railroady/models_diagram.rb
Overview
RailRoady models diagram
Instance Method Summary collapse
- #engine_files ⇒ Object
- #extract_class_name(filename) ⇒ Object
-
#generate ⇒ Object
Process model files.
- #get_files(prefix = '') ⇒ Object
-
#include_inheritance?(current_class) ⇒ Boolean
process_class.
-
#initialize(options = OptionsStruct.new) ⇒ ModelsDiagram
constructor
A new instance of ModelsDiagram.
- #process_active_record_model(current_class) ⇒ Object
-
#process_association(class_name, assoc) ⇒ Object
Process a model association.
- #process_basic_class(current_class) ⇒ Object
- #process_basic_module(current_class) ⇒ Object
-
#process_class(current_class) ⇒ Object
Process a model class.
-
#process_couchrest_model(current_class) ⇒ Object
Some very basic CouchRest::Model support.
- #process_datamapper_model(current_class) ⇒ Object
-
#process_datamapper_relationship(class_name, relation) ⇒ Object
Process a DataMapper relationship.
- #process_mongoid_model(current_class) ⇒ Object
Methods inherited from AppDiagram
Constructor Details
#initialize(options = OptionsStruct.new) ⇒ ModelsDiagram
Returns a new instance of ModelsDiagram.
11 12 13 14 15 16 |
# File 'lib/railroady/models_diagram.rb', line 11 def initialize( = OptionsStruct.new) super @graph.diagram_type = 'Models' # Processed habtm associations @habtm = [] end |
Instance Method Details
#engine_files ⇒ Object
39 40 41 |
# File 'lib/railroady/models_diagram.rb', line 39 def engine_files engines.collect { |engine| Dir.glob("#{engine.root}/app/models/**/*.rb") }.flatten end |
#extract_class_name(filename) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/railroady/models_diagram.rb', line 43 def extract_class_name(filename) filename_was, class_name = filename, nil filename = "app/models/#{filename.split('app/models')[1]}" while filename.split('/').length > 2 begin class_name = filename.match(/.*\/models\/(.*).rb$/)[1].camelize class_name.constantize break rescue Exception class_name = nil filename_end = filename.split('/')[2..-1] filename_end.shift filename = "#{filename.split('/')[0, 2].join('/')}/#{filename_end.join('/')}" end end if class_name.nil? filename_was.match(/.*\/models\/(.*).rb$/)[1].camelize else class_name end end |
#generate ⇒ Object
Process model files
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/railroady/models_diagram.rb', line 19 def generate STDERR.puts 'Generating models diagram' if @options.verbose get_files.each do |f| begin process_class extract_class_name(f).constantize rescue Exception STDERR.puts "Warning: exception #{$ERROR_INFO} raised while trying to load model class #{f}" end end end |
#get_files(prefix = '') ⇒ Object
30 31 32 33 34 35 36 37 |
# File 'lib/railroady/models_diagram.rb', line 30 def get_files(prefix = '') files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix + 'app/models/**/*.rb') files += Dir.glob('vendor/plugins/**/app/models/*.rb') if @options.plugins_models files -= Dir.glob(prefix + 'app/models/concerns/**/*.rb') unless @options.include_concerns files += engine_files if @options.engine_models files -= Dir.glob(@options.exclude) files end |
#include_inheritance?(current_class) ⇒ Boolean
process_class
93 94 95 96 97 98 |
# File 'lib/railroady/models_diagram.rb', line 93 def include_inheritance?(current_class) STDERR.puts current_class.superclass if @options.verbose (defined?(ActiveRecord::Base) ? current_class.superclass != ActiveRecord::Base : true) && (defined?(CouchRest::Model::Base) ? current_class.superclass != CouchRest::Model::Base : true) && (current_class.superclass != Object) end |
#process_active_record_model(current_class) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/railroady/models_diagram.rb', line 111 def process_active_record_model(current_class) node_attribs = [] if @options.brief || current_class.abstract_class? node_type = 'model-brief' else node_type = 'model' # Collect model's content columns # content_columns = current_class.content_columns if @options.hide_magic # From patch #13351 # http://wiki.rubyonrails.org/rails/pages/MagicFieldNames magic_fields = %w(created_at created_on updated_at updated_on lock_version type id position parent_id lft rgt quote template) magic_fields << current_class.table_name + '_count' if current_class.respond_to? 'table_name' content_columns = current_class.content_columns.select { |c| !magic_fields.include? c.name } else content_columns = current_class.columns end content_columns.each do |a| content_column = a.name content_column += ' :' + a.sql_type.to_s unless @options.hide_types node_attribs << content_column end end @graph.add_node [node_type, current_class.name, node_attribs] # Process class associations associations = current_class.reflect_on_all_associations if @options.inheritance && ! @options.transitive superclass_associations = current_class.superclass.reflect_on_all_associations associations = associations.select { |a| !superclass_associations.include? a } # This doesn't works! # associations -= current_class.superclass.reflect_on_all_associations end associations.each do |a| process_association current_class.name, a end true end |
#process_association(class_name, assoc) ⇒ Object
Process a model association
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/railroady/models_diagram.rb', line 271 def process_association(class_name, assoc) STDERR.puts "- Processing model association #{assoc.name}" if @options.verbose # Skip "belongs_to" associations macro = assoc.macro.to_s return if %w(belongs_to referenced_in).include?(macro) && !@options.show_belongs_to # Skip "through" associations through = assoc..include?(:through) return if through && @options.hide_through # TODO: # FAIL: assoc.methods.include?(:class_name) # FAIL: assoc.responds_to?(:class_name) assoc_class_name = assoc.class_name rescue nil assoc_class_name ||= assoc.name.to_s.underscore.singularize.camelize # Only non standard association names needs a label # from patch #12384 # if assoc.class_name == assoc.name.to_s.singularize.camelize if assoc_class_name == assoc.name.to_s.singularize.camelize assoc_name = '' else assoc_name = assoc.name.to_s end # Patch from "alpack" to support classes in a non-root module namespace. See: http://disq.us/yxl1v if class_name.include?('::') && !assoc_class_name.include?('::') assoc_class_name = class_name.split('::')[0..-2].push(assoc_class_name).join('::') end assoc_class_name.gsub!(/^::/, '') if %w(has_one references_one embeds_one).include?(macro) assoc_type = 'one-one' elsif macro == 'has_many' && (!assoc.[:through]) || %w(references_many embeds_many).include?(macro) assoc_type = 'one-many' elsif macro == 'belongs_to' assoc_type = 'belongs-to' else # habtm or has_many, :through # Add FAKE associations too in order to understand mistakes return if @habtm.include? [assoc_class_name, class_name, assoc_name] assoc_type = 'many-many' @habtm << [class_name, assoc_class_name, assoc_name] end # from patch #12384 # @graph.add_edge [assoc_type, class_name, assoc.class_name, assoc_name] @graph.add_edge [assoc_type, class_name, assoc_class_name, assoc_name] end |
#process_basic_class(current_class) ⇒ Object
100 101 102 103 104 |
# File 'lib/railroady/models_diagram.rb', line 100 def process_basic_class(current_class) node_type = @options.brief ? 'class-brief' : 'class' @graph.add_node [node_type, current_class.name] true end |
#process_basic_module(current_class) ⇒ Object
106 107 108 109 |
# File 'lib/railroady/models_diagram.rb', line 106 def process_basic_module(current_class) @graph.add_node ['module', current_class.name] false end |
#process_class(current_class) ⇒ Object
Process a model class
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/railroady/models_diagram.rb', line 70 def process_class(current_class) STDERR.puts "Processing #{current_class}" if @options.verbose generated = if defined?(CouchRest::Model::Base) && current_class.new.is_a?(CouchRest::Model::Base) process_couchrest_model(current_class) elsif defined?(Mongoid::Document) && current_class.new.is_a?(Mongoid::Document) process_mongoid_model(current_class) elsif defined?(DataMapper::Resource) && current_class.new.is_a?(DataMapper::Resource) process_datamapper_model(current_class) elsif current_class.respond_to? 'reflect_on_all_associations' process_active_record_model(current_class) elsif @options.all && (current_class.is_a? Class) process_basic_class(current_class) elsif @options.modules && (current_class.is_a? Module) process_basic_module(current_class) end if @options.inheritance && generated && include_inheritance?(current_class) @graph.add_edge ['is-a', current_class.superclass.name, current_class.name] end end |
#process_couchrest_model(current_class) ⇒ Object
Some very basic CouchRest::Model support
Field types note: the field’s type is rendered only if it’s explicitly specified in a model.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/railroady/models_diagram.rb', line 242 def process_couchrest_model(current_class) node_attribs = [] if @options.brief node_type = 'model-brief' else node_type = 'model' # Collect model's content columns content_columns = current_class.properties if @options.hide_magic magic_fields = %w(created_at updated_at type _id _rev) content_columns = content_columns.select { |c| !magic_fields.include?(c.name) } end content_columns.each do |a| content_column = a.name content_column += " :#{a.type}" unless @options.hide_types || a.type.nil? node_attribs << content_column end end @graph.add_node [node_type, current_class.name, node_attribs] true end |
#process_datamapper_model(current_class) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/railroady/models_diagram.rb', line 156 def process_datamapper_model(current_class) node_attribs = [] if @options.brief # || current_class.abstract_class? node_type = 'model-brief' else node_type = 'model' # Collect model's properties props = current_class.properties.sort_by(&:name) if @options.hide_magic # From patch #13351 # http://wiki.rubyonrails.org/rails/pages/MagicFieldNames magic_fields = %w(created_at created_on updated_at updated_on lock_version _type _id position parent_id lft rgt quote template) props = props.select { |c| !magic_fields.include?(c.name.to_s) } end props.each do |a| prop = a.name.to_s prop += ' :' + a.class.name.split('::').last unless @options.hide_types node_attribs << prop end end @graph.add_node [node_type, current_class.name, node_attribs] # Process relationships relationships = current_class.relationships # TODO: Manage inheritance relationships.each do |a| process_datamapper_relationship current_class.name, a end true end |
#process_datamapper_relationship(class_name, relation) ⇒ Object
Process a DataMapper relationship
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/railroady/models_diagram.rb', line 323 def process_datamapper_relationship(class_name, relation) STDERR.puts "- Processing DataMapper model relationship #{relation.name}" if @options.verbose # Skip "belongs_to" relationships dm_type = relation.class.to_s.split('::')[-2] return if dm_type == 'ManyToOne' && !@options.show_belongs_to dm_parent_model = relation.parent_model.to_s dm_child_model = relation.child_model.to_s assoc_class_name = '' # Get the assoc_class_name if dm_parent_model.eql?(class_name) assoc_class_name = dm_child_model else assoc_class_name = dm_parent_model end # Only non standard association names needs a label assoc_name = '' unless relation.name.to_s.singularize.camelize.eql?(assoc_class_name.split('::').last) assoc_name = relation.name.to_s end # TO BE IMPROVED rel_type = 'many-many' # default value for ManyToOne and ManyToMany if dm_type == 'OneToOne' rel_type = 'one-one' elsif dm_type == 'OneToMany' rel_type = 'one-many' end @graph.add_edge [rel_type, class_name, assoc_class_name, assoc_name] end |
#process_mongoid_model(current_class) ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/railroady/models_diagram.rb', line 194 def process_mongoid_model(current_class) node_attribs = [] if @options.brief node_type = 'model-brief' else node_type = 'model' # Collect model's content columns content_columns = current_class.fields.values.sort_by(&:name) if @options.hide_magic # From patch #13351 # http://wiki.rubyonrails.org/rails/pages/MagicFieldNames magic_fields = %w(created_at created_on updated_at updated_on lock_version _type _id position parent_id lft rgt quote template) content_columns = content_columns.select { |c| !magic_fields.include?(c.name) } end content_columns.each do |a| content_column = a.name content_column += " :#{a.type}" unless @options.hide_types node_attribs << content_column end end @graph.add_node [node_type, current_class.name, node_attribs] # Process class associations associations = current_class.relations.values if @options.inheritance && !@options.transitive && current_class.superclass.respond_to?(:relations) associations -= current_class.superclass.relations.values end associations.each do |a| process_association current_class.name, a end true end |