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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/workflows/documentation.yml +65 -0
  6. data/.github/workflows/rspec.yml +96 -0
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +90 -2
  9. data/CHANGELOG.md +112 -0
  10. data/Gemfile +14 -4
  11. data/README.md +95 -3
  12. data/benchmark/path_filter_bench.rb +58 -0
  13. data/bin/console +1 -2
  14. data/lib/ruby_jard.rb +68 -32
  15. data/lib/ruby_jard/box_drawer.rb +175 -0
  16. data/lib/ruby_jard/color_scheme.rb +28 -0
  17. data/lib/ruby_jard/color_schemes.rb +54 -0
  18. data/lib/ruby_jard/color_schemes/256_color_scheme.rb +50 -0
  19. data/lib/ruby_jard/color_schemes/256_light_color_scheme.rb +50 -0
  20. data/lib/ruby_jard/color_schemes/deep_space_color_scheme.rb +49 -0
  21. data/lib/ruby_jard/color_schemes/gruvbox_color_scheme.rb +48 -0
  22. data/lib/ruby_jard/color_schemes/one_half_dark_color_scheme.rb +47 -0
  23. data/lib/ruby_jard/color_schemes/one_half_light_color_scheme.rb +49 -0
  24. data/lib/ruby_jard/column.rb +26 -0
  25. data/lib/ruby_jard/commands/color_helpers.rb +32 -0
  26. data/lib/ruby_jard/commands/continue_command.rb +4 -9
  27. data/lib/ruby_jard/commands/down_command.rb +9 -8
  28. data/lib/ruby_jard/commands/exit_command.rb +27 -0
  29. data/lib/ruby_jard/commands/frame_command.rb +13 -11
  30. data/lib/ruby_jard/commands/jard/color_scheme_command.rb +74 -0
  31. data/lib/ruby_jard/commands/jard/filter_command.rb +136 -0
  32. data/lib/ruby_jard/commands/jard/hide_command.rb +40 -0
  33. data/lib/ruby_jard/commands/jard/output_command.rb +36 -0
  34. data/lib/ruby_jard/commands/jard/show_command.rb +41 -0
  35. data/lib/ruby_jard/commands/jard_command.rb +52 -0
  36. data/lib/ruby_jard/commands/list_command.rb +31 -0
  37. data/lib/ruby_jard/commands/next_command.rb +11 -8
  38. data/lib/ruby_jard/commands/step_command.rb +11 -8
  39. data/lib/ruby_jard/commands/step_out_command.rb +34 -0
  40. data/lib/ruby_jard/commands/up_command.rb +10 -8
  41. data/lib/ruby_jard/commands/validation_helpers.rb +50 -0
  42. data/lib/ruby_jard/config.rb +61 -0
  43. data/lib/ruby_jard/console.rb +158 -0
  44. data/lib/ruby_jard/control_flow.rb +73 -0
  45. data/lib/ruby_jard/decorators/array_decorator.rb +79 -0
  46. data/lib/ruby_jard/decorators/attributes_decorator.rb +172 -0
  47. data/lib/ruby_jard/decorators/color_decorator.rb +80 -0
  48. data/lib/ruby_jard/decorators/hash_decorator.rb +74 -0
  49. data/lib/ruby_jard/decorators/inspection_decorator.rb +109 -0
  50. data/lib/ruby_jard/decorators/loc_decorator.rb +108 -119
  51. data/lib/ruby_jard/decorators/object_decorator.rb +122 -0
  52. data/lib/ruby_jard/decorators/path_decorator.rb +56 -60
  53. data/lib/ruby_jard/decorators/rails_decorator.rb +194 -0
  54. data/lib/ruby_jard/decorators/source_decorator.rb +3 -1
  55. data/lib/ruby_jard/decorators/string_decorator.rb +41 -0
  56. data/lib/ruby_jard/decorators/struct_decorator.rb +79 -0
  57. data/lib/ruby_jard/frame.rb +68 -0
  58. data/lib/ruby_jard/key_binding.rb +14 -0
  59. data/lib/ruby_jard/key_bindings.rb +96 -0
  60. data/lib/ruby_jard/keys.rb +48 -0
  61. data/lib/ruby_jard/layout.rb +17 -88
  62. data/lib/ruby_jard/layout_calculator.rb +168 -0
  63. data/lib/ruby_jard/layout_picker.rb +34 -0
  64. data/lib/ruby_jard/layouts.rb +52 -0
  65. data/lib/ruby_jard/layouts/narrow_horizontal_layout.rb +32 -0
  66. data/lib/ruby_jard/layouts/narrow_vertical_layout.rb +32 -0
  67. data/lib/ruby_jard/layouts/tiny_layout.rb +29 -0
  68. data/lib/ruby_jard/layouts/wide_layout.rb +50 -0
  69. data/lib/ruby_jard/pager.rb +112 -0
  70. data/lib/ruby_jard/path_classifier.rb +133 -0
  71. data/lib/ruby_jard/path_filter.rb +125 -0
  72. data/lib/ruby_jard/reflection.rb +97 -0
  73. data/lib/ruby_jard/repl_processor.rb +151 -89
  74. data/lib/ruby_jard/repl_proxy.rb +337 -0
  75. data/lib/ruby_jard/row.rb +31 -0
  76. data/lib/ruby_jard/row_renderer.rb +119 -0
  77. data/lib/ruby_jard/screen.rb +14 -41
  78. data/lib/ruby_jard/screen_adjuster.rb +104 -0
  79. data/lib/ruby_jard/screen_drawer.rb +25 -0
  80. data/lib/ruby_jard/screen_manager.rb +167 -82
  81. data/lib/ruby_jard/screen_renderer.rb +152 -0
  82. data/lib/ruby_jard/screens.rb +31 -12
  83. data/lib/ruby_jard/screens/backtrace_screen.rb +118 -116
  84. data/lib/ruby_jard/screens/menu_screen.rb +73 -45
  85. data/lib/ruby_jard/screens/source_screen.rb +86 -106
  86. data/lib/ruby_jard/screens/threads_screen.rb +103 -78
  87. data/lib/ruby_jard/screens/variables_screen.rb +224 -142
  88. data/lib/ruby_jard/session.rb +151 -16
  89. data/lib/ruby_jard/span.rb +23 -0
  90. data/lib/ruby_jard/templates/layout_template.rb +35 -0
  91. data/lib/ruby_jard/templates/screen_template.rb +34 -0
  92. data/lib/ruby_jard/thread_info.rb +69 -0
  93. data/lib/ruby_jard/version.rb +1 -1
  94. data/ruby_jard.gemspec +7 -8
  95. metadata +84 -50
  96. data/.travis.yml +0 -6
  97. data/lib/ruby_jard/commands/finish_command.rb +0 -31
  98. data/lib/ruby_jard/decorators/text_decorator.rb +0 -61
  99. data/lib/ruby_jard/layout_template.rb +0 -101
  100. data/lib/ruby_jard/screens/breakpoints_screen.rb +0 -23
  101. data/lib/ruby_jard/screens/empty_screen.rb +0 -13
  102. data/lib/ruby_jard/screens/expressions_sreen.rb +0 -22
