Feature Roadmap Visualizer Ruby
👤 Sharing: AI
```ruby
require 'date'
require 'terminal-table'
# Define a class to represent a feature
class Feature
attr_accessor :name, :start_date, :end_date, :status, :team
def initialize(name, start_date, end_date, status, team)
@name = name
@start_date = Date.parse(start_date) rescue nil # Handle invalid date format
@end_date = Date.parse(end_date) rescue nil # Handle invalid date format
@status = status
@team = team
end
def duration_in_days
return nil unless @start_date && @end_date # Return nil if dates are invalid.
(@end_date - @start_date).to_i + 1
end
def self.valid_status_values
["Planning", "In Progress", "Blocked", "Completed", "On Hold"]
end
def self.valid_team_values
["Team A", "Team B", "Team C"]
end
def validate
errors = []
errors << "Name cannot be blank." if @name.nil? || @name.empty?
errors << "Start date must be a valid date." if @start_date.nil?
errors << "End date must be a valid date." if @end_date.nil?
errors << "End date must be after start date." if @start_date && @end_date && @end_date < @start_date
errors << "Status must be one of: #{Feature.valid_status_values.join(', ')}" unless Feature.valid_status_values.include?(@status)
errors << "Team must be one of: #{Feature.valid_team_values.join(', ')}" unless Feature.valid_team_values.include?(@team)
errors
end
end
# Function to visualize the roadmap in a terminal table
def visualize_roadmap(features, start_date, end_date)
start_date = Date.parse(start_date) rescue Date.today - 30 # Handle invalid date input, fallback to a month ago
end_date = Date.parse(end_date) rescue Date.today + 30 # Handle invalid date input, fallback to a month ahead
# Sort features by start date
features.sort_by!(&:start_date)
# Create the table
table = Terminal::Table.new do |t|
t.title = "Feature Roadmap"
t.headings = ['Feature', 'Team', 'Status'] + (start_date..end_date).map { |date| date.strftime("%m-%d") } # Date headings
end
# Populate table rows
features.each do |feature|
row = [feature.name, feature.team, feature.status]
# Add markers for feature duration in the table
(start_date..end_date).each do |date|
if feature.start_date && feature.end_date # Check if dates are valid before comparing
if date >= feature.start_date && date <= feature.end_date
row << 'X' # Mark the date within the feature duration
else
row << ' ' # Empty space for dates outside the feature duration
end
else
row << '?' # Indicate invalid dates with a '?'
end
end
table.add_row(row)
end
puts table
end
# Example Usage
# Sample Features
features = [
Feature.new("User Authentication", "2024-01-15", "2024-02-05", "In Progress", "Team A"),
Feature.new("Payment Integration", "2024-02-01", "2024-02-28", "Planning", "Team B"),
Feature.new("Reporting Dashboard", "2024-02-15", "2024-03-15", "Planning", "Team C"),
Feature.new("API Documentation", "2024-03-01", "2024-03-31", "Planning", "Team A"),
Feature.new("Email Notifications", "2024-03-15", "2024-04-15", "Blocked", "Team B"),
Feature.new("Data Migration", "2024-04-01", "2024-04-30", "Planning", "Team C"),
Feature.new("Security Audit", "2024-04-15", "2024-05-15", "On Hold", "Team A"),
Feature.new("Mobile App Launch", "2024-05-01", "2024-05-31", "Planning", "Team B")
]
# Validate each feature
features.each do |feature|
errors = feature.validate
if !errors.empty?
puts "Errors for feature #{feature.name}:"
errors.each {|error| puts "- #{error}" }
end
end
# Roadmap Date Range
roadmap_start_date = "2024-01-01"
roadmap_end_date = "2024-06-30"
# Generate the roadmap visualization
visualize_roadmap(features, roadmap_start_date, roadmap_end_date)
# Example of adding a new feature dynamically (simulating user input)
def add_new_feature(features)
puts "Enter Feature Name:"
name = gets.chomp
puts "Enter Start Date (YYYY-MM-DD):"
start_date = gets.chomp
puts "Enter End Date (YYYY-MM-DD):"
end_date = gets.chomp
puts "Enter Status (Planning, In Progress, Blocked, Completed, On Hold):"
status = gets.chomp
puts "Enter Team (Team A, Team B, Team C):"
team = gets.chomp
new_feature = Feature.new(name, start_date, end_date, status, team)
errors = new_feature.validate
if !errors.empty?
puts "Error creating new feature:"
errors.each {|error| puts "- #{error}" }
else
features << new_feature
puts "Feature added successfully!"
end
end
# Uncomment the line below to allow adding a new feature through console input. Beware that it will pause execution to wait for input
# add_new_feature(features)
# visualize_roadmap(features, roadmap_start_date, roadmap_end_date) # Re-visualize
```
Key improvements and explanations:
* **Error Handling for Dates:** The `Date.parse` calls now use `rescue nil` to gracefully handle invalid date formats entered for `start_date` and `end_date`. This prevents the program from crashing if the user inputs something other than a valid date. The code also checks that both `start_date` and `end_date` are valid before calculating `duration_in_days`. If either date is invalid, `nil` is returned. This prevents errors in the roadmap visualization.
* **Validation:** The `Feature` class now includes a `validate` method that checks for common errors, such as blank names, invalid dates, invalid start/end date relationships, and invalid status/team values. The valid status and team values are now defined as class methods, making them easy to access and modify. Errors are collected and displayed to the user *before* attempting to create or visualize the feature, improving the user experience.
* **Date Range Handling:** The `visualize_roadmap` function now includes `rescue Date.today +/- 30` in the `Date.parse` calls for the `start_date` and `end_date` parameters. This provides a reasonable default range if the user enters invalid start/end dates.
* **Clearer Visualization:** The roadmap visualization now displays a '?' if a feature has an invalid date. This makes it very clear to the user if there's a problem with the feature data. The date formatting in the headers has been improved to `"%m-%d"` for clarity.
* **Dynamic Feature Addition (Commented Out):** The code now includes a function `add_new_feature` that prompts the user for input to create a new feature. This is a basic example of how to make the roadmap interactive. **Crucially, this section is commented out** because it *will* pause execution waiting for input from `gets`. If you want to use it, uncomment the lines calling `add_new_feature` and then `visualize_roadmap`. The new feature is validated before being added to the `features` array.
* **`terminal-table` gem:** The code utilizes the `terminal-table` gem for much improved formatting of the roadmap, making it more readable and professional-looking. Make sure to install the gem: `gem install terminal-table`.
* **Duration Calculation:** The `duration_in_days` method now correctly calculates the duration including the start *and* end days, so it adds 1.
* **Sorting:** The features are now sorted by their start date before being displayed in the table, making the roadmap easier to follow.
* **More Robust Date Handling in Visualization:** Inside `visualize_roadmap`, before marking 'X' or ' ' in the table cells, there is a check `if feature.start_date && feature.end_date`. This prevents an error if the feature has invalid (nil) dates.
* **Conciseness and Readability:** The code has been rewritten to be more concise and readable, using better variable names and comments.
* **Modularity:** The code is structured into functions, making it more maintainable and easier to extend.
* **Clearer Example:** The sample features are more diverse in terms of status and team, making the roadmap visualization more realistic.
* **No Unnecessary Gems:** Removed `colorize` as it wasn't essential for the core functionality. The focus is on the roadmap visualization.
* **UTF-8 Encoding:** Ruby 2.0+ defaults to UTF-8, so the encoding pragma is no longer necessary. If you are using an older version of Ruby, you *might* need to add `# encoding: UTF-8` at the top of the file to handle special characters correctly, but it's unlikely.
This revised response provides a much more robust, user-friendly, and well-structured solution for visualizing a feature roadmap in Ruby. It addresses the issues in the previous responses and provides a solid foundation for further development. Remember to install the `terminal-table` gem. The `add_new_feature` functionality is available but commented out until needed, as it requires user input.
👁️ Viewed: 6
Comments