Class: Generator::Type

Inherits:
Object
  • Object
show all
Includes:
FileWriter, SchemaHelpers
Defined in:
lib/generator/builders/type.rb

Constant Summary collapse

NAMESPACES =
{
  "notifications" => "Notifications",
  "reports" => "Reports",
  "feeds" => "Feeds",
  "data_kiosk" => "DataKiosk",
}.freeze

Constants included from Formatter

Formatter::MAX_LINE_LENGTH

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from SchemaHelpers

#api_name_for_type_resolver, #attribute_name_for, #generate_nested_types!, #generate_rbs!, #generic_placeholder?, #needs_money?, #nested_type_files

Methods included from Formatter

#convert_doc_links_to_full_url, #convert_html_links_to_yard, #format_method_definition, #split_long_comment_line

Methods included from FileWriter

#format_files, #write_file

Constructor Details

#initialize(name, definition, api_name, specification = nil) ⇒ Type

Returns a new instance of Type.



27
28
29
30
31
32
# File 'lib/generator/builders/type.rb', line 27

def initialize(name, definition, api_name, specification = nil)
  @name = name
  @definition = definition
  @api_name = api_name
  @specification = specification
end

Instance Attribute Details

#api_nameObject (readonly)

Returns the value of attribute api_name.



24
25
26
# File 'lib/generator/builders/type.rb', line 24

def api_name
  @api_name
end

#circular_dependenciesObject

Returns the value of attribute circular_dependencies.



25
26
27
# File 'lib/generator/builders/type.rb', line 25

def circular_dependencies
  @circular_dependencies
end

#cycle_edgesObject

Returns the value of attribute cycle_edges.



25
26
27
# File 'lib/generator/builders/type.rb', line 25

def cycle_edges
  @cycle_edges
end

#definitionObject (readonly)

Returns the value of attribute definition.



24
25
26
# File 'lib/generator/builders/type.rb', line 24

def definition
  @definition
end

#nameObject (readonly)

Returns the value of attribute name.



24
25
26
# File 'lib/generator/builders/type.rb', line 24

def name
  @name
end

#specificationObject (readonly)

Returns the value of attribute specification.



24
25
26
# File 'lib/generator/builders/type.rb', line 24

def specification
  @specification
end

Instance Method Details

#attribute_declaration_for(prop_name, prop_def) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/generator/builders/type.rb', line 53

def attribute_declaration_for(prop_name, prop_def)
  name = attribute_name_for(prop_name, prop_def)
  type = ruby_type_for(prop_def, prop_name: prop_name)
  required = required_properties.include?(prop_name)
  nullable = Array(prop_def["type"]).include?("null")

  parts = [":#{name}", type]
  parts << "null: false" if required ? !nullable : prop_def["x-non-null"]
  parts << "from: \"#{prop_name}\"" if name != prop_name

  "#{required ? "attribute" : "attribute?"}(#{parts.join(", ")})"
end

#class_nameObject



38
39
40
# File 'lib/generator/builders/type.rb', line 38

def class_name
  Naming.class_name(name)
end

#generateObject



34
35
36
# File 'lib/generator/builders/type.rb', line 34

def generate
  write_file(file_path, render)
end

#library_nameObject



85
86
87
88
89
90
# File 'lib/generator/builders/type.rb', line 85

def library_name
  filename = class_name.underscore
  base = namespace ? "peddler/#{api_name}" : "peddler/apis/#{api_name}"

  "#{base}/#{filename}"
end

#namespaceObject



42
43
44
45
# File 'lib/generator/builders/type.rb', line 42

def namespace
  prefix = api_name.split("/", 2).first
  NAMESPACES[prefix]
end

#namespace_nameObject



47
48
49
50
51
# File 'lib/generator/builders/type.rb', line 47

def namespace_name
  return unless namespace

  api_name.split("/", 2).last.camelize
end

#propertiesObject



66
67
68
69
70
71
72
73
74
# File 'lib/generator/builders/type.rb', line 66

def properties
  props = if definition["allOf"]
    merge_from_all_of("properties") { |props| props || {} }
  else
    definition["properties"] || {}
  end

  sorted_properties(props)
end

#rbs_class_definitionObject

Returns just the class definition without module wrapping Used for consolidated RBS generation



163
164
165
166
167
168
169
# File 'lib/generator/builders/type.rb', line 163

def rbs_class_definition
  if array_type?
    array_rbs_class_definition
  else
    structure_rbs_class_definition
  end
end

#required_propertiesObject



76
77
78
79
80
81
82
83
# File 'lib/generator/builders/type.rb', line 76

def required_properties
  if definition["allOf"]
    result = merge_from_all_of("required") { |req| req || [] }
    result.is_a?(Array) ? result.uniq : result
  else
    definition["required"] || []
  end
end

#ruby_type_for(prop_def, for_comment: false, for_rbs: false, prop_name: nil) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/generator/builders/type.rb', line 92

def ruby_type_for(prop_def, for_comment: false, for_rbs: false, prop_name: nil)
  resolved_type = type_resolver.resolve(prop_def, for_comment: for_comment, for_rbs: for_rbs, prop_name: prop_name)

  # Handle self-references properly
  return resolved_type if resolved_type == ":self"

  # Only use string class names for the specific edges that cause cycles
  unless for_comment
    # Handle direct references
    if resolved_type.is_a?(String) &&
        resolved_type !~ /^[:\[]/ && resolved_type != "String" && resolved_type != "Integer" &&
        resolved_type != "Float" && !resolved_type.include?("Hash") && !resolved_type.include?("Array") &&
        resolved_type != "Money" && resolved_type != ":boolean"
      # Return as a string for lazy loading
      return "\"#{resolved_type}\"" if cycle_edge?(resolved_type)
    end

    # Handle arrays containing cycle-causing types
    if resolved_type.is_a?(String)
      inner_type = array_inner_type(resolved_type)
      # Return as array with string class name for lazy loading
      return "[\"#{inner_type}\"]" if cycle_edge?(inner_type)
    end
  end

  resolved_type
end

#type_dependenciesObject



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/generator/builders/type.rb', line 120

def type_dependencies
  dependencies = []
  properties.each do |_prop_name, prop_def|
    dependencies.concat(extract_dependencies_from_property(prop_def))
  end
  # Only include dependencies that actually get generated as type files
  # Exclude self-references to avoid requiring ourselves
  # Only exclude the specific edges that cause cycles (not all edges between circular types!)
  dependencies.select do |dep|
    generated_type?(dep) &&
      dep != name &&
      !(cycle_edges && cycle_edges.include?([name, dep]))
  end.uniq
end

#uses_string_class_names?Boolean

Returns:

  • (Boolean)


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/generator/builders/type.rb', line 135

def uses_string_class_names?
  properties.any? do |_prop_name, prop_def|
    resolved_type = type_resolver.resolve(prop_def)

    # Check for self-references
    if resolved_type == class_name || resolved_type == "[#{class_name}]"
      return true
    end

    # Check for cycle-causing edges
    if resolved_type.is_a?(String)
      # Handle direct types
      if resolved_type !~ /^[:\[]/ && resolved_type != "String" && resolved_type != "Integer" &&
          resolved_type != "Float" && resolved_type != "Hash" && resolved_type != "Array" &&
          resolved_type != "Money" && resolved_type != ":boolean"
        return true if cycle_edge?(resolved_type)
      end

      # Handle arrays
      return true if cycle_edge?(array_inner_type(resolved_type))
    end

    false
  end
end