docrb-html 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +21 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +52 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +37 -0
- data/assets/breadcrumb.scss +25 -0
- data/assets/checkbox.scss +34 -0
- data/assets/class_header.scss +75 -0
- data/assets/class_mod_name.scss +8 -0
- data/assets/component_list.scss +4 -0
- data/assets/container.scss +9 -0
- data/assets/doc_box.scss +79 -0
- data/assets/documentation_block.scss +5 -0
- data/assets/favicon.ico +0 -0
- data/assets/fonts.scss +105 -0
- data/assets/footer.scss +15 -0
- data/assets/images/balance.svg +9 -0
- data/assets/images/breadcrumb_separator.svg +1 -0
- data/assets/images/checkbox-off.svg +1 -0
- data/assets/images/checkbox-on.svg +1 -0
- data/assets/images/chevron.svg +1 -0
- data/assets/images/docrb-label.svg +20 -0
- data/assets/images/github.svg +11 -0
- data/assets/images/home.svg +1 -0
- data/assets/images/inherited.svg +1 -0
- data/assets/images/override.svg +1 -0
- data/assets/images/questionmark.svg +1 -0
- data/assets/images/rubygems.svg +9 -0
- data/assets/images/user.svg +12 -0
- data/assets/js/filtering.js +66 -0
- data/assets/links.scss +16 -0
- data/assets/markdown.scss +41 -0
- data/assets/method_argument.scss +75 -0
- data/assets/method_display.scss +27 -0
- data/assets/method_list.scss +51 -0
- data/assets/project_header.scss +55 -0
- data/assets/reference.scss +36 -0
- data/assets/shared.scss +23 -0
- data/assets/style.scss +43 -0
- data/assets/symbol.scss +5 -0
- data/assets/tab_bar.scss +22 -0
- data/assets/text_block.scss +23 -0
- data/assets/type_definition.scss +3 -0
- data/assets/typedef.scss +6 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/docrb-html +12 -0
- data/lib/renderer/component/breadcrumb.rb +14 -0
- data/lib/renderer/component/checkbox.rb +9 -0
- data/lib/renderer/component/class_header.rb +14 -0
- data/lib/renderer/component/class_mod_name.rb +9 -0
- data/lib/renderer/component/component_list.rb +15 -0
- data/lib/renderer/component/doc_box.rb +38 -0
- data/lib/renderer/component/documentation_block.rb +9 -0
- data/lib/renderer/component/footer.rb +9 -0
- data/lib/renderer/component/markdown.rb +9 -0
- data/lib/renderer/component/method_argument.rb +106 -0
- data/lib/renderer/component/method_display.rb +9 -0
- data/lib/renderer/component/method_list.rb +9 -0
- data/lib/renderer/component/project_header.rb +9 -0
- data/lib/renderer/component/reference.rb +24 -0
- data/lib/renderer/component/symbol.rb +9 -0
- data/lib/renderer/component/tab_bar.rb +9 -0
- data/lib/renderer/component/text_block.rb +15 -0
- data/lib/renderer/component/type_definition.rb +9 -0
- data/lib/renderer/component/typedef.rb +9 -0
- data/lib/renderer/component.rb +50 -0
- data/lib/renderer/core_extensions.rb +11 -0
- data/lib/renderer/defs/specialized_object.rb +172 -0
- data/lib/renderer/defs/specialized_projection.rb +31 -0
- data/lib/renderer/defs.rb +180 -0
- data/lib/renderer/helpers.rb +82 -0
- data/lib/renderer/metadata.rb +44 -0
- data/lib/renderer/page.rb +17 -0
- data/lib/renderer/template.rb +38 -0
- data/lib/renderer/version.rb +5 -0
- data/lib/renderer.rb +129 -0
- data/renderer.gemspec +31 -0
- data/script/makecomponent +23 -0
- data/script/reload.js +14 -0
- data/script/serve +2 -0
- data/script/watch +17 -0
- data/templates/base.erb +25 -0
- data/templates/breadcrumb.erb +28 -0
- data/templates/checkbox.erb +8 -0
- data/templates/class_header.erb +53 -0
- data/templates/class_mod_name.erb +3 -0
- data/templates/component_list.erb +21 -0
- data/templates/doc_box.erb +82 -0
- data/templates/documentation_block.erb +18 -0
- data/templates/footer.erb +9 -0
- data/templates/markdown.erb +3 -0
- data/templates/method_argument.erb +29 -0
- data/templates/method_display.erb +28 -0
- data/templates/method_list.erb +25 -0
- data/templates/project_header.erb +38 -0
- data/templates/reference.erb +14 -0
- data/templates/symbol.erb +3 -0
- data/templates/tab_bar.erb +7 -0
- data/templates/text_block.erb +16 -0
- data/templates/type_definition.erb +4 -0
- data/templates/typedef.erb +3 -0
- metadata +178 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Component
|
5
|
+
class MethodArgument < Component
|
6
|
+
prop :type, :name, :value, :value_type, :computed
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@computed = {
|
10
|
+
rest: rest_arg,
|
11
|
+
name:,
|
12
|
+
continuation: continuation_for_type,
|
13
|
+
value: value_for_argument
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def continuation_for_type
|
18
|
+
if type == "kwarg" || type == "kwoptarg"
|
19
|
+
:colon
|
20
|
+
elsif type&.index("opt")&.zero?
|
21
|
+
:equal
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
REST_ARG_BY_TYPE = {
|
26
|
+
"kwrestarg" => :double,
|
27
|
+
"restarg" => :single,
|
28
|
+
"blockarg" => :block
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def rest_arg
|
32
|
+
REST_ARG_BY_TYPE[type]
|
33
|
+
end
|
34
|
+
|
35
|
+
def value_for_argument
|
36
|
+
return if value_type.nil?
|
37
|
+
|
38
|
+
case value_type
|
39
|
+
when "sym"
|
40
|
+
{ kind: :symbol, value: }
|
41
|
+
when "bool"
|
42
|
+
{ kind: :symbol, value: value.inspect }
|
43
|
+
when "nil"
|
44
|
+
{ kind: :symbol, value: "nil" }
|
45
|
+
when "int"
|
46
|
+
{ kind: :number, value: }
|
47
|
+
when "str"
|
48
|
+
{ kind: :string, value: }
|
49
|
+
when "send"
|
50
|
+
method_call_argument(value)
|
51
|
+
when "const"
|
52
|
+
const_value(value)
|
53
|
+
else
|
54
|
+
{ kind: :plain, value: }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_call_argument(value)
|
59
|
+
class_path = value[:target].map do |i|
|
60
|
+
next { kind: :symbol, value: "self" } if i == "self"
|
61
|
+
|
62
|
+
# TODO: Is this plain?
|
63
|
+
[{ kind: :class_or_module, value: i }, { kind: :plain, value: "::" }]
|
64
|
+
end.flatten
|
65
|
+
|
66
|
+
class_path.pop
|
67
|
+
|
68
|
+
{
|
69
|
+
kind: :method_call_argument,
|
70
|
+
value: [
|
71
|
+
class_path,
|
72
|
+
{ kind: :plain, value: "." },
|
73
|
+
{ kind: :plain, value: value[:name] }
|
74
|
+
].flatten
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def const_value(value)
|
79
|
+
class_path = value[:target].map do |i|
|
80
|
+
# TODO: Is this plain?
|
81
|
+
[{ kind: :class_or_module, value: i }, { kind: :continuation, double: true }]
|
82
|
+
end.flatten
|
83
|
+
|
84
|
+
class_path.pop
|
85
|
+
|
86
|
+
if class_path.empty?
|
87
|
+
return {
|
88
|
+
kind: :const,
|
89
|
+
value: [
|
90
|
+
{ kind: :class_or_module, value: value[:name] }
|
91
|
+
].flatten
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
{
|
96
|
+
kind: :const,
|
97
|
+
value: [
|
98
|
+
class_path,
|
99
|
+
{ kind: :continuation, double: true },
|
100
|
+
{ kind: :class_or_module, value: value[:name] }
|
101
|
+
].flatten
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Component
|
5
|
+
class Reference < Component
|
6
|
+
prop :ref, :unresolved, :path
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@unresolved = !ref[:ref_path]
|
10
|
+
return if @unresolved
|
11
|
+
|
12
|
+
components = ref[:ref_path].dup
|
13
|
+
@path = if ref[:ref_type] == "method"
|
14
|
+
method_name = components.pop
|
15
|
+
parent_name = components.pop
|
16
|
+
components + ["#{parent_name}.html#{method_name}"]
|
17
|
+
else
|
18
|
+
last = components.pop
|
19
|
+
(components + ["#{last}.html"]).compact
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Component
|
5
|
+
class TextBlock < Component
|
6
|
+
prop :list
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
return unless !@list.nil? && !@list.is_a?(Array)
|
10
|
+
|
11
|
+
@list = [{ type: "html", contents: @list }]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Component
|
5
|
+
attr_accessor :id
|
6
|
+
|
7
|
+
def self.prop(*names)
|
8
|
+
attr_accessor(*names)
|
9
|
+
|
10
|
+
@props ||= []
|
11
|
+
@props.append(*names)
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_writer :template
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.template
|
19
|
+
return @template_instance if @template_instance
|
20
|
+
|
21
|
+
t_name = @template || name.split("::").last.snakify
|
22
|
+
@template_instance = Template.new("templates/#{t_name}.erb")
|
23
|
+
end
|
24
|
+
|
25
|
+
def props = @props ||= self.class.instance_variable_get(:@props) || []
|
26
|
+
def template = self.class.template
|
27
|
+
|
28
|
+
def initialize(**kwargs)
|
29
|
+
@id = kwargs.delete(:id)
|
30
|
+
kwargs.each do |k, v|
|
31
|
+
raise ArgumentError, "Unknown property #{k} for #{self.class.name}" unless props.include? k
|
32
|
+
|
33
|
+
send("#{k}=", v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def prepare; end
|
38
|
+
|
39
|
+
def render(&)
|
40
|
+
prepare
|
41
|
+
opts = props.map { [_1, send(_1)] }.to_h
|
42
|
+
opts[:id] = @id
|
43
|
+
template.render(HELPERS, **opts, &)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Dir[Pathname.new(__dir__).join("component/*.rb")].each do |file|
|
49
|
+
require_relative "component/#{Pathname.new(file).basename}"
|
50
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Defs
|
5
|
+
class SpecializedObject
|
6
|
+
def initialize(obj, parent, provider)
|
7
|
+
@obj = obj
|
8
|
+
@provider = provider
|
9
|
+
prepare(parent)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.specialize(obj, parent, provider)
|
13
|
+
return nil if obj.nil?
|
14
|
+
|
15
|
+
new(obj, parent, provider)
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](key) = @obj[key]
|
19
|
+
def fetch(*, **, &) = @obj.fetch(*, **, &)
|
20
|
+
|
21
|
+
def resolve(name)
|
22
|
+
named = named_as(name)
|
23
|
+
modules.find(&named) \
|
24
|
+
|| classes.find(&named) \
|
25
|
+
|| attributes&.find(&named) \
|
26
|
+
|| defs.find(&named) \
|
27
|
+
|| sdefs.find(&named)
|
28
|
+
end
|
29
|
+
|
30
|
+
def resolve_inheritance(name)
|
31
|
+
named = named_as(name)
|
32
|
+
modules.find(&named) \
|
33
|
+
|| classes.find(&named) \
|
34
|
+
|| parent&.resolve_inheritance(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def resolve_parent(name)
|
38
|
+
parent = self[:parent]
|
39
|
+
return { type: "Unknown Ref", name: } unless parent
|
40
|
+
|
41
|
+
parent.resolve(name) || parent.resolve_parent(name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def resolve_path(path)
|
45
|
+
p = path.dup
|
46
|
+
obj = self
|
47
|
+
until p.empty?
|
48
|
+
obj = obj.resolve(p[0])
|
49
|
+
return unless obj
|
50
|
+
|
51
|
+
p.shift
|
52
|
+
end
|
53
|
+
obj
|
54
|
+
end
|
55
|
+
|
56
|
+
def resolve_qualified(obj)
|
57
|
+
result = nil
|
58
|
+
query = nil
|
59
|
+
|
60
|
+
if obj[:class_path]&.length&.> 0
|
61
|
+
query = obj[:class_path] + [obj[:name]]
|
62
|
+
result = root.resolve_path(query)
|
63
|
+
else
|
64
|
+
query = obj[:name]
|
65
|
+
result = resolve(query)
|
66
|
+
result ||= resolve_inheritance(query)
|
67
|
+
end
|
68
|
+
|
69
|
+
puts "Qualified resolution of #{query.inspect} by #{name} failed." unless result
|
70
|
+
|
71
|
+
result
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(method_name, *args, **kwargs, &)
|
75
|
+
var = "@#{method_name}".to_sym
|
76
|
+
if instance_variables.include?(var)
|
77
|
+
instance_variable_get(var)
|
78
|
+
elsif @obj.key? method_name
|
79
|
+
@obj.fetch(method_name)
|
80
|
+
else
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def respond_to_missing?(method_name, include_private = false)
|
86
|
+
instance_variables.include?("@#{method_name}".to_sym) || @obj.key?(method_name) || super
|
87
|
+
end
|
88
|
+
|
89
|
+
def to_s
|
90
|
+
"<SpecializedObject for #{@provider.path_of(@obj).join("::")}>"
|
91
|
+
end
|
92
|
+
|
93
|
+
def inspect = to_s
|
94
|
+
|
95
|
+
def prepare_inheritance
|
96
|
+
@inheritance_prepared = true
|
97
|
+
@inherits = coerce_inheritance_data(@obj[:inherits])
|
98
|
+
@extends = @obj[:extends]&.map { resolve_qualified _1 }
|
99
|
+
@includes = @obj[:includes]&.map { resolve_qualified _1 }
|
100
|
+
@classes.each(&:prepare_inheritance)
|
101
|
+
@modules.each(&:prepare_inheritance)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def make_path
|
107
|
+
r = [name]
|
108
|
+
p = parent
|
109
|
+
while p
|
110
|
+
r << p.name
|
111
|
+
p = p.parent
|
112
|
+
end
|
113
|
+
|
114
|
+
r.reverse
|
115
|
+
end
|
116
|
+
|
117
|
+
def parent_of(parent)
|
118
|
+
return unless parent
|
119
|
+
|
120
|
+
p = parent
|
121
|
+
while p
|
122
|
+
return p unless p.parent
|
123
|
+
|
124
|
+
p = p.parent
|
125
|
+
end
|
126
|
+
|
127
|
+
p
|
128
|
+
end
|
129
|
+
|
130
|
+
def specialize_defs(defs, _parent)
|
131
|
+
defs.values.map do |i|
|
132
|
+
decoration = if i[:source] == "inheritance"
|
133
|
+
"inherited"
|
134
|
+
elsif i[:overriding]
|
135
|
+
"override"
|
136
|
+
else
|
137
|
+
""
|
138
|
+
end
|
139
|
+
|
140
|
+
origin = i[:source]
|
141
|
+
|
142
|
+
@provider.find_source(i)
|
143
|
+
.merge({ decoration:, origin: })
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def coerce_inheritance_data(obj)
|
148
|
+
return obj if obj.nil?
|
149
|
+
|
150
|
+
resolve_inheritance(obj) || obj
|
151
|
+
end
|
152
|
+
|
153
|
+
def prepare(parent)
|
154
|
+
@inheritance_prepared = true
|
155
|
+
@parent = parent
|
156
|
+
@defs = specialize_defs(@obj[:defs], self)
|
157
|
+
@sdefs = specialize_defs(@obj[:sdefs], self)
|
158
|
+
@attributes = (@obj[:attributes] || {}).values.map do |v|
|
159
|
+
@provider.prepare_attr(v)
|
160
|
+
end
|
161
|
+
|
162
|
+
@root = parent_of(parent)
|
163
|
+
@path = make_path
|
164
|
+
|
165
|
+
@classes = @obj[:classes].map { SpecializedObject.specialize(_1, self, @provider) }
|
166
|
+
@modules = @obj[:modules].map { SpecializedObject.specialize(_1, self, @provider) }
|
167
|
+
end
|
168
|
+
|
169
|
+
def named_as(n) = ->(o) { o.name == n }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Renderer
|
4
|
+
class Defs
|
5
|
+
class SpecializedProjection < Array
|
6
|
+
def initialize(provider)
|
7
|
+
super()
|
8
|
+
@provider = provider
|
9
|
+
replace((provider.modules + provider.classes)
|
10
|
+
.map { provider.specialize_object _1 }
|
11
|
+
.each(&:prepare_inheritance))
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_path(path)
|
15
|
+
path = @provider.path_of(path) unless path.is_a? Array
|
16
|
+
p = path.dup
|
17
|
+
obj = find { _1.name == p.first }
|
18
|
+
p.shift
|
19
|
+
return unless obj
|
20
|
+
|
21
|
+
until p.empty?
|
22
|
+
obj = obj.resolve(p.first)
|
23
|
+
p.shift
|
24
|
+
return unless obj
|
25
|
+
end
|
26
|
+
|
27
|
+
obj
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "defs/specialized_object"
|
4
|
+
require_relative "defs/specialized_projection"
|
5
|
+
|
6
|
+
class Renderer
|
7
|
+
class Defs
|
8
|
+
class << self
|
9
|
+
attr_reader :singleton
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_writer :singleton
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(base, metadata)
|
17
|
+
@data = JSON.parse(File.read("#{base}/data.json"), symbolize_names: true)
|
18
|
+
@meta = metadata
|
19
|
+
Defs.singleton = self
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :meta
|
23
|
+
|
24
|
+
def classes = @classes ||= make_paths(@data[:classes])
|
25
|
+
def modules = @modules ||= make_paths(@data[:modules])
|
26
|
+
|
27
|
+
def make_paths(obj)
|
28
|
+
return [] unless obj
|
29
|
+
|
30
|
+
obj.each { set_parent(_1, nil) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_parent(obj, parent)
|
34
|
+
obj[:parent] = parent
|
35
|
+
obj[:classes].each { set_parent(_1, obj) }
|
36
|
+
obj[:modules].each { set_parent(_1, obj) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def document_outline
|
40
|
+
(classes + modules).map { outline(_1) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def outline(object, level = 0)
|
44
|
+
defs = object[:defs].values.map { map_method(_1) }.sort_by { _1[:name] }
|
45
|
+
sdefs = object[:sdefs].values.map { map_method(_1) }.sort_by { _1[:name] }
|
46
|
+
attributes = object[:attributes]&.values&.map { prepare_attr(_1) }&.sort_by { _1[:name] }
|
47
|
+
|
48
|
+
{
|
49
|
+
level:,
|
50
|
+
name: object[:name],
|
51
|
+
type: object[:type],
|
52
|
+
classes: object[:classes].map { outline(_1, level + 1) },
|
53
|
+
modules: object[:modules].map { outline(_1, level + 1) },
|
54
|
+
defs: defs + sdefs,
|
55
|
+
attributes:
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def map_method(met)
|
60
|
+
decoration = if met[:source] == "inheritance"
|
61
|
+
"inherited"
|
62
|
+
elsif met[:overriding]
|
63
|
+
"override"
|
64
|
+
end
|
65
|
+
|
66
|
+
obj = find_source(met)
|
67
|
+
type = [].tap do |arr|
|
68
|
+
arr << "Class" if obj[:type] == "defs"
|
69
|
+
arr << "Method"
|
70
|
+
end.join(" ")
|
71
|
+
|
72
|
+
{
|
73
|
+
name: obj[:name],
|
74
|
+
visibility: obj[:visibility],
|
75
|
+
args: obj[:args],
|
76
|
+
type:,
|
77
|
+
short_type: obj[:type],
|
78
|
+
doc: obj[:doc],
|
79
|
+
decoration:
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_source(met)
|
84
|
+
obj = met
|
85
|
+
obj = obj[:definition] while obj[:source] != "source"
|
86
|
+
obj[:definition]
|
87
|
+
end
|
88
|
+
|
89
|
+
def prepare_attr(met)
|
90
|
+
decoration = if met[:source] == "inheritance"
|
91
|
+
"inherited"
|
92
|
+
elsif met[:overriding]
|
93
|
+
"override"
|
94
|
+
end
|
95
|
+
origin = met[:source]
|
96
|
+
att = find_source(met)
|
97
|
+
visibility = if att[:reader_visibility] == "public" && att[:writer_visibility] == "public"
|
98
|
+
"read/write"
|
99
|
+
elsif att[:reader_visibility] == "public" && att[:writer_visibility] != "public"
|
100
|
+
"read-only"
|
101
|
+
else
|
102
|
+
"write-only"
|
103
|
+
end
|
104
|
+
|
105
|
+
{
|
106
|
+
name: att[:name],
|
107
|
+
type: "Attribute",
|
108
|
+
visibility:,
|
109
|
+
decoration:,
|
110
|
+
origin:,
|
111
|
+
doc: att[:doc]
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
def path_of(item)
|
116
|
+
p = []
|
117
|
+
parent = item
|
118
|
+
until parent.nil?
|
119
|
+
p << parent[:name]
|
120
|
+
parent = parent[:parent]
|
121
|
+
end
|
122
|
+
p.reverse
|
123
|
+
end
|
124
|
+
|
125
|
+
def definitions_of(item)
|
126
|
+
item[:defined_by]&.map do |d|
|
127
|
+
path_components = d[:filename].split("/")
|
128
|
+
{
|
129
|
+
name: path_components.last,
|
130
|
+
href: git_url(d)
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def git_url(definition)
|
136
|
+
"#{@meta.git_url}/blob/#{@meta.git_tip}#{definition[:filename].gsub(@meta.git_root,
|
137
|
+
"")}#L#{definition[:start_at]}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def clean_file_path(definition) = definition[:filename].gsub(meta.git_root, "")
|
141
|
+
|
142
|
+
def specialized_projection
|
143
|
+
@specialized_projection ||= SpecializedProjection.new(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
def specialize_data
|
147
|
+
@specialize_data ||= (data[:modules] + data[:classes])
|
148
|
+
.map { specialize_object _1 }
|
149
|
+
.each(&:prepare_inheritance)
|
150
|
+
end
|
151
|
+
|
152
|
+
def specialize_object(obj, parent = nil)
|
153
|
+
SpecializedObject.specialize(obj, parent, self)
|
154
|
+
end
|
155
|
+
|
156
|
+
def by_name(n) = ->(o) { o[:name] == n }
|
157
|
+
|
158
|
+
def doc_for(path)
|
159
|
+
path = path_of(path) if path.is_a? Hash
|
160
|
+
path = path.dup
|
161
|
+
named = by_name(path.shift)
|
162
|
+
root = classes.find(&named) || modules.find(&named)
|
163
|
+
|
164
|
+
return unless root
|
165
|
+
|
166
|
+
find_recursive(path, root)
|
167
|
+
end
|
168
|
+
|
169
|
+
def find_recursive(path, root)
|
170
|
+
return root if path.empty?
|
171
|
+
|
172
|
+
named = by_name(path.shift)
|
173
|
+
next_item = root.classes.find(&named) || root.modules.find(&named)
|
174
|
+
|
175
|
+
return nil unless next_item
|
176
|
+
|
177
|
+
find_recursive(path, next_item)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|