lib/diagrams/dot.rb in diagrams-rb-0.0.3 vs lib/diagrams/dot.rb in diagrams-rb-0.1.0

- old
+ new

@@ -2,139 +2,109 @@ require 'open3' require 'tempfile' module Diagrams - class Dot # rubocop:disable Metrics/ClassLength - DEFAULTS = { + class Dot + GRAPH_DEFAULTS = { + pad: '2.0', + splines: 'ortho', + nodesep: '0.60', + ranksep: '0.75', + rankdir: 'TB', + fontname: '"Sans-Serif"', + fontsize: '15', + fontcolor: '"#2D3436"' + }.freeze - GRAPH: { - pad: '2.0', - splines: 'ortho', - nodesep: '0.60', - ranksep: '0.75', - rankdir: 'TB', - fontname: '"Sans-Serif"', - fontsize: '15', - fontcolor: '"#2D3436"' - }, + NODE_DEFAULTS = { + shape: 'box', + style: 'rounded', + fixedsize: 'true', + width: '1.4', + height: '1.4', + labelloc: 'b', + imagescale: 'true', + penwidth: '0', + fontname: '"Sans-Serif"', + fontsize: '13', + fontcolor: '"#2D3436"' + }.freeze - NODE: { - shape: 'box', - style: 'rounded', - fixedsize: 'true', - width: '1.4', - height: '1.4', - labelloc: 'b', - imagescale: 'true', - penwidth: '0', - fontname: '"Sans-Serif"', - fontsize: '13', - fontcolor: '"#2D3436"' - }, + CLUSTER_DEFAULTS = { + shape: 'box', + style: 'rounded', + labeljust: 'l', + pencolor: '"#AEB6BE"' + }.freeze - CLUSTER: { - shape: 'box', - style: 'rounded', - labeljust: 'l', - pencolor: '"#AEB6BE"' - }, + CLUSTER_BGCOLORS = %w[#E5F5FD #EBF3E7 #ECE8F6 #FDF7E3].freeze - CLUSTER_BGCOLORS: %w[#E5F5FD #EBF3E7 #ECE8F6 #FDF7E3], - - EDGE: { - color: '"#7B8894"', - fontcolor: '"#2D3436"', - fontname: '"Sans-Serif"', - fontsize: '13' - }, - - PADDING: 0.45 - + EDGE_DEFAULTS = { + color: '"#7B8894"', + fontcolor: '"#2D3436"', + fontname: '"Sans-Serif"', + fontsize: '13' }.freeze - attr_accessor :format, :space, :bg_color_len + attr_accessor :dot_output, :format, :space, :clen def initialize(**attrs) + @dot_output = "digraph G {\n".dup @format = attrs.delete(:format) || 'png' - @test = attrs.delete(:test) + GRAPH_DEFAULTS.merge(attrs).each do |key, value| + @dot_output << " #{key}=#{value};\n" + end @space = ' ' - @bg_color_len = DEFAULTS[:CLUSTER_BGCOLORS].length + @clen = CLUSTER_BGCOLORS.length @depth = 0 @cluster_idx = -1 - write_digraph_default(attrs) end + def indent + space * @depth + end + def add_node(id, label: '', icon: nil, **attrs) - attributes = DEFAULTS[:NODE].merge(attrs.merge(height: node_height(label))).map { |k, v| "#{k}=#{v}" }.join(',') + attributes = NODE_DEFAULTS.merge(attrs).map { |k, v| "#{k}=#{v}" }.join(',') dot_output << "#{indent} #{id} [label=\"#{label}\", image=\"#{icon}\", #{attributes}];\n" end def add_edge(from, to:, **attrs) - attributes = DEFAULTS[:EDGE].merge(attrs).map { |k, v| "#{k}=#{v}" }.join(',') + attributes = EDGE_DEFAULTS.merge(attrs).map { |k, v| "#{k}=#{v}" }.join(',') dot_output << " #{from} -> #{to} [#{attributes}];\n" end def begin_cluster(label, **attrs) # rubocop:disable Metrics/AbcSize cluster_label = label.empty? ? "cluster_#{@cluster_idx += 1}" : label dot_output << "#{indent}subgraph cluster_#{identifier(cluster_label)} {\n" dot_output << "#{indent} label=\"#{label}\";\n" - dot_output << "#{indent} bgcolor=\"#{DEFAULTS[:CLUSTER_BGCOLORS][@depth % bg_color_len]}\";\n" - DEFAULTS[:CLUSTER].merge(attrs).each do |key, value| - dot_output << "#{indent} #{key}=#{value};\n" + dot_output << "#{indent} bgcolor=\"#{CLUSTER_BGCOLORS[@depth % clen]}\";\n" + CLUSTER_DEFAULTS.merge(attrs).each do |key, value| + dot_output << "#{indent} #{key}=#{value};\n" end @depth += 1 - @dot_output end def end_cluster dot_output << "#{indent}}\n" @depth -= 1 end - def generate_image - dot_output << "}\n" - return dot_output if @test - - write_output - end - - private - - def dot_output - @dot_output ||= "digraph G {\n".dup - end - - def write_digraph_default(attrs) - DEFAULTS[:GRAPH].merge(attrs).each do |key, value| - dot_output << " #{key}=#{value};\n" - end - end - - def indent - space * @depth - end - - def node_height(label) - (DEFAULTS[:NODE][:height].to_f + (DEFAULTS[:PADDING] * label.split("\\n").size)).round(1).to_s - end - def identifier(string) string.gsub(/\s+/, '_') end - def write_output + def generate_image + output_path = caller_locations.last.path.gsub('.rb', ".#{format}") + dot_output << "}\n" Tempfile.open('temp.dot') do |file| File.write(file.path, dot_output) cmd = "dot -T#{format} #{file.path} -o #{output_path}" _, stderr, status = Open3.capture3(cmd) puts stderr unless status.success? end - end - - def output_path - caller_locations.last.path.gsub('.rb', ".#{format}") end end end