lib/cukedep/feature-model.rb in cukedep-0.0.1 vs lib/cukedep/feature-model.rb in cukedep-0.0.3
- old
+ new
@@ -14,11 +14,13 @@
# See also: Is this topological sort in Ruby flawed?
class FeatureModel
FeatureDependencies = Struct.new(:dependee, :dependents)
-
+# Helper class used internally by FeatureModel class.
+# Purpose: to try to create a valid dependency graph and perform a
+# topological sort of the nodes.
class DepGraph
include TSort # Mix-in module for topological sorting
attr_reader(:dependencies)
@@ -59,11 +61,11 @@
end
# Retrieve the feature file matching the given feature identifiers
# theIds one or more Strings, each being one feature identifier
def select_by_ids(*theIds)
- features_by_ids = id2features()
+ features_by_ids = id2features
selection = theIds.each_with_object([]) do |an_id, sub_result|
found_feature = features_by_ids[an_id]
if found_feature.nil?
fail(StandardError, "No feature file with identifier '#{an_id}'.")
end
@@ -80,11 +82,11 @@
# Build an array of FileDependencies objects.
def dependency_links()
if @dependencies.nil?
# Build the mapping: feature identifier => feature
- features_by_id = id2features()
+ features_by_id = id2features
# Resolve the dependency tags
resolve_dependencies(features_by_id)
end
@@ -92,13 +94,13 @@
end
# Sort the feature files by dependency order.
def sort_features_by_dep()
- dep_links = dependency_links()
+ dep_links = dependency_links
graph = DepGraph.new(dep_links)
- sorted_deps = graph.tsort()
+ sorted_deps = graph.tsort
all_sorted = sorted_deps.map(&:dependee)
@sorted_features = all_sorted.reject { |f| f.feature.anonymous? }
end
@@ -140,11 +142,11 @@
end
def emit_heading(anIO)
dir = File.dirname(File.absolute_path(feature_files[0].filepath))
- heading =<<-EOS
+ heading = <<-EOS
// Graph of dependencies of feature files in directory:
// '#{dir}'
// This file uses the DOT syntax, a free utility from the Graphviz toolset.
// Graphviz is available at: www.graphviz.org
// File generated on #{Time.now.asctime}.
@@ -164,39 +166,48 @@
def emit_body(anIO)
anIO.puts <<-EOS
subgraph island {
node [shape = box, style=filled, color=lightgray];
EOS
- feature_files.each_with_index { |ff, i| draw_node(anIO, ff, i) if ff.feature.anonymous? }
+ feature_files.each_with_index do |ff, i|
+ draw_node(anIO, ff, i) if ff.feature.anonymous?
+ end
anIO.puts <<-EOS
label = "Isolated features";
}
subgraph dependencies {
node [shape = box, fillcolor = none];
EOS
- feature_files.each_with_index { |ff, i| draw_node(anIO, ff, i) unless ff.feature.anonymous? }
+ feature_files.each_with_index do |ff, i|
+ draw_node(anIO, ff, i) unless ff.feature.anonymous?
+ end
anIO.puts <<-EOS
label = "Dependencies";
}
// The edges represent dependencies
EOS
- dependencies.each {|a_dep| draw_edge(anIO, a_dep) }
+ dependencies.each { |a_dep| draw_edge(anIO, a_dep) }
end
# Output the closing part of the graph drawing
def emit_trailing(anIO)
- anIO.puts "} // End of graph"
+ anIO.puts '} // End of graph'
end
# Draw a refinement node in DOT format
def draw_node(anIO, aFeatureFile, anIndex)
basename = File.basename(aFeatureFile.filepath, '.feature')
- identifier_suffix = aFeatureFile.feature.anonymous? ? '' : " -- #{aFeatureFile.feature.identifier}"
- anIO.puts %Q| node_#{anIndex} [label = "#{basename}#{identifier_suffix}"];|
+ its_feature = aFeatureFile.feature
+ if its_feature.anonymous?
+ id_suffix = ''
+ else
+ id_suffix = " -- #{its_feature.identifier}"
+ end
+ anIO.puts %Q| node_#{anIndex} [label = "#{basename}#{id_suffix}"];|
end
# Draw an edge between feature files having dependencies.
def draw_edge(anIO, aDependency)
source_id = feature_files.find_index(aDependency.dependee)
@@ -210,22 +221,22 @@
end
def generate_rake_tasks(rakefile, theProjDir)
puts " #{rakefile}"
- template_filepath = Pathname.new(File.dirname(__FILE__)).parent.parent + './templates/rake.erb'
- template_source = File.read(template_filepath)
+ grandparent_path = Pathname.new(File.dirname(__FILE__)).parent.parent
+ template_source = File.read(grandparent_path + './templates/rake.erb')
# Create one template engine instance
engine = ERB.new(template_source)
- source_dir = File.absolute_path(Dir.getwd())
+ source_dir = File.absolute_path(Dir.getwd)
proj_dir = File.absolute_path(theProjDir)
- anonymous = anonymous_features.map {|ff| ff.basename}
+ anonymous = anonymous_features.map { |ff| ff.basename }
feature_ids = feature_files.map { |ff| ff.feature.identifier }
feature_ids.compact!
- deps = dependencies.reject {|dep| dep.dependee.feature.anonymous?}
+ deps = dependencies.reject { |dep| dep.dependee.feature.anonymous? }
# Generate the text representation with given context
file_source = engine.result(binding)
File.open(rakefile, 'w') { |f| f.write(file_source) }
end
@@ -264,11 +275,12 @@
end
# Complain when dependency tag refers to an unknown feature
dependents = dep_tags.map do |a_tag|
unless aMapping.include?(a_tag)
- msg = "Feature with identifier '#{its_id}' depends on unknown feature '#{a_tag}'"
- fail(StandardError, msg)
+ msg_p1 = "Feature with identifier '#{its_id}'"
+ msg_p2 = " depends on unknown feature '#{a_tag}'"
+ fail(StandardError, msg_p1 = msg_p2)
end
aMapping[a_tag]
end
@dependencies << FeatureDependencies.new(feature_file, dependents)