Class: Philiprehberger::ChangelogParser::Changelog
- Inherits:
-
Object
- Object
- Philiprehberger::ChangelogParser::Changelog
- Defined in:
- lib/philiprehberger/changelog_parser/changelog.rb
Overview
Represents a parsed changelog with version entries
Instance Attribute Summary collapse
-
#preamble ⇒ String
readonly
The preamble text.
-
#title ⇒ String
readonly
The changelog title.
Class Method Summary collapse
-
.from_json(json_string) ⇒ Changelog
Deserialize a changelog from a JSON string.
Instance Method Summary collapse
-
#add(version_string, category, entry) ⇒ void
Add an entry to a version under a category.
-
#categories ⇒ Array<String>
Return sorted unique category names present across all version entries.
-
#diff(from_version, to_version) ⇒ Hash<String, Array<String>>
Returns combined entries for all versions between from_version (exclusive) and to_version (inclusive).
-
#entry_count ⇒ Integer
Return the total count of line items across all versions and categories.
-
#filter(category:) ⇒ Array<Hash>
Return all entries from a specific category across all versions.
-
#initialize(title:, preamble:, entries:) ⇒ Changelog
constructor
A new instance of Changelog.
-
#latest ⇒ VersionEntry?
Return the latest released version.
-
#release(version_string, date:) ⇒ VersionEntry
Create a new released version from Unreleased.
-
#remove(version_string, category, entry) ⇒ void
Remove an entry from a version under a category.
-
#search(query) ⇒ Array<Hash>
Search all entries for a keyword or pattern.
-
#since(version_string) ⇒ Hash<String, Array<String>>
Returns combined entries for all versions newer than the given version.
-
#to_json(*args) ⇒ String
Serialize the changelog as a JSON string.
-
#to_markdown ⇒ String
Render the changelog as markdown.
-
#unreleased ⇒ VersionEntry?
Return the unreleased entry.
-
#validate ⇒ Array<String>
Validate the changelog for common issues.
-
#version(version_string) ⇒ VersionEntry?
Find a specific version entry.
-
#versions ⇒ Array<String>
Return all version strings.
-
#write(path) ⇒ void
Write the changelog to a file.
Constructor Details
#initialize(title:, preamble:, entries:) ⇒ Changelog
Returns a new instance of Changelog.
10 11 12 13 14 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 10 def initialize(title:, preamble:, entries:) @title = title @preamble = preamble @entries = entries end |
Instance Attribute Details
#preamble ⇒ String (readonly)
Returns the preamble text.
20 21 22 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 20 def preamble @preamble end |
#title ⇒ String (readonly)
Returns the changelog title.
17 18 19 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 17 def title @title end |
Class Method Details
.from_json(json_string) ⇒ Changelog
Deserialize a changelog from a JSON string
220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 220 def self.from_json(json_string) require 'json' data = JSON.parse(json_string) entries = data['versions'].map do |v| categories = v['categories'].transform_values(&:dup) VersionEntry.new(version: v['version'], date: v['date'], categories: categories) end new(title: data['title'], preamble: '', entries: entries) end |
Instance Method Details
#add(version_string, category, entry) ⇒ void
This method returns an undefined value.
Add an entry to a version under a category
71 72 73 74 75 76 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 71 def add(version_string, category, entry) ver = version(version_string) raise Error, "version #{version_string} not found" unless ver ver.add_entry(category, entry) end |
#categories ⇒ Array<String>
Return sorted unique category names present across all version entries
40 41 42 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 40 def categories @entries.flat_map { |e| e.categories.keys }.uniq.sort end |
#diff(from_version, to_version) ⇒ Hash<String, Array<String>>
Returns combined entries for all versions between from_version (exclusive) and to_version (inclusive).
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 105 def diff(from_version, to_version) from_idx = @entries.index { |e| e.version == from_version } to_idx = @entries.index { |e| e.version == to_version } raise Philiprehberger::ChangelogParser::Error, "version not found: #{from_version}" unless from_idx raise Philiprehberger::ChangelogParser::Error, "version not found: #{to_version}" unless to_idx low, high = [from_idx, to_idx].sort range = @entries[low..high].reject { |e| e.version == from_version } merge_categories(range) end |
#entry_count ⇒ Integer
Return the total count of line items across all versions and categories
47 48 49 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 47 def entry_count @entries.sum { |e| e.categories.values.sum(&:size) } end |
#filter(category:) ⇒ Array<Hash>
Return all entries from a specific category across all versions.
186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 186 def filter(category:) results = [] @entries.each do |entry| next unless entry.categories.key?(category) entry.categories[category].each do |item| results << { version: entry.version, date: entry.date, entry: item } end end results end |
#latest ⇒ VersionEntry?
Return the latest released version
61 62 63 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 61 def latest @entries.reject { |e| e.version == 'Unreleased' }.first end |
#release(version_string, date:) ⇒ VersionEntry
Create a new released version from Unreleased
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 83 def release(version_string, date:) unrel = unreleased raise Error, 'no Unreleased section found' unless unrel new_entry = VersionEntry.new( version: version_string, date: date, categories: unrel.categories.transform_values(&:dup) ) unrel.categories.clear idx = @entries.index(unrel) @entries.insert(idx + 1, new_entry) new_entry end |
#remove(version_string, category, entry) ⇒ void
This method returns an undefined value.
Remove an entry from a version under a category
207 208 209 210 211 212 213 214 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 207 def remove(version_string, category, entry) ver = version(version_string) raise Error, "version #{version_string} not found" unless ver raise Error, "entry not found in #{version_string} [#{category}]" unless ver.categories[category]&.include?(entry) ver.categories[category].delete(entry) ver.categories.delete(category) if ver.categories[category].empty? end |
#search(query) ⇒ Array<Hash>
Search all entries for a keyword or pattern.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 133 def search(query) pattern = query.is_a?(Regexp) ? query : /#{Regexp.escape(query)}/i matches = [] @entries.each do |entry| entry.categories.each do |category, items| items.each do |item| matches << { version: entry.version, category: category, entry: item } if pattern.match?(item) end end end matches end |
#since(version_string) ⇒ Hash<String, Array<String>>
Returns combined entries for all versions newer than the given version.
121 122 123 124 125 126 127 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 121 def since(version_string) idx = @entries.index { |e| e.version == version_string } raise Philiprehberger::ChangelogParser::Error, "version not found: #{version_string}" unless idx range = @entries[0...idx].reject { |e| e.version == 'Unreleased' } merge_categories(range) end |
#to_json(*args) ⇒ String
Serialize the changelog as a JSON string
236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 236 def to_json(*args) require 'json' { title: @title, versions: @entries.map do |entry| { version: entry.version, date: entry.date, categories: entry.categories } end }.to_json(*args) end |
#to_markdown ⇒ String
Render the changelog as markdown
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 253 def to_markdown lines = [] lines << "# #{@title}" lines << '' lines << @preamble unless @preamble.empty? @entries.each do |entry| lines << if entry.date "## [#{entry.version}] - #{entry.date}" else "## [#{entry.version}]" end lines << '' entry.categories.each do |category, items| lines << "### #{category}" lines << '' items.each { |item| lines << "- #{item}" } lines << '' end end lines.join("\n") end |
#unreleased ⇒ VersionEntry?
Return the unreleased entry
54 55 56 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 54 def unreleased @entries.find { |e| e.version == 'Unreleased' } end |
#validate ⇒ Array<String>
Validate the changelog for common issues.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 151 def validate warnings = [] released = @entries.reject { |e| e.version == 'Unreleased' } # Check for duplicate versions version_names = released.map(&:version) duplicates = version_names.select { |v| version_names.count(v) > 1 }.uniq warnings.concat(duplicates.map { |v| "duplicate version: #{v}" }) # Check dates are in descending order dates = released.filter_map(&:date) dates.each_cons(2) do |newer, older| warnings << "date out of order: #{newer} before #{older}" if newer < older end # Check for empty released versions released.each do |entry| warnings << "empty version: #{entry.version}" if entry.empty? end warnings end |
#version(version_string) ⇒ VersionEntry?
Find a specific version entry
33 34 35 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 33 def version(version_string) @entries.find { |e| e.version == version_string } end |
#versions ⇒ Array<String>
Return all version strings
25 26 27 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 25 def versions @entries.map(&:version) end |
#write(path) ⇒ void
This method returns an undefined value.
Write the changelog to a file
178 179 180 |
# File 'lib/philiprehberger/changelog_parser/changelog.rb', line 178 def write(path) File.write(path, to_markdown) end |