reloadable_middleware 1.0.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: e0281e16f5f7150ffe47f3e5925013d3e4abdc9f2b98d3935f1a91a2c338647f
4
+ data.tar.gz: 6a26b27aa61dd2c294295a488d8cd4c862498381cfdfe33adba6663a9ef04bda
5
+ SHA512:
6
+ metadata.gz: f282832e0fc9d22624e5f0db462318d1eb174fd6a5722632f7842b0d2a6cf2a5393b01165c0807b662be3c13e701a1862aeb9dfd33c502bd68d000b1cc845da6
7
+ data.tar.gz: 7961961f2f5d2b0db76180a99663c2bad75af91f3b5831214fc2ee62623f4cd963eaa1c0a06ac3440fadb34bef386959986a5091538abf9ca784049147952bbb
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # Bundler lock
11
+ Gemfile.lock
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.17.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 1.0.0
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in reloadable_middleware.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # reloadable_midleware
2
+
3
+ Makes any Rack middleware reloadable. Or, rather - wraps a given piece of Rack middleware with a
4
+ special module, which will call `.new` on your middleware at `call()` time, not at instantiation
5
+ time. This means that the Rack application stack is not going to contain an object reference and
6
+ will be able to reload during constant teardown/setup.
7
+
8
+ ## Usage
9
+
10
+ Replace your standard middleware initialization block:
11
+
12
+ ```ruby
13
+ use CustomAuthentication, option: 'bar'
14
+ ```
15
+
16
+ with this alteration:
17
+
18
+ ```ruby
19
+ use ReloadableMiddleware.wrap(CustomAuthentication), option: 'bar'
20
+ ```
21
+
22
+ This will make your middleware reloadable. In Rails, use
23
+
24
+ ```ruby
25
+ Rails.application.config.middleware.use ReloadableMiddleware.wrap(MyMiddleware)
26
+ ```
27
+
28
+ ## Performance in production modes
29
+
30
+ If you are running with `RACK_ENV` set to `production` or with `Rails.env.production? == true`
31
+ the reloading will be disabled and you will have one instance of your middleware as usual. This
32
+ reduces object churn, since Rack assumes that your entire app stack is going to be built once
33
+ and then cached between requests - which helps performance.
34
+
35
+ ## Installation
36
+
37
+ Add this line to your application's Gemfile:
38
+
39
+ ```ruby
40
+ gem 'reloadable_middleware'
41
+ ```
42
+
43
+ And then execute:
44
+
45
+ $ bundle
46
+
47
+ Or install it yourself as:
48
+
49
+ $ gem install reloadable_middleware
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/julik/reloadable_middleware.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "reloadable_middleware"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,53 @@
1
+ require_relative "reloadable_middleware/version"
2
+ require_relative 'reloadable_middleware/railtie' if defined?(Rails)
3
+
4
+ module ReloadableMiddleware
5
+ # Base class for the reloadable middleware. We need to save
6
+ # the middleware name somewhere, so this class will be
7
+ # subclassed dynamically and preconfigured with the
8
+ # correct middleware name, to be used by its `.to_s` return value
9
+ class Lazy
10
+ # Saves the app and the arguments for configuring the middleware and applies them
11
+ # when `call()` gets called.
12
+ def initialize(app, *args_for_middleware_new, &block_for_middleware_new)
13
+ @app = app
14
+ @args_for_middleware_new = args_for_middleware_new
15
+ @block_for_middleware_new = block_for_middleware_new.to_proc if block_for_middleware_new
16
+ end
17
+
18
+ # Instantiate the given middleware by name, on the spot, and call() it immediately
19
+ def call(env)
20
+ middleware_module = lookup_middleware_module
21
+ app_wrapped_with_middleware = middleware_module.new(@app, *@args_for_middleware_new, &@block_for_middleware_new)
22
+ app_wrapped_with_middleware.call(env)
23
+ end
24
+
25
+ # This is needed since Rails, for instance, calls "to_s" on the middleware
26
+ # class when showing its middleware list. The output also is valid Ruby code,
27
+ # so we need to print something that can be pasted into code again.
28
+ def self.to_s
29
+ "ReloadableMiddleware.wrap(#{@middleware_name})"
30
+ end
31
+
32
+ private
33
+
34
+ def lookup_middleware_module
35
+ middleware_module_name = self.class.instance_variable_get('@middleware_name')
36
+ # Rails constantize() on the cheap
37
+ middleware_module_name.split('::').reject(&:empty?).inject(Kernel) {|namespace, const_name| namespace.const_get(const_name) }
38
+ end
39
+ end
40
+
41
+ def self.wrap(middleware_class_or_name)
42
+ # Specific case: if the middleware is being _defined_ in production (Rails or bare Rack)
43
+ # instead of making it reloadable return the object itself, since we otherwise churn
44
+ # one instance of the middleware we wrap per request.
45
+ if ENV['RACK_ENV'] == 'production' || defined?(Rails.env) && Rails.env.production?
46
+ return middleware_class_or_name
47
+ else
48
+ middleware_module_name = middleware_class_or_name.to_s
49
+ Class.new(Lazy) { @middleware_name = middleware_module_name }
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,3 @@
1
+ module ReloadableMiddleware
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,40 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "reloadable_middleware/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "reloadable_middleware"
8
+ spec.version = ReloadableMiddleware::VERSION
9
+ spec.authors = ["Julik Tarkhanov"]
10
+ spec.email = ["me@julik.nl"]
11
+
12
+ spec.summary = %q{ Wraps any Rack middleware with lazy resolve at call() }
13
+ spec.description = %q{ Wraps any Rack middleware with lazy resolve at call() }
14
+ spec.homepage = "https://github.com/julik/reloadable_middleware"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = "https://github.com/julik/reloadable_middleware"
22
+ spec.metadata["changelog_uri"] = "https://github.com/julik/reloadable_middleware/blob/master/CHANGELOG.md"
23
+ else
24
+ raise "RubyGems 2.0 or newer is required to protect against " \
25
+ "public gem pushes."
26
+ end
27
+
28
+ # Specify which files should be added to the gem when it is released.
29
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ `git ls-files -z`.split("\x0")
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.17"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rspec", "~> 3.0"
40
+ end
@@ -0,0 +1,69 @@
1
+ RSpec.describe ReloadableMiddleware do
2
+ it "has a version number" do
3
+ expect(ReloadableMiddleware::VERSION).not_to be nil
4
+ end
5
+
6
+ it "wraps a given module with a reloading class, giving it a sensible to_s return value" do
7
+ class MiddlewareWithArguments
8
+ def initialize(app, frobnicate:)
9
+ @app = app
10
+ @frobnicate = frobnicate
11
+ end
12
+
13
+ def call(env)
14
+ raise "Should not call the same middleware object for the second time" if @got_called
15
+ @got_called = :yes
16
+
17
+ env['did_pass_middleware1'] = true
18
+ env['frobnicate'] = @frobnicate
19
+ @app.call(env)
20
+ end
21
+ end
22
+
23
+ class MiddlewareWithoutArguments
24
+ def initialize(app)
25
+ @app = app
26
+ end
27
+
28
+ def call(env)
29
+ raise "Should not call the same middleware object for the second time" if @got_called
30
+ @got_called = :yes
31
+
32
+ env['did_pass_middleware2'] = true
33
+ @app.call(env)
34
+ end
35
+ end
36
+
37
+ reloadable_class = ReloadableMiddleware.wrap(MiddlewareWithArguments)
38
+ expect(reloadable_class.to_s).to include('MiddlewareWithArguments')
39
+
40
+ rack_app = ->(env) {
41
+ expect(env['did_pass_middleware1']).to eq(true)
42
+ expect(env['did_pass_middleware2']).to eq(true)
43
+ expect(env['frobnicate']).to eq('totally')
44
+ }
45
+ expect(rack_app).to receive(:call).twice.and_call_original
46
+
47
+ reloadable_class2 = ReloadableMiddleware.wrap(MiddlewareWithoutArguments)
48
+
49
+ # Build out a tiny Rack app stack
50
+ mounted_middleware = reloadable_class2.new(reloadable_class.new(rack_app, frobnicate: 'totally'))
51
+
52
+ # ...and call into it, twice. If our middleware objects were retained (as they are with standard
53
+ # Rack wrapping process) we will get an exception, since these particular middleware objects
54
+ # will only tolerate being called once.
55
+ mounted_middleware.call({})
56
+ mounted_middleware.call({})
57
+ end
58
+
59
+ it 'turns wrap() into a no-op if RACK_ENV is set to "production"' do
60
+ class SomeMiddleware
61
+ end
62
+
63
+ ENV['RACK_ENV'] = 'production'
64
+ wrapped = ReloadableMiddleware.wrap(SomeMiddleware)
65
+ expect(wrapped).to eq(SomeMiddleware)
66
+
67
+ ENV.delete('RACK_ENV')
68
+ end
69
+ end
@@ -0,0 +1,14 @@
1
+ require "bundler/setup"
2
+ require "reloadable_middleware"
3
+
4
+ RSpec.configure do |config|
5
+ # Enable flags like --only-failures and --next-failure
6
+ config.example_status_persistence_file_path = ".rspec_status"
7
+
8
+ # Disable RSpec exposing methods globally on `Module` and `main`
9
+ config.disable_monkey_patching!
10
+
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = :expect
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reloadable_middleware
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Julik Tarkhanov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: " Wraps any Rack middleware with lazy resolve at call() "
56
+ email:
57
+ - me@julik.nl
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - CHANGELOG.md
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - lib/reloadable_middleware.rb
72
+ - lib/reloadable_middleware/version.rb
73
+ - reloadable_middleware.gemspec
74
+ - spec/reloadable_middleware_spec.rb
75
+ - spec/spec_helper.rb
76
+ homepage: https://github.com/julik/reloadable_middleware
77
+ licenses: []
78
+ metadata:
79
+ homepage_uri: https://github.com/julik/reloadable_middleware
80
+ source_code_uri: https://github.com/julik/reloadable_middleware
81
+ changelog_uri: https://github.com/julik/reloadable_middleware/blob/master/CHANGELOG.md
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.7.6
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Wraps any Rack middleware with lazy resolve at call()
102
+ test_files: []