openapi-sourcetools 0.4.3 → 0.6.0

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.
data/lib/helper.rb ADDED
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright © 2024 Ismo Kärkkäinen
4
+ # Licensed under Universal Permissive License. See LICENSE.txt.
5
+
6
+ require_relative 'task'
7
+
8
+
9
+ class Helper
10
+ attr_reader :doc, :parents
11
+ attr_accessor :parent_parameters
12
+
13
+ # Stores the nearesh Hash for each Hash.
14
+ def store_parents(obj, parent = nil)
15
+ if obj.is_a?(Hash)
16
+ @parents[obj.object_id] = parent
17
+ obj.each do |k, v|
18
+ store_parents(v, obj)
19
+ end
20
+ elsif obj.is_a?(Array)
21
+ obj.each do |v|
22
+ store_parents(v, parent)
23
+ end
24
+ end
25
+ end
26
+
27
+ def initialize(doc)
28
+ @doc = doc
29
+ # For each hash in doc, set parent?
30
+ # Build an object_id to parent object mapping and use parent method?
31
+ @parents = {}
32
+ store_parents(@doc)
33
+ end
34
+
35
+ def parent(object)
36
+ @parents[object.object_id]
37
+ end
38
+
39
+ COMPONENTS = '#/components/'
40
+
41
+ def category_and_name(ref_or_obj)
42
+ ref = ref_or_obj.is_a?(Hash) ? ref_or_obj['$ref'] : ref_or_obj
43
+ return nil unless ref.is_a?(String)
44
+ return nil unless ref.start_with?(Helper::COMPONENTS)
45
+ idx = ref.index('/', Helper::COMPONENTS.size)
46
+ return nil if idx.nil?
47
+ category = ref[Helper::COMPONENTS.size...idx]
48
+ [ category, ref[(idx + 1)...ref.size] ]
49
+ end
50
+
51
+ def dereference(ref_or_obj)
52
+ cn = category_and_name(ref_or_obj)
53
+ return nil if cn.nil?
54
+ cs = @doc.dig('components', cn.first) || {}
55
+ cs[cn.last]
56
+ end
57
+
58
+ def basename(ref_or_obj)
59
+ cn = category_and_name(ref_or_obj)
60
+ return nil if cn.nil?
61
+ cn.last
62
+ end
63
+
64
+ def parameters(operation_object, empty_unless_local = false)
65
+ return [] if empty_unless_local && !operation_object.key?('parameters')
66
+ cps = @doc.dig('components', 'parameters') || {}
67
+ uniqs = {}
68
+ path_item_object = parent(operation_object)
69
+ [path_item_object, operation_object].each do |p|
70
+ p.fetch('parameters', []).each do |param|
71
+ r = basename(param)
72
+ r = cps[r] if r.is_a?(String)
73
+ uniqs["#{r['name']}:#{r['in']}"] = param
74
+ end
75
+ end
76
+ uniqs.keys.sort!.map { |k| uniqs[k] }
77
+ end
78
+ end
79
+
80
+
81
+ class HelperTask
82
+ include TaskInterface
83
+
84
+ def generate(context_binding)
85
+ Gen.h = Helper.new(Gen.doc)
86
+ end
87
+
88
+ def output_name
89
+ nil
90
+ end
91
+
92
+ def discard
93
+ true
94
+ end
95
+ end
96
+
data/lib/loaders.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright © 2024 Ismo Kärkkäinen
4
+ # Licensed under Universal Permissive License. See LICENSE.txt.
5
+
6
+ module Loaders
7
+
8
+ GEM_PREFIX = 'gem:'
9
+
10
+ def self.gem_loader(name)
11
+ return false unless name.downcase.start_with?(GEM_PREFIX)
12
+ begin
13
+ require(name.slice(GEM_PREFIX.size...name.size))
14
+ rescue LoadError => e
15
+ raise StandardError, "Failed to require #{name}\n#{e.to_s}"
16
+ rescue Exception => e
17
+ raise StandardError, "Problem with #{name}\n#{e.to_s}"
18
+ end
19
+ true
20
+ end
21
+
22
+ RUBY_EXT = '.rb'
23
+
24
+ def self.ruby_loader(name)
25
+ return false unless name.downcase.end_with?(RUBY_EXT)
26
+ origwd = Dir.pwd
27
+ d = File.dirname(name)
28
+ Dir.chdir(d) unless d == '.'
29
+ begin
30
+ require(File.join(Dir.pwd, File.basename(name)))
31
+ rescue LoadError => e
32
+ raise StandardError, "Failed to require #{name}\n#{e.to_s}"
33
+ rescue Exception => e
34
+ raise StandardError, "Problem with #{name}\n#{e.to_s}"
35
+ end
36
+ Dir.chdir(origwd) unless d == '.'
37
+ true
38
+ end
39
+
40
+ def self.loaders
41
+ [ method(:gem_loader), method(:ruby_loader) ]
42
+ end
43
+
44
+ def self.document
45
+ %(
46
+ - #{Loaders::GEM_PREFIX}gem_name : requires the gem.
47
+ - ruby_file#{Loaders::RUBY_EXT} : changes to Ruby file directory and requires the file.
48
+ )
49
+ end
50
+
51
+ end
data/lib/task.rb ADDED
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright © 2024 Ismo Kärkkäinen
4
+ # Licensed under Universal Permissive License. See LICENSE.txt.
5
+
6
+ require 'erb'
7
+ require_relative 'common'
8
+
9
+
10
+ module TaskInterface
11
+ def generate(context_binding)
12
+ raise NotImplementedError
13
+ end
14
+
15
+ def output_name
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def discard
20
+ false
21
+ end
22
+
23
+ def executable
24
+ false
25
+ end
26
+ end
27
+
28
+ class Task
29
+ include TaskInterface
30
+
31
+ attr_reader :src, :template, :template_name
32
+ attr_accessor :name, :executable, :discard, :x
33
+
34
+ def initialize(src, template, template_name)
35
+ @src = src
36
+ @template = template
37
+ @template_name = template_name
38
+ if @template.nil?
39
+ raise ArgumentError, "template_name or template must be given" if @template_name.nil?
40
+ begin
41
+ @template = File.read(@template_name)
42
+ rescue Errno::ENOENT
43
+ raise StandardError, "Could not load #{@template_name}"
44
+ rescue StandardError => e
45
+ raise StandardError, "#{e}\nFailed to read #{@template_name}"
46
+ end
47
+ end
48
+ @name = nil
49
+ @executable = false
50
+ @discard = false
51
+ @x = nil
52
+ end
53
+
54
+ # If this is overridden to perform some processing but not to produce output,
55
+ # set @discard = true and return value will be ignored. No other methods are
56
+ # called in that case.
57
+ def internal_generate(context_binding)
58
+ ERB.new(@template).result(context_binding)
59
+ end
60
+
61
+ # You can override this instead of internal_generate if you do not need the
62
+ # exception handling.
63
+ def generate(context_binding)
64
+ n = @template_name.nil? ? '' : "#{@template_name} "
65
+ internal_generate(context_binding)
66
+ rescue SyntaxError => e
67
+ aargh("Template #{n}syntax error: #{e.full_message}", 5)
68
+ rescue Exception => e
69
+ aargh("Template #{n}error: #{e.full_message}", 6)
70
+ end
71
+
72
+ # This is only called when generate produced output that is not discarded.
73
+ def output_name
74
+ return @name unless @name.nil?
75
+ # Using template name may show where name assignment is missing.
76
+ # Name assignment may also be missing in the task creation stage.
77
+ return File.basename(@template_name) unless @template_name.nil?
78
+ nil
79
+ end
80
+ end
81
+
82
+ class WriteTask
83
+ include TaskInterface
84
+
85
+ attr_reader :name, :contents, :executable
86
+
87
+ def initialize(name, contents, executable = false)
88
+ raise ArgumentError, "name and contents must be given" if name.nil? || contents.nil?
89
+ @name = name
90
+ @contents = contents
91
+ @executable = executable
92
+ end
93
+
94
+ def generate(context_binding)
95
+ @contents
96
+ end
97
+
98
+ def output_name
99
+ @name
100
+ end
101
+ end
metadata CHANGED
@@ -1,37 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi-sourcetools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismo Kärkkäinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-29 00:00:00.000000000 Z
11
+ date: 2024-07-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |2
14
14
 
