Class: Lutaml::Model::Choice
- Inherits:
-
Object
- Object
- Lutaml::Model::Choice
- Defined in:
- lib/lutaml/model/choice.rb
Constant Summary collapse
- INTERNAL_ATTRIBUTES =
Rebound at mapping finalize: sequence-nested choices are built against the mapping object, validation resolves through the mapper class (lutaml-model#687).
i[@flat_attributes].freeze
Instance Attribute Summary collapse
-
#attributes ⇒ Object
readonly
Returns the value of attribute attributes.
-
#format ⇒ Object
Returns the value of attribute format.
-
#max ⇒ Object
readonly
Returns the value of attribute max.
-
#min ⇒ Object
readonly
Returns the value of attribute min.
-
#model ⇒ Object
Returns the value of attribute model.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #attribute(name, type, options = {}) ⇒ Object
- #can_render_empty?(_object) ⇒ Boolean
- #choice(min: 1, max: 1, &block) ⇒ Object
- #deep_duplicate(new_model, register = nil) ⇒ Object
- #flat_attributes ⇒ Object
- #import_model_attributes(model, register_id = nil) ⇒ Object
-
#initialize(model, min, max, format: nil) ⇒ Choice
constructor
A new instance of Choice.
- #optional_empty_choice?(count) ⇒ Boolean
- #pretty_print_instance_variables ⇒ Object
-
#remove_attribute(name) ⇒ Boolean
Remove an attribute from this choice block.
-
#restrict(name, options = {}) ⇒ Symbol
Restrict options on a predefined or imported attribute within this choice.
- #validate_content!(object, register = nil) ⇒ Object
- #validate_count_errors!(count, attributes) ⇒ Object
- #validate_sequence_content!(elements, appearance_count = 0, register = nil) ⇒ Object
Constructor Details
#initialize(model, min, max, format: nil) ⇒ Choice
Returns a new instance of Choice.
15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/lutaml/model/choice.rb', line 15 def initialize(model, min, max, format: nil) @attributes = [] @model = model @min = min @max = max @format = format if @min.negative? || @max.negative? raise Lutaml::Model::InvalidChoiceRangeError.new(@min, @max) end end |
Instance Attribute Details
#attributes ⇒ Object (readonly)
Returns the value of attribute attributes.
6 7 8 |
# File 'lib/lutaml/model/choice.rb', line 6 def attributes @attributes end |
#format ⇒ Object
Returns the value of attribute format.
7 8 9 |
# File 'lib/lutaml/model/choice.rb', line 7 def format @format end |
#max ⇒ Object (readonly)
Returns the value of attribute max.
6 7 8 |
# File 'lib/lutaml/model/choice.rb', line 6 def max @max end |
#min ⇒ Object (readonly)
Returns the value of attribute min.
6 7 8 |
# File 'lib/lutaml/model/choice.rb', line 6 def min @min end |
#model ⇒ Object
Returns the value of attribute model.
7 8 9 |
# File 'lib/lutaml/model/choice.rb', line 7 def model @model end |
Instance Method Details
#==(other) ⇒ Object
28 29 30 31 32 33 |
# File 'lib/lutaml/model/choice.rb', line 28 def ==(other) @attributes == other.attributes && @min == other.min && @max == other.max && @model == other.model end |
#attribute(name, type, options = {}) ⇒ Object
35 36 37 38 |
# File 'lib/lutaml/model/choice.rb', line 35 def attribute(name, type, = {}) [:choice] = self @attributes << @model.attribute(name, type, ) end |
#can_render_empty?(_object) ⇒ Boolean
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/lutaml/model/choice.rb', line 103 def can_render_empty?(_object) # Check if ALL attributes in the choice have render_empty: true # This allows empty instances of required elements to pass validation return false unless @format mapping = @model.mappings_for(@format) return false unless mapping&.elements @attributes.all? do |attribute| next true if attribute.is_a?(Choice) # Nested choices handled separately rule = mapping.elements.find { |r| r.to == attribute.name } rule&.render_empty? end rescue StandardError false end |
#choice(min: 1, max: 1, &block) ⇒ Object
70 71 72 73 74 |
# File 'lib/lutaml/model/choice.rb', line 70 def choice(min: 1, max: 1, &block) @attributes << Choice.new(@model, min, max, format: @format).tap do |c| c.instance_eval(&block) end end |
#deep_duplicate(new_model, register = nil) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/lutaml/model/choice.rb', line 153 def deep_duplicate(new_model, register = nil) choice = self.class.new(new_model, @min, @max, format: @format) attrs = @attributes.map do |attr| next attr.deep_duplicate(new_model, register) if attr.is_a?(Choice) choice_attr = new_model.attributes(register)[attr.name] next if choice_attr.nil? choice_attr.[:choice] = choice choice_attr end choice.attributes.concat(attrs.compact) choice end |
#flat_attributes ⇒ Object
76 77 78 79 80 |
# File 'lib/lutaml/model/choice.rb', line 76 def flat_attributes @flat_attributes ||= @attributes.flat_map do |attribute| attribute.is_a?(Choice) ? attribute.flat_attributes : attribute end end |
#import_model_attributes(model, register_id = nil) ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/lutaml/model/choice.rb', line 121 def import_model_attributes(model, register_id = nil) if later_importable?(model) return import_model_later(model, :import_model_attributes) end root_model_error(model) register_id ||= Lutaml::Model::Config.default_register if register_id != :default # Non-default register: store in register-specific storage only current_record = @model.register_records[register_id] ||= { attributes: {}, choice_attributes: [] } imported_attributes = Utils.deep_dup(model.attributes(register_id)) imported_attributes.each_value do |attr| attr.[:choice] = self end current_record[:attributes].merge!(imported_attributes) return end # Default register: store in class-level storage imported_attributes = Utils.deep_dup(model.attributes.values) imported_attributes.each do |attr| attr.[:choice] = self @model.define_attribute_methods(attr) end @attributes.concat(imported_attributes) attrs_hash = imported_attributes.to_h { |attr| [attr.name, attr] } @model.attributes.merge!(attrs_hash) end |
#optional_empty_choice?(count) ⇒ Boolean
183 184 185 186 187 188 189 |
# File 'lib/lutaml/model/choice.rb', line 183 def optional_empty_choice?(count) count.zero? && @attributes.any? do |attr| next attr.optional_empty_choice?(count) if attr.is_a?(self.class) optional_attribute?(attr) end end |
#pretty_print_instance_variables ⇒ Object
191 192 193 |
# File 'lib/lutaml/model/choice.rb', line 191 def pretty_print_instance_variables (instance_variables - INTERNAL_ATTRIBUTES).sort end |
#remove_attribute(name) ⇒ Boolean
Remove an attribute from this choice block
60 61 62 63 64 65 66 67 68 |
# File 'lib/lutaml/model/choice.rb', line 60 def remove_attribute(name) attr = @attributes.find { |a| !a.is_a?(Choice) && a.name == name } return nil unless attr @attributes.delete(attr) attr..delete(:choice) invalidate_cache! attr end |
#restrict(name, options = {}) ⇒ Symbol
Restrict options on a predefined or imported attribute within this choice
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/lutaml/model/choice.rb', line 45 def restrict(name, = {}) @model.restrict(name, ) attr = @model.attributes[name] unless @attributes.include?(attr) attr.[:choice] = self @attributes << attr end invalidate_cache! name end |
#validate_content!(object, register = nil) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/lutaml/model/choice.rb', line 91 def validate_content!(object, register = nil) validated_attributes = [] valid = valid_attributes(object, validated_attributes, register) # Allow empty choice if it can render empty elements if valid.none? && can_render_empty?(object) return end validate_count_errors!(valid.count, validated_attributes) end |
#validate_count_errors!(count, attributes) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/lutaml/model/choice.rb', line 169 def validate_count_errors!(count, attributes) return if count.between?(@min, @max) return if optional_empty_choice?(count) if count < @min raise Lutaml::Model::ChoiceLowerBoundError.new(attributes, @min) end if count > @max raise Lutaml::Model::ChoiceUpperBoundError.new(attributes, @max) end end |
#validate_sequence_content!(elements, appearance_count = 0, register = nil) ⇒ Object
82 83 84 85 86 87 88 89 |
# File 'lib/lutaml/model/choice.rb', line 82 def validate_sequence_content!(elements, appearance_count = 0, register = nil) choices_hash = ::Hash.new { |h, k| h[k] = 0 } choices_hash[self] = appearance_count current_index = validate_choices(elements, choices_hash, register) raise_errors(choices_hash) current_index end |