Last active
January 11, 2025 16:56
-
-
Save bradgessler/fcb89e3d6a848c48c774de797fc5a1cd to your computer and use it in GitHub Desktop.
Superview link helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'bundler/inline' | |
gemfile do | |
source 'https://rubygems.org' | |
gem 'rspec' | |
end | |
require 'rspec/autorun' | |
class Scope | |
include Enumerable | |
def initialize(*segments) | |
@segments = segments | |
end | |
def each(&) | |
@segments.each(&) | |
end | |
def models | |
select { |segment| segment.respond_to? :to_model } | |
end | |
def path | |
map do |segment| | |
if segment.respond_to? :to_param | |
segment.to_param | |
else | |
segment.to_s | |
end | |
end.join("/").prepend("/") | |
end | |
def a(**attributes, &content) | |
"<a #{attributes.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")}>#{content&.call}</a>" | |
end | |
def show(*,**,&) | |
path, content = segment(*,&) | |
a(href: path, data_turbo_method: :get, **, &content) | |
end | |
def scope(*segments) | |
Scope.new(*@segments, *segments) | |
end | |
def parent | |
*segments, _ = @segments | |
Scope.new(*segments) | |
end | |
protected | |
def segment(*segments, &block) | |
if segments.any? | |
scope(*segments).segment(&block) | |
else | |
content = content(&block) || Proc.new { path } | |
[ path, content ] | |
end | |
end | |
def content(&block) | |
Proc.new { | |
if block.lambda? | |
block.call models.last | |
elsif block | |
block.call *models | |
end | |
} if block | |
end | |
end | |
def scope(*) | |
Scope.new(*) | |
end | |
def show(*, **, &) = scope(*, **).show(&) | |
class Blog < Struct.new(:id, :name) | |
def to_param = id | |
def to_model = self | |
end | |
class Post < Struct.new(:id, :title, :blog) | |
def to_param = id | |
def to_model = self | |
end | |
RSpec.describe "Links" do | |
let(:blog) { Blog.new(1, "Bob Law's Law Blog") } | |
let(:post) { Post.new(1, "Post", blog) } | |
let(:posts) { scope(:blogs, blog, :posts) } | |
let(:post_scope) { scope(:blogs, blog, :posts, post) } | |
describe "post title link" do | |
subject { posts.show(post, &:title) } | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1" data_turbo_method="get">Post</a>) } | |
end | |
describe "edit link with block content" do | |
subject do | |
posts.show(post, :edit) { |blog, post| "Open #{blog.name} - #{post.title}" } | |
end | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1/edit" data_turbo_method="get">Open Bob Law's Law Blog - Post</a>) } | |
end | |
describe "preview link with block content" do | |
subject do | |
posts.show(post, :preview) { |blog, post| "Preview #{blog.name} - #{post.title}" } | |
end | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1/preview" data_turbo_method="get">Preview Bob Law's Law Blog - Post</a>) } | |
end | |
describe "default show link with block content" do | |
subject do | |
post_scope.show { |blog, post| "#{blog.name} - #{post.title}" } | |
end | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1" data_turbo_method="get">Bob Law's Law Blog - Post</a>) } | |
end | |
describe "link using title lambda" do | |
subject { post_scope.show(class: "btn btn-primary", &:title) } | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1" data_turbo_method="get" class="btn btn-primary">Post</a>) } | |
end | |
describe "preview link using title lambda" do | |
subject { post_scope.show(:preview, &:title) } | |
it { is_expected.to eq %(<a href="/blogs/1/posts/1/preview" data_turbo_method="get">Post</a>) } | |
end | |
describe "parent link with custom block content" do | |
subject { post_scope.parent.show { "#{_1.name} Posts" } } | |
it { is_expected.to eq %(<a href="/blogs/1/posts" data_turbo_method="get">Bob Law's Law Blog Posts</a>) } | |
end | |
describe "parent link with no block" do | |
subject { post_scope.parent.show } | |
it { is_expected.to eq %(<a href="/blogs/1/posts" data_turbo_method="get">/blogs/1/posts</a>) } | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment