Class: MongoidErd

Inherits:
Object
  • Object
show all
Defined in:
lib/mongoid_erd.rb

Instance Method Summary collapse

Constructor Details

#initialize(config = {}) ⇒ MongoidErd

Returns a new instance of MongoidErd.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/mongoid_erd.rb', line 29

def initialize config = {}
  @config = config
    # tag: [], tags: {}, include = [], exclude = [], model_dir = ""

  
  # parse the option file

  if @config[:conf_file] and File.exists? @config[:conf_file]
    yml = YAML.load(File.open(@config[:conf_file], 'r:utf-8').read)
    @config[:tags] = yml["tags"]
    @config[:title] = yml["title"]
  else
    raise "#{@config[:conf_file]} does not exists" if @config[:conf_file]
  end
  
  # merge tag attributes recursively

  @config[:tags].each do |t,v|
    tv = @config[:tags]["_default"].clone || {} 
    p = nil
    t.split('.').each do |pt|
      p = p ? [p, pt].join('.') : pt # merge in order: tv < a < a.b < a.b.c, ...

      # puts "merge from #{p} to #{t}"

      tv.merge! @config[:tags][p] if @config[:tags][p]
    end
    @config[:tags][t] = tv
  end

  @models = Hash.new
end

Instance Method Details

#get(key) ⇒ Object



61
62
63
# File 'lib/mongoid_erd.rb', line 61

def get key
  @config[key]
end

#outputObject



190
191
192
193
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
# File 'lib/mongoid_erd.rb', line 190

def output 
  g = Rviz::Graph.new @config[:title], {rankdir: 'LR', dpi: 300}

  @models.each do |mname, model|
    g.add_record(model.name.camelize, model.attrs)
    g.node(model.name.camelize).add_row(model.title, true)
    model.fields.each do |field|
      g.node(model.name.camelize).add_row(field.as_row, true, 'l')
      if field.edge
        to_node, to_anchor, attrs = field.edge[0].underscore, field.edge[1], field.edge[2]
        unless @models[to_node]
          g.add(to_node, 'oval', {style:'filled', fillcolor:'grey', color:'grey'})
          to_anchor = ''
        end
        g.link(model.name.camelize, field.as_row, to_node.camelize, to_anchor, attrs)
      end
    end

    # relations

    if model.parent
      unless @models[model.parent]
        g.add(model.parent, 'oval', {style:'filled', fillcolor:'grey', color:'grey'})
      end
      g.link(model.name.camelize, model.title, model.parent.camelize, '', {arrowhead: 'onormal'})
    end
  end

  g.output
end

#parseObject

parse the fold contains mongoid source



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
155
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
# File 'lib/mongoid_erd.rb', line 75

