parklife 0.6.1 → 0.8.0.beta1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c94649aadc5cc8fe79a9215950b461adfdf658ec56c396c42d3e69e9e6082d3
4
- data.tar.gz: 54c2b0b8c4f8a8a5149d10b5f649d0009e9c9f32201d85acc8960bb595ea1e9c
3
+ metadata.gz: 5fee28b7e4a5dd221a56dc23db922173062e06b22888b2daf3a8bc05136525e2
4
+ data.tar.gz: '02408d7f687ea75db42814178c9ae168595f43d16e287ce30e558baa0abb5d9a'
5
5
  SHA512:
6
- metadata.gz: 3e77cf82affdd32b75f747c2a9a4bc7aaf8df14d0b847470b241b1fb34e3f98b8aea13fdb55430caff5a420e28a5ba0dc6e80d32505e315428317fb42a5fd9d6
7
- data.tar.gz: d80856454fb213de0ef217f18518d42bed3f0a4e57b870f22d2e8eaa72b1cec45123e0c84b38f875b6cd85a62f543381437c8e8200cff87a31f3b2683671f94e
6
+ metadata.gz: c6d913ec8bb296a0ad792b75dd4460a65cb94bf07a47d02db3f0db5c4ec5070de63033a8c4333eda08dfa1655c743f67bc615eef89ee5804d08502df75524ddb
7
+ data.tar.gz: 10fd0665002537622e0229dd0c366cd3ff32ad6234f18a0da80a8fda4cfc64c296d106346193e3ec1ef4aad1c0bd66eff17373a0a402dcffa33842a19d459ec5
@@ -18,21 +18,6 @@ jobs:
18
18
  - run: test -f build/index.html
19
19
  working-directory: examples/rack
20
20
 
21
- rails:
22
- runs-on: ubuntu-latest
23
- name: Rails example
24
- steps:
25
- - uses: actions/checkout@v3
26
- - uses: ruby/setup-ruby@v1
27
- with:
28
- bundler-cache: true
29
- ruby-version: '3.2'
30
- working-directory: examples/rails
31
- - run: bin/static-build
32
- working-directory: examples/rails
33
- - run: test -f build/index.html
34
- working-directory: examples/rails
35
-
36
21
  roda:
37
22
  runs-on: ubuntu-latest
38
23
  name: Roda example
@@ -56,9 +41,9 @@ jobs:
56
41
  - uses: ruby/setup-ruby@v1
57
42
  with:
58
43
  bundler-cache: true
59
- ruby-version: '2.7'
44
+ ruby-version: '3.4'
60
45
  working-directory: examples/sinatra
61
- - run: bundle exec parklife build
46
+ - run: bin/static-build
62
47
  working-directory: examples/sinatra
63
48
  - run: test -f build/index.html
64
49
  working-directory: examples/sinatra
@@ -6,6 +6,7 @@ jobs:
6
6
  rspec:
7
7
  runs-on: ubuntu-latest
8
8
  strategy:
9
+ fail-fast: false
9
10
  matrix:
10
11
  ruby:
11
12
  - '2.7'
@@ -13,22 +14,50 @@ jobs:
13
14
  - '3.1'
14
15
  - '3.2'
15
16
  - '3.3'
16
- name: Ruby ${{ matrix.ruby }} RSpec
17
+ - '3.4'
18
+ name: RSpec (Ruby ${{ matrix.ruby }})
17
19
  steps:
18
- - uses: actions/checkout@v3
20
+ - uses: actions/checkout@v4
19
21
  - uses: ruby/setup-ruby@v1
20
22
  with:
21
23
  bundler-cache: true
22
24
  ruby-version: ${{ matrix.ruby }}
23
- - run: bundle exec rspec
25
+ - run: bundle exec rspec --exclude-pattern "spec/**/*sinatra*"
24
26
 
25
27
  rubocop:
26
28
  runs-on: ubuntu-latest
27
29
  name: RuboCop
28
30
  steps:
29
- - uses: actions/checkout@v3
31
+ - uses: actions/checkout@v4
30
32
  - uses: ruby/setup-ruby@v1
31
33
  with:
32
34
  bundler-cache: true
33
35
  ruby-version: '3.2'
34
36
  - run: bundle exec rubocop
