From 47cc6a9d10dbdbc669bb75607f93f90c5f830721 Mon Sep 17 00:00:00 2001 From: Urban Rotnik Date: Mon, 7 Jan 2019 15:55:45 +0100 Subject: [PATCH] Refactor workflow_image_generation and move to service class --- app/models/experiment.rb | 117 +----------------- app/services/executable_service.rb | 7 ++ app/services/workflow_image_generator.rb | 89 +++++++++++++ .../services/workflow_image_generator_spec.rb | 6 + 4 files changed, 103 insertions(+), 116 deletions(-) create mode 100644 app/services/executable_service.rb create mode 100644 app/services/workflow_image_generator.rb create mode 100644 spec/services/workflow_image_generator_spec.rb diff --git a/app/models/experiment.rb b/app/models/experiment.rb index f271a72f3..86c9e6895 100644 --- a/app/models/experiment.rb +++ b/app/models/experiment.rb @@ -221,123 +221,8 @@ class Experiment < ApplicationRecord true end - # This method generate the workflow image and saves it as - # experiment attachment def generate_workflow_img - require 'graphviz' - - graph = GraphViz.new(:G, - type: :digraph, - use: :neato) - - graph[:size] = '4,4' - graph.node[color: Constants::COLOR_ALTO, - style: :filled, - fontcolor: Constants::COLOR_EMPEROR, - shape: 'circle', - fontname: 'Arial', - fontsize: '16.0'] - - graph.edge[color: Constants::COLOR_ALTO] - - label = '' - subg = {} - - # Draw orphan modules - my_modules.without_group.each do |my_module| - graph - .subgraph(rank: 'same') - .add_nodes("Orphan-#{my_module.id}", - label: label, - pos: "#{my_module.x / 10},-#{my_module.y / 10}!") - end - - # Draw grouped modules - if my_module_groups.many? - my_module_groups.each_with_index do |group, gindex| - subgraph_name = "cluster-#{gindex}" - subg[subgraph_name] = graph.subgraph(rank: 'same') - group.ordered_modules.each_with_index do |my_module, index| - if my_module.outputs.any? - parent = subg[subgraph_name] - .add_nodes("#{subgraph_name}-#{index}", - label: label, - pos: "#{my_module.x / 10},-#{my_module.y / 10}!") - - my_module.outputs.each_with_index do |output, i| - child_mod = MyModule.find_by_id(output.input_id) - child_node = subg[subgraph_name] - .add_nodes("#{subgraph_name}-O#{child_mod.id}-#{i}", - label: label, - pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!") - - subg[subgraph_name].add_edges(parent, child_node) - end - elsif my_module.inputs.any? - parent = subg[subgraph_name] - .add_nodes("#{subgraph_name}-#{index}", - label: label, - pos: "#{my_module.x / 10},-#{my_module.y / 10}!") - - my_module.inputs.each_with_index do |input, i| - child_mod = MyModule.find_by_id(input.output_id) - child_node = subg[subgraph_name] - .add_nodes("#{subgraph_name}-I#{child_mod.id}-#{i}", - label: label, - pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!") - - subg[subgraph_name].add_edges(child_node, parent) - end - end - end - end - else - my_module_groups.each do |group| - group.ordered_modules.each_with_index do |my_module, index| - if my_module.outputs.any? - parent = graph.add_nodes("N-#{index}", - label: label, - pos: "#{my_module.x / 10},-#{ my_module.y / 10}!") - - my_module.outputs.each_with_index do |output, i| - child_mod = MyModule.find_by_id(output.input_id) - child_node = graph - .add_nodes("N-O#{child_mod.id}-#{i}", - label: label, - pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!") - graph.add_edges(parent, child_node) - end - elsif my_module.inputs.any? - parent = graph.add_nodes("N-#{index}", - label: label, - pos: "#{my_module.x / 10},-#{my_module.y / 10}!") - my_module.inputs.each_with_index do |input, i| - child_mod = MyModule.find_by_id(input.output_id) - child_node = graph - .add_nodes("N-I#{child_mod.id}-#{i}", - label: label, - pos: "#{child_mod.x / 10},-#{child_mod.y / 10}!") - graph.add_edges(child_node, parent) - end - end - end - end - end - - file_location = Tempfile.open(['wimg', '.png'], - Rails.root.join('tmp')) - - graph.output(png: file_location.path) - - begin - file = File.open(file_location) - self.workflowimg = file - file.close - save - touch(:workflowimg_updated_at) - rescue => ex - logger.error ex.message - end + WorkflowImageGenerator.execute(experiment_id: id) end # Clone this experiment to given project diff --git a/app/services/executable_service.rb b/app/services/executable_service.rb new file mode 100644 index 000000000..5512f8845 --- /dev/null +++ b/app/services/executable_service.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module ExecutableService + def execute(*args) + new(*args).execute + end +end diff --git a/app/services/workflow_image_generator.rb b/app/services/workflow_image_generator.rb new file mode 100644 index 000000000..61fdf8cd6 --- /dev/null +++ b/app/services/workflow_image_generator.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +class WorkflowImageGenerator + extend ExecutableService + require 'graphviz' + + attr_reader :errors + + def initialize(experiment_id:) + @exp = Experiment.find experiment_id + @graph = GraphViz.new(:G, type: :digraph, use: :neato) + + @graph[:size] = '4,4' + @graph.node[color: Constants::COLOR_ALTO, + style: :filled, + fontcolor: Constants::COLOR_EMPEROR, + shape: 'circle', + fontname: 'Arial', + fontsize: '16.0'] + + @graph.edge[color: Constants::COLOR_ALTO] + @errors = [] + end + + def execute + draw_diagram + save_file + self + end + + def succeed? + @errors.none? + end + + private + + def draw_diagram + # Draw orphan nodes + @exp.my_modules.without_group.each do |my_module| + @graph.subgraph(rank: 'same').add_nodes( + "Orphan-#{my_module.id}", + label: '', + pos: "#{my_module.x / 10},-#{my_module.y / 10}!" + ) + end + + # Draw grouped modules + subg = {} + @exp.my_module_groups.each_with_index do |group, gindex| + subgraph_id = "cluster-#{gindex}" + subg[subgraph_id] = @graph.subgraph(rank: 'same') + nodes = {} + + group.my_modules.workflow_ordered.each_with_index do |my_module, index| + # draw nodes + node = subg[subgraph_id].add_nodes( + "#{subgraph_id}-#{index}", + label: '', + pos: "#{my_module.x / 10},-#{my_module.y / 10}!" + ) + nodes[my_module.id] = node + end + + # draw edges + group.my_modules.workflow_ordered.each do |m| + m.outputs.each do |output| + parent_node = nodes[m.id] + child_node = nodes[output.input_id] + subg[subgraph_id].add_edges(parent_node, child_node) + end + end + end + end + + def save_file + t_file = Tempfile.open(%w(wimg .png), Rails.root.join('tmp')) + @graph.output(png: t_file.path) + + begin + file = File.open(t_file) + @exp.workflowimg = file + file.close + @exp.save + @exp.touch(:workflowimg_updated_at) + rescue StandardError => ex + logger.error ex.message + end + end +end diff --git a/spec/services/workflow_image_generator_spec.rb b/spec/services/workflow_image_generator_spec.rb new file mode 100644 index 000000000..654fdc1fb --- /dev/null +++ b/spec/services/workflow_image_generator_spec.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe WorkflowImageGenerator do +end