robro 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 10669183561bee9dc05019e9ba48e4a310d677bf7f6d894a2087b921bcbbf4e2
4
+ data.tar.gz: 5dc3de7e22944e99eb1573ec854c6c85c448c372b133e10a81919888b35106df
5
+ SHA512:
6
+ metadata.gz: dc6d2c6335ddbad6ac9d1a4eeef648b1b1762230f3d9dc547adf73760662f070ec63b8cbecc17a0949ee3c6d799518c2bc469915ca7a60ebe5ade369f94f417d
7
+ data.tar.gz: ed9fc9c0d20e14fcf379617fccf84f98abb30e03936f71660bae4c79e21c7054b3b701d46ec0cb1dd1543900d774280ffd8574b091f065f09ed99d35054768cc
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ .rspec_status
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /Gemfile.lock
11
+ /.byebug_history
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in robro.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Robro
2
+
3
+ **Robro**, _Robotized brower_, a tool to ease some tasks automation that needs a _real_ browser.
4
+
5
+ Technically, `robro` is a CLI that starts a browser and provides some helpers to drive it.
6
+
7
+ **Robro** is designed to run _user scripts_, specialized for the wanted automation. Out of the box, `robro` only provides a `browse` command to starts a browser, visit an URL and drop a ruby shell.
8
+
9
+ ## Usage
10
+
11
+ Built-in command: `browse` will open the provided URL than simply drop a ruby shell (_byebug_).
12
+
13
+ ```
14
+ robro browse https://example.com
15
+ ```
16
+
17
+ Its useful to design your own _user script_, see below.
18
+
19
+ ## User scripts
20
+
21
+ _User scripts_ are ruby files that provide new commands, designed to use the robotized browser.
22
+
23
+ ## Development
24
+
25
+ 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.
26
+
27
+ 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).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/opus-codium/robro.
32
+
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 "robro"
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
data/exe/robro ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ require 'robro/cli'
6
+
7
+ begin
8
+ Robro::CLI.start ARGV
9
+ #rescue Robro::Error => e
10
+ # $stderr.puts e.message
11
+ # exit 1
12
+ end
@@ -0,0 +1,119 @@
1
+ require 'capybara'
2
+ require 'capybara/dsl'
3
+ require 'capybara-screenshot'
4
+
5
+ module Robro
6
+ class Browser
7
+ attr_reader :application
8
+
9
+ include Capybara::DSL
10
+
11
+ def initialize(application)
12
+ @application = application.to_sym
13
+ @headless = false # FIXME ENV['GUI'].nil?
14
+
15
+ Capybara.configure do |config|
16
+ config.run_server = false
17
+ config.default_max_wait_time = 5
18
+ end
19
+
20
+ # FIXME Register chrome_jack_headless
21
+ require 'selenium-webdriver'
22
+ Capybara.register_driver :chrome_jack do |app|
23
+ options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts|
24
+ opts.args << '--start-maximized'
25
+ opts.args << '--disable-blink-features'
26
+ opts.args << '--disable-blink-features=AutomationControlled'
27
+ opts.args << '--excludeSwitches=enable-automation'
28
+ opts.args << '--disable-gpu'
29
+ end
30
+ driver = Capybara::Selenium::Driver.new(app, browser: :chrome, capabilities: options)
31
+ bridge = driver.browser.send(:bridge)
32
+
33
+ path = '/session/:session_id/chromium/send_command'
34
+ path[':session_id'] = bridge.session_id
35
+
36
+ javascript = <<~JAVASCRIPT
37
+ Object.defineProperty(document, 'visibilityState', {value: 'visible', writable: true});
38
+ Object.defineProperty(document, 'hidden', {value: false, writable: true});
39
+ document.dispatchEvent(new Event("visibilitychange"));
40
+
41
+ Object.defineProperty(window, 'navigator', {
42
+ value: new Proxy(navigator, {
43
+ has: (target, key) => (key === 'webdriver' ? false : key in target),
44
+ get: (target, key) =>
45
+ key === 'webdriver'
46
+ ? undefined
47
+ : typeof target[key] === 'function'
48
+ ? target[key].bind(target)
49
+ : target[key]
50
+ })
51
+ });
52
+ JAVASCRIPT
53
+
54
+ bridge.http.call(:post, path, cmd: 'Page.addScriptToEvaluateOnNewDocument',
55
+ params: {
56
+ source: javascript,
57
+ })
58
+
59
+ driver
60
+ end
61
+
62
+ Capybara.current_driver = driver
63
+
64
+ Capybara::Screenshot.register_driver(Capybara.current_driver) do |driver, path|
65
+ driver.browser.save_screenshot(path)
66
+ end
67
+
68
+ Robro.logger.debug "Browser User-Agent: '#{page.execute_script 'return navigator.userAgent'}'"
69
+
70
+ Robro.logger.debug "Capybara driver: #{Capybara.current_driver} (application: #{application}, headless: #{headless?})"
71
+ end
72
+
73
+ def headless?
74
+ @headless
75
+ end
76
+
77
+ def clear
78
+ visit 'file:///dev/null'
79
+ end
80
+
81
+ def close_other_tabs
82
+ current_tab = page.driver.browser.window_handle
83
+ tabs = page.driver.browser.window_handles - [current_tab]
84
+ tabs.each do |tab|
85
+ page.driver.browser.switch_to.window(tab)
86
+ page.driver.browser.close
87
+ end
88
+ page.driver.browser.switch_to.window current_tab
89
+ end
90
+
91
+ def keep_only_tabs_with(url:)
92
+ tabs = page.driver.browser.window_handles
93
+
94
+ tabs.each do |tab|
95
+ page.driver.browser.switch_to.window(tab)
96
+ page.driver.browser.close unless page.current_url.start_with?(url_start_with)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def driver
103
+ @application = 'chrome' if @application == 'chromium'
104
+
105
+ driver_name = case @application
106
+ when :firefox
107
+ 'selenium'
108
+ when :chrome
109
+ 'chrome_jack'
110
+ else
111
+ raise "Unsupported browser: '#{application}'"
112
+ end
113
+
114
+ driver_name += '_headless' if @headless
115
+
116
+ driver_name.to_sym
117
+ end
118
+ end
119
+ end
data/lib/robro/cli.rb ADDED
@@ -0,0 +1,76 @@
1
+ require 'robro'
2
+ require 'robro/user_scripts'
3
+
4
+ require 'thor'
5
+ require 'json'
6
+
7
+ require 'active_support/inflector'
8
+
9
+ module Robro
10
+ class CLI < Thor
11
+ desc 'browse URL', 'Start browser at URL, drop a shell'
12
+ method_option :browser, :type => :string, :description => 'Supported values: firefox or chromium', :default => 'chrome'
13
+ def browse(url)
14
+ uri = validate_url(url)
15
+
16
+ Robro.browser = Browser.new options[:browser]
17
+ Robro.browser.visit uri
18
+
19
+ quit = false
20
+ until quit
21
+ UserScripts.all.each do |us_class|
22
+ us = us_class.new
23
+ next unless uri.host.start_with? *(us.supported_urls)
24
+
25
+ unless us.nil?
26
+ puts "Commands for this URL: #{us.supported_url_commands}"
27
+
28
+ us.supported_url_commands.each do |command|
29
+ define_singleton_method command do |*args|
30
+ us.send(command, *args)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ byebug
37
+ end
38
+ end
39
+
40
+ no_commands do
41
+ def validate_url(url)
42
+ uri = URI(url)
43
+
44
+ case uri.scheme
45
+ when 'http'
46
+ uri.scheme = 'https'
47
+ when 'https'
48
+ # Supported
49
+ else
50
+ raise NotImplementedError
51
+ end
52
+
53
+ uri
54
+ end
55
+ end
56
+
57
+ UserScripts.all.each do |us_class|
58
+ us = us_class.new
59
+ us.supported_url_commands.each do |command|
60
+ desc "#{command} URL", command.to_s
61
+ method_option :browser, :type => :string, :description => 'Supported values: firefox or chromium', :default => 'chrome'
62
+ define_method command do |*args|
63
+ url = args.shift
64
+ raise Thor::Error, 'URL argument is missing' if url.nil?
65
+
66
+ uri = validate_url(url)
67
+
68
+ Robro.browser = Browser.new options[:browser]
69
+ Robro.browser.visit uri
70
+
71
+ puts JSON.pretty_generate(us.send(command, *args))
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ module Robro
2
+ module UserScripts
3
+ def self.all
4
+ Dir.glob('userscripts/*.rb').map do |file|
5
+ require File.expand_path(file)
6
+ class_name = File.basename(file, '.rb').camelize
7
+ const_get class_name
8
+ end
9
+ end
10
+
11
+ class Base
12
+ def commands
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module Robro
2
+ VERSION = "0.1.0"
3
+ end
data/lib/robro.rb ADDED
@@ -0,0 +1,25 @@
1
+ require "robro/browser"
2
+ require "robro/version"
3
+
4
+ require 'tty/logger'
5
+ require 'byebug'
6
+
7
+ module Robro
8
+ class Error < StandardError; end
9
+
10
+ def self.logger
11
+ @@logger ||= TTY::Logger.new do |config|
12
+ config.handlers = [
13
+ [:console, { output: $stderr, level: :debug }],
14
+ ]
15
+ end
16
+ end
17
+
18
+ def self.browser=(browser)
19
+ @@browser = browser
20
+ end
21
+
22
+ def self.browser
23
+ @@browser || raise('Browser must be initialized first!')
24
+ end
25
+ end
data/robro.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ require_relative 'lib/robro/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "robro"
5
+ spec.version = Robro::VERSION
6
+ spec.authors = ["Romuald Conty"]
7
+ spec.email = ["neomilium@gmail.com"]
8
+
9
+ spec.summary = %q{Robotized Browser}
10
+ spec.description = %q{Automate tasks that require a _real_ browser}
11
+ spec.homepage = "https://github.com/neomilium/robro"
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
13
+
14
+ spec.metadata["homepage_uri"] = spec.homepage
15
+ spec.metadata["source_code_uri"] = "#{spec.homepage}.git"
16
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/Changelog.md"
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency "activesupport"
28
+ spec.add_dependency "capybara"
29
+ spec.add_dependency "capybara-screenshot"
30
+ spec.add_dependency "selenium-webdriver"
31
+ spec.add_dependency "thor"
32
+ spec.add_dependency "tty-logger"
33
+ spec.add_development_dependency "byebug"
34
+ spec.add_development_dependency "bundler"
35
+ spec.add_development_dependency "rake"
36
+ spec.add_development_dependency "rspec"
37
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: robro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Romuald Conty
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: capybara
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: capybara-screenshot
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: selenium-webdriver
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-logger
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: byebug
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: bundler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Automate tasks that require a _real_ browser
154
+ email:
155
+ - neomilium@gmail.com
156
+ executables:
157
+ - robro
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".gitignore"
162
+ - ".rspec"
163
+ - ".travis.yml"
164
+ - Gemfile
165
+ - README.md
166
+ - Rakefile
167
+ - bin/console
168
+ - bin/setup
169
+ - exe/robro
170
+ - lib/robro.rb
171
+ - lib/robro/browser.rb
172
+ - lib/robro/cli.rb
173
+ - lib/robro/user_scripts.rb
174
+ - lib/robro/version.rb
175
+ - robro.gemspec
176
+ homepage: https://github.com/neomilium/robro
177
+ licenses: []
178
+ metadata:
179
+ homepage_uri: https://github.com/neomilium/robro
180
+ source_code_uri: https://github.com/neomilium/robro.git
181
+ changelog_uri: https://github.com/neomilium/robro/Changelog.md
182
+ post_install_message:
183
+ rdoc_options: []
184
+ require_paths:
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: 2.5.0
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubygems_version: 3.1.2
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: Robotized Browser
201
+ test_files: []