37
+
38
+ sinatra:
39
+ runs-on: ubuntu-latest
40
+ strategy:
41
+ fail-fast: false
42
+ matrix:
43
+ ruby:
44
+ - '2.7'
45
+ - '3.0'
46
+ - '3.1'
47
+ - '3.2'
48
+ - '3.3'
49
+ - '3.4'
50
+ sinatra:
51
+ - '3.x'
52
+ - '4.0'
53
+ - '4.1'
54
+ env:
55
+ BUNDLE_GEMFILE: gemfiles/sinatra_${{ matrix.sinatra }}.gemfile
56
+ name: Ruby ${{ matrix.ruby }} / Sinatra ${{ matrix.sinatra }}
57
+ steps:
58
+ - uses: actions/checkout@v4
59
+ - uses: ruby/setup-ruby@v1
60
+ with:
61
+ bundler-cache: true
62
+ ruby-version: ${{ matrix.ruby }}
63
+ - run: bundle exec rspec --pattern "spec/**/*sinatra*"
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  /_yardoc/
5
5
  /coverage/
6
6
  /doc/
7
+ /gemfiles/*.gemfile.lock
7
8
  /pkg/
8
9
  /spec/examples.txt
9
10
  /spec/reports/
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@ AllCops:
2
2
  NewCops: enable
3
3
  Exclude:
4
4
  - examples/**/*
5
+ - gemfiles/*
5
6
  - vendor/**/*
6
7
  SuggestExtensions: false
7
8
  TargetRubyVersion: 2.5
data/Appraisals ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise 'sinatra_3.x' do
4
+ gem 'sinatra', '~> 3.0'
5
+ end
6
+
7
+ appraise 'sinatra_4.0' do
8
+ gem 'sinatra', '~> 4.0.0'
9
+ end
10
+
11
+ appraise 'sinatra_4.1' do
12
+ gem 'sinatra', '~> 4.1.0'
13
+ end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## Unreleased
2
+
3
+ ## Version 0.8.0.beta1 - 2025-08-10
4
+
5
+ - Remove out-of-the-box Rails integration in preparation for a separate gem. <https://github.com/benpickles/parklife/pull/131>
6
+ - Include the port when automatically assigning the base from Rails `default_url_options`. <https://github.com/benpickles/parklife/pull/130>
7
+ - Improve the HTTP redirect error message to include the request's full URL and redirect location. <https://github.com/benpickles/parklife/pull/129>
8
+ - Empty the build directory instead of deleting it. <https://github.com/benpickles/parklife/pull/125>
9
+ - Resurrect build callbacks (`before_build`/`after_build`). <https://github.com/benpickles/parklife/pull/124>
10
+
11
+ ## Version 0.7.0 - 2025-02-03
12
+
13
+ - Add support for Rails 8 and add test infrastructure to ensure future compatibility with Rails 7.0, 7.1, and 8.0. <https://github.com/benpickles/parklife/pull/115>, <https://github.com/benpickles/parklife/pull/117>, <https://github.com/benpickles/parklife/pull/121>
14
+ - Improve out-of-the-box compatibility with Rails by reading `default_url_options`, `relative_url_root`, and `force_ssl` settings on boot and applying them to Parklife's `config.base` (`force_ssl` has been set to `true` in `production.rb` since Rails 7.1). <https://github.com/benpickles/parklife/pull/118>
15
+ - Improve out-of-the-box compatibility with Sinatra 4.1 which has host authorisation middleware enabled by default in development mode and would otherwise respond to Parklife requests with a 403 status. Additionally the generated Sinatra production build script now sets the environment variable `APP_ENV=production` to enable production mode. <https://github.com/benpickles/parklife/pull/123>, <https://github.com/benpickles/parklife/pull/122>
16
+ - When discovering HTML links ignore `<a>` elements without an `href`. <https://github.com/benpickles/parklife/pull/107>
17
+
1
18
  ## Version 0.6.1 - 2024-08-23
2
19
 
3
20
  - Don't error when the public directory doesn't exist <https://github.com/benpickles/parklife/pull/105>
data/Gemfile CHANGED
@@ -7,8 +7,8 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
7
7
  # Specify your gem's dependencies in parklife.gemspec
8
8
  gemspec
