https://github.com/zw963/hot_reloader
A dead simple ruby code hot reloader wrap around zeitwerk and listen.
https://github.com/zw963/hot_reloader
Last synced: about 1 year ago
JSON representation
A dead simple ruby code hot reloader wrap around zeitwerk and listen.
- Host: GitHub
- URL: https://github.com/zw963/hot_reloader
- Owner: zw963
- License: mit
- Created: 2019-03-21T06:32:57.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2023-02-09T19:27:00.000Z (over 3 years ago)
- Last Synced: 2024-10-10T13:11:06.433Z (over 1 year ago)
- Language: Ruby
- Homepage:
- Size: 31.3 KB
- Stars: 12
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG
- License: LICENSE
Awesome Lists containing this project
README
# HotReloader [](https://github.com/zw963/hot_reloader/actions/workflows/ci.yml) [](http://badge.fury.io/rb/hot_reloader) 
A dead simple ruby code hot reloader wrap around [zeitwerk](https://github.com/fxn/zeitwerk) and [listen](https://github.com/guard/listen).
See README for those gems for usage.
## Getting Started
Install via Rubygems
$ gem install hot_reloader
OR ...
Add to your Gemfile
gem 'hot_reloader'
## Usage
Following is a example for use hot_reloader with [Roda](https://github.com/jeremyevans/roda):
### Add loader initialize code into `config/environment.rb`
For simple use case, you just need pass paths to `HotReloader.eager_load` or `HotReloader.will_listen`.
```rb
# config/environment.rb
require 'bundler'
Bundler.require(:default, ENV.fetch('RACK_ENV', "development"))
require_relative 'application'
paths = ["#{__dir__}/../app", "#{__dir__}/../app/models"]
if ENV['RACK_ENV'] == 'development'
HotReloader.will_listen(*paths)
else
HotReloader.eager_load(*paths)
end
```
For more advanced case(e.g. you need setup zeitwerk loader instance yourself), you
can pass this instance to HotReloader methods too.
```rb
# config/environment.rb
require 'bundler'
Bundler.require(:default, ENV.fetch('RACK_ENV', "development"))
require_relative 'application'
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/../app")
loader.push_dir("#{__dir__}/../app/models")
if ENV['RACK_ENV'] == 'development'
HotReloader.will_listen(loader)
else
HotReloader.eager_load(loader)
end
```
When you change root directories files(app/*.rb or app/models/*.rb for above case),
all monitored files will be reload.
it is possible to trigger reload from any `.rb` files, even this file not follow constant
lookup name convention, and this file folder not add to root directories use `push_dir` method.
Following is a example.
```rb
# app/app.rb
class App < Roda
plugin :hash_routes
Dir["routes/**/*.rb"].each do |route_file|
load route_file
end
end
```
```rb
# routes/blog.rb
class App
hash_routes.on "blog" do |r|
"blog"
end
end
```
`routes/blog.rb` is not follow constant lookup name convention, so, `routes/` folder can't be
add to root directories use push_dir method, but you can always trigger with `loader.reload`
if `routes/blog.rb` was changed, then when `app/app.rb` reloaded, it will load the
newest code in `routes/blog.rb` from the Dir each loop.
For achieve this, you only need pass listened folders to will_listen method as secondary arg.
```rb
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/../app")
listened_folders = ["#{__dir__}/../routes"]
if ENV['RACK_ENV'] == 'development'
HotReloader.will_listen(loader, listened_folders)
else
HotReloader.eager_load(loader)
end
```
### Add other app files
`config.ru` which used to start rack based web server with `command rackup -o 0.0.0.0 -p 9393`
```rb
# config.ru
require_relative './config/environment'
if ENV['RACK_ENV'] == 'development'
run ->(env) { App.call(env) }
else
run App.freeze.app
end
```
Write whatever application needed initialize code into config/application.rb
```rb
# config/application.rb
DB = Sequel.connect(ENV.fetch("#{ENV.fetch('RACK_ENV', "development").upcase}_DATABASE_URL"), timeout: 10000)
Sequel::Model.plugin :timestamps
Sequel.extension :symbol_aref
```
Add roda code into app/app.rb
```rb
# app/app.rb
class App < Roda
articles = ['programming ruby', 'programming rust']
route do |r|
r.post "articles" do
articles << r.params["content"]
"Count: #{articles.count}"
end
r.get "articles" do
articles.join(', ')
end
end
end
```
Directory structure is like this:
```
├── app/app.rb
├── config/environment.rb
├── config/application.rb
├── config.ru
├── Gemfile
└── Gemfile.lock
```
After change code in app.rb, **all constant get removed from memory, and app.rb evaluated again**!
For a more rich WIP sample project, please check my another project [marketbet_crawler](https://github.com/zw963/marketbet_crawler).
## Support
* MRI 2.5+
* JRuby
## Dependency
[zeitwerk](https://github.com/fxn/zeitwerk) https://github.com/fxn/zeitwerk
[listen](https://github.com/guard/listen) https://github.com/guard/listen
## Contributing
* [Bug reports](https://github.com/zw963/hot_reloader/issues)
* [Source](https://github.com/zw963/hot_reloader)
* Patches:
* Fork on Github.
* Run `gem install --dev hot_reloader` or `bundle install`.
* Create your feature branch: `git checkout -b my-new-feature`.
* Commit your changes: `git commit -am 'Add some feature'`.
* Push to the branch: `git push origin my-new-feature`.
* Send a pull request :D.
## license
Released under the MIT license, See [LICENSE](https://github.com/zw963/hot_reloader/blob/master/LICENSE) for details.