Class: Generator::Notification
- Inherits:
-
Object
- Object
- Generator::Notification
- Includes:
- FileWriter, SchemaGenerator, SchemaHelpers
- Defined in:
- lib/generator/notification.rb
Overview
Generates Ruby type classes for SP-API notification payloads from JSON Schema files
Constant Summary
Constants included from Formatter
Instance Attribute Summary collapse
-
#file_path ⇒ Object
readonly
Returns the value of attribute file_path.
-
#schema ⇒ Object
readonly
Returns the value of attribute schema.
Class Method Summary collapse
Instance Method Summary collapse
-
#class_name ⇒ Object
Class name for the notification (e.g., "AnyOfferChanged").
-
#envelope_properties ⇒ Object
Get envelope properties (notificationVersion, notificationType, eventTime, etc.).
-
#envelope_required_properties ⇒ Object
Get required envelope properties.
-
#generate_schema_types(written_files, all_types) ⇒ Object
-
#initialize(file_path) ⇒ Notification
constructor
A new instance of Notification.
-
#notification_name ⇒ Object
Extract notification name from filename (e.g., "AnyOfferChangedNotification.json" => "AnyOfferChanged").
-
#notification_object_name ⇒ Object
Get the actual notification object name within payload (handles casing variations).
-
#notification_type ⇒ Object
Detect if this is Type A (nested) or Type B (flat) notification.
-
#payload_key_name ⇒ Object
Get the actual payload key name from the schema (handles PascalCase vs camelCase).
-
#payload_properties ⇒ Object
Get payload properties based on notification type.
-
#payload_required_properties ⇒ Object
Get required payload properties based on notification type.
-
#payload_schema ⇒ Object
Get payload schema (the full payload object).
-
#payload_version ⇒ Object
Extract payload version from the schema examples or filename.
-
#raw_description ⇒ Object
Class description from schema (no leading spaces - template handles indentation) Raw description from schema (will be formatted by Type class).
-
#replace_inline_objects_with_refs(properties, extracted_types) ⇒ Object
Replace inline object definitions with $ref pointers to extracted types.
-
#wrapper_properties ⇒ Object
Properties from the wrapper level (notificationVersion, notificationType, etc.).
-
#wrapper_required_properties ⇒ Object
Required properties from the wrapper level.
Methods included from SchemaGenerator
#generate, #generate_main_file!, #generate_supplementary_files, included, #needs_money?, #output_file_path, #sorted_properties
Methods included from SchemaHelpers
#api_name_for_type_resolver, #attribute_name_for, #format_property_comment, #generate_nested_types!, #generate_rbs!, #generic_placeholder?, #needs_money?, #nested_type_files, #ruby_type_for, #type_resolver
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
Constructor Details
#initialize(file_path) ⇒ Notification
Returns a new instance of Notification.
35 36 37 38 39 40 |
# File 'lib/generator/notification.rb', line 35 def initialize(file_path) @file_path = file_path @schema = JSON.parse(File.read(file_path)) resolve_root_ref! apply_json_patch! end |
Instance Attribute Details
#file_path ⇒ Object (readonly)
Returns the value of attribute file_path.
27 28 29 |
# File 'lib/generator/notification.rb', line 27 def file_path @file_path end |
#schema ⇒ Object (readonly)
Returns the value of attribute schema.
27 28 29 |
# File 'lib/generator/notification.rb', line 27 def schema @schema end |
Class Method Details
.schema_type ⇒ Object
30 31 32 |
# File 'lib/generator/notification.rb', line 30 def schema_type "notifications" end |
Instance Method Details
#class_name ⇒ Object
Class name for the notification (e.g., "AnyOfferChanged")
84 85 86 87 |
# File 'lib/generator/notification.rb', line 84 def class_name # Underscore first to ensure ActiveSupport::Inflector applies acronym rules correctly notification_name.underscore.camelize end |
#envelope_properties ⇒ Object
Get envelope properties (notificationVersion, notificationType, eventTime, etc.)
134 135 136 137 138 139 140 141 |
# File 'lib/generator/notification.rb', line 134 def envelope_properties keys = ["notificationVersion", "notificationType", "payloadVersion", "eventTime", "notificationMetadata"] keys.flat_map { |key| [key, key.sub(/\A./, &:upcase)] }.each_with_object({}) do |key, props| prop = schema.dig("properties", key) props[key] = prop if prop end end |
#envelope_required_properties ⇒ Object
Get required envelope properties
144 145 146 147 148 |
# File 'lib/generator/notification.rb', line 144 def envelope_required_properties required = schema["required"] || [] envelope_keys = envelope_properties.keys required.select { |r| envelope_keys.include?(r) } end |
#generate_schema_types(written_files, all_types) ⇒ Object
42 43 44 45 46 47 48 49 50 51 |
# File 'lib/generator/notification.rb', line 42 def generate_schema_types(written_files, all_types) # Generate Payload and Notification as types payload_results = generate_payload_types! written_files.concat(payload_results[:files]) all_types.concat(payload_results[:types]) notification_result = generate_notification_type! written_files << notification_result[:file] all_types << notification_result[:type] end |
#notification_name ⇒ Object
Extract notification name from filename (e.g., "AnyOfferChangedNotification.json" => "AnyOfferChanged")
54 55 56 57 58 59 |
# File 'lib/generator/notification.rb', line 54 def notification_name base_name = File.basename(file_path, ".json") # Remove "Notification" suffix but keep version suffix (e.g., "_2023-12-13") # Convert dashes in version suffix to underscores for valid Ruby identifiers base_name.sub(/Notification$/, "").tr("-", "_") end |
#notification_object_name ⇒ Object
Get the actual notification object name within payload (handles casing variations)
74 75 76 77 78 79 80 81 |
# File 'lib/generator/notification.rb', line 74 def notification_object_name payload = resolved_payload_schema return unless payload notification_object_candidates.find do |candidate| payload.dig("properties", candidate) end end |
#notification_type ⇒ Object
Detect if this is Type A (nested) or Type B (flat) notification
127 128 129 130 131 |
# File 'lib/generator/notification.rb', line 127 def notification_type return :unknown unless resolved_payload_schema notification_object_schema ? :nested : :flat end |
#payload_key_name ⇒ Object
Get the actual payload key name from the schema (handles PascalCase vs camelCase)
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/generator/notification.rb', line 62 def payload_key_name # Check if schema uses "payload" or "Payload" if schema.dig("properties", "payload") "payload" elsif schema.dig("properties", "Payload") "Payload" else "payload" # fallback end end |
#payload_properties ⇒ Object
Get payload properties based on notification type
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/generator/notification.rb', line 156 def payload_properties payload = resolved_payload_schema return {} unless payload if notification_type == :nested nested_obj = notification_object_schema return sorted_properties(nested_obj["properties"] || {}) if nested_obj {} else # Type B: use payload properties directly sorted_properties(payload["properties"] || {}) end end |
#payload_required_properties ⇒ Object
Get required payload properties based on notification type
172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/generator/notification.rb', line 172 def payload_required_properties payload = resolved_payload_schema return [] unless payload if notification_type == :nested nested_obj = notification_object_schema nested_obj ? (nested_obj["required"] || []) : [] else # Type B: use payload required directly payload["required"] || [] end end |
#payload_schema ⇒ Object
Get payload schema (the full payload object)
151 152 153 |
# File 'lib/generator/notification.rb', line 151 def payload_schema schema.dig("properties", "payload") || schema.dig("properties", "Payload") end |
#payload_version ⇒ Object
Extract payload version from the schema examples or filename
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/generator/notification.rb', line 90 def payload_version # Try to get from examples first examples = schema.dig("examples") if examples&.first return examples.first["payloadVersion"] || examples.first["PayloadVersion"] end # Fall back to filename-based version (e.g., "_2023-12-13") if file_path =~ /_(\d{4}-\d{2}-\d{2})\.json$/ matched = ::Regexp.last_match(1) return matched if matched end # Default to 1.0 if no version found "1.0" end |
#raw_description ⇒ Object
Class description from schema (no leading spaces - template handles indentation) Raw description from schema (will be formatted by Type class)
119 120 121 122 123 124 |
# File 'lib/generator/notification.rb', line 119 def raw_description return unless schema["description"] return if generic_placeholder?(schema["description"]) schema["description"] end |
#replace_inline_objects_with_refs(properties, extracted_types) ⇒ Object
Replace inline object definitions with $ref pointers to extracted types
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/generator/notification.rb', line 186 def replace_inline_objects_with_refs(properties, extracted_types) result = {} properties.each do |prop_name, prop_def| # Check if this is a money-like object if MoneyDetector.money_like?(prop_def) result[prop_name] = { "$ref" => "#/definitions/Money", "description" => prop_def["description"], }.compact next end # Check if this property matches an extracted type name if prop_def["type"] == "object" && extracted_types.key?(prop_name) # Replace with $ref result[prop_name] = { "$ref" => "#/definitions/#{prop_name}" } elsif prop_def["type"] == "array" && prop_def["items"] # Handle array items - check if they're objects that match extracted types items = prop_def["items"] # Handle case where items is an array (non-standard format) items = items.first if items.is_a?(Array) && !items.empty? # Check if items are money-like objects if items.is_a?(Hash) && MoneyDetector.money_like?(items) result[prop_name] = prop_def.dup result[prop_name]["items"] = { "$ref" => "#/definitions/Money" } next end # Check if items are inline objects that match extracted types if items.is_a?(Hash) && (items["type"] == "object" || items["anyOf"]) item_type_name = prop_name.singularize if extracted_types.key?(item_type_name) result[prop_name] = prop_def.dup result[prop_name]["items"] = { "$ref" => "#/definitions/#{item_type_name}" } else result[prop_name] = prop_def end else result[prop_name] = prop_def end else result[prop_name] = prop_def end end result end |
#wrapper_properties ⇒ Object
Properties from the wrapper level (notificationVersion, notificationType, etc.)
108 109 110 |
# File 'lib/generator/notification.rb', line 108 def wrapper_properties sorted_properties(schema["properties"] || {}) end |
#wrapper_required_properties ⇒ Object
Required properties from the wrapper level
113 114 115 |
# File 'lib/generator/notification.rb', line 113 def wrapper_required_properties schema["required"] || [] end |