@@ -3,26 +3,27 @@
3
3
  module RubyJard
4
4
  module Commands
5
5
  # Command used to explore stacktrace.
6
- # Data attached in the throw:
7
- # * command: constant symbol (:down)
8
- # * pry: current context pry instance
9
6
  class DownCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ValidationHelpers
8
+
10
9
  group 'RubyJard'
11
10
  description 'Explore the frames bellow the current stopped line in the backtrace'
12
11
 
13
12
  match 'down'
14
13
 
15
14
  banner <<-BANNER
16
- Usage: down
17
-
18
- Explore the frames bellow the current stopped line in the backtrace.
19
-
15
+ Usage: down [-h] [times]
20
16
  Examples:
21
17
  down
18
+ down 1
19
+ down 7
20
+
21
+ Explore the frames bellow the current stopped line in the backtrace. All the C frames will be skipped.
22
22
  BANNER
23
23
 
24
24
  def process
25
- throw :control_flow, command: :down, pry: pry_instance
25
+ times = validate_positive_integer!(args.first || 1)
26
+ RubyJard::ControlFlow.dispatch(:down, times: times.to_i)
26
27
  end
27
28
  end
28
29
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ # Command used to exit program execution.
6
+ class ExitCommand < Pry::ClassCommand
7
+ group 'RubyJard'
8
+ description 'Exit program execution.'
9
+
10
+ match 'exit'
11
+
12
+ banner <<-BANNER
13
+ Usage: exit
14
+ Examples:
15
+ exit
16
+
17
+ Exit program execution. The program will stop at the next breakpoint, or run until it finishes.
18
+ BANNER
19
+
20
+ def process
21
+ RubyJard::ControlFlow.dispatch(:exit)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Pry::Commands.add_command(RubyJard::Commands::ExitCommand)
@@ -3,31 +3,33 @@
3
3
  module RubyJard
