expressir 2.3.5 → 2.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +1 -1
  3. data/.gitignore +2 -0
  4. data/.rubocop_todo.yml +17 -12
  5. data/CHANGELOG.md +159 -0
  6. data/docs/_guides/ler/step-packages.adoc +385 -0
  7. data/lib/expressir/coverage.rb +4 -4
  8. data/lib/expressir/express/builder.rb +1 -1
  9. data/lib/expressir/express/builder_registry.rb +12 -35
  10. data/lib/expressir/express/builders/constant_builder.rb +8 -2
  11. data/lib/expressir/express/builders/expression_builder.rb +2 -2
  12. data/lib/expressir/express/builders/helpers.rb +2 -8
  13. data/lib/expressir/express/builders/procedure_decl_builder.rb +2 -1
  14. data/lib/expressir/express/builders/qualifier_builder.rb +2 -1
  15. data/lib/expressir/express/builders/statement_builder.rb +18 -5
  16. data/lib/expressir/express/builders/type_builder.rb +20 -12
  17. data/lib/expressir/express/formatter.rb +32 -164
  18. data/lib/expressir/express/formatters/data_types_formatter.rb +51 -8
  19. data/lib/expressir/express/formatters/declarations_formatter.rb +47 -8
  20. data/lib/expressir/express/formatters/expressions_formatter.rb +27 -9
  21. data/lib/expressir/express/formatters/literals_formatter.rb +12 -5
  22. data/lib/expressir/express/formatters/references_formatter.rb +10 -1
  23. data/lib/expressir/express/formatters/remark_formatter.rb +1 -89
  24. data/lib/expressir/express/formatters/remark_item_formatter.rb +5 -4
  25. data/lib/expressir/express/formatters/statements_formatter.rb +32 -9
  26. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +7 -3
  27. data/lib/expressir/express/hyperlink_formatter.rb +1 -3
  28. data/lib/expressir/express/model_visitor.rb +1 -1
  29. data/lib/expressir/express/pretty_formatter.rb +31 -108
  30. data/lib/expressir/express/remark_attacher.rb +118 -88
  31. data/lib/expressir/express/schema_head_formatter.rb +1 -3
  32. data/lib/expressir/model/concerns.rb +6 -0
  33. data/lib/expressir/model/declarations/function.rb +0 -1
  34. data/lib/expressir/model/declarations/interface_item.rb +2 -0
  35. data/lib/expressir/model/declarations/interfaced_item.rb +3 -0
  36. data/lib/expressir/model/declarations/procedure.rb +0 -1
  37. data/lib/expressir/model/declarations/remark_item.rb +3 -0
  38. data/lib/expressir/model/declarations/schema.rb +7 -5
  39. data/lib/expressir/model/exp_file.rb +1 -0
  40. data/lib/expressir/model/identifier.rb +3 -1
  41. data/lib/expressir/model/model_element.rb +3 -3
  42. data/lib/expressir/model/repository.rb +8 -0
  43. data/lib/expressir/model/search_engine.rb +1 -1
  44. data/lib/expressir/package/reader.rb +9 -24
  45. data/lib/expressir/version.rb +1 -1
  46. metadata +4 -2
@@ -282,18 +282,18 @@ module Expressir
282
282
  # @return [Boolean] True if the entity has documentation
283
283
  def self.entity_documented?(entity)
284
284
  # Check for direct remarks (types with Identifier module have remarks)
285
- if entity.is_a?(Model::ModelElement) && entity.class.method_defined?(:remarks) && entity.remarks && !entity.remarks.empty?
285
+ if entity.is_a?(Model::HasRemarks) && entity.remarks && !entity.remarks.empty?
286
286
  return true
287
287
  end
288
288
 
289
289
  # Check for remark_items (types with Identifier module have remark_items)
290
- if entity.is_a?(Model::ModelElement) && entity.class.method_defined?(:remark_items) && entity.remark_items && !entity.remark_items.empty?
290
+ if entity.is_a?(Model::HasRemarkItems) && entity.remark_items && !entity.remark_items.empty?
291
291
  return true
292
292
  end
293
293
 
294
294
  # For schema entities, check if there's a remark_item with their ID
295
295
  parent = entity.parent
296
- if parent.is_a?(Model::ModelElement) && parent.class.method_defined?(:remark_items) && parent.remark_items
296
+ if parent.is_a?(Model::HasRemarkItems) && parent.remark_items
297
297
  entity_id = entity.id.to_s.downcase
