glib-web 4.42.2 → 4.42.4
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 +4 -4
- data/app/controllers/concerns/glib/json/libs.rb +2 -2
- data/app/views/json_ui/garage/test_page/_header.json.jbuilder +84 -14
- data/app/views/json_ui/garage/test_page/browsers.json.jbuilder +101 -0
- data/app/views/json_ui/garage/test_page/calendar.json.jbuilder +109 -0
- data/app/views/json_ui/garage/test_page/calendar_empty_data.json.jbuilder +3 -0
- data/app/views/json_ui/garage/test_page/carousel.json.jbuilder +70 -0
- data/app/views/json_ui/garage/test_page/charts.json.jbuilder +370 -0
- data/app/views/json_ui/garage/test_page/column.json.jbuilder +121 -0
- data/app/views/json_ui/garage/test_page/commands.json.jbuilder +98 -0
- data/app/views/json_ui/garage/test_page/components.json.jbuilder +143 -0
- data/app/views/json_ui/garage/test_page/cookies.json.jbuilder +109 -0
- data/app/views/json_ui/garage/test_page/custom.json.jbuilder +56 -0
- data/app/views/json_ui/garage/test_page/flow.json.jbuilder +70 -0
- data/app/views/json_ui/garage/test_page/forms.json.jbuilder +105 -0
- data/app/views/json_ui/garage/test_page/grid.json.jbuilder +68 -0
- data/app/views/json_ui/garage/test_page/horizontal.json.jbuilder +68 -0
- data/app/views/json_ui/garage/test_page/http.json.jbuilder +87 -37
- data/app/views/json_ui/garage/test_page/image.json.jbuilder +145 -0
- data/app/views/json_ui/garage/test_page/list.json.jbuilder +75 -0
- data/app/views/json_ui/garage/test_page/lists_append.json.jbuilder +151 -0
- data/app/views/json_ui/garage/test_page/logics_set.json.jbuilder +7 -6
- data/app/views/json_ui/garage/test_page/multimedia_video.json.jbuilder +118 -0
- data/app/views/json_ui/garage/test_page/pagination.json.jbuilder +64 -0
- data/app/views/json_ui/garage/test_page/panels.json.jbuilder +113 -0
- data/app/views/json_ui/garage/test_page/popovers.json.jbuilder +112 -0
- data/app/views/json_ui/garage/test_page/progressCircle.json.jbuilder +119 -0
- data/app/views/json_ui/garage/test_page/responsive.json.jbuilder +100 -0
- data/app/views/json_ui/garage/test_page/scroll.json.jbuilder +77 -0
- data/app/views/json_ui/garage/test_page/split.json.jbuilder +82 -0
- data/app/views/json_ui/garage/test_page/storage_items.json.jbuilder +144 -0
- data/app/views/json_ui/garage/test_page/table.json.jbuilder +99 -0
- data/app/views/json_ui/garage/test_page/timeline.json.jbuilder +97 -0
- data/app/views/json_ui/garage/test_page/timeouts.json.jbuilder +86 -0
- data/app/views/json_ui/garage/test_page/ul.json.jbuilder +68 -0
- data/app/views/json_ui/garage/test_page/vertical.json.jbuilder +68 -0
- data/app/views/json_ui/garage/test_page/web.json.jbuilder +64 -0
- data/app/views/json_ui/garage/test_page/windows.json.jbuilder +129 -0
- data/lib/glib/rubocop/cops/multiline_method_call_style.rb +0 -8
- data/lib/tasks/db.rake +1 -1
- metadata +39 -7
- data/lib/glib/doc_generator.rb +0 -386
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
json.title 'Test Page (Windows)'
|
|
2
|
+
|
|
3
|
+
page = json_ui_page json
|
|
4
|
+
|
|
5
|
+
page.body(
|
|
6
|
+
childViews: ->(body) do
|
|
7
|
+
render 'json_ui/garage/test_page/header', view: body
|
|
8
|
+
body.panels_responsive(
|
|
9
|
+
padding: glib_json_padding_body,
|
|
10
|
+
childViews: ->(res) do
|
|
11
|
+
res.h2 text: 'Windows'
|
|
12
|
+
res.label text: 'Open, update, and close windows.'
|
|
13
|
+
res.spacer height: 12
|
|
14
|
+
res.hr width: 'matchParent'
|
|
15
|
+
res.spacer height: 12
|
|
16
|
+
|
|
17
|
+
res.h2 text: 'Overview'
|
|
18
|
+
res.label text: 'Window actions can open new pages, update existing windows, or close navigation stacks.'
|
|
19
|
+
res.spacer height: 12
|
|
20
|
+
res.hr width: 'matchParent'
|
|
21
|
+
res.spacer height: 12
|
|
22
|
+
|
|
23
|
+
res.h2 text: 'Basic example'
|
|
24
|
+
res.spacer height: 8
|
|
25
|
+
res.button(
|
|
26
|
+
text: 'windows/open',
|
|
27
|
+
onClick: ->(action) do
|
|
28
|
+
action.windows_open url: json_ui_garage_url(path: 'home/blank')
|
|
29
|
+
end
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
res.spacer height: 16
|
|
33
|
+
res.hr width: 'matchParent'
|
|
34
|
+
res.spacer height: 16
|
|
35
|
+
|
|
36
|
+
res.h2 text: 'Variants/props'
|
|
37
|
+
res.spacer height: 8
|
|
38
|
+
res.panels_flow(
|
|
39
|
+
innerPadding: { bottom: 0 },
|
|
40
|
+
width: 'matchParent',
|
|
41
|
+
childViews: ->(flow) do
|
|
42
|
+
flow.button(
|
|
43
|
+
text: 'windows/open (updateExisting: true)',
|
|
44
|
+
onClick: ->(action) do
|
|
45
|
+
action.windows_open updateExisting: true, url: json_ui_garage_url(path: 'home/blank', sleep: true), loaderViews: ->(view) do
|
|
46
|
+
view.panels_responsive padding: { all: 16 }, childViews: ->(res) do
|
|
47
|
+
res.skeleton template: 'textArea'
|
|
48
|
+
res.skeleton template: 'commentList'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
)
|
|
53
|
+
flow.spacer width: 8
|
|
54
|
+
flow.button(
|
|
55
|
+
text: 'windows/open (multistep form)',
|
|
56
|
+
onClick: ->(action) do
|
|
57
|
+
action.windows_open url: json_ui_garage_url(path: 'multistep_form/step1')
|
|
58
|
+
end
|
|
59
|
+
)
|
|
60
|
+
flow.spacer width: 8
|
|
61
|
+
flow.button(
|
|
62
|
+
text: 'windows/openWeb',
|
|
63
|
+
onClick: ->(action) do
|
|
64
|
+
action.windows_openWeb url: 'http://www.google.com'
|
|
65
|
+
end
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
res.spacer height: 16
|
|
71
|
+
res.hr width: 'matchParent'
|
|
72
|
+
res.spacer height: 16
|
|
73
|
+
|
|
74
|
+
res.h2 text: 'Actions/events'
|
|
75
|
+
res.spacer height: 8
|
|
76
|
+
res.panels_flow(
|
|
77
|
+
innerPadding: { bottom: 0 },
|
|
78
|
+
width: 'matchParent',
|
|
79
|
+
childViews: ->(flow) do
|
|
80
|
+
flow.button(
|
|
81
|
+
text: 'windows/close',
|
|
82
|
+
onClick: ->(action) do
|
|
83
|
+
action.windows_close onClose: ->(subaction) do
|
|
84
|
+
subaction.dialogs_alert message: 'Previous window closed'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
)
|
|
88
|
+
flow.spacer width: 8
|
|
89
|
+
flow.button(
|
|
90
|
+
text: 'windows/closeWithOpen',
|
|
91
|
+
onClick: ->(action) do
|
|
92
|
+
action.windows_closeWithOpen url: json_ui_garage_url(path: 'home/print', encoded_key: 'Hello+World')
|
|
93
|
+
end
|
|
94
|
+
)
|
|
95
|
+
flow.spacer width: 8
|
|
96
|
+
flow.button(
|
|
97
|
+
text: 'windows/closeAllWithOpen',
|
|
98
|
+
onClick: ->(action) do
|
|
99
|
+
action.windows_closeAllWithOpen url: json_ui_garage_url(path: 'home/index', sleep: true), loaderViews: ->(view) do
|
|
100
|
+
view.panels_responsive padding: { all: 16 }, childViews: ->(res) do
|
|
101
|
+
res.skeleton template: 'textArea'
|
|
102
|
+
res.skeleton template: 'commentList'
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
res.spacer height: 16
|
|
111
|
+
res.hr width: 'matchParent'
|
|
112
|
+
res.spacer height: 16
|
|
113
|
+
|
|
114
|
+
res.h2 text: 'Edge/advanced'
|
|
115
|
+
res.spacer height: 8
|
|
116
|
+
res.button(
|
|
117
|
+
text: 'windows/open (with loader)',
|
|
118
|
+
onClick: ->(action) do
|
|
119
|
+
action.windows_open url: json_ui_garage_url(path: 'home/blank', sleep: true), loaderViews: ->(view) do
|
|
120
|
+
view.panels_responsive padding: { all: 16 }, childViews: ->(res) do
|
|
121
|
+
res.skeleton template: 'bigProgressCircle'
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
)
|
|
@@ -38,7 +38,6 @@ module RuboCop
|
|
|
38
38
|
return if proper_parentheses_style?(node)
|
|
39
39
|
return if proper_backslash_style?(node) && allow_backslash?
|
|
40
40
|
return if inside_correctable_parent?(node)
|
|
41
|
-
return if assignment_method?(node)
|
|
42
41
|
|
|
43
42
|
add_offense(node) do |corrector|
|
|
44
43
|
autocorrect(corrector, node)
|
|
@@ -53,13 +52,6 @@ module RuboCop
|
|
|
53
52
|
node.multiline? && node.arguments.any?
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
def assignment_method?(node)
|
|
57
|
-
# Skip setter methods (e.g., response.body=, foo.bar=)
|
|
58
|
-
# These are written as assignments (response.body = ...) and shouldn't
|
|
59
|
-
# be converted to method call style (response.body(...))
|
|
60
|
-
node.method_name.to_s.end_with?('=')
|
|
61
|
-
end
|
|
62
|
-
|
|
63
55
|
def allow_backslash?
|
|
64
56
|
# Allow backslash style without warnings when configured
|
|
65
57
|
# Set to true to allow both styles (but auto-correct will still convert to parentheses)
|
data/lib/tasks/db.rake
CHANGED
metadata
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: glib-web
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.42.
|
|
4
|
+
version: 4.42.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ''
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2019-10-04 00:00:00.000000000 Z
|
|
@@ -136,7 +136,7 @@ dependencies:
|
|
|
136
136
|
- - ">="
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
|
-
description:
|
|
139
|
+
description:
|
|
140
140
|
email: ''
|
|
141
141
|
executables: []
|
|
142
142
|
extensions: []
|
|
@@ -373,21 +373,54 @@ files:
|
|
|
373
373
|
- app/views/json_ui/garage/tables/panel_content.json.jbuilder
|
|
374
374
|
- app/views/json_ui/garage/test_page/_header.json.jbuilder
|
|
375
375
|
- app/views/json_ui/garage/test_page/auto_validate.json.jbuilder
|
|
376
|
+
- app/views/json_ui/garage/test_page/browsers.json.jbuilder
|
|
377
|
+
- app/views/json_ui/garage/test_page/calendar.json.jbuilder
|
|
378
|
+
- app/views/json_ui/garage/test_page/calendar_empty_data.json.jbuilder
|
|
379
|
+
- app/views/json_ui/garage/test_page/carousel.json.jbuilder
|
|
380
|
+
- app/views/json_ui/garage/test_page/charts.json.jbuilder
|
|
381
|
+
- app/views/json_ui/garage/test_page/column.json.jbuilder
|
|
382
|
+
- app/views/json_ui/garage/test_page/commands.json.jbuilder
|
|
383
|
+
- app/views/json_ui/garage/test_page/components.json.jbuilder
|
|
384
|
+
- app/views/json_ui/garage/test_page/cookies.json.jbuilder
|
|
385
|
+
- app/views/json_ui/garage/test_page/custom.json.jbuilder
|
|
376
386
|
- app/views/json_ui/garage/test_page/dialog.json.jbuilder
|
|
377
387
|
- app/views/json_ui/garage/test_page/dialog_open.json.jbuilder
|
|
378
388
|
- app/views/json_ui/garage/test_page/dirty_state.json.jbuilder
|
|
379
389
|
- app/views/json_ui/garage/test_page/file_upload_new.json.jbuilder
|
|
390
|
+
- app/views/json_ui/garage/test_page/flow.json.jbuilder
|
|
380
391
|
- app/views/json_ui/garage/test_page/form.json.jbuilder
|
|
381
392
|
- app/views/json_ui/garage/test_page/form_dynamic.json.jbuilder
|
|
393
|
+
- app/views/json_ui/garage/test_page/forms.json.jbuilder
|
|
394
|
+
- app/views/json_ui/garage/test_page/grid.json.jbuilder
|
|
395
|
+
- app/views/json_ui/garage/test_page/horizontal.json.jbuilder
|
|
382
396
|
- app/views/json_ui/garage/test_page/http.json.jbuilder
|
|
397
|
+
- app/views/json_ui/garage/test_page/image.json.jbuilder
|
|
383
398
|
- app/views/json_ui/garage/test_page/lifecycle.json.jbuilder
|
|
399
|
+
- app/views/json_ui/garage/test_page/list.json.jbuilder
|
|
384
400
|
- app/views/json_ui/garage/test_page/list_editable.json.jbuilder
|
|
401
|
+
- app/views/json_ui/garage/test_page/lists_append.json.jbuilder
|
|
385
402
|
- app/views/json_ui/garage/test_page/logics_set.json.jbuilder
|
|
403
|
+
- app/views/json_ui/garage/test_page/multimedia_video.json.jbuilder
|
|
386
404
|
- app/views/json_ui/garage/test_page/multiupload.json.jbuilder
|
|
405
|
+
- app/views/json_ui/garage/test_page/pagination.json.jbuilder
|
|
406
|
+
- app/views/json_ui/garage/test_page/panels.json.jbuilder
|
|
407
|
+
- app/views/json_ui/garage/test_page/popovers.json.jbuilder
|
|
408
|
+
- app/views/json_ui/garage/test_page/progressCircle.json.jbuilder
|
|
409
|
+
- app/views/json_ui/garage/test_page/responsive.json.jbuilder
|
|
410
|
+
- app/views/json_ui/garage/test_page/scroll.json.jbuilder
|
|
387
411
|
- app/views/json_ui/garage/test_page/selectable.json.jbuilder
|
|
388
412
|
- app/views/json_ui/garage/test_page/sheets.json.jbuilder
|
|
389
413
|
- app/views/json_ui/garage/test_page/snackbars.json.jbuilder
|
|
414
|
+
- app/views/json_ui/garage/test_page/split.json.jbuilder
|
|
415
|
+
- app/views/json_ui/garage/test_page/storage_items.json.jbuilder
|
|
416
|
+
- app/views/json_ui/garage/test_page/table.json.jbuilder
|
|
417
|
+
- app/views/json_ui/garage/test_page/timeline.json.jbuilder
|
|
418
|
+
- app/views/json_ui/garage/test_page/timeouts.json.jbuilder
|
|
419
|
+
- app/views/json_ui/garage/test_page/ul.json.jbuilder
|
|
420
|
+
- app/views/json_ui/garage/test_page/vertical.json.jbuilder
|
|
421
|
+
- app/views/json_ui/garage/test_page/web.json.jbuilder
|
|
390
422
|
- app/views/json_ui/garage/test_page/window.json.jbuilder
|
|
423
|
+
- app/views/json_ui/garage/test_page/windows.json.jbuilder
|
|
391
424
|
- app/views/json_ui/garage/views/_chart_data.json.jbuilder
|
|
392
425
|
- app/views/json_ui/garage/views/_checkbox_expand.json.jbuilder
|
|
393
426
|
- app/views/json_ui/garage/views/_expand_shrink_ex.json.jbuilder
|
|
@@ -431,7 +464,6 @@ files:
|
|
|
431
464
|
- lib/glib-web.rb
|
|
432
465
|
- lib/glib/all_helpers.rb
|
|
433
466
|
- lib/glib/crypt/utils.rb
|
|
434
|
-
- lib/glib/doc_generator.rb
|
|
435
467
|
- lib/glib/dynamic_text.rb
|
|
436
468
|
- lib/glib/dynamic_text/config.rb
|
|
437
469
|
- lib/glib/engine.rb
|
|
@@ -467,10 +499,10 @@ files:
|
|
|
467
499
|
- lib/glib/version.rb
|
|
468
500
|
- lib/tasks/db.rake
|
|
469
501
|
- lib/tasks/docs.rake
|
|
470
|
-
homepage:
|
|
502
|
+
homepage:
|
|
471
503
|
licenses: []
|
|
472
504
|
metadata: {}
|
|
473
|
-
post_install_message:
|
|
505
|
+
post_install_message:
|
|
474
506
|
rdoc_options: []
|
|
475
507
|
require_paths:
|
|
476
508
|
- lib
|
|
@@ -486,7 +518,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
486
518
|
version: '0'
|
|
487
519
|
requirements: []
|
|
488
520
|
rubygems_version: 3.4.6
|
|
489
|
-
signing_key:
|
|
521
|
+
signing_key:
|
|
490
522
|
specification_version: 4
|
|
491
523
|
summary: ''
|
|
492
524
|
test_files: []
|
data/lib/glib/doc_generator.rb
DELETED
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
require 'parser/current'
|
|
2
|
-
require 'yaml'
|
|
3
|
-
require 'fileutils'
|
|
4
|
-
require 'time'
|
|
5
|
-
|
|
6
|
-
module Glib
|
|
7
|
-
class DocGenerator
|
|
8
|
-
def initialize
|
|
9
|
-
@parser = Parser::CurrentRuby
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# Generate YAML documentation for a single Ruby file
|
|
13
|
-
def generate_for_file(file_path, output_path)
|
|
14
|
-
unless File.exist?(file_path)
|
|
15
|
-
puts "Warning: File not found: #{file_path}"
|
|
16
|
-
return
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
source = File.read(file_path)
|
|
20
|
-
ast = @parser.parse(source)
|
|
21
|
-
|
|
22
|
-
components = extract_components(ast, source)
|
|
23
|
-
|
|
24
|
-
# Generate YAML
|
|
25
|
-
yaml_data = {
|
|
26
|
-
'meta' => {
|
|
27
|
-
'source_file' => file_path,
|
|
28
|
-
'generated_at' => Time.now.iso8601,
|
|
29
|
-
'generator_version' => '1.0.0'
|
|
30
|
-
},
|
|
31
|
-
'components' => components
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
# Ensure output directory exists
|
|
35
|
-
FileUtils.mkdir_p(File.dirname(output_path))
|
|
36
|
-
|
|
37
|
-
# Write YAML file
|
|
38
|
-
File.write(output_path, yaml_data.to_yaml)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
# Extract component information from AST
|
|
44
|
-
def extract_components(node, source)
|
|
45
|
-
components = {}
|
|
46
|
-
|
|
47
|
-
traverse_ast(node, source) do |class_node, class_name, parent_class, comment|
|
|
48
|
-
next unless class_node.type == :class
|
|
49
|
-
|
|
50
|
-
# Parse YARD comment
|
|
51
|
-
yard_doc = parse_yard_comment(comment)
|
|
52
|
-
|
|
53
|
-
# Extract properties
|
|
54
|
-
properties = extract_properties(class_node, source)
|
|
55
|
-
|
|
56
|
-
# Build component hash
|
|
57
|
-
component_key = underscore(class_name)
|
|
58
|
-
components[component_key] = {
|
|
59
|
-
'class_name' => class_name,
|
|
60
|
-
'extends' => parent_class,
|
|
61
|
-
'description' => yard_doc[:description],
|
|
62
|
-
'properties' => properties,
|
|
63
|
-
'examples' => yard_doc[:examples],
|
|
64
|
-
'references' => yard_doc[:references],
|
|
65
|
-
'notes' => yard_doc[:notes],
|
|
66
|
-
'deprecated' => yard_doc[:deprecated]
|
|
67
|
-
}.compact
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
components
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Traverse AST and yield class nodes with their comments
|
|
74
|
-
def traverse_ast(node, source, &block)
|
|
75
|
-
return unless node.is_a?(Parser::AST::Node)
|
|
76
|
-
|
|
77
|
-
if node.type == :class
|
|
78
|
-
class_name = extract_class_name(node)
|
|
79
|
-
parent_class = extract_parent_class(node)
|
|
80
|
-
comment = extract_comment(node, source)
|
|
81
|
-
|
|
82
|
-
yield node, class_name, parent_class, comment
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Recursively traverse child nodes
|
|
86
|
-
node.children.each do |child|
|
|
87
|
-
traverse_ast(child, source, &block)
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Extract class name from class node
|
|
92
|
-
def extract_class_name(class_node)
|
|
93
|
-
const_node = class_node.children[0]
|
|
94
|
-
if const_node.type == :const
|
|
95
|
-
const_node.children[1].to_s
|
|
96
|
-
else
|
|
97
|
-
'Unknown'
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# Extract parent class name
|
|
102
|
-
def extract_parent_class(class_node)
|
|
103
|
-
parent_node = class_node.children[1]
|
|
104
|
-
return nil unless parent_node
|
|
105
|
-
|
|
106
|
-
if parent_node.type == :const
|
|
107
|
-
parent_node.children[1].to_s
|
|
108
|
-
else
|
|
109
|
-
nil
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Extract comment before a node
|
|
114
|
-
def extract_comment(node, source)
|
|
115
|
-
return '' unless node.location
|
|
116
|
-
|
|
117
|
-
# Get all lines before the node
|
|
118
|
-
lines = source.lines
|
|
119
|
-
node_line = node.location.line - 1
|
|
120
|
-
|
|
121
|
-
# Walk backwards to collect comment lines
|
|
122
|
-
comment_lines = []
|
|
123
|
-
(node_line - 1).downto(0) do |i|
|
|
124
|
-
line = lines[i].strip
|
|
125
|
-
break unless line.start_with?('#') || line.empty?
|
|
126
|
-
|
|
127
|
-
if line.start_with?('#')
|
|
128
|
-
# Remove leading # and whitespace
|
|
129
|
-
comment_lines.unshift(line.sub(/^#\s?/, ''))
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
comment_lines.join("\n")
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Parse YARD comment into structured data
|
|
137
|
-
def parse_yard_comment(comment)
|
|
138
|
-
return {} if comment.empty?
|
|
139
|
-
|
|
140
|
-
result = {
|
|
141
|
-
description: '',
|
|
142
|
-
examples: [],
|
|
143
|
-
references: [],
|
|
144
|
-
notes: [],
|
|
145
|
-
deprecated: nil
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
current_section = :description
|
|
149
|
-
current_example = nil
|
|
150
|
-
description_lines = []
|
|
151
|
-
|
|
152
|
-
comment.lines.each do |line|
|
|
153
|
-
line = line.chomp
|
|
154
|
-
|
|
155
|
-
# Check for YARD tags
|
|
156
|
-
if line =~ /^@example\s*(.*)/
|
|
157
|
-
# Save current example if exists
|
|
158
|
-
result[:examples] << current_example if current_example
|
|
159
|
-
|
|
160
|
-
current_example = {
|
|
161
|
-
'label' => $1.strip,
|
|
162
|
-
'code' => ''
|
|
163
|
-
}
|
|
164
|
-
current_section = :example
|
|
165
|
-
elsif line =~ /^@see\s+(.*)/
|
|
166
|
-
reference = $1.strip
|
|
167
|
-
# Parse URL and description
|
|
168
|
-
if reference =~ /^(https?:\/\/\S+)\s+(.*)/
|
|
169
|
-
result[:references] << { 'url' => $1, 'description' => $2 }
|
|
170
|
-
elsif reference =~ /^(https?:\/\/\S+)/
|
|
171
|
-
result[:references] << { 'url' => $1 }
|
|
172
|
-
else
|
|
173
|
-
result[:references] << { 'text' => reference }
|
|
174
|
-
end
|
|
175
|
-
current_section = :description
|
|
176
|
-
elsif line =~ /^@note\s+(.*)/
|
|
177
|
-
result[:notes] << $1.strip
|
|
178
|
-
current_section = :description
|
|
179
|
-
elsif line =~ /^@deprecated\s*(.*)/
|
|
180
|
-
result[:deprecated] = $1.strip
|
|
181
|
-
result[:deprecated] = true if result[:deprecated].empty?
|
|
182
|
-
current_section = :description
|
|
183
|
-
else
|
|
184
|
-
# Regular content
|
|
185
|
-
if current_section == :example && current_example
|
|
186
|
-
# Remove leading spaces from example code (preserve relative indentation)
|
|
187
|
-
current_example['code'] += line + "\n"
|
|
188
|
-
elsif current_section == :description
|
|
189
|
-
description_lines << line unless line.strip.empty? && description_lines.empty?
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
# Save last example
|
|
195
|
-
result[:examples] << current_example if current_example
|
|
196
|
-
|
|
197
|
-
# Clean up example code (remove extra leading whitespace)
|
|
198
|
-
result[:examples].each do |example|
|
|
199
|
-
example['code'] = unindent(example['code'])
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Join description lines
|
|
203
|
-
result[:description] = description_lines.join("\n").strip
|
|
204
|
-
|
|
205
|
-
# Remove empty arrays/nils
|
|
206
|
-
result.delete(:examples) if result[:examples].empty?
|
|
207
|
-
result.delete(:references) if result[:references].empty?
|
|
208
|
-
result.delete(:notes) if result[:notes].empty?
|
|
209
|
-
result.delete(:deprecated) if result[:deprecated].nil?
|
|
210
|
-
|
|
211
|
-
result
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
# Extract properties from class body
|
|
215
|
-
def extract_properties(class_node, source)
|
|
216
|
-
properties = {}
|
|
217
|
-
|
|
218
|
-
class_body = class_node.children[2]
|
|
219
|
-
return properties unless class_body
|
|
220
|
-
|
|
221
|
-
traverse_class_body(class_body, source) do |method_name, args, comment|
|
|
222
|
-
# These are the DSL property definition methods
|
|
223
|
-
if [:string, :int, :bool, :float, :action, :views, :array, :hash,
|
|
224
|
-
:icon, :color, :length, :date, :date_time, :text, :any,
|
|
225
|
-
:panels_builder, :menu, :singleton_array].include?(method_name)
|
|
226
|
-
|
|
227
|
-
property_name = args.first
|
|
228
|
-
next unless property_name
|
|
229
|
-
|
|
230
|
-
# Parse property comment
|
|
231
|
-
prop_doc = parse_property_comment(comment)
|
|
232
|
-
|
|
233
|
-
# Extract options if present (for hash, singleton_array, etc.)
|
|
234
|
-
options = extract_property_options(args)
|
|
235
|
-
|
|
236
|
-
properties[property_name] = {
|
|
237
|
-
'type' => method_name.to_s,
|
|
238
|
-
'description' => prop_doc[:description],
|
|
239
|
-
'required' => options[:required] || false,
|
|
240
|
-
'options' => options[:options],
|
|
241
|
-
'examples' => prop_doc[:examples],
|
|
242
|
-
'notes' => prop_doc[:notes],
|
|
243
|
-
'deprecated' => prop_doc[:deprecated]
|
|
244
|
-
}.compact
|
|
245
|
-
|
|
246
|
-
# Remove empty arrays
|
|
247
|
-
properties[property_name].delete('examples') if properties[property_name]['examples']&.empty?
|
|
248
|
-
properties[property_name].delete('notes') if properties[property_name]['notes']&.empty?
|
|
249
|
-
end
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
properties
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
# Traverse class body to find method calls (property definitions)
|
|
256
|
-
def traverse_class_body(node, source, &block)
|
|
257
|
-
return unless node.is_a?(Parser::AST::Node)
|
|
258
|
-
|
|
259
|
-
if node.type == :send
|
|
260
|
-
receiver = node.children[0]
|
|
261
|
-
method_name = node.children[1]
|
|
262
|
-
args = node.children[2..-1].map { |arg| extract_symbol_or_string(arg) }
|
|
263
|
-
comment = extract_comment(node, source)
|
|
264
|
-
|
|
265
|
-
# Only process calls without a receiver (DSL methods)
|
|
266
|
-
yield method_name, args, comment if receiver.nil?
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
node.children.each do |child|
|
|
270
|
-
traverse_class_body(child, source, &block)
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
# Extract symbol or string value from AST node
|
|
275
|
-
def extract_symbol_or_string(node)
|
|
276
|
-
return nil unless node.is_a?(Parser::AST::Node)
|
|
277
|
-
|
|
278
|
-
case node.type
|
|
279
|
-
when :sym
|
|
280
|
-
node.children[0].to_s
|
|
281
|
-
when :str
|
|
282
|
-
node.children[0]
|
|
283
|
-
when :hash
|
|
284
|
-
extract_hash(node)
|
|
285
|
-
else
|
|
286
|
-
nil
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
# Extract hash from AST node
|
|
291
|
-
def extract_hash(node)
|
|
292
|
-
return nil unless node.type == :hash
|
|
293
|
-
|
|
294
|
-
result = {}
|
|
295
|
-
node.children.each do |pair|
|
|
296
|
-
next unless pair.type == :pair
|
|
297
|
-
key = extract_symbol_or_string(pair.children[0])
|
|
298
|
-
value = extract_symbol_or_string(pair.children[1]) || extract_array(pair.children[1])
|
|
299
|
-
result[key] = value if key
|
|
300
|
-
end
|
|
301
|
-
result
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
# Extract array from AST node
|
|
305
|
-
def extract_array(node)
|
|
306
|
-
return nil unless node.is_a?(Parser::AST::Node) && node.type == :array
|
|
307
|
-
|
|
308
|
-
node.children.map { |child| extract_symbol_or_string(child) }.compact
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
# Extract property options from arguments
|
|
312
|
-
def extract_property_options(args)
|
|
313
|
-
options = { required: false }
|
|
314
|
-
|
|
315
|
-
args.each do |arg|
|
|
316
|
-
if arg.is_a?(Hash)
|
|
317
|
-
if arg['required']
|
|
318
|
-
options[:required] = true
|
|
319
|
-
end
|
|
320
|
-
if arg['optional']
|
|
321
|
-
options[:options] = { 'optional' => arg['optional'] }
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
options
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
# Parse property comment
|
|
330
|
-
def parse_property_comment(comment)
|
|
331
|
-
return {} if comment.empty?
|
|
332
|
-
|
|
333
|
-
result = {
|
|
334
|
-
description: '',
|
|
335
|
-
examples: [],
|
|
336
|
-
notes: [],
|
|
337
|
-
deprecated: nil
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
description_lines = []
|
|
341
|
-
|
|
342
|
-
comment.lines.each do |line|
|
|
343
|
-
line = line.chomp
|
|
344
|
-
|
|
345
|
-
if line =~ /^@example\s+(.*)/
|
|
346
|
-
result[:examples] << $1.strip
|
|
347
|
-
elsif line =~ /^@note\s+(.*)/
|
|
348
|
-
result[:notes] << $1.strip
|
|
349
|
-
elsif line =~ /^@deprecated\s*(.*)/
|
|
350
|
-
result[:deprecated] = $1.strip
|
|
351
|
-
result[:deprecated] = true if result[:deprecated].empty?
|
|
352
|
-
else
|
|
353
|
-
description_lines << line unless line.strip.empty? && description_lines.empty?
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
result[:description] = description_lines.join("\n").strip
|
|
358
|
-
|
|
359
|
-
result
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
# Convert CamelCase to snake_case
|
|
363
|
-
def underscore(string)
|
|
364
|
-
string.gsub(/::/, '_')
|
|
365
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
366
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
367
|
-
.tr('-', '_')
|
|
368
|
-
.downcase
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
# Remove common leading whitespace from multi-line strings
|
|
372
|
-
def unindent(text)
|
|
373
|
-
return text if text.empty?
|
|
374
|
-
|
|
375
|
-
lines = text.lines
|
|
376
|
-
# Find minimum indentation (ignoring empty lines)
|
|
377
|
-
min_indent = lines
|
|
378
|
-
.reject { |line| line.strip.empty? }
|
|
379
|
-
.map { |line| line.match(/^(\s*)/)[1].length }
|
|
380
|
-
.min || 0
|
|
381
|
-
|
|
382
|
-
# Remove that amount of indentation from each line
|
|
383
|
-
lines.map { |line| line.strip.empty? ? line : line[min_indent..-1] }.join
|
|
384
|
-
end
|
|
385
|
-
end
|
|
386
|
-
end
|