showcase-rails 0.2.2 → 0.2.4
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 +4 -4
- data/README.md +71 -5
- data/app/assets/builds/showcase.css +9 -1
- data/app/assets/builds/showcase.highlights.css +112 -0
- data/app/models/showcase/path.rb +8 -16
- data/app/models/showcase/sample.rb +6 -6
- data/app/views/layouts/showcase.html.erb +2 -2
- data/app/views/showcase/engine/_preview.html.erb +1 -1
- data/app/views/showcase/engine/_sample.html.erb +2 -2
- data/app/views/showcase/engine/_stylesheets.html.erb +1 -1
- data/app/views/showcase/engine/path/_path.html.erb +1 -1
- data/lib/showcase/engine.rb +2 -2
- data/lib/showcase/options.rb +89 -0
- data/lib/showcase/previews_test.rb +45 -0
- data/lib/showcase/version.rb +1 -1
- data/lib/showcase.rb +52 -3
- data/lib/tasks/showcase_tasks.rake +6 -6
- metadata +5 -4
- data/app/models/showcase/options.rb +0 -51
- data/lib/showcase/integration_test.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aead2040b7c095f85df0c152c6d96aa3bec927e52f49db09f407926536ce36ae
|
4
|
+
data.tar.gz: c5fd847fd56d1ffa39a4d9aae681106685c71aef2e199bbb637158ec80f43cbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ffe05a31b2be808620a735573c1cbaf705cceb75bdf03f750193f0ad5534096cb3bc81a4d98e51b80712408ca7b3b60465e85a23828ae469da9af3fdb348db5
|
7
|
+
data.tar.gz: f6ec194dec60349be7b4effd48a20517c8af04e45604b104687a6479a4bba92087ae11b36d702fac03e8d1faebb22521b6d49e62d816b5a42d187e027ce9ce00
|
data/README.md
CHANGED
@@ -29,11 +29,59 @@ Which will then render the following:
|
|
29
29
|
|
30
30
|