15
- Tools for generating source code from API specification in OpenAPI format.
15
+ Tools for handling API specification in OpenAPI format. Replacement of
16
+ duplicate definitions with references. Other checks. Does not validate
17
+ the document against OpenAPI format specification.
16
18
  email: ismokarkkainen@icloud.com
17
19
  executables:
18
- - openapi-generatecode
20
+ - openapi-addheaders
21
+ - openapi-addparameters
22
+ - openapi-addresponses
23
+ - openapi-addschemas
24
+ - openapi-checkschemas
19
25
  - openapi-frequencies
26
+ - openapi-generate
20
27
  - openapi-merge
21
28
  - openapi-processpaths
22
29
  extensions: []
23
30
  extra_rdoc_files: []
24
31
  files:
25
32
  - LICENSE.txt
33
+ - bin/openapi-addheaders
34
+ - bin/openapi-addparameters
35
+ - bin/openapi-addresponses
36
+ - bin/openapi-addschemas
37
+ - bin/openapi-checkschemas
26
38
  - bin/openapi-frequencies
27
- - bin/openapi-generatecode
39
+ - bin/openapi-generate
28
40
  - bin/openapi-merge
29
41
  - bin/openapi-processpaths
42
+ - lib/apiobjects.rb
30
43
  - lib/common.rb
44
+ - lib/gen.rb
45
+ - lib/generate.rb
46
+ - lib/helper.rb
47
+ - lib/loaders.rb
48
+ - lib/task.rb
31
49
  homepage: https://xn--ismo-krkkinen-gfbd.fi/openapi-sourcetools/index.html
32
50
  licenses:
33
51
  - UPL-1.0
34
- metadata: {}
52
+ metadata:
53
+ rubygems_mfa_required: 'true'
35
54
  post_install_message:
