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
@@ -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,25 @@
|
|
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
|
+
def call(event)
|
15
|
+
event_path = event.path
|
16
|
+
!paths.any? do |path|
|
17
|
+
next str?(path, event_path) if path.is_a? String
|
18
|
+
next regexp?(path, event_path) if path.is_a? Regexp
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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
|
@@ -1,41 +1,30 @@
|
|
1
1
|
module RShade
|
2
2
|
module Formatter
|
3
|
-
class Json
|
4
|
-
attr_reader :
|
5
|
-
FILE_NAME = 'stacktrace.json'.freeze
|
3
|
+
class Json
|
4
|
+
attr_reader :event_processor
|
6
5
|
|
7
|
-
|
6
|
+
# @param [RShade::EventProcessor] event_store
|
7
|
+
def call(event_store)
|
8
8
|
@event_store = event_store
|
9
|
-
end
|
10
|
-
|
11
|
-
def call
|
12
9
|
flat
|
13
10
|
end
|
14
11
|
|
15
12
|
def flat
|
16
13
|
arr = []
|
17
|
-
event_store.
|
18
|
-
arr << item(node)
|
14
|
+
event_store.each do |node|
|
15
|
+
arr << item(node.event)
|
19
16
|
end
|
20
|
-
|
21
|
-
arr
|
17
|
+
arr.sort_by { |item| item[:level]}
|
22
18
|
end
|
23
19
|
|
24
20
|
def hierarchical
|
25
21
|
hash = {}
|
26
|
-
event_store.
|
22
|
+
event_store.each do |node|
|
23
|
+
depth = node.level
|
27
24
|
ref = hash_iterate(hash, depth)
|
28
25
|
ref[:data] = item(node)
|
29
26
|
end
|
30
|
-
|
31
|
-
write_to_file(JSON.pretty_generate(hash))
|
32
|
-
hash
|
33
|
-
end
|
34
|
-
|
35
|
-
def write_to_file(data)
|
36
|
-
File.open(File.join(RShade.config.store_dir, FILE_NAME), "w+") do |f|
|
37
|
-
f.write data
|
38
|
-
end
|
27
|
+
sort_hash(hash)
|
39
28
|
end
|
40
29
|
|
41
30
|
def sort_hash(h)
|
@@ -58,11 +47,11 @@ module RShade
|
|
58
47
|
|
59
48
|
def item(value)
|
60
49
|
{
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
66
55
|
}
|
67
56
|
end
|
68
57
|
end
|
@@ -1,29 +1,35 @@
|
|
1
1
|
module RShade
|
2
2
|
module Formatter
|
3
|
-
class String
|
4
|
-
attr_reader :event_store
|
3
|
+
class String
|
5
4
|
ROOT_SEP = "---\n"
|
6
5
|
|
7
|
-
def initialize(
|
8
|
-
@event_store = event_store
|
6
|
+
def initialize(opts= {})
|
9
7
|
end
|
10
8
|
|
11
|
-
|
9
|
+
# @param [RShade::EventProcessor] event_store
|
10
|
+
def call(event_store)
|
12
11
|
buffer = StringIO.new
|
13
|
-
event_store.
|
12
|
+
event_store.each_with_index do |node, idx|
|
13
|
+
depth = node.level
|
14
|
+
event = node.value
|
14
15
|
if depth == 1
|
15
16
|
buffer << ROOT_SEP
|
16
17
|
next
|
17
18
|
end
|
18
|
-
|
19
|
+
next unless event
|
20
|
+
buffer.write line(idx, event, node.vlevel)
|
19
21
|
end
|
20
22
|
buffer.string
|
21
23
|
end
|
22
24
|
|
23
|
-
def line(value, depth)
|
24
|
-
|
25
|
-
|
26
|
-
|
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"
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RShade
|
2
|
+
module Serializer
|
3
|
+
class Traversal
|
4
|
+
attr_reader :types
|
5
|
+
|
6
|
+
def initialize(custom_types={})
|
7
|
+
@types = default_types.merge(custom_types)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(hash)
|
11
|
+
new_val = {}
|
12
|
+
hash.each do |name, value|
|
13
|
+
new_val[name] = traverse(value)
|
14
|
+
end
|
15
|
+
new_val
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_types
|
19
|
+
{
|
20
|
+
default: ->(value) { value.to_s },
|
21
|
+
Integer => ->(value) { value },
|
22
|
+
Float => ->(value) { value },
|
23
|
+
Numeric => ->(value) { value },
|
24
|
+
String => ->(value) { value },
|
25
|
+
Hash => ->(value) do
|
26
|
+
hash = {}
|
27
|
+
value.each do |k,v|
|
28
|
+
hash[k] = traverse(v)
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end,
|
32
|
+
Array => ->(value) do
|
33
|
+
value.map { |item| traverse(item) }
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def traverse(value)
|
39
|
+
klass = value
|
40
|
+
klass = value.class unless value.is_a?(Class)
|
41
|
+
serializer = types[klass]
|
42
|
+
serializer = types[:default] unless serializer
|
43
|
+
serializer.call(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/rshade/trace.rb
CHANGED
@@ -1,54 +1,34 @@
|
|
1
1
|
module RShade
|
2
2
|
class Trace
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@filter = options.fetch(:filter, RShade.config.filter)
|
10
|
-
@tp = TracePoint.new(*EVENTS, &method(:process_trace))
|
11
|
-
@level = 1
|
12
|
-
@stat = {}
|
13
|
-
@calls = 0
|
14
|
-
@returns = 0
|
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
|
15
9
|
end
|
16
10
|
|
17
|
-
def self.reveal(
|
18
|
-
new(
|
11
|
+
def self.reveal(config=nil, &block)
|
12
|
+
new(config).reveal(&block)
|
19
13
|
end
|
20
14
|
|
21
|
-
def reveal
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
def reveal(&block)
|
16
|
+
processor = EventProcessor.new(event_store, config)
|
17
|
+
observer = EventObserver.new(config, processor)
|
18
|
+
observable = RShade::TraceObservable.new([observer], config)
|
19
|
+
observable.reveal &block
|
26
20
|
self
|
27
|
-
ensure
|
28
|
-
@tp.disable
|
29
21
|
end
|
30
22
|
|
31
23
|
def show
|
32
|
-
formatter.call(event_store)
|
24
|
+
config.formatter.call(event_store)
|
33
25
|
end
|
34
26
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if tp.event == :call
|
41
|
-
@level +=1
|
42
|
-
hash = EventSerializer.call(tp, @level)
|
43
|
-
return unless filter.call(hash)
|
44
|
-
@calls += 1
|
45
|
-
event_store << Event.new(hash)
|
46
|
-
end
|
47
|
-
|
48
|
-
if tp.event == :return && @level > 0
|
49
|
-
@returns += 1
|
50
|
-
@level -=1
|
51
|
-
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
|
52
32
|
end
|
53
33
|
end
|
54
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,32 +1,31 @@
|
|
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/serializer/traversal'
|
9
|
+
require 'rshade/event_tree'
|
10
|
+
require 'rshade/event_processor'
|
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'
|
6
20
|
require 'rshade/formatter/string'
|
7
21
|
require 'rshade/formatter/json'
|
22
|
+
require 'rshade/formatter/file'
|
23
|
+
require 'rshade/formatter/html'
|
8
24
|
require 'rshade/formatter/stdout'
|
9
|
-
require 'rshade/formatter/http'
|
10
25
|
require 'rshade/event'
|
11
|
-
require 'rshade/event_store'
|
12
26
|
require 'rshade/trace'
|
13
27
|
require 'rshade/rspec/rspec'
|
14
28
|
require 'rshade/version'
|
15
29
|
|
16
|
-
|
17
30
|
module RShade
|
18
|
-
APP_TRACE = :app_trace
|
19
|
-
FULL_TRACE = :full_trace
|
20
|
-
|
21
|
-
class << self
|
22
|
-
attr_writer :config
|
23
|
-
|
24
|
-
def config
|
25
|
-
@config ||= Configuration.new
|
26
|
-
end
|
27
|
-
|
28
|
-
def configure
|
29
|
-
yield configuration
|
30
|
-
end
|
31
|
-
end
|
32
31
|
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", "~>
|
41
|
+
spec.add_development_dependency "bundler", "~> 2.2.33"
|
42
42
|
spec.add_development_dependency "rake", ">= 12.3.3"
|
43
43
|
spec.add_development_dependency "rspec", "~> 3.0"
|
44
44
|
end
|