Class: BitClust::IncludeGraph
Overview
doctree の #@include グラフを版ゲート付きで解析する。
LIBRARIES の各エントリ
特定の版範囲([3.0, 4.2) 等)への絞り込みは行わない faithful 層。 スコープ適用は IncludeGraph::Scope が担い、範囲はパラメータ化されている (旧版サルベージ時に別範囲で再利用するため)。
Defined Under Namespace
Classes: Condition, Membership, Scope
Constant Summary collapse
- ENTITY_H1_RE =
RRDParser は /\A=[^=]/ で H1 行を認識し
=直後の空白は必須でない (実データ: _builtin/Encoding は「=class Encoding」) /\A=(?!=)\s*(?:class|module|object|reopen|redefine)\b/
Instance Attribute Summary collapse
-
#warnings ⇒ Object
readonly
Returns the value of attribute warnings.
Class Method Summary collapse
- .analyze(src_root) ⇒ Object
-
.bounds(conditions) ⇒ Object
conditions から下限・上限を [Gem::Version, 原文字列] の組で集める。 :if の連言(ubygems の "1.9.1" <= version and version < "2.5.0" 等)も 分解して境界に寄与させる。分解できない連言子は寄与しない(保守的に広く扱う。 恒偽の証明は Scope#never? が連言子単位で別途行う).
-
.if_bounds(expr) ⇒ Object
連言(and 区切り)の #@if 条件式を since/until 境界に分解する。 対応形: "X" <= version / version >= "X" → since X、version < "X" → until X。 <= や否定(#@else 反転)は正確に表現できないので分解しない.
-
.interval(conditions) ⇒ Object
conditions が表す版区間 [lo, hi)。lo/hi は Gem::Version、制約なしは nil。 :since は max、:until は min を取る。.
Instance Method Summary collapse
- #analyze ⇒ Object
- #fragments ⇒ Object
-
#front_matter_map(scope) ⇒ Object
各 grouping メンバーへ注入する front matter(スコープ適用済み)。 単一所属: { relpath => { "library" => name, "since" => v, "until" => v } } 複数所属: { relpath => { "library" => [{ "name" => n, "since" => v, "until" => v }, ...], ... } } RRDToMarkdown の extra_front_matter: にそのまま渡せる形。.
-
#grouping_include_sites ⇒ Object
grouping include のサイト一覧(prune 対象)。 { relpath => [#@include に記載どおりの target 文字列] } fragment include は含まない(transclusion として温存する)。.
- #groupings ⇒ Object
-
#initialize(src_root) ⇒ IncludeGraph
constructor
A new instance of IncludeGraph.
-
#library_front_matter_map(scope) ⇒ Object
各ライブラリ概要ファイル(LIBRARIES のルート)へ注入する front matter。 { relpath => { "type" => "library", "since" => v, "until" => v } } LIBRARIES 内の版ゲート(fiber: until 3.1 等)をスコープ適用して付与する。 スコープ外のライブラリ(cmath/scanf/sync 等)は含まない。.
-
#memberships(relpath) ⇒ Object
grouping ファイル relpath の全 membership(生・スコープ未適用).
Constructor Details
#initialize(src_root) ⇒ IncludeGraph
Returns a new instance of IncludeGraph.
154 155 156 157 158 159 160 161 |
# File 'lib/bitclust/include_graph.rb', line 154 def initialize(src_root) @src_root = src_root @memberships = {} # relpath => [Membership] @kinds = {} # relpath => :grouping | :fragment @grouping_sites = {} # relpath => [include target(記載どおりの文字列)] @library_gates = {} # library name => [Condition](LIBRARIES 由来) @warnings = [] end |
Instance Attribute Details
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
152 153 154 |
# File 'lib/bitclust/include_graph.rb', line 152 def warnings @warnings end |
Class Method Details
.analyze(src_root) ⇒ Object
27 28 29 |
# File 'lib/bitclust/include_graph.rb', line 27 def self.analyze(src_root) new(src_root).analyze end |
.bounds(conditions) ⇒ Object
conditions から下限・上限を [Gem::Version, 原文字列] の組で集める。 :if の連言(ubygems の "1.9.1" <= version and version < "2.5.0" 等)も 分解して境界に寄与させる。分解できない連言子は寄与しない(保守的に広く扱う。 恒偽の証明は Scope#never? が連言子単位で別途行う)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/bitclust/include_graph.rb', line 42 def self.bounds(conditions) sinces = [] #: Array[bound] untils = [] #: Array[bound] conditions.each do |c| case c.kind when :since then sinces << [Gem::Version.new(c.version), c.version] when :until then untils << [Gem::Version.new(c.version), c.version] when :if if_bounds(c.version).each do |kind, v| (kind == :since ? sinces : untils) << [Gem::Version.new(v), v] end end end [sinces.max_by(&:first), untils.min_by(&:first)] end |
.if_bounds(expr) ⇒ Object
連言(and 区切り)の #@if 条件式を since/until 境界に分解する。 対応形: "X" <= version / version >= "X" → since X、version < "X" → until X。 <= や否定(#@else 反転)は正確に表現できないので分解しない
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/bitclust/include_graph.rb', line 61 def self.if_bounds(expr) return [] if expr.lstrip.start_with?('!') bounds = [] #: Array[[Symbol, String?]] expr.split(/\band\b/).each do |c| case c when /version\s*<\s*"([\d.]+)"/ then bounds << [:until, $1] when /version\s*>=\s*"([\d.]+)"/, /"([\d.]+)"\s*<=\s*version/ then bounds << [:since, $1] end end bounds end |
.interval(conditions) ⇒ Object
conditions が表す版区間 [lo, hi)。lo/hi は Gem::Version、制約なしは nil。 :since は max、:until は min を取る。
33 34 35 36 |
# File 'lib/bitclust/include_graph.rb', line 33 def self.interval(conditions) lo, hi = bounds(conditions) [lo&.first, hi&.first] end |
Instance Method Details
#analyze ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/bitclust/include_graph.rb', line 163 def analyze read_libraries.each do |name, gate| root = "#{name}.rd" unless File.file?(File.join(@src_root, root)) @warnings << "library root not found: #{root}" next end @library_gates[name] = gate walk(root, name, gate, [root]) end self end |
#fragments ⇒ Object
186 187 188 |
# File 'lib/bitclust/include_graph.rb', line 186 def fragments @kinds.select { |_, kind| kind == :fragment }.keys.sort end |
#front_matter_map(scope) ⇒ Object
各 grouping メンバーへ注入する front matter(スコープ適用済み)。 単一所属: { relpath => { "library" => name, "since" => v, "until" => v } } 複数所属: { relpath => { "library" => [{ "name" => n, "since" => v, "until" => v }, ...], ... } } RRDToMarkdown の extra_front_matter: にそのまま渡せる形。
- スコープ外のメンバーは含まない(旧版サルベージは別スコープで再実行)
- 複数ライブラリへの所属(旧 rdoc の同時所属、thread 系の版切替所属)は ゲート付きリストで表現する(MARKUP_SPEC §1.2)。並び順は 「現在まで存在する側(until なし)→ 名前順」で決定的にする。 このときトップレベルの since/until はライブラリ横断の hull (エンティティ自体の存在ゲート)
- 同一ライブラリ内の複数 include サイトは、いずれかが有効なら エンティティが存在するため、ゲートは区間の hull(弱い方)を取る
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/bitclust/include_graph.rb', line 229 def front_matter_map(scope) result = {} #: Hash[String, front_matter] groupings.each do |path, ms| covered = ms.select { |m| scope.cover?(m.conditions) } next if covered.empty? libraries = covered.map(&:library).uniq per_lib = libraries.to_h { |lib| [lib, hull(covered.select { |m| m.library == lib } .map { |m| scope.gate(m.conditions) })] } if libraries.size == 1 fm = { 'library' => libraries.first } gate = per_lib.values.first else entries = per_lib.map { |lib, g| e = { 'name' => lib } e['since'] = g[:since] if g[:since] e['until'] = g[:until] if g[:until] e }.sort_by { |e| [e['until'] ? 1 : 0, e['name']] } fm = { 'library' => entries } gate = hull(per_lib.values) end fm['since'] = gate[:since] if gate[:since] fm['until'] = gate[:until] if gate[:until] result[path] = fm end result end |
#grouping_include_sites ⇒ Object
grouping include のサイト一覧(prune 対象)。 { relpath => [#@include に記載どおりの target 文字列] } fragment include は含まない(transclusion として温存する)。
193 194 195 |
# File 'lib/bitclust/include_graph.rb', line 193 def grouping_include_sites @grouping_sites end |
#groupings ⇒ Object
181 182 183 184 |
# File 'lib/bitclust/include_graph.rb', line 181 def groupings @kinds.select { |_, kind| kind == :grouping }.keys.sort .to_h { |path| [path, @memberships.fetch(path, [])] } end |
#library_front_matter_map(scope) ⇒ Object
各ライブラリ概要ファイル(LIBRARIES のルート)へ注入する front matter。 { relpath => { "type" => "library", "since" => v, "until" => v } } LIBRARIES 内の版ゲート(fiber: until 3.1 等)をスコープ適用して付与する。 スコープ外のライブラリ(cmath/scanf/sync 等)は含まない。
201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/bitclust/include_graph.rb', line 201 def library_front_matter_map(scope) result = {} #: Hash[String, Hash[String, String]] @library_gates.each do |name, gate| root = "#{name}.rd" scoped = scope.gate(gate) next unless scoped fm = { 'type' => 'library' } fm['since'] = scoped[:since] if scoped[:since] fm['until'] = scoped[:until] if scoped[:until] result[root] = fm end result end |
#memberships(relpath) ⇒ Object
grouping ファイル relpath の全 membership(生・スコープ未適用)
177 178 179 |
# File 'lib/bitclust/include_graph.rb', line 177 def memberships(relpath) @memberships.fetch(relpath, []) end |