36
55
  rdoc_options: []
37
56
  require_paths:
@@ -40,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
40
59
  requirements:
41
60
  - - ">="
42
61
  - !ruby/object:Gem::Version
43
- version: '0'
62
+ version: 3.0.0
44
63
  required_rubygems_version: !ruby/object:Gem::Requirement
45
64
  requirements:
46
65
  - - ">="
47
66
  - !ruby/object:Gem::Version
48
67
  version: '0'
49
68
  requirements: []
50
- rubygems_version: 3.1.2
69
+ rubygems_version: 3.2.33
51
70
  signing_key:
52
71
  specification_version: 4
53
72
  summary: Tools for creating source code from API specification.
@@ -1,128 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # Copyright © 2021 Ismo Kärkkäinen
5
- # Licensed under Universal Permissive License. See LICENSE.txt.
6
-
7
- require_relative '../lib/common.rb'
8
- require 'optparse'
9
- require 'yaml'
10
- require 'erb'
11
-
12
-
13
- default_env(:out, '')
14
- default_env(:in, '')
15
- default_env(:template, '')
16
-
17
- ENV['POSIXLY_CORRECT'] = '1'
18
- parser = OptionParser.new do |opts|
19
- opts.summary_indent = ' '
20
- opts.summary_width = 26
21
- opts.banner = 'Usage: openapi-generatecode [options] [additions...]'
22
- opts.separator ''
23
- opts.separator 'Options (equivalent environment variable and value in parentheses):'
24
- opts.on('-i', '--input FILE', 'Read processed API from FILE, not stdin (IN=FILE).') do |f|
25
- env(:in, f)
26
- end
27
- opts.on('-o', '--output FILE', 'Output result to FILE, not stdout (OUT=FILE).') do |f|
28
- env(:out, f)
29
- end
30
- opts.on('-t', '--template FILE', 'Read template from FILE (TEMPLATE=FILE).') do |f|
31
- env(:template, f)
32
- end
33
- opts.on('-h', '--help', 'Print this help and exit.') do
34
- $stdout.puts %(#{opts}
35
-
36
- Loads ERB template and optional additions to a context along with the processed
37
- API document and produces the template result.
38
- )
39
- exit 0
40
- end
41
- end
42
- parser.parse!
43
-
44
- aargh('Template file name must be given.', 1) if env(:template).empty?
45
-
46
- def load_content(name)
47
- name.empty? ? $stdin.read : File.read(name)
48
- rescue Errno::ENOENT
49
- aargh("Could not load #{name || 'stdin'}", 2)
50
- rescue StandardError => e
51
- aargh("#{e}\nFailed to read #{name || 'stdin'}", 2)
52
- end
53
-
54
- class Generator
55
- attr_accessor :addition, :order, :full_name_order, :template, :document
56
-
57
- def initialize(document_content, template_content)
58
- @addition = Hash.new
59
- @order = []
60
- @full_name_order = []
61
- @document = document_content
62
- @template = template_content
63
- end
64
-
65
- def get_binding
66
- binding
67
- end
68
-
69
- def add(name, content, strip_suffix)
70
- @full_name_order.push({ filename: name, contents: content })
71
- name = File.basename(name)
72
- @order.push name
73
- if strip_suffix
74
- idx = name.rindex('.')
75
- name = name.slice(0, idx) unless idx.nil?
76
- end
77
- @addition[name] = content
78
- end
79
- end
80
- t = load_content(env(:template))
81
- d = load_content(env(:in))
82
- begin
83
- $generator = Generator.new(YAML.safe_load(d), t)
84
- rescue StandardError => e
85
- aargh('Failed to parse API document.', 3)
86
- end
87
-
88
- ARGV.each do |name|
89
- aargh('Addition file name is empty.', 1) if name.empty?
90
- if name.end_with? '.rb'
91
- begin
92
- require File.absolute_path(name)
93
- rescue SyntaxError => e
94
- aargh("Syntax error in addition #{name}: #{e.to_s}", 4)
95
- rescue StandardError => e
96
- aargh("Failed to require addition #{name}: #{e.to_s}", 5)
97
- end
98
- else
99
- c = load_content(name)
100
- begin
101
- d = YAML.safe_load(c)
102
- rescue StandardError
103
- d = c
104
- end
105
- $generator.add(name, d, name.upcase.end_with?('.YAML') || name.upcase.end_with?('.JSON'))
106
- end
107
- end
108
-
109
- begin
110
- out = ERB.new($generator.template).result($generator.get_binding)
111
- rescue SyntaxError => e
112
- aargh("Template syntax error: #{e.to_s}", 6)
113
- rescue StandardError => e
114
- aargh("Template error: #{e.to_s}", 7)
115
- end
116
-
117
- output = env(:out)
118
- if output.empty?
119
- output = $stdout
120
- else
121
- begin
122
- output = File.open(output, 'w')
123
- rescue StandardError
124
- aargh("Failed to open for writing: #{output}", 1)
125
- end
126
- end
127
- output.write(out)
128
- output.close