4
4
  module Commands
5
5
  # Command used to explore stacktrace.
6
- # Data attached in the throw:
7
- # * command: constant symbol (:frame)
8
- # * pry: current context pry instance
9
- # * frame (optional): frame id of the destination frame
10
6
  class FrameCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ValidationHelpers
8
+
11
9
  group 'RubyJard'
12
10
  description 'Explore to any frame of current stacktrace.'
13
11
 
14
12
  match 'frame'
15
13
 
16
14
  banner <<-BANNER
17
- Usage: frame
15
+ Usage: frame [FRAME_ID]
18
16
 
19
17
  Explore to any frame of current stacktrace.
20
18
 
21
19
  Examples:
22
- frame [FRAME_ID]
20
+ frame 4 # Jump to frame 4 in the backtrace
23
21
  BANNER
24
22
 
23
+ def initialize(context = {})
24
+ super(context)
25
+ @current_backtrace = (context[:session] || RubyJard::Session).current_backtrace
26
+ end
27
+
25
28
  def process
26
- throw :control_flow,
27
- command: :frame,
28
- pry: pry_instance,
29
- # TODO: Remove redundant options
30
- options: { frame: args.first }
29
+ frame = validate_present!(args.first)
30
+ frame = validate_non_negative_integer!(frame)
31
+ frame = validate_range!(frame, 0, @current_backtrace.map(&:virtual_pos).compact.max)
32
+ RubyJard::ControlFlow.dispatch(:frame, frame: frame)
31
33
  end
32
34
  end