298
298
  parent.remark_items.any? do |item|
299
299
  item.id.to_s.downcase == entity_id || item.id.to_s.downcase.include?("#{entity_id}.")
@@ -331,7 +331,7 @@ module Expressir
331
331
  # Filter out nil elements and ensure all have IDs
332
332
  # Note: Some ModelElement types (like Interface) don't have id
333
333
  entities = entities.compact.select do |e|
334
- e.is_a?(Model::ModelElement) && e.class.method_defined?(:id) && e.id
334
+ e.is_a?(Model::HasId) && e.id
335
335
  end
336
336
 
337
337
  # Filter out skipped entity types
@@ -354,7 +354,7 @@ module Expressir
354
354
  end
355
355
 
356
356
  def attach_source_info(result, data)
357
- return unless @source && result.is_a?(Model::ModelElement)
357
+ return unless @source && result.is_a?(Expressir::Model::ModelElement)
358
358
 
359
359
  source_info = extract_source_info(data)
360
360
  return unless source_info
@@ -181,18 +181,18 @@ module Expressir
181
181
  Builder.register(:interval_high) { |d| expression.build_interval_high(d) }
182
182
  Builder.register(:interval_item) { |d| expression.build_interval_item(d) }
183
183
  Builder.register(:interval_op) do |d|
184
- expression.send(:extract_interval_op, d)
184
+ expression.extract_interval_op(d)
185
185
  end
186
186
 
187
187
  # Operators
188
188
  Builder.register(:add_like_op) do |d|
189
- expression.send(:extract_operator, d)
189
+ expression.extract_operator(d)
190
190
  end
191
191
  Builder.register(:mul_like_op) do |d|
192
- expression.send(:extract_operator, d)
192
+ expression.extract_operator(d)
193
193
  end
194
- Builder.register(:unary_op) { |d| expression.send(:extract_unary_op, d) }
195
- Builder.register(:rel_op) { |d| expression.send(:extract_rel_op, d) }
194
+ Builder.register(:unary_op) { |d| expression.extract_unary_op(d) }
195
+ Builder.register(:rel_op) { |d| expression.extract_rel_op(d) }
196
196
 
197
197
  # ========================================================================
198
198
  # Interface Builder (closures)
@@ -319,45 +319,22 @@ module Expressir
319
319
  subtype_constraint.build_total_over(d)
320
320
  end
321
321
 
322
- Builder.register(:subtype_constraint_decl) do |d|
323
- subtype_constraint.build_subtype_constraint_decl(d)
324
- end
325
- Builder.register(:total_over) do |d|
326
- subtype_constraint.build_total_over(d)
327
- end
328
- Builder.register(:supertype_expression) do |d|
329
- subtype_constraint.build_supertype_expression(d)
330
- end
331
- Builder.register(:supertype_factor) do |d|
332
- subtype_constraint.build_supertype_factor(d)
333
- end
334
- Builder.register(:supertype_term) do |d|
335
- subtype_constraint.build_supertype_term(d)
336
- end
337
- Builder.register(:one_of) { |d| subtype_constraint.build_one_of(d) }
338
- Builder.register(:supertype_rule) do |d|
339
- subtype_constraint.build_supertype_rule(d)
340
- end
341
- Builder.register(:subtype_constraint) do |d|
342
- subtype_constraint.build_subtype_constraint(d)
343
- end
344
- Builder.register(:subtype_declaration) do |d|
345
- subtype_constraint.build_subtype_declaration(d)
346
- end
347
-
348
322
  # ========================================================================
349
323
  # Type Builder (closures)
350
324
  # ========================================================================
351
325
 
352
326
  # Simple types
353
- %i[boolean_type integer_type logical_type number_type].each do |type|
354
- Builder.register(type) { |d| type_builder.send(:"build_#{type}", d) }
355
- end
327
+ Builder.register(:boolean_type) { |d| type_builder.build_boolean_type(d) }
328
+ Builder.register(:integer_type) { |d| type_builder.build_integer_type(d) }
329
+ Builder.register(:logical_type) { |d| type_builder.build_logical_type(d) }
330
+ Builder.register(:number_type) { |d| type_builder.build_number_type(d) }
356
331
 
357
332
  # Type constructors
358
333
  Builder.register(:generic_type) { |_d| Expressir::Model::DataTypes::Generic.new }
359
334
  Builder.register(:generic_entity_type) { |_d| Expressir::Model::DataTypes::GenericEntity.new }
360
- Builder.register(:aggregate_type) { |_d| Expressir::Model::DataTypes::Aggregate.new }
335
+ Builder.register(:aggregate_type) do |d|
336
+ type_builder.build_aggregate_type(d)
337
+ end
361
338
  Builder.register(:general_set_type) do |d|
362
339
  type_builder.build_general_set_type(d)
363
340
  end
@@ -36,7 +36,10 @@ module Expressir
36
36
  ids = if ids_data.is_a?(Hash)
37
37
  [Builder.build({ variable_id: ids_data })]
38
38
  elsif ids_data.is_a?(Array)
39
- ids_data.map { |id| Builder.build({ variable_id: id }) }
39
+ ids_data.filter_map do |elem|
40
+ actual_id = elem[:variable_id] || elem
41
+ Builder.build({ variable_id: actual_id })
42
+ end
40
43
  else
41
44
  []
42
45
  end
@@ -64,7 +67,10 @@ module Expressir
64
67
  ids = if ids_data.is_a?(Hash)
65
68
  [Builder.build({ parameter_id: ids_data })]
66
69
  elsif ids_data.is_a?(Array)
67
- ids_data.map { |id| Builder.build({ parameter_id: id }) }
70
+ ids_data.filter_map do |elem|
71
+ actual_id = elem[:parameter_id] || elem
72
+ Builder.build({ parameter_id: actual_id })
73
+ end
68
74
  else
69
75
  []
70
76
  end
@@ -43,7 +43,7 @@ module Expressir
43
43
  term = Builder.build_term(ast_data[:term])
44
44
  rhs = ast_data[:rhs]
45
45
 
46
- return term if rhs.nil? || (rhs.respond_to?(:empty?) && rhs.empty?)
46
+ return term if rhs.nil? || (rhs.is_a?(Array) && rhs.empty?)
47
47
 
48
48
  rhs_array = rhs.is_a?(Array) ? rhs : [rhs]
49
49
 
@@ -74,7 +74,7 @@ module Expressir
74
74
  factor = Builder.build_factor(ast_data[:factor])
75
75
  rhs = ast_data[:rhs]
76
76
 
77
- return factor if rhs.nil? || (rhs.respond_to?(:empty?) && rhs.empty?)
77
+ return factor if rhs.nil? || (rhs.is_a?(Array) && rhs.empty?)
78
78
 
79
79
  rhs_array = rhs.is_a?(Array) ? rhs : [rhs]
80
80
 
@@ -9,11 +9,9 @@ module Expressir
9
9
  # Extract text from Parsanol::Slice or return as-is
10
10
  def extract_text(val)
11
11
  return nil unless val
12
- # Handle String, Symbol, and objects with to_str (duck typing via class check)
13
12
  return val.to_s if val.is_a?(String)
14
13
  return val.to_s if val.is_a?(Symbol)
15
- # Handle Parsanol Slice objects - they respond to to_s but not to_str
16
- return val.to_s if val.class.name&.include?("Slice")
14
+ return val.to_s if val.is_a?(Parsanol::Slice)
17
15
 
18
16
  if val.is_a?(Hash)
19
17
  str = val[:str]
@@ -34,8 +32,7 @@ module Expressir
34
32
  return nil unless data
35
33
  return data.to_s if data.is_a?(String)
36
34
  return data.to_s if data.is_a?(Symbol)
37
- # Handle Parsanol Slice objects
38
- return data.to_s if data.class.name&.include?("Slice")
35
+ return data.to_s if data.is_a?(Parsanol::Slice)
39
36
 
40
37
  if data.is_a?(Hash)
41
38
  str = data[:str]
@@ -141,9 +138,6 @@ module Expressir
141
138
  when Expressir::Model::References::SimpleReference
142
139
  Expressir::Model::References::AttributeReference.new(ref: ref,
143
140
  attribute: qualifier)
144
- when Hash
145
- Expressir::Model::References::IndexReference.new(ref: ref,
146
- index1: qualifier[:index1], index2: qualifier[:index2])
147
141
  else
148
142
  ref
149
143
  end
