rails_dt 0.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.yardopts +2 -0
- data/Gemfile +14 -0
- data/MIT-LICENSE +1 -1
- data/README.md +43 -135
- data/lib/dt.rb +31 -215
- data/lib/dt/config.rb +74 -0
- data/lib/dt/instance.rb +117 -0
- data/lib/rails_dt.rb +3 -2
- data/lib/rails_dt/version.rb +4 -0
- data/rails_dt.gemspec +12 -50
- data/spec/lib/dt/config_spec.rb +76 -0
- data/spec/lib/dt/instance_spec.rb +173 -0
- data/spec/lib/dt_spec.rb +14 -0
- data/spec/lib/rails_dt_spec.rb +6 -0
- data/spec/lib/spec/alias_method_matcher_spec.rb +16 -0
- data/spec/lib/spec/context_when_spec.rb +32 -0
- data/spec/lib/spec/let_m_spec.rb +104 -0
- data/spec/lib/spec/use_custom_let_spec.rb +46 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/00extend_x.rb +23 -0
- data/spec/support/alias_method_matcher.rb +20 -0
- data/spec/support/context_when.rb +39 -0
- data/spec/support/let_m.rb +27 -0
- data/spec/support/use_custom_let.rb +80 -0
- metadata +43 -52
- data/README.html +0 -171
- data/Rakefile +0 -68
- data/VERSION.yml +0 -4
- data/generators/rails_dt/USAGE +0 -11
- data/generators/rails_dt/WARNING +0 -2
- data/generators/rails_dt/rails_dt_generator.rb +0 -9
- data/generators/rails_dt/templates/INSTALL +0 -20
- data/generators/rails_dt/templates/dt.css +0 -27
- data/generators/rails_dt/templates/dt.rb +0 -4
- data/init.rb +0 -2
- data/lib/dt/action_controller_extensions.rb +0 -29
- data/lib/generators/rails_dt/USAGE +0 -11
- data/lib/generators/rails_dt/rails_dt_generator.rb +0 -9
- data/lib/generators/rails_dt/templates/INSTALL +0 -20
- data/lib/generators/rails_dt/templates/dt.css +0 -27
- data/lib/generators/rails_dt/templates/dt.rb +0 -4
data/lib/dt/config.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
require_relative "../dt"
|
5
|
+
|
6
|
+
module DT
|
7
|
+
class Config
|
8
|
+
attr_writer :env, :rails
|
9
|
+
|
10
|
+
def initialize(attrs = {})
|
11
|
+
attrs.each { |k, v| public_send("#{k}=", v) }
|
12
|
+
end
|
13
|
+
|
14
|
+
# A copy of <tt>ENV</tt> for value-reading purposes.
|
15
|
+
# @return [Hash] Default is <tt>ENV.to_h</tt>.
|
16
|
+
def env
|
17
|
+
@env ||= ENV.to_h
|
18
|
+
end
|
19
|
+
|
20
|
+
# Top-level Rails module or substitute value.
|
21
|
+
# @return [Module] <tt>Rails</tt>.
|
22
|
+
# @return [nil]
|
23
|
+
def rails
|
24
|
+
if instance_variable_defined?(k = :@rails)
|
25
|
+
instance_variable_get(k)
|
26
|
+
else
|
27
|
+
instance_variable_set(k, (Rails if defined? Rails))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @!attribute root_path
|
32
|
+
# @return [Pathname]
|
33
|
+
def root_path
|
34
|
+
@root_path ||= begin
|
35
|
+
# 1. Fetch "raw" value, suitable as `Pathname` argument.
|
36
|
+
s = if rails
|
37
|
+
# Rails project.
|
38
|
+
rails.root
|
39
|
+
else
|
40
|
+
# Non-Rails project, attempt to guess.
|
41
|
+
if (fn = env["BUNDLE_GEMFILE"])
|
42
|
+
# The project has a Gemfile, hook it up.
|
43
|
+
File.expand_path("..", fn)
|
44
|
+
else
|
45
|
+
# Default to pwd otherwise.
|
46
|
+
Dir.pwd
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# 2. Attempt to absolutize raw path, but in a non-fatal way.
|
51
|
+
begin
|
52
|
+
# See "Implementation notes".
|
53
|
+
Pathname(s).realpath
|
54
|
+
rescue Errno::ENOENT
|
55
|
+
Pathname(s)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def root_path=(s)
|
61
|
+
@root_path = if s.is_a? Pathname
|
62
|
+
s
|
63
|
+
else
|
64
|
+
Pathname(s)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Implementation notes:
|
72
|
+
#
|
73
|
+
# * We call `Pathname` as `Pathname` to be able to stub them as own methods during testing. Other
|
74
|
+
# than that we should be using `Kernel.Pathname` which is also usable, but is more ugly.
|
data/lib/dt/instance.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
|
2
|
+
require_relative "../dt"
|
3
|
+
|
4
|
+
module DT
|
5
|
+
class Instance
|
6
|
+
attr_writer \
|
7
|
+
:conf,
|
8
|
+
:dt_logger,
|
9
|
+
:is_rails_console,
|
10
|
+
:rails_logger,
|
11
|
+
:stderr
|
12
|
+
|
13
|
+
def initialize(attrs = {})
|
14
|
+
attrs.each { |k, v| public_send("#{k}=", v) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# The configuration object.
|
18
|
+
# @return [Config] <tt>DT.conf</tt>.
|
19
|
+
def conf
|
20
|
+
# NOTE: See "Implementation notes".
|
21
|
+
@conf ||= DT.conf
|
22
|
+
end
|
23
|
+
|
24
|
+
# File logger, an instance of Ruby's <tt>Logger</tt>.
|
25
|
+
# @return [Logger] Default is a <tt>Logger</tt> writing to <tt>log/dt.log</tt>.
|
26
|
+
def dt_logger
|
27
|
+
if instance_variable_defined?(k = :@dt_logger)
|
28
|
+
instance_variable_get(k)
|
29
|
+
else
|
30
|
+
instance_variable_set(k, begin
|
31
|
+
Logger.new(conf.root_path + "log/dt.log")
|
32
|
+
rescue Errno::ENOENT
|
33
|
+
nil
|
34
|
+
end)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# <tt>true</tt> if running in Rails console.
|
39
|
+
# @return [Boolean]
|
40
|
+
def is_rails_console
|
41
|
+
if instance_variable_defined?(k = :@is_rails_console)
|
42
|
+
instance_variable_get(k)
|
43
|
+
else
|
44
|
+
instance_variable_set(k, conf.rails && conf.rails.const_defined?(:Console))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias_method :rails_console?, :is_rails_console
|
48
|
+
|
49
|
+
# An object to use as log in Rails mode.
|
50
|
+
# @return [ActiveSupport::Logger] Default is <tt>conf.rails.logger</tt>.
|
51
|
+
def rails_logger
|
52
|
+
if instance_variable_defined?(k = :@rails_logger)
|
53
|
+
instance_variable_get(k)
|
54
|
+
else
|
55
|
+
instance_variable_set(k, conf.rails && conf.rails.logger)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# A writable IO stream to print to. Default is <tt>STDERR</tt>.
|
60
|
+
# @return [IO]
|
61
|
+
def stderr
|
62
|
+
@stderr ||= STDERR
|
63
|
+
end
|
64
|
+
|
65
|
+
#--------------------------------------- Actions
|
66
|
+
|
67
|
+
# Lower level implementation of <tt>p</tt>.
|
68
|
+
#
|
69
|
+
# * Print to {#dt_logger} if one is available.
|
70
|
+
# * Print to {#rails_logger} if one is available.
|
71
|
+
# * Print to {#stderr} if not running in {#rails_console?}.
|
72
|
+
#
|
73
|
+
# @param caller [Array<Array<file, line>>]
|
74
|
+
# @return nil
|
75
|
+
# @see DT.p
|
76
|
+
def _p(caller, *args)
|
77
|
+
file, line = caller[0].split(":")
|
78
|
+
file_rel = begin
|
79
|
+
Pathname(file).relative_path_from(conf.root_path)
|
80
|
+
rescue ArgumentError
|
81
|
+
# If `file` is "" or other non-path, `relative_path_from` will raise an error.
|
82
|
+
# Fall back to original value then.
|
83
|
+
file
|
84
|
+
end
|
85
|
+
|
86
|
+
args.each do |arg|
|
87
|
+
value = case arg
|
88
|
+
when String
|
89
|
+
arg
|
90
|
+
else
|
91
|
+
arg.inspect
|
92
|
+
end
|
93
|
+
|
94
|
+
msg = "[DT #{file_rel}:#{line}] #{value}"
|
95
|
+
|
96
|
+
# Fire!
|
97
|
+
dt_logger.debug(msg) if dt_logger
|
98
|
+
if rails_logger
|
99
|
+
rails_logger.debug(msg)
|
100
|
+
stderr.puts(msg) if stderr && !rails_console?
|
101
|
+
else
|
102
|
+
stderr.puts(msg) if stderr
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Be like `puts`.
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Implementation notes:
|
114
|
+
#
|
115
|
+
# * `DT.conf` acts as a subsystem-wide global, all instance copies point to the same object. The
|
116
|
+
# reason for that is that it's possible that certain configuration options will be added in the
|
117
|
+
# future.
|
data/lib/rails_dt.rb
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
|
2
|
-
require
|
1
|
+
|
2
|
+
# Main gem require. Load all libraries.
|
3
|
+
Dir[File.expand_path("../**/*.rb", __FILE__)].each { |fn| require fn }
|
data/rails_dt.gemspec
CHANGED
@@ -1,56 +1,18 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
1
|
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
# TODO: Finalize.
|
3
|
+
#require_relative ""
|
4
|
+
require File.expand_path("../lib/rails_dt/version", __FILE__)
|
9
5
|
|
10
|
-
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "rails_dt"
|
8
|
+
s.version = RailsDt::VERSION
|
11
9
|
s.authors = ["Alex Fortuna"]
|
12
|
-
s.
|
13
|
-
s.
|
14
|
-
s.email = %q{alex.r@askit.org}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"README.html",
|
17
|
-
"README.md"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
"MIT-LICENSE",
|
21
|
-
"README.html",
|
22
|
-
"README.md",
|
23
|
-
"Rakefile",
|
24
|
-
"VERSION.yml",
|
25
|
-
"generators/rails_dt/USAGE",
|
26
|
-
"generators/rails_dt/WARNING",
|
27
|
-
"generators/rails_dt/rails_dt_generator.rb",
|
28
|
-
"generators/rails_dt/templates/INSTALL",
|
29
|
-
"generators/rails_dt/templates/dt.css",
|
30
|
-
"generators/rails_dt/templates/dt.rb",
|
31
|
-
"init.rb",
|
32
|
-
"lib/dt.rb",
|
33
|
-
"lib/dt/action_controller_extensions.rb",
|
34
|
-
"lib/generators/rails_dt/USAGE",
|
35
|
-
"lib/generators/rails_dt/rails_dt_generator.rb",
|
36
|
-
"lib/generators/rails_dt/templates/INSTALL",
|
37
|
-
"lib/generators/rails_dt/templates/dt.css",
|
38
|
-
"lib/generators/rails_dt/templates/dt.rb",
|
39
|
-
"lib/rails_dt.rb",
|
40
|
-
"rails_dt.gemspec"
|
41
|
-
]
|
42
|
-
s.homepage = %q{http://github.com/dadooda/rails_dt}
|
43
|
-
s.require_paths = ["lib"]
|
44
|
-
s.rubygems_version = %q{1.6.2}
|
45
|
-
s.summary = %q{Rails Debug Toolkit}
|
10
|
+
s.email = ["fortunadze@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/dadooda/rails_dt"
|
46
12
|
|
47
|
-
|
48
|
-
s.specification_version = 3
|
13
|
+
s.summary = "Ruby/Rails debug toolkit"
|
49
14
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
else
|
54
|
-
end
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.require_paths = ["lib"]
|
55
18
|
end
|
56
|
-
|
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
module DT
|
3
|
+
RSpec.describe Config do
|
4
|
+
use_custom_let(:let_a, :attrs)
|
5
|
+
|
6
|
+
let(:instance) { described_class.new(attrs) }
|
7
|
+
|
8
|
+
subject { instance.send(m) }
|
9
|
+
|
10
|
+
describe "#env" do
|
11
|
+
let_m
|
12
|
+
it { is_expected.to eq ENV.to_h }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#rails" do
|
16
|
+
let_m
|
17
|
+
let_a(:rails)
|
18
|
+
# NOTE: We can't reliably test for constant probing since `defined?` is a language keyword.
|
19
|
+
context_when rails: :signature do
|
20
|
+
it { is_expected.to eq :signature }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#root_path" do
|
25
|
+
let_m
|
26
|
+
let(:pathname_double) { double "Pathname(raw_path)" }
|
27
|
+
let_a(:env)
|
28
|
+
let_a(:rails)
|
29
|
+
|
30
|
+
before :each do
|
31
|
+
expect(instance).to receive(:Pathname).with(raw_path).once.and_return(pathname_double)
|
32
|
+
expect(pathname_double).to receive(:realpath).once.and_return(:signature)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when Rails" do
|
36
|
+
let(:raw_path) { Pathname("/path/to/project") }
|
37
|
+
let_a(:rails) { double "rails" }
|
38
|
+
it do
|
39
|
+
expect(rails).to receive(:root).once.and_return(raw_path)
|
40
|
+
is_expected.to eq :signature
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context_when rails: nil do
|
45
|
+
context do
|
46
|
+
let(:bundle_gemfile) { self.class.bundle_gemfile }
|
47
|
+
let(:raw_path) { self.class.raw_path }
|
48
|
+
|
49
|
+
define_singleton_method(:raw_path) { "/path/to/project" }
|
50
|
+
define_singleton_method(:bundle_gemfile) { "#{raw_path}/Gemfile"}
|
51
|
+
|
52
|
+
context_when env: {"BUNDLE_GEMFILE" => bundle_gemfile } do
|
53
|
+
it { is_expected.to eq :signature }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context_when env: {} do
|
58
|
+
let(:raw_path) { Dir.pwd }
|
59
|
+
it do
|
60
|
+
subject
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end # describe "#root_path"
|
65
|
+
|
66
|
+
describe "#root_path=" do
|
67
|
+
let_a(:root_path)
|
68
|
+
|
69
|
+
subject { instance.root_path }
|
70
|
+
|
71
|
+
context_when root_path: "/some/path" do
|
72
|
+
it { is_expected.to eq Pathname("/some/path") }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
|
2
|
+
module DT
|
3
|
+
RSpec.describe Instance do
|
4
|
+
use_custom_let(:let_a, :attrs)
|
5
|
+
|
6
|
+
let(:instance) { described_class.new(attrs) }
|
7
|
+
|
8
|
+
subject { instance.send(m) }
|
9
|
+
|
10
|
+
describe "attributes" do
|
11
|
+
describe "#conf" do
|
12
|
+
let_m
|
13
|
+
it do
|
14
|
+
expect(DT).to receive(:conf).once.and_return(:signature)
|
15
|
+
is_expected.to eq :signature
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#dt_logger" do
|
20
|
+
let_m
|
21
|
+
it do
|
22
|
+
expect(Logger).to receive(:new).and_return(:signature)
|
23
|
+
expect(subject).to eq :signature
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#is_rails_console" do
|
28
|
+
let_m
|
29
|
+
let_a(:conf) { double "conf" }
|
30
|
+
let(:rails_double) { double "rails" }
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
expect(conf).to receive(:rails).at_least(:once).and_return(rails_double)
|
34
|
+
expect(rails_double).to receive(:const_defined?).with(:Console).and_return(is_const_defined)
|
35
|
+
end
|
36
|
+
|
37
|
+
context_when is_const_defined: true do
|
38
|
+
it { is_expected.to be true }
|
39
|
+
end
|
40
|
+
|
41
|
+
context_when is_const_defined: false do
|
42
|
+
it { is_expected.to be false }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#rails_logger" do
|
47
|
+
let_m
|
48
|
+
let_a(:conf) { double "conf" }
|
49
|
+
|
50
|
+
context "when Rails mode" do
|
51
|
+
let(:rails_double) { double "rails" }
|
52
|
+
|
53
|
+
it do
|
54
|
+
expect(conf).to receive(:rails).at_least(:once).and_return(rails_double)
|
55
|
+
expect(rails_double).to receive(:logger).and_return(:signature)
|
56
|
+
expect(subject).to eq :signature
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when non-Rails mode" do
|
61
|
+
it do
|
62
|
+
expect(conf).to receive(:rails).at_least(:once).and_return(nil)
|
63
|
+
expect(subject).to be nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#stderr" do
|
69
|
+
let_m
|
70
|
+
it { is_expected.to eq STDERR }
|
71
|
+
end
|
72
|
+
|
73
|
+
it { expect(instance).to alias_method(:rails_console?, :is_rails_console) }
|
74
|
+
end # describe "attributes"
|
75
|
+
|
76
|
+
describe "actions" do
|
77
|
+
describe "#_p" do
|
78
|
+
let_m
|
79
|
+
|
80
|
+
let_a(:conf) { Config.new(root_path: "/some/path") }
|
81
|
+
let_a(:is_rails_console)
|
82
|
+
|
83
|
+
# Output channels.
|
84
|
+
let_a(:dt_logger) { double "dt_logger" } # "1".
|
85
|
+
let_a(:rails_logger) { double "rails_logger" } # "2".
|
86
|
+
let_a(:stderr) { double "stderr" } # This one is a "backup" output channel which pairs with `rails_logger`.
|
87
|
+
|
88
|
+
let(:args) { ["Message", {kk: 12}] }
|
89
|
+
let(:caller) do
|
90
|
+
[
|
91
|
+
"/some/path/lib/file2:20 in `method2'",
|
92
|
+
"/some/path/lib/file1:10 in `method1'",
|
93
|
+
]
|
94
|
+
end
|
95
|
+
let(:msg1) { "#{pfx} Message" }
|
96
|
+
let(:msg2) { "#{pfx} {:kk=>12}"}
|
97
|
+
let(:pfx) { "[DT lib/file2:20 in `method2']" }
|
98
|
+
|
99
|
+
subject { instance.send(m, caller, *args) }
|
100
|
+
|
101
|
+
# Disable output channels in combos to leave out just one.
|
102
|
+
# Order: dt_logger, rails_logger, stdout (via `is_rails_console`).
|
103
|
+
|
104
|
+
def expect_to_dt
|
105
|
+
expect(dt_logger).to receive(:debug).once.with(msg1)
|
106
|
+
expect(dt_logger).to receive(:debug).once.with(msg2)
|
107
|
+
end
|
108
|
+
|
109
|
+
def expect_to_rails
|
110
|
+
expect(rails_logger).to receive(:debug).once.with(msg1)
|
111
|
+
expect(rails_logger).to receive(:debug).once.with(msg2)
|
112
|
+
end
|
113
|
+
|
114
|
+
def expect_to_stderr
|
115
|
+
expect(stderr).to receive(:puts).once.with(msg1)
|
116
|
+
expect(stderr).to receive(:puts).once.with(msg2)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Disable 1.
|
120
|
+
context_when dt_logger: nil do
|
121
|
+
context_when is_rails_console: true do
|
122
|
+
it do
|
123
|
+
expect_to_rails
|
124
|
+
subject
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it do
|
129
|
+
expect_to_rails
|
130
|
+
expect_to_stderr
|
131
|
+
subject
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Disable 2.
|
136
|
+
context_when rails_logger: nil do
|
137
|
+
it do
|
138
|
+
expect_to_dt
|
139
|
+
expect_to_stderr
|
140
|
+
subject
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Disable 1 and 2.
|
145
|
+
context_when dt_logger: nil, rails_logger: nil do
|
146
|
+
it do
|
147
|
+
expect_to_stderr
|
148
|
+
subject
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Disable all.
|
153
|
+
context_when dt_logger: nil, rails_logger: nil, stderr: nil do
|
154
|
+
it "generally works" do
|
155
|
+
# Just expect nothing to crash by using `nil`.
|
156
|
+
# RSpec negative expectations are warned against (which I think is right).
|
157
|
+
subject
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Generic case, all channels enabled.
|
162
|
+
context_when is_rails_console: false do
|
163
|
+
it do
|
164
|
+
expect_to_dt
|
165
|
+
expect_to_rails
|
166
|
+
expect_to_stderr
|
167
|
+
subject
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|