33
35
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ # Command used to explore stacktrace.
6
+ class ColorSchemeCommand < Pry::ClassCommand
7
+ include RubyJard::Commands::ColorHelpers
8
+
9
+ group 'RubyJard'
10
+ description 'Control the color scheme used in Jard'
11
+
12
+ match 'color-scheme'
13
+
14
+ banner <<-BANNER
15
+ Usage: color-scheme -l
16
+ color-scheme [scheme-name]
17
+ BANNER
18
+
19
+ def initialize(context = {})
20
+ super(context)
21
+ @color_schemes = context[:color_schemes] || RubyJard::ColorSchemes
22
+ @config = context[:config] || RubyJard.config
23
+ end
24
+
25
+ def options(opt)
26
+ opt.on :l, :list, 'List all available color schemes'
27
+ end
28
+
29
+ def process
30
+ if opts[:l]
31
+ if @color_schemes.names.empty?
32
+ pry_instance.output.puts 'No loaded color schemes'
33
+ else
34
+ print_color_schemes
35
+ end
36
+ else
37
+ color_scheme = args.first.to_s.strip
38
+ if color_scheme.empty?
39
+ raise Pry::CommandError,
40
+ 'You must provide a color scheme name. '\
41
+ "Please use `#{highlight('jard color-scheme -l')}` to list all color schemes."
42
+ end
43
+
44
+ if @color_schemes[color_scheme].nil?
45
+ raise Pry::CommandError,
46
+ "Color scheme `#{secondary(color_scheme)}` not found. "\
47
+ "Please use `#{highlight('jard color-scheme -l')}` to list all color schemes."
48
+ end
49
+
50
+ @config.color_scheme = color_scheme
51
+ RubyJard::ControlFlow.dispatch(:list)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def print_color_schemes
58
+ pry_instance.output.puts
59
+ pry_instance.output.puts highlight("#{@color_schemes.names.length} available color schemes")
60
+ pry_instance.output.puts
61
+ padding = @color_schemes.names.map(&:length).max
62
+ @color_schemes.names.each do |name|
63
+ scheme = @color_schemes[name]
64
+ decorator = RubyJard::Decorators::ColorDecorator.new(scheme.new)
65
+ pallete = scheme.const_get(:STYLES).keys.map do |style|
66
+ decorator.decorate(style, '⬤ ')
67
+ end.join(' ')
68
+ pry_instance.output.puts "#{name.ljust(padding)} #{pallete}"
69
+ pry_instance.output.puts
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Control filter, included and excluded
7
+ class FilterCommand < Pry::ClassCommand
8
+ include RubyJard::Commands::ColorHelpers
9
+
10
+ group 'RubyJard'
11
+ description 'Filter to keep only relevant location when you debugging'
12
+
13
+ match 'filter'
14
+
15
+ banner <<-BANNER
16
+ Usage:
17
+ jard filter
18
+ jard filter [everything, gems, application, source_tree]
19
+ jard filter [include, exclude] pattern
20
+ jard filter clear
21
+
22
+ Ruby Jard has a strong filtering system. This system consists of a filter mode, included list, and excluded list. Filter mode is how Ruby Jard reacts to control flow commands. See https://rubyjard.org/docs/guides/filter for more information.
23
+
24
+ Examples:
25
+
26
+ jard filter # Show filter status
27
+
28
+ jard filter application # Switch to application mode
29
+ jard filter gems # Switch to gems mode
30
+ jard filter everything # Switch to everything mode
31
+ jard filter source_tree # Switch to source tree mode
32
+
33
+ jard filter include sidekiq # Include sidekiq pattern
34
+ jard filter include aws-*
35
+ jard filter include aws-* active* action* # Multiple patterns separated by <space>
36
+ jard filter include lib/**/*.erb
37
+ jard filter include ~/home/lib/**/*.rb
38
+
39
+ jard filter exclude sidekiq # exclude sidekiq pattern
40
+ jard filter exclude aws-*
41
+ jard filter exclude aws-* active* action* # Multiple patterns separated by <space>
42
+ jard filter exclude lib/**/*.erb
43
+ jard filter exclude ~/home/lib/**/*.rb
44
+
45
+ jard filter clear # Clear filter
46
+ BANNER
47
+
48
+ def initialize(*args)
49
+ super(*args)
50
+ @filters = RubyJard::PathFilter::FILTERS
51
+ @config = context[:config] || RubyJard.config
52
+ end
53
+
54
+ def process
55
+ if args.empty?
56
+ print_current_filter
57
+ return
58
+ end
59
+
60
+ sub_command = args.shift.to_sym
61
+
62
+ case sub_command
63
+ when *@filters
64
+ @config.filter = sub_command
65
+ RubyJard::ControlFlow.dispatch(:list)
66
+ when :include
67
+ handle_included
68
+ when :exclude
69
+ handle_excluded
70
+ when :clear
71
+ handle_clear
72
+ else
73
+ raise Pry::CommandError,
74
+ "Invalid filter '#{secondary(sub_command)}'."\
75
+ "Please type `#{highlight('jard filter --help')}` for more information"
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def print_current_filter
82
+ pry_instance.output.puts
83
+ pry_instance.output.puts highlight('Filter mode')
84
+ pry_instance.output.puts " #{@config.filter}"
85
+ pry_instance.output.puts highlight("Included (#{@config.filter_included.length})")
86
+ @config.filter_included.each do |included|
87
+ pry_instance.output.puts " +#{included}"
88
+ end
89
+
90
+ pry_instance.output.puts highlight("Excluded (#{@config.filter_excluded.length})")
91
+ @config.filter_excluded.each do |excluded|
92
+ pry_instance.output.puts " -#{excluded}"
93
+ end
94
+ pry_instance.output.puts
95
+ pry_instance.output.puts "Please type `#{highlight('jard filter --help')}` for more information"
96
+ pry_instance.output.puts
97
+ end
98
+
99
+ def handle_included
100
+ if args.empty?
101
+ raise Pry::CommandError,
102
+ 'Wrong number of arguments! '\
103
+ "Please type `#{highlight('jard filter --help')}` for more information"
104
+ end
105
+ filters = args.map(&:strip)
106
+ @config.filter_included.append(*filters)
107
+ @config.filter_included.uniq!
108
+ filters.each do |filter|
109
+ @config.filter_excluded.delete(filter) if @config.filter_excluded.include?(filter)
110
+ end
111
+ RubyJard::ControlFlow.dispatch(:list)
112
+ end
113
+
114
+ def handle_excluded
115
+ if args.empty?
116
+ raise Pry::CommandError,
117
+ 'Wrong number of arguments!'\
118
+ "Please type `#{highlight('jard filter --help')}` for more information"
119
+ end
120
+ filters = args.map(&:strip)
121
+ @config.filter_excluded.append(*filters)
122
+ @config.filter_excluded.uniq!
123
+ filters.each do |filter|
124
+ @config.filter_included.delete(filter) if @config.filter_included.include?(filter)
125
+ end
126
+ RubyJard::ControlFlow.dispatch(:list)
127
+ end
128
+
129
+ def handle_clear
130
+ @config.filter_excluded.clear
131
+ @config.filter_included.clear
132
+ RubyJard::ControlFlow.dispatch(:list)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Show a screen
7
+ class HideCommand < Pry::ClassCommand
8
+ description 'Hide a screen'
9
+ banner <<-BANNER
10
+ Usage: jard hide [-h] [screen]
11
+ BANNER
12
+ match 'hide'
13
+
14
+ def initialize(context = {})
15
+ super(context)
16
+
17
+ @screens = context[:screens] || RubyJard::Screens
18
+ @config = context[:config] || RubyJard.config
19
+ end
20
+
21
+ def process
22
+ screen = args.first.to_s.strip
23
+
24
+ if screen.empty?
25
+ raise Pry::CommandError,
26
+ "Please input one of the following: #{@screens.names.join(', ')}"
27
+ end
28
+
29
+ unless @screens.names.include?(screen)
30
+ raise Pry::CommandError,
31
+ "Screen `#{screen}` not found. Please input one of the following: #{@screens.names.join(', ')}"
32
+ end
33
+
34
+ @config.enabled_screens.delete(screen)
35
+
36
+ RubyJard::ControlFlow.dispatch(:list)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ # Command used to explore stacktrace.
6
+ class OutputCommand < Pry::ClassCommand
7
+ group 'RubyJard'
8
+ description 'Show all current program output'
9
+
10
+ match 'output'
11
+
12
+ banner <<-BANNER
13
+ Usage: output
14
+ BANNER
15
+
16
+ def initialize(*args)
17
+ super(*args)
18
+ @session = (context[:session] || RubyJard::Session)
19
+ end
20
+
21
+ def process
22
+ pry_instance.pager.open(
23
+ force_open: true,
24
+ pager_start_at_the_end: true,
25
+ prompt: 'Program output'
26
+ ) do |pager|
27
+ @session.output_buffer.each do |string|
28
+ string.each do |s|
29
+ pager.write(s)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyJard
4
+ module Commands
5
+ ##
6
+ # Show a screen
7
+ class ShowCommand < Pry::ClassCommand
8
+ description 'Show a screen'
9
+ banner <<-BANNER
10
+ Usage: jard show [-h] [screen]
11
+ BANNER
12
+ match 'show'
13
+
14
+ def initialize(context = {})
15
+ super(context)
16
+
17
+ @screens = context[:screens] || RubyJard::Screens
18
+ @config = context[:config] || RubyJard.config
19
+ end
20
+
21
+ def process
22
+ screen = args.first.to_s.strip
23
+
24
+ if screen.empty?
25
+ raise Pry::CommandError,
26
+ "Please input one of the following: #{@screens.names.join(', ')}"
27
+ end
28
+
29
+ unless @screens.names.include?(screen)
30
+ raise Pry::CommandError,
31
+ "Screen `#{screen}` not found. Please input one of the following: #{@screens.names.join(', ')}"
32
+ end
33
+
34
+ @config.enabled_screens << screen
35
+ @config.enabled_screens.uniq!
36
+
37
+ RubyJard::ControlFlow.dispatch(:list)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ruby_jard/commands/jard/show_command'
4
+ require 'ruby_jard/commands/jard/hide_command'
5
+ require 'ruby_jard/commands/jard/color_scheme_command'
6
+ require 'ruby_jard/commands/jard/output_command'
7
+ require 'ruby_jard/commands/jard/filter_command'
8
+
9
+ module RubyJard
10
+ module Commands
11
+ # Command used to explore stacktrace.
12
+ class JardCommand < Pry::ClassCommand
13
+ group 'RubyJard'
14
+ description 'Show all current program output'
15
+
16
+ match 'jard'
17
+
18
+ banner <<-BANNER
19
+ Usage: jard [-h] [sub commands]
20
+ BANNER
21
+
22
+ SUB_COMMANDS = {
23
+ 'show' => RubyJard::Commands::ShowCommand,
24
+ 'hide' => RubyJard::Commands::HideCommand,
25
+ 'color-scheme' => RubyJard::Commands::ColorSchemeCommand,
26
+ 'output' => RubyJard::Commands::OutputCommand,
27
+ 'filter' => RubyJard::Commands::FilterCommand
28
+ }.freeze
29
+
30
+ def subcommands(cmd)
31
+ SUB_COMMANDS.each do |command_name, sub_command|
32
+ cmd.command command_name do |opt|
33
+ opt.description sub_command.description
34
+ opt.run do |_, arguments|
35
+ @ran_sub_command = true
36
+ sub_command.new(context).send(:call_safely, *arguments)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def process
43
+ return if @ran_sub_command
44
+ return if ['-h', '--help'].include?(args.first) || SUB_COMMANDS.keys.include?(args.first)
45
+
46
+ pry_instance.output.puts help
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ Pry::Commands.add_command(RubyJard::Commands::JardCommand)