super 0.0.13 → 0.0.14

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.
@@ -5,10 +5,14 @@ module Super
5
5
  source_root File.expand_path("templates", __dir__)
6
6
 
7
7
  def copy_the_pack_file
8
- template(
9
- "pack_super_application.js.erb",
10
- "app/javascript/packs/super/application.js.erb"
11
- )
8
+ path =
9
+ if Gem::Dependency.new("webpacker", ">= 6.0.0.beta2", "!= 6.0.0.pre1", "!= 6.0.0.pre2").matching_specs.any?
10
+ "app/packs/entrypoints/super/application.js.erb"
11
+ else
12
+ "app/javascript/packs/super/application.js.erb"
13
+ end
14
+
15
+ template("pack_super_application.js.erb", path)
12
16
  end
13
17
 
14
18
  def set_asset_handler_to_webpacker
@@ -16,7 +20,7 @@ module Super
16
20
  "config/initializers/super.rb",
17
21
  " c.javascripts = Super::Assets.use_webpacker(c.javascripts)\n" \
18
22
  " c.stylesheets = Super::Assets.use_webpacker(c.stylesheets)\n",
19
- before: /\bend\b/
23
+ before: /^end\b/
20
24
  )
21
25
  end
22
26
 
data/lib/super.rb CHANGED
@@ -31,7 +31,8 @@ require "super/form/schema_types"
31
31
  require "super/form/strong_params"
32
32
  require "super/layout"
33
33
  require "super/link"
34
- require "super/navigation/automatic"
34
+ require "super/link_builder"
35
+ require "super/navigation"
35
36
  require "super/pagination"
36
37
  require "super/panel"
37
38
  require "super/partial"
data/lib/super/assets.rb CHANGED
@@ -21,7 +21,7 @@ module Super
21
21
  assets.map do |asset|
22
22
  grep_matches = grep && asset === grep
23
23
  if grep_matches || !grep
24
- asset.instance_variable_set(:@handler, Handler.webpacker)
24
+ asset.send(:handler=, Handler.webpacker)
25
25
  end
26
26
 
27
27
  asset
@@ -34,7 +34,7 @@ module Super
34
34
  assets.map do |asset|
35
35
  grep_matches = grep && asset === grep
36
36
  if grep_matches || !grep
37
- asset.instance_variable_set(:@asset_handler, Handler.sprockets)
37
+ asset.send(:handler=, Handler.sprockets)
38
38
  end
39
39
 
40
40
  asset
@@ -52,6 +52,14 @@ module Super
52
52
  attr_reader :path
53
53
  attr_reader :arguments
54
54
 
55
+ def ==(other)
56
+ return false if handler != other.handler
57
+ return false if path != other.path
58
+ return false if arguments != other.arguments
59
+
60
+ true
61
+ end
62
+
55
63
  def ===(other)
56
64
  return true if path == other
57
65
  return true if other.is_a?(Regexp) && path.match?(other)
@@ -61,6 +69,10 @@ module Super
61
69
 
62
70
  false
63
71
  end
72
+
73
+ private
74
+
75
+ attr_writer :handler
64
76
  end
65
77
 
66
78
  def self.dist(gem_name, package_name)
@@ -74,29 +86,34 @@ module Super
74
86
  end
75
87
 
76
88
  class Handler
77
- def self.auto
78
- @auto ||=
79
- if Gem::Dependency.new("sprockets", "~> 4.0").matching_specs.any?
80
- sprockets
81
- elsif Gem::Dependency.new("sprockets", "~> 3.0").matching_specs.any?
82
- sprockets
83
- elsif Gem::Dependency.new("sprockets", "~> 2.0").matching_specs.any?
84
- sprockets
85
- elsif Gem::Dependency.new("webpacker", "~> 6.0").matching_specs.any?
86
- webpacker
87
- elsif Gem::Dependency.new("webpacker", "~> 5.0").matching_specs.any?
88
- webpacker
89
- elsif Gem::Dependency.new("webpacker", "~> 4.0").matching_specs.any?
90
- webpacker
91
- elsif Gem::Dependency.new("webpacker", "~> 3.0").matching_specs.any?
92
- webpacker
93
- else
94
- none
89
+ class << self
90
+ def auto
91
+ sprockets_spec = gem_specification("sprockets")
92
+ if sprockets_spec
93
+ major = sprockets_spec.version.segments.first
94
+ if major >= 2
95
+ return sprockets
96
+ end
97
+ end
98
+
99
+ webpacker_spec = gem_specification("webpacker")
100
+ if webpacker_spec
101
+ major = webpacker_spec.version.segments.first
102
+ if major >= 4
103
+ return webpacker
104
+ end
95
105
  end
