|
1 | | -# ruby-code-autoreloader |
| 1 | +# RubyCodeAutoreloader |
| 2 | +A simple way to add code auto-reloading to not Rails app |
| 3 | + |
| 4 | +## Index |
| 5 | +- [Usage](#usage) |
| 6 | + - [Installation](#installation) |
| 7 | + - [Configuration](#configuration) |
| 8 | + - [Naming convention](#naming-convention) |
| 9 | + - [How to use in an application](#how-to-use-in-an-application) |
| 10 | +- [Contributing](CONTRIBUTING.md) |
| 11 | + - [Maintainers](https://github.com/resolving/ruby-code-autoreloader/graphs/contributors) |
| 12 | +- [License](#license) |
| 13 | + |
| 14 | + |
| 15 | +## Usage |
| 16 | + |
| 17 | +### Installation |
| 18 | +Add this line to your application's Gemfile: |
| 19 | + |
| 20 | +```ruby |
| 21 | +gem 'ruby-code-autoreloader', resolving: 'ruby-code-autoreloader', tag: '0.1.0' # or ref: 'some md5' |
| 22 | +``` |
| 23 | + |
| 24 | +And then execute: |
| 25 | +```bash |
| 26 | +$ bundle install |
| 27 | +``` |
| 28 | + |
| 29 | +### Configuration |
| 30 | + |
| 31 | +To set configuration use `RubyCodeAutoreloader.configure` with a hash of params. |
| 32 | +List of possible params: |
| 33 | + |
| 34 | +| Name | Default value | Description | |
| 35 | +| --- | :---: | --- | |
| 36 | +| default_file_watcher | ActiveSupport::FileUpdateChecker | File watcher class that will be used for checking files updates | |
| 37 | +| autoreload_enabled | ENV['RACK_ENV'] == 'development' | The code reloading will works only if this param is `true`. Then all libs specified in `autoloadable_paths` will be loaded with `load` directive, e.g. `load 'lib_path/file.rb'`. If this param is `false`, then all libs specified in `autoloadable_paths` will be loaded as usual with `require`. Loading process uses the `ActiveSupport::Dependencies::Loadable.require_or_load` method | |
| 38 | +| autoloadable_paths | [] | This is an `Array` of paths from which will be loaded all ruby files `'*.rb'`. All files and Classes should be in the compliance with the [`Naming convention`](#naming-convention) described below. | |
| 39 | +| reload_only_on_change | TRUE | If this is `true`, then Reloader will check files in `autoloadable_paths` with initialized `file_watcher` and will reload the files if any of them was updated. If this is `false`, then files will be reloaded on each `RubyCodeAutoreloader.reload` method call, e.g. always | |
| 40 | +| logger | Logger.new(STDOUT) | Logger object | |
| 41 | + |
| 42 | +Also you can add specific environment variable for changing reloader mode, for |
| 43 | +example `ENV['AUTORELOAD_ENABLED']='true'`, and use it in configure. |
| 44 | + |
| 45 | +Example of initializer with configuration: |
| 46 | +```ruby |
| 47 | +# config/initializers/ruby_code_autoreloader.rb |
| 48 | +require 'ruby_code_autoreloader' |
| 49 | + |
| 50 | +RubyCodeAutoreloader.configure(autoreload_enabled: (ENV['RACK_ENV'] == 'development' && |
| 51 | + ENV['AUTORELOAD_ENABLED'] == 'true'), |
| 52 | + reload_only_on_change: false, |
| 53 | + autoloadable_paths: %w(app/endpoint_flux/middlewares/decorator |
| 54 | + app/endpoint_flux/middlewares/validator |
| 55 | + app/models |
| 56 | + app/endpoint_flux/decorators |
| 57 | + app/endpoint_flux/endpoints |
| 58 | + app/workers).freeze) |
| 59 | +``` |
| 60 | + |
| 61 | +#### Naming convention |
| 62 | + |
| 63 | +`RubyCodeAutoreloader` will search for all ruby `"*.rb"` files inside directories that described in `autoloadable_paths`. |
| 64 | +The pattern for searching files is `Dir.glob("#{path}/**/*.rb")`, e.g. will be loaded all files from subdirectories too. |
| 65 | +Each file will be loaded by `load` or `require` directive, depends on `autoreload_enabled` mode. After each file loading, |
| 66 | +`RubyCodeAutoreloader` will accumulate loaded Classes/Modules inside module variable `@autoloaded_classes`, that will be |
| 67 | +used to remove constant before each `Reloading`. |
| 68 | + |
| 69 | +And here we have a special `Naming convention`: |
| 70 | +the **_Classes/Modules_** that will be used for `Reloading` (e.g. will be added to `autoloaded_classes`), **should have** |
| 71 | +**the same last module names** as the **`files name`** too. **Otherwise** it will not be included for `Reloading` and |
| 72 | +**will be loaded only once** at the start. |
| 73 | +That's because it's hard to track what modules was loaded from the file as they might have their own `require` libs inside. |
| 74 | + |
| 75 | +For example we have this file `app/endpoint_flux/endpoints/users/create.rb` in specified dir `app/endpoint_flux/endpoints`, |
| 76 | +then Class/Module defined inside should has the name `Create` as **the last module name**, |
| 77 | +e.g. like this `::SomeModule::Create` or `Users::Create` or `EndpointFlux::Users::Create` or just `Create` |
| 78 | + |
| 79 | +### How to use in an application |
| 80 | + |
| 81 | +Firstly you need to configure it with initializer, as described in [Configuration](#configuration). |
| 82 | +Then you need to call `RubyCodeAutoreloader.start` method after all initializers. |
| 83 | +Depends on the `autoreload_enabled` config param, `RubyCodeAutoreloader` will loads the ruby libs specified in |
| 84 | +`autoloadable_paths` by `load` or `require` directive. |
| 85 | + |
| 86 | +Example of `environment.rb` with initializing the `RubyCodeAutoreloader` by `start` method: |
| 87 | +```ruby |
| 88 | +# config/environment.rb |
| 89 | +ENV['RACK_ENV'] ||= 'development' |
| 90 | +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) |
| 91 | + |
| 92 | +if ENV['RACK_ENV'] == 'development' || ENV['RACK_ENV'] == 'test' |
| 93 | + require 'dotenv' |
| 94 | + Dotenv.load(".env.#{ENV['RACK_ENV']}", '.env') |
| 95 | +end |
| 96 | + |
| 97 | +require 'bundler/setup' |
| 98 | +Bundler.require(:default, ENV['RACK_ENV']) |
| 99 | + |
| 100 | +$LOAD_PATH.unshift File.expand_path('..', __dir__) |
| 101 | +$LOAD_PATH.unshift File.expand_path('../app', __dir__) |
| 102 | + |
| 103 | +Dir.glob('config/initializers/*.rb').each { |file| require file } |
| 104 | + |
| 105 | +require "config/environments/#{ENV['RACK_ENV']}.rb" |
| 106 | + |
| 107 | +RubyCodeAutoreloader.start ### Run it only after all initializers |
| 108 | +``` |
| 109 | + |
| 110 | +Then you can just put `RubyCodeAutoreloader.reload` to the place where you want to check for updates before starting |
| 111 | +processing the query. In the example below this `call_endpoint_flux` in Sneakers worker will be called on each query |
| 112 | +to the service, and we call `RubyCodeAutoreloader.reload` before another methods. If `autoreload_enabled` is set |
| 113 | +to `false`, then reloading will be skipped. |
| 114 | + |
| 115 | +Example of Sneakers worker with the `RubyCodeAutoreloader.reload` call inside: |
| 116 | +```ruby |
| 117 | +# app/workers/base_worker.rb |
| 118 | + |
| 119 | +module BunnyPublisher |
| 120 | + module EndpointFlux |
| 121 | + class SneakersWorker |
| 122 | + def call_endpoint_flux(message, props) |
| 123 | + action = self.class.endpoint_action || props[:headers]['action'] |
| 124 | + |
| 125 | + RubyCodeAutoreloader.reload # calling it before processing the query |
| 126 | + |
| 127 | + endpoint = endpoint_for("#{self.class.endpoint_namespace}/#{action}") |
| 128 | + |
| 129 | + _, response = endpoint.perform(request_object(message)) |
| 130 | + |
| 131 | + response.body |
| 132 | + end |
| 133 | + end |
| 134 | + end |
| 135 | +end |
| 136 | +``` |
| 137 | + |
| 138 | +## [Contributing](CONTRIBUTING.md) |
| 139 | + |
| 140 | +### [Maintainers](https://github.com/resolving/endpoint-flux/graphs/contributors) |
| 141 | + |
| 142 | + |
| 143 | +## License |
| 144 | + |
| 145 | +The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). |
0 commit comments