r2-oas 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +12 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  4. data/.gitignore +12 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +7 -0
  7. data/.rubocop_todo.yml +224 -0
  8. data/.travis.yml +22 -0
  9. data/CHANGELOG.md +3 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/Gemfile +12 -0
  12. data/Gemfile.lock +207 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.ja.md +585 -0
  15. data/README.md +582 -0
  16. data/Rakefile +8 -0
  17. data/bin/console +12 -0
  18. data/bin/setup +8 -0
  19. data/docs/HOW_TO_ANALYZE_DOCS.md +875 -0
  20. data/docs/HOW_TO_CLEAN_DOCS.md +19 -0
  21. data/docs/HOW_TO_DEPLOY_SWAGGER_DOC.md +839 -0
  22. data/docs/HOW_TO_DISPLAY_PATHS_LIST.md +28 -0
  23. data/docs/HOW_TO_DISPLAY_PATHS_STATS.md +53 -0
  24. data/docs/HOW_TO_GENERATE_DOCS.md +256 -0
  25. data/docs/HOW_TO_MONITOR_SWAGGER_DOC.md +219 -0
  26. data/docs/HOW_TO_START_SWAGGER_EDITOR.md +218 -0
  27. data/docs/HOW_TO_START_SWAGGER_UI.md +262 -0
  28. data/docs/HOW_TO_USE_HOOK_WHEN_GENERATE_DOC.md +244 -0
  29. data/docs/HOW_TO_USE_SCHEMA_NAMESPACE.md +176 -0
  30. data/docs/HOW_TO_USE_TAG_NAMESPACE.md +176 -0
  31. data/docs/versions/v3.md +155 -0
  32. data/lib/r2-oas.rb +36 -0
  33. data/lib/r2-oas/app_configuration.rb +102 -0
  34. data/lib/r2-oas/app_configuration/server.rb +35 -0
  35. data/lib/r2-oas/app_configuration/swagger.rb +35 -0
  36. data/lib/r2-oas/app_configuration/swagger/editor.rb +47 -0
  37. data/lib/r2-oas/app_configuration/swagger/ui.rb +45 -0
  38. data/lib/r2-oas/app_configuration/tool.rb +31 -0
  39. data/lib/r2-oas/app_configuration/tool/paths/stats.rb +43 -0
  40. data/lib/r2-oas/base.rb +48 -0
  41. data/lib/r2-oas/configuration.rb +69 -0
  42. data/lib/r2-oas/configuration/paths_config.rb +44 -0
  43. data/lib/r2-oas/deploy/client.rb +43 -0
  44. data/lib/r2-oas/deploy/swagger-ui/dist/favicon-16x16.png +0 -0
  45. data/lib/r2-oas/deploy/swagger-ui/dist/favicon-32x32.png +0 -0
  46. data/lib/r2-oas/deploy/swagger-ui/dist/oauth2-redirect.html +68 -0
  47. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui-bundle.js +134 -0
  48. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui-bundle.js.map +1 -0
  49. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui-standalone-preset.js +22 -0
  50. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui-standalone-preset.js.map +1 -0
  51. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui.css +4 -0
  52. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui.css.map +1 -0
  53. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui.js +9 -0
  54. data/lib/r2-oas/deploy/swagger-ui/dist/swagger-ui.js.map +1 -0
  55. data/lib/r2-oas/deploy/swagger-ui/index.html.erb +60 -0
  56. data/lib/r2-oas/errors.rb +7 -0
  57. data/lib/r2-oas/hooks/global_hook.rb +20 -0
  58. data/lib/r2-oas/hooks/hook.rb +77 -0
  59. data/lib/r2-oas/hooks/repository.rb +15 -0
  60. data/lib/r2-oas/logger/stdout_logger.rb +129 -0
  61. data/lib/r2-oas/pluggable_configuration.rb +33 -0
  62. data/lib/r2-oas/plugins/schema/v3/object/hookable_base_object.rb +100 -0
  63. data/lib/r2-oas/routing/adjustor.rb +44 -0
  64. data/lib/r2-oas/routing/base.rb +12 -0
  65. data/lib/r2-oas/routing/components/all.rb +5 -0
  66. data/lib/r2-oas/routing/components/base_component.rb +10 -0
  67. data/lib/r2-oas/routing/components/path_component.rb +67 -0
  68. data/lib/r2-oas/routing/components/request_component.rb +75 -0
  69. data/lib/r2-oas/routing/components/verb_component.rb +21 -0
  70. data/lib/r2-oas/routing/parser.rb +93 -0
  71. data/lib/r2-oas/schema/analyzer.rb +23 -0
  72. data/lib/r2-oas/schema/base.rb +11 -0
  73. data/lib/r2-oas/schema/cleaner.rb +23 -0
  74. data/lib/r2-oas/schema/editor.rb +120 -0
  75. data/lib/r2-oas/schema/generator.rb +23 -0
  76. data/lib/r2-oas/schema/manager/file/path_item_file_manager.rb +24 -0
  77. data/lib/r2-oas/schema/monitor.rb +52 -0
  78. data/lib/r2-oas/schema/squeezer.rb +23 -0
  79. data/lib/r2-oas/schema/ui.rb +74 -0
  80. data/lib/r2-oas/schema/v3/analyzer.rb +58 -0
  81. data/lib/r2-oas/schema/v3/analyzer/base_analyzer.rb +76 -0
  82. data/lib/r2-oas/schema/v3/analyzer/components/object_analyzer.rb +38 -0
  83. data/lib/r2-oas/schema/v3/analyzer/components_analyzer.rb +30 -0
  84. data/lib/r2-oas/schema/v3/analyzer/path_analyzer.rb +116 -0
  85. data/lib/r2-oas/schema/v3/analyzer/tag_analyzer.rb +38 -0
  86. data/lib/r2-oas/schema/v3/base.rb +28 -0
  87. data/lib/r2-oas/schema/v3/cleaner.rb +19 -0
  88. data/lib/r2-oas/schema/v3/cleaner/base_cleaner.rb +30 -0
  89. data/lib/r2-oas/schema/v3/cleaner/components_cleaner.rb +42 -0
  90. data/lib/r2-oas/schema/v3/generator.rb +28 -0
  91. data/lib/r2-oas/schema/v3/generator/base_generator.rb +88 -0
  92. data/lib/r2-oas/schema/v3/generator/components/object_generator.rb +83 -0
  93. data/lib/r2-oas/schema/v3/generator/components/request_body_generator.rb +45 -0
  94. data/lib/r2-oas/schema/v3/generator/components_generator.rb +38 -0
  95. data/lib/r2-oas/schema/v3/generator/doc_generator.rb +49 -0
  96. data/lib/r2-oas/schema/v3/generator/path_generator.rb +90 -0
  97. data/lib/r2-oas/schema/v3/generator/schema_generator.rb +78 -0
  98. data/lib/r2-oas/schema/v3/manager/diff/base_array_diff_manager.rb +60 -0
  99. data/lib/r2-oas/schema/v3/manager/diff/base_diff_manager.rb +29 -0
  100. data/lib/r2-oas/schema/v3/manager/diff/base_hash_diff_manager.rb +95 -0
  101. data/lib/r2-oas/schema/v3/manager/diff/components_diff_manager.rb +19 -0
  102. data/lib/r2-oas/schema/v3/manager/diff/tag_diff_manager.rb +17 -0
  103. data/lib/r2-oas/schema/v3/manager/file/base_file_manager.rb +60 -0
  104. data/lib/r2-oas/schema/v3/manager/file/components_file_manager.rb +22 -0
  105. data/lib/r2-oas/schema/v3/manager/file/include_ref_base_file_manager.rb +88 -0
  106. data/lib/r2-oas/schema/v3/manager/file/path_item_file_manager.rb +22 -0
  107. data/lib/r2-oas/schema/v3/manager/file_manager.rb +12 -0
  108. data/lib/r2-oas/schema/v3/manager/pathname_manager.rb +73 -0
  109. data/lib/r2-oas/schema/v3/object/base_object.rb +65 -0
  110. data/lib/r2-oas/schema/v3/object/components/request_body_object.rb +92 -0
  111. data/lib/r2-oas/schema/v3/object/components/schema_object.rb +55 -0
  112. data/lib/r2-oas/schema/v3/object/components_object.rb +81 -0
  113. data/lib/r2-oas/schema/v3/object/external_document_object.rb +19 -0
  114. data/lib/r2-oas/schema/v3/object/info_object.rb +34 -0
  115. data/lib/r2-oas/schema/v3/object/openapi_object.rb +58 -0
  116. data/lib/r2-oas/schema/v3/object/path_item_object.rb +167 -0
  117. data/lib/r2-oas/schema/v3/object/paths_object.rb +74 -0
  118. data/lib/r2-oas/schema/v3/object/public.rb +9 -0
  119. data/lib/r2-oas/schema/v3/object/server_object.rb +21 -0
  120. data/lib/r2-oas/schema/v3/object/tag_object.rb +36 -0
  121. data/lib/r2-oas/schema/v3/squeezer.rb +29 -0
  122. data/lib/r2-oas/schema/v3/squeezer/base_squeezer.rb +37 -0
  123. data/lib/r2-oas/schema/v3/squeezer/path_squeezer.rb +28 -0
  124. data/lib/r2-oas/schema/v3/squeezer/tag_squeezer.rb +19 -0
  125. data/lib/r2-oas/shared/all.rb +3 -0
  126. data/lib/r2-oas/shared/sortable.rb +23 -0
  127. data/lib/r2-oas/task.rb +11 -0
  128. data/lib/r2-oas/task_logging.rb +39 -0
  129. data/lib/r2-oas/tasks/common.rake +26 -0
  130. data/lib/r2-oas/tasks/main.rake +117 -0
  131. data/lib/r2-oas/tasks/tool.rake +79 -0
  132. data/lib/r2-oas/tool/paths/ls.rb +15 -0
  133. data/lib/r2-oas/tool/paths/stats.rb +84 -0
  134. data/lib/r2-oas/version.rb +5 -0
  135. data/r2-oas.gemspec +56 -0
  136. metadata +373 -0
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module R2OAS
4
+ module Schema
5
+ module V3
6
+ class BaseSqueezer < Base
7
+ def initialize(schema_data, options = {})
8
+ super(options)
9
+ @schema_data = schema_data
10
+ @tag_names = create_tag_names
11
+ end
12
+
13
+ def squeeze_docs
14
+ raise NoImplementError, 'Please implement in inherited class.'
15
+ end
16
+
17
+ private
18
+
19
+ attr_accessor :many_paths_file_paths
20
+
21
+ def create_tag_names
22
+ many_paths_file_paths.each_with_object([]) do |unit_paths_path, result|
23
+ paths_from_local = YAML.load_file(unit_paths_path)
24
+
25
+ tag_name_from_path = if paths_from_local['paths'].values[0].values[0].is_a?(Array)
26
+ 'unknown'
27
+ else
28
+ paths_from_local['paths'].values[0].values[0]['tags'][0]
29
+ end
30
+
31
+ result.push(tag_name_from_path)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_squeezer'
4
+
5
+ module R2OAS
6
+ module Schema
7
+ module V3
8
+ class PathSqueezer < BaseSqueezer
9
+ VERB = %w[get put post delete options head patch trace].freeze
10
+ NOT_VERB = %w[$ref summary description servers parameters].freeze
11
+
12
+ def squeeze_docs
13
+ slice_paths_schema = @schema_data['paths'].each_with_object({}) do |(path, data_when_path), result|
14
+ data_when_path.each do |verb_or_not, data_when_verb_or_not|
15
+ if VERB.include?(verb_or_not)
16
+ include_tag_name = data_when_verb_or_not['tags'].first.in? @tag_names
17
+ result.deep_merge!(path.to_s => data_when_path) if include_tag_name
18
+ elsif NOT_VERB.include?(verb_or_not)
19
+ result.deep_merge!(path.to_s => data_when_path)
20
+ end
21
+ end
22
+ end
23
+ { 'paths' => slice_paths_schema }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_squeezer'
4
+
5
+ module R2OAS
6
+ module Schema
7
+ module V3
8
+ class TagSqueezer < BaseSqueezer
9
+ def squeeze_docs
10
+ slice_tags_schema = @schema_data['tags'].each_with_object([]) do |tag, result|
11
+ eql_tag_name = tag['name'].in? @tag_names
12
+ result.push(tag) if eql_tag_name
13
+ end
14
+ { 'tags' => slice_tags_schema }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'sortable'
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module R2OAS
4
+ module Sortable
5
+ def deep_sort(data, target)
6
+ if data.is_a?(Hash)
7
+ data.each_with_object({}) do |(key, value), result|
8
+ result[key] = if key.eql? target
9
+ if value.is_a?(Hash)
10
+ Hash[value.sort]
11
+ else
12
+ value
13
+ end
14
+ else
15
+ deep_sort(value, target)
16
+ end
17
+ end
18
+ else
19
+ data
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module R2OAS
4
+ class Task < ::Rails::Railtie
5
+ rake_tasks do
6
+ main_task_path = File.join(File.dirname(__FILE__), './tasks/main.rake')
7
+ tool_task_path = File.join(File.dirname(__FILE__), './tasks/tool.rake')
8
+ Dir[main_task_path, tool_task_path].each { |f| load f }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Scope Rails
4
+ module R2OAS
5
+ module TaskLogging
6
+ def task(*args, &block)
7
+ Rake::Task.define_task(*args) do |task|
8
+ if block_given?
9
+ debug_log task, "[#{task.name}] started"
10
+ begin
11
+ block.call(task)
12
+ debug_log task, "[#{task.name}] finished"
13
+ rescue StandardError => e
14
+ debug_log task, "[#{task.name}] failed"
15
+ raise e
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def logger
24
+ R2OAS.logger
25
+ end
26
+
27
+ def set_info_level
28
+ R2OAS.logger.level = StdoutLogger::INFO
29
+ end
30
+
31
+ def set_debug_level
32
+ R2OAS.logger.level = StdoutLogger::DEBUG
33
+ end
34
+
35
+ def debug_log(task, message)
36
+ R2OAS.logger.debug message.to_s unless task.name == 'routes:oas:debug'
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../task_logging'
4
+
5
+ namespace :routes do
6
+ namespace :oas do
7
+ extend R2OAS::TaskLogging
8
+
9
+ # private
10
+ # desc "Setup a common setting for every tasks"
11
+ task common: [:environment] do
12
+ create_dot_paths
13
+ set_info_level
14
+ end
15
+
16
+ # private
17
+ # desc "Switch the level of a logger to DEBUG"
18
+ task debug: [:common] do
19
+ set_debug_level
20
+ end
21
+
22
+ def create_dot_paths
23
+ R2OAS.paths_config.create_dot_paths
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'r2-oas/schema/editor'
4
+ require 'r2-oas/schema/ui'
5
+ require 'r2-oas/schema/monitor'
6
+ require 'r2-oas/task_logging'
7
+ load File.expand_path('common.rake', __dir__)
8
+
9
+ namespace :routes do
10
+ namespace :oas do
11
+ desc 'Generate Swagger documentation files'
12
+ task docs: [:common] do
13
+ logger.info '[R2-OAS] start'
14
+ options = { unit_paths_file_path: unit_paths_file_path, skip_load_dot_paths: true }
15
+ generator = R2OAS::Schema::Generator.new(options)
16
+ generator.generate_docs
17
+ logger.info '[R2-OAS] end'
18
+ end
19
+
20
+ desc 'Analyze Swagger documentation'
21
+ task analyze: [:common] do
22
+ logger.info '[R2-OAS] start'
23
+
24
+ analyzer_options = { type: :existing, existing_schema_file_path: existing_schema_file_path }
25
+ analyzer = R2OAS::Schema::Analyzer.new({}, {}, analyzer_options)
26
+ analyzer.analyze_docs
27
+
28
+ generator_options = { skip_generate_docs: true }
29
+ generator = R2OAS::Schema::Generator.new(generator_options)
30
+ generator.generate_docs
31
+
32
+ logger.info '[R2-OAS] end'
33
+ end
34
+
35
+ desc 'Distribute Swagger documentation'
36
+ task dist: [:common] do
37
+ logger.info '[R2-OAS] start'
38
+
39
+ generator_options = { unit_paths_file_path: unit_paths_file_path, skip_generate_docs: true }
40
+ generator = R2OAS::Schema::Generator.new(generator_options)
41
+ generator.generate_docs
42
+
43
+ logger.info '[R2-OAS] end'
44
+ end
45
+
46
+ desc 'Open Swagger Editor'
47
+ task editor: [:common] do
48
+ logger.info '[R2-OAS] start'
49
+
50
+ generator_options = { unit_paths_file_path: unit_paths_file_path, skip_generate_docs: true }
51
+ generator = R2OAS::Schema::Generator.new(generator_options)
52
+ generator.generate_docs
53
+
54
+ before_schema_data = generator.oas_doc
55
+ editor_options = { unit_paths_file_path: unit_paths_file_path }
56
+ editor = R2OAS::Schema::Editor.new(before_schema_data, editor_options)
57
+ editor.start
58
+
59
+ logger.info '[R2-OAS] end'
60
+ end
61
+
62
+ desc 'Open Swagger UI'
63
+ task ui: [:common] do
64
+ logger.info '[R2-OAS] start'
65
+
66
+ generator_options = { unit_paths_file_path: unit_paths_file_path, skip_generate_docs: true }
67
+ generator = R2OAS::Schema::Generator.new(generator_options)
68
+ generator.generate_docs
69
+
70
+ ui_options = { unit_paths_file_path: unit_paths_file_path }
71
+ ui = R2OAS::Schema::UI.new(ui_options)
72
+ ui.start
73
+
74
+ logger.info '[R2-OAS] end'
75
+ end
76
+
77
+ desc 'Monitor Swagger Document'
78
+ task monitor: [:common] do
79
+ logger.info '[R2-OAS] start'
80
+
81
+ generator_options = { unit_paths_file_path: unit_paths_file_path, skip_generate_docs: true }
82
+ generator = R2OAS::Schema::Generator.new(generator_options)
83
+ generator.generate_docs
84
+
85
+ before_schema_data = generator.oas_doc
86
+ monitor_options = { unit_paths_file_path: unit_paths_file_path }
87
+ monitor = R2OAS::Schema::Monitor.new(before_schema_data, monitor_options)
88
+ monitor.start
89
+
90
+ logger.info '[R2-OAS] end'
91
+ end
92
+
93
+ desc 'Clean Swagger Document'
94
+ task clean: [:common] do
95
+ logger.info '[R2-OAS] start'
96
+
97
+ generator_options = { skip_generate_docs: true, skip_load_dot_paths: true }
98
+ generator = R2OAS::Schema::Generator.new(generator_options)
99
+ generator.generate_docs
100
+
101
+ cleaner = R2OAS::Schema::Cleaner.new
102
+ cleaner.clean_docs
103
+
104
+ logger.info '[R2-OAS] end'
105
+ end
106
+
107
+ private
108
+
109
+ def unit_paths_file_path
110
+ ENV.fetch('PATHS_FILE', '')
111
+ end
112
+
113
+ def existing_schema_file_path
114
+ ENV.fetch('OAS_FILE', '')
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'r2-oas/deploy/client'
4
+ require 'r2-oas/tool/paths/ls'
5
+ require 'r2-oas/tool/paths/stats'
6
+ require 'r2-oas/task_logging'
7
+ load File.expand_path('common.rake', __dir__)
8
+
9
+ namespace :routes do
10
+ namespace :oas do
11
+ desc 'Deploy Swagger UI'
12
+ task deploy: [:common] do
13
+ logger.info '[R2-OAS] start'
14
+
15
+ generator_options = { unit_paths_file_path: unit_paths_file_path, skip_generate_docs: true }
16
+ generator = R2OAS::Schema::Generator.new(generator_options)
17
+ generator.generate_docs
18
+
19
+ client_options = {}
20
+ client = R2OAS::Deploy::Client.new(client_options)
21
+ client.deploy
22
+
23
+ logger.info '[R2-OAS] end'
24
+ end
25
+
26
+ desc 'Display paths list'
27
+ task paths_ls: [:common] do
28
+ fd = IO.sysopen('/dev/null', 'w+')
29
+ $stdout = IO.new(fd)
30
+ logger.level = :null
31
+ logger.info '[R2-OAS] start'
32
+ $stdout = StringIO.new
33
+
34
+ paths_ls_options = {}
35
+ paths_ls = R2OAS::Tool::Paths::Ls.new(paths_ls_options)
36
+ paths_ls.print
37
+
38
+ logger.info '[R2-OAS] end'
39
+
40
+ result = $stdout.string
41
+ $stdout = STDOUT
42
+ puts result
43
+ end
44
+
45
+ desc 'Display paths stats'
46
+ task paths_stats: [:common] do
47
+ fd = IO.sysopen('/dev/null', 'w+')
48
+ $stdout = IO.new(fd)
49
+ logger.level = :null
50
+
51
+ logger.info '[R2-OAS] start'
52
+ generator_options = { skip_generate_docs: true, skip_load_dot_paths: true }
53
+ generator = R2OAS::Schema::Generator.new(generator_options)
54
+ generator.generate_docs
55
+
56
+ $stdout = StringIO.new
57
+
58
+ paths_log_options = {}
59
+ paths_log = R2OAS::Tool::Paths::Stats.new(paths_log_options)
60
+ paths_log.print
61
+
62
+ logger.info '[R2-OAS] end'
63
+
64
+ result = $stdout.string
65
+ $stdout = STDOUT
66
+ puts result
67
+ end
68
+
69
+ private
70
+
71
+ def unit_paths_file_path
72
+ ENV.fetch('PATHS_FILE', '')
73
+ end
74
+
75
+ def existing_schema_file_path
76
+ ENV.fetch('OAS_FILE', '')
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module R2OAS
4
+ module Tool
5
+ module Paths
6
+ class Ls < Base
7
+ def print
8
+ Dir.glob("#{schema_save_dir_path}/paths/**/**.yml").each do |path|
9
+ puts path
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'terminal-table'
4
+ require 'paint'
5
+ require 'forwardable'
6
+
7
+ module R2OAS
8
+ module Tool
9
+ module Paths
10
+ class Stats < Base
11
+ extend Forwardable
12
+
13
+ TIMESTAMPS = ['Created At', 'Updated At'].freeze
14
+ TABLE_TITLE = 'Paths Stats'
15
+
16
+ def initialize(options = {})
17
+ super
18
+ @paths_list = Dir.glob("#{schema_save_dir_path}/paths/**/**.yml")
19
+ @path_from = Pathname(File.dirname(File.expand_path(root_dir_path)))
20
+ @paths_stats = tool.paths_stats
21
+ end
22
+
23
+ def print
24
+ table.title = Paint[TABLE_TITLE, table_title_color]
25
+ puts table
26
+ puts "\n#{Paint['Red', warning_color]}: over #{month_to_turn_to_warning_color} months since the last update."
27
+ end
28
+
29
+ private
30
+
31
+ def_delegators :@paths_stats, :month_to_turn_to_warning_color, :warning_color, :table_title_color, :heading_color, :highlight_color
32
+
33
+ def table
34
+ @table ||= Terminal::Table.new do |t|
35
+ @paths_list.each_with_index do |file_path, index|
36
+ t.headings = ['No', 'File Path', *TIMESTAMPS].map { |head| Paint[head, heading_color] }
37
+ t << table_content(index, file_path)
38
+ t.style = { all_separators: true }
39
+ end
40
+ end
41
+ end
42
+
43
+ def table_content(index, file_path)
44
+ content = [(index + 1).to_s, relative_file_path(file_path), *timestamps(file_path)]
45
+ if file_path.in? paths_config.many_paths_file_paths
46
+ content.map { |c| Paint[c, highlight_color] }
47
+ else
48
+ content
49
+ end
50
+ end
51
+
52
+ def relative_file_path(file_path)
53
+ path_to = Pathname(file_path)
54
+ path_to.relative_path_from(@path_from).to_s
55
+ end
56
+
57
+ def timestamps(file_path)
58
+ timestamps_data(file_path) do |result, stat|
59
+ mtime = stat.mtime
60
+ result.deep_merge!(
61
+ mtime: expired?(mtime) ? Paint[mtime, warning_color] : mtime
62
+ )
63
+ end.values
64
+ end
65
+
66
+ def timestamps_data(file_path)
67
+ stat = File::Stat.new(file_path)
68
+ result = {
69
+ birthtime: stat.birthtime,
70
+ mtime: stat.mtime
71
+ }
72
+ yield result, stat if block_given?
73
+ result
74
+ end
75
+
76
+ def expired?(mtime)
77
+ month = month_to_turn_to_warning_color.send(:month)
78
+ expired_at = Time.current.ago(month)
79
+ mtime < expired_at
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end