wayfarer 0.4.9 → 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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/actions/setup-mise/action.yaml +22 -0
  3. data/.github/workflows/push.yaml +89 -0
  4. data/.github/workflows/release.yaml +2 -2
  5. data/.gitignore +1 -0
  6. data/AGENTS.md +265 -0
  7. data/CLAUDE.md +1 -0
  8. data/Dockerfile +1 -0
  9. data/Gemfile.lock +5 -1
  10. data/docs/cookbook/batch_routing.md +3 -1
  11. data/docs/cookbook/consent_screen.md +3 -1
  12. data/docs/cookbook/executing_javascript.md +9 -3
  13. data/docs/cookbook/navigation.md +9 -3
  14. data/docs/cookbook/querying_html.md +9 -3
  15. data/docs/cookbook/screenshots.md +6 -2
  16. data/docs/guides/cli.md +1 -1
  17. data/docs/guides/debugging.md +1 -1
  18. data/docs/guides/development.md +18 -26
  19. data/docs/guides/handlers.md +1 -1
  20. data/docs/guides/jobs.md +13 -9
  21. data/docs/guides/middleware.md +134 -0
  22. data/docs/guides/navigation.md +6 -3
  23. data/docs/guides/networking/capybara.md +3 -1
  24. data/docs/guides/networking/custom_adapters.md +3 -3
  25. data/docs/guides/networking/ferrum.md +3 -1
  26. data/docs/guides/networking/http.md +4 -2
  27. data/docs/guides/networking/selenium.md +7 -3
  28. data/docs/guides/pages.md +4 -2
  29. data/docs/guides/routing.md +16 -8
  30. data/docs/guides/tasks.md +1 -1
  31. data/docs/guides/tutorial.md +73 -1
  32. data/docs/guides/user_agents.md +10 -10
  33. data/docs/index.md +1 -1
  34. data/lib/wayfarer/base.rb +6 -10
  35. data/lib/wayfarer/cli.rb +19 -1
  36. data/lib/wayfarer/gc.rb +0 -1
  37. data/lib/wayfarer/handler.rb +7 -5
  38. data/lib/wayfarer/logging.rb +3 -4
  39. data/lib/wayfarer/middleware/controller.rb +9 -8
  40. data/lib/wayfarer/middleware/dependency_graph.rb +181 -0
  41. data/lib/wayfarer/routing/matchers/query.rb +3 -2
  42. data/lib/wayfarer.rb +23 -2
  43. data/mise.toml +2 -0
  44. data/mkdocs.yml +1 -0
  45. data/rake/lint.rake +16 -0
  46. data/spec/spec_helpers.rb +1 -1
  47. data/spec/wayfarer/cli/routing_spec.rb +36 -6
  48. data/spec/wayfarer/integration/dependency_graph_spec.rb +111 -0
  49. data/spec/wayfarer/middleware/controller_spec.rb +34 -9
  50. data/spec/wayfarer/middleware/dependency_graph_spec.rb +367 -0
  51. data/spec/wayfarer/routing/integration_spec.rb +18 -0
  52. data/spec/wayfarer/routing/matchers/query_spec.rb +18 -0
  53. data/wayfarer.gemspec +1 -1
  54. metadata +11 -3
  55. data/.github/workflows/lint.yaml +0 -27
  56. data/.github/workflows/tests.yaml +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 102ad4ff568c6a84fb710cbb46f3ca4839ce6a319265d33953f5ed601038d95d
4
- data.tar.gz: 22f2f2460eb814a5534567cfc4222663d5819739df76e8c07bd0e5add4de15ec
3
+ metadata.gz: e46ffe5b40bd68f97cc1dc1c1777fc18f26ddf25e4b803efa99a6ca5ba8eb96e
4
+ data.tar.gz: 45359bcb3a30ac6d80052e05ecc35a78321c1b5d58fda6f6f2bf263375c9661d
5
5
  SHA512:
6
- metadata.gz: 7c3c4780264a54b3ffc3b885027affb00d041c7d0d828435987d71d19cdaba03d69a03dda645901abfa59ab8f5b4f702dd85722fec87efb36a08d304a903296b
7
- data.tar.gz: e05ab817b1125ebc8b644b79ec63e18fce3566ffdf4508e6409d5e8669a060b0bbd88e30a782db7f6abc9555198e1919fbb0feda4d9b75aba8f5b8823592c294
6
+ metadata.gz: 510c6839238f636cea908e27baed38b5f21999c56ef60486e1d8f23e006a205a25cd4e01f8ef017c52f35f91ae96fc198e582f8b517353128911cc7d355d76f0
7
+ data.tar.gz: a34c0c7a57688c4fc6442261391dcd8f55509711dbab4bd223303c376a8ca2a8f9e5e618cab472ef041c6cd3f1a660834a7d301b3d41624ea7cb79a42f19fa2e
@@ -0,0 +1,22 @@
1
+ name: Setup mise
2
+ description: Installs mise and tools
3
+ runs:
4
+ using: composite
5
+ steps:
6
+ - name: Install mise
7
+ shell: bash
8
+ run: |
9
+ sudo apt update -y && sudo apt install -y curl
10
+ sudo install -dm 755 /etc/apt/keyrings
11
+ curl -fSs https://mise.jdx.dev/gpg-key.pub | sudo tee /etc/apt/keyrings/mise-archive-keyring.asc 1> /dev/null
12
+ echo "deb [signed-by=/etc/apt/keyrings/mise-archive-keyring.asc] https://mise.jdx.dev/deb stable main" | sudo tee /etc/apt/sources.list.d/mise.list
13
+ sudo apt update -y
14
+ sudo apt install -y mise
15
+
16
+ - name: Add mise shims to PATH
17
+ shell: bash
18
+ run: echo "$HOME/.local/share/mise/shims" >> $GITHUB_PATH
19
+
20
+ - name: Install tools
21
+ shell: bash
22
+ run: mise install -y
@@ -0,0 +1,89 @@
1
+ name: Push
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - '*'
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: "pages"
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ lint:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Start services
24
+ run: docker compose up -d wayfarer
25
+
26
+ - name: RuboCop
27
+ run: docker compose run --rm --name test wayfarer bundle exec rake lint:rubocop
28
+
29
+ - name: Verify RubyGem platforms
30
+ if: success() || failure()
31
+ run: docker compose run --rm wayfarer bundle exec rake lint:platforms
32
+
33
+ - name: Setup mise
34
+ if: success() || failure()
35
+ uses: ./.github/actions/setup-mise
36
+
37
+ - name: Vale
38
+ if: success() || failure()
39
+ env:
40
+ VALE_STYLES_PATH: /tmp/value
41
+ run: |
42
+ vale sync
43
+ vale --glob="*.md" $(git diff --name-only origin/${{ github.base_ref }}...HEAD)
44
+
45
+ unit-tests:
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+
50
+ - name: Set up Docker Compose
51
+ run: docker compose up -d
52
+
53
+ - name: Run tests
54
+ run: docker compose exec -T -e CI=$CI wayfarer bundle exec rake test
55
+
56
+ - name: Verify gem version
57
+ run: docker compose exec -T -e CI=true wayfarer bundle exec rake release:guard_versions
58
+
59
+ check-links:
60
+ runs-on: ubuntu-latest
61
+ steps:
62
+ - uses: actions/checkout@v4
63
+
64
+ - name: Setup mise
65
+ uses: ./.github/actions/setup-mise
66
+
67
+ - name: Install dependencies
68
+ run: pip install -r requirements.txt
69
+
70
+ - name: Build site (Strict)
71
+ run: python -m mkdocs build --strict
72
+
73
+ - name: Upload artifact
74
+ if: github.ref_name == github.event.repository.default_branch
75
+ uses: actions/upload-pages-artifact@v3
76
+ with:
77
+ path: 'site'
78
+
79
+ deploy-docs:
80
+ needs: check-links
81
+ if: github.ref_name == github.event.repository.default_branch
82
+ environment:
83
+ name: github-pages
84
+ url: ${{ steps.deployment.outputs.page_url }}
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - name: Deploy to GitHub Pages
88
+ id: deployment
89
+ uses: actions/deploy-pages@v4
@@ -4,10 +4,10 @@ on: workflow_dispatch
4
4
 
5
5
  jobs:
6
6
  release:
7
- if: github.ref_name == 'master' || github.ref_name == 'develop'
7
+ if: github.ref_name == 'master'
8
8
  runs-on: ubuntu-latest
9
9
  steps:
10
- - uses: actions/checkout@v2
10
+ - uses: actions/checkout@v4
11
11
 
12
12
  - run: docker compose up -d
13
13
 
data/.gitignore CHANGED
@@ -9,3 +9,4 @@ yard
9
9
  .tool-versions
10
10
  *.tar.gz
11
11
  styles
12
+ .opencode
data/AGENTS.md ADDED
@@ -0,0 +1,265 @@
1
+ # Wayfarer -- AI Assistant Guide
2
+
3
+ ## Project Overview
4
+
5
+ Wayfarer is a Ruby gem (v0.5.0) for versatile web crawling, built on top of **ActiveJob**. It provides a middleware-based pipeline for fetching, parsing, deduplicating, and routing web pages, with support for plain HTTP, headless Chrome (Ferrum/Capybara), and Selenium browser automation.
6
+
7
+ - **Gem name:** `wayfarer`
8
+ - **Ruby version:** 3.4.4 (enforced via `mise.toml`)
9
+ - **License:** MIT
10
+
11
+ ---
12
+
13
+ ## Technology Stack
14
+
15
+ | Layer | Technology |
16
+ |---|---|
17
+ | Language | Ruby 3.4.4 |
18
+ | Job framework | ActiveJob 7.1+ |
19
+ | Deduplication/state | Redis 5.4+ |
20
+ | Plain HTTP | net-http-persistent 4.0+ |
21
+ | Headless Chrome (CDP) | Ferrum 0.17+ |
22
+ | Browser (Selenium) | selenium-webdriver 4.35+ |
23
+ | Browser wrapper | Capybara 3.4+ |
24
+ | HTML/XML parsing | Nokogiri 1.18+ |
25
+ | Meta-tag parsing | MetaInspector 5.16+ |
26
+ | URL routing/matching | Mustermann 3.0+ |
27
+ | URL normalization | Addressable 2.8+ |
28
+ | Autoloading | Zeitwerk 2.7+ |
29
+ | CLI | Thor 1.0+ |
30
+ | Connection pooling | connection_pool 2.5+ |
31
+ | Testing | RSpec 3.13+ |
32
+ | Linting | RuboCop 1.80+ |
33
+ | Documentation | MkDocs (Material theme) + YARD |
34
+
35
+ ---
36
+
37
+ ## Development Workflow
38
+
39
+ ### Initial Setup
40
+
41
+ ```bash
42
+ mise install # Install Ruby 3.4.4, Python 3.13, vale
43
+ bundle install
44
+ ```
45
+
46
+ ### Docker (recommended for CI-equivalent runs)
47
+
48
+ ```bash
49
+ docker compose up -d
50
+ docker compose exec -T -e CI=true wayfarer bundle exec rake test
51
+ docker compose run --rm wayfarer bundle exec rake lint:rubocop
52
+ ```
53
+
54
+ ### Interactive Console
55
+
56
+ ```bash
57
+ bundle exec rake console # Pry REPL with wayfarer loaded
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Running Tests
63
+
64
+ Tests use **RSpec** with tag-based filtering. Always run via Rake, not `rspec` directly.
65
+
66
+ ```bash
67
+ bundle exec rake test # All tests
68
+ bundle exec rake test:isolated # No browser/Redis -- fastest
69
+ bundle exec rake test:integration # Redis + CLI
70
+ bundle exec rake test:selenium # Selenium browser
71
+ bundle exec rake test:ferrum # Ferrum (Chrome CDP)
72
+ bundle exec rake test:cli # CLI tests
73
+ ```
74
+
75
+ **RSpec tags:** `:selenium`, `:ferrum`, `:cli`, `:redis`. Untagged tests run in `test:isolated`.
76
+
77
+ A Sinatra test server starts automatically on port 9876 before the suite. FactoryBot factories are in `spec/factories/`. The shared context `"with Redis"` is auto-included for `:redis`-tagged examples.
78
+
79
+ ---
80
+
81
+ ## Linting
82
+
83
+ ```bash
84
+ bundle exec rake lint:rubocop
85
+ ```
86
+
87
+ Key RuboCop settings: 120-char line limit, double-quoted strings, outdented access modifiers, max 20-line methods, AbcSize <= 30, RSpec max 5 expectations/example and max 5 nested groups.
88
+
89
+ ---
90
+
91
+ ## Common Ruby Patterns
92
+
93
+ ### ActiveSupport::Concern for Mixins
94
+
95
+ The codebase uses `extend ActiveSupport::Concern` throughout to structure reusable modules with `included` and `class_methods` blocks. The `included` block runs on inclusion; `class_methods` defines class-level behavior without verbose `def self.included` boilerplate.
96
+
97
+ ```ruby
98
+ module Base
99
+ extend ActiveSupport::Concern
100
+
101
+ included do
102
+ include Wayfarer::Middleware::Controller
103
+ use Wayfarer::Middleware::Redis
104
+ use Wayfarer::Middleware::UriParser
105
+ # ...
106
+ end
107
+
108
+ class_methods do
109
+ def crawl(url, batch: SecureRandom.uuid)
110
+ Task.new(url, batch).tap { |task| perform_later(task) }
111
+ end
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Middleware Chain via Recursive Lambda
117
+
118
+ `Middleware::Chain` composes middleware as a recursive lambda. Each middleware receives a block representing the rest of the chain, and calls `yield` to continue or returns early to halt.
119
+
120
+ ```ruby
121
+ def call(task)
122
+ traverse = lambda do |i|
123
+ if middlewares[i]
124
+ middlewares[i].call(task) { traverse.call(i + 1) }
125
+ elsif block_given?
126
+ yield
127
+ end
128
+ end
129
+ traverse.call(0)
130
+ end
131
+ ```
132
+
133
+ ### Strategy Pattern via Module Inclusion
134
+
135
+ `Networking::Strategy` defines the abstract interface (raising `NotImplementedError`) and shared helpers (`success`, `redirect`). Concrete agents (`HTTP`, `Ferrum`, `Selenium`, `Capybara`) include the mixin and override the required methods.
136
+
137
+ ```ruby
138
+ module Strategy
139
+ extend ActiveSupport::Concern
140
+
141
+ def fetch(instance, url) = navigate(instance, url).then { live(instance) }
142
+ def navigate(_instance, _url) = raise NotImplementedError
143
+ def create = raise NotImplementedError
144
+ def destroy(_instance); end
145
+
146
+ private
147
+ def success(...) = Networking::Result::Success.new(Page.new(...))
148
+ def redirect(...) = Networking::Result::Redirect.new(...)
149
+ end
150
+ ```
151
+
152
+ ### Fluent Routing DSL
153
+
154
+ `Routing::DSL` provides chainable builder methods. Each method calls `child_route`, which creates a child `Route` and appends it to `children`. Inline keyword arguments and blocks are both supported, enabling two equivalent syntaxes:
155
+
156
+ ```ruby
157
+ # Inline
158
+ route.host("example.com", path: "/articles/:id", to: :article)
159
+
160
+ # Block
161
+ route.host("example.com") do
162
+ path "/articles/:id", to: :article
163
+ end
164
+ ```
165
+
166
+ The method signature uses `**` and `&` forwarding to keep DSL methods concise. Last `.to()` call wins when routes conflict.
167
+
168
+ ### Visitor Pattern for Tree Traversal
169
+
170
+ Routes form a tree searched depth-first by `Routing::PathFinder`. Routes call `accept(visitor)`, which calls `enter`, `visit`, and `leave` on the visitor. This separates traversal logic from matching logic while allowing the visitor to accumulate mutable state (params, matched actions).
171
+
172
+ ```ruby
173
+ # In Route
174
+ def accept(visitor)
175
+ visitor.enter(self)
176
+ return visitor.leave unless visitor.visit(self)
177
+ children.each { |child| child.accept(visitor) }
178
+ visitor.leave
179
+ end
180
+ ```
181
+
182
+ ### Dynamic Method Generation via Module Subclasses
183
+
184
+ `Logging.emit` returns an anonymous `Module` subclass whose `included` hook uses `define_method` to inject a `log` method. This lets each middleware declare its log messages declaratively at the class level.
185
+
186
+ ```ruby
187
+ class Router
188
+ include Wayfarer::Logging.emit(
189
+ mismatch: [:info, "No matching route"],
190
+ match: [:info, "Routing to %<action>s"],
191
+ )
192
+ end
193
+ ```
194
+
195
+ ### Singleton + Connection Pooling
196
+
197
+ `Networking::Pool` is a `Singleton` wrapping `ConnectionPool`. Cleanup is registered via `at_exit`. A `class_attribute :finalizer` lambda allows customizing shutdown behavior without subclassing. `ConnectionPool::TimeoutError` is wrapped into the gem's own error class at the boundary.
198
+
199
+ ### Configuration Syntax
200
+
201
+ Use bracket syntax `Wayfarer.config[:key][:subkey]` instead of `dig` for predictable configuration access.
202
+
203
+ ### Value Objects with Declarative Stringify
204
+
205
+ Value objects (`Task`, `Page`) include lightweight mixins like `Stringify` and `KV`. `stringify :url, :batch` registers which attributes appear in `#to_s`/`#inspect`. Custom `ActiveJob::Serializers::ObjectSerializer` subclasses handle serialization to/from JSON.
206
+
207
+ ### Inline Error Classes
208
+
209
+ Lightweight custom errors are defined inline at module scope:
210
+
211
+ ```ruby
212
+ UserAgentTimeoutError = Class.new(StandardError)
213
+ ```
214
+
215
+ Rescue lists are built dynamically from configuration:
216
+
217
+ ```ruby
218
+ rescue *strategy.class.renew_on, *Wayfarer.config[:network][:renew_on] => e
219
+ renew
220
+ end
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Documentation
226
+
227
+ ### Writing Style
228
+
229
+ Documentation in `docs/` must strictly mimic the voice, tone, and typography of existing guides. Key rules:
230
+
231
+ - **Address the reader directly** using second person ("you can", "use the")
232
+ - **Use contractions** ("isn't", "doesn't", "it's") -- Vale enforces `Google.Contractions`
233
+ - **Prefer active voice** over passive voice ("the graph compiles" not "the chain is compiled")
234
+ - **Use ASCII characters** -- write `word--word` not Unicode em dashes. Avoid Unicode dashes, quotes, and other non-ASCII punctuation unless explicitly required.
235
+ - **Headings use sentence-style capitalization** -- `## Adding middleware` not `## Adding Middleware`
236
+ - **Keep paragraphs short** -- one concept per paragraph, 2-3 sentences max
237
+ - **Code references use backticks** -- `` `use` ``, `` `dependency_graph.remove` ``
238
+ - **Cross-link related guides** -- `[tasks](tasks.md)`, `[handlers](handlers.md)`
239
+ - **Use mkdocs-material admonitions** for callouts -- `!!! note`, `!!! warning`, `!!! danger`
240
+
241
+ ### Linting with Vale
242
+
243
+ Documentation is linted with [Vale](https://vale.sh) using the Google style guide. Configuration lives in `.vale.ini` and domain vocabulary in `styles/config/vocabularies/Wayfarer/accept.txt`.
244
+
245
+ ```bash
246
+ vale sync # Download style packages (run once)
247
+ vale docs/guides/middleware.md # Lint a specific file
248
+ vale docs/ # Lint all documentation
249
+ ```
250
+
251
+ Fix all errors and warnings. Suggestions (passive voice, acronym expansion) are acceptable when they match the existing documentation style.
252
+
253
+ ---
254
+
255
+ ## Key Conventions
256
+
257
+ - **All files:** `# frozen_string_literal: true` at the top
258
+ - **Strings:** Always double-quoted
259
+ - **Modules vs Classes:** Namespaced under `Wayfarer::*`; use `ActiveSupport::Concern` for mixins
260
+ - **Autoloading:** Zeitwerk with custom inflections -- file names must match constant names after inflection (`cli` -> `CLI`, `dsl` -> `DSL`, `http` -> `HTTP`, `uri` -> `URI`, `url` -> `URL`, etc.)
261
+ - **Numeric comparisons:** Use `== 0` not `.zero?`
262
+ - **No module documentation cop** -- use YARD `@param`/`@return`/`@yield`/`@example`/`@see` tags to document complex logic, public APIs, and overridden template methods instead. Use comments to explain *why* something is done.
263
+ - **Specs:** Tag browser tests (`:selenium`, `:ferrum`), Redis tests (`:redis`), CLI tests (`:cli`); all others run isolated
264
+ - **Do not skip RuboCop** without an inline disable comment with justification
265
+ - **Version consistency:** `VERSION::STRING` in `lib/wayfarer.rb` must match `wayfarer.gemspec`; CI enforces via `rake release:guard_versions`
data/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ AGENTS.md
data/Dockerfile CHANGED
@@ -2,6 +2,7 @@ FROM ruby:3.4.4-alpine
2
2
  RUN apk add --no-cache build-base git yaml-dev zlib-dev
3
3
  RUN git config --global --add safe.directory /opt/app
4
4
  WORKDIR /opt/app
5
+ ENV BUNDLE_FROZEN=true
5
6
  COPY Gemfile Gemfile.lock *.gemspec ./
6
7
  RUN bundle install
7
8
  COPY . .
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- wayfarer (0.4.9)
4
+ wayfarer (0.5.0)
5
5
  activejob (>= 7.1)
6
6
  addressable (~> 2.8)
7
7
  capybara (~> 3.4)
@@ -98,6 +98,7 @@ GEM
98
98
  concurrent-ruby (~> 1.1)
99
99
  webrick (~> 1.7)
100
100
  websocket-driver (~> 0.7)
101
+ ffi (1.17.2-arm64-darwin)
101
102
  ffi (1.17.2-x86_64-darwin)
102
103
  ffi (1.17.2-x86_64-linux-musl)
103
104
  globalid (1.2.1)
@@ -148,6 +149,8 @@ GEM
148
149
  net-http-persistent (4.0.6)
149
150
  connection_pool (~> 2.2, >= 2.2.4)
150
151
  nio4r (2.7.4)
152
+ nokogiri (1.18.9-arm64-darwin)
153
+ racc (~> 1.4)
151
154
  nokogiri (1.18.9-x86_64-darwin)
152
155
  racc (~> 1.4)
153
156
  nokogiri (1.18.9-x86_64-linux-musl)
@@ -302,6 +305,7 @@ GEM
302
305
  zlib (3.2.1)
303
306
 
304
307
  PLATFORMS
308
+ arm64-darwin-25
305
309
  x86_64-darwin-24
306
310
  x86_64-linux-musl
307
311
 
@@ -4,7 +4,9 @@
4
4
  # Create a record in an external database and store the hostname
5
5
  record = Database::Row.create(hostname: "example.com")
6
6
 
7
- class DummyJob < Wayfarer::Base
7
+ class DummyJob < ActiveJob::Base
8
+ include Wayfarer::Base
9
+
8
10
  route do |hostname|
9
11
  host hostname, to: :index
10
12
  end
@@ -8,7 +8,9 @@ iframe, clicked, and makes the live page behind the screen accessible to
8
8
  ```ruby
9
9
  Wayfarer.config[:network][:agent] = :ferrum
10
10
 
11
- class DummyJob < Wayfarer::Base
11
+ class DummyJob < ActiveJob::Base
12
+ include Wayfarer::Base
13
+
12
14
  route.to :index, host: "example.com"
13
15
 
14
16
  before_action if: :consent_required? do
@@ -5,7 +5,9 @@ Executing JavaScript requires automating a browser.
5
5
  === "Ferrum"
6
6
 
7
7
  ```ruby
8
- class DummyJob < Wayfarer::Base
8
+ class DummyJob < ActiveJob::Base
9
+ include Wayfarer::Base
10
+
9
11
  route.to :index
10
12
 
11
13
  def index
@@ -17,7 +19,9 @@ Executing JavaScript requires automating a browser.
17
19
  === "Selenium"
18
20
 
19
21
  ```ruby
20
- class DummyJob < Wayfarer::Base
22
+ class DummyJob < ActiveJob::Base
23
+ include Wayfarer::Base
24
+
21
25
  route.to :index
22
26
 
23
27
  def index
@@ -30,7 +34,9 @@ Executing JavaScript requires automating a browser.
30
34
  === "Capybara"
31
35
 
32
36
  ```ruby
33
- class DummyJob < Wayfarer::Base
37
+ class DummyJob < ActiveJob::Base
38
+ include Wayfarer::Base
39
+
34
40
  route.to :index
35
41
 
36
42
  def index
@@ -3,7 +3,9 @@
3
3
  === "Ferrum"
4
4
 
5
5
  ```ruby
6
- class DummyJob < Wayfarer::Base
6
+ class DummyJob < ActiveJob::Base
7
+ include Wayfarer::Base
8
+
7
9
  route.to :index
8
10
 
9
11
  def index
@@ -17,7 +19,9 @@
17
19
  === "Selenium"
18
20
 
19
21
  ```ruby
20
- class DummyJob < Wayfarer::Base
22
+ class DummyJob < ActiveJob::Base
23
+ include Wayfarer::Base
24
+
21
25
  route.to :index
22
26
 
23
27
  def index
@@ -31,7 +35,9 @@
31
35
  === "Capybara"
32
36
 
33
37
  ```ruby
34
- class DummyJob < Wayfarer::Base
38
+ class DummyJob < ActiveJob::Base
39
+ include Wayfarer::Base
40
+
35
41
  route.to :index
36
42
 
37
43
  def index
@@ -5,7 +5,9 @@ See: [Nokogiri: Searching an HTML / XML Document](https://nokogiri.org/tutorials
5
5
  === "Nokogiri"
6
6
 
7
7
  ```ruby
8
- class DummyJob < Wayfarer::Base
8
+ class DummyJob < ActiveJob::Base
9
+ include Wayfarer::Base
10
+
9
11
  route.to :index
10
12
 
11
13
  def index
@@ -18,7 +20,9 @@ See: [Nokogiri: Searching an HTML / XML Document](https://nokogiri.org/tutorials
18
20
  === "Ferrum"
19
21
 
20
22
  ```ruby
21
- class DummyJob < Wayfarer::Base
23
+ class DummyJob < ActiveJob::Base
24
+ include Wayfarer::Base
25
+
22
26
  route.to :index
23
27
 
24
28
  def index
@@ -31,7 +35,9 @@ See: [Nokogiri: Searching an HTML / XML Document](https://nokogiri.org/tutorials
31
35
  === "Selenium"
32
36
 
33
37
  ```ruby
34
- class DummyJob < Wayfarer::Base
38
+ class DummyJob < ActiveJob::Base
39
+ include Wayfarer::Base
40
+
35
41
  route.to :index
36
42
 
37
43
  def index
@@ -5,7 +5,9 @@ Taking screenshots requires automating a browser.
5
5
  === "Ferrum"
6
6
 
7
7
  ```ruby
8
- class DummyJob < Wayfarer::Base
8
+ class DummyJob < ActiveJob::Base
9
+ include Wayfarer::Base
10
+
9
11
  route.to :index
10
12
 
11
13
  def index
@@ -17,7 +19,9 @@ Taking screenshots requires automating a browser.
17
19
  === "Selenium"
18
20
 
19
21
  ```ruby
20
- class DummyJob < Wayfarer::Base
22
+ class DummyJob < ActiveJob::Base
23
+ include Wayfarer::Base
24
+
21
25
  route.to :index
22
26
 
23
27
  def index
data/docs/guides/cli.md CHANGED
@@ -8,7 +8,7 @@ The command-line interface to Wayfarer.
8
8
  wayfarer [OPTIONS] [perform|enqueue|execute|route|tree]
9
9
  ```
10
10
 
11
- See [Configuration](../reference/cli) for the respected environment variables.
11
+ See [Configuration](configuration.md) for the respected environment variables.
12
12
 
13
13
  ---
14
14
 
@@ -1,6 +1,6 @@
1
1
  # Debugging
2
2
 
3
- [Wayfarer's CLI](/reference/cli/) has two sub-commands that come in handy when
3
+ [Wayfarer's CLI](cli.md) has two sub-commands that come in handy when
4
4
  diagnosing problems in the development workflow.
5
5
 
6
6
  ## Routing a URL from the shell