rails-threaded-proxy 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbc7f9b0318c1136497926119e07a245bacd9d017126add8a1da34e7426d79e0
4
- data.tar.gz: 6506ac75b092ad1530ef54ceaf5d4c75775b3589cb1db2648afef0598e54c9de
3
+ metadata.gz: 627edadeb8a4d381699398dcd596285b425994116b21393d5a1c4b61f91bf195
4
+ data.tar.gz: '0066744825548c505bf61585302e20a011761f7198f12cdb34fa9f79607317c4'
5
5
  SHA512:
6
- metadata.gz: 38bfa986e8033530bdddcf28a201ce18648bb8d8b46cd7d6738c8addc736aee573f685fc355d45072f6dcd4b632f22e5280891a67d56f7ccb75d9391d92300bb
7
- data.tar.gz: 5a03daa8831574b0dc693916f11a7ebc8bfe8f409578a45e1de82f0f849b60c76dab4c929bf7c91322030f74ce6060df0eb99fdbab28390641df81f195844959
6
+ metadata.gz: 52d909c71d9657f8e0f5f601bb4478979dfb4971bbf93230067172cd0077fbfc77601b9a1bc76f27b94f01185f83e07c08540eacbea70c612e66211d0cca4bb3
7
+ data.tar.gz: 108158c59c1b87c72e6559cb7fdb535d1c05819a581f321feff8679ea4213491a37c7dd204fc55357dbdf9bfc6a3e7724fa4223c488036b53a20594c235a7d56
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2016 James Hu
3
+ Copyright (c) 2024 Michael Nutt
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # rails-threaded-proxy
2
+
3
+ Asynchronous high throughput reverse proxy for rails
4
+
5
+ *Warning: experimental. Use at your own risk.*
6
+
7
+ ## About
8
+
9
+ Rails concurrency is often limited to running many processes, which can be memory-intensive. Even for servers that support threads, it can be difficult running dozens or hundreds of threads. But you may have backend services that are slow to respond, and/or return very large responses. It is useful to put these services behind rails for authentication, but slow responses can tie up your rails workers preventing them from serving other clients.
10
+
11
+ `rails-threaded-proxy` disconnects the proxying from the rack request/response cycle, freeing up workers to serve other clients. It does this by running the origin request in a thread. But running in a thread is not enough: we need to be able to respond to the rails request, but rack owns the socket. So it hijacks the request: rack completes immediately but dissociates from the socket. Then we're free to manage the socket ourselves. Copying between sockets, we can achieve high throughput (100MB/s+) with minimal CPU and memory overhead.
12
+
13
+ ## Usage
14
+
15
+ ```ruby
16
+ class MyController
17
+ include ThreadedProxy::Controller
18
+
19
+ def my_backend
20
+ proxy_fetch "http://backend.service/path/to/endpoint", method: :post do |config|
21
+ config.on_headers do |client_response|
22
+ # override some response headers coming from the backend
23
+ client_response['content-security-policy'] = "sandbox;"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ ```
29
+
30
+ ## Requirements
31
+
32
+ Tested with Rails 7, but probably works in Rails 6+. Needs an application server that supports `rack.hijack`. (only tested on [https://puma.io/](Puma) so far)
33
+
34
+ ## Caveats
35
+
36
+ * There isn't currently a way to limit concurrency. It is possible to run your server out of file descriptors, memory, etc.
37
+ * Since the proxying happens in a thread, callbacks are also run inside of the thread. Don't do anything non-threadsafe in callbacks.
38
+ * There is currently probably not sufficient error handling for edge cases. This is experimental.
39
+
40
+ ## Attribution
41
+
42
+ Inspired by [https://github.com/axsuul/rails-reverse-proxy](rails-reverse-proxy), and tries to use similar API structure where possible. If you don't care about the specific benefits of `rails-threaded-proxy`, you should consider using `rails-reverse-proxy` instead.
43
+
44
+ ## License
45
+
46
+ See LICENSE
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.1
@@ -9,7 +9,7 @@ module ThreadedProxy
9
9
  class Client
10
10
  DISALLOWED_RESPONSE_HEADERS = %w[keep-alive].freeze
11
11
 
12
- METHODS = {
12
+ HTTP_METHODS = {
13
13
  'get' => Net::HTTP::Get,
14
14
  'post' => Net::HTTP::Post,
15
15
  'put' => Net::HTTP::Put,
@@ -19,6 +19,20 @@ module ThreadedProxy
19
19
  'trace' => Net::HTTP::Trace
20
20
  }.freeze
21
21
 
22
+ CALLBACK_METHODS = %i[
23
+ on_response
24
+ on_headers
25
+ on_body
26
+ on_complete
27
+ on_error
28
+ ].freeze
29
+
30
+ CALLBACK_METHODS.each do |method_name|
31
+ define_method(method_name) do |&block|
32
+ @callbacks[method_name] = block
33
+ end
34
+ end
35
+
22
36
  DEFAULT_OPTIONS = {
23
37
  headers: {},
24
38
  debug: false,
@@ -28,6 +42,13 @@ module ThreadedProxy
28
42
  def initialize(origin_url, options = {})
29
43
  @origin_url = Addressable::URI.parse(origin_url)
30
44
  @options = DEFAULT_OPTIONS.merge(options)
45
+
46
+ @callbacks = {}
47
+ CALLBACK_METHODS.each do |method_name|
48
+ @callbacks[method_name] = proc {}
49
+ end
50
+
51
+ yield(self) if block_given?
31
52
  end
32
53
 
33
54
  def log(message)
@@ -38,7 +59,7 @@ module ThreadedProxy
38
59
  request_method = @options[:method].to_s.downcase
39
60
  request_headers = @options[:headers].merge('Connection' => 'close')
40
61
 
41
- request_class = METHODS[request_method]
62
+ request_class = HTTP_METHODS[request_method]
42
63
  http_request = request_class.new(@origin_url, request_headers)
43
64
  if @options[:body].respond_to?(:read)
44
65
  http_request.body_stream = @options[:body]
@@ -55,21 +76,15 @@ module ThreadedProxy
55
76
 
56
77
  http.start do
57
78
  http.request(http_request) do |client_response|
58
- # We don't support reusing connections once we have disconnected them from rack
59
- client_response['connection'] = 'close'
79
+ @callbacks[:on_response].call(client_response, socket)
80
+ break if socket.closed?
60
81
 
61
- yield client_response if block_given?
62
-
63
- # start writing response
64
82
  log('Writing response status and headers')
65
- socket.write "HTTP/1.1 #{client_response.code} #{client_response.message}\r\n"
66
-
67
- client_response.each_header do |key, value|
68
- socket.write "#{key}: #{value}\r\n" unless DISALLOWED_RESPONSE_HEADERS.include?(key.downcase)
69
- end
83
+ write_headers(client_response, socket)
84
+ break if socket.closed?
70
85
 
71
- # Done with headers
72
- socket.write "\r\n"
86
+ @callbacks[:on_body].call(client_response, socket)
87
+ break if socket.closed?
73
88
 
74
89
  # There may have been some existing data in client_response's read buffer, flush it out
75
90
  # before we manually connect the raw sockets
@@ -79,11 +94,32 @@ module ThreadedProxy
79
94
  # Copy the rest of the client response to the socket
80
95
  log('Copying response body to client')
81
96
  http.copy_to(socket)
97
+
98
+ @callbacks[:on_complete].call(client_response)
82
99
  end
100
+ rescue StandardError => e
101
+ @callbacks[:on_error].call(e) or raise
83
102
  end
84
103
  end
85
104
  end
86
105
 
106
+ def write_headers(client_response, socket)
107
+ socket.write "HTTP/1.1 #{client_response.code} #{client_response.message}\r\n"
108
+
109
+ # We don't support reusing connections once we have disconnected them from rack
110
+ client_response['connection'] = 'close'
111
+
112
+ @callbacks[:on_headers].call(client_response, socket)
113
+ return if socket.closed?
114
+
115
+ client_response.each_header do |key, value|
116
+ socket.write "#{key}: #{value}\r\n" unless DISALLOWED_RESPONSE_HEADERS.include?(key.downcase)
117
+ end
118
+
119
+ # Done with headers
120
+ socket.write "\r\n"
121
+ end
122
+
87
123
  def default_port(uri)
88
124
  case uri.scheme
89
125
  when 'http'
@@ -4,7 +4,7 @@ require_relative 'client'
4
4
 
5
5
  module ThreadedProxy
6
6
  module Controller
7
- def proxy_fetch(origin_url, options = {})
7
+ def proxy_fetch(origin_url, options = {}, &block)
8
8
  # hijack the response so we can take it outside of the rack request/response cycle
9
9
  request.env['rack.hijack'].call
10
10
  socket = request.env['rack.hijack_io']
@@ -25,7 +25,7 @@ module ThreadedProxy
25
25
  options[:headers]['Content-Type'] = request.env['CONTENT_TYPE'] if request.env['CONTENT_TYPE']
26
26
  end
27
27
 
28
- client = Client.new(origin_url, options)
28
+ client = Client.new(origin_url, options, &block)
29
29
  client.start(socket)
30
30
  rescue Errno::EPIPE
31
31
  # client disconnected before request finished; not an error
@@ -2,21 +2,21 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: rails-threaded-proxy 0.3.0 ruby lib
5
+ # stub: rails-threaded-proxy 0.4.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "rails-threaded-proxy".freeze
9
- s.version = "0.3.0".freeze
9
+ s.version = "0.4.1".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Michael Nutt".freeze]
14
- s.date = "2024-10-14"
14
+ s.date = "2024-10-17"
15
15
  s.description = "Threaded reverse proxy for Ruby on Rails".freeze
16
16
  s.email = "michael@nuttnet.net".freeze
17
- s.executables = ["bundle".freeze, "htmldiff".freeze, "jeweler".freeze, "ldiff".freeze, "nokogiri".freeze, "racc".freeze, "rackup".freeze, "rake".freeze, "rdoc".freeze, "ri".freeze, "rspec".freeze, "rubocop".freeze, "semver".freeze]
18
17
  s.extra_rdoc_files = [
19
- "LICENSE"
18
+ "LICENSE",
19
+ "README.md"
20
20
  ]
21
21
  s.files = [
22
22
  ".bundle/config",
@@ -26,21 +26,9 @@ Gem::Specification.new do |s|
26
26
  "Gemfile",
27
27
  "Gemfile.lock",
28
28
  "LICENSE",
29
+ "README.md",
29
30
  "Rakefile",
30
31
  "VERSION",
31
- "bin/bundle",
32
- "bin/htmldiff",
33
- "bin/jeweler",
34
- "bin/ldiff",
35
- "bin/nokogiri",
36
- "bin/racc",
37
- "bin/rackup",
38
- "bin/rake",
39
- "bin/rdoc",
40
- "bin/ri",
41
- "bin/rspec",
42
- "bin/rubocop",
43
- "bin/semver",
44
32
  "lib/rails-threaded-proxy.rb",
45
33
  "lib/threaded-proxy.rb",
46
34
  "lib/threaded_proxy.rb",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-threaded-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Nutt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-14 00:00:00.000000000 Z
11
+ date: 2024-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -138,23 +138,11 @@ dependencies:
138
138
  version: '0'
139
139
  description: Threaded reverse proxy for Ruby on Rails
140
140
  email: michael@nuttnet.net
141
- executables:
142
- - bundle
143
- - htmldiff
144
- - jeweler
145
- - ldiff
146
- - nokogiri
147
- - racc
148
- - rackup
149
- - rake
150
- - rdoc
151
- - ri
152
- - rspec
153
- - rubocop
154
- - semver
141
+ executables: []
155
142
  extensions: []
156
143
  extra_rdoc_files:
157
144
  - LICENSE
145
+ - README.md
158
146
  files:
159
147
  - ".bundle/config"
160
148
  - ".rspec"
@@ -163,21 +151,9 @@ files:
163
151
  - Gemfile
164
152
  - Gemfile.lock
165
153
  - LICENSE
154
+ - README.md
166
155
  - Rakefile
167
156
  - VERSION
168
- - bin/bundle
169
- - bin/htmldiff
170
- - bin/jeweler
171
- - bin/ldiff
172
- - bin/nokogiri
173
- - bin/racc
174
- - bin/rackup
175
- - bin/rake
176
- - bin/rdoc
177
- - bin/ri
178
- - bin/rspec
179
- - bin/rubocop
180
- - bin/semver
181
157
  - lib/rails-threaded-proxy.rb
182
158
  - lib/threaded-proxy.rb
183
159
  - lib/threaded_proxy.rb
data/bin/bundle DELETED
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'bundle' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- require "rubygems"
12
-
13
- m = Module.new do
14
- module_function
15
-
16
- def invoked_as_script?
17
- File.expand_path($0) == File.expand_path(__FILE__)
18
- end
19
-
20
- def env_var_version
21
- ENV["BUNDLER_VERSION"]
22
- end
23
-
24
- def cli_arg_version
25
- return unless invoked_as_script? # don't want to hijack other binstubs
26
- return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
- bundler_version = nil
28
- update_index = nil
29
- ARGV.each_with_index do |a, i|
30
- if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
31
- bundler_version = a
32
- end
33
- next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
- bundler_version = $1
35
- update_index = i
36
- end
37
- bundler_version
38
- end
39
-
40
- def gemfile
41
- gemfile = ENV["BUNDLE_GEMFILE"]
42
- return gemfile if gemfile && !gemfile.empty?
43
-
44
- File.expand_path("../Gemfile", __dir__)
45
- end
46
-
47
- def lockfile
48
- lockfile =
49
- case File.basename(gemfile)
50
- when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
51
- else "#{gemfile}.lock"
52
- end
53
- File.expand_path(lockfile)
54
- end
55
-
56
- def lockfile_version
57
- return unless File.file?(lockfile)
58
- lockfile_contents = File.read(lockfile)
59
- return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
- Regexp.last_match(1)
61
- end
62
-
63
- def bundler_requirement
64
- @bundler_requirement ||=
65
- env_var_version ||
66
- cli_arg_version ||
67
- bundler_requirement_for(lockfile_version)
68
- end
69
-
70
- def bundler_requirement_for(version)
71
- return "#{Gem::Requirement.default}.a" unless version
72
-
73
- bundler_gem_version = Gem::Version.new(version)
74
-
75
- bundler_gem_version.approximate_recommendation
76
- end
77
-
78
- def load_bundler!
79
- ENV["BUNDLE_GEMFILE"] ||= gemfile
80
-
81
- activate_bundler
82
- end
83
-
84
- def activate_bundler
85
- gem_error = activation_error_handling do
86
- gem "bundler", bundler_requirement
87
- end
88
- return if gem_error.nil?
89
- require_error = activation_error_handling do
90
- require "bundler/version"
91
- end
92
- return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
93
- warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
94
- exit 42
95
- end
96
-
97
- def activation_error_handling
98
- yield
99
- nil
100
- rescue StandardError, LoadError => e
101
- e
102
- end
103
- end
104
-
105
- m.load_bundler!
106
-
107
- if m.invoked_as_script?
108
- load Gem.bin_path("bundler", "bundle")
109
- end
data/bin/htmldiff DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'htmldiff' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("diff-lcs", "htmldiff")
data/bin/jeweler DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'jeweler' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("jeweler", "jeweler")
data/bin/ldiff DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'ldiff' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("diff-lcs", "ldiff")
data/bin/nokogiri DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'nokogiri' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("nokogiri", "nokogiri")
data/bin/racc DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'racc' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("racc", "racc")
data/bin/rackup DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rackup' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("rack", "rackup")
data/bin/rake DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rake' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("rake", "rake")
data/bin/rdoc DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rdoc' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("rdoc", "rdoc")
data/bin/ri DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'ri' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("rdoc", "ri")
data/bin/rspec DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rspec' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("rspec-core", "rspec")
data/bin/rubocop DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'rubocop' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
12
-
13
- bundle_binstub = File.expand_path('bundle', __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?('This file was generated by Bundler')
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require 'rubygems'
25
- require 'bundler/setup'
26
-
27
- load Gem.bin_path('rubocop', 'rubocop')
data/bin/semver DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- #
5
- # This file was generated by Bundler.
6
- #
7
- # The application 'semver' is installed as part of a gem, and
8
- # this file is here to facilitate running it.
9
- #
10
-
11
- ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
12
-
13
- bundle_binstub = File.expand_path("bundle", __dir__)
14
-
15
- if File.file?(bundle_binstub)
16
- if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
- load(bundle_binstub)
18
- else
19
- abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
- Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
- end
22
- end
23
-
24
- require "rubygems"
25
- require "bundler/setup"
26
-
27
- load Gem.bin_path("semver2", "semver")