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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24a9dbd46ccbe35d34075383efeb99bedb2825c56976b7b5ce2bb5fba294ffcc
4
- data.tar.gz: 28dc05bf705b386845aa630a188d87295ba6069445583af781478e10052d5ae8
3
+ metadata.gz: aead2040b7c095f85df0c152c6d96aa3bec927e52f49db09f407926536ce36ae
4
+ data.tar.gz: c5fd847fd56d1ffa39a4d9aae681106685c71aef2e199bbb637158ec80f43cbc
5
5
  SHA512:
6
- metadata.gz: e62b4977a6c7f8cb53fe74373e17de88870cf245ddcb449be791afb5cab22197a03aabe263aa543bde5d86bbd683e8914002ba133178825542abfe455bdbbda9
7
- data.tar.gz: 77213dbf5e976b366ec64947b0e0a0efcf50eb8b0360a7d6698e72ea452512c5d8a37f91e838c9546a98c5b6f3d6b54cca4215bb8f301ad80e31029103de068c
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
  ![](/readme/example.png?raw=true "Showcase showing a button component")
31
31
 
32
- ## Automatic integration testing
32
+ ## Using options contexts
33
33
 
34
- Showcase automatically runs integration tests for all your Showcases by rendering them and asserting they respond with `200 OK`. As long as `gem "showcase-rails"` is in the `:test` group you're set.
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
- If you want to tweak this, run `bin/rails showcase:install:integration_test` and open `test/integration/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.
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.6 | MIT License | https://tailwindcss.com
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
+ }
@@ -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
- root? ? "Previews" : id
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).tap { _1.index(...) }.ordered_children
29
- end
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
- lines = extract_block_lines_via_matched_indentation_from(*block.source_location)
38
- @source = @view_context.instance_exec(lines, &Showcase.sample_renderer)
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 extract_block_lines_via_matched_indentation_from(file, starting_index)
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>
@@ -1,4 +1,4 @@
1
- <div class="sc-space-y-8">
1
+ <div class="sc-space-y-8" id="<%= preview.id %>">
2
2
  <section>
3
3
  <% if preview.title %>
4
4
  <div class="sc-flex sc-items-center sc-space-x-2 sc-mb-2">
@@ -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
- <%= sample.source %>
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>
@@ -6,8 +6,8 @@ module Showcase
6
6
  config.assets.precompile += %w[showcase_manifest]
7
7
  end
8
8
 
9
- initializer "showcase.integration_test.autorun" do
10
- Showcase::IntegrationTest.autorun if Rails.env.test?
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
@@ -1,3 +1,3 @@
1
1
  module Showcase
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.4"
3
3
  end
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 :IntegrationTest, "showcase/integration_test"
5
- autoload :RouteHelper, "showcase/route_helper"
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 = ->(lines) { tag.pre lines.join.strip_heredoc }
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
- INTEGRATION_TEST_PATH = "test/integration/showcase_test.rb"
3
+ PREVIEWS_TEST_PATH = "test/views/showcase_test.rb"
4
4
 
5
- desc "Install Showcase integration testing in #{INTEGRATION_TEST_PATH}"
6
- task :integration_test do
7
- mkdir_p File.dirname(INTEGRATION_TEST_PATH)
8
- File.write INTEGRATION_TEST_PATH, <<~RUBY
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::IntegrationTest
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.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-02-13 00:00:00.000000000 Z
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/integration_test.rb
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