Class: Kabosu::DictManager
- Inherits:
-
Object
- Object
- Kabosu::DictManager
- Defined in:
- lib/kabosu/dict_manager.rb
Defined Under Namespace
Classes: DictNotFound, DownloadError
Constant Summary collapse
- EDITIONS =
%w[small core full].freeze
- EDITION_PRIORITY =
%w[full core small].freeze
- GITHUB_REPO =
"WorksApplications/SudachiDict"- GITHUB_API =
"https://api.github.com"
Instance Attribute Summary collapse
-
#dir ⇒ Object
readonly
Returns the value of attribute dir.
Class Method Summary collapse
-
.default_dir ⇒ Object
Default storage directory.
Instance Method Summary collapse
-
#available_versions ⇒ Object
List available versions from GitHub releases.
-
#find(edition: nil) ⇒ Object
Find the best available dictionary path.
-
#initialize(dir: self.class.default_dir) ⇒ DictManager
constructor
A new instance of DictManager.
-
#install(edition = "core", version: nil) ⇒ Object
Download and extract a dictionary edition.
-
#install_if_missing(edition = "core", version: nil) ⇒ Object
Idempotent install.
-
#installed ⇒ Object
List all installed dictionaries.
-
#latest_version ⇒ Object
Fetch the latest release tag from GitHub.
-
#remove(edition: nil, version: nil) ⇒ Object
Remove a specific dictionary edition, or an entire version.
Constructor Details
#initialize(dir: self.class.default_dir) ⇒ DictManager
Returns a new instance of DictManager.
24 25 26 |
# File 'lib/kabosu/dict_manager.rb', line 24 def initialize(dir: self.class.default_dir) @dir = dir end |
Instance Attribute Details
#dir ⇒ Object (readonly)
Returns the value of attribute dir.
28 29 30 |
# File 'lib/kabosu/dict_manager.rb', line 28 def dir @dir end |
Class Method Details
.default_dir ⇒ Object
Default storage directory. Honors KABOSU_DICT_DIR so consumers can point the gem at a Docker volume / shared mount without subclassing or threading ‘dir:` through every call site. Falls back to ~/.kabosu/dict/.
20 21 22 |
# File 'lib/kabosu/dict_manager.rb', line 20 def self.default_dir ENV["KABOSU_DICT_DIR"] || File.join(Dir.home, ".kabosu", "dict") end |
Instance Method Details
#available_versions ⇒ Object
List available versions from GitHub releases.
168 169 170 171 172 |
# File 'lib/kabosu/dict_manager.rb', line 168 def available_versions uri = URI("#{GITHUB_API}/repos/#{GITHUB_REPO}/releases") response = http_get(uri, headers: { "Accept" => "application/json" }) JSON.parse(response.body).map { |r| r["tag_name"].sub(/\Av/, "") } end |
#find(edition: nil) ⇒ Object
Find the best available dictionary path. Prefers: latest version, then full > core > small.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/kabosu/dict_manager.rb', line 108 def find(edition: nil) candidates = installed raise DictNotFound, "No dictionaries installed. Run: rake kabosu:install" if candidates.empty? if edition edition = validate_edition(edition) match = candidates.find { |d| d[:edition] == edition } raise DictNotFound, "No #{edition} dictionary installed" unless match return match[:path] end # Group by version (already sorted newest-first), pick best edition by_version = candidates.group_by { |d| d[:version] } latest_version_dicts = by_version.values.first best = EDITION_PRIORITY.each do |ed| found = latest_version_dicts.find { |d| d[:edition] == ed } break found if found end best.is_a?(Hash) ? best[:path] : latest_version_dicts.first[:path] end |
#install(edition = "core", version: nil) ⇒ Object
Download and extract a dictionary edition.
manager.install("small")
manager.install("core", version: "20260116")
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/kabosu/dict_manager.rb', line 37 def install(edition = "core", version: nil) edition = validate_edition(edition) version ||= latest_version dest_dir = File.join(@dir, "sudachi-dictionary-#{version}") dic_path = File.join(dest_dir, "system_#{edition}.dic") if File.exist?(dic_path) $stderr.puts "Already installed: #{dic_path}" return dic_path end url = release_asset_url(version, edition) zip_path = File.join(@dir, "sudachi-dictionary-#{version}-#{edition}.zip") FileUtils.mkdir_p(@dir) download(url, zip_path) extract(zip_path, @dir) FileUtils.rm_f(zip_path) unless File.exist?(dic_path) raise DownloadError, "Expected #{dic_path} after extraction, but file not found" end $stderr.puts "Installed: #{dic_path}" dic_path end |
#install_if_missing(edition = "core", version: nil) ⇒ Object
Idempotent install. Returns the existing dictionary path if a matching one is already on disk; otherwise downloads and extracts. Useful for entrypoint scripts and CI hooks that should converge on the desired state without paying the network cost on every run.
manager.install_if_missing("core")
manager.install_if_missing("core", version: "20260116")
73 74 75 76 77 78 79 80 81 |
# File 'lib/kabosu/dict_manager.rb', line 73 def install_if_missing(edition = "core", version: nil) edition = validate_edition(edition) matching = installed.find do |d| d[:edition] == edition && (version.nil? || d[:version] == version) end return matching[:path] if matching install(edition, version: version) end |
#installed ⇒ Object
List all installed dictionaries. Returns an array of hashes: { version:, edition:, path: }
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/kabosu/dict_manager.rb', line 87 def installed results = [] return results unless Dir.exist?(@dir) Dir.glob(File.join(@dir, "sudachi-dictionary-*")).sort.reverse.each do |version_dir| next unless File.directory?(version_dir) version = File.basename(version_dir).sub("sudachi-dictionary-", "") EDITIONS.each do |edition| dic = File.join(version_dir, "system_#{edition}.dic") next unless File.exist?(dic) results << { version: version, edition: edition, path: dic } end end results end |
#latest_version ⇒ Object
Fetch the latest release tag from GitHub.
158 159 160 161 162 163 164 165 |
# File 'lib/kabosu/dict_manager.rb', line 158 def latest_version uri = URI("#{GITHUB_API}/repos/#{GITHUB_REPO}/releases/latest") response = http_get(uri, headers: { "Accept" => "application/json" }) data = JSON.parse(response.body) tag = data["tag_name"] # Tags are like "v20260116" — strip the "v" prefix tag.sub(/\Av/, "") end |
#remove(edition: nil, version: nil) ⇒ Object
Remove a specific dictionary edition, or an entire version.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/kabosu/dict_manager.rb', line 134 def remove(edition: nil, version: nil) targets = installed targets = targets.select { |d| d[:version] == version } if version targets = targets.select { |d| d[:edition] == edition } if edition raise DictNotFound, "No matching dictionary found" if targets.empty? targets.each do |d| FileUtils.rm_f(d[:path]) $stderr.puts "Removed: #{d[:path]}" # Clean up empty version directories version_dir = File.dirname(d[:path]) dics_remaining = Dir.glob(File.join(version_dir, "system_*.dic")) if dics_remaining.empty? FileUtils.rm_rf(version_dir) $stderr.puts "Removed empty directory: #{version_dir}" end end end |