def parse
  raise "directory #{@config[:model_dir]} not exists" unless File.directory? @config[:model_dir]
  Dir["#{@config[:model_dir]}/*.rb"].each do |file|
    crt_model = Model.new
    model_attrs_ = Hash.new
    in_public = true
    File.open(file, 'r:utf-8').each do |line|
      line.chomp!

      # erd_tag and attr

      if /^[\#\s]*erd_tag\:?\s*(?<tag_>[\w\.]+)/ =~ line
        crt_model.tag = tag_ 
        crt_model.attrs = @config[:tags][tag_]
      end

      # catch class definition

      if /^\s*class\s+(?<name_>\w+)/ =~ line
        crt_model.name = name_.underscore 
        self.parse_erd crt_model, line
        if /^\s*class\s+\w+\s+\<\s+(?<parent_>\w+)/ =~ line
          crt_model.parent = parent_.underscore if parent_
        end
      end
      
      # catch functions

      in_public = true if /public\:/ =~ line
      in_public = false if /private\:/ =~ line

      if /^\s*def\s+(?<func_>[^#]+)\s*/ =~ line
        field_ = Fields.new
        field_.name, field_.type = func_, 'function'
        self.parse_erd field_, line # parse erd attr and label

        # arbitrage link

        if /\-\>\s*(?<name_>\w+)(\{(?<attrs_>.+)\})?/ =~ line
          attrs = {}
          attrs = YAML.load(attrs_) if attrs_
          field_.edge = [name_, '', attrs]
        end
        crt_model.fields << field_ 
      end

      # catch field

      if /^\s*field\s+\:(?<name_>\w+)\s*\,.*\:?type\:?\s*(?<type_>[A-Za-z_0-9\:]+)/ =~ line
        field_ = Fields.new
        field_.name, field_.type = name_, type_
        self.parse_erd field_, line # parse erd attr and label

        # arbitrage link

        if /\-\>\s*(?<name_>\w+)(\{(?<attrs_>.+)\})?/ =~ line
          attrs = {}
          attrs = YAML.load(attrs_) if attrs_
          field_.edge = [name_, '', attrs]
        end
        crt_model.fields << field_ 
      end

      # catch relations

      if /^\s*(?<rel_>embeds_many|embeds_one|has_many|has_one|belongs_to|embedded_in)\s+\:(?<name_>\w+)\s*(\,.*\:?as\:?\s*(?<as_>\w+))?/ =~ line
        field_ = Fields.new
        field_.name, field_.type = rel_, name_
        field_.name = "#{rel_} (as #{as_})" if as_
        self.parse_erd field_, line # parse erd attr and label

        crt_model.fields << field_ 
        #if %w[belongs_to embedded_in embeds_one has_one].include? rel_

        field_.edge = [name_, '', {label: rel_, arrowhead: 'onormal'}]
        #end

      end
      
      # common extension field

      if /^\s*symbolize\s+\:(?<name>\w+)\s*\,.*\:?in\:?.*(?<in_>\[.+\])/ =~ line
        field_ = Fields.new
        field_.name, field_.type = name_, "symbolized in #{in_}"
        self.parse_erd field_, line # parse erd attr and label

        crt_model.fields << field_ 
      end

      if /^\s*state_machine\s+\:(?<state_>\w+)/ =~ line
        field_ = Fields.new
        field_.name = state_ == "initial" ? "state" : state_
        field_.type = "state_machine"
        self.parse_erd field_, line # parse erd attr and label

        crt_model.fields << field_ 
      end

      if /\s*as_enum\s+\:(?<name_>\w+)\s*\,\s*(?<enum_>[^#]+)/ =~ line
        field_ = Fields.new
        field_.name = name_
        field_.type = "[ENUM] " + enum_ 
        self.parse_erd field_, line # parse erd attr and label

        crt_model.fields << field_ 
      end

    end # open and parse one file


    # assign attributes at the last moment

    crt_model.attrs.merge! model_attrs_

    # if config.include/tag, default to exclude_it = true

    if @config[:include].size > 0 or @config[:tag].size > 0
      include_it = false
    else
      include_it = true
    end

    # if in the include list, include it

    include_it = true if @config[:include] and @config[:include].include? crt_model.name
    @config[:tag].each do |t|
      include_it = true if t == crt_model.tag or /^#{t}(\..+)?/.match(crt_model.tag)
    end

    include_it = false if @config[:exclude].include? crt_model.name
    @models[crt_model.name] = crt_model if include_it
  end # open directory

  self
end

#parse_erd(o, line) ⇒ Object



65
66
67
68
69
70
71
72
# File 'lib/mongoid_erd.rb', line 65

def parse_erd o, line
  if /erd\{(?<yml_>.+?)\}:?/ =~ line
    o.attrs.merge! YAML.load(yml_) if yml_
  end
  if /erd(\{.+?\})?\s*:?\s+(?<label_>.+)/ =~ line
    o.erd_label = label_ if label_
  end
end

#set(key, value) ⇒ Object



57
58
59
# File 'lib/mongoid_erd.rb', line 57

def set key, value
  @config[key] = value
end