diff --git a/examples/usual/example1/season.rb b/examples/usual/example1/season.rb index 4c86af5..337c760 100644 --- a/examples/usual/example1/season.rb +++ b/examples/usual/example1/season.rb @@ -7,11 +7,22 @@ class Season < Datory::Base # uuid! :serialId, to: :serial_id integer! :number + string! :code # many! :episodes, include: Episode date! :premieredOn, to: :premiered_on date? :endedOn, to: :ended_on + + # deserialize + getter :code do |attributes:| + "s#{attributes.fetch(:number)}" + end + + # serialize + setter :code do |attributes:| + "s#{attributes.fetch(:number)}" + end end end end diff --git a/examples/usual/example2/product.rb b/examples/usual/example2/product.rb index b109472..bc43786 100644 --- a/examples/usual/example2/product.rb +++ b/examples/usual/example2/product.rb @@ -6,6 +6,7 @@ class Product < Datory::Base uuid! :id string! :title + string! :formattedTitle, to: :formatted_title money! :price money? :discount @@ -13,6 +14,16 @@ class Product < Datory::Base integer! :quantity, min: 1, max: 10 duration? :installmentDuration, to: :installment_duration + + # deserialize + getter :formattedTitle do |attributes:| + "The New #{attributes.fetch(:title)} (from getter)" + end + + # serialize + setter :formatted_title do |attributes:| + "The New #{attributes.fetch(:title)} (from setter)" + end end end end diff --git a/examples/usual/example3/language.rb b/examples/usual/example3/language.rb index 445dfbb..7c755ae 100644 --- a/examples/usual/example3/language.rb +++ b/examples/usual/example3/language.rb @@ -6,6 +6,7 @@ class Language < Datory::Base uuid! :id string! :name + string? :fullName, to: :full_name # TODO: Need to prepare this example: # { @@ -32,6 +33,21 @@ class Language < Datory::Base one? :lastEOLVersion, to: :last_eol, include: Version many? :previousVersions, to: :previous, include: Version + + # deserialize + getter :fullName do |**| + nil + end + + # serialize + setter :full_name do |attributes:| + language_name = attributes.fetch(:name) + current_version_name = attributes.dig(:current, :name) + + next language_name if current_version_name.blank? + + "#{language_name} (#{current_version_name})" + end end end end diff --git a/lib/datory/attributes/collection.rb b/lib/datory/attributes/collection.rb index c9c8053..28fee8a 100644 --- a/lib/datory/attributes/collection.rb +++ b/lib/datory/attributes/collection.rb @@ -18,6 +18,10 @@ def internal_names map { |attribute| attribute.to.name } end + def external_names + map { |attribute| attribute.from.name } + end + def include_class_exist? @include_class_exist ||= filter do |attribute| # rubocop:disable Performance/Count include_class = attribute.to.include_class diff --git a/lib/datory/attributes/descriptor.rb b/lib/datory/attributes/descriptor.rb index ab43659..e085f43 100644 --- a/lib/datory/attributes/descriptor.rb +++ b/lib/datory/attributes/descriptor.rb @@ -26,7 +26,10 @@ def describe(service_class_name:, collection_of_attributes:) # rubocop:disable M row << attribute.from.type row << attribute.to.name row << attribute.to.type - row << (include_class if include_class <= Datory::Base) if collection_of_attributes.include_class_exist? + + if collection_of_attributes.include_class_exist? && !include_class.nil? + row << (include_class if include_class.respond_to?(:<=) && include_class <= Datory::Base) + end rows << row end diff --git a/lib/datory/attributes/serialization/model.rb b/lib/datory/attributes/serialization/model.rb index 516c133..d04336e 100644 --- a/lib/datory/attributes/serialization/model.rb +++ b/lib/datory/attributes/serialization/model.rb @@ -12,9 +12,9 @@ def self.to_hash(...) new.to_hash(...) end - def prepare(data) + def prepare(data, collection_of_attributes) if data.is_a?(Hash) - build(data.deep_dup) + build(collection_of_attributes, data.deep_dup) else data end @@ -28,17 +28,34 @@ def to_hash(data) end end - def build(attributes = {}) # rubocop:disable Metrics/MethodLength - attributes.each do |key, value| + private + + def define_setter(key, value) + self.class.send(:attr_accessor, key) + + instance_variable_set(:"@#{key}", value) + + self + end + + def build(collection_of_attributes, attributes = {}) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + additional_attributes = collection_of_attributes.internal_names.difference(attributes.keys).to_h do |key| + [key, nil] + end + + attributes.merge(additional_attributes).each do |key, value| self.class.send(:attr_accessor, key) instance_variable_set(:"@#{key}", value) if value.is_a?(Array) - value.map! { |item| Datory::Attributes::Serialization::Model.prepare(item) } + value.map! { |item| Datory::Attributes::Serialization::Model.prepare(item, collection_of_attributes) } instance_variable_set(:"@#{key}", value) elsif value.is_a?(Hash) - instance_variable_set(:"@#{key}", Datory::Attributes::Serialization::Model.prepare(value)) + instance_variable_set( + :"@#{key}", + Datory::Attributes::Serialization::Model.prepare(value, collection_of_attributes) + ) else instance_variable_set(:"@#{key}", value) end diff --git a/lib/datory/attributes/workspace.rb b/lib/datory/attributes/workspace.rb index f7c9a55..0ff5e12 100644 --- a/lib/datory/attributes/workspace.rb +++ b/lib/datory/attributes/workspace.rb @@ -5,7 +5,7 @@ module Attributes module Workspace private - def serialize(model:, collection_of_attributes:) + def serialize(model:, collection_of_attributes:, **) super return nil if model.nil? # NOTE: When `one` is optional and not passed @@ -18,7 +18,7 @@ def serialize(model:, collection_of_attributes:) ) end - def deserialize(incoming_attributes:, collection_of_attributes:) + def deserialize(incoming_attributes:, collection_of_attributes:, **) super Deserialization::ServiceBuilder.build!(self, incoming_attributes, collection_of_attributes) diff --git a/lib/datory/base.rb b/lib/datory/base.rb index fb1bbf5..0f81fb1 100644 --- a/lib/datory/base.rb +++ b/lib/datory/base.rb @@ -4,6 +4,8 @@ module Datory class Base include Info::DSL include Context::DSL + include Getters::DSL + include Setters::DSL include Attributes::DSL end end diff --git a/lib/datory/context/callable.rb b/lib/datory/context/callable.rb index 6245c25..4fdcc80 100644 --- a/lib/datory/context/callable.rb +++ b/lib/datory/context/callable.rb @@ -14,7 +14,7 @@ def serialize(model) # rubocop:disable Metrics/MethodLength end else context = send(:new, _datory_to_model: false) - model = Datory::Attributes::Serialization::Model.prepare(model) + model = Datory::Attributes::Serialization::Model.prepare(model, collection_of_attributes) _serialize(context, model) end rescue Datory::Service::Exceptions::Input, @@ -23,7 +23,7 @@ def serialize(model) # rubocop:disable Metrics/MethodLength raise Datory::Exceptions::SerializationError.new(message: e.message) end - def deserialize(data) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + def deserialize(data) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/PerceivedComplexity prepared_data = if data.is_a?(Datory::Base) Datory::Attributes::Serialization::Model.to_hash(data) @@ -40,6 +40,13 @@ def deserialize(data) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize else context = send(:new, _datory_to_model: false) + additional_attributes = + collection_of_attributes.external_names.difference(prepared_data.symbolize_keys.keys).to_h do |key| + [key, nil] + end + + prepared_data = prepared_data.merge(additional_attributes) + _deserialize(context, **prepared_data) end rescue Datory::Service::Exceptions::Input, @@ -96,7 +103,8 @@ def _serialize(context, model) context.send( :_serialize, model: model, - collection_of_attributes: collection_of_attributes + collection_of_attributes: collection_of_attributes, + collection_of_setters: collection_of_setters ) end @@ -104,7 +112,8 @@ def _deserialize(context, **attributes) context.send( :_deserialize, incoming_attributes: attributes.symbolize_keys, - collection_of_attributes: collection_of_attributes + collection_of_attributes: collection_of_attributes, + collection_of_getters: collection_of_getters ) end diff --git a/lib/datory/context/workspace.rb b/lib/datory/context/workspace.rb index ff2ed7c..85a3198 100644 --- a/lib/datory/context/workspace.rb +++ b/lib/datory/context/workspace.rb @@ -5,6 +5,14 @@ module Context module Workspace private + def define_setter(key, value) + self.class.send(:attr_accessor, key) + + instance_variable_set(:"@#{key}", value) + + self + end + def merge!(attributes) attributes.each do |key, value| instance_variable_set(:"@#{key}", value) @@ -19,17 +27,19 @@ def keys instance_variables.map { |instance_variable| instance_variable.to_s.sub(/^@/, "").to_sym } end - def _serialize(model:, collection_of_attributes:) + def _serialize(model:, collection_of_attributes:, collection_of_setters:) serialize( model: model, - collection_of_attributes: collection_of_attributes + collection_of_attributes: collection_of_attributes, + collection_of_setters: collection_of_setters ) end - def _deserialize(incoming_attributes:, collection_of_attributes:) + def _deserialize(incoming_attributes:, collection_of_attributes:, collection_of_getters:) deserialize( incoming_attributes: incoming_attributes, - collection_of_attributes: collection_of_attributes + collection_of_attributes: collection_of_attributes, + collection_of_getters: collection_of_getters ) end diff --git a/lib/datory/getters/collection.rb b/lib/datory/getters/collection.rb new file mode 100644 index 0000000..6d22935 --- /dev/null +++ b/lib/datory/getters/collection.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Datory + module Getters + class Collection + extend Forwardable + def_delegators :@collection, :<<, :each, :merge + + def initialize(collection = Set.new) + @collection = collection + end + end + end +end diff --git a/lib/datory/getters/dsl.rb b/lib/datory/getters/dsl.rb new file mode 100644 index 0000000..3bdcdd3 --- /dev/null +++ b/lib/datory/getters/dsl.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Datory + module Getters + module DSL + def self.included(base) + base.extend(ClassMethods) + base.include(Workspace) + end + + module ClassMethods + def inherited(child) + super + + child.send(:collection_of_getters).merge(collection_of_getters) + end + + private + + def getter(name) + collection_of_getters << Getter.new(name, ->(attributes:) { yield(attributes: attributes) }) + end + + def collection_of_getters + @collection_of_getters ||= Collection.new + end + end + end + end +end diff --git a/lib/datory/getters/getter.rb b/lib/datory/getters/getter.rb new file mode 100644 index 0000000..1890cda --- /dev/null +++ b/lib/datory/getters/getter.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Datory + module Getters + class Getter + attr_reader :name, :block + + def initialize(name, block) + @name = name + @block = block + end + end + end +end diff --git a/lib/datory/getters/workspace.rb b/lib/datory/getters/workspace.rb new file mode 100644 index 0000000..99e1a95 --- /dev/null +++ b/lib/datory/getters/workspace.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Datory + module Getters + module Workspace + private + + def deserialize(incoming_attributes:, collection_of_attributes:, collection_of_getters:) + super + + collection_of_getters.each do |getter| + incoming_attributes.merge!(getter.name => getter.block.call(attributes: incoming_attributes)) + end + end + end + end +end diff --git a/lib/datory/setters/collection.rb b/lib/datory/setters/collection.rb new file mode 100644 index 0000000..e37d3c2 --- /dev/null +++ b/lib/datory/setters/collection.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Datory + module Setters + class Collection + extend Forwardable + def_delegators :@collection, :<<, :each, :merge + + def initialize(collection = Set.new) + @collection = collection + end + end + end +end diff --git a/lib/datory/setters/dsl.rb b/lib/datory/setters/dsl.rb new file mode 100644 index 0000000..aae6949 --- /dev/null +++ b/lib/datory/setters/dsl.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Datory + module Setters + module DSL + def self.included(base) + base.extend(ClassMethods) + base.include(Workspace) + end + + module ClassMethods + def inherited(child) + super + + child.send(:collection_of_setters).merge(collection_of_setters) + end + + private + + def setter(name) + collection_of_setters << Setter.new(name, ->(attributes:) { yield(attributes: attributes) }) + end + + def collection_of_setters + @collection_of_setters ||= Collection.new + end + end + end + end +end diff --git a/lib/datory/setters/setter.rb b/lib/datory/setters/setter.rb new file mode 100644 index 0000000..c082e85 --- /dev/null +++ b/lib/datory/setters/setter.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Datory + module Setters + class Setter + attr_reader :name, :block + + def initialize(name, block) + @name = name + @block = block + end + end + end +end diff --git a/lib/datory/setters/workspace.rb b/lib/datory/setters/workspace.rb new file mode 100644 index 0000000..7af9e79 --- /dev/null +++ b/lib/datory/setters/workspace.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Datory + module Setters + module Workspace + private + + def serialize(model:, collection_of_attributes:, collection_of_setters:) + super + + collection_of_setters.each do |setter| + hash = Datory::Attributes::Serialization::Model.to_hash(model) + + model.send(:define_setter, setter.name, setter.block.call(attributes: hash)) + end + end + end + end +end diff --git a/spec/examples/usual/example1/serial_spec.rb b/spec/examples/usual/example1/serial_spec.rb index b2d7135..1b429c8 100644 --- a/spec/examples/usual/example1/serial_spec.rb +++ b/spec/examples/usual/example1/serial_spec.rb @@ -296,6 +296,7 @@ { id: "27df8a44-556f-4e08-9984-4aa663b78f98", number: 1, + code: "s1", premieredOn: "2008-09-03", endedOn: "2008-11-26" } @@ -354,6 +355,7 @@ { id: "27df8a44-556f-4e08-9984-4aa663b78f98", number: 1, + code: "s1", premieredOn: "2008-09-03", endedOn: "2008-11-26" } @@ -1203,6 +1205,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | id | String | id | String | | number | Integer | number | Integer | + | code | String | code | String | | premieredOn | String | premiered_on | Date | | endedOn | [String, NilClass] | ended_on | [Date, NilClass] | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1319,6 +1322,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | id | String | id | String | | number | Integer | number | Integer | + | code | String | code | String | | premieredOn | String | premiered_on | Date | | endedOn | [String, NilClass] | ended_on | [Date, NilClass] | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/spec/examples/usual/example2/product_spec.rb b/spec/examples/usual/example2/product_spec.rb index 9d1bbe0..9e385cd 100644 --- a/spec/examples/usual/example2/product_spec.rb +++ b/spec/examples/usual/example2/product_spec.rb @@ -139,6 +139,7 @@ { id: "55363a14-aa9a-4eba-9276-7f7cec432123", title: "iPhone 15 Pro", + formattedTitle: "The New iPhone 15 Pro (from setter)", price_cents: 999_00, price_currency: "USD", discount_cents: nil, @@ -162,6 +163,7 @@ { id: "55363a14-aa9a-4eba-9276-7f7cec432123", title: "iPhone 15 Pro", + formattedTitle: "The New iPhone 15 Pro (from setter)", price_cents: 999_00, price_currency: "USD", discount_cents: nil, @@ -215,6 +217,7 @@ { id: "55363a14-aa9a-4eba-9276-7f7cec432123", title: "iPhone 15 Pro", + formatted_title: "The New iPhone 15 Pro (from setter)", price_cents: 999_00, price_currency: "USD", quantity: 5 @@ -240,6 +243,7 @@ have_attributes( id: "55363a14-aa9a-4eba-9276-7f7cec432123", title: "iPhone 15 Pro", + formatted_title: "The New iPhone 15 Pro (from getter)", price_cents: 999_00, price_currency: "USD", quantity: 5 @@ -384,6 +388,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | id | String | id | String | | title | String | title | String | + | formattedTitle | String | formatted_title | String | | price_cents | Integer | price_cents | Integer | | price_currency | String | price_currency | String | | discount_cents | [Integer, NilClass] | discount_cents | [Integer, NilClass] | @@ -413,6 +418,7 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | id | String | id | String | | title | String | title | String | + | formattedTitle | String | formatted_title | String | | price_cents | Integer | price_cents | Integer | | price_currency | String | price_currency | String | | discount_cents | [Integer, NilClass] | discount_cents | [Integer, NilClass] | @@ -478,6 +484,27 @@ include: nil } }, + formattedTitle: { + from: { + name: :formattedTitle, + type: String, + min: nil, + max: nil, + consists_of: false, + format: nil + }, + to: { + name: :formatted_title, + type: String, + required: true, + default: nil, + min: nil, + max: nil, + consists_of: false, + format: nil, + include: nil + } + }, price_cents: { from: { name: :price_cents, diff --git a/spec/examples/usual/example3/language_spec.rb b/spec/examples/usual/example3/language_spec.rb index fb5da41..d85bfa9 100644 --- a/spec/examples/usual/example3/language_spec.rb +++ b/spec/examples/usual/example3/language_spec.rb @@ -137,6 +137,7 @@ { id: "73031620-be3b-4088-9a78-5589ff7e1f61", name: "Ruby", + fullName: "Ruby (3.3.1)", currentVersion: { name: "3.3.1", releasedAt: nil, @@ -161,6 +162,7 @@ { id: "73031620-be3b-4088-9a78-5589ff7e1f61", name: "Ruby", + fullName: "Ruby (3.3.1)", currentVersion: { name: "3.3.1", releasedAt: nil, @@ -374,17 +376,18 @@ expect { perform }.to( output( <<~TABLE - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | Usual::Example3::Language | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | Attribute | From | To | As | Include | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | id | String | id | String | | - | name | String | name | String | | - | currentVersion | [Usual::Example3::Version, Hash] | current | [Usual::Example3::Version, Hash] | Usual::Example3::Version | - | lastEOLVersion | [Usual::Example3::Version, Hash, NilClass] | last_eol | [Usual::Example3::Version, Hash, NilClass] | Usual::Example3::Version | - | previousVersions | Array | previous | Array | Usual::Example3::Version | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | Usual::Example3::Language | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | Attribute | From | To | As | Include | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | id | String | id | String | | + | name | String | name | String | | + | fullName | [String, NilClass] | full_name | [String, NilClass] | | + | currentVersion | [Usual::Example3::Version, Hash] | current | [Usual::Example3::Version, Hash] | Usual::Example3::Version | + | lastEOLVersion | [Usual::Example3::Version, Hash, NilClass] | last_eol | [Usual::Example3::Version, Hash, NilClass] | Usual::Example3::Version | + | previousVersions | Array | previous | Array | Usual::Example3::Version | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TABLE ).to_stdout ) @@ -400,17 +403,18 @@ expect { perform }.to( output( <<~TABLE - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | Usual::Example3::Language | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | Attribute | From | To | As | Include | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - | id | String | id | String | | - | name | String | name | String | | - | currentVersion | [Usual::Example3::Version, Hash] | current | [Usual::Example3::Version, Hash] | Usual::Example3::Version | - | lastEOLVersion | [Usual::Example3::Version, Hash, NilClass] | last_eol | [Usual::Example3::Version, Hash, NilClass] | Usual::Example3::Version | - | previousVersions | Array | previous | Array | Usual::Example3::Version | - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | Usual::Example3::Language | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | Attribute | From | To | As | Include | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | id | String | id | String | | + | name | String | name | String | | + | fullName | [String, NilClass] | full_name | [String, NilClass] | | + | currentVersion | [Usual::Example3::Version, Hash] | current | [Usual::Example3::Version, Hash] | Usual::Example3::Version | + | lastEOLVersion | [Usual::Example3::Version, Hash, NilClass] | last_eol | [Usual::Example3::Version, Hash, NilClass] | Usual::Example3::Version | + | previousVersions | Array | previous | Array | Usual::Example3::Version | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TABLE ).to_stdout ) @@ -469,6 +473,27 @@ include: nil } }, + fullName: { + from: { + name: :fullName, + type: [String, NilClass], + min: nil, + max: nil, + consists_of: false, + format: nil + }, + to: { + name: :full_name, + type: [String, NilClass], + required: false, + default: nil, + min: nil, + max: nil, + consists_of: false, + format: nil, + include: nil + } + }, currentVersion: { from: { name: :currentVersion,