rails_dt 0.1.4 → 1.2.0

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.yardopts +2 -0
  4. data/Gemfile +14 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +43 -135
  7. data/lib/dt.rb +31 -215
  8. data/lib/dt/config.rb +74 -0
  9. data/lib/dt/instance.rb +117 -0
  10. data/lib/rails_dt.rb +3 -2
  11. data/lib/rails_dt/version.rb +4 -0
  12. data/rails_dt.gemspec +12 -50
  13. data/spec/lib/dt/config_spec.rb +76 -0
  14. data/spec/lib/dt/instance_spec.rb +173 -0
  15. data/spec/lib/dt_spec.rb +14 -0
  16. data/spec/lib/rails_dt_spec.rb +6 -0
  17. data/spec/lib/spec/alias_method_matcher_spec.rb +16 -0
  18. data/spec/lib/spec/context_when_spec.rb +32 -0
  19. data/spec/lib/spec/let_m_spec.rb +104 -0
  20. data/spec/lib/spec/use_custom_let_spec.rb +46 -0
  21. data/spec/spec_helper.rb +6 -0
  22. data/spec/support/00extend_x.rb +23 -0
  23. data/spec/support/alias_method_matcher.rb +20 -0
  24. data/spec/support/context_when.rb +39 -0
  25. data/spec/support/let_m.rb +27 -0
  26. data/spec/support/use_custom_let.rb +80 -0
  27. metadata +43 -52
  28. data/README.html +0 -171
  29. data/Rakefile +0 -68
  30. data/VERSION.yml +0 -4
  31. data/generators/rails_dt/USAGE +0 -11
  32. data/generators/rails_dt/WARNING +0 -2
  33. data/generators/rails_dt/rails_dt_generator.rb +0 -9
  34. data/generators/rails_dt/templates/INSTALL +0 -20
  35. data/generators/rails_dt/templates/dt.css +0 -27
  36. data/generators/rails_dt/templates/dt.rb +0 -4
  37. data/init.rb +0 -2
  38. data/lib/dt/action_controller_extensions.rb +0 -29
  39. data/lib/generators/rails_dt/USAGE +0 -11
  40. data/lib/generators/rails_dt/rails_dt_generator.rb +0 -9
  41. data/lib/generators/rails_dt/templates/INSTALL +0 -20
  42. data/lib/generators/rails_dt/templates/dt.css +0 -27
  43. data/lib/generators/rails_dt/templates/dt.rb +0 -4
@@ -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.
@@ -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.
@@ -1,2 +1,3 @@
1
- # A bridge between names.
2
- require File.join(File.dirname(__FILE__), "dt")
1
+
2
+ # Main gem require. Load all libraries.
3
+ Dir[File.expand_path("../**/*.rb", __FILE__)].each { |fn| require fn }
@@ -0,0 +1,4 @@
1
+
2
+ module RailsDt
3
+ VERSION = "1.2.0"
4
+ end
@@ -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
- Gem::Specification.new do |s|
7
- s.name = %q{rails_dt}
8
- s.version = "0.1.4"
2
+ # TODO: Finalize.
3
+ #require_relative ""
4
+ require File.expand_path("../lib/rails_dt/version", __FILE__)
9
5
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ Gem::Specification.new do |s|
7
+ s.name = "rails_dt"
8
+ s.version = RailsDt::VERSION
11
9
  s.authors = ["Alex Fortuna"]
12
- s.date = %q{2011-07-13}
13
- s.description = %q{Rails Debug Toolkit}
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
- if s.respond_to? :specification_version then
48
- s.specification_version = 3
13
+ s.summary = "Ruby/Rails debug toolkit"
49
14
 
50
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
- else
52
- end
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