menuable 0.1.0 → 0.1.2

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: d7cd924adb10768078fdf03b62129b6bfd9a90ef7425777cc94d4bfa6fbd4ed7
4
- data.tar.gz: 24f889651399a85900f5e6b18ca57a02e5fa129137021c45f94bc3c9c98ab8b1
3
+ metadata.gz: f3e428de3e6e6e19e26e5eebbdf163677fc2dac048610e572a0c1c9e8473375f
4
+ data.tar.gz: abdd56584c6ceeb8854dceea90bad7c41134b28c3211c2d4ae5a6a99c4415e0f
5
5
  SHA512:
6
- metadata.gz: 15bd6260b99ffffab22ea211731a17c85ae5bb35978d78e5e7dac0d2b3a4112c24df2be5ec92f50898c4084dc70b9a95dcf942d8023dfe0210f9c45d3dffb9b7
7
- data.tar.gz: 681c86be7c17653563d8f00ca77a841c5bacc2aacd4762ea61b10a278a499eafb03d995ba46d65ea7f96de0a09d77a40c3490f9640dba7267415bcf3dc4ddd27
6
+ metadata.gz: 410d422e140b3e3f922a763df3086cf982c31cb18e5dcda9d4203189a383ef7af55bb1ac18922fdf1853849eb2dda14ae9e4f241941979266ea449d97f44a6a6
7
+ data.tar.gz: b1c01be9f31432e70d7b5667361b54ed414ab9b19d09f01f74ca6cb672af7c31c4d869560f422ad2c53150d67dcb3af0a1c4b36e2dda3ecefa45789ef489233e
data/.rubocop.yml CHANGED
@@ -1,5 +1,11 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rake
4
+ - rubocop-rspec
5
+
1
6
  AllCops:
2
7
  TargetRubyVersion: 3.2.2
8
+ NewCops: enable
3
9
 
4
10
  Style/StringLiterals:
5
11
  Enabled: true
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Menuable
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/menuable.rb CHANGED
@@ -3,51 +3,65 @@
3
3
  require_relative "menuable/version"
4
4
  require "active_support/all"
5
5
 
6
+ #
7
+ # Menuable is a module for dynamically generating sidemenus
8
+ #
6
9
  module Menuable
7
10
  extend ActiveSupport::Concern
8
11
 
9
12
  class_methods do
10
- def menu(resource_name, &block)
11
- namespace = self.name.to_s.deconstantize.constantize
13
+ def resource(resource_name, **options, &)
14
+ resources(resource_name, single: true, **options, &)
15
+ end
16
+
17
+ def resources(resource_name, single: false, **options, &block)
18
+ namespace = name.to_s.deconstantize.constantize
12
19
 
13
20
  menu = Class.new(MenuDefinition)
14
- menu.namespace =
15
- self.name.split("::").try do |token|
16
- token.shift
17
- token.pop
18
- token.first&.underscore
19
- end
21
+ menu.options = options
22
+ menu.single = single
20
23
  menu.resource_name = resource_name
21
24
  menu.model_name = ActiveModel::Name.new(nil, nil, "#{namespace}/#{resource_name.to_s.classify}")
22
25
  menu.instance_eval(&block) if block
23
26
 
24
- self.class_eval do
27
+ class_eval do
25
28
  class_attribute :menu, default: menu
26
29
  end
27
30
  end
28
31
  end
29
32
 
33
+ #
34
+ # Value to set from controller
35
+ #
30
36
  class MenuDefinition
31
- class_attribute :namespace
37
+ class_attribute :options
32
38
  class_attribute :resource_name
33
39
  class_attribute :model_name
34
- class_attribute :name
40
+ class_attribute :single
35
41
 
36
42
  NOTHING = ->(_) { true }
37
43
 
44
+ def self.single?
45
+ single
46
+ end
47
+
38
48
  def self.loyalty(&value)
39
49
  return (@loyalty || NOTHING) if value.nil?
40
50
 
41
51
  @loyalty = value
42
52
  end
43
53
 
44
- def self.member_actions(values = nil)
45
- return Array(@member_actions) if values.nil?
54
+ def self.actions(&value)
55
+ return @actions if value.nil?
46
56
 
47
- @member_actions = values
57
+ @actions = value
48
58
  end
49
59
  end
50
60
 
61
+ #
62
+ # A class for binding with view_content to convert the settings defined in yaml
63
+ # into something that can actually be used
64
+ #
51
65
  class MenuContext
52
66
  attr_reader :context
53
67
 
@@ -56,14 +70,15 @@ module Menuable
56
70
  @context = context
57
71
  end
58
72
 
59
- def each
73
+ def each # rubocop:todo Metrics/MethodLength
74
+ return enum_for(:each) unless block_given?
75
+
60
76
  @menus.each do |config|
61
77
  case config
62
78
  in divider:
63
79
  yield config
64
- in group:
65
- items = config[:items].filter_map { |item| menu(item) }
66
- yield menu({ **config, items: })
80
+ in items:
81
+ yield menu({ **config, items: items.filter_map { |item| menu(item) } })
67
82
  else
