pakyow-reflection 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE +4 -0
- data/README.md +29 -0
- data/lib/pakyow/application/behavior/reflection/reflecting.rb +54 -0
- data/lib/pakyow/application/config/reflection.rb +33 -0
- data/lib/pakyow/presenter/renderer/behavior/reflection/install_form_metadata.rb +30 -0
- data/lib/pakyow/reflection.rb +12 -0
- data/lib/pakyow/reflection/action.rb +30 -0
- data/lib/pakyow/reflection/attribute.rb +30 -0
- data/lib/pakyow/reflection/builders/actions.rb +81 -0
- data/lib/pakyow/reflection/builders/base.rb +13 -0
- data/lib/pakyow/reflection/builders/endpoints.rb +87 -0
- data/lib/pakyow/reflection/builders/helpers/controller.rb +234 -0
- data/lib/pakyow/reflection/builders/source.rb +60 -0
- data/lib/pakyow/reflection/endpoint.rb +84 -0
- data/lib/pakyow/reflection/extensions/controller.rb +314 -0
- data/lib/pakyow/reflection/framework.rb +67 -0
- data/lib/pakyow/reflection/mirror.rb +350 -0
- data/lib/pakyow/reflection/nested.rb +30 -0
- data/lib/pakyow/reflection/scope.rb +67 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d9e1be2fff54bd5e80f3768b5b5dd97807f1487b6d59fd7815cde828d9d17ed7
|
4
|
+
data.tar.gz: c7210f0d4c895b4f1148a7a78ed3f6ae13bac65608bcdfce2cca997babbb6d0a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d48551b8e337febffedfa1415d11f0e695c9510e784ea8b802cb16e1868db51ca5470c6485a9081776cce0f6944cef8862cb57ee6e0868270dbddf2ebd063db8
|
7
|
+
data.tar.gz: 89f0632f6218b457a13e6401615a7df6d45faf58fc3c03080526ff3db2599492111eff260c7b87163f476a69e9502f44d3a1ce533e1f17b248c757b671a6b61d
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# pakyow-reflection
|
2
|
+
|
3
|
+
Reflected behavior for Pakyow.
|
4
|
+
|
5
|
+
# Download
|
6
|
+
|
7
|
+
The latest version of Pakyow Reflection can be installed with RubyGems:
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install pakyow-reflection
|
11
|
+
```
|
12
|
+
|
13
|
+
Source code can be downloaded as part of the Pakyow project on Github:
|
14
|
+
|
15
|
+
- https://github.com/pakyow/pakyow/tree/master/pakyow-reflection
|
16
|
+
|
17
|
+
# License
|
18
|
+
|
19
|
+
Pakyow Reflection is free and open-source under the [LGPLv3 license](https://choosealicense.com/licenses/gpl-3.0/).
|
20
|
+
|
21
|
+
# Support
|
22
|
+
|
23
|
+
Found a bug? Tell us about it here:
|
24
|
+
|
25
|
+
- https://github.com/pakyow/pakyow/issues
|
26
|
+
|
27
|
+
We'd love to have you in the community:
|
28
|
+
|
29
|
+
- http://pakyow.org/get-involved
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/class_state"
|
4
|
+
|
5
|
+
require "pakyow/reflection/mirror"
|
6
|
+
|
7
|
+
module Pakyow
|
8
|
+
class Application
|
9
|
+
module Behavior
|
10
|
+
module Reflection
|
11
|
+
module Reflecting
|
12
|
+
extend Support::Extension
|
13
|
+
|
14
|
+
apply_extension do
|
15
|
+
attr_reader :mirror
|
16
|
+
|
17
|
+
after "initialize", priority: :high do
|
18
|
+
@mirror = Pakyow::Reflection::Mirror.new(self)
|
19
|
+
|
20
|
+
builders = Hash[
|
21
|
+
config.reflection.builders.map { |type, builder|
|
22
|
+
[type, builder.new(self, @mirror.scopes)]
|
23
|
+
}
|
24
|
+
]
|
25
|
+
|
26
|
+
# Build the scopes.
|
27
|
+
#
|
28
|
+
@mirror.scopes.each do |scope|
|
29
|
+
builders[:source].build(scope)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Build the actions.
|
33
|
+
#
|
34
|
+
@mirror.scopes.each do |scope|
|
35
|
+
builders[:actions].build(scope.actions)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Build the endpoints.
|
39
|
+
#
|
40
|
+
builders[:endpoints].build(@mirror.endpoints)
|
41
|
+
|
42
|
+
# Cleanup.
|
43
|
+
#
|
44
|
+
unless Pakyow.env?(:test)
|
45
|
+
@mirror.scopes.each(&:cleanup)
|
46
|
+
@mirror.endpoints.each(&:cleanup)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/class_state"
|
4
|
+
|
5
|
+
require "pakyow/reflection/builders/source"
|
6
|
+
require "pakyow/reflection/builders/endpoints"
|
7
|
+
require "pakyow/reflection/builders/actions"
|
8
|
+
|
9
|
+
module Pakyow
|
10
|
+
class Application
|
11
|
+
module Config
|
12
|
+
module Reflection
|
13
|
+
extend Support::Extension
|
14
|
+
|
15
|
+
apply_extension do
|
16
|
+
configurable :reflection do
|
17
|
+
setting :builders, {
|
18
|
+
source: Pakyow::Reflection::Builders::Source,
|
19
|
+
endpoints: Pakyow::Reflection::Builders::Endpoints,
|
20
|
+
actions: Pakyow::Reflection::Builders::Actions
|
21
|
+
}
|
22
|
+
|
23
|
+
setting :ignored_template_stores, [:errors]
|
24
|
+
|
25
|
+
configurable :data do
|
26
|
+
setting :connection, :default
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/extension"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Presenter
|
7
|
+
class Renderer
|
8
|
+
module Behavior
|
9
|
+
module Reflection
|
10
|
+
module InstallFormMetadata
|
11
|
+
extend Support::Extension
|
12
|
+
|
13
|
+
apply_extension do
|
14
|
+
build do |view, composer:|
|
15
|
+
forms = view.forms
|
16
|
+
if !view.object.is_a?(StringDoc) && view.object.significant?(:form)
|
17
|
+
forms << view
|
18
|
+
end
|
19
|
+
|
20
|
+
forms.each do |form|
|
21
|
+
form.label(:form)[:view_path] = composer.view_path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/routing"
|
4
|
+
require "pakyow/presenter"
|
5
|
+
|
6
|
+
# Load data after presenter, so that containers are created with reflected attributes.
|
7
|
+
#
|
8
|
+
require "pakyow/data"
|
9
|
+
|
10
|
+
require "pakyow/form"
|
11
|
+
|
12
|
+
require "pakyow/reflection/framework"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/inflector"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Reflection
|
7
|
+
# @api private
|
8
|
+
class Action
|
9
|
+
attr_reader :name, :scope, :node, :view_path, :binding, :attributes, :nested, :parents
|
10
|
+
|
11
|
+
def initialize(name:, scope:, node:, view_path:, binding: nil, attributes: [], nested: [], parents: [])
|
12
|
+
@name, @scope, @node, @view_path, @binding, @attributes, @nested, @parents = normalize(name), scope, node, view_path, binding, attributes, nested, parents
|
13
|
+
end
|
14
|
+
|
15
|
+
def named?(name)
|
16
|
+
@name == normalize(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cleanup
|
20
|
+
@node = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normalize(name)
|
26
|
+
Support.inflector.singularize(name.to_s).to_sym
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/inflector"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Reflection
|
7
|
+
# @api private
|
8
|
+
class Attribute
|
9
|
+
attr_reader :name, :type
|
10
|
+
|
11
|
+
def initialize(name, type:, required: false)
|
12
|
+
@name, @type, @required = normalize(name), type, required
|
13
|
+
end
|
14
|
+
|
15
|
+
def named?(name)
|
16
|
+
@name == normalize(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def required?
|
20
|
+
@required == true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def normalize(name)
|
26
|
+
name.to_s.to_sym
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/reflection/builders/base"
|
4
|
+
require "pakyow/reflection/builders/helpers/controller"
|
5
|
+
|
6
|
+
module Pakyow
|
7
|
+
module Reflection
|
8
|
+
module Builders
|
9
|
+
# @api private
|
10
|
+
class Actions < Base
|
11
|
+
include Helpers::Controller
|
12
|
+
|
13
|
+
def build(actions)
|
14
|
+
actions.each do |action|
|
15
|
+
define_action(action)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def define_action(action)
|
22
|
+
if action.parents.any?
|
23
|
+
parents = action.parents.dup
|
24
|
+
|
25
|
+
current_resource = ensure_controller_has_helpers(
|
26
|
+
find_or_define_resource_for_scope_at_path(parents.shift, action.view_path)
|
27
|
+
)
|
28
|
+
|
29
|
+
parents.each do |parent|
|
30
|
+
current_resource = ensure_controller_has_helpers(
|
31
|
+
find_or_define_resource_for_scope_in_resource(parent, current_resource)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
resource = find_or_define_resource_for_scope_in_resource(action.scope, current_resource)
|
36
|
+
else
|
37
|
+
resource = find_or_define_resource_for_scope_at_path(action.scope, action.view_path)
|
38
|
+
end
|
39
|
+
|
40
|
+
ensure_controller_has_helpers(resource)
|
41
|
+
|
42
|
+
# Define the route unless it exists.
|
43
|
+
#
|
44
|
+
# Actions are easy since they always go in the resource controller for
|
45
|
+
# the scope. If a nested scope, the action is defined on the nested
|
46
|
+
# resource returned by `find_or_define_resource_for_scope`.
|
47
|
+
#
|
48
|
+
route = resource.routes.values.flatten.find { |possible_route|
|
49
|
+
possible_route.name == action.name
|
50
|
+
} || resource.send(action.name) do
|
51
|
+
reflect
|
52
|
+
end
|
53
|
+
|
54
|
+
# Install the reflect action if it hasn't been installed for this route.
|
55
|
+
#
|
56
|
+
if route.name
|
57
|
+
unless action.node.labeled?(:endpoint)
|
58
|
+
form_endpoint_name = [resource.name_of_self.to_s, route.name.to_s].join("_").to_sym
|
59
|
+
action.node.significance << :endpoint
|
60
|
+
action.node.set_label(:endpoint, form_endpoint_name)
|
61
|
+
action.node.attributes[:"data-e"] = form_endpoint_name
|
62
|
+
end
|
63
|
+
|
64
|
+
resource.action :set_reflected_action, only: [route.name] do
|
65
|
+
if connection.form
|
66
|
+
form_view_path = connection.form[:view_path]
|
67
|
+
form_binding = connection.form[:binding]&.to_sym
|
68
|
+
|
69
|
+
connection.set(:__reflected_action, action.scope.actions.find { |possible_action|
|
70
|
+
possible_action.view_path == form_view_path && possible_action.binding == form_binding
|
71
|
+
})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
# TODO: warn the user that a reflection couldn't be installed for an unnamed route
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/core_refinements/string/normalization"
|
4
|
+
|
5
|
+
require "pakyow/reflection/builders/base"
|
6
|
+
require "pakyow/reflection/builders/helpers/controller"
|
7
|
+
require "pakyow/reflection/extensions/controller"
|
8
|
+
|
9
|
+
module Pakyow
|
10
|
+
module Reflection
|
11
|
+
module Builders
|
12
|
+
# @api private
|
13
|
+
class Endpoints < Base
|
14
|
+
include Helpers::Controller
|
15
|
+
|
16
|
+
using Support::Refinements::String::Normalization
|
17
|
+
|
18
|
+
def build(endpoints)
|
19
|
+
endpoints.each do |endpoint|
|
20
|
+
define_endpoint(endpoint)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def define_endpoint(endpoint)
|
27
|
+
controller = if within_resource?(endpoint.view_path)
|
28
|
+
find_or_define_resource_for_scope_at_path(
|
29
|
+
resource_source_at_path(endpoint.view_path),
|
30
|
+
controller_path(endpoint.view_path),
|
31
|
+
endpoint.type
|
32
|
+
)
|
33
|
+
else
|
34
|
+
find_or_define_controller_at_path(controller_path(endpoint.view_path))
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO: Make this the responsibility of the helpers.
|
38
|
+
#
|
39
|
+
ensure_controller_has_helpers(controller)
|
40
|
+
|
41
|
+
if controller.expansions.include?(:resource)
|
42
|
+
endpoint_name = String.normalize_path(
|
43
|
+
endpoint.view_path.gsub(String.collapse_path(controller.path_to_self), "")
|
44
|
+
).split("/", 2)[1]
|
45
|
+
|
46
|
+
endpoint_name = if endpoint_name.empty?
|
47
|
+
:list
|
48
|
+
else
|
49
|
+
endpoint_name.to_sym
|
50
|
+
end
|
51
|
+
|
52
|
+
case endpoint_name
|
53
|
+
when :new, :edit, :list, :show
|
54
|
+
# Find or define the route by resource endpoint name.
|
55
|
+
#
|
56
|
+
route = controller.routes.values.flatten.find { |possible_route|
|
57
|
+
possible_route.name == endpoint_name
|
58
|
+
} || controller.send(endpoint_name) do
|
59
|
+
reflect
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
unless route
|
65
|
+
# Find or define the route by path.
|
66
|
+
#
|
67
|
+
# TODO: This should look across all controllers, not just the current one. Look through endpoints?
|
68
|
+
#
|
69
|
+
route = controller.routes.values.flatten.find { |possible_route|
|
70
|
+
possible_route.path == route_path(endpoint.view_path)
|
71
|
+
} || controller.get(route_name(endpoint.view_path), route_path(endpoint.view_path)) do
|
72
|
+
operations.reflect(controller: self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
if route.name
|
77
|
+
controller.action :set_reflected_endpoint, only: [route.name] do
|
78
|
+
connection.set(:__reflected_endpoint, endpoint)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
# TODO: warn the user that a reflection couldn't be installed for an unnamed route
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/core_refinements/string/normalization"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Reflection
|
7
|
+
module Builders
|
8
|
+
module Helpers
|
9
|
+
module Controller
|
10
|
+
using Support::Refinements::String::Normalization
|
11
|
+
|
12
|
+
def find_or_define_controller_at_path(path)
|
13
|
+
controller_at_path(path) || define_controller_at_path(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def controller_at_path(path, state = @app.state(:controller))
|
17
|
+
if state.any?
|
18
|
+
state.find { |controller|
|
19
|
+
String.normalize_path(String.collapse_path(controller.path_to_self)) == String.normalize_path(path)
|
20
|
+
} || controller_at_path(path, state.flat_map(&:children))
|
21
|
+
else
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def controller_closest_to_path(path, state = @app.state(:controller))
|
27
|
+
if state.any?
|
28
|
+
controller_closest_to_path(path, state.flat_map(&:children)) || state.find { |controller|
|
29
|
+
String.normalize_path(path).start_with?(String.normalize_path(String.collapse_path(controller.path_to_self)))
|
30
|
+
}
|
31
|
+
else
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def define_controller_at_path(path, within: nil)
|
37
|
+
nested_state = if within
|
38
|
+
within.children
|
39
|
+
else
|
40
|
+
@app.state(:controller)
|
41
|
+
end
|
42
|
+
|
43
|
+
path = String.normalize_path(path)
|
44
|
+
|
45
|
+
if controller = controller_closest_to_path(path, nested_state)
|
46
|
+
context = controller
|
47
|
+
path = path.gsub(
|
48
|
+
/^#{String.normalize_path(String.collapse_path(controller.path_to_self))}/, ""
|
49
|
+
)
|
50
|
+
else
|
51
|
+
context = within || @app
|
52
|
+
end
|
53
|
+
|
54
|
+
controller_name = if path == "/"
|
55
|
+
:root
|
56
|
+
else
|
57
|
+
String.normalize_path(path)[1..-1].gsub("/", "_").to_sym
|
58
|
+
end
|
59
|
+
|
60
|
+
method = if context.is_a?(Class) && context.ancestors.include?(Pakyow::Routing::Controller)
|
61
|
+
:namespace
|
62
|
+
else
|
63
|
+
:controller
|
64
|
+
end
|
65
|
+
|
66
|
+
context.send(method, controller_name, String.normalize_path(path)) do
|
67
|
+
# intentionally empty
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def controller_path(view_path)
|
72
|
+
if view_path_directory?(view_path)
|
73
|
+
view_path
|
74
|
+
else
|
75
|
+
view_path.split("/")[0..-2].to_a.join("/")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def within_resource?(view_path)
|
80
|
+
view_path.split("/").any? { |view_path_part|
|
81
|
+
@app.state(:source).any? { |source|
|
82
|
+
source.plural_name == view_path_part.to_sym
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def route_name(view_path)
|
88
|
+
if view_path_directory?(view_path)
|
89
|
+
:default
|
90
|
+
else
|
91
|
+
view_path.split("/").last.to_sym
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def route_path(view_path)
|
96
|
+
if view_path_directory?(view_path)
|
97
|
+
"/"
|
98
|
+
else
|
99
|
+
"/#{view_path.split("/").last}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def resource_source_at_path(view_path)
|
104
|
+
view_path.split("/").reverse.each do |view_path_part|
|
105
|
+
@app.state(:source).each do |source|
|
106
|
+
if source.plural_name == view_path_part.to_sym
|
107
|
+
return source
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def view_path_directory?(view_path)
|
114
|
+
@app.state(:templates).any? { |templates|
|
115
|
+
File.directory?(File.join(templates.path, templates.config[:paths][:pages], view_path))
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
RESOURCE_ENDPOINTS = %i(new edit list show).freeze
|
120
|
+
|
121
|
+
def find_or_define_resource_for_scope_at_path(scope, path, endpoint_type = nil)
|
122
|
+
resource = resource_for_scope_at_path(scope, path) || define_resource_for_scope_at_path(scope, path)
|
123
|
+
|
124
|
+
if path.end_with?(resource_path_for_scope(scope)) || endpoint_type.nil? || RESOURCE_ENDPOINTS.include?(path.split("/").last.to_sym)
|
125
|
+
return resource
|
126
|
+
else
|
127
|
+
controller_for_endpoint_type = resource.send(endpoint_type)
|
128
|
+
|
129
|
+
nested_path = if view_path_directory?(path)
|
130
|
+
path
|
131
|
+
else
|
132
|
+
path.split("/")[0..-2].join("/")
|
133
|
+
end
|
134
|
+
|
135
|
+
nested_path = nested_path.gsub(
|
136
|
+
/^#{String.normalize_path(String.collapse_path(controller_for_endpoint_type.path_to_self))}/, ""
|
137
|
+
)
|
138
|
+
|
139
|
+
if current_controller = controller_at_path(nested_path, resource.children)
|
140
|
+
return current_controller
|
141
|
+
else
|
142
|
+
if nested_path.empty?
|
143
|
+
controller_for_endpoint_type
|
144
|
+
else
|
145
|
+
define_controller_at_path(nested_path, within: controller_for_endpoint_type)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def resource_for_scope_at_path(scope, path, state = @app.state(:controller))
|
152
|
+
if state.any?
|
153
|
+
state.select { |controller|
|
154
|
+
controller.expansions.include?(:resource)
|
155
|
+
}.find { |controller|
|
156
|
+
String.normalize_path(String.collapse_path(controller.path_to_self)) == full_resource_path_for_scope_at_path(scope, path)
|
157
|
+
} || resource_for_scope_at_path(scope, path, state.flat_map(&:children))
|
158
|
+
else
|
159
|
+
nil
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def define_resource_for_scope_at_path(scope, path)
|
164
|
+
context = if resource_namespace_path = resource_namespace_path_for_scope_at_path(scope, path)
|
165
|
+
if within_resource?(resource_namespace_path)
|
166
|
+
ensure_controller_has_helpers(
|
167
|
+
find_or_define_resource_for_scope_at_path(
|
168
|
+
resource_source_at_path(resource_namespace_path), resource_namespace_path
|
169
|
+
)
|
170
|
+
)
|
171
|
+
else
|
172
|
+
ensure_controller_has_helpers(
|
173
|
+
find_or_define_controller_at_path(resource_namespace_path)
|
174
|
+
)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
@app
|
178
|
+
end
|
179
|
+
|
180
|
+
context.resource resource_name_for_scope(scope), resource_path_for_scope(scope) do
|
181
|
+
# intentionally empty
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def resource_namespace_path_for_scope_at_path(scope, path)
|
186
|
+
resource_path = resource_path_for_scope(scope)
|
187
|
+
|
188
|
+
if path.start_with?(resource_path)
|
189
|
+
nil
|
190
|
+
elsif path.include?(resource_path)
|
191
|
+
path.split(resource_path, 2)[0]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def resource_name_for_scope(scope)
|
196
|
+
scope.plural_name
|
197
|
+
end
|
198
|
+
|
199
|
+
def resource_path_for_scope(scope)
|
200
|
+
String.normalize_path(scope.plural_name)
|
201
|
+
end
|
202
|
+
|
203
|
+
def ensure_controller_has_helpers(controller)
|
204
|
+
unless controller.ancestors.include?(Extension::Controller)
|
205
|
+
controller.include Extension::Controller
|
206
|
+
end
|
207
|
+
|
208
|
+
controller
|
209
|
+
end
|
210
|
+
|
211
|
+
def find_or_define_resource_for_scope_in_resource(scope, resource)
|
212
|
+
resource.children.find { |child|
|
213
|
+
child.path == resource_path_for_scope(scope)
|
214
|
+
} || resource.resource(resource_name_for_scope(scope), resource_path_for_scope(scope)) do
|
215
|
+
# intentionally empty
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def full_resource_path_for_scope_at_path(scope, path)
|
220
|
+
String.normalize_path(
|
221
|
+
File.join(
|
222
|
+
resource_namespace_path_for_scope_at_path(scope, path).to_s,
|
223
|
+
scope.plural_name.to_s
|
224
|
+
)
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|