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.
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