ruby_jard 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/documentation.yml +65 -0
- data/.github/workflows/rspec.yml +96 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +90 -2
- data/CHANGELOG.md +112 -0
- data/Gemfile +14 -4
- data/README.md +95 -3
- data/benchmark/path_filter_bench.rb +58 -0
- data/bin/console +1 -2
- data/lib/ruby_jard.rb +68 -32
- data/lib/ruby_jard/box_drawer.rb +175 -0
- data/lib/ruby_jard/color_scheme.rb +28 -0
- data/lib/ruby_jard/color_schemes.rb +54 -0
- data/lib/ruby_jard/color_schemes/256_color_scheme.rb +50 -0
- data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +50 -0
- data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +49 -0
- data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +48 -0
- data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +47 -0
- data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +49 -0
- data/lib/ruby_jard/column.rb +26 -0
- data/lib/ruby_jard/commands/color_helpers.rb +32 -0
- data/lib/ruby_jard/commands/continue_command.rb +4 -9
- data/lib/ruby_jard/commands/down_command.rb +9 -8
- data/lib/ruby_jard/commands/exit_command.rb +27 -0
- data/lib/ruby_jard/commands/frame_command.rb +13 -11
- data/lib/ruby_jard/commands/jard/color_scheme_command.rb +74 -0
- data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
- data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
- data/lib/ruby_jard/commands/jard/output_command.rb +36 -0
- data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
- data/lib/ruby_jard/commands/jard_command.rb +52 -0
- data/lib/ruby_jard/commands/list_command.rb +31 -0
- data/lib/ruby_jard/commands/next_command.rb +11 -8
- data/lib/ruby_jard/commands/step_command.rb +11 -8
- data/lib/ruby_jard/commands/step_out_command.rb +34 -0
- data/lib/ruby_jard/commands/up_command.rb +10 -8
- data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
- data/lib/ruby_jard/config.rb +61 -0
- data/lib/ruby_jard/console.rb +158 -0
- data/lib/ruby_jard/control_flow.rb +73 -0
- data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
- data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
- data/lib/ruby_jard/decorators/color_decorator.rb +80 -0
- data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
- data/lib/ruby_jard/decorators/inspection_decorator.rb +109 -0
- data/lib/ruby_jard/decorators/loc_decorator.rb +108 -119
- data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
- data/lib/ruby_jard/decorators/path_decorator.rb +56 -60
- data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
- data/lib/ruby_jard/decorators/source_decorator.rb +3 -1
- data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
- data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
- data/lib/ruby_jard/frame.rb +68 -0
- data/lib/ruby_jard/key_binding.rb +14 -0
- data/lib/ruby_jard/key_bindings.rb +96 -0
- data/lib/ruby_jard/keys.rb +48 -0
- data/lib/ruby_jard/layout.rb +17 -88
- data/lib/ruby_jard/layout_calculator.rb +168 -0
- data/lib/ruby_jard/layout_picker.rb +34 -0
- data/lib/ruby_jard/layouts.rb +52 -0
- data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +32 -0
- data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
- data/lib/ruby_jard/layouts/tiny_layout.rb +29 -0
- data/lib/ruby_jard/layouts/wide_layout.rb +50 -0
- data/lib/ruby_jard/pager.rb +112 -0
- data/lib/ruby_jard/path_classifier.rb +133 -0
- data/lib/ruby_jard/path_filter.rb +125 -0
- data/lib/ruby_jard/reflection.rb +97 -0
- data/lib/ruby_jard/repl_processor.rb +151 -89
- data/lib/ruby_jard/repl_proxy.rb +337 -0
- data/lib/ruby_jard/row.rb +31 -0
- data/lib/ruby_jard/row_renderer.rb +119 -0
- data/lib/ruby_jard/screen.rb +14 -41
- data/lib/ruby_jard/screen_adjuster.rb +104 -0
- data/lib/ruby_jard/screen_drawer.rb +25 -0
- data/lib/ruby_jard/screen_manager.rb +167 -82
- data/lib/ruby_jard/screen_renderer.rb +152 -0
- data/lib/ruby_jard/screens.rb +31 -12
- data/lib/ruby_jard/screens/backtrace_screen.rb +118 -116
- data/lib/ruby_jard/screens/menu_screen.rb +73 -45
- data/lib/ruby_jard/screens/source_screen.rb +86 -106
- data/lib/ruby_jard/screens/threads_screen.rb +103 -78
- data/lib/ruby_jard/screens/variables_screen.rb +224 -142
- data/lib/ruby_jard/session.rb +151 -16
- data/lib/ruby_jard/span.rb +23 -0
- data/lib/ruby_jard/templates/layout_template.rb +35 -0
- data/lib/ruby_jard/templates/screen_template.rb +34 -0
- data/lib/ruby_jard/thread_info.rb +69 -0
- data/lib/ruby_jard/version.rb +1 -1
- data/ruby_jard.gemspec +7 -8
- metadata +84 -50
- data/.travis.yml +0 -6
- data/lib/ruby_jard/commands/finish_command.rb +0 -31
- data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
- data/lib/ruby_jard/layout_template.rb +0 -101
- data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
- data/lib/ruby_jard/screens/empty_screen.rb +0 -13
- data/lib/ruby_jard/screens/expressions_sreen.rb +0 -22
@@ -1,87 +1,83 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
require 'rbconfig'
|
5
|
+
|
3
6
|
module RubyJard
|
4
7
|
module Decorators
|
5
8
|
##
|
6
9
|
# Simplify and generate labels to indicate the location of a path.
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# If it's from the current working dir, strip the working dir.
|
10
|
+
# The return value is an array of two elements. The first one is overview,
|
11
|
+
# the second is detailed path location.
|
10
12
|
class PathDecorator
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
TYPE_PWD = :pwd,
|
15
|
-
TYPE_GEM = :gem
|
16
|
-
].freeze
|
13
|
+
def initialize(path_classifier: nil)
|
14
|
+
@path_classifier = path_classifier || RubyJard::PathClassifier.new
|
15
|
+
end
|
17
16
|
|
18
|
-
|
17
|
+
def decorate(path, lineno = nil)
|
18
|
+
return ['at ???', 'at ???'] if path.nil?
|
19
19
|
|
20
|
-
|
21
|
-
@gem = nil
|
22
|
-
@gem_version = nil
|
23
|
-
@path = path
|
24
|
-
@lineno = lineno
|
25
|
-
@type = TYPE_UNKNOWN
|
20
|
+
type, *info = @path_classifier.classify(path)
|
26
21
|
|
27
|
-
|
28
|
-
end
|
22
|
+
lineno = ":#{lineno}" unless lineno.nil?
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
case type
|
25
|
+
when RubyJard::PathClassifier::TYPE_SOURCE_TREE
|
26
|
+
path = File.expand_path(path)
|
27
|
+
decorate_source_tree(path, lineno)
|
28
|
+
when RubyJard::PathClassifier::TYPE_GEM
|
29
|
+
decorate_gem(path, lineno, info)
|
30
|
+
when RubyJard::PathClassifier::TYPE_STDLIB
|
31
|
+
decorate_stdlib(path, lineno, info)
|
32
|
+
when RubyJard::PathClassifier::TYPE_INTERNAL
|
33
|
+
["in #{path}", path]
|
34
|
+
when RubyJard::PathClassifier::TYPE_EVALUATION
|
35
|
+
["at #{path}#{lineno}", "#{path}#{lineno}"]
|
36
|
+
when RubyJard::PathClassifier::TYPE_RUBY_SCRIPT
|
37
|
+
["at (-e ruby script)#{lineno}", "(-e ruby script)#{lineno}"]
|
34
38
|
else
|
35
|
-
|
39
|
+
path = compact_with_relative_path(path)
|
40
|
+
["at #{path}#{lineno}", "#{path}#{lineno}"]
|
36
41
|
end
|
37
|
-
|
38
|
-
@path = @path[1..-1] if @path.start_with?('/')
|
39
|
-
end
|
40
|
-
|
41
|
-
def gem?
|
42
|
-
@type == TYPE_GEM
|
43
42
|
end
|
44
43
|
|
45
44
|
private
|
46
45
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
46
|
+
def decorate_source_tree(path, lineno)
|
47
|
+
path = path[Dir.pwd.length..-1]
|
48
|
+
path = path[1..-1] if path.start_with?('/')
|
49
|
+
path = "#{path}#{lineno}"
|
50
|
+
["at #{path}", path]
|
51
|
+
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
match = GEM_PATTERN.match(@gem)
|
59
|
-
if match
|
60
|
-
@gem = match[1]
|
61
|
-
@gem_version = match[2]
|
53
|
+
def decorate_gem(_path, lineno, info)
|
54
|
+
gem_name, gem_version, relative_path = info
|
55
|
+
overview =
|
56
|
+
if gem_version.nil?
|
57
|
+
"<#{gem_name}>"
|
58
|
+
else
|
59
|
+
"<#{gem_name} #{gem_version}>"
|
62
60
|
end
|
63
|
-
|
64
|
-
|
65
|
-
end
|
61
|
+
detail = "<#{gem_name}:#{relative_path}#{lineno}>"
|
62
|
+
["in #{overview}", detail]
|
66
63
|
end
|
67
64
|
|
68
|
-
def
|
69
|
-
|
65
|
+
def decorate_stdlib(_path, lineno, info)
|
66
|
+
lib_name, relative_path = info
|
70
67
|
|
71
|
-
|
72
|
-
|
73
|
-
paths << File.join(gem_path, 'gems')
|
74
|
-
paths << gem_path
|
75
|
-
end
|
76
|
-
end
|
68
|
+
["in <stdlib:#{lib_name}>", "<stdlib:#{relative_path}#{lineno}>"]
|
69
|
+
end
|
77
70
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
71
|
+
def compact_with_relative_path(path)
|
72
|
+
relative_path = Pathname.new(path).relative_path_from(Pathname.pwd).to_s
|
73
|
+
if relative_path.length < path.length
|
74
|
+
relative_path
|
75
|
+
else
|
76
|
+
path
|
82
77
|
end
|
83
|
-
|
84
|
-
|
78
|
+
rescue ArgumentError
|
79
|
+
# Fail to get relative path, ignore
|
80
|
+
path
|
85
81
|
end
|
86
82
|
end
|
87
83
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
module Decorators
|
5
|
+
##
|
6
|
+
# A collection of rails-specific decorators.
|
7
|
+
# Why?
|
8
|
+
# Because Rails is magic, and it is like stepping on a minefield. Rails objects
|
9
|
+
# can trigger side-effects (like calling database queries, or even API queries).
|
10
|
+
# And from the end-user perspective, Rails' internal variables are useless. They
|
11
|
+
# care more about database attributes, which requires some extra steps to display
|
12
|
+
# if I don't want to use `#inspect`.
|
13
|
+
class RailsDecorator
|
14
|
+
##
|
15
|
+
# Individual Active Record object is trivial. The object is a mapping from a DB
|
16
|
+
# entity to Ruby object. It is always in the memory.
|
17
|
+
class ActiveRecordBaseDecorator
|
18
|
+
def initialize(generic_decorator)
|
19
|
+
@generic_decorator = generic_decorator
|
20
|
+
@attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
|
21
|
+
end
|
22
|
+
|
23
|
+
def match?(variable)
|
24
|
+
return false unless defined?(ActiveRecord::Base)
|
25
|
+
|
26
|
+
RubyJard::Reflection.call_is_a?(variable, ActiveRecord::Base)
|
27
|
+
end
|
28
|
+
|
29
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
30
|
+
label = RubyJard::Span.new(
|
31
|
+
content: RubyJard::Reflection.call_to_s(variable).chomp!('>'),
|
32
|
+
margin_right: 1, styles: :text_primary
|
33
|
+
)
|
34
|
+
spans = [label]
|
35
|
+
spans += @attributes_decorator.inline_pairs(
|
36
|
+
variable.attributes.each_with_index,
|
37
|
+
total: variable.attributes.length, line_limit: line_limit - label.content_length - 2,
|
38
|
+
process_key: false, depth: depth + 1
|
39
|
+
)
|
40
|
+
spans << RubyJard::Span.new(content: '>', styles: :text_primary)
|
41
|
+
end
|
42
|
+
|
43
|
+
def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
|
44
|
+
singleline = decorate_singleline(variable, line_limit: first_line_limit)
|
45
|
+
|
46
|
+
if singleline.map(&:content_length).sum < line_limit
|
47
|
+
[singleline]
|
48
|
+
else
|
49
|
+
spans = [RubyJard::Span.new(content: RubyJard::Reflection.call_to_s(variable), styles: :text_primary)]
|
50
|
+
|
51
|
+
item_count = 0
|
52
|
+
variable.attributes.each_with_index do |(key, value), index|
|
53
|
+
spans << @attributes_decorator.pair(
|
54
|
+
key, value, line_limit: line_limit, process_key: false, depth: depth + 1
|
55
|
+
)
|
56
|
+
item_count += 1
|
57
|
+
break if index >= lines - 2
|
58
|
+
end
|
59
|
+
if variable.attributes.length > item_count
|
60
|
+
spans << [RubyJard::Span.new(
|
61
|
+
content: "▸ #{variable.attributes.length - item_count} more...",
|
62
|
+
margin_left: 2, styles: :text_dim
|
63
|
+
)]
|
64
|
+
end
|
65
|
+
spans
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# When creating an active record relation, Rails won't trigger any SQL query, until
|
72
|
+
# to_ary events. It is required to check for records loaded before recursively display
|
73
|
+
# its children. Hint if the relation is not loaded yet.
|
74
|
+
class ActiveRecordRelationDecorator
|
75
|
+
def initialize(generic_decorator)
|
76
|
+
@generic_decorator = generic_decorator
|
77
|
+
@attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
|
78
|
+
end
|
79
|
+
|
80
|
+
def match?(variable)
|
81
|
+
return false unless defined?(ActiveRecord::Relation)
|
82
|
+
|
83
|
+
RubyJard::Reflection.call_class(variable) < ActiveRecord::Relation
|
84
|
+
rescue StandardError
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
88
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
89
|
+
if variable.respond_to?(:loaded?) && variable.loaded?
|
90
|
+
spans = []
|
91
|
+
label = RubyJard::Span.new(
|
92
|
+
content: RubyJard::Reflection.call_to_s(variable).chomp('>'), styles: :text_primary
|
93
|
+
)
|
94
|
+
spans << label
|
95
|
+
spans += @attributes_decorator.inline_values(
|
96
|
+
variable.each_with_index,
|
97
|
+
total: variable.length, line_limit: line_limit - label.content_length - 2,
|
98
|
+
depth: depth + 1
|
99
|
+
)
|
100
|
+
spans << RubyJard::Span.new(content: '>', styles: :text_primary)
|
101
|
+
|
102
|
+
spans
|
103
|
+
else
|
104
|
+
relation_summary(variable, line_limit)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
|
109
|
+
singleline = decorate_singleline(variable, line_limit: first_line_limit)
|
110
|
+
if singleline.map(&:content_length).sum < line_limit
|
111
|
+
[singleline]
|
112
|
+
elsif !variable.respond_to?(:loaded?) || !variable.loaded?
|
113
|
+
[relation_summary(variable, first_line_limit)]
|
114
|
+
else
|
115
|
+
spans = [[RubyJard::Span.new(content: RubyJard::Reflection.call_to_s(variable), styles: :text_primary)]]
|
116
|
+
|
117
|
+
item_count = 0
|
118
|
+
variable.each_with_index do |value, index|
|
119
|
+
spans << @attributes_decorator.value(value, line_limit: line_limit, depth: depth + 1)
|
120
|
+
|
121
|
+
item_count += 1
|
122
|
+
break if index >= lines - 2
|
123
|
+
end
|
124
|
+
if variable.length > item_count
|
125
|
+
spans << [RubyJard::Span.new(
|
126
|
+
content: "▸ #{variable.length - item_count} more...",
|
127
|
+
margin_left: 2, styles: :text_dim
|
128
|
+
)]
|
129
|
+
end
|
130
|
+
spans
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def relation_summary(variable, line_limit)
|
137
|
+
overview = RubyJard::Reflection.call_to_s(variable).chomp('>')
|
138
|
+
width = overview.length + 1 + 12
|
139
|
+
spans = [RubyJard::Span.new(content: overview, styles: :text_primary)]
|
140
|
+
if RubyJard::Reflection.call_respond_to?(variable, :to_sql) && width < line_limit
|
141
|
+
detail = variable.to_sql
|
142
|
+
detail = detail[0..line_limit - width - 2] + '…' if width + detail.length < line_limit
|
143
|
+
spans << RubyJard::Span.new(content: detail, styles: :text_dim, margin_left: 1)
|
144
|
+
end
|
145
|
+
spans << RubyJard::Span.new(content: '>', styles: :text_primary)
|
146
|
+
spans << RubyJard::Span.new(content: '(not loaded)', margin_left: 1, styles: :text_dim)
|
147
|
+
spans
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def initialize(generic_decorator)
|
152
|
+
@generic_decorator = generic_decorator
|
153
|
+
@sub_decorators = [
|
154
|
+
@active_record_base_decorator = ActiveRecordBaseDecorator.new(generic_decorator),
|
155
|
+
@active_record_relation_decorator = ActiveRecordRelationDecorator.new(generic_decorator)
|
156
|
+
]
|
157
|
+
end
|
158
|
+
|
159
|
+
def match?(variable)
|
160
|
+
@sub_decorators.any? { |sub_decorator| sub_decorator.match?(variable) }
|
161
|
+
rescue StandardError
|
162
|
+
false
|
163
|
+
end
|
164
|
+
|
165
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
166
|
+
@sub_decorators.each do |sub_decorator|
|
167
|
+
next unless sub_decorator.match?(variable)
|
168
|
+
|
169
|
+
return sub_decorator.decorate_singleline(
|
170
|
+
variable, line_limit: line_limit, depth: depth
|
171
|
+
)
|
172
|
+
end
|
173
|
+
|
174
|
+
nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
|
178
|
+
@sub_decorators.each do |sub_decorator|
|
179
|
+
next unless sub_decorator.match?(variable)
|
180
|
+
|
181
|
+
return sub_decorator.decorate_multiline(
|
182
|
+
variable,
|
183
|
+
first_line_limit: first_line_limit,
|
184
|
+
lines: lines,
|
185
|
+
line_limit: line_limit,
|
186
|
+
depth: depth
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
nil
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -12,6 +12,8 @@ module RubyJard
|
|
12
12
|
@file = file
|
13
13
|
@lineno = lineno
|
14
14
|
@window = window
|
15
|
+
@window_start = 0
|
16
|
+
@window_end = 0
|
15
17
|
@codes = []
|
16
18
|
|
17
19
|
decorate
|
@@ -25,7 +27,7 @@ module RubyJard
|
|
25
27
|
end
|
26
28
|
|
27
29
|
@window_start = @lineno - @window / 2
|
28
|
-
@window_start =
|
30
|
+
@window_start = 1 if @window_start <= 0
|
29
31
|
@window_end = @window_start + @window
|
30
32
|
|
31
33
|
until file.eof?
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
module Decorators
|
5
|
+
##
|
6
|
+
# A light decorator for a string. String should be escaped, and cut off.
|
7
|
+
class StringDecorator
|
8
|
+
def initialize(generic_decorator)
|
9
|
+
@generic_decorator = generic_decorator
|
10
|
+
end
|
11
|
+
|
12
|
+
def match?(variable)
|
13
|
+
RubyJard::Reflection.call_is_a?(variable, String)
|
14
|
+
end
|
15
|
+
|
16
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
17
|
+
def decorate_multiline(variable, first_line_limit:, line_limit:, lines:, depth: 0)
|
18
|
+
[
|
19
|
+
decorate_singleline(variable, line_limit: first_line_limit)
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
24
|
+
inspection = variable.inspect[1..-1].chomp!('"')
|
25
|
+
str =
|
26
|
+
if inspection.length < line_limit - 2
|
27
|
+
inspection
|
28
|
+
else
|
29
|
+
inspection[0..line_limit - 4] + '…'
|
30
|
+
end
|
31
|
+
[
|
32
|
+
|
33
|
+
RubyJard::Span.new(content: '"', styles: :string),
|
34
|
+
RubyJard::Span.new(content: str, styles: :string),
|
35
|
+
RubyJard::Span.new(content: '"', styles: :string)
|
36
|
+
]
|
37
|
+
end
|
38
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
module Decorators
|
5
|
+
##
|
6
|
+
# Decorator for Struct.
|
7
|
+
# TODO: This one should handle Open Struct too
|
8
|
+
class StructDecorator
|
9
|
+
def initialize(generic_decorator)
|
10
|
+
@generic_decorator = generic_decorator
|
11
|
+
@attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
|
12
|
+
end
|
13
|
+
|
14
|
+
def match?(variable)
|
15
|
+
RubyJard::Reflection.call_is_a?(variable, Struct)
|
16
|
+
end
|
17
|
+
|
18
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
19
|
+
spans = [RubyJard::Span.new(content: '#<struct', margin_right: 1, styles: :text_dim)]
|
20
|
+
unless variable.class.name.nil?
|
21
|
+
spans << RubyJard::Span.new(content: variable.class.name.to_s, margin_right: 1, styles: :text_primary)
|
22
|
+
end
|
23
|
+
spans += @attributes_decorator.inline_pairs(
|
24
|
+
variable.members.each_with_index,
|
25
|
+
total: variable.length, line_limit: line_limit - spans.map(&:content_length).sum - 1,
|
26
|
+
process_key: false, depth: depth + 1,
|
27
|
+
value_proc: ->(key) { variable[key] }
|
28
|
+
)
|
29
|
+
spans << RubyJard::Span.new(content: '>', styles: :text_dim)
|
30
|
+
end
|
31
|
+
|
32
|
+
def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
|
33
|
+
if variable.size > lines * 1.5
|
34
|
+
return do_decorate_multiline(variable, lines: lines, line_limit: line_limit, depth: depth)
|
35
|
+
end
|
36
|
+
|
37
|
+
singleline = decorate_singleline(variable, line_limit: first_line_limit)
|
38
|
+
|
39
|
+
if singleline.map(&:content_length).sum < line_limit || variable.length <= 1
|
40
|
+
[singleline]
|
41
|
+
else
|
42
|
+
do_decorate_multiline(variable, lines: lines, line_limit: line_limit, depth: depth)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def do_decorate_multiline(variable, lines:, line_limit:, depth: 0)
|
49
|
+
spans = []
|
50
|
+
start = [RubyJard::Span.new(content: '#<struct', styles: :text_dim)]
|
51
|
+
unless variable.class.name.nil?
|
52
|
+
start << RubyJard::Span.new(content: variable.class.name.to_s, margin_left: 1, styles: :text_primary)
|
53
|
+
end
|
54
|
+
start << RubyJard::Span.new(content: '>', styles: :text_dim)
|
55
|
+
spans << start
|
56
|
+
|
57
|
+
item_count = 0
|
58
|
+
variable.members.each_with_index do |member, index|
|
59
|
+
spans << @attributes_decorator.pair(
|
60
|
+
member, variable[member], line_limit: line_limit, process_key: false, depth: depth + 1
|
61
|
+
)
|
62
|
+
item_count += 1
|
63
|
+
break if index >= lines - 2
|
64
|
+
end
|
65
|
+
spans << last_line(variable.length, item_count) if variable.length > item_count
|
66
|
+
spans
|
67
|
+
end
|
68
|
+
|
69
|
+
def last_line(total, item_count)
|
70
|
+
[
|
71
|
+
RubyJard::Span.new(
|
72
|
+
content: "▸ #{total - item_count} more...",
|
73
|
+
margin_left: 2, styles: :text_dim
|
74
|
+
)
|
75
|
+
]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|