|
31
31
|
|
32
|
-
##
|
32
|
+
## Using options contexts
|
33
33
|
|
34
|
-
Showcase
|
34
|
+
Showcase also supports custom options contexts. They're useful for cases where the options have a very specific format and it would be nice to keep them standardized.
|
35
35
|
|
36
|
-
|
36
|
+
By default, Showcase ships Nice Partials and Stimulus contexts out of the box. Here's a sample of the Stimulus one:
|
37
|
+
|
38
|
+
```erb
|
39
|
+
<% showcase.options.stimulus controller: :welcome do |o| %>
|
40
|
+
<% o.optional.targets :greeter, "If the id of the target element must be printed" %>
|
41
|
+
<% end %>
|
42
|
+
```
|
43
|
+
|
44
|
+
In case Showcase didn't ship with a Stimulus context, here's how you could add it:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# config/initializers/showcase.rb
|
48
|
+
if defined?(Showcase)
|
49
|
+
Showcase.options.define :stimulus do
|
50
|
+
def targets(name, ...)
|
51
|
+
option(%(data-#{@controller}-target="#{name}"), ...)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
## Automatic previews testing
|
58
|
+
|
59
|
+
Showcase automatically runs tests for all your Showcases by rendering them. As long as `gem "showcase-rails"` is in the `:test` group you're set.
|
60
|
+
|
61
|
+
If you want to tweak this, run `bin/rails showcase:install:previews_test` and open `test/views/showcase_test.rb`. You can then add your own `setup` and `teardown` hooks, as well as override the provided `assert_showcase_preview` to add custom assertions.
|
62
|
+
|
63
|
+
If you need custom assertions for specific previews and their samples, you can use the `test` helper:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# test/views/showcase_test.rb
|
67
|
+
require "test_helper"
|
68
|
+
|
69
|
+
class ShowcaseTest < Showcase::PreviewsTest
|
70
|
+
test showcase: "combobox" do
|
71
|
+
# This test block runs within the #combobox container element.
|
72
|
+
assert_text "This is a combobox, for sure."
|
73
|
+
end
|
74
|
+
|
75
|
+
test showcase: "button", id: "basic" do
|
76
|
+
# This test block runs within the #button container element's #basic sample.
|
77
|
+
assert_button class: ["text-xs"]
|
78
|
+
end
|
79
|
+
|
80
|
+
test "some non-Showcase test" do
|
81
|
+
# You can still use the regular Rails `test` method too.
|
82
|
+
end
|
83
|
+
end
|
84
|
+
```
|
37
85
|
|
38
86
|
## View examples
|
39
87
|
|
@@ -70,7 +118,7 @@ copy the file from our repo `app/views` directory into your `app/views` director
|
|
70
118
|
|
71
119
|
### Loading your own assets
|
72
120
|
|
73
|
-
Showcase bundles its own `showcase.js` and `showcase.css` asset files through
|
121
|
+
Showcase bundles its own `showcase.js`, `showcase.css` and `showcase.highlights.css` asset files through
|
74
122
|
Action View's [javascript_include_tag][] and [stylesheet_link_tag][].
|
75
123
|
|
76
124
|
If your assets require more sophisticated loading techniques, declare your own
|
@@ -78,12 +126,24 @@ versions of the [showcase/engine/_javascripts.html.erb][] and
|
|
78
126
|
[showcase/engine/_stylesheets.html.erb][] partials. When customizing those
|
79
127
|
partials, make sure to include `"showcase"` in your list of assets.
|
80
128
|
|
81
|
-
|
82
129
|
[javascript_include_tag]: https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-javascript_include_tag
|
83
130
|
[stylesheet_link_tag]: https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-stylesheet_link_tag
|
84
131
|
[showcase/engine/_javascripts.html.erb]: ./showcase/engine/_javascripts.html.erb
|
85
132
|
[showcase/engine/_stylesheets.html.erb]: ./showcase/engine/_stylesheets.html.erb
|
86
133
|
|
134
|
+
#### Loading your own syntax highlighting theme
|
135
|
+
|
136
|
+
By default, Showcase's syntax highlighting runs on Rouge's "github" theme.
|
137
|
+
|
138
|
+
To use a different theme, override [showcase/engine/_stylesheets.html.erb][] with the following, replacing `:magritte` with a [valid theme](rouge-themes):
|
139
|
+
|
140
|
+
```erb
|
141
|
+
<%= stylesheet_link_tag "application", "showcase" %> # We've removed the default showcase.highlights file here.
|
142
|
+
<%= tag.style Rouge::Theme.find(:magritte).render(scope: ".sc-highlight") %>
|
143
|
+
```
|
144
|
+
|
145
|
+
[rouge-themes]: https://github.com/rouge-ruby/rouge/tree/master/lib/rouge/themes
|
146
|
+
|
87
147
|
## Installation
|
88
148
|
|
89
149
|
Add this line to your application's Gemfile. To get the automatic integration testing make sure the `showcase-rails` gem is available to your test environment:
|
@@ -104,6 +164,12 @@ Or install it yourself as:
|
|
104
164
|
$ gem install showcase-rails
|
105
165
|
```
|
106
166
|
|
167
|
+
Then add the following in your `config/routes.rb` within the block passed to `Rails.application.routes.draw`:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
mount Showcase::Engine, at: "/docs/showcase" if defined?(Showcase::Engine)
|
171
|
+
```
|
172
|
+
|
107
173
|
## Contributing
|
108
174
|
Contribution directions go here.
|
109
175
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
! tailwindcss v3.2.
|
2
|
+
! tailwindcss v3.2.7 | MIT License | https://tailwindcss.com
|
3
3
|
*/
|
4
4
|
|
5
5
|
/*
|
@@ -985,6 +985,14 @@ select {
|
|
985
985
|
background-color: rgb(238 242 255 / var(--tw-bg-opacity));
|
986
986
|
}
|
987
987
|
|
988
|
+
.hover\:sc-text-inherit:hover {
|
989
|
+
color: inherit;
|
990
|
+
}
|
991
|
+
|
992
|
+
.hover\:sc-no-underline:hover {
|
993
|
+
text-decoration-line: none;
|
994
|
+
}
|
995
|
+
|
988
996
|
@media (min-width: 768px) {
|
989
997
|
.md\:sc-text-lg {
|
990
998
|
font-size: 1.125rem;
|
@@ -0,0 +1,112 @@
|
|
1
|
+
.sc-highlight table td { padding: 5px; }
|
2
|
+
.sc-highlight table pre { margin: 0; }
|
3
|
+
.sc-highlight, .sc-highlight .w {
|
4
|
+
color: #24292f;
|
5
|
+
background-color: #f6f8fa;
|
6
|
+
}
|
7
|
+
.sc-highlight .k, .sc-highlight .kd, .sc-highlight .kn, .sc-highlight .kp, .sc-highlight .kr, .sc-highlight .kt, .sc-highlight .kv {
|
8
|
+
color: #cf222e;
|
9
|
+
}
|
10
|
+
.sc-highlight .gr {
|
11
|
+
color: #f6f8fa;
|
12
|
+
}
|
13
|
+
.sc-highlight .gd {
|
14
|
+
color: #82071e;
|
15
|
+
background-color: #ffebe9;
|
16
|
+
}
|
17
|
+
.sc-highlight .nb {
|
18
|
+
color: #953800;
|
19
|
+
}
|
20
|
+
.sc-highlight .nc {
|
21
|
+
color: #953800;
|
22
|
+
}
|
23
|
+
.sc-highlight .no {
|
24
|
+
color: #953800;
|
25
|
+
}
|
26
|
+
.sc-highlight .nn {
|
27
|
+
color: #953800;
|
28
|
+
}
|
29
|
+
.sc-highlight .sr {
|
30
|
+
color: #116329;
|
31
|
+
}
|
32
|
+
.sc-highlight .na {
|
33
|
+
color: #116329;
|
34
|
+
}
|
35
|
+
.sc-highlight .nt {
|
36
|
+
color: #116329;
|
37
|
+
}
|
38
|
+
.sc-highlight .gi {
|
39
|
+
color: #116329;
|
40
|
+
background-color: #dafbe1;
|
41
|
+
}
|
42
|
+
.sc-highlight .kc {
|
43
|
+
color: #0550ae;
|
44
|
+
}
|
45
|
+
.sc-highlight .l, .sc-highlight .ld, .sc-highlight .m, .sc-highlight .mb, .sc-highlight .mf, .sc-highlight .mh, .sc-highlight .mi, .sc-highlight .il, .sc-highlight .mo, .sc-highlight .mx {
|
46
|
+
color: #0550ae;
|
47
|
+
}
|
48
|
+
.sc-highlight .sb {
|
49
|
+
color: #0550ae;
|
50
|
+
}
|
51
|
+
.sc-highlight .bp {
|
52
|
+
color: #0550ae;
|
53
|
+
}
|
54
|
+
.sc-highlight .ne {
|
55
|
+
color: #0550ae;
|
56
|
+
}
|
57
|
+
.sc-highlight .nl {
|
58
|
+
color: #0550ae;
|
59
|
+
}
|
60
|
+
.sc-highlight .py {
|
61
|
+
color: #0550ae;
|
62
|
+
}
|
63
|
+
.sc-highlight .nv, .sc-highlight .vc, .sc-highlight .vg, .sc-highlight .vi, .sc-highlight .vm {
|
64
|
+
color: #0550ae;
|
65
|
+
}
|
66
|
+
.sc-highlight .o, .sc-highlight .ow {
|
67
|
+
color: #0550ae;
|
68
|
+
}
|
69
|
+
.sc-highlight .gh {
|
70
|
+
color: #0550ae;
|
71
|
+
font-weight: bold;
|
72
|
+
}
|
73
|
+
.sc-highlight .gu {
|
74
|
+
color: #0550ae;
|
75
|
+
font-weight: bold;
|
76
|
+
}
|
77
|
+
.sc-highlight .s, .sc-highlight .sa, .sc-highlight .sc, .sc-highlight .dl, .sc-highlight .sd, .sc-highlight .s2, .sc-highlight .se, .sc-highlight .sh, .sc-highlight .sx, .sc-highlight .s1, .sc-highlight .ss {
|
78
|
+
color: #0a3069;
|
79
|
+
}
|
80
|
+
.sc-highlight .nd {
|
81
|
+
color: #8250df;
|
82
|
+
}
|
83
|
+
.sc-highlight .nf, .sc-highlight .fm {
|
84
|
+
color: #8250df;
|
85
|
+
}
|
86
|
+
.sc-highlight .err {
|
87
|
+
color: #f6f8fa;
|
88
|
+
background-color: #82071e;
|
89
|
+
}
|
90
|
+
.sc-highlight .c, .sc-highlight .ch, .sc-highlight .cd, .sc-highlight .cm, .sc-highlight .cp, .sc-highlight .cpf, .sc-highlight .c1, .sc-highlight .cs {
|
91
|
+
color: #6e7781;
|
92
|
+
}
|
93
|
+
.sc-highlight .gl {
|
94
|
+
color: #6e7781;
|
95
|
+
}
|
96
|
+
.sc-highlight .gt {
|
97
|
+
color: #6e7781;
|
98
|
+
}
|
99
|
+
.sc-highlight .ni {
|
100
|
+
color: #24292f;
|
101
|
+
}
|
102
|
+
.sc-highlight .si {
|
103
|
+
color: #24292f;
|
104
|
+
}
|
105
|
+
.sc-highlight .ge {
|
106
|
+
color: #24292f;
|
107
|
+
font-style: italic;
|
108
|
+
}
|
109
|
+
.sc-highlight .gs {
|
110
|
+
color: #24292f;
|
111
|
+
font-weight: bold;
|
112
|
+
}
|
data/app/models/showcase/path.rb
CHANGED
@@ -1,19 +1,16 @@
|
|
1
1
|
class Showcase::Path
|
2
|
-
class Tree < Struct.new(:id, :children)
|
2
|
+
class Tree < Struct.new(:id, :children, :root)
|
3
3
|
def initialize(id, children = [])
|
4
|
-
super
|
4
|
+
super(id, children, false)
|
5
5
|
end
|
6
|
+
alias_method :root?, :root
|
6
7
|
delegate :<<, to: :children
|
7
8
|
|
8
9
|
cached_partial_path = "showcase/engine/path/tree"
|
9
10
|
define_method(:to_partial_path) { cached_partial_path }
|
10
11
|
|
11
12
|
def name
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def root?
|
16
|
-
id == "."
|
13
|
+
id == "." ? "Previews" : id
|
17
14
|
end
|
18
15
|
|
19
16
|
def ordered_children
|
@@ -24,15 +21,10 @@ class Showcase::Path
|
|
24
21
|
children.flat_map { _1.is_a?(Tree) ? _1.ordered_paths : _1 }
|
25
22
|
end
|
26
23
|
|
27
|
-
def self.index(
|
28
|
-
new(:discardable_root)
|
29
|
-
|
30
|
-
|
31
|
-
def index(paths)
|
32
|
-
paths.each do |path|
|
33
|
-
ids = yield path
|
34
|
-
ids.inject(self, :edge_for) << path
|
35
|
-
end
|
24
|
+
def self.index(paths)
|
25
|
+
paths.each_with_object new(:discardable_root) do |path, root|
|
26
|
+
yield(path).reduce(root, :edge_for) << path
|
27
|
+
end.children.sort_by(&:id).each { _1.root = true }
|
36
28
|
end
|
37
29
|
|
38
30
|
def edge_for(id)
|
@@ -2,9 +2,9 @@ class Showcase::Sample
|
|
2
2
|
attr_reader :name, :id, :events, :details
|
3
3
|
attr_reader :source, :instrumented
|
4
4
|
|
5
|
-
def initialize(view_context, name, description: nil, id: name.parameterize, events: nil, **details)
|
5
|
+
def initialize(view_context, name, description: nil, id: name.parameterize, syntax: :erb, events: nil, **details)
|
6
6
|
@view_context = view_context
|
7
|
-
@name, @id, @details = name, id, details
|
7
|
+
@name, @id, @syntax, @details = name, id, syntax, details
|
8
8
|
@events = Array(events)
|
9
9
|
description description if description
|
10
10
|
end
|
@@ -34,13 +34,13 @@ class Showcase::Sample
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def extract(&block)
|
37
|
-
|
38
|
-
@source = @view_context.instance_exec(
|
37
|
+
source = extract_source_block_via_matched_indentation_from(*block.source_location)
|
38
|
+
@source = @view_context.instance_exec(source, @syntax, &Showcase.sample_renderer)
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
|
-
def
|
43
|
+
def extract_source_block_via_matched_indentation_from(file, starting_index)
|
44
44
|
first_line, *lines = File.readlines(file).from(starting_index - 1)
|
45
45
|
|
46
46
|
indentation = first_line.match(/^\s+(?=\b)/).to_s
|
@@ -48,6 +48,6 @@ class Showcase::Sample
|
|
48
48
|
|
49
49
|
index = lines.index { _1.match?(matcher) }
|
50
50
|
lines.slice!(index..) if index
|
51
|
-
lines
|
51
|
+
lines.join.strip_heredoc
|
52
52
|
end
|
53
53
|
end
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<title>Showcase</title>
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
6
|
|
7
|
-
<%= render "stylesheets" %>
|
8
|
-
<%= render "javascripts" %>
|
7
|
+
<%= render "showcase/engine/stylesheets" %>
|
8
|
+
<%= render "showcase/engine/javascripts" %>
|
9
9
|
</head>
|
10
10
|
|
11
11
|
<body>
|
@@ -27,8 +27,8 @@
|
|
27
27
|
<details>
|
28
28
|
<summary class="sc-px-4 sc-py-2 hover:sc-bg-indigo-50 sc-cursor-pointer sc-select-none">View Source</summary>
|
29
29
|
|
30
|
-
<section class="sc-px-4 sc-py-2 sc-relative sc-overflow-y-auto hover:sc-select-all">
|
31
|
-
|
30
|
+
<section class="sc-highlight sc-px-4 sc-py-2 sc-relative sc-overflow-y-auto hover:sc-select-all">
|
31
|
+
<pre><%= sample.source %></pre>
|
32
32
|
</section>
|
33
33
|
</details>
|
34
34
|
<% end %>
|
@@ -1 +1 @@
|
|
1
|
-
<%= stylesheet_link_tag "application", "showcase" %>
|
1
|
+
<%= stylesheet_link_tag "application", "showcase", "showcase.highlights" %>
|
@@ -1,3 +1,3 @@
|
|
1
1
|
<article class="hover:sc-bg-indigo-50 <%= "sc-bg-indigo-50" if path.id == params[:id] %>">
|
2
|
-
<%= link_to path.basename.titleize, preview_path(path.id), class: "sc-inline-block sc-py-2 sc-px-8 sc-w-full" %>
|
2
|
+
<%= link_to path.basename.titleize, preview_path(path.id), class: "sc-inline-block sc-py-2 sc-px-8 sc-w-full hover:sc-text-inherit hover:sc-no-underline" %>
|
3
3
|
</article>
|
data/lib/showcase/engine.rb
CHANGED
@@ -6,8 +6,8 @@ module Showcase
|
|
6
6
|
config.assets.precompile += %w[showcase_manifest]
|
7
7
|
end
|
8
8
|
|
9
|
-
initializer "showcase.
|
10
|
-
Showcase::
|
9
|
+
initializer "showcase.previews_test.autorun" do
|
10
|
+
Showcase::PreviewsTest.autorun if Rails.env.test?
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "active_support/option_merger"
|
2
|
+
|
3
|
+
class Showcase::Options
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(view_context)
|
7
|
+
@view_context = view_context
|
8
|
+
@options = []
|
9
|
+
@order = [:name, :required, :type, :default, :description]
|
10
|
+
end
|
11
|
+
delegate :empty?, to: :@options
|
12
|
+
|
13
|
+
# Showcase.options.define :stimulus do
|
14
|
+
# def value(name, ...)
|
15
|
+
# option("data-#{@controller}-#{name}-value", ...)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
singleton_class.attr_reader :contexts
|
19
|
+
@contexts = Hash.new { |h,k| h[k] = Class.new Context }
|
20
|
+
|
21
|
+
def self.define(key, &block)
|
22
|
+
contexts[key].class_eval(&block) # Lets users reopen an already defined context class.
|
23
|
+
end
|
24
|
+
|
25
|
+
# showcase.options.stimulus controller: :welcome do |o|
|
26
|
+
# o.value :greeting, default: "Hello"
|
27
|
+
# end
|
28
|
+
def context(key, **options, &block)
|
29
|
+
context = self.class.contexts.fetch(key)
|
30
|
+
context.new(@view_context, @options, **options).tap { yield _1 if block_given? }
|
31
|
+
end
|
32
|
+
|
33
|
+
def required(*arguments, **keywords, &block)
|
34
|
+
if arguments.none?
|
35
|
+
ActiveSupport::OptionMerger.new(self, required: true)
|
36
|
+
else
|
37
|
+
option(*arguments, **keywords, required: true, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def optional(*arguments, **keywords, &block)
|
42
|
+
if arguments.none?
|
43
|
+
ActiveSupport::OptionMerger.new(self, required: false)
|
44
|
+
else
|
45
|
+
option(*arguments, **keywords, required: false, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
DEFAULT_OMITTED = Object.new
|
50
|
+
|
51
|
+
def option(name, description = nil, required: false, type: nil, default: DEFAULT_OMITTED, **options, &block)
|
52
|
+
description ||= @view_context.capture(&block).remove(/^\s+/).html_safe if block
|
53
|
+
|
54
|
+
type ||= type_from_default(default)
|
55
|
+
default = default == DEFAULT_OMITTED ? nil : default.inspect
|
56
|
+
|
57
|
+
@options << options.with_defaults(name: name, default: default, type: type, description: description, required: required)
|
58
|
+
end
|
59
|
+
|
60
|
+
def headers
|
61
|
+
@headers ||= @order | @options.flat_map(&:keys).uniq.sort
|
62
|
+
end
|
63
|
+
|
64
|
+
def each(&block)
|
65
|
+
@options.each do |option|
|
66
|
+
yield headers.index_with { option[_1] }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
class Context < Showcase::Options
|
73
|
+
def initialize(view_context, options, **kwargs)
|
74
|
+
super(view_context)
|
75
|
+
@options = options
|
76
|
+
kwargs.each { instance_variable_set(:"@#{_1}", _2) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def type_from_default(default)
|
81
|
+
case default
|
82
|
+
when DEFAULT_OMITTED then String
|
83
|
+
when true, false then "Boolean"
|
84
|
+
when nil then "nil"
|
85
|
+
else
|
86
|
+
default.class
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Showcase::PreviewsTest < ActionView::TestCase
|
2
|
+
def self.inherited(test_class)
|
3
|
+
super
|
4
|
+
test_class.prepare
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.autorun
|
8
|
+
at_exit { prepare unless subclasses.any? }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.prepare
|
12
|
+
tests Showcase::EngineController._helpers
|
13
|
+
|
14
|
+
tree = Showcase::Path.tree
|
15
|
+
tree.flat_map(&:ordered_paths).each do |path|
|
16
|
+
test "Showcase: automatically renders showcase/previews/#{path.id}" do
|
17
|
+
render "showcase/engine/preview", preview: path.preview_for(view)
|
18
|
+
assert_showcase_preview(path.id)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
test "Showcase: isn't empty" do
|
23
|
+
assert_not_empty tree, "Showcase couldn't find any samples to generate tests for"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.test(name = nil, showcase: nil, id: nil, &block)
|
28
|
+
case
|
29
|
+
when name then super(name, &block)
|
30
|
+
when id && showcase.nil? then raise ArgumentError, "can't test a sample without a showcase"
|
31
|
+
else
|
32
|
+
super "Showcase: showcase/previews/#{showcase} #{"sample #{id}" if id}".squish do
|
33
|
+
path = Showcase::Path.new(showcase)
|
34
|
+
render "showcase/engine/preview", preview: path.preview_for(view)
|
35
|
+
|
36
|
+
assert_showcase_preview(path.id)
|
37
|
+
assert_element(id: id || path.id) { instance_eval(&block) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Override `assert_showcase_preview` to add custom assertions.
|
43
|
+
def assert_showcase_preview(id)
|
44
|
+
end
|
45
|
+
end
|
data/lib/showcase/version.rb
CHANGED
data/lib/showcase.rb
CHANGED
@@ -1,11 +1,28 @@
|
|
1
1
|
require_relative "showcase/version"
|
2
2
|
|
3
|
+
# Activate the app-bundled Rouge gem to setup default syntax highlighting.
|
4
|
+
begin
|
5
|
+
gem "rouge"
|
6
|
+
require "rouge"
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
3
10
|
module Showcase
|
4
|
-
autoload :
|
5
|
-
autoload :RouteHelper,
|
11
|
+
autoload :PreviewsTest, "showcase/previews_test"
|
12
|
+
autoload :RouteHelper, "showcase/route_helper"
|
13
|
+
autoload :Options, "showcase/options"
|
6
14
|
|
7
15
|
singleton_class.attr_accessor :sample_renderer
|
8
|
-
@sample_renderer =
|
16
|
+
@sample_renderer = proc { _1 }
|
17
|
+
|
18
|
+
if defined?(Rouge)
|
19
|
+
Formatter = Rouge::Formatters::HTML.new
|
20
|
+
|
21
|
+
@sample_renderer = ->(source, syntax) do
|
22
|
+
lexed = Rouge::Lexer.find(syntax).lex(source)
|
23
|
+
Showcase::Formatter.format(lexed).html_safe
|
24
|
+
end
|
25
|
+
end
|
9
26
|
|
10
27
|
singleton_class.attr_reader :previews_path
|
11
28
|
@previews_path = "showcase/previews"
|
@@ -15,6 +32,38 @@ module Showcase
|
|
15
32
|
Dir.glob("**/*.*", base: File.join(root, previews_path))
|
16
33
|
end.uniq
|
17
34
|
end
|
35
|
+
|
36
|
+
def self.options
|
37
|
+
Options
|
38
|
+
end
|
39
|
+
|
40
|
+
options.define :stimulus do
|
41
|
+
def targets(name, ...)
|
42
|
+
option(%(data-#{@controller}-target="#{name}"), ...)
|
43
|
+
end
|
44
|
+
|
45
|
+
def values(name, ...)
|
46
|
+
option("data-#{@controller}-#{name}-value", ...)
|
47
|
+
end
|
48
|
+
|
49
|
+
def classes(name, ...)
|
50
|
+
option("data-#{@controller}-#{name}-class", ...)
|
51
|
+
end
|
52
|
+
|
53
|
+
def outlet(name, ...)
|
54
|
+
option("data-#{@controller}-#{name}-outlet", ...)
|
55
|
+
end
|
56
|
+
|
57
|
+
def action(name, ...)
|
58
|
+
option(%(data-action="#{name}"), ...)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
options.define :nice_partials do
|
63
|
+
def content_block(*arguments, **options, &block)
|
64
|
+
option(*arguments, **options, type: "Content Block", &block)
|
65
|
+
end
|
66
|
+
end
|
18
67
|
end
|
19
68
|
|
20
69
|
require "showcase/engine" if defined?(Rails::Engine)
|
@@ -1,14 +1,14 @@
|
|
1
1
|
namespace :showcase do
|
2
2
|
namespace :install do
|
3
|
-
|
3
|
+
PREVIEWS_TEST_PATH = "test/views/showcase_test.rb"
|
4
4
|
|
5
|
-
desc "Install Showcase
|
6
|
-
task :
|
7
|
-
mkdir_p File.dirname(
|
8
|
-
File.write
|
5
|
+
desc "Install Showcase previews testing in #{PREVIEWS_TEST_PATH}"
|
6
|
+
task :previews_test do
|
7
|
+
mkdir_p File.dirname(PREVIEWS_TEST_PATH)
|
8
|
+
File.write PREVIEWS_TEST_PATH, <<~RUBY
|
9
9
|
require "test_helper"
|
10
10
|
|
11
|
-
class ShowcaseTest < Showcase::
|
11
|
+
class ShowcaseTest < Showcase::PreviewsTest
|
12
12
|
def assert_showcase_preview(id)
|
13
13
|
# Add any custom preview response body assertions here.
|
14
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: showcase-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Pence
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-03-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -50,11 +50,11 @@ files:
|
|
50
50
|
- README.md
|
51
51
|
- Rakefile
|
52
52
|
- app/assets/builds/showcase.css
|
53
|
+
- app/assets/builds/showcase.highlights.css
|
53
54
|
- app/assets/config/showcase_manifest.js
|
54
55
|
- app/assets/javascripts/showcase.js
|
55
56
|
- app/controllers/showcase/engine_controller.rb
|
56
57
|
- app/controllers/showcase/previews_controller.rb
|
57
|
-
- app/models/showcase/options.rb
|
58
58
|
- app/models/showcase/path.rb
|
59
59
|
- app/models/showcase/preview.rb
|
60
60
|
- app/models/showcase/sample.rb
|
@@ -74,7 +74,8 @@ files:
|
|
74
74
|
- lib/showcase-rails.rb
|
75
75
|
- lib/showcase.rb
|
76
76
|
- lib/showcase/engine.rb
|
77
|
-
- lib/showcase/
|
77
|
+
- lib/showcase/options.rb
|
78
|
+
- lib/showcase/previews_test.rb
|
78
79
|
- lib/showcase/route_helper.rb
|
79
80
|
- lib/showcase/version.rb
|
80
81
|
- lib/tasks/showcase_tasks.rake
|
@@ -1,51 +0,0 @@
|
|
1
|
-
class Showcase::Options
|
2
|
-
include Enumerable
|
3
|
-
|
4
|
-
def initialize(view_context)
|
5
|
-
@view_context = view_context
|
6
|
-
@options = []
|
7
|
-
@order = [:name, :required, :type, :default, :description]
|
8
|
-
end
|
9
|
-
delegate :empty?, to: :@options
|
10
|
-
|
11
|
-
def required(*arguments, **keywords, &block)
|
12
|
-
option(*arguments, **keywords, required: true, &block)
|
13
|
-
end
|
14
|
-
|
15
|
-
def optional(*arguments, **keywords, &block)
|
16
|
-
option(*arguments, **keywords, required: false, &block)
|
17
|
-
end
|
18
|
-
|
19
|
-
DEFAULT_OMITTED = Object.new
|
20
|
-
|
21
|
-
def option(name, description = nil, required: false, type: nil, default: DEFAULT_OMITTED, **options, &block)
|
22
|
-
description ||= @view_context.capture(&block).remove(/^\s+/).html_safe if block
|
23
|
-
|
24
|
-
type ||= type_from_default(default)
|
25
|
-
default = default == DEFAULT_OMITTED ? nil : default.inspect
|
26
|
-
|
27
|
-
@options << options.with_defaults(name: name, default: default, type: type, description: description, required: required)
|
28
|
-
end
|
29
|
-
|
30
|
-
def headers
|
31
|
-
@headers ||= @order | @options.flat_map(&:keys).uniq.sort
|
32
|
-
end
|
33
|
-
|
34
|
-
def each(&block)
|
35
|
-
@options.each do |option|
|
36
|
-
yield headers.index_with { option[_1] }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def type_from_default(default)
|
43
|
-
case default
|
44
|
-
when DEFAULT_OMITTED then String
|
45
|
-
when true, false then "Boolean"
|
46
|
-
when nil then "nil"
|
47
|
-
else
|
48
|
-
default.class
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
class Showcase::IntegrationTest < ActionDispatch::IntegrationTest
|
2
|
-
def self.inherited(test_class)
|
3
|
-
super
|
4
|
-
test_class.prepare
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.autorun
|
8
|
-
at_exit { prepare unless subclasses.any? }
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.prepare
|
12
|
-
tree = Showcase::Path.tree
|
13
|
-
tree.flat_map(&:ordered_paths).each do |path|
|
14
|
-
test "Showcase: GET showcase/previews/#{path.id} renders successfully" do
|
15
|
-
get showcase.preview_path(path.id)
|
16
|
-
|
17
|
-
assert_response :ok
|
18
|
-
assert_showcase_preview(path.id)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
test "Showcase: isn't empty" do
|
23
|
-
assert_not_empty tree, "Showcase couldn't find any samples to generate tests for"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Override `assert_showcase_preview` to add custom assertions.
|
28
|
-
def assert_showcase_preview(id)
|
29
|
-
end
|
30
|
-
end
|