showcase-rails 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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