@@ -62,7 +62,8 @@ module Expressir
62
62
 
63
63
  parameters = []
64
64
  Builder.ensure_array(params_data).each do |param|
65
- result = Builder.build({ procedure_head_parameter: param })
65
+ actual_param = param[:procedure_head_parameter] || param
66
+ result = Builder.build({ procedure_head_parameter: actual_param })
66
67
  parameters.concat(Builder.ensure_array(result)) if result
67
68
  end
68
69
  parameters
@@ -65,7 +65,8 @@ module Expressir
65
65
  def build_index_qualifier(ast_data)
66
66
  index1 = Builder.build_optional(ast_data[:index1])
67
67
  index2 = Builder.build_optional(ast_data[:index2])
68
- { index1: index1, index2: index2 }
68
+ Expressir::Model::References::IndexReference.new(index1: index1,
69
+ index2: index2)
69
70
  end
70
71
 
71
72
  def build_index1(ast_data)
@@ -85,12 +85,14 @@ module Expressir
85
85
  def build_case_stmt(ast_data)
86
86
  selector = Builder.build_optional(ast_data[:selector])
87
87
  actions = Builder.build_children(ast_data[:case_action])
88
- otherwise = Builder.build_children(ast_data[:otherwise]&.dig(:stmt))
88
+ otherwise_stmt = if ast_data[:t_otherwise] && ast_data[:stmt].is_a?(Hash)
89
+ Builder.build({ stmt: ast_data[:stmt] })
90
+ end
89
91
 
90
92
  Expressir::Model::Statements::Case.new(
91
93
  expression: selector,
92
94
  actions: actions.compact,
93
- otherwise: otherwise.compact,
95
+ otherwise_statement: otherwise_stmt,
94
96
  )
95
97
  end
96
98
 
@@ -101,12 +103,23 @@ module Expressir
101
103
  end
102
104
 
103
105
  def build_case_action(ast_data)
104
- labels = Builder.build_children(ast_data[:case_label])
105
- statements = Builder.build_children(ast_data[:stmt])
106
+ label_data = ast_data[:list_of_case_label]
107
+ labels = if label_data.is_a?(Hash)
108
+ Builder.build_children(label_data[:case_label])
109
+ elsif label_data.is_a?(Array)
110
+ label_data.flat_map do |item|
111
+ Builder.build_children(item.is_a?(Hash) ? item[:case_label] : item)
112
+ end
113
+ else
114
+ []
115
+ end
116
+ stmt = if ast_data[:stmt].is_a?(Hash)
117
+ Builder.build({ stmt: ast_data[:stmt] })
118
+ end
106
119
 
107
120
  Expressir::Model::Statements::CaseAction.new(
108
121
  labels: labels.compact,
109
- statements: statements.compact,
122
+ statement: stmt,
110
123
  )
111
124
  end
112
125
 
@@ -7,18 +7,20 @@ module Expressir
7
7
  class TypeBuilder
8
8
  include ::Expressir::Express::Builders::Helpers
9
9
 
10
- # Simple types
11
- {
12
- boolean_type: Expressir::Model::DataTypes::Boolean,
13
- integer_type: Expressir::Model::DataTypes::Integer,
14
- logical_type: Expressir::Model::DataTypes::Logical,
15
- number_type: Expressir::Model::DataTypes::Number,
16
- generic_type: Expressir::Model::DataTypes::Generic,
17
- generic_entity_type: Expressir::Model::DataTypes::GenericEntity,
18
- }.each do |type_name, klass|
19
- define_method(:"build_#{type_name}") do |_ast_data|
20
- klass.new
21
- end
10
+ def build_boolean_type(_ast_data)
11
+ Expressir::Model::DataTypes::Boolean.new
12
+ end
13
+
14
+ def build_integer_type(_ast_data)
15
+ Expressir::Model::DataTypes::Integer.new
16
+ end
17
+
18
+ def build_logical_type(_ast_data)
19
+ Expressir::Model::DataTypes::Logical.new
20
+ end
21
+
22
+ def build_number_type(_ast_data)
23
+ Expressir::Model::DataTypes::Number.new
22
24
  end
23
25
 
24
26
  # String type
@@ -49,6 +51,12 @@ module Expressir
49
51
  end
50
52
  end
51
53
 
