rshade 0.1.7 → 0.1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/Gemfile.lock +23 -22
- data/README.md +74 -19
- data/html/template.html.erb +72 -0
- data/lib/rshade/config/store.rb +46 -0
- data/lib/rshade/config.rb +76 -0
- data/lib/rshade/core_extensions/object/reveal.rb +8 -0
- data/lib/rshade/event.rb +35 -14
- data/lib/rshade/event_observer.rb +45 -0
- data/lib/rshade/event_processor.rb +36 -0
- data/lib/rshade/event_tree.rb +75 -0
- data/lib/rshade/filter/abstract_filter.rb +26 -0
- data/lib/rshade/filter/default.rb +28 -0
- data/lib/rshade/filter/exclude_path_filter.rb +25 -0
- data/lib/rshade/filter/filter_builder.rb +28 -0
- data/lib/rshade/filter/filter_composition.rb +57 -0
- data/lib/rshade/filter/include_path_filter.rb +43 -0
- data/lib/rshade/filter/variable_filter.rb +33 -0
- data/lib/rshade/formatter/file.rb +28 -0
- data/lib/rshade/formatter/html.rb +33 -0
- data/lib/rshade/formatter/json.rb +15 -26
- data/lib/rshade/formatter/stdout.rb +3 -3
- data/lib/rshade/formatter/string.rb +17 -11
- data/lib/rshade/serializer/traversal.rb +47 -0
- data/lib/rshade/trace.rb +19 -39
- data/lib/rshade/trace_observable.rb +40 -0
- data/lib/rshade/version.rb +1 -1
- data/lib/rshade.rb +21 -22
- data/rshade.gemspec +1 -1
- metadata +25 -14
- data/lib/rshade/base.rb +0 -13
- data/lib/rshade/configuration.rb +0 -39
- data/lib/rshade/event_serializer.rb +0 -29
- data/lib/rshade/event_store.rb +0 -23
- data/lib/rshade/filter/app_filter.rb +0 -20
- data/lib/rshade/formatter/http.rb +0 -8
- data/lib/rshade/storage.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91ab4d11c9af8066bff925ab208f10e20c5bf7fd5685418b0c8ef01880c13d2f
|
4
|
+
data.tar.gz: 7c0e95c99b1707e5290440cf3459e02cd465c653bdbfbfdc3f216d77a3647c66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21fe1fa50bf9c63261fbed6651ad8999edc22734567c3f33b2ba872ba95640cb70b3cff8fa0c640fd13faa8cf73371bb107ee8d0303e3e1322bba06a87f30d58
|
7
|
+
data.tar.gz: 2b657588399858bcc1aa9f60cac2baf92ea3427b341542c40f15c7a7a26cbfb17cabfa3b98a2c5465c1905a3c8dfeb9500ed772351d89bdd7c2b6ca3ac223392
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,43 +1,44 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rshade (0.1.
|
4
|
+
rshade (0.1.9.1)
|
5
5
|
colorize
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
coderay (1.1.
|
10
|
+
coderay (1.1.3)
|
11
11
|
colorize (0.8.1)
|
12
|
-
diff-lcs (1.
|
13
|
-
method_source (0.
|
14
|
-
pry (0.
|
15
|
-
coderay (~> 1.1
|
16
|
-
method_source (~>
|
17
|
-
rake (13.0.
|
18
|
-
rspec (3.
|
19
|
-
rspec-core (~> 3.
|
20
|
-
rspec-expectations (~> 3.
|
21
|
-
rspec-mocks (~> 3.
|
22
|
-
rspec-core (3.
|
23
|
-
rspec-support (~> 3.
|
24
|
-
rspec-expectations (3.
|
12
|
+
diff-lcs (1.5.0)
|
13
|
+
method_source (1.0.0)
|
14
|
+
pry (0.14.1)
|
15
|
+
coderay (~> 1.1)
|
16
|
+
method_source (~> 1.0)
|
17
|
+
rake (13.0.6)
|
18
|
+
rspec (3.11.0)
|
19
|
+
rspec-core (~> 3.11.0)
|
20
|
+
rspec-expectations (~> 3.11.0)
|
21
|
+
rspec-mocks (~> 3.11.0)
|
22
|
+
rspec-core (3.11.0)
|
23
|
+
rspec-support (~> 3.11.0)
|
24
|
+
rspec-expectations (3.11.0)
|
25
25
|
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
-
rspec-support (~> 3.
|
27
|
-
rspec-mocks (3.
|
26
|
+
rspec-support (~> 3.11.0)
|
27
|
+
rspec-mocks (3.11.0)
|
28
28
|
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
-
rspec-support (~> 3.
|
30
|
-
rspec-support (3.
|
29
|
+
rspec-support (~> 3.11.0)
|
30
|
+
rspec-support (3.11.0)
|
31
31
|
|
32
32
|
PLATFORMS
|
33
|
-
|
33
|
+
x86_64-darwin-19
|
34
|
+
x86_64-darwin-20
|
34
35
|
|
35
36
|
DEPENDENCIES
|
36
|
-
bundler (~>
|
37
|
+
bundler (~> 2.2.33)
|
37
38
|
pry
|
38
39
|
rake (>= 12.3.3)
|
39
40
|
rshade!
|
40
41
|
rspec (~> 3.0)
|
41
42
|
|
42
43
|
BUNDLED WITH
|
43
|
-
|
44
|
+
2.2.33
|
data/README.md
CHANGED
@@ -2,20 +2,82 @@
|
|
2
2
|
|
3
3
|
![warcraft shade](https://github.com/gingray/rshade/raw/master/shade.jpg)
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
RShade is a debugging/code exploration tool based on `TracePoint` functionality.
|
6
|
+
Recent years I've working with relatively huge legacy code and I need a tool which can help me to figure out what is going on due execution.
|
7
|
+
Luckely Ruby have build in functionality to achieve it, but it's pretty low level. It was my motivation to create `RShade` it helps me to save tons of time
|
8
|
+
when I face with something not trivial or a good start point to create dependency map when I do refactoring or bugfix. Tool still in beta and it's possible that there
|
9
|
+
is some bugs, but it's do the job.
|
10
|
+
|
11
|
+
## How it works?
|
12
|
+
```shell
|
13
|
+
gem install rshade
|
14
|
+
```
|
15
|
+
Simple wrap code that you want to check in to block and it will pretty print all of the calls which was made in this block with pointing line of executions, variables what was pass
|
16
|
+
inside methods and variables what was return
|
7
17
|
```ruby
|
8
|
-
|
18
|
+
RShade::Trace.reveal do
|
9
19
|
#your code here
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
20
|
+
end.show
|
21
|
+
```
|
22
|
+
Due that tool create a detailed log with all of the steps of execution it's hard to read (it's can easelly be 20 - 30k lines because it's shows not only your custom code but also
|
23
|
+
code in gems that are involved in execution). `RShade` have filters to tackle this problem. Default filter is illiminate all code related to gems and only expose app code itself. You can
|
24
|
+
change this behaviour or add your own filter. Even when some piece of code are not shown due filtration order of calls and execution still shown in correct way.
|
25
|
+
|
26
|
+
## Table of Contents
|
27
|
+
- [Configuration](#configuration)
|
28
|
+
- [Filters](#filters)
|
29
|
+
- [Filter by path include](#filter-by-path-include)
|
30
|
+
- [Filter by path exclude](#filter-by-path-exclude)
|
31
|
+
- [Filter by variable name or value](#filter-by-variable-name-or-value)
|
32
|
+
- [Examples](#examples)
|
33
|
+
|
34
|
+
### Configuration
|
35
|
+
```ruby
|
36
|
+
config = ::RShade::Config.default
|
37
|
+
|
38
|
+
RShade::Trace.reveal(config) do
|
39
|
+
end.show
|
40
|
+
```
|
41
|
+
### Filters
|
42
|
+
Filters by default represent by expression `(include_path or variable_match) or (not exclude_path)`
|
43
|
+
Filters can be chained like:
|
44
|
+
```ruby
|
45
|
+
config = ::RShade::Config.default.include_paths { |paths| paths << /devise/ }
|
46
|
+
.exclude_paths { |paths| paths << /warden/ }
|
47
|
+
.match_variable { |name, value| name == :current_user }
|
48
|
+
```
|
49
|
+
#### Filter by path include
|
50
|
+
`paths` - is array which accept regex or string
|
51
|
+
```ruby
|
52
|
+
config = ::RShade::Config.default.include_paths { |paths| paths << /devise/ }
|
53
|
+
|
54
|
+
RShade::Trace.reveal(config) do
|
55
|
+
#your code
|
56
|
+
end.show
|
16
57
|
|
17
58
|
```
|
18
|
-
|
59
|
+
#### Filter by path exclude
|
60
|
+
`paths` - is array which accept regex or string
|
61
|
+
```ruby
|
62
|
+
config = ::RShade::Config.default.exclude_paths { |paths| paths << /devise/ }
|
63
|
+
|
64
|
+
RShade::Trace.reveal(config) do
|
65
|
+
#your code
|
66
|
+
end.show
|
67
|
+
```
|
68
|
+
|
69
|
+
#### Filter by variable name or value
|
70
|
+
`name` - represent variable name as symbol
|
71
|
+
`value` - actual variable value
|
72
|
+
```ruby
|
73
|
+
config = ::RShade::Config.default.match_variable { |name, value| name == :current_user }
|
74
|
+
|
75
|
+
RShade::Trace.reveal(config) do
|
76
|
+
#your code
|
77
|
+
end.show
|
78
|
+
```
|
79
|
+
|
80
|
+
## Examples
|
19
81
|
I've took example from https://github.com/spree/spree code base. Wrap code to take a look what code is in use when you save variant.
|
20
82
|
On such huge codebase as spree it's helpful to know what callbacks are triggered and so on.
|
21
83
|
```ruby
|
@@ -24,7 +86,7 @@ On such huge codebase as spree it's helpful to know what callbacks are triggered
|
|
24
86
|
before { variant.cost_currency = nil }
|
25
87
|
|
26
88
|
it 'populates cost currency with the default value on save', focus: true do
|
27
|
-
|
89
|
+
RShade::Trace.reveal do
|
28
90
|
variant.save!
|
29
91
|
end
|
30
92
|
expect(variant.cost_currency).to eql 'USD'
|
@@ -32,18 +94,11 @@ On such huge codebase as spree it's helpful to know what callbacks are triggered
|
|
32
94
|
end
|
33
95
|
end
|
34
96
|
```
|
97
|
+
|
35
98
|
Below is example how output will look like.
|
36
99
|
As you can see all code that have been in use is printed.
|
37
100
|
[![asciicast](https://asciinema.org/a/MR5KL7TmHmYRUhwBUWQjBI373.svg)](https://asciinema.org/a/MR5KL7TmHmYRUhwBUWQjBI373)
|
38
101
|
|
39
|
-
## Installation
|
40
|
-
|
41
|
-
Add this line to your application's Gemfile:
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
gem 'rshade'
|
45
|
-
```
|
46
|
-
|
47
102
|
## TODO
|
48
103
|
Use stack to keep connections between current method and caller
|
49
104
|
take a look on https://github.com/matugm/visual-call-graph
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
|
3
|
+
<html lang="en">
|
4
|
+
<head>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<title>RShade call trace viewer</title>
|
7
|
+
<meta name="description" content="The HTML5 Herald">
|
8
|
+
<meta name="author" content="me">
|
9
|
+
<style>
|
10
|
+
body {
|
11
|
+
overflow-x: scroll;
|
12
|
+
}
|
13
|
+
.stacktrace-line {
|
14
|
+
color: #1c1c1c;
|
15
|
+
font-family: monospace;
|
16
|
+
border: 1px solid hsla(210,50%, 50%, 1);
|
17
|
+
margin-bottom: 10px;
|
18
|
+
width: fit-content;
|
19
|
+
}
|
20
|
+
.method-line {
|
21
|
+
font-size: 1.2rem;
|
22
|
+
padding: 10px;
|
23
|
+
background: hsla(210,50%, 50%, 0.1);
|
24
|
+
}
|
25
|
+
|
26
|
+
.path-line {
|
27
|
+
padding: 10px;
|
28
|
+
font-size: 0.9rem;
|
29
|
+
background: hsla(110,50%, 50%, 0.1);
|
30
|
+
}
|
31
|
+
|
32
|
+
.vars-line {
|
33
|
+
font-size: 0.7rem;
|
34
|
+
padding: 10px;
|
35
|
+
background: hsla(60,50%, 50%, 0.1);
|
36
|
+
}
|
37
|
+
|
38
|
+
</style>
|
39
|
+
</head>
|
40
|
+
<body>
|
41
|
+
<div class="stacktrace"></div>
|
42
|
+
<script>
|
43
|
+
var data = <%=json %>;
|
44
|
+
var el = document.querySelector(".stacktrace");
|
45
|
+
for(i=0; i < data.length; i++) {
|
46
|
+
var value = data[i];
|
47
|
+
var newEl = document.createElement('div');
|
48
|
+
newEl.setAttribute("class", "stacktrace-line");
|
49
|
+
newEl.style.marginLeft = `${value.depth * 10}px`
|
50
|
+
|
51
|
+
line1 = document.createElement('div');
|
52
|
+
line1.setAttribute("class", "method-line");
|
53
|
+
line1.innerText = `${value.class}#${value.method_name}`;
|
54
|
+
|
55
|
+
var line2 = document.createElement('div');
|
56
|
+
line2.setAttribute("class", "path-line");
|
57
|
+
line2.innerText = `${value.class}#${value.full_path}`;
|
58
|
+
|
59
|
+
var line3 = document.createElement('div');
|
60
|
+
line3.setAttribute("class", "vars-line");
|
61
|
+
line3.innerText = JSON.stringify(value.vars)
|
62
|
+
|
63
|
+
newEl.appendChild(line1);
|
64
|
+
newEl.appendChild(line2);
|
65
|
+
newEl.appendChild(line3);
|
66
|
+
el.appendChild(newEl)
|
67
|
+
}
|
68
|
+
console.log(data);
|
69
|
+
</script>
|
70
|
+
|
71
|
+
</body>
|
72
|
+
</html>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module RShade
|
3
|
+
class Config
|
4
|
+
class Store
|
5
|
+
attr_reader :filter_composition, :formatter, :tp_events, :custom_serializers
|
6
|
+
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [RShade::Filter::FilterComposition] :filter_composition
|
9
|
+
# @option options [#call(event_store)] :formatter
|
10
|
+
# @option options [Array<Symbol>] :tp_events
|
11
|
+
def initialize(options={})
|
12
|
+
@filter_composition = options.fetch(:filter_composition, default_filter_composition)
|
13
|
+
@formatter = options.fetch(:formatter, ::RShade::Formatter::Stdout)
|
14
|
+
@tp_events = options.fetch(:tp_events, [:call, :return])
|
15
|
+
@custom_serializers = options.fetch(:custom_serializers, {})
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_tp_events(tp_events)
|
19
|
+
@tp_events = tp_events
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_custom_serializers(hash)
|
24
|
+
custom_serializers.merge!(hash)
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def config_filter(filter_type, &block)
|
30
|
+
filter_composition.config_filter(filter_type, &block)
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_formatter(formatter)
|
35
|
+
@formatter = formatter
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def default_filter_composition
|
42
|
+
RShade::Filter::FilterBuilder.build([:or,[:or, RShade::Filter::VariableFilter.new, RShade::Filter::IncludePathFilter.new] , RShade::Filter::ExcludePathFilter.new])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module RShade
|
2
|
+
class Config
|
3
|
+
RUBY_VERSION_PATTERN = /ruby-[0-9.]*/
|
4
|
+
|
5
|
+
def self.default
|
6
|
+
::RShade::Config::Store.new.set_formatter(::RShade::Formatter::Stdout.new)
|
7
|
+
.config_filter(::RShade::Filter::ExcludePathFilter) do |paths|
|
8
|
+
default_excluded_path.each do |path|
|
9
|
+
paths << path
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [RShade::Config::Store] config_store
|
15
|
+
def initialize(config_store)
|
16
|
+
@config_store = config_store
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param [Hash] options
|
20
|
+
# @option options [RShade::Filter::FilterComposition] :filter_composition
|
21
|
+
# @option options [#call(event_store)] :formatter
|
22
|
+
# @option options [Array<Symbol>] :tp_events
|
23
|
+
def self.create(options={})
|
24
|
+
new(Config::Store.new(options))
|
25
|
+
end
|
26
|
+
|
27
|
+
def tp_events(&block)
|
28
|
+
events = block.call
|
29
|
+
@config_store.set_tp_events(events)
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def include_paths(&block)
|
34
|
+
@config_store.config_filter(::RShade::Filter::IncludePathFilter, &block)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def exclude_paths(&block)
|
39
|
+
@config_store.config_filter(::RShade::Filter::ExcludePathFilter, &block)
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def match_variable(&block)
|
44
|
+
@config_store.config_filter(::RShade::Filter::VariableFilter, &block)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def formatter(&block)
|
49
|
+
formatter = block.call
|
50
|
+
@config_store.set_formatter(formatter)
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_custom_serializers(hash)
|
55
|
+
@config_store.add_custom_serializers(hash)
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def value
|
60
|
+
@config_store
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.store_dir
|
64
|
+
File.expand_path('../../tmp', __dir__)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.root_dir
|
68
|
+
@root_dir ||= File.expand_path('../../', __dir__)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
def self.default_excluded_path
|
73
|
+
[ENV['GEM_PATH'].split(':'), RUBY_VERSION_PATTERN, /internal/].flatten.compact
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/rshade/event.rb
CHANGED
@@ -1,35 +1,56 @@
|
|
1
1
|
module RShade
|
2
2
|
# nodoc
|
3
3
|
class Event
|
4
|
-
attr_reader :hash
|
5
|
-
|
4
|
+
attr_reader :hash, :skipped
|
5
|
+
RETURN_EVENTS = [:return, :b_return, :c_return]
|
6
|
+
|
6
7
|
|
7
8
|
def initialize(hash)
|
8
9
|
@hash = hash
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
[:klass, :path, :lineno, :method_name, :vars, :level, :return_value].each do |method_name|
|
13
|
+
define_method method_name do
|
14
|
+
fetch method_name
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
|
-
def
|
16
|
-
@hash[:
|
18
|
+
def with_level!(level)
|
19
|
+
@hash[:level] = level
|
20
|
+
self
|
17
21
|
end
|
18
22
|
|
19
|
-
def
|
20
|
-
@hash[:
|
23
|
+
def set_return_value!(return_value)
|
24
|
+
@hash[:return_value] = return_value
|
25
|
+
self
|
21
26
|
end
|
22
27
|
|
23
|
-
def
|
24
|
-
@hash[:
|
28
|
+
def with_serialized_return!(serializer)
|
29
|
+
@hash[:return_value] = serializer.call(@hash[:return_value])
|
30
|
+
self
|
25
31
|
end
|
26
32
|
|
27
|
-
def
|
28
|
-
@hash[:
|
33
|
+
def with_serialized_vars!(serializer)
|
34
|
+
@hash[:vars] = serializer.call(@hash[:vars])
|
35
|
+
self
|
29
36
|
end
|
30
37
|
|
31
|
-
def
|
32
|
-
|
38
|
+
def self.from_trace_point(evt)
|
39
|
+
vars = {}
|
40
|
+
evt.binding.local_variables.each do |var_name|
|
41
|
+
vars[var_name] = evt.binding.local_variable_get var_name
|
42
|
+
end
|
43
|
+
|
44
|
+
hash = { path: evt.path, lineno: evt.lineno, klass: evt.defined_class, method_name: evt.method_id, vars: vars,
|
45
|
+
event_type: evt.event }
|
46
|
+
hash.merge!({return_value: evt.return_value}) if RETURN_EVENTS.include?(evt.event)
|
47
|
+
new(hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def fetch(key)
|
53
|
+
@hash[key]
|
33
54
|
end
|
34
55
|
end
|
35
56
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module RShade
|
2
|
+
class EventObserver
|
3
|
+
attr_reader :event_processor, :config
|
4
|
+
|
5
|
+
# @param [RShade::Config::Store] config
|
6
|
+
# @param [RShade::EventProcessor] event_store
|
7
|
+
def initialize(config, event_processor)
|
8
|
+
@event_processor = event_processor
|
9
|
+
@config = config
|
10
|
+
@level = 0
|
11
|
+
@hook = Hash.new(0)
|
12
|
+
@hook[:enter] = 1
|
13
|
+
@hook[:leave] = -1
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [:enter, :leave, :other] type
|
17
|
+
# @param [RShade::Event] event
|
18
|
+
def call(event, type)
|
19
|
+
@level += @hook[type]
|
20
|
+
return unless pass?(event)
|
21
|
+
|
22
|
+
enter(event) if type == :enter
|
23
|
+
leave(event) if type == :leave
|
24
|
+
other(event) if type == :other
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def enter(event)
|
30
|
+
event_processor.enter event, @level
|
31
|
+
end
|
32
|
+
|
33
|
+
def leave(event)
|
34
|
+
event_processor.leave event, @level
|
35
|
+
end
|
36
|
+
|
37
|
+
def other(event)
|
38
|
+
event_processor.other event, @level
|
39
|
+
end
|
40
|
+
|
41
|
+
def pass?(event)
|
42
|
+
config.filter_composition.call(event)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RShade
|
2
|
+
# nodoc
|
3
|
+
class EventProcessor
|
4
|
+
attr_reader :store
|
5
|
+
|
6
|
+
def initialize(store, config)
|
7
|
+
@store = store
|
8
|
+
custom_serializers = config.custom_serializers
|
9
|
+
@var_serializer = ::RShade::Serializer::Traversal.new(custom_serializers)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [RShade::Event] event
|
13
|
+
# @param [Integer] level
|
14
|
+
def enter(event, level)
|
15
|
+
event.with_serialized_vars!(@var_serializer).with_level!(level)
|
16
|
+
store.add(event, level)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param [RShade::Event] event
|
20
|
+
# @param [Integer] level
|
21
|
+
def leave(event, level)
|
22
|
+
store.current! do |node|
|
23
|
+
node.value.set_return_value!(event.return_value)
|
24
|
+
.with_serialized_return!(->(value) { value.inspect })
|
25
|
+
end
|
26
|
+
rescue => e
|
27
|
+
# this rescue here due this issue which reproduce in ruby-2.6.6 at least
|
28
|
+
# https://bugs.ruby-lang.org/issues/18060
|
29
|
+
end
|
30
|
+
# @param [RShade::Event] event
|
31
|
+
# @param [Integer] level
|
32
|
+
def other(event, level)
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module RShade
|
2
|
+
class EventTree
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :current, :head
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@current = @head = EventTreeNode.new(nil, 0, nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(value, level)
|
12
|
+
if current.level + 1 == level
|
13
|
+
current.children << EventTreeNode.new(value, level, current)
|
14
|
+
return
|
15
|
+
end
|
16
|
+
if current.level + 1 < level
|
17
|
+
|
18
|
+
last = current.children.last
|
19
|
+
unless last
|
20
|
+
current.children << EventTreeNode.new(nil, current.level + 1 , current)
|
21
|
+
end
|
22
|
+
@current = current.children.last
|
23
|
+
add(value, level)
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
if current.level + 1 > level
|
28
|
+
unless current.parent
|
29
|
+
return
|
30
|
+
end
|
31
|
+
@current = current.parent
|
32
|
+
add(value, level)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def current!(&block)
|
37
|
+
block.call(current.children.last) if current.children.last
|
38
|
+
end
|
39
|
+
|
40
|
+
def each(&block)
|
41
|
+
@head.each(&block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class EventTreeNode
|
46
|
+
include Enumerable
|
47
|
+
attr_reader :children, :level, :vlevel, :value
|
48
|
+
attr_accessor :parent
|
49
|
+
|
50
|
+
def initialize(value, level, parent=nil)
|
51
|
+
@children = []
|
52
|
+
@level = level
|
53
|
+
@parent = parent
|
54
|
+
@value = value
|
55
|
+
@vlevel = set_vlevel(parent)
|
56
|
+
end
|
57
|
+
|
58
|
+
def each(&block)
|
59
|
+
block.call(self) if parent != nil || value != nil
|
60
|
+
children.each { |item| item.each(&block) }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def set_vlevel(node)
|
66
|
+
return 0 if node == nil
|
67
|
+
|
68
|
+
if node.value || node.level == 0
|
69
|
+
node.vlevel + 1
|
70
|
+
else
|
71
|
+
set_vlevel(node.parent)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class AbstractFilter
|
4
|
+
def name
|
5
|
+
raise NotImplementedError
|
6
|
+
end
|
7
|
+
|
8
|
+
def priority
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(event)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def config_call
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def config(&block)
|
21
|
+
config_call(&block)
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|