proxy_rb 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|