54
+ # Aggregate type (AGGREGATE OF type)
55
+ def build_aggregate_type(ast_data)
56
+ base_type = Builder.build_optional(ast_data[:parameter_type])
57
+ Expressir::Model::DataTypes::Aggregate.new(base_type: base_type)
58
+ end
59
+
52
60
  # Aggregation types
53
61
  def build_array_type(ast_data)
54
62
  build_aggregation_type(ast_data, Expressir::Model::DataTypes::Array)
@@ -1,6 +1,18 @@
1
1
  module Expressir
2
2
  module Express
3
3
  class Formatter
4
+ # Registry infrastructure — must precede includes so modules can register handlers
5
+ @format_registry = {}
6
+
7
+ def self.format_registry
8
+ @format_registry || superclass&.format_registry
9
+ end
10
+
11
+ def self.register_formatter(model_class, method_name)
12
+ @format_registry[model_class] = method_name
13
+ end
14
+
15
+ # Include formatter modules — each registers its handlers via self.included
4
16
  include Formatters::RemarkItemFormatter
5
17
  include Formatters::RemarkFormatter
6
18
  include Formatters::LiteralsFormatter
@@ -11,6 +23,14 @@ module Expressir
11
23
  include Formatters::DataTypesFormatter
12
24
  include Formatters::DeclarationsFormatter
13
25
 
26
+ # Handlers for types implemented directly in this class
27
+ register_formatter Model::Repository, :format_repository
28
+ register_formatter Model::ExpFile, :format_exp_file
29
+ register_formatter Model::Declarations::SchemaVersionItem, :format_noop
30
+ register_formatter Model::Declarations::InterfacedItem, :format_noop
31
+ register_formatter Model::Cache, :format_noop
32
+ register_formatter Model::ModelElement, :format_noop
33
+
14
34
  INDENT_CHAR = " ".freeze
15
35
  INDENT_WIDTH = 2
16
36
  INDENT = INDENT_CHAR * INDENT_WIDTH
@@ -54,177 +74,25 @@ module Expressir
54
74
  @no_remarks = no_remarks
55
75
  end
56
76
 
57
- # Formats Express model into an Express code
58
- # @param [Model::ModelElement] node
59
- # @return [String]
60
77
  def self.format(node)
61
- formatter = new
62
- formatter.format(node)
78
+ new.format(node)
63
79
  end
64
80
 
