pakyow-reflection 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|