pakyow-reflection 1.0.0.rc1
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 +7 -0
- data/CHANGELOG.md +0 -0
- data/LICENSE +4 -0
- data/README.md +29 -0
- data/lib/pakyow/reflection/action.rb +25 -0
- data/lib/pakyow/reflection/attribute.rb +29 -0
- data/lib/pakyow/reflection/behavior/config.rb +33 -0
- data/lib/pakyow/reflection/behavior/reflecting.rb +45 -0
- data/lib/pakyow/reflection/behavior/rendering/install_form_metadata.rb +28 -0
- data/lib/pakyow/reflection/builders/abstract.rb +13 -0
- data/lib/pakyow/reflection/builders/actions.rb +80 -0
- data/lib/pakyow/reflection/builders/endpoints.rb +86 -0
- data/lib/pakyow/reflection/builders/helpers/controller.rb +234 -0
- data/lib/pakyow/reflection/builders/source.rb +51 -0
- data/lib/pakyow/reflection/endpoint.rb +74 -0
- data/lib/pakyow/reflection/extensions/controller.rb +302 -0
- data/lib/pakyow/reflection/framework.rb +70 -0
- data/lib/pakyow/reflection/mirror.rb +343 -0
- data/lib/pakyow/reflection/nested.rb +29 -0
- data/lib/pakyow/reflection/scope.rb +62 -0
- data/lib/pakyow/reflection.rb +12 -0
- metadata +133 -0
@@ -0,0 +1,343 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/inflector"
|
4
|
+
|
5
|
+
require "pakyow/presenter/composers/view"
|
6
|
+
|
7
|
+
require "pakyow/reflection/action"
|
8
|
+
require "pakyow/reflection/attribute"
|
9
|
+
require "pakyow/reflection/endpoint"
|
10
|
+
require "pakyow/reflection/nested"
|
11
|
+
require "pakyow/reflection/scope"
|
12
|
+
|
13
|
+
module Pakyow
|
14
|
+
module Reflection
|
15
|
+
# Reflects state from an application's view templates.
|
16
|
+
#
|
17
|
+
class Mirror
|
18
|
+
using Support::DeepDup
|
19
|
+
|
20
|
+
attr_reader :scopes, :endpoints, :actions
|
21
|
+
|
22
|
+
def initialize(app)
|
23
|
+
@app, @scopes, @endpoints, @actions = app, [], [], []
|
24
|
+
|
25
|
+
view_paths.each do |view_path|
|
26
|
+
discover_view_scopes(view_path: view_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
view_paths.each do |view_path|
|
30
|
+
discover_view_path_associations(view_path: view_path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def scope(name)
|
35
|
+
@scopes.find { |scope|
|
36
|
+
scope.named?(name)
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def view_paths
|
43
|
+
@app.state(:templates).reject { |template_store|
|
44
|
+
@app.config.reflection.ignored_template_stores.include?(template_store.name)
|
45
|
+
}.flat_map(&:paths)
|
46
|
+
end
|
47
|
+
|
48
|
+
def discover_view_scopes(view_path:, view: nil, parent_scope: nil, parent_exposure: nil, binding_path: [])
|
49
|
+
unless view
|
50
|
+
composer = Presenter::Composers::View.new(view_path, app: @app)
|
51
|
+
view = composer.view(return_cached: true)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Descend to find the most specific scope first.
|
55
|
+
#
|
56
|
+
view.each_binding_scope do |binding_scope_node|
|
57
|
+
unless binding_scope_node.significant?(:within_form) || binding_scope_node.labeled?(:plug)
|
58
|
+
binding_scope_view = Presenter::View.from_object(binding_scope_node)
|
59
|
+
scope = scope_for_binding(binding_scope_view.binding_name, parent_scope)
|
60
|
+
|
61
|
+
# Discover attributes from scopes nested within views.
|
62
|
+
#
|
63
|
+
discover_attributes(binding_scope_view, fields: false).each do |attribute|
|
64
|
+
unless scope.attribute(attribute.name, type: :view)
|
65
|
+
scope.add_attribute(attribute, type: :view)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Define an endpoint for this scope.
|
70
|
+
#
|
71
|
+
endpoint = ensure_endpoint(
|
72
|
+
view_path, view.info.dig(:reflection, :endpoint)
|
73
|
+
)
|
74
|
+
|
75
|
+
unless endpoint.exposures.any? { |e| e.binding == binding_scope_view.channeled_binding_name}
|
76
|
+
exposure = Exposure.new(
|
77
|
+
scope: scope,
|
78
|
+
node: binding_scope_node,
|
79
|
+
parent: parent_exposure,
|
80
|
+
binding: binding_scope_view.channeled_binding_name,
|
81
|
+
dataset: binding_scope_view.label(:dataset)
|
82
|
+
)
|
83
|
+
|
84
|
+
endpoint.add_exposure(exposure)
|
85
|
+
|
86
|
+
# Discover nested view scopes.
|
87
|
+
#
|
88
|
+
discover_view_scopes(
|
89
|
+
view_path: view_path,
|
90
|
+
view: binding_scope_view,
|
91
|
+
parent_scope: scope,
|
92
|
+
parent_exposure: exposure,
|
93
|
+
binding_path: binding_path.dup << binding_scope_node.label(:binding)
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Discover forms.
|
100
|
+
#
|
101
|
+
view.object.each_significant_node(:form) do |form_node|
|
102
|
+
if form_node.labeled?(:binding)
|
103
|
+
form_view = Presenter::View.from_object(form_node)
|
104
|
+
scope = scope_for_binding(form_view.binding_name, parent_scope)
|
105
|
+
|
106
|
+
# Discover attributes from scopes nested within forms.
|
107
|
+
#
|
108
|
+
attributes = discover_attributes(form_view)
|
109
|
+
attributes.each do |attribute|
|
110
|
+
unless scope.attribute(attribute.name, type: :form)
|
111
|
+
scope.add_attribute(attribute, type: :form)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Define an endpoint for this form.
|
116
|
+
#
|
117
|
+
endpoint = ensure_endpoint(
|
118
|
+
view_path, view.info.dig(:reflection, :endpoint)
|
119
|
+
)
|
120
|
+
|
121
|
+
unless endpoint.exposures.any? { |e| e.binding == form_view.channeled_binding_name }
|
122
|
+
exposure = Exposure.new(
|
123
|
+
scope: scope,
|
124
|
+
node: form_node,
|
125
|
+
parent: parent_exposure,
|
126
|
+
binding: form_view.channeled_binding_name
|
127
|
+
)
|
128
|
+
|
129
|
+
endpoint.add_exposure(exposure)
|
130
|
+
|
131
|
+
# Define the reflected action, if there is one.
|
132
|
+
#
|
133
|
+
if action = action_for_form(form_view, view_path)
|
134
|
+
# Define an action to handle this form submission.
|
135
|
+
#
|
136
|
+
scope.actions << Action.new(
|
137
|
+
name: action,
|
138
|
+
scope: scope,
|
139
|
+
node: form_node,
|
140
|
+
|
141
|
+
# We need the view path to to identify the correct action to pull
|
142
|
+
# expected attributes from on submission.
|
143
|
+
#
|
144
|
+
view_path: view_path,
|
145
|
+
|
146
|
+
# We need the channeled binding name to differentiate between submissions of two
|
147
|
+
# forms with the same scope from the same view path.
|
148
|
+
#
|
149
|
+
binding: form_view.label(:channeled_binding),
|
150
|
+
|
151
|
+
attributes: attributes,
|
152
|
+
nested: discover_nested(form_view),
|
153
|
+
parents: binding_path.map { |binding_path_part|
|
154
|
+
scope(binding_path_part)
|
155
|
+
}
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Discover nested form scopes.
|
160
|
+
discover_form_scopes(
|
161
|
+
view_path: view_path,
|
162
|
+
view: form_view,
|
163
|
+
parent_scope: scope,
|
164
|
+
parent_exposure: exposure
|
165
|
+
)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Define delete actions for delete links.
|
171
|
+
#
|
172
|
+
view.object.find_significant_nodes(:endpoint).select { |endpoint_node|
|
173
|
+
endpoint_node.label(:endpoint).to_s.end_with?("_delete")
|
174
|
+
}.each do |endpoint_node|
|
175
|
+
scope = scope_for_binding(
|
176
|
+
endpoint_node.label(:endpoint).to_s.split("_", 2)[0],
|
177
|
+
parent_scope
|
178
|
+
)
|
179
|
+
|
180
|
+
unless scope.action(:delete)
|
181
|
+
scope.actions << Action.new(
|
182
|
+
name: :delete,
|
183
|
+
scope: scope,
|
184
|
+
node: endpoint_node,
|
185
|
+
view_path: view_path
|
186
|
+
)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def discover_view_path_associations(view_path:)
|
192
|
+
view_path_parts = view_path.split("/").reverse.map(&:to_sym)
|
193
|
+
|
194
|
+
until view_path_parts.count < 2
|
195
|
+
view_path_part = view_path_parts.shift
|
196
|
+
|
197
|
+
if child_scope = scope(view_path_part)
|
198
|
+
view_path_parts.map { |each_view_path_part|
|
199
|
+
scope(each_view_path_part)
|
200
|
+
}.compact.each do |parent_scope|
|
201
|
+
child_scope.add_parent(parent_scope)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def discover_form_scopes(view_path:, view: nil, parent_scope: nil, parent_exposure: nil)
|
208
|
+
view.each_binding_scope do |binding_scope_node|
|
209
|
+
if binding_scope_node.significant?(:field) || binding_scope_node.find_significant_nodes(:field).any?
|
210
|
+
binding_scope_view = Presenter::View.from_object(binding_scope_node)
|
211
|
+
scope = scope_for_binding(binding_scope_view.binding_name, parent_scope)
|
212
|
+
|
213
|
+
# Discover attributes from scopes nested within forms.
|
214
|
+
#
|
215
|
+
discover_attributes(binding_scope_view).each do |attribute|
|
216
|
+
unless scope.attribute(attribute.name, type: :form)
|
217
|
+
scope.add_attribute(attribute, type: :form)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Discover nested form scopes.
|
222
|
+
#
|
223
|
+
discover_form_scopes(
|
224
|
+
view_path: view_path,
|
225
|
+
view: binding_scope_view,
|
226
|
+
parent_scope: scope
|
227
|
+
)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
IGNORED_ATTRIBUTES = %i(id).freeze
|
233
|
+
|
234
|
+
def discover_attributes(view, fields: true)
|
235
|
+
view.binding_props.reject { |binding_prop_node|
|
236
|
+
binding_prop_node.significant?(:multipart_binding) && binding_prop_node.label(:binding) != view.binding_name
|
237
|
+
}.select { |binding_prop_node|
|
238
|
+
!fields || Presenter::Form::FIELD_TAGS.include?(binding_prop_node.tagname)
|
239
|
+
}.each_with_object([]) do |binding_prop_node, attributes|
|
240
|
+
binding_prop_view = Presenter::View.from_object(binding_prop_node)
|
241
|
+
binding_prop_name = if binding_prop_node.significant?(:multipart_binding)
|
242
|
+
binding_prop_node.label(:binding_prop)
|
243
|
+
else
|
244
|
+
binding_prop_node.label(:binding)
|
245
|
+
end
|
246
|
+
|
247
|
+
unless IGNORED_ATTRIBUTES.include?(binding_prop_name)
|
248
|
+
attribute = Attribute.new(
|
249
|
+
binding_prop_name,
|
250
|
+
type: type_for_form_view(binding_prop_view),
|
251
|
+
required: binding_prop_view.attrs.has?(:required)
|
252
|
+
)
|
253
|
+
|
254
|
+
attributes << attribute
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def discover_nested(view)
|
260
|
+
view.binding_scopes.select { |binding_scope_node|
|
261
|
+
binding_scope_node.significant?(:field) || binding_scope_node.find_significant_nodes(:field).any?
|
262
|
+
}.map { |binding_scope_node|
|
263
|
+
binding_scope_view = Presenter::View.from_object(binding_scope_node)
|
264
|
+
|
265
|
+
Nested.new(
|
266
|
+
binding_scope_view.binding_name,
|
267
|
+
attributes: discover_attributes(binding_scope_view),
|
268
|
+
nested: discover_nested(binding_scope_view)
|
269
|
+
)
|
270
|
+
}
|
271
|
+
end
|
272
|
+
|
273
|
+
def scope_for_binding(binding, parent_scope)
|
274
|
+
unless scope = scopes.find { |possible_scope| possible_scope.named?(binding) }
|
275
|
+
scope = Scope.new(binding); @scopes << scope
|
276
|
+
end
|
277
|
+
|
278
|
+
if parent_scope
|
279
|
+
scope.add_parent(parent_scope)
|
280
|
+
end
|
281
|
+
|
282
|
+
scope
|
283
|
+
end
|
284
|
+
|
285
|
+
def type_for_form_view(view)
|
286
|
+
type_for_binding_name(view.binding_name.to_s) ||
|
287
|
+
(view.attributes.has?(:type) && type_for_attribute_type(view.attributes[:type])) ||
|
288
|
+
:string
|
289
|
+
end
|
290
|
+
|
291
|
+
def type_for_binding_name(binding_name)
|
292
|
+
if binding_name.end_with?("_at")
|
293
|
+
:datetime
|
294
|
+
else
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def type_for_attribute_type(type)
|
299
|
+
case type
|
300
|
+
when "date"
|
301
|
+
:date
|
302
|
+
when "time"
|
303
|
+
:time
|
304
|
+
when "datetime-local"
|
305
|
+
:datetime
|
306
|
+
when "number", "range"
|
307
|
+
:decimal
|
308
|
+
else
|
309
|
+
nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def action_for_form(view, path)
|
314
|
+
plural_binding_name = Support.inflector.pluralize(view.binding_name)
|
315
|
+
if view.labeled?(:endpoint)
|
316
|
+
endpoint = view.label(:endpoint).to_s
|
317
|
+
if endpoint.end_with?("#{plural_binding_name}_create")
|
318
|
+
:create
|
319
|
+
elsif endpoint.end_with?("#{plural_binding_name}_update")
|
320
|
+
:update
|
321
|
+
elsif endpoint.end_with?("#{plural_binding_name}_delete")
|
322
|
+
:delete
|
323
|
+
else
|
324
|
+
nil
|
325
|
+
end
|
326
|
+
elsif path.include?(plural_binding_name) && path.include?("edit")
|
327
|
+
:update
|
328
|
+
else
|
329
|
+
:create
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def ensure_endpoint(view_path, options)
|
334
|
+
unless endpoint = @endpoints.find { |e| e.view_path == view_path }
|
335
|
+
endpoint = Endpoint.new(view_path, options: options)
|
336
|
+
@endpoints << endpoint
|
337
|
+
end
|
338
|
+
|
339
|
+
endpoint
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/inflector"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Reflection
|
7
|
+
class Nested
|
8
|
+
attr_reader :name, :attributes, :nested
|
9
|
+
|
10
|
+
def initialize(name, attributes: [], nested: [])
|
11
|
+
@name, @attributes, @nested = normalize(name), attributes, nested
|
12
|
+
end
|
13
|
+
|
14
|
+
def named?(name)
|
15
|
+
@name == normalize(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def plural_name
|
19
|
+
Support.inflector.pluralize(@name).to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def normalize(name)
|
25
|
+
name.to_s.to_sym
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pakyow/support/inflector"
|
4
|
+
|
5
|
+
module Pakyow
|
6
|
+
module Reflection
|
7
|
+
class Scope
|
8
|
+
attr_reader :name, :parents, :actions, :children
|
9
|
+
attr_writer :parent
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
@name = normalize(name)
|
13
|
+
@parents, @actions, @attributes, @children = [], [], { form: [], view: [] }, []
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_parent(parent)
|
17
|
+
unless @parents.include?(parent)
|
18
|
+
@parents << parent
|
19
|
+
parent.children << self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def named?(name)
|
24
|
+
@name == normalize(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def action(name)
|
28
|
+
@actions.find { |action|
|
29
|
+
action.named?(name)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def attribute(name, type:)
|
34
|
+
@attributes[type].find { |attribute|
|
35
|
+
attribute.named?(name)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_attribute(attribute, type:)
|
40
|
+
@attributes[type] << attribute
|
41
|
+
end
|
42
|
+
|
43
|
+
def attributes
|
44
|
+
# TODO: In addition to finding view attributes, should we be finding view associations?
|
45
|
+
#
|
46
|
+
@attributes[:form].concat(@attributes[:view]).uniq { |attribute|
|
47
|
+
attribute.name
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def plural_name
|
52
|
+
Support.inflector.pluralize(@name).to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def normalize(name)
|
58
|
+
Support.inflector.singularize(name.to_s).to_sym
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
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"
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pakyow-reflection
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bryan Powell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-07-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pakyow-core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0.rc1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0.rc1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pakyow-data
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.0.rc1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.0.rc1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pakyow-form
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0.rc1
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0.rc1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pakyow-presenter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0.rc1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.0.rc1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pakyow-support
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.0.rc1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.0.rc1
|
83
|
+
description: Reflected behavior for Pakyow
|
84
|
+
email: bryan@metabahn.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- CHANGELOG.md
|
90
|
+
- LICENSE
|
91
|
+
- README.md
|
92
|
+
- lib/pakyow/reflection.rb
|
93
|
+
- lib/pakyow/reflection/action.rb
|
94
|
+
- lib/pakyow/reflection/attribute.rb
|
95
|
+
- lib/pakyow/reflection/behavior/config.rb
|
96
|
+
- lib/pakyow/reflection/behavior/reflecting.rb
|
97
|
+
- lib/pakyow/reflection/behavior/rendering/install_form_metadata.rb
|
98
|
+
- lib/pakyow/reflection/builders/abstract.rb
|
99
|
+
- lib/pakyow/reflection/builders/actions.rb
|
100
|
+
- lib/pakyow/reflection/builders/endpoints.rb
|
101
|
+
- lib/pakyow/reflection/builders/helpers/controller.rb
|
102
|
+
- lib/pakyow/reflection/builders/source.rb
|
103
|
+
- lib/pakyow/reflection/endpoint.rb
|
104
|
+
- lib/pakyow/reflection/extensions/controller.rb
|
105
|
+
- lib/pakyow/reflection/framework.rb
|
106
|
+
- lib/pakyow/reflection/mirror.rb
|
107
|
+
- lib/pakyow/reflection/nested.rb
|
108
|
+
- lib/pakyow/reflection/scope.rb
|
109
|
+
homepage: https://pakyow.org
|
110
|
+
licenses:
|
111
|
+
- LGPL-3.0
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: 2.5.0
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">"
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.3.1
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.7.6
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Pakyow Reflection
|
133
|
+
test_files: []
|