rails_server_hotkeys 1.1.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dcf7eece0e781456e10984440dacaa89d63f1c8a2d5e253b3e46edbb8777bd36
4
+ data.tar.gz: 25f0dc57f124910142dfef2d37789e772faf26b04ea00c564bb3adfaa2e84072
5
+ SHA512:
6
+ metadata.gz: bbd24268025046933f74dc66a92a6359c79253cb39b33dbf3eac561ec91619c0b5931fe90e36a17f11a9d393313610395a33b30af37600101ec5cfd88680ddf4
7
+ data.tar.gz: 8c259bab6875bdbeb776e5ee0e5ec89c46abd65ca6843d4bbeece9c4513cba5687e00bfec2d55451b78b9af90728f158f0b756f01c492467ecba2845090e9163
data/CHANGELOG.md ADDED
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.1.1] - 2026-10-31
10
+
11
+ ### Changed
12
+ - Gem metadata: source code, changelog and bug tracker links; MFA required to publish.
13
+ - `CHANGELOG.md` is now included in the gem package.
14
+
15
+ ## [1.1.0] - 2026-10-31
16
+
17
+ ### Added
18
+ - Hotkeys for `rails server`: `r` restart, `c` clear, `o` open browser, `h`/`?` help, `q` quit.
19
+ - `RailsServerHotkeys.register` / `unregister` for custom hotkeys.
20
+ - `RailsServerHotkeys.color` to customize message color (ANSI name, 0-255, hex or `nil`); honors `NO_COLOR`.
21
+ - `config.hotkeys.enabled`, `config.hotkeys.url` and `RAILS_SERVER_HOTKEYS=false` to configure or disable.
22
+ - `o` opens the port the server is actually listening on.
23
+ - Banner shown after Puma's "Use Ctrl-C to stop".
24
+
25
+ [Unreleased]: https://github.com/samuelpismel/rails_server_hotkeys/compare/v1.1.1...HEAD
26
+ [1.1.1]: https://github.com/samuelpismel/rails_server_hotkeys/compare/v1.1.0...v1.1.1
27
+ [1.1.0]: https://github.com/samuelpismel/rails_server_hotkeys/releases/tag/v1.1.0
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Samuel Gavassi Pismel
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # rails_server_hotkeys
2
+
3
+ Expo-style keyboard shortcuts for `bin/rails server`. Press `r` to restart the server — no more `touch tmp/restart.txt` in another terminal.
4
+
5
+ ```
6
+ => Booting Puma
7
+ ...
8
+ › Press r to restart, h for help
9
+ ```
10
+
11
+ ## Install
12
+
13
+ ```ruby
14
+ # Gemfile
15
+ gem "rails_server_hotkeys", group: :development
16
+ ```
17
+
18
+ That's it. Run `bin/rails s` and press a key.
19
+
20
+ | Key | Action |
21
+ |---|---|
22
+ | `r` | restart the server (same as `bin/rails restart`) |
23
+ | `c` | clear the terminal |
24
+ | `o` | open the app in the browser |
25
+ | `h` / `?` | list hotkeys |
26
+ | `q` | quit the server |
27
+
28
+ ## Custom hotkeys
29
+
30
+ ```ruby
31
+ # config/initializers/hotkeys.rb
32
+ if defined?(RailsServerHotkeys)
33
+ RailsServerHotkeys.register("m", "run db:migrations") { system("bin/rails db:migrate") }
34
+ RailsServerHotkeys.register("t", "run custom task") { system("bin/rails myapp:do_something") }
35
+ RailsServerHotkeys.register("e", "run system echo") { system("echo 'custom message'") }
36
+ end
37
+ ```
38
+
39
+ Registering an existing key replaces it; `RailsServerHotkeys.unregister("o")` removes one.
40
+
41
+ ## Configuration
42
+
43
+ ```ruby
44
+ # config/environments/development.rb
45
+ config.hotkeys.enabled = false # turn it off
46
+ config.hotkeys.url = "https://myapp.test" # URL opened by `o` (default: localhost on the port the server is listening on)
47
+ ```
48
+
49
+ Or disable for a single run: `RAILS_SERVER_HOTKEYS=false bin/rails s`.
50
+
51
+ ### Color
52
+
53
+ Messages are light blue by default. Change it in an initializer:
54
+
55
+ ```ruby
56
+ # config/initializers/hotkeys.rb
57
+ if defined?(RailsServerHotkeys)
58
+ RailsServerHotkeys.color = :green # black, red, green, yellow, blue, magenta, cyan, white,
59
+ # or light_* of any of them (the default is :green)
60
+ RailsServerHotkeys.color = 208 # 256-color palette (0-255)
61
+ RailsServerHotkeys.color = "#ff8800" # true color (hex)
62
+ RailsServerHotkeys.color = nil # no color
63
+ end
64
+ ```
65
+
66
+ An invalid value raises `ArgumentError` at boot. Colors are skipped when the output isn't a terminal or `NO_COLOR` is set.
67
+
68
+ ## When is it active?
69
+
70
+ Only for `rails server`, in the `development` environment, when stdin is a terminal. Console, rake, tests, jobs and non-interactive runs (Docker without `-it`, CI) are untouched.
71
+
72
+ ## Caveats
73
+
74
+ - **Restart needs Puma's `tmp_restart` plugin.** It's in the `config/puma.rb` generated by Rails; if yours lacks it, add `plugin :tmp_restart`.
75
+ - **`bin/dev` (foreman) doesn't forward stdin**, so hotkeys can't work there. Run `bin/rails s` directly, or use overmind and `overmind connect web`.
76
+ - **Unix/macOS only** (uses `stty`). On Windows the gem does nothing.
77
+
78
+ ## Development
79
+
80
+ ```sh
81
+ bundle install
82
+ bundle exec rake test
83
+ ```
84
+
85
+ ### Trying it in a dummy app
86
+
87
+ The unit tests run without Rails, but hotkeys only show up for real under `rails server` in a terminal. To try your changes by hand, create a throwaway app next to the gem:
88
+
89
+ ```sh
90
+ # Needs the rails and bundler gems (`gem install rails bundler`)
91
+ cd ..
92
+ rails new hotkeys-dummy --minimal --skip-git
93
+ cd hotkeys-dummy
94
+
95
+ # Point the app at your local copy of the gem
96
+ echo 'gem "rails_hotkeys", path: "../restart-rails-hotkeys", group: :development' >> Gemfile
97
+ bundle install
98
+
99
+ bin/rails s
100
+ ```
101
+
102
+ Adjust the `path:` if your clone has a different folder name.
103
+
104
+ You should see this in light blue, right after Puma's `Use Ctrl-C to stop`:
105
+
106
+ ```
107
+ › Press r to restart, h for help
108
+ ```
109
+
110
+ Things to check:
111
+
112
+ - `r` prints `* Restarting...` and the server comes back up
113
+ - `h` lists the hotkeys, `c` clears the screen
114
+ - `o` opens the browser on the port the server is listening on (try `bin/rails s -p 4000`)
115
+ - `q` or Ctrl+C stops the server, and your shell echoes what you type again
116
+ - `bin/rails s < /dev/null` boots normally with no banner (no TTY, hotkeys off)
117
+
118
+ Because the gem is loaded through `path:`, edits to it take effect on the next restart: press `r` instead of stopping the server. You don't need to run `bundle install` again unless you change the gemspec.
119
+
120
+ ## License
121
+
122
+ MIT
@@ -0,0 +1,94 @@
1
+ require "fileutils"
2
+ require "rbconfig"
3
+ require "socket"
4
+
5
+ module RailsServerHotkeys
6
+ # Built-in hotkeys. They resolve paths and URLs when pressed, so they work no
7
+ # matter when the app finishes booting.
8
+ module Actions
9
+ class << self
10
+ attr_writer :root, :url, :output
11
+
12
+ def root
13
+ @root || (defined?(Rails) && Rails.respond_to?(:root) && Rails.root) || Dir.pwd
14
+ end
15
+
16
+ def url
17
+ @url || "http://localhost:#{listening_ports.first || ENV.fetch("PORT", 3000)}"
18
+ end
19
+
20
+ # Ports this process is actually listening on, however they were chosen
21
+ # (-p, PORT, config/puma.rb). Resolved on demand, so restarts are covered.
22
+ def listening_ports
23
+ ObjectSpace.each_object(TCPServer).filter_map do |server|
24
+ next if server.closed?
25
+
26
+ server.local_address.ip_port
27
+ rescue IOError, SystemCallError
28
+ nil
29
+ end.uniq.sort
30
+ end
31
+
32
+ def output
33
+ @output || $stdout
34
+ end
35
+
36
+ def banner
37
+ colorize("\n› Press r to restart, h for help")
38
+ end
39
+
40
+ # Uses RailsServerHotkeys.color, only on a real terminal (and respecting NO_COLOR).
41
+ def colorize(text)
42
+ code = Color.sgr(RailsServerHotkeys.color)
43
+ return text if code.nil? || ENV["NO_COLOR"] || !(output.respond_to?(:tty?) && output.tty?)
44
+
45
+ "\e[#{code}m#{text}\e[0m"
46
+ end
47
+
48
+ # Same as `bin/rails restart`; picked up by Puma's tmp_restart plugin.
49
+ def restart
50
+ path = File.join(root.to_s, "tmp", "restart.txt")
51
+ FileUtils.mkdir_p(File.dirname(path))
52
+ FileUtils.touch(path)
53
+ output.puts colorize("› Restarting...")
54
+ end
55
+
56
+ def clear
57
+ output.print "\e[H\e[2J\e[3J"
58
+ output.puts banner
59
+ end
60
+
61
+ def open_browser
62
+ command = case RbConfig::CONFIG["host_os"]
63
+ when /darwin/ then "open"
64
+ else "xdg-open"
65
+ end
66
+ output.puts colorize("› Opening #{url}")
67
+ pid = Process.spawn(command, url, out: File::NULL, err: File::NULL)
68
+ Process.detach(pid)
69
+ end
70
+
71
+ def help
72
+ output.puts colorize("› Hotkeys:")
73
+ RailsServerHotkeys.hotkeys.each_value do |hotkey|
74
+ output.puts colorize(" #{hotkey.key} #{hotkey.description}")
75
+ end
76
+ end
77
+
78
+ def quit
79
+ Process.kill(:INT, Process.pid)
80
+ end
81
+
82
+ def register_defaults
83
+ RailsServerHotkeys.register("r", "restart the server") { restart }
84
+ RailsServerHotkeys.register("c", "clear the terminal") { clear }
85
+ RailsServerHotkeys.register("o", "open the app in the browser") { open_browser }
86
+ RailsServerHotkeys.register("h", "show this help") { help }
87
+ RailsServerHotkeys.register("?", "show this help") { help }
88
+ RailsServerHotkeys.register("q", "quit the server") { quit }
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ RailsServerHotkeys::Actions.register_defaults
@@ -0,0 +1,28 @@
1
+ module RailsServerHotkeys
2
+ # Runs a block once the server has booted, so output lands after Puma's
3
+ # "Use Ctrl-C to stop" instead of in the middle of its startup log.
4
+ module BootHook
5
+ # Puma >= 6.5 renamed fire_on_booted! to fire_after_booted!.
6
+ PUMA_EVENTS = %i[fire_after_booted! fire_on_booted!].freeze
7
+
8
+ def self.call(&block)
9
+ load_puma_events
10
+ event = defined?(Puma::Events) && PUMA_EVENTS.find { |name| Puma::Events.method_defined?(name) }
11
+ return block.call unless event
12
+
13
+ Puma::Events.prepend(Module.new do
14
+ define_method(event) do |*args, **kwargs|
15
+ super(*args, **kwargs).tap { block.call }
16
+ end
17
+ end)
18
+ end
19
+
20
+ # When Rails runs server blocks, the Puma handler is chosen but
21
+ # Puma::Events isn't required yet.
22
+ def self.load_puma_events
23
+ require "puma/events" if defined?(Puma) && !defined?(Puma::Events)
24
+ rescue LoadError
25
+ nil
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ module RailsServerHotkeys
2
+ # Turns a user-facing color setting into an ANSI SGR code.
3
+ module Color
4
+ NAMES = %i[black red green yellow blue magenta cyan white].freeze
5
+
6
+ CODES = NAMES.each_with_index.each_with_object({}) do |(name, index), codes|
7
+ codes[name] = (30 + index).to_s
8
+ codes[:"light_#{name}"] = (90 + index).to_s
9
+ end.freeze
10
+
11
+ HEX = /\A#?(\h{2})(\h{2})(\h{2})\z/
12
+
13
+ # :green / "light_green" => named color, 0..255 => 256-color palette,
14
+ # "#ff8800" => true color, nil / false => no color.
15
+ def self.sgr(color)
16
+ case color
17
+ when nil, false then nil
18
+ when Integer
19
+ "38;5;#{color}" if color.between?(0, 255)
20
+ when Symbol, String
21
+ CODES[color.to_sym] || (match = HEX.match(color.to_s)) && "38;2;#{match.captures.map(&:hex).join(";")}"
22
+ end
23
+ end
24
+
25
+ def self.valid?(color)
26
+ color.nil? || color == false || !sgr(color).nil?
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ module RailsServerHotkeys
2
+ # Reads keys from +input+ and runs the matching hotkey. Unknown keys are ignored.
3
+ class Listener
4
+ def initialize(input:, output:, hotkeys:)
5
+ @input = input
6
+ @output = output
7
+ @hotkeys = hotkeys
8
+ end
9
+
10
+ def start
11
+ @thread = Thread.new { run }
12
+ @thread.name = "rails_server_hotkeys"
13
+ @thread.report_on_exception = false
14
+ @thread
15
+ end
16
+
17
+ def run
18
+ while (char = @input.getc)
19
+ handle(char)
20
+ end
21
+ rescue IOError, SystemCallError
22
+ # stdin closed; nothing left to listen to
23
+ end
24
+
25
+ def handle(char)
26
+ hotkey = @hotkeys[char] || @hotkeys[char.downcase]
27
+ return unless hotkey
28
+
29
+ hotkey.action.call
30
+ rescue StandardError => e
31
+ @output.puts "[rails_server_hotkeys] '#{char}' failed: #{e.class}: #{e.message}"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,18 @@
1
+ require "rails/railtie"
2
+
3
+ module RailsServerHotkeys
4
+ class Railtie < Rails::Railtie
5
+ config.hotkeys = ActiveSupport::OrderedOptions.new
6
+ config.hotkeys.enabled = true
7
+ config.hotkeys.url = nil
8
+
9
+ # Runs only for `rails server`; never for console, rake, tests or jobs.
10
+ server do
11
+ options = Rails.application.config.hotkeys
12
+ next unless RailsServerHotkeys.enabled?(rails_env: Rails.env, config_enabled: options.enabled)
13
+
14
+ RailsServerHotkeys::Actions.url = options.url if options.url
15
+ RailsServerHotkeys.start
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ module RailsServerHotkeys
2
+ # Puts the TTY in "cbreak" mode: keys are delivered one at a time and not
3
+ # echoed, while output processing (OPOST) and signals (ISIG, so Ctrl+C) stay
4
+ # untouched. IO#raw would disable OPOST and make the server logs staircase.
5
+ class Terminal
6
+ # Puma restarts by exec'ing a new process, which skips at_exit. Give the
7
+ # terminal back right before any exec so the new process sees (and saves)
8
+ # the user's original settings.
9
+ module RestoreBeforeExec
10
+ def exec(*args)
11
+ RailsServerHotkeys::Terminal.current&.restore!
12
+ super
13
+ end
14
+ end
15
+
16
+ class << self
17
+ attr_accessor :current
18
+ end
19
+
20
+ def initialize(input)
21
+ @input = input
22
+ end
23
+
24
+ def enable!
25
+ @state = stty_state
26
+ return unless @state && stty("-icanon", "-echo", "min", "1")
27
+
28
+ self.class.current = self
29
+ Kernel.singleton_class.prepend(RestoreBeforeExec)
30
+ Process.singleton_class.prepend(RestoreBeforeExec)
31
+ at_exit { restore! }
32
+ end
33
+
34
+ def restore!
35
+ stty(@state) if @state
36
+ @state = nil
37
+ end
38
+
39
+ private
40
+
41
+ def stty_state
42
+ state = IO.popen(%w[stty -g], in: @input, err: File::NULL, &:read).strip
43
+ state.empty? ? nil : state
44
+ rescue SystemCallError
45
+ nil
46
+ end
47
+
48
+ def stty(*args)
49
+ system("stty", *args, in: @input, err: File::NULL)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module RailsServerHotkeys
2
+ VERSION = "1.1.1"
3
+ end
@@ -0,0 +1,76 @@
1
+ require "rails_server_hotkeys/version"
2
+ require "rails_server_hotkeys/terminal"
3
+ require "rails_server_hotkeys/listener"
4
+ require "rails_server_hotkeys/boot_hook"
5
+ require "rails_server_hotkeys/color"
6
+
7
+ module RailsServerHotkeys
8
+ Hotkey = Struct.new(:key, :description, :action)
9
+ DEFAULT_COLOR = :green
10
+
11
+ class << self
12
+ # Registers a hotkey. Registering an existing key replaces it.
13
+ #
14
+ # RailsServerHotkeys.register("m", "Run migrations") { system("bin/rails db:migrate") }
15
+ def register(key, description, &action)
16
+ raise ArgumentError, "hotkey must be a single character" unless key.is_a?(String) && key.length == 1
17
+ raise ArgumentError, "a block is required" unless action
18
+
19
+ hotkeys[key] = Hotkey.new(key, description, action)
20
+ end
21
+
22
+ def unregister(key)
23
+ hotkeys.delete(key)
24
+ end
25
+
26
+ def hotkeys
27
+ @hotkeys ||= {}
28
+ end
29
+
30
+ # Color of the gem's messages.
31
+ #
32
+ # RailsServerHotkeys.color = :green # any of Color::CODES
33
+ # RailsServerHotkeys.color = 208 # 256-color palette
34
+ # RailsServerHotkeys.color = "#ff8800" # true color
35
+ # RailsServerHotkeys.color = nil # no color
36
+ def color
37
+ defined?(@color) ? @color : DEFAULT_COLOR
38
+ end
39
+
40
+ def color=(value)
41
+ unless Color.valid?(value)
42
+ raise ArgumentError, "invalid color #{value.inspect}; use one of #{Color::CODES.keys.join(", ")}, " \
43
+ "an integer 0-255, a hex string like \"#ff8800\", or nil"
44
+ end
45
+
46
+ @color = value
47
+ end
48
+
49
+ def reset_color
50
+ remove_instance_variable(:@color) if defined?(@color)
51
+ end
52
+
53
+ # Whether hotkeys should run for this process.
54
+ def enabled?(input: $stdin, env: ENV, rails_env: nil, config_enabled: true)
55
+ return false unless config_enabled
56
+ return false if %w[0 false off].include?(env["RAILS_SERVER_HOTKEYS"].to_s.downcase)
57
+ return false if Gem.win_platform?
58
+ return false if rails_env && rails_env != "development"
59
+
60
+ input.respond_to?(:tty?) && input.tty?
61
+ end
62
+
63
+ def start(input: $stdin, output: $stdout)
64
+ return if @listener
65
+
66
+ Terminal.new(input).enable!
67
+ @listener = Listener.new(input: input, output: output, hotkeys: hotkeys)
68
+ @listener.start
69
+ BootHook.call { output.puts Actions.banner }
70
+ @listener
71
+ end
72
+ end
73
+ end
74
+
75
+ require "rails_server_hotkeys/actions"
76
+ require "rails_server_hotkeys/railtie" if defined?(Rails::Railtie)
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_server_hotkeys
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Gavassi Pismel
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 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'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ description: 'Adds interactive hotkeys to the Rails development server: r to restart,
27
+ c to clear, o to open the browser, q to quit, and your own.'
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - CHANGELOG.md
33
+ - LICENSE.txt
34
+ - README.md
35
+ - lib/rails_server_hotkeys.rb
36
+ - lib/rails_server_hotkeys/actions.rb
37
+ - lib/rails_server_hotkeys/boot_hook.rb
38
+ - lib/rails_server_hotkeys/color.rb
39
+ - lib/rails_server_hotkeys/listener.rb
40
+ - lib/rails_server_hotkeys/railtie.rb
41
+ - lib/rails_server_hotkeys/terminal.rb
42
+ - lib/rails_server_hotkeys/version.rb
43
+ homepage: https://github.com/samuelpismel/rails_server_hotkeys
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ homepage_uri: https://github.com/samuelpismel/rails_server_hotkeys
48
+ source_code_uri: https://github.com/samuelpismel/rails_server_hotkeys
49
+ changelog_uri: https://github.com/samuelpismel/rails_server_hotkeys/blob/master/CHANGELOG.md
50
+ bug_tracker_uri: https://github.com/samuelpismel/rails_server_hotkeys/issues
51
+ rubygems_mfa_required: 'true'
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '3.0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubygems_version: 4.0.7
67
+ specification_version: 4
68
+ summary: Keyboard hotkeys for `rails server` (press r to restart).
69
+ test_files: []