bridgetown-routes 1.0.0.alpha2

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: 7d99af4d6cf66c15ad4ca1da7044ca24142f45dbf6035696573dbb8e5033f8c7
4
+ data.tar.gz: 8418e77c8b4bd9263468149ba6d231d5a51b6922ffe299291374b8abb8e2ba80
5
+ SHA512:
6
+ metadata.gz: 5f0528d922fbf73a90edf3f62fd584f8fba34853337228b2fa16dcb3e2f31a927d0c6e30ebe549a4762aa56f9649812c03d4c9be5b5f9e1597fac4e00d8c25ff
7
+ data.tar.gz: b17f234af39b21ec58721c842eb6f4bbd6294c579f0c4a9cf0884ad0a891aaf873e33b7a01d34efef9abd7d496281dd9ab42a5454ce6648320046ef555e2555d
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ inherit_from: ../.rubocop.yml
3
+
4
+ AllCops:
5
+ Exclude:
6
+ - "*.gemspec"
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ task spec: :test
6
+ require "rake/testtask"
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << "lib" << "test"
9
+ test.pattern = "test/**/test_*.rb"
10
+ test.verbose = true
11
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../bridgetown-core/lib/bridgetown-core/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "bridgetown-routes"
7
+ spec.version = Bridgetown::VERSION
8
+ spec.author = "Bridgetown Team"
9
+ spec.email = "maintainers@bridgetownrb.com"
10
+ spec.summary = "A Bridgetown plugin to add support for file-based Roda backend routes within the source folder."
11
+ spec.homepage = "https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-routes"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script|spec|features)/!) }
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_dependency("bridgetown-core", Bridgetown::VERSION)
18
+ spec.add_dependency("roda-route_list", ">= 2.1")
19
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Routes
5
+ module CodeBlocks
6
+ class << self
7
+ attr_accessor :blocks
8
+
9
+ def add_route(name, file_code = nil, &block)
10
+ block.instance_variable_set(:@_route_file_code, file_code) if file_code
11
+
12
+ @blocks ||= {}
13
+ @blocks[name] = block
14
+ end
15
+
16
+ # @param name [String]
17
+ def route_defined?(name)
18
+ blocks&.key?(name)
19
+ end
20
+
21
+ def route_block(name)
22
+ blocks[name] if route_defined?(name)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Routes
5
+ module ViewHelpers
6
+ def request
7
+ view.resource&.roda_data&.request
8
+ end
9
+ alias_method :r, :request
10
+
11
+ def response
12
+ view.resource&.roda_data&.response
13
+ end
14
+
15
+ def flash
16
+ view.resource&.roda_data&.flash
17
+ end
18
+
19
+ # def csrf_tag(...)
20
+ # request.scope.csrf_tag(...)
21
+ # end
22
+
23
+ # def csrf_token(...)
24
+ # request.scope.csrf_token(...)
25
+ # end
26
+ end
27
+ end
28
+ end
29
+
30
+ Bridgetown::RubyTemplateView::Helpers.include Bridgetown::Routes::ViewHelpers
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Routes
5
+ module Manifest
6
+ class << self
7
+ def routable_extensions
8
+ %w(rb md serb erb liquid)
9
+ end
10
+
11
+ def generate_manifest # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
12
+ return @route_manifest if @route_manifest && Bridgetown.env.production?
13
+
14
+ routes_dir = File.expand_path("src/_routes", Dir.pwd)
15
+ # @type [Array]
16
+ routes = Dir.glob(routes_dir + "/**/*.{#{routable_extensions.join(",")}}").map do |file|
17
+ if File.basename(file).start_with?("_", ".") ||
18
+ File.basename(file, ".*").end_with?(".test")
19
+ next
20
+ end
21
+
22
+ # @type [String]
23
+ file_slug = file.delete_prefix("#{routes_dir}/").then do |f|
24
+ [File.dirname(f), File.basename(f, ".*")].join("/").delete_prefix("./")
25
+ end.delete_suffix("/index")
26
+ segment_keys = []
27
+ file_slug.gsub!(%r{\[([^/]+)\]}) do |_segment|
28
+ segment_keys << Regexp.last_match(1)
29
+ ":#{Regexp.last_match(1)}"
30
+ end
31
+
32
+ [file, file_slug, segment_keys]
33
+ end.compact
34
+
35
+ routes.sort! do |route_a, route_b|
36
+ # @type [String]
37
+ _, slug_a = route_a
38
+ _, slug_b = route_b
39
+
40
+ weight1 = slug_a.count("/") <=> slug_b.count("/")
41
+ if weight1.zero?
42
+ slug_b.count("/:") <=> slug_a.count("/:")
43
+ else
44
+ weight1
45
+ end
46
+ end.reverse!
47
+
48
+ @route_manifest = routes
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Routes
5
+ module RodaRouter
6
+ def self.start!(app) # rubocop:disable Metrics/MethodLength
7
+ r = app.request
8
+ response = app.response
9
+
10
+ Bridgetown::Routes::Manifest.generate_manifest.each do |route|
11
+ file, file_slug, segment_keys = route
12
+
13
+ r.on file_slug do |*segment_values|
14
+ response["X-Bridgetown-SSR"] = "1"
15
+ unless Bridgetown.env.production? &&
16
+ Bridgetown::Routes::CodeBlocks.route_defined?(file_slug)
17
+ eval_route_file file, file_slug, app
18
+ end
19
+
20
+ segment_values.each_with_index do |value, index|
21
+ r.params[segment_keys[index]] ||= value
22
+ end
23
+
24
+ route_block = Bridgetown::Routes::CodeBlocks.route_block(file_slug)
25
+ app.instance_variable_set(
26
+ :@_route_file_code, route_block.instance_variable_get(:@_route_file_code)
27
+ ) # could be nil
28
+ app.instance_exec(&route_block)
29
+ end
30
+ end
31
+
32
+ nil
33
+ end
34
+
35
+ def self.eval_route_file(file, file_slug, app) # rubocop:disable Lint/UnusedMethodArgument
36
+ code = File.read(file)
37
+ code_postmatch = nil
38
+ ruby_content = code.match(Bridgetown::FrontMatterImporter::RUBY_BLOCK)
39
+ if ruby_content
40
+ code = ruby_content[1]
41
+ code_postmatch = ruby_content.post_match
42
+ end
43
+
44
+ code = <<~RUBY
45
+ r = app.request
46
+ Bridgetown::Routes::CodeBlocks.add_route(#{file_slug.inspect}, #{code_postmatch.inspect}) do
47
+ #{code}
48
+ end
49
+ RUBY
50
+ instance_eval(code, file, -1)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bridgetown-core"
4
+ require "bridgetown-core/version"
5
+
6
+ require_relative "roda/plugins/bridgetown_routes"
7
+
8
+ require_relative "bridgetown-routes/helpers"
9
+
10
+ module Bridgetown
11
+ module Routes
12
+ autoload :CodeBlocks, "bridgetown-routes/code_blocks"
13
+ autoload :Manifest, "bridgetown-routes/manifest"
14
+ autoload :RodaRouter, "bridgetown-routes/roda_router"
15
+
16
+ # rubocop:disable Bridgetown/NoPutsAllowed
17
+ def self.print_roda_routes
18
+ routes = begin
19
+ JSON.parse(File.read("#{Dir.pwd}/.routes.json"))
20
+ rescue StandardError
21
+ []
22
+ end
23
+ puts
24
+ puts "Routes:"
25
+ puts "======="
26
+ if routes.blank?
27
+ puts "No routes found. Have you commented all of your routes?"
28
+ puts "Documentation: https://github.com/jeremyevans/roda-route_list#basic-usage-"
29
+ end
30
+
31
+ routes.each do |route|
32
+ puts [route["methods"]&.join("|") || "GET", route["path"]].compact.join(" ")
33
+ end
34
+ end
35
+ # rubocop:enable Bridgetown/NoPutsAllowed
36
+ end
37
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "roda/plugins/flash"
4
+
5
+ class Roda
6
+ module RodaPlugins
7
+ module BridgetownRoutes
8
+ def self.load_dependencies(app)
9
+ app.plugin :slash_path_empty # now /hello and /hello/ are both matched
10
+ app.plugin :placeholder_string_matchers
11
+ app.plugin :flash
12
+ app.plugin :route_csrf, check_header: true
13
+ end
14
+
15
+ def self.configure(app, _opts = {})
16
+ return unless app.opts[:bridgetown_site].nil?
17
+
18
+ raise "Roda app failure: the bridgetown_ssr plugin must be registered before" \
19
+ " bridgetown_routes"
20
+ end
21
+
22
+ module InstanceMethods
23
+ def render_with(data: {}) # rubocop:todo Metrics/AbcSize
24
+ path = Kernel.caller_locations(1, 1).first.absolute_path
25
+ source_path = Pathname.new(path).relative_path_from(Bridgetown::Current.site.source)
26
+ code = @_route_file_code
27
+
28
+ unless code.present?
29
+ raise Bridgetown::Errors::FatalException,
30
+ "`render_with' method must be called from a template-based file in `src/_routes'"
31
+ end
32
+
33
+ data = Bridgetown::Model::BuilderOrigin.new("builder://#{source_path}").read do
34
+ data[:_collection_] = Bridgetown::Current.site.collections.pages
35
+ data[:_content_] = code
36
+ data
37
+ end
38
+
39
+ Bridgetown::Model::Base.new(data).to_resource.tap do |resource|
40
+ resource.roda_data[:request] = request
41
+ resource.roda_data[:response] = response
42
+ resource.roda_data[:flash] = nil
43
+ # resource.roda_data[:flash] = flash
44
+ end.read!.transform!.output
45
+ end
46
+
47
+ ruby2_keywords def render(*args, &block)
48
+ view.render(*args, &block)
49
+ end
50
+
51
+ def view(view_class: Bridgetown::ERBView)
52
+ response._fake_resource_view(
53
+ view_class: view_class, request: request, bridgetown_site: bridgetown_site
54
+ )
55
+ end
56
+ end
57
+
58
+ module ResponseMethods
59
+ def _fake_resource_view(view_class:, request:, bridgetown_site:)
60
+ @_fake_resource_views ||= {}
61
+ @_fake_resource_views[view_class] ||= view_class.new(
62
+ # TODO: use a Stuct for better performance...?
63
+ HashWithDotAccess::Hash.new({
64
+ data: {},
65
+ roda_data: {
66
+ request: request,
67
+ response: self,
68
+ flash: nil, # flash,
69
+ },
70
+ site: bridgetown_site,
71
+ })
72
+ )
73
+ end
74
+ end
75
+ end
76
+
77
+ register_plugin :bridgetown_routes, BridgetownRoutes
78
+ end
79
+ end
80
+
81
+ module RodaResourceExtension
82
+ module RubyResource
83
+ def roda_data
84
+ @roda_data ||= HashWithDotAccess::Hash.new
85
+ end
86
+ end
87
+ end
88
+ Bridgetown::Resource.register_extension RodaResourceExtension
89
+
90
+ Roda::RodaPlugins::Flash::FlashHash.class_eval do
91
+ def info
92
+ self["info"]
93
+ end
94
+
95
+ def info=(val)
96
+ self["info"] = val
97
+ end
98
+
99
+ def alert
100
+ self["alert"]
101
+ end
102
+
103
+ def alert=(val)
104
+ self["alert"] = val
105
+ end
106
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bridgetown-routes
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.alpha2
5
+ platform: ruby
6
+ authors:
7
+ - Bridgetown Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-10-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bridgetown-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0.alpha2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0.alpha2
27
+ - !ruby/object:Gem::Dependency
28
+ name: roda-route_list
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.1'
41
+ description:
42
+ email: maintainers@bridgetownrb.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - ".rubocop.yml"
48
+ - Rakefile
49
+ - bridgetown-routes.gemspec
50
+ - lib/bridgetown-routes.rb
51
+ - lib/bridgetown-routes/code_blocks.rb
52
+ - lib/bridgetown-routes/helpers.rb
53
+ - lib/bridgetown-routes/manifest.rb
54
+ - lib/bridgetown-routes/roda_router.rb
55
+ - lib/roda/plugins/bridgetown_routes.rb
56
+ homepage: https://github.com/bridgetownrb/bridgetown/tree/main/bridgetown-routes
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">"
72
+ - !ruby/object:Gem::Version
73
+ version: 1.3.1
74
+ requirements: []
75
+ rubygems_version: 3.1.4
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: A Bridgetown plugin to add support for file-based Roda backend routes within
79
+ the source folder.
80
+ test_files: []