65
- # Formats Express model into an Express code
66
- # @param [Model::ModelElement] node
67
- # @return [String]
68
- def format(node) # rubocop:disable Metrics/MethodLength
69
- case node
70
- when Model::Repository
71
- format_repository(node)
72
- when Model::ExpFile
73
- format_exp_file(node)
74
- when Model::Declarations::Attribute
75
- format_declarations_attribute(node)
76
- when Model::Declarations::Constant
77
- format_declarations_constant(node)
78
- when Model::Declarations::Entity
79
- format_declarations_entity(node)
80
- when Model::Declarations::Function
81
- format_declarations_function(node)
82
- when Model::Declarations::Interface
83
- format_declarations_interface(node)
84
- when Model::Declarations::InterfaceItem
85
- format_declarations_interface_item(node)
86
- when Model::Declarations::Parameter
87
- format_declarations_parameter(node)
88
- when Model::Declarations::Procedure
89
- format_declarations_procedure(node)
90
- when Model::Declarations::Rule
91
- format_declarations_rule(node)
92
- when Model::Declarations::Schema
93
- format_declarations_schema(node)
94
- when Model::Declarations::SchemaVersion
95
- format_declarations_schema_version(node)
96
- when Model::Declarations::SubtypeConstraint
97
- format_declarations_subtype_constraint(node)
98
- when Model::Declarations::Type
99
- format_declarations_type(node)
100
- when Model::Declarations::UniqueRule
101
- format_declarations_unique_rule(node)
102
- when Model::Declarations::Variable
103
- format_declarations_variable(node)
104
- when Model::Declarations::WhereRule
105
- format_declarations_where_rule(node)
106
- when Model::Declarations::InformalPropositionRule
107
- format_declarations_informal_proposition_rule(node)
108
- when Model::DataTypes::Aggregate
109
- format_data_types_aggregate(node)
110
- when Model::DataTypes::Array
111
- format_data_types_array(node)
112
- when Model::DataTypes::Bag
113
- format_data_types_bag(node)
114
- when Model::DataTypes::Binary
115
- format_data_types_binary(node)
116
- when Model::DataTypes::Boolean
117
- format_data_types_boolean(node)
118
- when Model::DataTypes::Enumeration
119
- format_data_types_enumeration(node)
120
- when Model::DataTypes::EnumerationItem
121
- format_data_types_enumeration_item(node)
122
- when Model::DataTypes::GenericEntity
123
- format_data_types_generic_entity(node)
124
- when Model::DataTypes::Generic
125
- format_data_types_generic(node)
126
- when Model::DataTypes::Integer
127
- format_data_types_integer(node)
128
- when Model::DataTypes::List
129
- format_data_types_list(node)
130
- when Model::DataTypes::Logical
131
- format_data_types_logical(node)
132
- when Model::DataTypes::Number
133
- format_data_types_number(node)
134
- when Model::DataTypes::Real
135
- format_data_types_real(node)
136
- when Model::DataTypes::Select
137
- format_data_types_select(node)
138
- when Model::DataTypes::Set
139
- format_data_types_set(node)
140
- when Model::DataTypes::String
141
- format_data_types_string(node)
142
- when Model::Expressions::AggregateInitializer
143
- format_expressions_aggregate_initializer(node)
144
- when Model::Expressions::AggregateInitializerItem
145
- format_expressions_aggregate_initializer_item(node)
146
- when Model::Expressions::BinaryExpression
147
- format_expressions_binary_expression(node)
148
- when Model::Expressions::EntityConstructor
149
- format_expressions_entity_constructor(node)
150
- when Model::Expressions::FunctionCall
151
- format_expressions_function_call(node)
152
- when Model::Expressions::Interval
153
- format_expressions_interval(node)
154
- when Model::Expressions::QueryExpression
155
- format_expressions_query_expression(node)
156
- when Model::Expressions::UnaryExpression
157
- format_expressions_unary_expression(node)
158
- when Model::Literals::Binary
159
- format_literals_binary(node)
160
- when Model::Literals::Integer
161
- format_literals_integer(node)
162
- when Model::Literals::Logical
163
- format_literals_logical(node)
164
- when Model::Literals::Real
165
- format_literals_real(node)
166
- when Model::Literals::String
167
- format_literals_string(node)
168
- when Model::References::AttributeReference
169
- format_references_attribute_reference(node)
170
- when Model::References::GroupReference
171
- format_references_group_reference(node)
172
- when Model::References::IndexReference
173
- format_references_index_reference(node)
174
- when Model::References::SimpleReference
175
- format_references_simple_reference(node)
176
- when Model::Statements::Alias
177
- format_statements_alias(node)
178
- when Model::Statements::Assignment
179
- format_statements_assignment(node)
180
- when Model::Statements::Case
181
- format_statements_case(node)
182
- when Model::Statements::CaseAction
183
- format_statements_case_action(node)
184
- when Model::Statements::Compound
185
- format_statements_compound(node)
186
- when Model::Statements::Escape
187
- format_statements_escape(node)
188
- when Model::Statements::If
189
- format_statements_if(node)
190
- when Model::Statements::Null
191
- format_statements_null(node)
192
- when Model::Statements::ProcedureCall
193
- format_statements_procedure_call(node)
194
- when Model::Statements::Repeat
195
- format_statements_repeat(node)
196
- when Model::Statements::Return
197
- format_statements_return(node)
198
- when Model::Statements::Skip
199
- format_statements_skip(node)
200
- when Model::SupertypeExpressions::BinarySupertypeExpression
201
- format_supertype_expressions_binary_supertype_expression(node)
202
- when Model::SupertypeExpressions::OneofSupertypeExpression
203
- format_supertype_expressions_oneof_supertype_expression(node)
204
- when Model::Declarations::SchemaVersionItem
205
- # not implemented yet
206
- when Model::Declarations::InterfacedItem
207
- # not implemented yet
208
- when Model::Declarations::RemarkItem
209
- format_remark_item(node)
210
- when Model::Cache
211
- # not implemented yet
212
- when Model::ModelElement
213
- # not implemented yet
214
- when Model::Literals::Logical
215
- node.value
216
- when NilClass
217
- # not implemented yet
218
- else
219
- warn "#{node.class.name} format not implemented"
220
- ""
221
- end
81
+ def format(node)
82
+ return "" if node.nil?
83
+
84
+ handler = self.class.format_registry[node.class]
85
+ return public_send(handler, node) if handler
86
+
87
+ warn "#{node.class.name} format not implemented"
88
+ ""
222
89
  end
