ruby_jard 0.2.3 → 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/workflows/documentation.yml +65 -0
- data/.github/workflows/{ruby.yml → rspec.yml} +22 -11
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +15 -3
- data/Gemfile +9 -2
- data/README.md +52 -332
- data/benchmark/path_filter_bench.rb +58 -0
- data/lib/ruby_jard.rb +15 -5
- data/lib/ruby_jard/color_schemes.rb +9 -1
- data/lib/ruby_jard/color_schemes/256_color_scheme.rb +21 -35
- data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +23 -35
- data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +20 -34
- data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +20 -34
- data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +20 -34
- data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +21 -34
- data/lib/ruby_jard/commands/color_helpers.rb +32 -0
- data/lib/ruby_jard/commands/frame_command.rb +2 -2
- data/lib/ruby_jard/commands/jard/color_scheme_command.rb +25 -3
- data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
- data/lib/ruby_jard/commands/jard/output_command.rb +13 -5
- data/lib/ruby_jard/commands/jard_command.rb +3 -1
- data/lib/ruby_jard/config.rb +9 -2
- 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 +12 -5
- data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
- data/lib/ruby_jard/decorators/inspection_decorator.rb +91 -58
- data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
- data/lib/ruby_jard/decorators/path_decorator.rb +55 -72
- data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
- 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 +23 -10
- data/lib/ruby_jard/keys.rb +1 -0
- data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +4 -0
- data/lib/ruby_jard/layouts/tiny_layout.rb +4 -0
- data/lib/ruby_jard/pager.rb +21 -5
- 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 +71 -38
- data/lib/ruby_jard/row_renderer.rb +5 -3
- data/lib/ruby_jard/screen.rb +2 -2
- data/lib/ruby_jard/screen_manager.rb +13 -36
- data/lib/ruby_jard/screen_renderer.rb +1 -1
- data/lib/ruby_jard/screens/backtrace_screen.rb +55 -39
- data/lib/ruby_jard/screens/menu_screen.rb +30 -30
- data/lib/ruby_jard/screens/source_screen.rb +46 -62
- data/lib/ruby_jard/screens/threads_screen.rb +59 -72
- data/lib/ruby_jard/screens/variables_screen.rb +168 -124
- data/lib/ruby_jard/session.rb +120 -16
- data/lib/ruby_jard/thread_info.rb +69 -0
- data/lib/ruby_jard/version.rb +1 -1
- data/ruby_jard.gemspec +3 -1
- metadata +20 -39
- data/.travis.yml +0 -6
- data/CNAME +0 -1
- data/_config.yml +0 -1
- data/docs/_config.yml +0 -8
- data/docs/color_schemes/256-light.png +0 -0
- data/docs/color_schemes/256.png +0 -0
- data/docs/color_schemes/deep-space.png +0 -0
- data/docs/color_schemes/gruvbox.png +0 -0
- data/docs/color_schemes/one-half-dark.png +0 -0
- data/docs/color_schemes/one-half-light.png +0 -0
- data/docs/demo.png +0 -0
- data/docs/guide-ui.png +0 -0
- data/docs/index.md +0 -238
- data/docs/logo.jpg +0 -0
- data/docs/screen-backtrace.png +0 -0
- data/docs/screen-repl.png +0 -0
- data/docs/screen-source.png +0 -0
- data/docs/screen-threads.png +0 -0
- data/docs/screen-variables.png +0 -0
- data/images/bg_hr.png +0 -0
- data/images/blacktocat.png +0 -0
- data/images/body-bg.jpg +0 -0
- data/images/download-button.png +0 -0
- data/images/github-button.png +0 -0
- data/images/header-bg.jpg +0 -0
- data/images/highlight-bg.jpg +0 -0
- data/images/icon_download.png +0 -0
- data/images/sidebar-bg.jpg +0 -0
- data/images/sprite_download.png +0 -0
- data/javascripts/main.js +0 -1
- data/stylesheets/github-light.css +0 -130
- data/stylesheets/normalize.css +0 -424
- data/stylesheets/print.css +0 -228
- data/stylesheets/stylesheet.css +0 -245
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RubyJard
|
4
|
+
module Decorators
|
5
|
+
##
|
6
|
+
# Default decorator for non-primitive data structure. It is aimed to replace default `inspect`.
|
7
|
+
# If a variable re-implement `#inspect`, it hornors this decision, but still try to
|
8
|
+
# parse the result.
|
9
|
+
# Otherwise, it use `Kernel#to_s`, and try to push instance variables into the result.
|
10
|
+
class ObjectDecorator
|
11
|
+
DEFAULT_INSPECTION_PATTERN = /#<(.*:0x[0-9a-z]+)(.*)>/i.freeze
|
12
|
+
|
13
|
+
def initialize(generic_decorator)
|
14
|
+
@generic_decorator = generic_decorator
|
15
|
+
@attributes_decorator = RubyJard::Decorators::AttributesDecorator.new(generic_decorator)
|
16
|
+
end
|
17
|
+
|
18
|
+
def decorate_singleline(variable, line_limit:, depth: 0)
|
19
|
+
if native_inspect?(variable)
|
20
|
+
decorate_native_inspection(variable, line_limit: line_limit, depth: depth)
|
21
|
+
else
|
22
|
+
decorate_custom_inspection(variable, line_limit: line_limit)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def decorate_multiline(variable, first_line_limit:, lines:, line_limit:, depth: 0)
|
27
|
+
singleline = decorate_singleline(variable, line_limit: first_line_limit)
|
28
|
+
return [singleline] if singleline.map(&:content_length).sum < line_limit
|
29
|
+
|
30
|
+
spans = [decorate_native_inspection(variable, line_limit: first_line_limit, with_children: false)]
|
31
|
+
|
32
|
+
item_count = 0
|
33
|
+
instance_variables = RubyJard::Reflection.call_instance_variables(variable)
|
34
|
+
instance_variables.each do |key|
|
35
|
+
spans << @attributes_decorator.pair(
|
36
|
+
key, RubyJard::Reflection.call_instance_variable_get(variable, key),
|
37
|
+
line_limit: line_limit, process_key: false, depth: depth + 1
|
38
|
+
)
|
39
|
+
|
40
|
+
item_count += 1
|
41
|
+
break if item_count >= lines - 2
|
42
|
+
end
|
43
|
+
|
44
|
+
if instance_variables.length > item_count
|
45
|
+
spans << [
|
46
|
+
RubyJard::Span.new(
|
47
|
+
content: "▸ #{instance_variables.length - item_count} more...",
|
48
|
+
margin_left: 2, styles: :text_dim
|
49
|
+
)
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
spans
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def native_inspect?(variable)
|
59
|
+
return true unless RubyJard::Reflection.call_respond_to?(variable, :inspect)
|
60
|
+
|
61
|
+
RubyJard::Reflection.bind_call(::Kernel, :method, variable, :inspect).owner == ::Kernel
|
62
|
+
end
|
63
|
+
|
64
|
+
def call_inspect(variable)
|
65
|
+
variable.inspect
|
66
|
+
rescue StandardError
|
67
|
+
RubyJard::Reflection.call_to_s(variable)
|
68
|
+
end
|
69
|
+
|
70
|
+
def decorate_native_inspection(variable, line_limit:, depth: 0, with_children: true)
|
71
|
+
raw_inspection = RubyJard::Reflection.call_to_s(variable)
|
72
|
+
match = raw_inspection.match(DEFAULT_INSPECTION_PATTERN)
|
73
|
+
|
74
|
+
if match
|
75
|
+
instance_variables = RubyJard::Reflection.call_instance_variables(variable)
|
76
|
+
spans = [
|
77
|
+
RubyJard::Span.new(content: '#<', styles: :text_primary),
|
78
|
+
RubyJard::Span.new(content: match[1], styles: :text_primary)
|
79
|
+
]
|
80
|
+
if with_children && !instance_variables.empty?
|
81
|
+
spans << RubyJard::Span.new(content: ' ', styles: :text_primary)
|
82
|
+
spans += @attributes_decorator.inline_pairs(
|
83
|
+
instance_variables.each_with_index, total: instance_variables.length,
|
84
|
+
line_limit: line_limit - spans.map(&:content_length).sum - 1,
|
85
|
+
depth: depth + 1, process_key: false,
|
86
|
+
value_proc: ->(key) { RubyJard::Reflection.call_instance_variable_get(variable, key) }
|
87
|
+
)
|
88
|
+
end
|
89
|
+
spans << RubyJard::Span.new(content: '>', styles: :text_primary)
|
90
|
+
spans
|
91
|
+
elsif raw_inspection.length <= line_limit
|
92
|
+
[RubyJard::Span.new(content: raw_inspection[0..line_limit], styles: :text_primary)]
|
93
|
+
else
|
94
|
+
[RubyJard::Span.new(content: raw_inspection[0..line_limit - 3] + '…>', styles: :text_primary)]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def decorate_custom_inspection(variable, line_limit:)
|
99
|
+
raw_inspection = call_inspect(variable)
|
100
|
+
match = raw_inspection.match(DEFAULT_INSPECTION_PATTERN)
|
101
|
+
if match
|
102
|
+
detail =
|
103
|
+
if match[2].length < line_limit - match[1].length - 3
|
104
|
+
match[2]
|
105
|
+
else
|
106
|
+
match[2][0..line_limit - match[1].length - 4] + '…'
|
107
|
+
end
|
108
|
+
[
|
109
|
+
RubyJard::Span.new(content: '#<', styles: :text_primary),
|
110
|
+
RubyJard::Span.new(content: match[1], styles: :text_primary),
|
111
|
+
RubyJard::Span.new(content: detail, styles: :text_dim),
|
112
|
+
RubyJard::Span.new(content: '>', styles: :text_primary)
|
113
|
+
]
|
114
|
+
elsif raw_inspection.length <= line_limit
|
115
|
+
[RubyJard::Span.new(content: raw_inspection[0..line_limit], styles: :text_primary)]
|
116
|
+
else
|
117
|
+
[RubyJard::Span.new(content: raw_inspection[0..line_limit - 3] + '…>', styles: :text_primary)]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -1,100 +1,83 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
+
require 'rbconfig'
|
4
5
|
|
5
6
|
module RubyJard
|
6
7
|
module Decorators
|
7
8
|
##
|
8
9
|
# Simplify and generate labels to indicate the location of a path.
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# 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.
|
12
12
|
class PathDecorator
|
13
|
-
|
14
|
-
|
15
|
-
TYPE_UNKNOWN = :unknown,
|
16
|
-
TYPE_PWD = :pwd,
|
17
|
-
TYPE_GEM = :gem
|
18
|
-
].freeze
|
19
|
-
|
20
|
-
attr_reader :path, :lineno, :gem, :gem_version
|
21
|
-
|
22
|
-
def initialize(path, lineno)
|
23
|
-
@gem = nil
|
24
|
-
@gem_version = nil
|
25
|
-
@path = path.to_s
|
26
|
-
@lineno = lineno
|
27
|
-
@type = TYPE_UNKNOWN
|
28
|
-
|
29
|
-
decorate
|
13
|
+
def initialize(path_classifier: nil)
|
14
|
+
@path_classifier = path_classifier || RubyJard::PathClassifier.new
|
30
15
|
end
|
31
16
|
|
32
|
-
def decorate
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
17
|
+
def decorate(path, lineno = nil)
|
18
|
+
return ['at ???', 'at ???'] if path.nil?
|
19
|
+
|
20
|
+
type, *info = @path_classifier.classify(path)
|
21
|
+
|
22
|
+
lineno = ":#{lineno}" unless lineno.nil?
|
23
|
+
|
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}"]
|
40
38
|
else
|
41
|
-
|
39
|
+
path = compact_with_relative_path(path)
|
40
|
+
["at #{path}#{lineno}", "#{path}#{lineno}"]
|
42
41
|
end
|
43
42
|
end
|
44
43
|
|
45
|
-
def gem?
|
46
|
-
@type == TYPE_GEM
|
47
|
-
end
|
48
|
-
|
49
44
|
private
|
50
45
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
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
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
match = GEM_PATTERN.match(@gem)
|
63
|
-
if match
|
64
|
-
@gem = match[1]
|
65
|
-
@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}>"
|
66
60
|
end
|
61
|
+
detail = "<#{gem_name}:#{relative_path}#{lineno}>"
|
62
|
+
["in #{overview}", detail]
|
63
|
+
end
|
67
64
|
|
68
|
-
|
69
|
-
|
65
|
+
def decorate_stdlib(_path, lineno, info)
|
66
|
+
lib_name, relative_path = info
|
67
|
+
|
68
|
+
["in <stdlib:#{lib_name}>", "<stdlib:#{relative_path}#{lineno}>"]
|
70
69
|
end
|
71
70
|
|
72
|
-
def
|
73
|
-
relative_path = Pathname.new(
|
74
|
-
if relative_path.length <
|
75
|
-
|
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
|
76
77
|
end
|
77
78
|
rescue ArgumentError
|
78
79
|
# Fail to get relative path, ignore
|
79
|
-
|
80
|
-
|
81
|
-
def gem_paths
|
82
|
-
paths = []
|
83
|
-
|
84
|
-
if defined?(Gem)
|
85
|
-
Gem.path.each do |gem_path|
|
86
|
-
paths << File.join(gem_path, 'gems')
|
87
|
-
paths << gem_path
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
if defined?(Bundler)
|
92
|
-
bundle_path = Bundler.bundle_path.to_s
|
93
|
-
paths << File.join(bundle_path, 'gems')
|
94
|
-
paths << bundle_path
|
95
|
-
end
|
96
|
-
|
97
|
-
paths
|
80
|
+
path
|
98
81
|
end
|
99
82
|
end
|
100
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
|