showcase-rails 0.2.2 → 0.2.3

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: '081d707dee9578e786c17cb621826f685bf2a4f9eab5221037b2394ac3b6805b'
4
+ data.tar.gz: 46fad2bf9b84aba2bf22bf0a627eb225ee904cd67da55cda4c0690b34d8d5a07
5
5
  SHA512:
6
- metadata.gz: e62b4977a6c7f8cb53fe74373e17de88870cf245ddcb449be791afb5cab22197a03aabe263aa543bde5d86bbd683e8914002ba133178825542abfe455bdbbda9
7
- data.tar.gz: 77213dbf5e976b366ec64947b0e0a0efcf50eb8b0360a7d6698e72ea452512c5d8a37f91e838c9546a98c5b6f3d6b54cca4215bb8f301ad80e31029103de068c
6
+ metadata.gz: 480d2d5a3c891703603caec5131d3990e19d31c97e815c622d8c6152ec2c1519a430e55416fc63caab1d7f136dd0fe96bf9e45a39bbf854e39134339822f6157
7
+ data.tar.gz: d35a92bd276b05225cdb827a9d3ec832665e1b0978b2ec02294ecc3d0810fee926fbb5f58d989612177ebe879d833ea8a476057efa04ca845d5e3e2b1808694a
data/README.md CHANGED
@@ -29,6 +29,31 @@ Which will then render the following:
29
29
 
30
30
  ![](/readme/example.png?raw=true "Showcase showing a button component")
31
31
 
32
+ ## Using options contexts
33
+
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
+
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
+
32
57
  ## Automatic integration testing
33
58
 
34
59
  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.
@@ -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
  /*
@@ -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)
@@ -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>
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Showcase
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
data/lib/showcase.rb CHANGED
@@ -3,6 +3,7 @@ require_relative "showcase/version"
3
3
  module Showcase
4
4
  autoload :IntegrationTest, "showcase/integration_test"
5
5
  autoload :RouteHelper, "showcase/route_helper"
6
+ autoload :Options, "showcase/options"
6
7
 
7
8
  singleton_class.attr_accessor :sample_renderer
8
9
  @sample_renderer = ->(lines) { tag.pre lines.join.strip_heredoc }
@@ -15,6 +16,38 @@ module Showcase
15
16
  Dir.glob("**/*.*", base: File.join(root, previews_path))
16
17
  end.uniq
17
18
  end
19
+
20
+ def self.options
21
+ Options
22
+ end
23
+
24
+ options.define :stimulus do
25
+ def targets(name, ...)
26
+ option(%(data-#{@controller}-target="#{name}"), ...)
27
+ end
28
+
29
+ def values(name, ...)
30
+ option("data-#{@controller}-#{name}-value", ...)
31
+ end
32
+
33
+ def classes(name, ...)
34
+ option("data-#{@controller}-#{name}-class", ...)
35
+ end
36
+
37
+ def outlet(name, ...)
38
+ option("data-#{@controller}-#{name}-outlet", ...)
39
+ end
40
+
41
+ def action(name, ...)
42
+ option(%(data-action="#{name}"), ...)
43
+ end
44
+ end
45
+
46
+ options.define :nice_partials do
47
+ def content_block(*arguments, **options, &block)
48
+ option(*arguments, **options, type: "Content Block", &block)
49
+ end
50
+ end
18
51
  end
19
52
 
20
53
  require "showcase/engine" if defined?(Rails::Engine)
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.3
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-02-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -54,7 +54,6 @@ files:
54
54
  - app/assets/javascripts/showcase.js
55
55
  - app/controllers/showcase/engine_controller.rb
56
56
  - app/controllers/showcase/previews_controller.rb
57
- - app/models/showcase/options.rb
58
57
  - app/models/showcase/path.rb
59
58
  - app/models/showcase/preview.rb
60
59
  - app/models/showcase/sample.rb
@@ -75,6 +74,7 @@ files:
75
74
  - lib/showcase.rb
76
75
  - lib/showcase/engine.rb
77
76
  - lib/showcase/integration_test.rb
77
+ - lib/showcase/options.rb
78
78
  - lib/showcase/route_helper.rb
79
79
  - lib/showcase/version.rb
80
80
  - lib/tasks/showcase_tasks.rake
@@ -100,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
102
  requirements: []
103
- rubygems_version: 3.4.1
103
+ rubygems_version: 3.4.7
104
104
  signing_key:
105
105
  specification_version: 4
106
106
  summary: Showcase helps you show off and document your partials, components, view
@@ -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