class SoberSwag::Reporting::Output::Struct
A DSL for building “output object structs.”
Attributes
Public Class Methods
Serialize an object to a hash.
@param value [Object] value to serialize @param view [Symbol] which view to use to serialize this output. @return [Hash] the serialized ruby hash, suitable for passing to JSON.generate
# File lib/sober_swag/reporting/output/struct.rb, line 124 def call(value, view: :base) view(view).output.call(value) end
Define a view for this object.
Views behave like their own output structs, which inherit the parent (or 'base' view). This means that fields after the definition of a view *will be present in the view*. This enables views to maintain a subtyping relationship.
Your base view should thus serialize *as little as possible*.
View classes get defined as child constants. So, if I write `define_view(:foo)` on a struct called `Person`, I will get `Person::Foo` as a class I can use if I want!
@param name [Symbol] name of this view. @yieldself [self] a block in which you can add more fields to the view. @return [Class]
# File lib/sober_swag/reporting/output/struct.rb, line 161 def define_view(name, &block) # rubocop:disable Metrics/MethodLength raise ArgumentError, "duplicate view #{name}" if name == :base || views.include?(name) classy_name = name.to_s.classify Class.new(self).tap do |c| c.instance_eval(&block) c.define_singleton_method(:define_view) do |*| raise ArgumentError, 'no nesting views' end c.define_singleton_method(:identifier) do [parent_struct.identifier, classy_name.gsub('::', '.')].join('.') end const_set(classy_name, c) view_map[name] = c end end
Set a description for the type of this output. It will show up as a description in the component key for this output. Right now that unfortunately will not render with ReDoc, but it should eventually.
@param val [String, nil] pass if you want to set, otherwise you will get the current value @return [String] the description assigned to this object, if any.
# File lib/sober_swag/reporting/output/struct.rb, line 47 def description(val = nil) return @description unless val @description = val end
Define a new field to be serialized.
@param name [Symbol] name of this field. @param output [Interface] reporting output to use to serialize. @param description [String,nil] description for this field. @param block [Proc, nil]
If a block is given, it will be defined as a method on the output object struct. If the block takes an argument, the object being serialized will be passed to it. Otherwise, it will be accessible as `#object_to_serialize` from within the body. You can access other methods from this method.
# File lib/sober_swag/reporting/output/struct.rb, line 22 def field(name, output, description: nil, &extract) define_field(name, extract) object_fields[name] = Object::Property.new( output.view(:base).via_map(&name.to_proc), description: description ) end
Used to generate 'allOf' subtyping relationships. Probably do not call this yourself.
@return [Interface]
# File lib/sober_swag/reporting/output/struct.rb, line 72 def identified_with_base object_output.referenced([identifier, 'Base'].join('.')) end
Used to generate 'allOf' subtyping relationships. Probably do not call this yourself.
# File lib/sober_swag/reporting/output/struct.rb, line 79 def identified_without_base if parent_struct MergeObjects .new(parent_struct.inherited_output, object_output) else object_output end.referenced(identifier) end
Set a new identifier for this output object.
@param value [String, nil] provide a new identifier to use.
Stateful operation.
@return [String] identifier key to use in the components hash.
In rare cases (a class with no name and no set identifier) it can return nil. We consider this case "unsupported", IE, please do not do that.
# File lib/sober_swag/reporting/output/struct.rb, line 219 def identifier(value = nil) if value @identifier = value else @identifier || name&.gsub('::', '.') end end
When this class is inherited, it sets up a future subtyping relationship. This gets expressed with 'allOf' in the generated swagger.
# File lib/sober_swag/reporting/output/struct.rb, line 207 def inherited(other) other.parent_struct = self unless self == ::SoberSwag::Reporting::Output::Struct end
Used to generate 'allOf' subtyping relationships. Probably do not call this yourself! Use {#single_output} instead.
This allows us to implement inheritance. So, if you inherit from another output object struct, you get its methods and attributes. Views behave as if they have inherited the base object.
This means that any views added to any parent output objects will be visible in children. @return [Interface]
# File lib/sober_swag/reporting/output/struct.rb, line 99 def inherited_output inherited = if parent_struct MergeObjects .new(parent_struct.inherited_output, object_output) else object_output end identifier ? inherited.referenced([identifier, 'Base'].join('.')) : inherited end
# File lib/sober_swag/reporting/output/struct.rb, line 247 def initialize(struct_serialized) @_struct_serialized = struct_serialized end
@return [Hash<Symbol, Object::Property>] the properties defined directly on this object.
Does not include inherited fields!
# File lib/sober_swag/reporting/output/struct.rb, line 141 def object_fields @object_fields ||= {} end
# File lib/sober_swag/reporting/output/struct.rb, line 31 def object_output base = Object.new(object_fields).via_map { |o| new(o) } if description base.described(description) else base end end
Serialize an object to a hash, with type-checking.
@param value [Object] value to serialize @param view [Symbol] which view to use @return [Hash] the serialized ruby hash, suitable for passsing to JSON.generate
# File lib/sober_swag/reporting/output/struct.rb, line 134 def serialize_report(value, view: :base) view(view).output.serialize_report(value) end
An output for this specific schema type. If this schema has any views, it will be defined as a map of possible views to the actual views used. Otherwise, it will directly be the base definition.
# File lib/sober_swag/reporting/output/struct.rb, line 57 def single_output single = if view_map.any? Viewed.new(identified_view_map) else inherited_output end identifier ? single.referenced(identifier) : single end
Schema for this output. Will include views, if applicable.
# File lib/sober_swag/reporting/output/struct.rb, line 114 def swagger_schema single_output.swagger_schema end
@param name [Symbol] which view to use. @return [Interface] a serializer suitable for this interface.
# File lib/sober_swag/reporting/output/struct.rb, line 196 def view(name) return inherited_output if name == :base view_map.fetch(name).view(:base) end
@return Hash<Symbol,Class> map of potential views.
Does not include the 'base' view.
# File lib/sober_swag/reporting/output/struct.rb, line 182 def view_map @view_map ||= {} end
@return [Set<Symbol>] all applicable views.
Will always include `:base`.
# File lib/sober_swag/reporting/output/struct.rb, line 189 def views [:base, *view_map.keys].to_set end
Private Class Methods
# File lib/sober_swag/reporting/output/struct.rb, line 233 def define_field(method, extractor) e = if extractor.nil? proc { _struct_serialized.public_send(method) } elsif extractor.arity == 1 proc { extractor.call(_struct_serialized) } else extractor end define_method(method, &e) end
# File lib/sober_swag/reporting/output/struct.rb, line 229 def identified_view_map view_map.transform_values(&:identified_without_base).merge(base: inherited_output) end
Public Instance Methods
The object to serialize. Use this if you're defining your own methods.
# File lib/sober_swag/reporting/output/struct.rb, line 256 def object_to_serialize @_struct_serialized end