Class: Coradoc::AsciiDoc::Model::AttributeList
- Inherits:
-
Base
- Object
- Lutaml::Model::Serializable
- Base
- Coradoc::AsciiDoc::Model::AttributeList
- Includes:
- Matchers
- Defined in:
- lib/coradoc/asciidoc/model/attribute_list.rb,
lib/coradoc/asciidoc/model/attribute_list/matchers.rb
Overview
Attribute list for AsciiDoc elements.
Attribute lists represent the square-bracket attribute syntax in AsciiDoc: [positional1, pos2, name1=value1, name2=value2]
This class manages both positional and named attributes, with support for validation and rejection of invalid values.
Direct Known Subclasses
Defined Under Namespace
Modules: Matchers
Instance Attribute Summary collapse
-
#named ⇒ Array<Coradoc::AsciiDoc::Model::NamedAttribute>
readonly
Named attributes (key-value pairs).
-
#positional ⇒ Array<Coradoc::AsciiDoc::Model::AttributeListAttribute>
readonly
Positional attributes (by position).
-
#rejected_named ⇒ Array<Coradoc::AsciiDoc::Model::NamedAttribute>
readonly
Rejected named attributes.
-
#rejected_positional ⇒ Array<Coradoc::AsciiDoc::Model::RejectedPositionalAttribute>
readonly
Rejected positional attributes.
Attributes inherited from Base
Instance Method Summary collapse
-
#[](name) ⇒ String?
Get the scalar value of the first named attribute matching
name. -
#add_named(name, value) ⇒ Object
Add a named attribute to this list.
-
#add_positional(*attr) ⇒ Object
Add positional attributes to this list.
-
#delete_named(name) ⇒ String?
Remove the first named attribute matching
nameand return its scalar value (or nil if absent). - #empty? ⇒ Boolean
-
#fetch(name, default = nil) ⇒ Object
Get a named attribute value with default.
-
#fetch_all(name) ⇒ Array<String>
Get the full multi-value array for a named attribute.
-
#named_validators ⇒ Hash
To be overridden in subclasses.
-
#positional_validators ⇒ Array
To be overridden in subclasses.
-
#to_adoc(show_empty: true) ⇒ String
Serialize this attribute list to AsciiDoc.
-
#validate ⇒ Array<Lutaml::Model::Error>
Validate this attribute list.
-
#validate_named(validators: {}) {|name, value| ... } ⇒ Object
Validate named attributes against validators.
-
#validate_positional(validators: []) {|position, value| ... } ⇒ Object
Validate positional attributes against validators.
Methods included from Matchers
Methods inherited from Base
#block_level?, #inline?, #serialize_content, #simplify_block_content, #to_h, visit, #visit
Instance Attribute Details
#named ⇒ Array<Coradoc::AsciiDoc::Model::NamedAttribute> (readonly)
Returns Named attributes (key-value pairs).
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 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 119 120 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 40 class AttributeList < Base # Autoload Matchers module autoload :Matchers, 'coradoc/asciidoc/model/attribute_list/matchers' # Include Matchers module for validation methods include Matchers attribute :positional, Coradoc::AsciiDoc::Model::AttributeListAttribute, collection: true, initialize_empty: true attribute :named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true attribute :rejected_positional, Coradoc::AsciiDoc::Model::RejectedPositionalAttribute, collection: true, initialize_empty: true attribute :rejected_named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true # Add positional attributes to this list # # @param attr [Array<Object>] Values to add as positional attributes # # @example Adding positional attributes # attrs.add_positional("value1", "value2") # def add_positional(*attr) attr.each do |a| @positional << AttributeListAttribute.new(value: a) end end # Add a named attribute to this list # # @param name [String, Symbol] The attribute name # @param value [Object] The attribute value (will be converted to array) # # @example Adding named attributes # attrs.add_named("title", "My Title") # attrs.add_named("cols", "3,2,1") # def add_named(name, value) @named << NamedAttribute.new( name:, value: value.is_a?(Array) ? value : [value] ) end # Remove the first named attribute matching `name` and return its # scalar value (or nil if absent). Used by promoters that lift a # named attr out of the residual bag into a typed field. # @param name [String, Symbol] # @return [String, nil] def delete_named(name) name_str = name.to_s idx = named.index { |n| n.name.to_s == name_str } return nil unless idx removed = @named.delete_at(idx) removed.value.first&.to_s end # Validate named attributes against validators # # @param validators [Hash] Hash of name => matcher pairs # @yield [name, value] Block called for each invalid attribute # # @example Validate with custom validator # attrs.validate_named(title: /./) do |name, value| # puts "Invalid #{name}: #{value}" # end # def validate_named(validators: {}) named.each_with_index do |named_attribute, _i| name = named_attribute.name.to_sym value = named_attribute.value matcher = validators[name] next if matcher && matcher === value # Previous implementation would remove the value from the list # named.delete(name) rejected_named << named_attribute.dup yield(name, value) if block_given? end end # Validate positional attributes against validators # # @param validators [Array] Array of [position, matcher] pairs # @yield [position, value] Block called for each invalid attribute # # @example Validate positional attributes # attrs.validate_positional([[0, /./], [1, Integer]]) # def validate_positional(validators: []) positional.each_with_index do |positional_attribute, i| matcher = validators[i][1] value = positional_attribute.value next unless matcher && !(matcher === value) warn "#{value} does not match #{matcher}" # Previous implementation would remove the value from the list # positional[i] = nil rejected_positional << RejectedPositionalAttribute.new( position: i, value: ) yield(i, value) if block_given? end end # To be overridden in subclasses. # @return [Array] Array of positional validators def positional_validators [] end # To be overridden in subclasses. # @return [Hash] Hash of named validators def named_validators {} end # Validate this attribute list # # @return [Array<Lutaml::Model::Error>] Validation errors (empty if valid) def validate errors = super validate_positional(positional_validators) do |i, value| errors << Lutaml::Model::Error.new( "Positional attribute at position #{i} with value '#{value}' is not valid" ) end validate_named(named_validators) do |name, value| errors << Lutaml::Model::Error.new( "Named attribute #{name} with value '#{value}' is not valid" ) end errors end # Serialize this attribute list to AsciiDoc # # Generates the square-bracket syntax with valid attributes only. # # @param show_empty [Boolean] If true, show "[]" for empty lists (default: true) # @return [String] AsciiDoc representation of this attribute list # # @example Serialize with options # attrs.to_adoc(show_empty: true) # => "[value1,name=val]" # attrs.to_adoc(show_empty: false) # => "[value1,name=val]" # empty.to_adoc # => "[]" # empty.to_adoc(show_empty: false) # => "" # def to_adoc(show_empty: true) valid_positional = positional.reject.with_index do |_p, i| rejected_positional.any? { |r| r.position == i } end valid_named = named.reject do |n| rejected_named.any? { |r| r.name == n.name } end adoc = [valid_positional, valid_named].flatten.map(&:to_adoc).join(',') if adoc.empty? && show_empty '[]' elsif adoc.empty? '' else "[#{adoc}]" end end def empty? positional.empty? && named.empty? end # Get the scalar value of the first named attribute matching `name`. # Returns the first element of the underlying multi-value array, or # nil if the name is absent. Use {#fetch_all} to retrieve the full # multi-value array. # @param name [String, Symbol] The attribute name # @return [String, nil] def [](name) name_str = name.to_s named.find { |n| n.name.to_s == name_str }&.value&.first&.to_s end # Get the full multi-value array for a named attribute. # @param name [String, Symbol] # @return [Array<String>] (empty when absent) def fetch_all(name) name_str = name.to_s found = named.find { |n| n.name.to_s == name_str } found ? found.value : [] end # Get a named attribute value with default # @param name [String, Symbol] The attribute name # @param default [Object] The default value if not found # @return [Object] The attribute value or default def fetch(name, default = nil) value = self[name] value.nil? ? default : value end end |
#positional ⇒ Array<Coradoc::AsciiDoc::Model::AttributeListAttribute> (readonly)
Returns Positional attributes (by position).
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 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 119 120 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 40 class AttributeList < Base # Autoload Matchers module autoload :Matchers, 'coradoc/asciidoc/model/attribute_list/matchers' # Include Matchers module for validation methods include Matchers attribute :positional, Coradoc::AsciiDoc::Model::AttributeListAttribute, collection: true, initialize_empty: true attribute :named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true attribute :rejected_positional, Coradoc::AsciiDoc::Model::RejectedPositionalAttribute, collection: true, initialize_empty: true attribute :rejected_named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true # Add positional attributes to this list # # @param attr [Array<Object>] Values to add as positional attributes # # @example Adding positional attributes # attrs.add_positional("value1", "value2") # def add_positional(*attr) attr.each do |a| @positional << AttributeListAttribute.new(value: a) end end # Add a named attribute to this list # # @param name [String, Symbol] The attribute name # @param value [Object] The attribute value (will be converted to array) # # @example Adding named attributes # attrs.add_named("title", "My Title") # attrs.add_named("cols", "3,2,1") # def add_named(name, value) @named << NamedAttribute.new( name:, value: value.is_a?(Array) ? value : [value] ) end # Remove the first named attribute matching `name` and return its # scalar value (or nil if absent). Used by promoters that lift a # named attr out of the residual bag into a typed field. # @param name [String, Symbol] # @return [String, nil] def delete_named(name) name_str = name.to_s idx = named.index { |n| n.name.to_s == name_str } return nil unless idx removed = @named.delete_at(idx) removed.value.first&.to_s end # Validate named attributes against validators # # @param validators [Hash] Hash of name => matcher pairs # @yield [name, value] Block called for each invalid attribute # # @example Validate with custom validator # attrs.validate_named(title: /./) do |name, value| # puts "Invalid #{name}: #{value}" # end # def validate_named(validators: {}) named.each_with_index do |named_attribute, _i| name = named_attribute.name.to_sym value = named_attribute.value matcher = validators[name] next if matcher && matcher === value # Previous implementation would remove the value from the list # named.delete(name) rejected_named << named_attribute.dup yield(name, value) if block_given? end end # Validate positional attributes against validators # # @param validators [Array] Array of [position, matcher] pairs # @yield [position, value] Block called for each invalid attribute # # @example Validate positional attributes # attrs.validate_positional([[0, /./], [1, Integer]]) # def validate_positional(validators: []) positional.each_with_index do |positional_attribute, i| matcher = validators[i][1] value = positional_attribute.value next unless matcher && !(matcher === value) warn "#{value} does not match #{matcher}" # Previous implementation would remove the value from the list # positional[i] = nil rejected_positional << RejectedPositionalAttribute.new( position: i, value: ) yield(i, value) if block_given? end end # To be overridden in subclasses. # @return [Array] Array of positional validators def positional_validators [] end # To be overridden in subclasses. # @return [Hash] Hash of named validators def named_validators {} end # Validate this attribute list # # @return [Array<Lutaml::Model::Error>] Validation errors (empty if valid) def validate errors = super validate_positional(positional_validators) do |i, value| errors << Lutaml::Model::Error.new( "Positional attribute at position #{i} with value '#{value}' is not valid" ) end validate_named(named_validators) do |name, value| errors << Lutaml::Model::Error.new( "Named attribute #{name} with value '#{value}' is not valid" ) end errors end # Serialize this attribute list to AsciiDoc # # Generates the square-bracket syntax with valid attributes only. # # @param show_empty [Boolean] If true, show "[]" for empty lists (default: true) # @return [String] AsciiDoc representation of this attribute list # # @example Serialize with options # attrs.to_adoc(show_empty: true) # => "[value1,name=val]" # attrs.to_adoc(show_empty: false) # => "[value1,name=val]" # empty.to_adoc # => "[]" # empty.to_adoc(show_empty: false) # => "" # def to_adoc(show_empty: true) valid_positional = positional.reject.with_index do |_p, i| rejected_positional.any? { |r| r.position == i } end valid_named = named.reject do |n| rejected_named.any? { |r| r.name == n.name } end adoc = [valid_positional, valid_named].flatten.map(&:to_adoc).join(',') if adoc.empty? && show_empty '[]' elsif adoc.empty? '' else "[#{adoc}]" end end def empty? positional.empty? && named.empty? end # Get the scalar value of the first named attribute matching `name`. # Returns the first element of the underlying multi-value array, or # nil if the name is absent. Use {#fetch_all} to retrieve the full # multi-value array. # @param name [String, Symbol] The attribute name # @return [String, nil] def [](name) name_str = name.to_s named.find { |n| n.name.to_s == name_str }&.value&.first&.to_s end # Get the full multi-value array for a named attribute. # @param name [String, Symbol] # @return [Array<String>] (empty when absent) def fetch_all(name) name_str = name.to_s found = named.find { |n| n.name.to_s == name_str } found ? found.value : [] end # Get a named attribute value with default # @param name [String, Symbol] The attribute name # @param default [Object] The default value if not found # @return [Object] The attribute value or default def fetch(name, default = nil) value = self[name] value.nil? ? default : value end end |
#rejected_named ⇒ Array<Coradoc::AsciiDoc::Model::NamedAttribute> (readonly)
Returns Rejected named attributes.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 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 119 120 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 40 class AttributeList < Base # Autoload Matchers module autoload :Matchers, 'coradoc/asciidoc/model/attribute_list/matchers' # Include Matchers module for validation methods include Matchers attribute :positional, Coradoc::AsciiDoc::Model::AttributeListAttribute, collection: true, initialize_empty: true attribute :named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true attribute :rejected_positional, Coradoc::AsciiDoc::Model::RejectedPositionalAttribute, collection: true, initialize_empty: true attribute :rejected_named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true # Add positional attributes to this list # # @param attr [Array<Object>] Values to add as positional attributes # # @example Adding positional attributes # attrs.add_positional("value1", "value2") # def add_positional(*attr) attr.each do |a| @positional << AttributeListAttribute.new(value: a) end end # Add a named attribute to this list # # @param name [String, Symbol] The attribute name # @param value [Object] The attribute value (will be converted to array) # # @example Adding named attributes # attrs.add_named("title", "My Title") # attrs.add_named("cols", "3,2,1") # def add_named(name, value) @named << NamedAttribute.new( name:, value: value.is_a?(Array) ? value : [value] ) end # Remove the first named attribute matching `name` and return its # scalar value (or nil if absent). Used by promoters that lift a # named attr out of the residual bag into a typed field. # @param name [String, Symbol] # @return [String, nil] def delete_named(name) name_str = name.to_s idx = named.index { |n| n.name.to_s == name_str } return nil unless idx removed = @named.delete_at(idx) removed.value.first&.to_s end # Validate named attributes against validators # # @param validators [Hash] Hash of name => matcher pairs # @yield [name, value] Block called for each invalid attribute # # @example Validate with custom validator # attrs.validate_named(title: /./) do |name, value| # puts "Invalid #{name}: #{value}" # end # def validate_named(validators: {}) named.each_with_index do |named_attribute, _i| name = named_attribute.name.to_sym value = named_attribute.value matcher = validators[name] next if matcher && matcher === value # Previous implementation would remove the value from the list # named.delete(name) rejected_named << named_attribute.dup yield(name, value) if block_given? end end # Validate positional attributes against validators # # @param validators [Array] Array of [position, matcher] pairs # @yield [position, value] Block called for each invalid attribute # # @example Validate positional attributes # attrs.validate_positional([[0, /./], [1, Integer]]) # def validate_positional(validators: []) positional.each_with_index do |positional_attribute, i| matcher = validators[i][1] value = positional_attribute.value next unless matcher && !(matcher === value) warn "#{value} does not match #{matcher}" # Previous implementation would remove the value from the list # positional[i] = nil rejected_positional << RejectedPositionalAttribute.new( position: i, value: ) yield(i, value) if block_given? end end # To be overridden in subclasses. # @return [Array] Array of positional validators def positional_validators [] end # To be overridden in subclasses. # @return [Hash] Hash of named validators def named_validators {} end # Validate this attribute list # # @return [Array<Lutaml::Model::Error>] Validation errors (empty if valid) def validate errors = super validate_positional(positional_validators) do |i, value| errors << Lutaml::Model::Error.new( "Positional attribute at position #{i} with value '#{value}' is not valid" ) end validate_named(named_validators) do |name, value| errors << Lutaml::Model::Error.new( "Named attribute #{name} with value '#{value}' is not valid" ) end errors end # Serialize this attribute list to AsciiDoc # # Generates the square-bracket syntax with valid attributes only. # # @param show_empty [Boolean] If true, show "[]" for empty lists (default: true) # @return [String] AsciiDoc representation of this attribute list # # @example Serialize with options # attrs.to_adoc(show_empty: true) # => "[value1,name=val]" # attrs.to_adoc(show_empty: false) # => "[value1,name=val]" # empty.to_adoc # => "[]" # empty.to_adoc(show_empty: false) # => "" # def to_adoc(show_empty: true) valid_positional = positional.reject.with_index do |_p, i| rejected_positional.any? { |r| r.position == i } end valid_named = named.reject do |n| rejected_named.any? { |r| r.name == n.name } end adoc = [valid_positional, valid_named].flatten.map(&:to_adoc).join(',') if adoc.empty? && show_empty '[]' elsif adoc.empty? '' else "[#{adoc}]" end end def empty? positional.empty? && named.empty? end # Get the scalar value of the first named attribute matching `name`. # Returns the first element of the underlying multi-value array, or # nil if the name is absent. Use {#fetch_all} to retrieve the full # multi-value array. # @param name [String, Symbol] The attribute name # @return [String, nil] def [](name) name_str = name.to_s named.find { |n| n.name.to_s == name_str }&.value&.first&.to_s end # Get the full multi-value array for a named attribute. # @param name [String, Symbol] # @return [Array<String>] (empty when absent) def fetch_all(name) name_str = name.to_s found = named.find { |n| n.name.to_s == name_str } found ? found.value : [] end # Get a named attribute value with default # @param name [String, Symbol] The attribute name # @param default [Object] The default value if not found # @return [Object] The attribute value or default def fetch(name, default = nil) value = self[name] value.nil? ? default : value end end |
#rejected_positional ⇒ Array<Coradoc::AsciiDoc::Model::RejectedPositionalAttribute> (readonly)
Returns Rejected positional attributes.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 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 119 120 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 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 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 40 class AttributeList < Base # Autoload Matchers module autoload :Matchers, 'coradoc/asciidoc/model/attribute_list/matchers' # Include Matchers module for validation methods include Matchers attribute :positional, Coradoc::AsciiDoc::Model::AttributeListAttribute, collection: true, initialize_empty: true attribute :named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true attribute :rejected_positional, Coradoc::AsciiDoc::Model::RejectedPositionalAttribute, collection: true, initialize_empty: true attribute :rejected_named, Coradoc::AsciiDoc::Model::NamedAttribute, collection: true, initialize_empty: true # Add positional attributes to this list # # @param attr [Array<Object>] Values to add as positional attributes # # @example Adding positional attributes # attrs.add_positional("value1", "value2") # def add_positional(*attr) attr.each do |a| @positional << AttributeListAttribute.new(value: a) end end # Add a named attribute to this list # # @param name [String, Symbol] The attribute name # @param value [Object] The attribute value (will be converted to array) # # @example Adding named attributes # attrs.add_named("title", "My Title") # attrs.add_named("cols", "3,2,1") # def add_named(name, value) @named << NamedAttribute.new( name:, value: value.is_a?(Array) ? value : [value] ) end # Remove the first named attribute matching `name` and return its # scalar value (or nil if absent). Used by promoters that lift a # named attr out of the residual bag into a typed field. # @param name [String, Symbol] # @return [String, nil] def delete_named(name) name_str = name.to_s idx = named.index { |n| n.name.to_s == name_str } return nil unless idx removed = @named.delete_at(idx) removed.value.first&.to_s end # Validate named attributes against validators # # @param validators [Hash] Hash of name => matcher pairs # @yield [name, value] Block called for each invalid attribute # # @example Validate with custom validator # attrs.validate_named(title: /./) do |name, value| # puts "Invalid #{name}: #{value}" # end # def validate_named(validators: {}) named.each_with_index do |named_attribute, _i| name = named_attribute.name.to_sym value = named_attribute.value matcher = validators[name] next if matcher && matcher === value # Previous implementation would remove the value from the list # named.delete(name) rejected_named << named_attribute.dup yield(name, value) if block_given? end end # Validate positional attributes against validators # # @param validators [Array] Array of [position, matcher] pairs # @yield [position, value] Block called for each invalid attribute # # @example Validate positional attributes # attrs.validate_positional([[0, /./], [1, Integer]]) # def validate_positional(validators: []) positional.each_with_index do |positional_attribute, i| matcher = validators[i][1] value = positional_attribute.value next unless matcher && !(matcher === value) warn "#{value} does not match #{matcher}" # Previous implementation would remove the value from the list # positional[i] = nil rejected_positional << RejectedPositionalAttribute.new( position: i, value: ) yield(i, value) if block_given? end end # To be overridden in subclasses. # @return [Array] Array of positional validators def positional_validators [] end # To be overridden in subclasses. # @return [Hash] Hash of named validators def named_validators {} end # Validate this attribute list # # @return [Array<Lutaml::Model::Error>] Validation errors (empty if valid) def validate errors = super validate_positional(positional_validators) do |i, value| errors << Lutaml::Model::Error.new( "Positional attribute at position #{i} with value '#{value}' is not valid" ) end validate_named(named_validators) do |name, value| errors << Lutaml::Model::Error.new( "Named attribute #{name} with value '#{value}' is not valid" ) end errors end # Serialize this attribute list to AsciiDoc # # Generates the square-bracket syntax with valid attributes only. # # @param show_empty [Boolean] If true, show "[]" for empty lists (default: true) # @return [String] AsciiDoc representation of this attribute list # # @example Serialize with options # attrs.to_adoc(show_empty: true) # => "[value1,name=val]" # attrs.to_adoc(show_empty: false) # => "[value1,name=val]" # empty.to_adoc # => "[]" # empty.to_adoc(show_empty: false) # => "" # def to_adoc(show_empty: true) valid_positional = positional.reject.with_index do |_p, i| rejected_positional.any? { |r| r.position == i } end valid_named = named.reject do |n| rejected_named.any? { |r| r.name == n.name } end adoc = [valid_positional, valid_named].flatten.map(&:to_adoc).join(',') if adoc.empty? && show_empty '[]' elsif adoc.empty? '' else "[#{adoc}]" end end def empty? positional.empty? && named.empty? end # Get the scalar value of the first named attribute matching `name`. # Returns the first element of the underlying multi-value array, or # nil if the name is absent. Use {#fetch_all} to retrieve the full # multi-value array. # @param name [String, Symbol] The attribute name # @return [String, nil] def [](name) name_str = name.to_s named.find { |n| n.name.to_s == name_str }&.value&.first&.to_s end # Get the full multi-value array for a named attribute. # @param name [String, Symbol] # @return [Array<String>] (empty when absent) def fetch_all(name) name_str = name.to_s found = named.find { |n| n.name.to_s == name_str } found ? found.value : [] end # Get a named attribute value with default # @param name [String, Symbol] The attribute name # @param default [Object] The default value if not found # @return [Object] The attribute value or default def fetch(name, default = nil) value = self[name] value.nil? ? default : value end end |
Instance Method Details
#[](name) ⇒ String?
Get the scalar value of the first named attribute matching name.
Returns the first element of the underlying multi-value array, or
nil if the name is absent. Use #fetch_all to retrieve the full
multi-value array.
232 233 234 235 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 232 def [](name) name_str = name.to_s named.find { |n| n.name.to_s == name_str }&.value&.first&.to_s end |
#add_named(name, value) ⇒ Object
Add a named attribute to this list
83 84 85 86 87 88 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 83 def add_named(name, value) @named << NamedAttribute.new( name:, value: value.is_a?(Array) ? value : [value] ) end |
#add_positional(*attr) ⇒ Object
Add positional attributes to this list
68 69 70 71 72 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 68 def add_positional(*attr) attr.each do |a| @positional << AttributeListAttribute.new(value: a) end end |
#delete_named(name) ⇒ String?
Remove the first named attribute matching name and return its
scalar value (or nil if absent). Used by promoters that lift a
named attr out of the residual bag into a typed field.
95 96 97 98 99 100 101 102 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 95 def delete_named(name) name_str = name.to_s idx = named.index { |n| n.name.to_s == name_str } return nil unless idx removed = @named.delete_at(idx) removed.value.first&.to_s end |
#empty? ⇒ Boolean
222 223 224 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 222 def empty? positional.empty? && named.empty? end |
#fetch(name, default = nil) ⇒ Object
Get a named attribute value with default
250 251 252 253 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 250 def fetch(name, default = nil) value = self[name] value.nil? ? default : value end |
#fetch_all(name) ⇒ Array<String>
Get the full multi-value array for a named attribute.
240 241 242 243 244 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 240 def fetch_all(name) name_str = name.to_s found = named.find { |n| n.name.to_s == name_str } found ? found.value : [] end |
#named_validators ⇒ Hash
To be overridden in subclasses.
163 164 165 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 163 def named_validators {} end |
#positional_validators ⇒ Array
To be overridden in subclasses.
157 158 159 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 157 def positional_validators [] end |
#to_adoc(show_empty: true) ⇒ String
Serialize this attribute list to AsciiDoc
Generates the square-bracket syntax with valid attributes only.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 201 def to_adoc(show_empty: true) valid_positional = positional.reject.with_index do |_p, i| rejected_positional.any? { |r| r.position == i } end valid_named = named.reject do |n| rejected_named.any? { |r| r.name == n.name } end adoc = [valid_positional, valid_named].flatten.map(&:to_adoc).join(',') if adoc.empty? && show_empty '[]' elsif adoc.empty? '' else "[#{adoc}]" end end |
#validate ⇒ Array<Lutaml::Model::Error>
Validate this attribute list
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 170 def validate errors = super validate_positional(positional_validators) do |i, value| errors << Lutaml::Model::Error.new( "Positional attribute at position #{i} with value '#{value}' is not valid" ) end validate_named(named_validators) do |name, value| errors << Lutaml::Model::Error.new( "Named attribute #{name} with value '#{value}' is not valid" ) end errors end |
#validate_named(validators: {}) {|name, value| ... } ⇒ Object
Validate named attributes against validators
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 114 def validate_named(validators: {}) named.each_with_index do |named_attribute, _i| name = named_attribute.name.to_sym value = named_attribute.value matcher = validators[name] next if matcher && matcher === value # Previous implementation would remove the value from the list # named.delete(name) rejected_named << named_attribute.dup yield(name, value) if block_given? end end |
#validate_positional(validators: []) {|position, value| ... } ⇒ Object
Validate positional attributes against validators
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/coradoc/asciidoc/model/attribute_list.rb', line 138 def validate_positional(validators: []) positional.each_with_index do |positional_attribute, i| matcher = validators[i][1] value = positional_attribute.value next unless matcher && !(matcher === value) warn "#{value} does not match #{matcher}" # Previous implementation would remove the value from the list # positional[i] = nil rejected_positional << RejectedPositionalAttribute.new( position: i, value: ) yield(i, value) if block_given? end end |