proxy_rb 0.4.0 → 0.5.0
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 +4 -4
- data/.travis.yml +9 -4
- data/Gemfile +2 -2
- data/History.md +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +15 -4
- data/Rakefile +8 -2
- data/exe/proxy_rb +8 -0
- data/fixtures/empty/README.md +18 -0
- data/fixtures/empty/Rakefile +10 -0
- data/lib/proxy_rb/announcer.rb +162 -0
- data/lib/proxy_rb/{rspec/helpers → api}/.keep +0 -0
- data/lib/proxy_rb/api/core.rb +25 -0
- data/lib/proxy_rb/api/http_proxy.rb +94 -0
- data/lib/proxy_rb/api/passwords.rb +26 -0
- data/lib/proxy_rb/api.rb +19 -0
- data/lib/proxy_rb/basic_configuration/{in_config_wrapper.rb → in_configuration_wrapper.rb} +1 -1
- data/lib/proxy_rb/basic_configuration.rb +2 -2
- data/lib/proxy_rb/cli.rb +27 -0
- data/lib/proxy_rb/colorizer.rb +113 -0
- data/lib/proxy_rb/configuration.rb +1 -1
- data/lib/proxy_rb/configuration_wrapper.rb +59 -0
- data/lib/proxy_rb/console/help.rb +29 -0
- data/lib/proxy_rb/console.rb +62 -0
- data/lib/proxy_rb/credentials.rb +11 -0
- data/lib/proxy_rb/drivers/poltergeist_driver.rb +8 -2
- data/lib/proxy_rb/drivers/selenium_driver.rb +7 -1
- data/lib/proxy_rb/drivers/webkit_driver.rb +10 -1
- data/lib/proxy_rb/errors.rb +12 -0
- data/lib/proxy_rb/event_bus/name_resolver.rb +163 -0
- data/lib/proxy_rb/event_bus.rb +60 -0
- data/lib/proxy_rb/events.rb +34 -0
- data/lib/proxy_rb/http_proxy.rb +8 -0
- data/lib/proxy_rb/initializer.rb +132 -0
- data/lib/proxy_rb/{rspec/matchers → matchers}/.keep +0 -0
- data/lib/proxy_rb/matchers/be_forbidden.rb +14 -0
- data/lib/proxy_rb/matchers/be_successful.rb +14 -0
- data/lib/proxy_rb/matchers/have_mime_type.rb +9 -0
- data/lib/proxy_rb/password_fetchers/basic_password_fetcher.rb +25 -0
- data/lib/proxy_rb/password_fetchers/chaining_password_fetcher.rb +54 -0
- data/lib/proxy_rb/password_fetchers/environment_password_fetcher.rb +7 -1
- data/lib/proxy_rb/password_fetchers/vault_password_fetcher.rb +7 -1
- data/lib/proxy_rb/proxy_url.rb +8 -0
- data/lib/proxy_rb/request.rb +5 -21
- data/lib/proxy_rb/resource.rb +11 -7
- data/lib/proxy_rb/response.rb +5 -13
- data/lib/proxy_rb/rspec.rb +32 -13
- data/lib/proxy_rb/runtime.rb +49 -0
- data/lib/proxy_rb/setup.rb +60 -0
- data/lib/proxy_rb/version.rb +1 -1
- data/proxy_rb.gemspec +2 -2
- metadata +38 -29
- data/lib/proxy_rb/rspec/helpers/http_proxy.rb +0 -83
- data/lib/proxy_rb/rspec/helpers/passwords.rb +0 -29
- data/lib/proxy_rb/rspec/shared_contexts/.keep +0 -0
- data/lib/proxy_rb/rspec/shared_examples/.keep +0 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# ProxyRb
|
3
|
+
module ProxyRb
|
4
|
+
# The ANSIColor module can be used for namespacing and mixed into your own
|
5
|
+
# classes.
|
6
|
+
module AnsiColor
|
7
|
+
# :stopdoc:
|
8
|
+
ATTRIBUTES = [
|
9
|
+
[:clear, 0],
|
10
|
+
[:reset, 0], # synonym for :clear
|
11
|
+
[:bold, 1],
|
12
|
+
[:dark, 2],
|
13
|
+
[:italic, 3], # not widely implemented
|
14
|
+
[:underline, 4],
|
15
|
+
[:underscore, 4], # synonym for :underline
|
16
|
+
[:blink, 5],
|
17
|
+
[:rapid_blink, 6], # not widely implemented
|
18
|
+
[:negative, 7], # no reverse because of String#reverse
|
19
|
+
[:concealed, 8],
|
20
|
+
[:strikethrough, 9], # not widely implemented
|
21
|
+
[:black, 30],
|
22
|
+
[:red, 31],
|
23
|
+
[:green, 32],
|
24
|
+
[:yellow, 33],
|
25
|
+
[:blue, 34],
|
26
|
+
[:magenta, 35],
|
27
|
+
[:cyan, 36],
|
28
|
+
[:white, 37],
|
29
|
+
[:on_black, 40],
|
30
|
+
[:on_red, 41],
|
31
|
+
[:on_green, 42],
|
32
|
+
[:on_yellow, 43],
|
33
|
+
[:on_blue, 44],
|
34
|
+
[:on_magenta, 45],
|
35
|
+
[:on_cyan, 46],
|
36
|
+
[:on_white, 47]
|
37
|
+
].freeze
|
38
|
+
|
39
|
+
ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
|
40
|
+
# :startdoc:
|
41
|
+
|
42
|
+
# Returns true, if the coloring function of this module
|
43
|
+
# is switched on, false otherwise.
|
44
|
+
def self.coloring?
|
45
|
+
@coloring
|
46
|
+
end
|
47
|
+
|
48
|
+
# Turns the coloring on or off globally, so you can easily do
|
49
|
+
# this for example:
|
50
|
+
# ProxyRb::Colorizer.coloring = STDOUT.isatty
|
51
|
+
def self.coloring=(val)
|
52
|
+
@coloring = val
|
53
|
+
end
|
54
|
+
self.coloring = true
|
55
|
+
|
56
|
+
ATTRIBUTES.each do |c, v|
|
57
|
+
define_method(c) do |string|
|
58
|
+
result = []
|
59
|
+
result << "\e[#{v}m" if ProxyRb::AnsiColor.coloring?
|
60
|
+
if block_given?
|
61
|
+
result << yield
|
62
|
+
elsif string
|
63
|
+
result << string
|
64
|
+
elsif respond_to?(:to_str)
|
65
|
+
result << to_str
|
66
|
+
else
|
67
|
+
return result # only switch on
|
68
|
+
end
|
69
|
+
result << "\e[0m" if ProxyRb::AnsiColor.coloring?
|
70
|
+
|
71
|
+
result.join
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Regular expression that is used to scan for ANSI-sequences while
|
76
|
+
# uncoloring strings.
|
77
|
+
COLORED_REGEXP = /\e\[(?:[34][0-7]|[0-9])?m/
|
78
|
+
|
79
|
+
def self.included(klass)
|
80
|
+
if klass == String
|
81
|
+
ATTRIBUTES.delete(:clear)
|
82
|
+
ATTRIBUTE_NAMES.delete(:clear)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns an uncolored version of the string, that is all
|
87
|
+
# ANSI-sequences are stripped from the string.
|
88
|
+
def uncolored(string = nil) # :yields:
|
89
|
+
if block_given?
|
90
|
+
yield.gsub(COLORED_REGEXP, '')
|
91
|
+
elsif string
|
92
|
+
string.gsub(COLORED_REGEXP, '')
|
93
|
+
elsif respond_to?(:to_str)
|
94
|
+
to_str.gsub(COLORED_REGEXP, '')
|
95
|
+
else
|
96
|
+
''
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns an array of all ProxyRb::Platforms::AnsiColor attributes as symbols.
|
101
|
+
def attributes
|
102
|
+
ATTRIBUTE_NAMES
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# ProxyRb
|
108
|
+
module ProxyRb
|
109
|
+
# Colorize output
|
110
|
+
class Colorizer
|
111
|
+
include ProxyRb::AnsiColor
|
112
|
+
end
|
113
|
+
end
|
@@ -3,7 +3,6 @@ require 'contracts'
|
|
3
3
|
|
4
4
|
require 'proxy_rb/version'
|
5
5
|
require 'proxy_rb/basic_configuration'
|
6
|
-
require 'proxy_rb/basic_configuration/in_config_wrapper'
|
7
6
|
|
8
7
|
require 'proxy_rb/password_fetchers/basic_password_fetcher'
|
9
8
|
require 'proxy_rb/password_fetchers/environment_password_fetcher'
|
@@ -18,6 +17,7 @@ module ProxyRb
|
|
18
17
|
class Configuration < BasicConfiguration
|
19
18
|
option_accessor :password_fetcher, contract: { PasswordFetchers::BasicPasswordFetcher => PasswordFetchers::BasicPasswordFetcher }, default: ProxyRb::PasswordFetchers::EnvironmentPasswordFetcher.new(prefix: 'SECRET')
|
20
19
|
option_accessor :driver, contract: { Drivers::BasicDriver => Drivers::BasicDriver }, default: ProxyRb::Drivers::WebkitDriver.new
|
20
|
+
option_accessor :console_history_file, contract: { String => String }, default: '~/.proxy_rb_history'
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ProxyRb
|
3
|
+
# This wraps the current runtime configuration of proxy_rb.
|
4
|
+
# If an option is changed, it notifies the event queue.
|
5
|
+
#
|
6
|
+
# This class is not meant for direct use - ConfigWrapper.new - by normal
|
7
|
+
# users.
|
8
|
+
#
|
9
|
+
# @private
|
10
|
+
class ConfigurationWrapper
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :config, :event_bus
|
14
|
+
|
15
|
+
public
|
16
|
+
|
17
|
+
# Create proxy
|
18
|
+
#
|
19
|
+
# @param [Config] config
|
20
|
+
# An proxy_rb config object.
|
21
|
+
#
|
22
|
+
# @param [#notify] event_bus
|
23
|
+
# The event queue which should be notified.
|
24
|
+
def initialize(config, event_bus)
|
25
|
+
@config = config
|
26
|
+
@event_bus = event_bus
|
27
|
+
end
|
28
|
+
|
29
|
+
# Proxy all methods
|
30
|
+
#
|
31
|
+
# If one method ends with "=", e.g. ":option1=", then notify the event
|
32
|
+
# queue, that the user changes the value of "option1"
|
33
|
+
def method_missing(name, *args, &block)
|
34
|
+
event_bus.notify Events::ChangedConfiguration.new(changed: { name: name.to_s.gsub(/=$/, ''), value: args.first }) if name.to_s.end_with? '='
|
35
|
+
|
36
|
+
config.send(name, *args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Pass on respond_to?-calls
|
40
|
+
def respond_to_missing?(name, _include_private)
|
41
|
+
config.respond_to? name
|
42
|
+
end
|
43
|
+
|
44
|
+
# Compare two configs
|
45
|
+
#
|
46
|
+
# The comparism is done based on their values. No hooks are compared.
|
47
|
+
#
|
48
|
+
# Somehow `#respond_to_missing?`, `method_missing?` and `respond_to?` don't
|
49
|
+
# help here.
|
50
|
+
def ==(other)
|
51
|
+
config == other
|
52
|
+
end
|
53
|
+
|
54
|
+
# Pass on respond_to?-calls
|
55
|
+
def respond_to?(m)
|
56
|
+
config.respond_to? m
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'proxy_rb/api'
|
3
|
+
|
4
|
+
# ProxyRb
|
5
|
+
module ProxyRb
|
6
|
+
# Consule
|
7
|
+
class Console
|
8
|
+
# Helpers for ProxyRb::Console
|
9
|
+
module Help
|
10
|
+
# Output help information
|
11
|
+
def proxy_rb_help
|
12
|
+
puts 'ProxyRb Version: ' + ProxyRb::VERSION
|
13
|
+
puts 'Issue Tracker: ' + 'https://github.com/fedux-org/proxy_rb/issues'
|
14
|
+
puts "Documentation:\n" + %w(http://www.rubydoc.info/gems/proxy_rb).map { |d| format('* %s', d) }.join("\n")
|
15
|
+
puts
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# List available methods in proxy_rb
|
21
|
+
def proxy_rb_methods
|
22
|
+
ms = (ProxyRb::Api.instance_methods - Module.instance_methods).each_with_object([]) { |e, a| a << format('* %s', e) }.sort
|
23
|
+
puts "Available Methods:\n" + ms.join("\n")
|
24
|
+
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'irb'
|
3
|
+
|
4
|
+
require 'proxy_rb/console/help'
|
5
|
+
require 'proxy_rb/api'
|
6
|
+
|
7
|
+
# ProxyRb
|
8
|
+
module ProxyRb
|
9
|
+
# Consule
|
10
|
+
class Console
|
11
|
+
# Start the proxy_rb console
|
12
|
+
def start
|
13
|
+
# Start IRB with current context:
|
14
|
+
# http://stackoverflow.com/questions/4189818/how-to-run-irb-start-in-context-of-current-class
|
15
|
+
ARGV.clear
|
16
|
+
IRB.setup nil
|
17
|
+
|
18
|
+
IRB.conf[:IRB_NAME] = 'proxy_rb'
|
19
|
+
|
20
|
+
IRB.conf[:PROMPT] = {}
|
21
|
+
IRB.conf[:PROMPT][:PROXY_RB] = {
|
22
|
+
PROMPT_I: '%N:%03n:%i> ',
|
23
|
+
PROMPT_S: '%N:%03n:%i%l ',
|
24
|
+
PROMPT_C: '%N:%03n:%i* ',
|
25
|
+
RETURN: "# => %s\n"
|
26
|
+
}
|
27
|
+
IRB.conf[:PROMPT_MODE] = :PROXY_RB
|
28
|
+
|
29
|
+
IRB.conf[:RC] = false
|
30
|
+
|
31
|
+
require 'irb/completion'
|
32
|
+
require 'irb/ext/save-history'
|
33
|
+
IRB.conf[:READLINE] = true
|
34
|
+
IRB.conf[:SAVE_HISTORY] = 1000
|
35
|
+
IRB.conf[:HISTORY_FILE] = ProxyRb.config.console_history_file
|
36
|
+
|
37
|
+
context = Class.new do
|
38
|
+
include ProxyRb::Console::Help
|
39
|
+
include ProxyRb::Api
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
'nil'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
irb = IRB::Irb.new(IRB::WorkSpace.new(context.new))
|
47
|
+
IRB.conf[:MAIN_CONTEXT] = irb.context
|
48
|
+
|
49
|
+
trap('SIGINT') do
|
50
|
+
irb.signal_handle
|
51
|
+
end
|
52
|
+
|
53
|
+
begin
|
54
|
+
catch(:IRB_EXIT) do
|
55
|
+
irb.eval_input
|
56
|
+
end
|
57
|
+
ensure
|
58
|
+
IRB.irb_at_exit
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/proxy_rb/credentials.rb
CHANGED
@@ -33,6 +33,17 @@ module ProxyRb
|
|
33
33
|
!(user_name? && password?)
|
34
34
|
end
|
35
35
|
|
36
|
+
# Convert to hash
|
37
|
+
#
|
38
|
+
# @return [Hash]
|
39
|
+
# The credentials as hash
|
40
|
+
def to_hash
|
41
|
+
{
|
42
|
+
user_name: user_name,
|
43
|
+
password: password
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
36
47
|
private
|
37
48
|
|
38
49
|
def user_name?
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'proxy_rb/drivers/basic_driver'
|
3
2
|
require 'capybara'
|
4
3
|
|
4
|
+
require 'proxy_rb/drivers/basic_driver'
|
5
|
+
require 'proxy_rb/errors'
|
6
|
+
|
5
7
|
begin
|
6
8
|
require 'capybara/poltergeist'
|
7
9
|
rescue LoadError => e
|
@@ -44,9 +46,13 @@ module ProxyRb
|
|
44
46
|
::Capybara.current_driver = proxy.to_ref
|
45
47
|
end
|
46
48
|
|
47
|
-
def
|
49
|
+
def timeout_errors
|
48
50
|
[::Capybara::Poltergeist::TimeoutError]
|
49
51
|
end
|
52
|
+
|
53
|
+
def failure_errors
|
54
|
+
[::Capybara::Poltergeist::StatusFailError]
|
55
|
+
end
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'proxy_rb/drivers/basic_driver'
|
3
3
|
require 'capybara'
|
4
4
|
require 'selenium-webdriver'
|
5
|
+
require 'proxy_rb/errors'
|
5
6
|
|
6
7
|
# ProxyRb
|
7
8
|
module ProxyRb
|
@@ -20,6 +21,7 @@ module ProxyRb
|
|
20
21
|
end
|
21
22
|
|
22
23
|
profile = Selenium::WebDriver::Firefox::Profile.new
|
24
|
+
# profile.proxy = Selenium::WebDriver::Proxy.new(http: proxy.full_url)
|
23
25
|
profile.proxy = Selenium::WebDriver::Proxy.new(http: format('%s:%s', proxy.host, proxy.port))
|
24
26
|
|
25
27
|
unless ::Capybara.drivers.key? proxy.to_ref
|
@@ -31,7 +33,11 @@ module ProxyRb
|
|
31
33
|
::Capybara.current_driver = proxy.to_ref
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
36
|
+
def timeout_errors
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_errors
|
35
41
|
[]
|
36
42
|
end
|
37
43
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'proxy_rb/drivers/basic_driver'
|
3
|
+
require 'proxy_rb/errors'
|
3
4
|
|
4
5
|
begin
|
5
6
|
require 'capybara/webkit'
|
@@ -48,9 +49,17 @@ module ProxyRb
|
|
48
49
|
::Capybara.current_driver = proxy.to_ref
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
+
def timeout_errors
|
52
53
|
[::Capybara::Webkit::TimeoutError]
|
53
54
|
end
|
55
|
+
|
56
|
+
def failure_errors
|
57
|
+
[
|
58
|
+
Capybara::Webkit::InvalidResponseError,
|
59
|
+
Capybara::Webkit::NoResponseError,
|
60
|
+
Capybara::Webkit::ConnectionError
|
61
|
+
]
|
62
|
+
end
|
54
63
|
end
|
55
64
|
end
|
56
65
|
end
|
data/lib/proxy_rb/errors.rb
CHANGED
@@ -2,4 +2,16 @@
|
|
2
2
|
module ProxyRb
|
3
3
|
# Raised if time out occured while fetch resource
|
4
4
|
class UrlTimeoutError < StandardError; end
|
5
|
+
|
6
|
+
# Raised when resource cannot be downloaded
|
7
|
+
class ResourceNotDownloadableError < StandardError; end
|
8
|
+
|
9
|
+
# Raised if one tries to use an unknown configuration option
|
10
|
+
class UnknownOptionError < ArgumentError; end
|
11
|
+
|
12
|
+
# Raised if an event name cannot be resolved
|
13
|
+
class EventNameResolveError < StandardError; end
|
14
|
+
|
15
|
+
# Raised if given object is not an event
|
16
|
+
class NoEventError < StandardError; end
|
5
17
|
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'proxy_rb/errors'
|
3
|
+
|
4
|
+
# Event notification library
|
5
|
+
module ProxyRb
|
6
|
+
# EventBus
|
7
|
+
class EventBus
|
8
|
+
# Resolve name to Event name
|
9
|
+
class NameResolver
|
10
|
+
# @private
|
11
|
+
# Helpers for Resolvers
|
12
|
+
module ResolveHelpers
|
13
|
+
def camel_case(underscored_name)
|
14
|
+
if RUBY_VERSION < '1.9.3'
|
15
|
+
underscored_name.to_s.split('_').map { |word| word.upcase.chars.to_a[0] + word.chars.to_a[1..-1].join }.join
|
16
|
+
else
|
17
|
+
underscored_name.to_s.split('_').map { |word| word.upcase[0] + word[1..-1] }.join
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Thanks ActiveSupport
|
22
|
+
# (Only needed to support Ruby 1.9.3 and JRuby)
|
23
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
24
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
25
|
+
def constantize(camel_cased_word)
|
26
|
+
names = camel_cased_word.split('::')
|
27
|
+
|
28
|
+
# Trigger a built-in NameError exception including the ill-formed constant in the message.
|
29
|
+
Object.const_get(camel_cased_word) if names.empty?
|
30
|
+
|
31
|
+
# Remove the first blank element in case of '::ClassName' notation.
|
32
|
+
names.shift if names.size > 1 && names.first.empty?
|
33
|
+
|
34
|
+
names.inject(Object) do |constant, name|
|
35
|
+
if constant == Object
|
36
|
+
constant.const_get(name)
|
37
|
+
else
|
38
|
+
candidate = constant.const_get(name)
|
39
|
+
|
40
|
+
next candidate if constant.const_defined?(name, false)
|
41
|
+
|
42
|
+
next candidate unless Object.const_defined?(name)
|
43
|
+
|
44
|
+
# Go down the ancestors to check if it is owned directly. The check
|
45
|
+
# stops when we reach Object or the end of ancestors tree.
|
46
|
+
# rubocop:disable Style/EachWithObject
|
47
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
48
|
+
break const if ancestor == Object
|
49
|
+
break ancestor if ancestor.const_defined?(name, false)
|
50
|
+
const
|
51
|
+
end
|
52
|
+
# rubocop:enable Style/EachWithObject
|
53
|
+
|
54
|
+
# owner is in Object, so raise
|
55
|
+
constant.const_get(name, false)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
60
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
61
|
+
end
|
62
|
+
|
63
|
+
# @private
|
64
|
+
# Convert a class in to an event class
|
65
|
+
class ClassResolver
|
66
|
+
class << self
|
67
|
+
def match?(event_id)
|
68
|
+
event_id.is_a? Class
|
69
|
+
end
|
70
|
+
|
71
|
+
# Which types are supported
|
72
|
+
def supports
|
73
|
+
[Class]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def transform(_, event_id)
|
78
|
+
event_id
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# @private
|
83
|
+
# Convert a string in to an event class
|
84
|
+
class StringResolver
|
85
|
+
include ResolveHelpers
|
86
|
+
|
87
|
+
class << self
|
88
|
+
def match?(event_id)
|
89
|
+
event_id.is_a? String
|
90
|
+
end
|
91
|
+
|
92
|
+
# Which types are supported
|
93
|
+
def supports
|
94
|
+
[String]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def transform(_, event_id)
|
99
|
+
constantize(event_id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @private
|
104
|
+
# Convert a symbol in to an event class
|
105
|
+
class SymbolResolver
|
106
|
+
include ResolveHelpers
|
107
|
+
|
108
|
+
class << self
|
109
|
+
def match?(event_id)
|
110
|
+
event_id.is_a? Symbol
|
111
|
+
end
|
112
|
+
|
113
|
+
# Which types are supported
|
114
|
+
def supports
|
115
|
+
[Symbol]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def transform(default_namespace, event_id)
|
120
|
+
constantize("#{default_namespace}::#{camel_case(event_id)}")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# @private
|
125
|
+
# Default failing resolver
|
126
|
+
#
|
127
|
+
# This comes into play if the user passes an invalid event type
|
128
|
+
class FailingResolver
|
129
|
+
class << self
|
130
|
+
def match?(event_id)
|
131
|
+
raise ArgumentError, %(Input type "#{event_id.class}" of event_id "#{event_id}" is invalid)
|
132
|
+
end
|
133
|
+
|
134
|
+
def supports
|
135
|
+
[]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
protected
|
141
|
+
|
142
|
+
attr_reader :resolvers, :default_namespace
|
143
|
+
|
144
|
+
public
|
145
|
+
|
146
|
+
def initialize(default_namespace)
|
147
|
+
@default_namespace = default_namespace
|
148
|
+
|
149
|
+
@resolvers = []
|
150
|
+
@resolvers << ClassResolver
|
151
|
+
@resolvers << StringResolver
|
152
|
+
@resolvers << SymbolResolver
|
153
|
+
@resolvers << FailingResolver
|
154
|
+
end
|
155
|
+
|
156
|
+
def transform(event_id)
|
157
|
+
resolvers.find { |r| r.match? event_id }.new.transform(default_namespace, event_id)
|
158
|
+
rescue => e
|
159
|
+
raise EventNameResolveError, %(Transforming "#{event_id}" into an event class failed. Supported types are: #{@resolvers.map(&:supports).flatten.join(', ')}. #{e.message}.\n\n#{e.backtrace.join("\n")})
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'proxy_rb/event_bus/name_resolver'
|
3
|
+
require 'proxy_rb/errors'
|
4
|
+
|
5
|
+
module ProxyRb
|
6
|
+
# Event bus
|
7
|
+
#
|
8
|
+
# Implements and in-process pub-sub events broadcaster allowing multiple observers
|
9
|
+
# to subscribe to different events that fire as your tests are executed.
|
10
|
+
#
|
11
|
+
class EventBus
|
12
|
+
# Create EventBus
|
13
|
+
#
|
14
|
+
# @param [#transform] resolver
|
15
|
+
# A resolver which transforms Symbol, String, Class into an event Class.
|
16
|
+
def initialize(resolver)
|
17
|
+
@resolver = resolver
|
18
|
+
@handlers = Hash.new { |h, k| h[k] = [] }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Register for an event
|
22
|
+
#
|
23
|
+
# @param [String, Symbol, Class, Array] event_ids
|
24
|
+
# If Array, register multiple events witht the same handler. If String,
|
25
|
+
# Symbol, Class register handler for given event.
|
26
|
+
#
|
27
|
+
# @param [#call] handler_object
|
28
|
+
# The handler object, needs to have method `#call`. Either
|
29
|
+
# `handler_object` or `block` can be defined. The handler object gets the
|
30
|
+
# event passed to `#call`.
|
31
|
+
#
|
32
|
+
# @yield
|
33
|
+
# Handler block which gets the event passed as parameter.
|
34
|
+
def register(event_ids, handler_object = nil, &handler_proc)
|
35
|
+
handler = handler_proc || handler_object
|
36
|
+
|
37
|
+
raise ArgumentError, 'Please pass either an object#call or a handler block' if handler.nil? || !handler.respond_to?(:call)
|
38
|
+
|
39
|
+
Array(event_ids).flatten.each do |id|
|
40
|
+
@handlers[
|
41
|
+
@resolver.transform(id).to_s
|
42
|
+
] << handler
|
43
|
+
end
|
44
|
+
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Broadcast an event
|
49
|
+
#
|
50
|
+
# @param [Object] event
|
51
|
+
# An object of registered event class. This object is passed to the event
|
52
|
+
# handler.
|
53
|
+
#
|
54
|
+
def notify(event)
|
55
|
+
raise NoEventError, 'Please pass an event object, not a class' if event.is_a?(Class)
|
56
|
+
|
57
|
+
@handlers[event.class.to_s].each { |handler| handler.call(event) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# ProxyRb
|
3
|
+
module ProxyRb
|
4
|
+
# Events
|
5
|
+
module Events
|
6
|
+
# Basic event
|
7
|
+
#
|
8
|
+
# This is not meant for direct use - BasicEvent.new - by users. It is inherited by normal events
|
9
|
+
#
|
10
|
+
# @private
|
11
|
+
class BasicEvent
|
12
|
+
attr_reader :entity
|
13
|
+
|
14
|
+
def initialize(entity)
|
15
|
+
@entity = entity
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Proxy was set
|
20
|
+
class ProxySet < BasicEvent; end
|
21
|
+
|
22
|
+
# User was set
|
23
|
+
class ProxyUserSet < BasicEvent; end
|
24
|
+
|
25
|
+
# User was set
|
26
|
+
class ResourceUserSet < BasicEvent; end
|
27
|
+
|
28
|
+
# User was set
|
29
|
+
class ResourceSet < BasicEvent; end
|
30
|
+
|
31
|
+
# The configuration was changed
|
32
|
+
class ChangedConfiguration < BasicEvent; end
|
33
|
+
end
|
34
|
+
end
|
data/lib/proxy_rb/http_proxy.rb
CHANGED
@@ -42,5 +42,13 @@ module ProxyRb
|
|
42
42
|
def to_ref
|
43
43
|
Shellwords.escape(*[host, port, user].compact.join('_')).to_sym
|
44
44
|
end
|
45
|
+
|
46
|
+
# Return proxy as full url
|
47
|
+
#
|
48
|
+
# @return [ProxyUrl]
|
49
|
+
# The proxy as url
|
50
|
+
def full_url
|
51
|
+
ProxyUrl.build url.to_hash.merge(credentials.to_hash)
|
52
|
+
end
|
45
53
|
end
|
46
54
|
end
|