9
9
 
10
+ gem 'appraisal'
10
11
  gem 'bundler'
11
- gem 'rails'
12
12
  gem 'rake'
13
13
  gem 'rspec'
14
14
  gem 'rubocop'
data/README.md CHANGED
@@ -110,7 +110,7 @@ Parklife.application.config.nested_index = false
110
110
 
111
111
  ### Changing the build output directory
112
112
 
113
- The build directory shouldn't exist and is destroyed and recreated before each build. Defaults to `build`.
113
+ The build directory's contents are removed before each build. Defaults to `build`.
114
114
 
115
115
  ```ruby
116
116
  Parklife.application.config.build_dir = 'my/build/dir'
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "bundler"
7
+ gem "rake"
8
+ gem "rspec"
9
+ gem "rubocop"
10
+ gem "sinatra", "~> 3.0"
11
+
12
+ gemspec path: "../"
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "bundler"
7
+ gem "rake"
8
+ gem "rspec"
9
+ gem "rubocop"
10
+ gem "sinatra", "~> 4.0.0"
11
+
12
+ gemspec path: "../"
@@ -0,0 +1,12 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "bundler"
7
+ gem "rake"
8
+ gem "rspec"
9
+ gem "rubocop"
10
+ gem "sinatra", "~> 4.1.0"
11
+
12
+ gemspec path: "../"
@@ -13,16 +13,37 @@ module Parklife
13
13
  def initialize
14
14
  @config = Config.new
15
15
  @route_set = RouteSet.new
16
+ @after_build_callbacks = []
17
+ @before_build_callbacks = []
18
+ end
19
+
20
+ def after_build(&block)
21
+ @after_build_callbacks << block
22
+ end
23
+
24
+ def before_build(&block)
25
+ @before_build_callbacks << block
16
26
  end
17
27
 
18
28
  def build
19
29
  raise BuildDirNotDefinedError if config.build_dir.nil?
20
30
  raise RackAppNotDefinedError if config.app.nil?
21
31
 
22
- FileUtils.rm_rf(config.build_dir)
23
- Dir.mkdir(config.build_dir)
32
+ if Dir.exist?(config.build_dir)
33
+ FileUtils.rm_rf(Pathname.new(config.build_dir).children)
34
+ else
35
+ Dir.mkdir(config.build_dir)
36
+ end
37
+
38
+ @before_build_callbacks.each do |callback|
39
+ callback.call(self)
40
+ end
24
41
 
25
42
  crawler.start
43
+
44
+ @after_build_callbacks.each do |callback|
45
+ callback.call(self)
46
+ end
26
47
  end
27
48
 
28
49
  def configure
@@ -18,6 +18,10 @@ module Parklife
18
18
  session.get(path, nil, env)
19
19
  end
20
20
 
21
+ def uri_for(path)
22
+ base.dup.tap { |uri| uri.path = path }
23
+ end
24
+
21
25
  private
22
26
  def set_env
23
27
  @env = {
data/lib/parklife/cli.rb CHANGED
@@ -26,6 +26,7 @@ module Parklife
26
26
  ['nested_index', application.config.nested_index],
27
27
  ['on_404', application.config.on_404.inspect],
28
28
  ['parklife/rails', defined?(::Parklife::Railtie) ? 'enabled' : '-'],
29
+ ['parklife/sinatra', defined?(::Parklife::Sinatra) ? 'enabled' : '-'],
29
30
  ['reporter', reporter == $stdout ? '$stdout' : reporter],
30
31
  ])
31
32
  end
@@ -51,6 +51,12 @@ module Parklife
51
51
  case response.status
52
52
  when 200
53
53
  # Continue processing the route.
54
+ when 301, 302
55
+ raise HTTPRedirectError.new(
56
+ response.status,
57
+ browser.uri_for(route.path),
58
+ response.headers['location']
59
+ )
54
60
  when 404
55
61
  case config.on_404
56
62
  when :warn
@@ -11,6 +11,12 @@ module Parklife
11
11
  end
12
12
  end
13
13
 
14
+ class HTTPRedirectError < Error
15
+ def initialize(status, from, to)
16
+ super %Q(#{status} redirect from "#{from}" to "#{to}")
17
+ end
18
+ end
19
+
14
20
  class ParkfileLoadError < Error
15
21
  def initialize(path)
16
22
  super %Q(Cannot load Parkfile "#{path}")
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinatra/base'
4
+
5
+ module Parklife
6
+ module Sinatra
7
+ def self.registered(app)
8
+ # Disable Rack::Protection::HostAuthorization middleware so that fetching
9
+ # a page with Parklife works in development. It's safe to do here because
10
+ # it will only be executed when this file is explicitly required in a
11
+ # Parkfile and not in general when the app is running in a web server.
12
+ if app.settings.respond_to?(:host_authorization)
13
+ app.set(:host_authorization, permitted_hosts: [])
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Sinatra.register Parklife::Sinatra
@@ -2,7 +2,11 @@
2
2
  require 'parklife/rails'
3
3
  require_relative 'config/environment'
4
4
  <% else -%>
5
- # Assuming your Rack app lives in ./app.rb:
5
+ <% if options[:sinatra] -%>
6
+ require 'parklife/sinatra'
7
+
8
+ <% end -%>
9
+ # Assuming your <%= options[:sinatra] ? 'Sinatra' : 'Rack' %> app lives in ./app.rb:
6
10
  require_relative 'app'
7
11
  <% end -%>
8
12
 
@@ -11,8 +15,9 @@ Parklife.application.configure do |config|
11
15
  # For a Sinatra "classic" app:
12
16
  config.app = Sinatra::Application
13
17
  #
14
- # Or for Sinatra modular style:
18
+ # For a modular-style Sinatra app the Parklife extension must be explicitly registered:
15
19
  # config.app = App
20
+ # App.register Parklife::Sinatra
16
21
 
17
22
  <% elsif !options[:rails] -%>
18
23
  config.app = App
@@ -15,11 +15,11 @@ jobs:
15
15
  build:
16
16
  runs-on: ubuntu-latest
17
17
  steps:
18
- - uses: actions/checkout@v3
18
+ - uses: actions/checkout@v4
19
19
  - uses: ruby/setup-ruby@v1
20
20
  with:
21
21
  bundler-cache: true
22
- - uses: actions/configure-pages@v3
22
+ - uses: actions/configure-pages@v5
23
23
  id: pages
24
24
 
25
25
  # Build with Parklife and use its GitHub Pages URL (either its custom
@@ -27,7 +27,7 @@ jobs:
27
27
  - run: bin/static-build --base "${{ steps.pages.outputs.base_url }}"
28
28
 
29
29
  - name: Upload artifact
30
- uses: actions/upload-pages-artifact@v1
30
+ uses: actions/upload-pages-artifact@v3
31
31
  if: github.ref == 'refs/heads/main' # Only upload on main branch.
32
32
  with:
33
33
  path: build/
@@ -45,4 +45,4 @@ jobs:
45
45
  steps:
46
46
  - name: Deploy to GitHub Pages
47
47
  id: deployment
48
- uses: actions/deploy-pages@v1
48
+ uses: actions/deploy-pages@v4
@@ -3,8 +3,7 @@
3
3
  set -eu
4
4
 
5
5
  <% if options[:rails] -%>
6
- # You probably need to run the app in production mode to ensure the correct
7
- # asset URLs are referenced.
6
+ # Run the app in production mode to ensure correct asset URLs are generated etc.
8
7
  export RAILS_ENV=production
9
8
  export SECRET_KEY_BASE=dummy
10
9
 
@@ -17,6 +16,10 @@ export SECRET_KEY_BASE=dummy
17
16
  # missing assets in production.
18
17
  bundle exec rails assets:precompile
19
18
 
19
+ <% elsif options[:sinatra] -%>
20
+ # Run the app in production mode.
21
+ export APP_ENV=production
22
+
20
23
  <% end -%>
21
24
  # Build with Parklife - and forward arguments sent to this script.
22
25
  bundle exec parklife build "$@"
@@ -39,7 +39,7 @@ module Parklife
39
39
 
40
40
  def scan_for_links(html)
41
41
  doc = Nokogiri::HTML.parse(html)
42
- doc.css('a').each do |a|
42
+ doc.css('a[href]').each do |a|
43
43
  uri = URI.parse(a[:href])
44
44
 
45
45
  # Don't visit a URL that belongs to a different domain - for now this is
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parklife
4
- VERSION = '0.6.1'
4
+ VERSION = '0.8.0.beta1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parklife
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.8.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Pickles
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-08-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: nokogiri
@@ -52,7 +51,6 @@ dependencies:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
53
  version: '0'
55
- description:
56
54
  email:
57
55
  - spideryoung@gmail.com
58
56
  executables:
@@ -65,6 +63,7 @@ files:
65
63
  - ".gitignore"
66
64
  - ".rspec"
67
65
  - ".rubocop.yml"
66
+ - Appraisals
68
67
  - CHANGELOG.md
69
68
  - CODE_OF_CONDUCT.md
70
69
  - Gemfile
@@ -74,6 +73,9 @@ files:
74
73
  - bin/console
75
74
  - bin/setup
76
75
  - exe/parklife
76
+ - gemfiles/sinatra_3.x.gemfile
77
+ - gemfiles/sinatra_4.0.gemfile
78
+ - gemfiles/sinatra_4.1.gemfile
77
79
  - lib/parklife.rb
78
80
  - lib/parklife/application.rb
79
81
  - lib/parklife/browser.rb
@@ -81,9 +83,9 @@ files:
81
83
  - lib/parklife/config.rb
82
84
  - lib/parklife/crawler.rb
83
85
  - lib/parklife/errors.rb
84
- - lib/parklife/rails.rb
85
86
  - lib/parklife/route.rb
86
87
  - lib/parklife/route_set.rb
88
+ - lib/parklife/sinatra.rb
87
89
  - lib/parklife/templates/Parkfile.erb
88
90
  - lib/parklife/templates/github_pages.yml
89
91
  - lib/parklife/templates/static_build.erb
@@ -98,7 +100,6 @@ metadata:
98
100
  homepage_uri: https://parklife.dev
99
101
  rubygems_mfa_required: 'true'
100
102
  source_code_uri: https://github.com/benpickles/parklife
101
- post_install_message:
102
103
  rdoc_options: []
103
104
  require_paths:
104
105
  - lib
@@ -113,8 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubygems_version: 3.5.17
117
- signing_key:
117
+ rubygems_version: 3.7.1
118
118
  specification_version: 4
119
119
  summary: Convert a Rack app into a static HTML site.
120
120
  test_files: []
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails'
4
-
5
- module Parklife
6
- module RailsConfigRefinements
7
- # When setting Parklife's base also configure the Rails app's
8
- # default_url_options and relative_url_root to match.
9
- def base=(value)
10
- super.tap { |uri|
11
- Rails.application.default_url_options = {
12
- host: Utils.host_with_port(uri),
13
- protocol: uri.scheme,
14
- }
15
-
16
- base_path = !uri.path.empty? && uri.path != '/' ? uri.path : nil
17
- ActionController::Base.relative_url_root = base_path
18
- }
19
- end
20
- end
21
-
22
- class Railtie < Rails::Railtie
23
- initializer 'parklife.disable_host_authorization' do |app|
24
- # The offending middleware is included in Rails (6+) development mode and
25
- # rejects a request with a 403 response if its host isn't present in the
26
- # allowlist (a security feature). This prevents Parklife from working in
27
- # a Rails app out of the box unless you manually add the expected
28
- # Parklife base to the hosts allowlist or set it to nil to disable it -
29
- # both of which aren't great because they disable the security feature
30
- # whenever the development server is booted.
31
- #
32
- # https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization
33
- #
34
- # However it's safe to remove the middleware at this point because it
35
- # won't be executed in the normal Rails development flow, only via a
36
- # Parkfile when parklife/rails is required.
37
- if defined?(ActionDispatch::HostAuthorization)
38
- app.middleware.delete(ActionDispatch::HostAuthorization)
39
- end
40
- end
41
-
42
- config.after_initialize do
43
- Parklife.application.config.app = Rails.application
44
-
45
- # Allow use of the Rails application's route helpers when defining
46
- # Parklife routes in the block form.
47
- Parklife.application.routes.singleton_class.include(Rails.application.routes.url_helpers)
48
-
49
- Parklife.application.config.extend(RailsConfigRefinements)
50
- end
51
- end
52
- end