68
83
  menu(config).try { yield _1 }
69
84
  end
@@ -84,7 +99,7 @@ module Menuable
84
99
  path || config[:path] || "/"
85
100
  end
86
101
 
87
- def active?(menu)
102
+ def active?(menu) # rubocop:todo Metrics/MethodLength
88
103
  case menu
89
104
  in items:
90
105
  items.any? do |item|
@@ -110,18 +125,37 @@ module Menuable
110
125
  end
111
126
  end
112
127
 
128
+ #
129
+ # The actual state of the definition body that reads YAML
130
+ #
113
131
  class Menu
114
- def initialize(namespace, path)
115
- @controllers = []
132
+ def initialize(namespace, path) # rubocop:todo Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
133
+ extract_namespace = lambda do |name|
134
+ if name
135
+ namespaces = name.split("/")
136
+ namespaces.pop
137
+ namespaces
138
+ else
139
+ []
140
+ end
141
+ end
142
+
143
+ @controllers = {}
116
144
  @menus = YAML.load_file(path).map do |config|
117
145
  config.deep_symbolize_keys!
118
- controller = "#{namespace}/#{config[:name]}_controller".classify.safe_constantize
119
- @controllers << controller if controller
146
+ namespaces = extract_namespace.call(config[:name])
147
+ controller = "#{namespace}/#{config[:name]&.pluralize}_controller".classify.safe_constantize
148
+ @controllers[namespaces] ||= []
149
+ @controllers[namespaces] << controller if controller
150
+
120
151
  config[:items]&.each do |item|
121
- item[:controller] = "#{namespace}/#{item[:name]}_controller".classify.safe_constantize
122
- @controllers << item[:controller] if item[:controller]
152
+ item[:controller] = "#{namespace}/#{item[:name]&.pluralize}_controller".classify.safe_constantize
153
+ item_namespaces = extract_namespace.call(item[:name])
154
+ @controllers[item_namespaces] ||= []
155
+ @controllers[item_namespaces] << item[:controller] if item[:controller]
123
156
  end
124
- { **config, controller: }
157
+
158
+ { **config, controller:, namespaces: }
125
159
  end
126
160
  end
127
161
 
@@ -134,29 +168,47 @@ module Menuable
134
168
  end
135
169
 
136
170
  def first(current_user:)
137
- @controllers.each do |controller|
171
+ @controllers.values.flatten.each do |controller|
138
172
  break controller.menu if controller.menu.loyalty.call(current_user)
139
173
  end
140
174
  end
141
175
 
142
- def routes(routing)
143
- controllers = @controllers
144
- routing.instance_eval do
145
- controllers.each do |controller|
146
- if controller.menu.namespace
147
- namespace controller.menu.namespace do
148
- resources controller.menu.resource_name do
149
- controller.menu.member_actions.each do |action_name|
150
- get action_name, on: :member
176
+ def routes(routing) # rubocop:todo Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
177
+ controller_mappings = @controllers
178
+ routing.instance_eval do # rubocop:todo Metrics/BlockLength
179
+ controller_mappings.each do |namespaces, controllers| # rubocop:todo Metrics/BlockLength
180
+ define =
181
+ controllers.map do |controller|
182
+ if controller.menu.single?
183
+ lambda do |router|
184
+ router.resource controller.menu.resource_name do
185
+ router.instance_eval(&controller.menu.actions) if controller.menu.actions
186
+ end
187
+ end
188
+ else
189
+ lambda do |router|
190
+ router.resources controller.menu.resource_name do
191
+ router.instance_eval(&controller.menu.actions) if controller.menu.actions
192
+ end
151
193
  end
152
194
  end
153
195
  end
154
- else
155
- resources controller.menu.resource_name do
156
- controller.menu.member_actions.each do |action_name|
157
- get action_name, on: :member
196
+
197
+ case namespaces.length
198
+ when 3
199
+ namespace namespaces[0] do
200
+ namespace namespaces[1] do
201
+ namespace namespaces[2] { define.each { _1.call(self) } }
158
202
  end
159
203
  end
204
+ when 2
205
+ namespace namespaces[0] do
206
+ namespace(namespaces[1]) { define.each { _1.call(self) } }
207
+ end
208
+ when 1
209
+ namespace(namespaces[0]) { define.each { _1.call(self) } }
210
+ when 0
211
+ define.each { _1.call(self) }
160
212
  end
161
213
  end
162
214
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: menuable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masa (Aileron inc)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-17 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2023-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description: 'This library provides menu.yml and controller macros to manage routes
14
28
  and sidebar implementations when implementing management functions in rails.
15
29
 
@@ -38,6 +52,7 @@ metadata:
38
52
  homepage_uri: https://github.com/aileron-inc/menuable
39
53
  source_code_uri: https://github.com/aileron-inc/menuable
40
54
  changelog_uri: https://github.com/aileron-inc/menuable
55
+ rubygems_mfa_required: 'true'
41
56
  post_install_message:
42
57
  rdoc_options: []
43
58
  require_paths: