dial 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1c66ebfd5f92223dfdb75e7f13880a293074408ccfbf835eae6b641bed9b8fcc
4
+ data.tar.gz: ef11315610241303543d3319ead19364effe60b326ee29f901ece1623331e8f2
5
+ SHA512:
6
+ metadata.gz: 004b0ed1ce0ba338bce6ec32a9c15b634263d6bdac011215a49497923c5f72bd6730d31ea76a6f38ce910efe67e09322d25efdd5e2dd97a6fd91959afe14bdcc
7
+ data.tar.gz: a60be22b96db02f9bdcfe3d1a314ef98fa1b1d51af6b2744962156fe191703ad07d1b7fc8242fbefcb8098d4d889302cc7f66a3a6a0775ee6758102f8904c50c
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2024-11-08
4
+
5
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Joshua Young
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Dial
2
+
3
+ WIP
4
+
5
+ A modern profiler for Rails applications.
6
+
7
+ <details>
8
+ <summary>POC</summary>
9
+
10
+ ![Demo 1](https://github.com/user-attachments/assets/904daaf5-3f18-4c94-a7e4-9418539a19f3)
11
+ ![Demo 2](https://github.com/user-attachments/assets/eb6ed9f5-b258-42df-8901-222c7d969fdd)
12
+
13
+ </details>
14
+
15
+ ## Installation
16
+
17
+ Install the gem and add it to your application's Gemfile by executing:
18
+
19
+ ```bash
20
+ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
21
+ ```
22
+
23
+ ## Development
24
+
25
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the
26
+ tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
27
+
28
+ ## Contributing
29
+
30
+ Bug reports and pull requests are welcome on GitHub at https://github.com/joshuay03/dial.
31
+
32
+ ## License
33
+
34
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
35
+
36
+ ## Code of Conduct
37
+
38
+ Everyone interacting in the Dial project's codebases, issue trackers, chat rooms and mailing lists is expected to follow
39
+ the [code of conduct](https://github.com/joshuay03/dial/blob/main/CODE_OF_CONDUCT.md).
data/dial.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/dial/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "dial"
7
+ spec.version = Dial::VERSION
8
+ spec.authors = ["Joshua Young"]
9
+ spec.email = ["djry1999@gmail.com"]
10
+
11
+ spec.summary = "A modern Rails profiler"
12
+ spec.homepage = "https://github.com/joshuay03/dial"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.0.0"
15
+
16
+ spec.metadata["source_code_uri"] = spec.homepage
17
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
18
+
19
+ spec.files = Dir["{lib}/**/*", "**/*.{gemspec,md,txt}"]
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "railties", ">= 7.0.0", "<= 8.0"
23
+ spec.add_dependency "activerecord", ">= 7.0.0", "<= 8.0"
24
+ spec.add_dependency "actionpack", ">= 7.0.0", "<= 8.0"
25
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ module Constants
5
+ DIAL_REQUEST_TIMING = "dial_request_timing"
6
+ end
7
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ruby_stat"
4
+ require_relative "rails_stat"
5
+ require_relative "constants"
6
+ require_relative "panel"
7
+
8
+ module Dial
9
+ class Middleware
10
+ include RubyStat
11
+ include RailsStat
12
+ include Constants
13
+
14
+ def initialize app
15
+ @app = app
16
+ end
17
+
18
+ def call env
19
+ start_time = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
20
+
21
+ ruby_vm_stat_before = RubyVM.stat
22
+ gc_stat_before = GC.stat
23
+ gc_stat_heap_before = GC.stat_heap
24
+
25
+ status, headers, rack_body = @app.call env
26
+ return [status, headers, rack_body] unless headers[::Rack::CONTENT_TYPE]&.include? "text/html"
27
+
28
+ finish_time = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
29
+ env[DIAL_REQUEST_TIMING] = ((finish_time - start_time) * 1_000).round 2
30
+
31
+ ruby_vm_stat_diff = ruby_vm_stat_diff ruby_vm_stat_before, RubyVM.stat
32
+ gc_stat_diff = gc_stat_diff gc_stat_before, GC.stat
33
+ gc_stat_heap_diff = gc_stat_heap_diff gc_stat_heap_before, GC.stat_heap
34
+ server_timing = server_timing headers
35
+
36
+ body = String.new.tap do |str|
37
+ rack_body.each { |chunk| str << chunk }
38
+ rack_body.close if body.respond_to? :close
39
+ end.sub "</body>", <<~HTML
40
+ #{Panel.html env, ruby_vm_stat_diff, gc_stat_diff, gc_stat_heap_diff, server_timing}
41
+ </body>
42
+ HTML
43
+
44
+ headers[::Rack::CONTENT_LENGTH] = body.bytesize.to_s
45
+
46
+ [status, headers, [body]]
47
+ end
48
+ end
49
+ end
data/lib/dial/panel.rb ADDED
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+
5
+ module Dial
6
+ class Panel
7
+ class << self
8
+ include Constants
9
+
10
+ def html env, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
11
+ <<~HTML
12
+ <style>#{style}</style>
13
+
14
+ <div id="dial">
15
+ <div id="dial-preview">
16
+ <span>#{formatted_rails_route_info(env)} | #{formatted_request_timing(env)}</span>
17
+ <span>#{formatted_rails_version}</span>
18
+ <span>#{formatted_rack_version}</span>
19
+ <span>#{formatted_ruby_version}</span>
20
+ </div>
21
+
22
+ <div id="dial-details">
23
+ <hr>
24
+
25
+ <details>
26
+ <summary>RubyVM stat</summary>
27
+ <div class="section">
28
+ #{formatted_ruby_vm_stat(ruby_vm_stat)}
29
+ </div>
30
+ </details>
31
+
32
+ <details>
33
+ <summary>GC stat</summary>
34
+ <div class="section">
35
+ #{formatted_gc_stat(gc_stat)}
36
+ </div>
37
+ </details>
38
+
39
+ <details>
40
+ <summary>GC stat heap</summary>
41
+ <div class="section">
42
+ #{formatted_gc_stat_heap(gc_stat_heap)}
43
+ </div>
44
+ </details>
45
+
46
+ <details>
47
+ <summary>Server timing</summary>
48
+ <div class="section">
49
+ #{formatted_server_timing(server_timing)}
50
+ </div>
51
+ </details>
52
+ </div>
53
+ </div>
54
+
55
+ <script>#{script}</script>
56
+ HTML
57
+ end
58
+
59
+ private
60
+
61
+ def style
62
+ <<~CSS
63
+ #dial {
64
+ z-index: 9999;
65
+ position: fixed;
66
+ bottom: 0;
67
+ right: 0;
68
+ background-color: white;
69
+ border-top-left-radius: 1rem;
70
+ box-shadow: -0.2rem -0.2rem 0.4rem rgba(0, 0, 0, 0.5);
71
+ display: flex;
72
+ flex-direction: column;
73
+ padding: 0.5rem;
74
+ font-size: 0.85rem;
75
+ color: black;
76
+ cursor: pointer;
77
+ }
78
+
79
+ #dial-preview {
80
+ display: flex;
81
+ flex-direction: column;
82
+ cursor: pointer;
83
+ }
84
+
85
+ #dial-details {
86
+ display: none;
87
+ }
88
+
89
+ .section {
90
+ display: flex;
91
+ flex-direction: column;
92
+ margin-top: 0.5rem;
93
+ }
94
+
95
+ span {
96
+ text-align: left;
97
+ }
98
+
99
+ hr {
100
+ width: -moz-available;
101
+ margin-top: 0.5rem;
102
+ }
103
+
104
+ details {
105
+ margin-top: 0.5rem;
106
+ text-align: left;
107
+ }
108
+
109
+ summary {
110
+ margin-bottom: 0.25rem;
111
+ cursor: pointer;
112
+ }
113
+ CSS
114
+ end
115
+
116
+ def script
117
+ <<~JS
118
+ const dialPreview = document.getElementById("dial-preview");
119
+ const dialDetails = document.getElementById("dial-details");
120
+ dialPreview.addEventListener("click", () => {
121
+ const collapsed = ["", "none"].includes(dialDetails.style.display);
122
+ dialDetails.style.display = collapsed ? "block" : "none";
123
+ });
124
+ JS
125
+ end
126
+
127
+ def formatted_rails_route_info env
128
+ rails_route_info = begin
129
+ ::Rails.application.routes.recognize_path env[::Rack::PATH_INFO], method: env[::Rack::REQUEST_METHOD]
130
+ rescue ::ActionController::RoutingError
131
+ {}
132
+ end.then do |info|
133
+ "<b>Controller:</b> #{info[:controller] || "NA"} | <b>Action:</b> #{info[:action] || "NA"}"
134
+ end
135
+ end
136
+
137
+ def formatted_request_timing env
138
+ "<b>Request timing:</b> #{env[DIAL_REQUEST_TIMING]}ms"
139
+ end
140
+
141
+ def formatted_rails_version
142
+ "<b>Rails version:</b> #{::Rails::VERSION::STRING}"
143
+ end
144
+
145
+ def formatted_rack_version
146
+ "<b>Rack version:</b> #{::Rack.release}"
147
+ end
148
+
149
+ def formatted_ruby_version
150
+ "<b>Ruby version:</b> #{RUBY_DESCRIPTION}"
151
+ end
152
+
153
+ def formatted_ruby_vm_stat ruby_vm_stat
154
+ ruby_vm_stat.map { |key, value| "<span><b>#{key}:</b> #{value}</span>" }.join
155
+ end
156
+
157
+ def formatted_gc_stat gc_stat
158
+ gc_stat.map { |key, value| "<span><b>#{key}:</b> #{value}</span>" }.join
159
+ end
160
+
161
+ def formatted_gc_stat_heap gc_stat_heap
162
+ gc_stat_heap.map do |slot, stats|
163
+ <<~HTML
164
+ <div class="section">
165
+ <span><u>Heap slot #{slot}</u></span>
166
+ <div class="section">
167
+ #{gc_stat_heap[slot].map { |key, value| "<span><b>#{key}:</b> #{value}</span>" }.join}
168
+ </div>
169
+ </div>
170
+ HTML
171
+ end.join
172
+ end
173
+
174
+ def formatted_server_timing server_timing
175
+ if server_timing.any?
176
+ server_timing
177
+ # TODO: Nested sorting
178
+ .sort_by { |_, timing| -timing }
179
+ .map { |event, timing| "<span><b>#{event}:</b> #{timing}</span>" }.join
180
+ else
181
+ "NA"
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ module RailsStat
5
+ private
6
+
7
+ def server_timing headers
8
+ timing = if (ActionDispatch.const_defined? :Constants) && (ActionDispatch::Constants.const_defined? :SERVER_TIMING)
9
+ headers[ActionDispatch::Constants::SERVER_TIMING]
10
+ else
11
+ headers["Server-Timing"]
12
+ end
13
+ (timing || "").split(", ").to_h do |pair|
14
+ event, duration = pair.split ";dur="
15
+ [event, duration.to_f]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+
5
+ require_relative "middleware"
6
+
7
+ module Dial
8
+ class Railtie < ::Rails::Railtie
9
+ initializer "dial.use_middleware" do |app|
10
+ app.middleware.insert_before 0, Middleware
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ module RubyStat
5
+ private
6
+
7
+ def ruby_vm_stat_diff before, after
8
+ stat_diff before, after, except: [:next_shape_id]
9
+ end
10
+
11
+ def gc_stat_diff before, after
12
+ stat_diff before, after, except: [
13
+ :heap_allocatable_slots,
14
+ :malloc_increase_bytes_limit,
15
+ :remembered_wb_unprotected_objects_limit,
16
+ :old_objects_limit,
17
+ :oldmalloc_increase_bytes_limit
18
+ ]
19
+ end
20
+
21
+ def gc_stat_heap_diff before, after
22
+ after.each_with_object({}) do |(slot_index, slot_stat), diff|
23
+ diff[slot_index] = stat_diff before[slot_index], slot_stat, except: [:slot_size]
24
+ end
25
+ end
26
+
27
+ def stat_diff before, after, except: []
28
+ after.except(*except).each_with_object({}) do |(key, value), diff|
29
+ diff[key] = value - before[key]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ VERSION = "0.1.0"
5
+ end
data/lib/dial.rb ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dial/version"
4
+ require_relative "dial/railtie"
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dial
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joshua Young
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2024-11-08 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: railties
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 7.0.0
19
+ - - "<="
20
+ - !ruby/object:Gem::Version
21
+ version: '8.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 7.0.0
29
+ - - "<="
30
+ - !ruby/object:Gem::Version
31
+ version: '8.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: activerecord
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: 7.0.0
39
+ - - "<="
40
+ - !ruby/object:Gem::Version
41
+ version: '8.0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 7.0.0
49
+ - - "<="
50
+ - !ruby/object:Gem::Version
51
+ version: '8.0'
52
+ - !ruby/object:Gem::Dependency
53
+ name: actionpack
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 7.0.0
59
+ - - "<="
60
+ - !ruby/object:Gem::Version
61
+ version: '8.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 7.0.0
69
+ - - "<="
70
+ - !ruby/object:Gem::Version
71
+ version: '8.0'
72
+ email:
73
+ - djry1999@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - CHANGELOG.md
79
+ - CODE_OF_CONDUCT.md
80
+ - LICENSE.txt
81
+ - README.md
82
+ - dial.gemspec
83
+ - lib/dial.rb
84
+ - lib/dial/constants.rb
85
+ - lib/dial/middleware.rb
86
+ - lib/dial/panel.rb
87
+ - lib/dial/rails_stat.rb
88
+ - lib/dial/railtie.rb
89
+ - lib/dial/ruby_stat.rb
90
+ - lib/dial/version.rb
91
+ homepage: https://github.com/joshuay03/dial
92
+ licenses:
93
+ - MIT
94
+ metadata:
95
+ source_code_uri: https://github.com/joshuay03/dial
96
+ changelog_uri: https://github.com/joshuay03/dial/blob/main/CHANGELOG.md
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: 3.0.0
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubygems_version: 3.6.0.dev
112
+ specification_version: 4
113
+ summary: A modern Rails profiler
114
+ test_files: []