96
- end
97
106
 
98
- def self.sprockets_available?
99
- Gem::Dependency.new("sprockets").matching_specs.any? && defined?(Sprockets)
107
+ none
108
+ end
109
+
110
+ def sprockets_available?
111
+ !gem_specification("sprockets").nil? && defined?(Sprockets)
112
+ end
113
+
114
+ def gem_specification(gem_name)
115
+ Gem::Dependency.new(gem_name).matching_specs&.sort_by(&:version)&.first
116
+ end
100
117
  end
101
118
 
102
119
  def self.sprockets
@@ -115,6 +132,10 @@ module Super
115
132
  @asset_handler = asset_handler
116
133
  end
117
134
 
135
+ def ==(other)
136
+ to_sym == other.to_sym
137
+ end
138
+
118
139
  def sprockets?
119
140
  @asset_handler == :sprockets
120
141
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Cheat
5
+ def controls
6
+ paths = %w[controls.rb controls/optional.rb controls/steps.rb controls/view.rb]
7
+ methods =
8
+ paths
9
+ .map { |f| File.read(File.join(__dir__, f)) }
10
+ .flat_map { |content| content.scan(/^\s+def .*$/) }
11
+ .map { |method| method.strip.sub(/^def /, "#") }
12
+
13
+ puts "== Super::Controls"
14
+ puts methods.join("\n")
15
+ end
16
+ end
17
+ end
@@ -23,5 +23,24 @@ module Super
23
23
  ActiveRecord::Base.sanitize_sql_like(query)
24
24
  end
25
25
  end
26
+
27
+ def polymorphic_path_container
28
+ if Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 0
29
+ @polymorphic_path_container ||=
30
+ begin
31
+ klass = Class.new do
32
+ include ActionDispatch::Routing::PolymorphicRoutes
33
+
34
+ def method_missing(method_name)
35
+ Rails.application.routes.url_helpers.public_send(method_name)
36
+ end
37
+ end
38
+
39
+ klass.new
40
+ end
41
+ else
42
+ Rails.application.routes.url_helpers
43
+ end
44
+ end
26
45
  end
27
46
  end
data/lib/super/link.rb CHANGED
@@ -22,57 +22,57 @@ module Super
22
22
 
23
23
  def self.registry
24
24
  @registry ||= {
25
- new: new(
25
+ new: LinkBuilder.new(
26
26
  "New",
27
27
  -> (params:) {
28
- Rails.application.routes.url_for(
28
+ {
29
29
  controller: params[:controller],
30
30
  action: :new,
31
31
  only_path: true
32
- )
32
+ }
33
33
  }
34
34
  ),
35
- index: new(
35
+ index: LinkBuilder.new(
36
36
  "Index",
37
37
  -> (params:) {
38
- Rails.application.routes.url_for(
38
+ {
39
39
  controller: params[:controller],
40
40
  action: :index,
41
41
  only_path: true
42
- )
42
+ }
43
43
  }
44
44
  ),
45
- show: new(
45
+ show: LinkBuilder.new(
46
46
  "View",
47
47
  -> (record:, params:) {
48
- Rails.application.routes.url_for(
48
+ {
49
49
  controller: params[:controller],
50
50
  action: :show,
51
51
  id: record,
52
52
  only_path: true
53
- )
53
+ }
54
54
  }
55
55
  ),
56
- edit: new(
56
+ edit: LinkBuilder.new(
57
57
  "Edit",
58
58
  -> (record:, params:) {
59
- Rails.application.routes.url_for(
59
+ {
60
60
  controller: params[:controller],
61
61
  action: :edit,
62
62
  id: record,
63
63
  only_path: true
64
- )
64
+ }
65
65
  }
66
66
  ),
67
- destroy: new(
67
+ destroy: LinkBuilder.new(
68
68
  "Delete",
69
69
  -> (record:, params:) {
70
- Rails.application.routes.url_for(
70
+ {
71
71
  controller: params[:controller],
72
72
  action: :destroy,
73
73
  id: record,
74
74
  only_path: true
75
- )
75
+ }
76
76
  },
77
77
  method: :delete,
78
78
  data: { confirm: "Really delete?" }
@@ -91,27 +91,33 @@ module Super
91
91
  @options = options
92
92
  end
93
93
 
94
- def to_s(default_options: nil, **proc_arguments)
94
+ attr_reader :text
95
+ attr_reader :options
96
+
97
+ def href
98
+ if @href.is_a?(String)
99
+ return @href
100
+ end
101
+
102
+ if @href.is_a?(Hash)
103
+ @href = Rails.application.routes.url_for(**@href)
104
+ return @href
105
+ end
106
+
107
+ @href = Super::Compatability.polymorphic_path_container.polymorphic_path(@href)
108
+ end
109
+
110
+ def to_s(default_options: nil)
95
111
  default_options ||= {}
96
112
  ActionController::Base.helpers.link_to(
97
- value(text, proc_arguments),
98
- value(href, proc_arguments),
99
- default_options.deep_merge(value(options, proc_arguments))
113
+ text,
114
+ href,
115
+ default_options.deep_merge(options)
100
116
  )
101
117
  end
102
118
 
103
- private
104
-
105
- attr_reader :text
106
- attr_reader :href
107
- attr_reader :options
108
-
109
- def value(proc_or_value, proc_arguments)
110
- if proc_or_value.kind_of?(Proc)
111
- proc_or_value.call(**proc_arguments)
112
- else
113
- proc_or_value
114
- end
119
+ def ==(other)
120
+ self.class == other.class && text == other.text && href == other.href && options == other.options
115
121
  end
116
122
  end
117
123
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class LinkBuilder
5
+ def initialize(text, href, **options)
6
+ @text = text
7
+ @href = href
8
+ @options = options
9
+ @requirements = []
10
+ @requirements += gather_requirements(text)
11
+ @requirements += gather_requirements(href)
12
+ @requirements += gather_requirements(options)
13
+
14
+ unknown_arguments = @requirements - known_requirements
15
+ if unknown_arguments.any?
16
+ raise Error::ArgumentError, "Unknown arguments: #{unknown_arguments.join(", ")}"
17
+ end
18
+ end
19
+
20
+ attr_reader :requirements
21
+
22
+ def to_s(default_options: nil, **kwargs)
23
+ resolve(**kwargs).to_s(default_options: default_options)
24
+ end
25
+
26
+ def resolve(**kwargs)
27
+ Link.new(
28
+ into_value(@text, kwargs),
29
+ into_value(@href, kwargs),
30
+ **into_value(@options, kwargs),
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def known_requirements
37
+ %i[params record].freeze
38
+ end
39
+
40
+ def gather_requirements(value_or_proc)
41
+ return [] if !value_or_proc.is_a?(Proc)
42
+
43
+ requirements =
44
+ value_or_proc
45
+ .parameters
46
+ .select { |(kind, name)| kind = :keyreq }
47
+ .map(&:last)
48
+ end
49
+
50
+ def into_value(value_or_proc, kwargs)
51
+ if value_or_proc.kind_of?(Proc)
52
+ value_or_proc.call(**kwargs)
53
+ else
54
+ value_or_proc
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class Navigation
5
+ def initialize
6
+ @builder = Builder.new
7
+ @definition = yield @builder
8
+ if !@definition.is_a?(Array)
9
+ @definition = [@definition]
10
+ end
11
+ end
12
+
13
+ def definition
14
+ return @defs if instance_variable_defined?(:@defs)
15
+
16
+ searcher = RouteFormatterButReallySearcher.new
17
+ inspector = ActionDispatch::Routing::RoutesInspector.new(Rails.application.routes.routes)
18
+ inspector.format(searcher)
19
+ all_matches = searcher.matches
20
+ unused_matches = all_matches.each_with_object({}) { |match, hash| hash[match] = true }
21
+
22
+ defs = expand_proc_syntax_sugar(@definition)
23
+ defs = validate_and_determine_explicit_links(defs, unused_matches)
24
+ @defs = expand_directives(defs, all_matches, unused_matches.keys)
25
+ end
26
+
27
+ private
28
+
29
+ # This expands the syntax sugar that allows `nav.menu("Name")[nav.link(Item)]`
30
+ def expand_proc_syntax_sugar(definition)
31
+ definition.map do |link_or_menu_or_rest_or_menuproc|
32
+ link_or_menu_or_rest =
33
+ if link_or_menu_or_rest_or_menuproc.is_a?(Proc)
34
+ link_or_menu_or_rest_or_menuproc.call
35
+ else
36
+ link_or_menu_or_rest_or_menuproc
37
+ end
38
+
39
+ if link_or_menu_or_rest.is_a?(Menu)
40
+ link_or_menu_or_rest.links = link_or_menu_or_rest.links.map do |menu_item|
41
+ if menu_item.is_a?(Proc)
42
+ menu_item.call
43
+ else
44
+ menu_item
45
+ end
46
+ end
47
+ end
48
+
49
+ link_or_menu_or_rest
50
+ end
51
+ end
52
+
53
+ def validate_and_determine_explicit_links(definition, unused_links)
54
+ definition.each do |link_or_menu_or_rest|
55
+ if link_or_menu_or_rest.is_a?(Super::Link)
56
+ unused_links.delete(link_or_menu_or_rest.href)
57
+ elsif link_or_menu_or_rest.is_a?(Menu)
58
+ link_or_menu_or_rest.links.each do |link_or_rest|
59
+ if link_or_rest.is_a?(Menu)
60
+ raise Super::Error::ArgumentError, "Navigation menus can't be nested"
61
+ end
62
+
63
+ if link_or_rest.is_a?(Link)
64
+ unused_links.delete(link_or_rest.href)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def expand_directives(defs, all_hrefs, rest_hrefs)
72
+ defs.flat_map do |link_or_menu_or_rest|
73
+ if link_or_menu_or_rest.is_a?(Menu)
74
+ link_or_menu_or_rest.links = link_or_menu_or_rest.links.flat_map do |link_or_rest|
75
+ if link_or_rest == ALL
76
+ linkify_hrefs(all_hrefs)
77
+ elsif link_or_rest == REST
78
+ linkify_hrefs(rest_hrefs)
79
+ else
80
+ link_or_rest
81
+ end
82
+ end
83
+
84
+ link_or_menu_or_rest
85
+ elsif link_or_menu_or_rest == ALL
86
+ linkify_hrefs(all_hrefs)
87
+ elsif link_or_menu_or_rest == REST
88
+ linkify_hrefs(rest_hrefs)
89
+ else
90
+ link_or_menu_or_rest
91
+ end
92
+ end
93
+ end
94
+
95
+ def linkify_hrefs(hrefs)
96
+ hrefs.map do |href|
97
+ Super::Link.new(href.split("/").last.humanize, href)
98
+ end
99
+ end
100
+
101
+ ALL = Object.new
102
+ REST = Object.new
103
+ Menu = Struct.new(:title, :links)
104
+
105
+ class Builder
106
+ def link(model, **kwargs)
107
+ text = model.model_name.human.pluralize
108
+ parts = Super::Link.polymorphic_parts(model)
109
+
110
+ Super::Link.new(text, parts, **kwargs)
111
+ end
112
+
113
+ def link_to(*args, **kwargs)
114
+ Super::Link.new(*args, **kwargs)
115
+ end
116
+
117
+ def menu(title, *links)
118
+ menu = Menu.new(title, links)
119
+ proc do |*more_links|
120
+ menu.links += more_links
121
+ menu
122
+ end
123
+ end
124
+
125
+ def rest
126
+ REST
127
+ end
128
+
129
+ def all
130
+ ALL
131
+ end
132
+ end
133
+
134
+ class RouteFormatterButReallySearcher
135
+ def initialize(route_namespace: Super.configuration.path)
136
+ @route_namespace = route_namespace.strip.gsub(%r{\A/+}, "").gsub(%r{/+\z}, "").strip
137
+ @route_namespace = "/#{@route_namespace}/"
138
+ @matches = []
139
+ end
140
+
141
+ def matches
142
+ @matches.map do |route|
143
+ route[:path].sub(/\(.*\)\Z/, "")
144
+ end
145
+ end
146
+
147
+ def section(routes)
148
+ @matches += routes.select do |route|
149
+ next false unless route[:verb] == "GET" || route[:verb] == ""
150
+ next false unless route[:path].start_with?(@route_namespace)
151
+ next false if route[:path].include?("/:")
152
+ next false if route[:reqs].end_with?("#new")
153
+
154
+ true
155
+ end
156
+ end
157
+
158
+ def header(routes); end
159
+ def no_routes(routes, filter); end
160
+ def result; end
161
+ def section_title(title); end
162
+ end
163
+ end
164
+ end