rshade 0.1.6 → 0.1.9
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 +24 -23
- data/README.md +74 -20
- data/html/template.html.erb +72 -0
- data/lib/rshade/binding_serializer.rb +35 -0
- data/lib/rshade/config/store.rb +38 -0
- data/lib/rshade/config.rb +71 -0
- data/lib/rshade/core_extensions/object/reveal.rb +8 -0
- data/lib/rshade/event.rb +60 -0
- data/lib/rshade/event_observer.rb +45 -0
- data/lib/rshade/event_processor.rb +35 -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 +24 -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 +59 -0
- data/lib/rshade/formatter/stdout.rb +10 -0
- data/lib/rshade/formatter/string.rb +36 -0
- data/lib/rshade/rails/rails.rb +0 -0
- data/lib/rshade/{rspec.rb → rspec/rspec.rb} +4 -6
- data/lib/rshade/trace.rb +21 -56
- data/lib/rshade/trace_observable.rb +40 -0
- data/lib/rshade/version.rb +1 -1
- data/lib/rshade.rb +26 -20
- data/rshade.gemspec +2 -2
- data/todo.md +8 -0
- metadata +37 -18
- data/lib/rshade/configuration.rb +0 -32
- data/lib/rshade/source.rb +0 -46
- data/lib/rshade/source_node.rb +0 -23
- data/lib/rshade/tree.rb +0 -30
@@ -0,0 +1,28 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class Default
|
4
|
+
RUBY_VERSION_PATTERN = /ruby-[0-9.]*/
|
5
|
+
|
6
|
+
def self.create
|
7
|
+
new.create
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
[create_exclude]
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_exclude
|
15
|
+
filter = ExcludePathFilter.new
|
16
|
+
filter.config do |paths|
|
17
|
+
excluded_paths.each do |path|
|
18
|
+
paths << path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def excluded_paths
|
24
|
+
[ENV['GEM_PATH'].split(':'), RUBY_VERSION_PATTERN, /internal/].flatten.compact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class ExcludePathFilter < IncludePathFilter
|
4
|
+
NAME = :exclude_paths
|
5
|
+
|
6
|
+
def name
|
7
|
+
NAME
|
8
|
+
end
|
9
|
+
|
10
|
+
def priority
|
11
|
+
0
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def str?(str, event_path)
|
16
|
+
!event_path.include?(str)
|
17
|
+
end
|
18
|
+
|
19
|
+
def regexp?(regex, event_path)
|
20
|
+
!regex.match?(event_path)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class FilterBuilder
|
4
|
+
def self.build(arr)
|
5
|
+
new.traverse(arr)
|
6
|
+
end
|
7
|
+
|
8
|
+
def map
|
9
|
+
{
|
10
|
+
or: [RShade::Filter::FilterComposition::OR_OP, 2],
|
11
|
+
and: [RShade::Filter::FilterComposition::AND_OP, 2],
|
12
|
+
unary: [RShade::Filter::FilterComposition::UNARY_OP, 1]
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def traverse(arr)
|
17
|
+
op, arity = map[arr[0]]
|
18
|
+
arg1 = arr[1]
|
19
|
+
arg2 = nil
|
20
|
+
arg2 = arr[2] if arity == 2
|
21
|
+
arg1 = traverse(arg1) if arg1.is_a?(Array)
|
22
|
+
arg2 = traverse(arg2) if arg2.is_a?(Array)
|
23
|
+
|
24
|
+
RShade::Filter::FilterComposition.new(op, arg1, arg2)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class FilterComposition
|
4
|
+
include Enumerable
|
5
|
+
AND_OP = :and
|
6
|
+
OR_OP = :or
|
7
|
+
UNARY_OP = :unary
|
8
|
+
attr_reader :op, :left, :right, :parent
|
9
|
+
attr_accessor :parent
|
10
|
+
|
11
|
+
# @param [#call, Enumerable] left
|
12
|
+
# @param [#call, Enumerable] right
|
13
|
+
def initialize(op=UNARY_OP, left=nil, right=nil)
|
14
|
+
@op = op
|
15
|
+
@left = left
|
16
|
+
@right = right
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(event)
|
20
|
+
case op
|
21
|
+
when UNARY_OP
|
22
|
+
return left&.call(event)
|
23
|
+
when AND_OP
|
24
|
+
return left&.call(event) && right&.call(event)
|
25
|
+
when OR_OP
|
26
|
+
l = left&.call(event)
|
27
|
+
r = right&.call(event)
|
28
|
+
# puts "#{left} => #{l} OR #{right} => #{r}"
|
29
|
+
return l || r
|
30
|
+
else
|
31
|
+
raise 'undefined op'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def each(&block)
|
36
|
+
if left&.respond_to?(:each)
|
37
|
+
left&.each(&block)
|
38
|
+
else
|
39
|
+
yield left
|
40
|
+
end
|
41
|
+
|
42
|
+
if right&.respond_to?(:each)
|
43
|
+
right&.each(&block)
|
44
|
+
else
|
45
|
+
yield right
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def config_filter(type, &block)
|
50
|
+
filter = find do |filter|
|
51
|
+
filter.is_a? type
|
52
|
+
end
|
53
|
+
filter.config(&block) if filter
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class IncludePathFilter < AbstractFilter
|
4
|
+
attr_reader :paths
|
5
|
+
|
6
|
+
NAME = :include_paths
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@paths = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
NAME
|
14
|
+
end
|
15
|
+
|
16
|
+
def priority
|
17
|
+
1
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(event)
|
21
|
+
event_path = event.path
|
22
|
+
paths.any? do |path|
|
23
|
+
next str?(path, event_path) if path.is_a? String
|
24
|
+
next regexp?(path, event_path) if path.is_a? Regexp
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def config_call(&block)
|
30
|
+
block.call(@paths)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def str?(str, event_path)
|
35
|
+
event_path.include?(str)
|
36
|
+
end
|
37
|
+
|
38
|
+
def regexp?(regex, event_path)
|
39
|
+
regex.match?(event_path)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RShade
|
2
|
+
module Filter
|
3
|
+
class VariableFilter < AbstractFilter
|
4
|
+
attr_reader :matchers
|
5
|
+
NAME = :variable_filter
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@matchers = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
:variable_filter
|
13
|
+
end
|
14
|
+
|
15
|
+
def priority
|
16
|
+
2
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(event)
|
20
|
+
matchers.each do |match|
|
21
|
+
event.vars.each do |name, value|
|
22
|
+
return true if match.call(name, value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def config_call(&block)
|
29
|
+
matchers << block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RShade
|
2
|
+
module Formatter
|
3
|
+
class File
|
4
|
+
attr_reader :formatter
|
5
|
+
FILE_NAME = 'stacktrace.json'.freeze
|
6
|
+
|
7
|
+
def initialize(args={})
|
8
|
+
@formatter = args.fetch(:format, Json)
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param [RShade::EventProcessor] event_store
|
12
|
+
def call(event_store)
|
13
|
+
data = formatter.call(event_store)
|
14
|
+
if formatter == Json
|
15
|
+
write_to_file(JSON.pretty_generate(data))
|
16
|
+
else
|
17
|
+
write_to_file(data.to_s)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_to_file(data)
|
22
|
+
::File.open(::File.join(RShade::Config.store_dir, FILE_NAME), "w+") do |f|
|
23
|
+
f.write data
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module RShade
|
4
|
+
module Formatter
|
5
|
+
class Html
|
6
|
+
attr_reader :formatter
|
7
|
+
FILE_NAME = 'stacktrace.html'.freeze
|
8
|
+
TEMPLATE = 'html/template.html.erb'
|
9
|
+
|
10
|
+
def initialize(args={})
|
11
|
+
@formatter = args.fetch(:formatter, Json)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [RShade::EventProcessor] event_store
|
15
|
+
def call(event_store)
|
16
|
+
data = formatter.call(event_store)
|
17
|
+
erb_template = ERB.new(template)
|
18
|
+
content = erb_template.result_with_hash({json: data.to_json})
|
19
|
+
write_to_file(content)
|
20
|
+
end
|
21
|
+
|
22
|
+
def write_to_file(data)
|
23
|
+
::File.open(::File.join(RShade::Config.store_dir, FILE_NAME), "w+") do |f|
|
24
|
+
f.write data
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def template
|
29
|
+
@template ||=::File.read(::File.join(::RShade::Config.root_dir, TEMPLATE))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RShade
|
2
|
+
module Formatter
|
3
|
+
class Json
|
4
|
+
attr_reader :event_processor
|
5
|
+
|
6
|
+
# @param [RShade::EventProcessor] event_store
|
7
|
+
def call(event_store)
|
8
|
+
@event_store = event_store
|
9
|
+
flat
|
10
|
+
end
|
11
|
+
|
12
|
+
def flat
|
13
|
+
arr = []
|
14
|
+
event_store.each do |node|
|
15
|
+
arr << item(node.event)
|
16
|
+
end
|
17
|
+
arr.sort_by { |item| item[:level]}
|
18
|
+
end
|
19
|
+
|
20
|
+
def hierarchical
|
21
|
+
hash = {}
|
22
|
+
event_store.each do |node|
|
23
|
+
depth = node.level
|
24
|
+
ref = hash_iterate(hash, depth)
|
25
|
+
ref[:data] = item(node)
|
26
|
+
end
|
27
|
+
sort_hash(hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
def sort_hash(h)
|
31
|
+
{}.tap do |h2|
|
32
|
+
h.sort.each do |k,v|
|
33
|
+
h2[k] = v.is_a?(Hash) ? sort_hash(v) : v
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash_iterate(hash, depth)
|
39
|
+
(0..depth).each do |lvl|
|
40
|
+
unless hash[:inner]
|
41
|
+
hash[:inner] = {}
|
42
|
+
end
|
43
|
+
hash = hash[:inner]
|
44
|
+
end
|
45
|
+
hash
|
46
|
+
end
|
47
|
+
|
48
|
+
def item(value)
|
49
|
+
{
|
50
|
+
class: value.klass.to_s,
|
51
|
+
method_name: value.method_name,
|
52
|
+
full_path: "#{value.path}:#{value.lineno}",
|
53
|
+
level: value.depth,
|
54
|
+
vars: value.vars
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module RShade
|
2
|
+
module Formatter
|
3
|
+
class String
|
4
|
+
ROOT_SEP = "---\n"
|
5
|
+
|
6
|
+
def initialize(opts= {})
|
7
|
+
end
|
8
|
+
|
9
|
+
# @param [RShade::EventProcessor] event_store
|
10
|
+
def call(event_store)
|
11
|
+
buffer = StringIO.new
|
12
|
+
event_store.each_with_index do |node, idx|
|
13
|
+
depth = node.level
|
14
|
+
event = node.value
|
15
|
+
if depth == 1
|
16
|
+
buffer << ROOT_SEP
|
17
|
+
next
|
18
|
+
end
|
19
|
+
next unless event
|
20
|
+
buffer.write line(idx, event, node.vlevel)
|
21
|
+
end
|
22
|
+
buffer.string
|
23
|
+
end
|
24
|
+
|
25
|
+
def line(line_idx, value, depth)
|
26
|
+
vars = value.vars
|
27
|
+
returned = ColorizedString["=> |#{value.return_value}|"].colorize(:magenta)
|
28
|
+
|
29
|
+
class_method = ColorizedString["#{value.klass}##{value.method_name}"].colorize(:green)
|
30
|
+
full_path = ColorizedString["#{value.path}:#{value.lineno}"].colorize(:blue)
|
31
|
+
line_idx = ColorizedString["[#{line_idx}] "].colorize(:red)
|
32
|
+
"#{' ' * depth}#{line_idx}#{class_method}(#{vars}) #{returned} -> #{full_path}\n"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
File without changes
|
@@ -2,15 +2,13 @@ module RShade
|
|
2
2
|
REPORTS = []
|
3
3
|
|
4
4
|
module RSpecHelper
|
5
|
-
def rshade_reveal(
|
5
|
+
def rshade_reveal(options = {})
|
6
6
|
raise 'No block given' unless block_given?
|
7
|
-
|
8
|
-
|
9
|
-
trace.reveal(options) do
|
7
|
+
options.merge!(formatter: Formatter::String) { |_key,v1, _v2| v1 }
|
8
|
+
result = Trace.reveal(options) do
|
10
9
|
yield
|
11
10
|
end
|
12
|
-
|
13
|
-
REPORTS.push trace.show(type)
|
11
|
+
REPORTS.push result.show
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
data/lib/rshade/trace.rb
CHANGED
@@ -1,69 +1,34 @@
|
|
1
1
|
module RShade
|
2
2
|
class Trace
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@stack = [@source_tree]
|
10
|
-
end
|
11
|
-
|
12
|
-
def reveal(options = {})
|
13
|
-
return unless block_given?
|
14
|
-
|
15
|
-
@tp.enable
|
16
|
-
yield
|
17
|
-
ensure
|
18
|
-
@tp.disable
|
3
|
+
attr_reader :config, :event_store
|
4
|
+
|
5
|
+
# @param [RShade::Config,RShade::Config::Store] config
|
6
|
+
def initialize(config)
|
7
|
+
@config = fetch_config(config)
|
8
|
+
@event_store = EventTree.new
|
19
9
|
end
|
20
10
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
show_full_trace
|
11
|
+
def self.reveal(config=nil, &block)
|
12
|
+
new(config).reveal(&block)
|
25
13
|
end
|
26
14
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
next
|
34
|
-
end
|
35
|
-
|
36
|
-
buffer << "#{' ' * depth} #{node.value.pretty}\n" if node.value
|
37
|
-
end
|
38
|
-
puts buffer.string
|
15
|
+
def reveal(&block)
|
16
|
+
processor = EventProcessor.new(@event_store)
|
17
|
+
observer = EventObserver.new(config, processor)
|
18
|
+
observable = RShade::TraceObservable.new([observer], config)
|
19
|
+
observable.reveal &block
|
20
|
+
self
|
39
21
|
end
|
40
22
|
|
41
|
-
def
|
42
|
-
|
43
|
-
next true if node.root?
|
44
|
-
|
45
|
-
node.value.app_code?
|
46
|
-
end
|
47
|
-
show_full_trace(clone)
|
23
|
+
def show
|
24
|
+
config.formatter.call(event_store)
|
48
25
|
end
|
49
26
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
vars[var] = tp.binding.local_variable_get var
|
56
|
-
end
|
57
|
-
hash = { level: @stack.size, path: tp.path, lineno: tp.lineno, klass: tp.defined_class, method_name: tp.method_id, vars: vars }
|
58
|
-
node = SourceNode.new(Source.new(hash))
|
59
|
-
node.parent = parent
|
60
|
-
parent << node
|
61
|
-
@stack.push node
|
62
|
-
end
|
63
|
-
|
64
|
-
if tp.event == :return && @stack.size > 1
|
65
|
-
@stack.pop
|
66
|
-
end
|
27
|
+
private
|
28
|
+
def fetch_config(config)
|
29
|
+
config = config || ::RShade::Config.default
|
30
|
+
config = config.value if config.is_a?(::RShade::Config)
|
31
|
+
config
|
67
32
|
end
|
68
33
|
end
|
69
34
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RShade
|
2
|
+
class TraceObservable
|
3
|
+
include Observable
|
4
|
+
attr_reader :trace_p
|
5
|
+
CALL_EVENTS = Set[:call, :c_call, :b_call]
|
6
|
+
RETURN_EVENTS = Set[:return, :c_return, :b_return]
|
7
|
+
|
8
|
+
# @param [Enumerable<#call>, #call] observers
|
9
|
+
# @param [::RShade::Config::Store] config
|
10
|
+
def initialize(observers, config)
|
11
|
+
@trace_p = TracePoint.new(*config.tp_events, &method(:process))
|
12
|
+
observers = [observers] unless observers.is_a?(Enumerable)
|
13
|
+
|
14
|
+
observers.each do |observer|
|
15
|
+
add_observer(observer, :call)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def reveal
|
20
|
+
return unless block_given?
|
21
|
+
|
22
|
+
trace_p.enable
|
23
|
+
yield
|
24
|
+
self
|
25
|
+
ensure
|
26
|
+
trace_p.disable
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
# more info https://rubyapi.org/3.1/o/tracepoint
|
31
|
+
# @param [TracePoint] tp
|
32
|
+
def process(tp)
|
33
|
+
changed
|
34
|
+
event = Event.from_trace_point(tp)
|
35
|
+
return notify_observers(event, :enter) if CALL_EVENTS.include?(tp.event)
|
36
|
+
return notify_observers(event, :leave) if RETURN_EVENTS.include?(tp.event)
|
37
|
+
notify_observers(event, :other)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/rshade/version.rb
CHANGED
data/lib/rshade.rb
CHANGED
@@ -1,26 +1,32 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
1
|
+
require 'colorized_string'
|
2
|
+
require 'erb'
|
3
|
+
require 'weakref'
|
4
|
+
require 'set'
|
5
|
+
require 'observer'
|
6
|
+
require 'rshade/config'
|
7
|
+
require 'rshade/config/store'
|
8
|
+
require 'rshade/event_tree'
|
9
|
+
require 'rshade/event_processor'
|
10
|
+
require 'rshade/binding_serializer'
|
11
|
+
require 'rshade/event_observer'
|
12
|
+
require 'rshade/trace_observable'
|
13
|
+
require 'rshade/filter/abstract_filter'
|
14
|
+
require 'rshade/filter/filter_builder'
|
15
|
+
require 'rshade/filter/filter_composition'
|
16
|
+
require 'rshade/filter/include_path_filter'
|
17
|
+
require 'rshade/filter/exclude_path_filter'
|
18
|
+
require 'rshade/filter/variable_filter'
|
19
|
+
require 'rshade/filter/default'
|
20
|
+
require 'rshade/formatter/string'
|
21
|
+
require 'rshade/formatter/json'
|
22
|
+
require 'rshade/formatter/file'
|
23
|
+
require 'rshade/formatter/html'
|
24
|
+
require 'rshade/formatter/stdout'
|
25
|
+
require 'rshade/event'
|
6
26
|
require 'rshade/trace'
|
7
|
-
require 'rshade/rspec'
|
27
|
+
require 'rshade/rspec/rspec'
|
8
28
|
require 'rshade/version'
|
9
29
|
|
10
30
|
|
11
31
|
module RShade
|
12
|
-
APP_TRACE = :app_trace
|
13
|
-
FULL_TRACE = :full_trace
|
14
|
-
|
15
|
-
class << self
|
16
|
-
attr_writer :config
|
17
|
-
|
18
|
-
def configuration
|
19
|
-
@config ||= Configuration.new
|
20
|
-
end
|
21
|
-
|
22
|
-
def configure
|
23
|
-
yield configuration
|
24
|
-
end
|
25
|
-
end
|
26
32
|
end
|
data/rshade.gemspec
CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
|
|
38
38
|
|
39
39
|
spec.add_runtime_dependency 'colorize'
|
40
40
|
|
41
|
-
spec.add_development_dependency "bundler", "~>
|
42
|
-
spec.add_development_dependency "rake", "
|
41
|
+
spec.add_development_dependency "bundler", "~> 2.2.33"
|
42
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
43
43
|
spec.add_development_dependency "rspec", "~> 3.0"
|
44
44
|
end
|
data/todo.md
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
1. Should I use rails way organizing module/file naming or not?
|
2
|
+
2. Reduce global state usage
|
3
|
+
3. Problem with stack deep
|
4
|
+
4. Problem when have binary values error in serialization (Encoding problems)
|
5
|
+
5. Make filter while tracing that will be more efficient
|
6
|
+
6. sort depth and than replace values
|
7
|
+
7. tree not working bcz of vars serialization
|
8
|
+
8. Some classes in Rails can't serialize safely produce StackTraceTooDeep
|