rshade 0.1.6 → 0.1.9
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/.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
|