crabfarm 0.2.5 → 0.3.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/lib/crabfarm.rb +17 -18
- data/lib/crabfarm/adapters/browser/abstract_webdriver.rb +60 -0
- data/lib/crabfarm/adapters/browser/chrome.rb +24 -0
- data/lib/crabfarm/adapters/browser/firefox.rb +26 -0
- data/lib/crabfarm/adapters/browser/noop.rb +25 -0
- data/lib/crabfarm/adapters/browser/phantom_js.rb +59 -0
- data/lib/crabfarm/adapters/browser/remote_webdriver.rb +31 -0
- data/lib/crabfarm/adapters/driver_wrapper/capybara.rb +11 -0
- data/lib/crabfarm/adapters/driver_wrapper/surfer.rb +13 -0
- data/lib/crabfarm/adapters/{browser → driver_wrapper}/watir.rb +7 -3
- data/lib/crabfarm/adapters/parser/nokogiri.rb +17 -15
- data/lib/crabfarm/adapters/parser/pdf_reader.rb +14 -12
- data/lib/crabfarm/assertion/fields.rb +85 -0
- data/lib/crabfarm/base_navigator.rb +78 -0
- data/lib/crabfarm/base_reducer.rb +68 -0
- data/lib/crabfarm/base_struct.rb +17 -0
- data/lib/crabfarm/cli.rb +18 -8
- data/lib/crabfarm/configuration.rb +24 -51
- data/lib/crabfarm/context.rb +19 -43
- data/lib/crabfarm/crabtrap_context.rb +4 -11
- data/lib/crabfarm/driver_pool.rb +32 -0
- data/lib/crabfarm/dsl/surfer/surf_context.rb +5 -25
- data/lib/crabfarm/engines/async_state_manager.rb +1 -1
- data/lib/crabfarm/engines/sync_state_manager.rb +1 -1
- data/lib/crabfarm/forked_navigator.rb +31 -0
- data/lib/crabfarm/modes/console.rb +4 -4
- data/lib/crabfarm/modes/generator.rb +24 -11
- data/lib/crabfarm/rspec.rb +26 -24
- data/lib/crabfarm/strategies.rb +15 -9
- data/lib/crabfarm/templates/Crabfile.erb +21 -26
- data/lib/crabfarm/templates/Gemfile.erb +6 -0
- data/lib/crabfarm/templates/navigator.rb.erb +20 -0
- data/lib/crabfarm/templates/{state_spec.rb.erb → navigator_spec.rb.erb} +1 -1
- data/lib/crabfarm/templates/{parser.rb.erb → reducer.rb.erb} +4 -4
- data/lib/crabfarm/templates/{parser_spec.rb.erb → reducer_spec.rb.erb} +1 -1
- data/lib/crabfarm/templates/struct.rb.erb +12 -0
- data/lib/crabfarm/transition_service.rb +20 -7
- data/lib/crabfarm/version.rb +1 -1
- metadata +50 -48
- data/lib/crabfarm/adapters/browser/capybara.rb +0 -7
- data/lib/crabfarm/adapters/browser/surfer.rb +0 -9
- data/lib/crabfarm/adapters/output/hash.rb +0 -11
- data/lib/crabfarm/adapters/output/jbuilder.rb +0 -11
- data/lib/crabfarm/adapters/output/ostruct.rb +0 -14
- data/lib/crabfarm/base_parser.rb +0 -59
- data/lib/crabfarm/base_state.rb +0 -112
- data/lib/crabfarm/default_driver_factory.rb +0 -86
- data/lib/crabfarm/driver_bucket.rb +0 -42
- data/lib/crabfarm/driver_bucket_pool.rb +0 -26
- data/lib/crabfarm/forked_state.rb +0 -38
- data/lib/crabfarm/mocks/noop_driver.rb +0 -6
- data/lib/crabfarm/phantom_driver_factory.rb +0 -33
- data/lib/crabfarm/templates/state.rb.erb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0b57880b14cf2f7456a2d457e9c3b9531c9ac2b
|
4
|
+
data.tar.gz: 61200983d1469d597384640d3d3457547ab486fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65659324efa94632a56a2da599f760ec0f79199f307efaf9399580d23344456f076987baba5631c1be7ac37ac063da41b46fd8aaf762c49911eae1439ba74d84
|
7
|
+
data.tar.gz: db9ee502e2db56b89ad0ec80dea565537cb20577b6660f27f1c3e3fbd8392da8a8ff1608b7e1c5011b7e30ddd922b2d6367bcff5630ab90fe67bc4aa7a27b766
|
data/lib/crabfarm.rb
CHANGED
@@ -2,24 +2,21 @@ require "logger"
|
|
2
2
|
require "forwardable"
|
3
3
|
require "net/http"
|
4
4
|
require "active_support/inflector"
|
5
|
-
require "selenium-webdriver"
|
6
5
|
|
7
6
|
require "crabfarm/version"
|
8
7
|
require "crabfarm/errors"
|
9
8
|
require "crabfarm/configuration"
|
10
9
|
require "crabfarm/global_state"
|
11
|
-
require "crabfarm/
|
12
|
-
require "crabfarm/driver_bucket_pool"
|
10
|
+
require "crabfarm/driver_pool"
|
13
11
|
require "crabfarm/http_client"
|
14
|
-
require "crabfarm/default_driver_factory"
|
15
|
-
require "crabfarm/phantom_driver_factory"
|
16
12
|
require "crabfarm/phantom_runner"
|
17
13
|
require "crabfarm/state_store"
|
18
14
|
require "crabfarm/context"
|
19
15
|
require "crabfarm/context_factory"
|
20
16
|
require "crabfarm/transition_service"
|
21
|
-
require "crabfarm/
|
22
|
-
require "crabfarm/
|
17
|
+
require "crabfarm/base_navigator"
|
18
|
+
require "crabfarm/base_reducer"
|
19
|
+
require "crabfarm/base_struct"
|
23
20
|
require "crabfarm/strategies"
|
24
21
|
|
25
22
|
require "crabfarm/utils/port_discovery"
|
@@ -47,18 +44,20 @@ module Crabfarm
|
|
47
44
|
end
|
48
45
|
|
49
46
|
module Strategies
|
50
|
-
# bundled browser
|
51
|
-
register :
|
52
|
-
register :
|
53
|
-
register :
|
47
|
+
# bundled browser adapters
|
48
|
+
register :browser, :phantomjs, 'Crabfarm::Adapters::Browser::PhantomJs', dependencies: ['selenium-webdriver']
|
49
|
+
register :browser, :firefox, 'Crabfarm::Adapters::Browser::Firefox', dependencies: ['selenium-webdriver']
|
50
|
+
register :browser, :chrome, 'Crabfarm::Adapters::Browser::Chrome', dependencies: ['selenium-webdriver']
|
51
|
+
register :browser, :remote, 'Crabfarm::Adapters::Browser::RemoteWebdriver', dependencies: ['selenium-webdriver']
|
52
|
+
register :browser, :noop, 'Crabfarm::Adapters::Browser::Noop'
|
53
|
+
|
54
|
+
# bundled webdriver dsl adapters
|
55
|
+
register :webdriver_dsl, :surfer, 'Crabfarm::Adapters::DriverWrapper::Surfer'
|
56
|
+
register :webdriver_dsl, :watir, 'Crabfarm::Adapters::DriverWrapper::Watir', dependencies: ['watir-webdriver']
|
57
|
+
register :webdriver_dsl, :capybara, 'Crabfarm::Adapters::DriverWrapper::Capybara', dependencies: ['capybara']
|
54
58
|
|
55
59
|
# bundled parsers dsl adapters
|
56
|
-
register :
|
57
|
-
register :
|
58
|
-
|
59
|
-
# bundled state output builders
|
60
|
-
register :output_builder, :hash, 'Crabfarm::HashOutputBuilder', 'crabfarm/adapters/output/hash'
|
61
|
-
register :output_builder, :ostruct, 'Crabfarm::OStructOutputBuilder', 'crabfarm/adapters/output/ostruct'
|
62
|
-
register :output_builder, :jbuilder, 'Crabfarm::JbuilderOutputBuilder', 'crabfarm/adapters/output/jbuilder', ['jbuilder']
|
60
|
+
register :parser, :nokogiri, 'Crabfarm::Adapters::Parser::Nokogiri', dependencies: ['nokogiri']
|
61
|
+
register :parser, :pdf_reader, 'Crabfarm::Adapters::Parser::PdfReader', dependencies: ['pdf-reader']
|
63
62
|
end
|
64
63
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Crabfarm
|
2
|
+
module Adapters
|
3
|
+
module Browser
|
4
|
+
class AbstractWebdriver
|
5
|
+
|
6
|
+
attr_accessor :config
|
7
|
+
|
8
|
+
def initialize(_proxy=nil)
|
9
|
+
@config = load_driver_config
|
10
|
+
@config[:proxy] = _proxy
|
11
|
+
end
|
12
|
+
|
13
|
+
def prepare_driver_services
|
14
|
+
# Nothing by default
|
15
|
+
end
|
16
|
+
|
17
|
+
def cleanup_driver_services
|
18
|
+
# Nothing by default
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_driver(_session_id)
|
22
|
+
|
23
|
+
# load driver and configure general selenium settings
|
24
|
+
driver = build_webdriver_instance
|
25
|
+
driver.manage.window.resize_to(config[:window_width], config[:window_height]) rescue nil
|
26
|
+
|
27
|
+
return wrap_driver driver
|
28
|
+
end
|
29
|
+
|
30
|
+
def release_driver(_driver)
|
31
|
+
@driver.quit rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def wrap_driver _driver
|
37
|
+
if config[:dsl].present?
|
38
|
+
Strategies.load(:webdriver_dsl, config[:dsl]).wrap _driver
|
39
|
+
else _driver end
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_webdriver_instance
|
43
|
+
raise NotImplementedError.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_driver_config
|
47
|
+
{
|
48
|
+
capabilities: Crabfarm.config.webdriver_capabilities,
|
49
|
+
remote_host: Crabfarm.config.webdriver_remote_host,
|
50
|
+
remote_timeout: Crabfarm.config.webdriver_remote_timeout,
|
51
|
+
window_width: Crabfarm.config.webdriver_window_width,
|
52
|
+
window_height: Crabfarm.config.webdriver_window_height,
|
53
|
+
dsl: Crabfarm.config.webdriver_dsl
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "crabfarm/adapters/browser/abstract_webdriver"
|
2
|
+
|
3
|
+
module Crabfarm
|
4
|
+
module Adapters
|
5
|
+
module Browser
|
6
|
+
class Chrome < AbstractWebdriver
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def build_webdriver_instance
|
11
|
+
switches = []
|
12
|
+
|
13
|
+
if config[:proxy].present?
|
14
|
+
switches << "--proxy-server=#{config[:proxy]}"
|
15
|
+
switches << "--ignore-certificate-errors"
|
16
|
+
end
|
17
|
+
|
18
|
+
Selenium::WebDriver.for :chrome, :switches => switches
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "crabfarm/adapters/browser/abstract_webdriver"
|
2
|
+
|
3
|
+
module Crabfarm
|
4
|
+
module Adapters
|
5
|
+
module Browser
|
6
|
+
class Firefox < AbstractWebdriver
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def build_webdriver_instance
|
11
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
12
|
+
|
13
|
+
if config.key? :proxy
|
14
|
+
profile.proxy = Selenium::WebDriver::Proxy.new({
|
15
|
+
:http => config[:proxy],
|
16
|
+
:ssl => config[:proxy]
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
Selenium::WebDriver.for :firefox, :profile => profile
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Crabfarm
|
2
|
+
module Adapters
|
3
|
+
module Browser
|
4
|
+
class Noop
|
5
|
+
|
6
|
+
def initialize(_proxy=nil)
|
7
|
+
end
|
8
|
+
|
9
|
+
def prepare_driver_services
|
10
|
+
end
|
11
|
+
|
12
|
+
def cleanup_driver_services
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_driver(_session_id)
|
16
|
+
_session_id || :noop
|
17
|
+
end
|
18
|
+
|
19
|
+
def release_driver(_driver)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "crabfarm/adapters/browser/abstract_webdriver"
|
2
|
+
require "crabfarm/phantom_runner"
|
3
|
+
|
4
|
+
module Crabfarm
|
5
|
+
module Adapters
|
6
|
+
module Browser
|
7
|
+
class PhantomJs < AbstractWebdriver
|
8
|
+
|
9
|
+
def prepare_driver_services
|
10
|
+
@phantom = load_and_start_phantom if @phantom.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
def cleanup_driver_services
|
14
|
+
@phantom.stop unless @phantom.nil?
|
15
|
+
@phantom = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_webdriver_instance
|
21
|
+
client = Selenium::WebDriver::Remote::Http::Default.new
|
22
|
+
client.timeout = config[:remote_timeout]
|
23
|
+
|
24
|
+
driver = Selenium::WebDriver.for :remote, {
|
25
|
+
:url => phantom_url,
|
26
|
+
:http_client => client,
|
27
|
+
:desired_capabilities => config[:capabilities] || Selenium::WebDriver::Remote::Capabilities.firefox
|
28
|
+
}
|
29
|
+
|
30
|
+
# TODO: not sure if this is necessary...
|
31
|
+
# driver.send(:bridge).setWindowSize(config[:window_width], config[:window_height])
|
32
|
+
|
33
|
+
return driver
|
34
|
+
end
|
35
|
+
|
36
|
+
def load_and_start_phantom
|
37
|
+
new_phantom = PhantomRunner.new phantom_config
|
38
|
+
new_phantom.start
|
39
|
+
return new_phantom
|
40
|
+
end
|
41
|
+
|
42
|
+
def phantom_config
|
43
|
+
{
|
44
|
+
load_images: Crabfarm.config.phantom_load_images,
|
45
|
+
ssl: Crabfarm.config.phantom_ssl,
|
46
|
+
bin_path: Crabfarm.config.phantom_bin_path,
|
47
|
+
proxy: config[:proxy],
|
48
|
+
port: Utils::PortDiscovery.find_available_port
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def phantom_url
|
53
|
+
"http://localhost:#{@phantom.port}"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "crabfarm/adapters/browser/abstract_webdriver"
|
2
|
+
|
3
|
+
module Crabfarm
|
4
|
+
module Adapters
|
5
|
+
module Browser
|
6
|
+
class RemoteWebdriver < AbstractWebdriver
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def build_webdriver_instance
|
11
|
+
client = Selenium::WebDriver::Remote::Http::Default.new
|
12
|
+
client.timeout = config[:remote_timeout]
|
13
|
+
|
14
|
+
if config.has_key? :proxy
|
15
|
+
client.proxy = Selenium::WebDriver::Proxy.new({
|
16
|
+
:http => config[:proxy],
|
17
|
+
:ssl => config[:proxy]
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
Selenium::WebDriver.for(:remote, {
|
22
|
+
:url => config[:remote_host],
|
23
|
+
:http_client => client,
|
24
|
+
:desired_capabilities => config[:capabilities] || Selenium::WebDriver::Remote::Capabilities.firefox
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -17,9 +17,13 @@ class Watir::ElementCollection
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module Crabfarm
|
20
|
-
|
21
|
-
|
22
|
-
Watir
|
20
|
+
module Adapters
|
21
|
+
module DriverWrapper
|
22
|
+
class Watir
|
23
|
+
def self.wrap(_driver)
|
24
|
+
::Watir::Browser.new _driver
|
25
|
+
end
|
26
|
+
end
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|
@@ -1,21 +1,23 @@
|
|
1
|
-
require 'nokogiri'
|
2
|
-
|
3
1
|
module Crabfarm
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
module Adapters
|
3
|
+
module Parser
|
4
|
+
class Nokogiri
|
5
|
+
def self.format
|
6
|
+
'html'
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def self.parse(_raw)
|
10
|
+
::Nokogiri::HTML _raw
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
def self.preprocess_parsing_target(_target)
|
14
|
+
if _target.respond_to? :to_html
|
15
|
+
_target.to_html
|
16
|
+
else
|
17
|
+
_target
|
18
|
+
end
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
21
|
-
end
|
23
|
+
end
|
@@ -1,17 +1,19 @@
|
|
1
|
-
require "pdf-reader"
|
2
|
-
|
3
1
|
module Crabfarm
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
module Adapters
|
3
|
+
module Parser
|
4
|
+
class PdfReader
|
5
|
+
def self.format
|
6
|
+
'pdf'
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def self.parse(_raw)
|
10
|
+
PDF::Reader.new StringIO.new _raw
|
11
|
+
end
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
def self.preprocess_parsing_target(_target)
|
14
|
+
_target
|
15
|
+
end
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
|
-
end
|
19
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "active_support/core_ext/object/duplicable"
|
2
|
+
require 'crabfarm/assertion/context'
|
3
|
+
|
4
|
+
module Crabfarm
|
5
|
+
module Assertion
|
6
|
+
module Fields
|
7
|
+
include Context
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
def has_field(_name, _options={})
|
12
|
+
name = _name.to_sym
|
13
|
+
|
14
|
+
fields << name
|
15
|
+
field_defaults[name] = _options.delete :field_default
|
16
|
+
|
17
|
+
assertion = _options.delete :field_assertion
|
18
|
+
if assertion
|
19
|
+
define_method("#{name}=") { |v| field_hash[name] = assert(v).send(assertion, _options) }
|
20
|
+
elsif not _options[:field_readonly]
|
21
|
+
define_method("#{name}=") { |v| field_hash[name] = v }
|
22
|
+
end
|
23
|
+
|
24
|
+
define_method(name) { field_hash[name] }
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_asserted_field(_name, _assertion, _options={})
|
28
|
+
has_field(_name, _options.merge(field_assertion: _assertion))
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_array(_name)
|
32
|
+
has_field(_name, field_default: [], field_readonly: true)
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_integer(_name, _options={})
|
36
|
+
has_asserted_field _name, :is_integer, _options
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_float(_name, _options={})
|
40
|
+
has_asserted_field _name, :is_float, _options
|
41
|
+
end
|
42
|
+
|
43
|
+
def has_string(_name, _options={})
|
44
|
+
has_asserted_field _name, :is_string, _options
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_word(_name, _options={})
|
48
|
+
has_asserted_field _name, :is_word, _options
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_boolean(_name, _options={})
|
52
|
+
has_asserted_field _name, :is_boolean, _options
|
53
|
+
end
|
54
|
+
|
55
|
+
def fields
|
56
|
+
@fields ||= []
|
57
|
+
end
|
58
|
+
|
59
|
+
def field_defaults
|
60
|
+
@field_defaults ||= {}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.included(klass)
|
66
|
+
klass.extend ClassMethods
|
67
|
+
end
|
68
|
+
|
69
|
+
def reset_fields
|
70
|
+
klass = self.class
|
71
|
+
|
72
|
+
@field_hash = {}
|
73
|
+
klass.fields.each do |field|
|
74
|
+
value = klass.field_defaults[field]
|
75
|
+
@field_hash[field] = value.duplicable? ? value.clone : value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def field_hash
|
80
|
+
@field_hash
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|