223
90
 
224
- private
91
+ def format_noop(_node)
92
+ ""
93
+ end
225
94
 
226
95
  def format_repository(node)
227
- # Format each file in the repository
228
96
  result = node.files&.map { |f| format(f) }&.join("\n\n")
229
97
  result ? "#{result}\n" : ""
230
98
  end
@@ -2,10 +2,53 @@ module Expressir
2
2
  module Express
3
3
  module Formatters
4
4
  module DataTypesFormatter
5
- private
5
+ def self.included(base)
6
+ base.register_formatter Model::DataTypes::Aggregate,
7
+ :format_data_types_aggregate
8
+ base.register_formatter Model::DataTypes::Array,
9
+ :format_data_types_array
10
+ base.register_formatter Model::DataTypes::Bag, :format_data_types_bag
11
+ base.register_formatter Model::DataTypes::Binary,
12
+ :format_data_types_binary
13
+ base.register_formatter Model::DataTypes::Boolean,
14
+ :format_data_types_boolean
15
+ base.register_formatter Model::DataTypes::Enumeration,
16
+ :format_data_types_enumeration
17
+ base.register_formatter Model::DataTypes::EnumerationItem,
18
+ :format_data_types_enumeration_item
19
+ base.register_formatter Model::DataTypes::GenericEntity,
20
+ :format_data_types_generic_entity
21
+ base.register_formatter Model::DataTypes::Generic,
22
+ :format_data_types_generic
23
+ base.register_formatter Model::DataTypes::Integer,
24
+ :format_data_types_integer
25
+ base.register_formatter Model::DataTypes::List,
26
+ :format_data_types_list
27
+ base.register_formatter Model::DataTypes::Logical,
28
+ :format_data_types_logical
29
+ base.register_formatter Model::DataTypes::Number,
30
+ :format_data_types_number
31
+ base.register_formatter Model::DataTypes::Real,
32
+ :format_data_types_real
33
+ base.register_formatter Model::DataTypes::Select,
34
+ :format_data_types_select
35
+ base.register_formatter Model::DataTypes::Set, :format_data_types_set
36
+ base.register_formatter Model::DataTypes::String,
37
+ :format_data_types_string
38
+ end
6
39
 
7
- def format_data_types_aggregate(_node)
8
- "AGGREGATE"
40
+ def format_data_types_aggregate(node)
41
+ [
42
+ "AGGREGATE",
43
+ *if node.base_type
44
+ [
45
+ " ",
46
+ "OF",
47
+ " ",
48
+ format(node.base_type),
49
+ ]
50
+ end,
51
+ ].join
9
52
  end
10
53
 
11
54
  def format_data_types_array(node)
@@ -220,7 +263,7 @@ module Expressir
220
263
 
221
264
  def format_data_types_select(node)
222
265
  indent_char = self.class.const_get(:INDENT_CHAR)
223
- node.items ||= []
266
+ items = Array(node.items)
224
267
  [
225
268
  *if node.extensible
226
269
  [
@@ -241,7 +284,7 @@ module Expressir
241
284
  "BASED_ON",
242
285
  " ",
243
286
  format(node.based_on),
244
- *if node.items&.length&.positive?
287
+ *if items.length.positive?
245
288
  item_indent = indent_char * "(".length
246
289
  [
247
290
  " ",
@@ -249,7 +292,7 @@ module Expressir
249
292
  "\n",
250
293
  indent([
251
294
  "(",
252
- node.items.map do |x|
295
+ items.map do |x|
253
296
  format(x)
254
297
  end.join(",\n#{item_indent}"),
255
298
  ")",
@@ -257,14 +300,14 @@ module Expressir
257
300
  ].join
258
301
  end,
259
302
  ].join
260
- else
303
+ elsif items.length.positive?
261
304
  indent_char = self.class.const_get(:INDENT_CHAR)
262
305
  item_indent = indent_char * "(".length
263
306
  [
264
307
  "\n",
265
308
  indent([
266
309
  "(",
267
- node.items.map do |x|
310
+ items.map do |x|
268
311
  format(x)
269
312
  end.join(",\n#{item_indent}"),
270
313
  ")",