expressir 2.4.0 → 2.4.2

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
  3. data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
  4. data/TODO.bugs/03-builder-mutable-state.md +43 -0
  5. data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
  6. data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
  7. data/TODO.bugs/06-collection-registry-single-source.md +53 -0
  8. data/TODO.bugs/07-require-relative-cleanup.md +42 -0
  9. data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
  10. data/TODO.bugs/09-parser-split.md +53 -0
  11. data/TODO.bugs/10-to-s-override.md +42 -0
  12. data/TODO.bugs/11-parser-class-variables.md +39 -0
  13. data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
  14. data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
  15. data/TODO.bugs/14-model-formatting-leak.md +30 -0
  16. data/TODO.bugs/15-expression-children-macro.md +27 -0
  17. data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
  18. data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
  19. data/TODO.bugs/18-const-get-private-constants.md +30 -0
  20. data/TODO.bugs/19-format-methods-public.md +22 -0
  21. data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
  22. data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
  23. data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
  24. data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
  25. data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
  26. data/TODO.bugs/25-debug-puts-in-production.md +21 -0
  27. data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
  28. data/TODO.bugs/27-package-build-god-method.md +19 -0
  29. data/TODO.bugs/28-package-god-class.md +30 -0
  30. data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
  31. data/TODO.bugs/30-unicode-map-extraction.md +19 -0
  32. data/TODO.bugs/README.md +43 -0
  33. data/TODO.max-perf/01-restore-ci-green.md +29 -0
  34. data/TODO.max-perf/02-streaming-parse-path.md +31 -0
  35. data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
  36. data/TODO.max-perf/04-benchmark-harness.md +28 -0
  37. data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
  38. data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
  39. data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
  40. data/TODO.max-perf/08-builder-build-perf.md +45 -0
  41. data/TODO.max-perf/09-grammar-cold-start.md +25 -0
  42. data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
  43. data/TODO.max-perf/11-ci-green-closeout.md +25 -0
  44. data/TODO.max-perf/12-require-boot-profile.md +25 -0
  45. data/TODO.max-perf/13-key-conversion-specs.md +26 -0
  46. data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
  47. data/benchmark/srl_benchmark.rb +76 -17
  48. data/docs/_tutorials/formatting-schemas.adoc +89 -0
  49. data/docs/_tutorials/index.adoc +10 -0
  50. data/docs/lychee.toml +3 -0
  51. data/expressir.gemspec +4 -2
  52. data/lib/expressir/cli.rb +3 -0
  53. data/lib/expressir/commands/changes_import_eengine.rb +0 -6
  54. data/lib/expressir/commands/changes_validate.rb +0 -2
  55. data/lib/expressir/commands/clean.rb +1 -1
  56. data/lib/expressir/commands/coverage.rb +6 -2
  57. data/lib/expressir/commands/file_violations.rb +70 -0
  58. data/lib/expressir/commands/format.rb +1 -1
  59. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  60. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  61. data/lib/expressir/commands/package.rb +143 -187
  62. data/lib/expressir/commands/validate_ascii.rb +0 -510
  63. data/lib/expressir/commands/version.rb +1 -1
  64. data/lib/expressir/commands.rb +3 -0
  65. data/lib/expressir/coverage.rb +49 -117
  66. data/lib/expressir/express/ast_key_converter.rb +114 -0
  67. data/lib/expressir/express/builder.rb +71 -194
  68. data/lib/expressir/express/builder_context.rb +22 -0
  69. data/lib/expressir/express/builders/expression_builder.rb +16 -16
  70. data/lib/expressir/express/cache.rb +35 -8
  71. data/lib/expressir/express/error.rb +24 -0
  72. data/lib/expressir/express/formatter.rb +33 -18
  73. data/lib/expressir/express/formatters/declarations_formatter.rb +24 -2
  74. data/lib/expressir/express/formatters/remark_formatter.rb +75 -2
  75. data/lib/expressir/express/formatters/statements_formatter.rb +20 -3
  76. data/lib/expressir/express/grammar/parser.rb +705 -0
  77. data/lib/expressir/express/grammar.rb +11 -0
  78. data/lib/expressir/express/node_position_index.rb +215 -0
  79. data/lib/expressir/express/parallel_files.rb +229 -0
  80. data/lib/expressir/express/parser.rb +138 -950
  81. data/lib/expressir/express/pretty_formatter.rb +23 -5
  82. data/lib/expressir/express/remark_attacher.rb +497 -581
  83. data/lib/expressir/express/remark_scanner.rb +84 -19
  84. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  85. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  86. data/lib/expressir/express/scope_resolver.rb +223 -0
  87. data/lib/expressir/express/source_formatter.rb +15 -0
  88. data/lib/expressir/express/streaming_builder.rb +147 -176
  89. data/lib/expressir/express.rb +10 -6
  90. data/lib/expressir/model/concerns.rb +3 -0
  91. data/lib/expressir/model/data_types/generic_entity.rb +6 -6
  92. data/lib/expressir/model/declarations/entity.rb +5 -0
  93. data/lib/expressir/model/declarations/function.rb +5 -0
  94. data/lib/expressir/model/declarations/procedure.rb +5 -0
  95. data/lib/expressir/model/declarations/rule.rb +6 -0
  96. data/lib/expressir/model/declarations/schema.rb +21 -8
  97. data/lib/expressir/model/declarations/type.rb +3 -0
  98. data/lib/expressir/model/exp_file.rb +2 -0
  99. data/lib/expressir/model/expressions/aggregate_initializer.rb +1 -0
  100. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +1 -0
  101. data/lib/expressir/model/expressions/binary_expression.rb +1 -0
  102. data/lib/expressir/model/expressions/entity_constructor.rb +1 -0
  103. data/lib/expressir/model/expressions/function_call.rb +1 -0
  104. data/lib/expressir/model/expressions/interval.rb +1 -0
  105. data/lib/expressir/model/expressions/query_expression.rb +2 -0
  106. data/lib/expressir/model/expressions/unary_expression.rb +1 -0
  107. data/lib/expressir/model/model_element.rb +133 -14
  108. data/lib/expressir/model/remark_format.rb +17 -0
  109. data/lib/expressir/model/remark_info.rb +31 -3
  110. data/lib/expressir/model/remark_placement.rb +29 -0
  111. data/lib/expressir/model/repository.rb +18 -5
  112. data/lib/expressir/model/statements/alias.rb +2 -0
  113. data/lib/expressir/model/statements/assignment.rb +4 -0
  114. data/lib/expressir/model/statements/case.rb +21 -0
  115. data/lib/expressir/model/statements/case_action.rb +1 -0
  116. data/lib/expressir/model/statements/compound.rb +4 -0
  117. data/lib/expressir/model/statements/escape.rb +3 -0
  118. data/lib/expressir/model/statements/if.rb +5 -0
  119. data/lib/expressir/model/statements/null.rb +3 -0
  120. data/lib/expressir/model/statements/procedure_call.rb +3 -0
  121. data/lib/expressir/model/statements/repeat.rb +3 -0
  122. data/lib/expressir/model/statements/return.rb +3 -0
  123. data/lib/expressir/model/statements/skip.rb +3 -0
  124. data/lib/expressir/model.rb +12 -3
  125. data/lib/expressir/package/builder.rb +2 -2
  126. data/lib/expressir/version.rb +6 -1
  127. data/lib/expressir.rb +56 -3
  128. metadata +81 -7
  129. data/lib/expressir/express/transformer/remark_handling.rb +0 -194
@@ -5,516 +5,6 @@ require "table_tennis"
5
5
 
6
6
  module Expressir
7
7
  module Commands
8
- # Represents a non-ASCII character with its details and replacement
9
- class NonAsciiCharacter
10
- attr_reader :char, :hex, :utf8, :is_math, :replacement,
11
- :replacement_type, :occurrences
12
-
13
- def initialize(char, hex, utf8, is_math, replacement, replacement_type)
14
- @char = char
15
- @hex = hex
16
- @utf8 = utf8
17
- @is_math = is_math
18
- @replacement = replacement
19
- @replacement_type = replacement_type
20
- @occurrences = []
21
- end
22
-
23
- def add_occurrence(line_number, column, line)
24
- @occurrences << {
25
- line_number: line_number,
26
- column: column,
27
- line: line,
28
- }
29
- end
30
-
31
- def replacement_text
32
- @is_math ? "AsciiMath: #{@replacement}" : "ISO 10303-11: #{@replacement}"
33
- end
34
-
35
- def occurrence_count
36
- @occurrences.size
37
- end
38
-
39
- def to_h
40
- {
41
- character: @char,
42
- hex: @hex,
43
- utf8: @utf8,
44
- is_math: @is_math,
45
- replacement_type: @replacement_type,
46
- replacement: @replacement,
47
- occurrence_count: occurrence_count,
48
- occurrences: @occurrences,
49
- }
50
- end
51
- end
52
-
53
- # Represents all non-ASCII characters in a file
54
- class FileViolations
55
- attr_reader :path, :filename, :directory, :violations, :unique_characters
56
-
57
- def initialize(file_path)
58
- @path = file_path
59
- @filename = File.basename(file_path)
60
- @directory = File.dirname(file_path)
61
- @characters = {} # Map of characters to NonAsciiCharacter objects
62
- @violations = [] # List of violations (line, column, etc.)
63
- end
64
-
65
- def add_violation(line_number, column, match, char_details, line)
66
- violation = {
67
- line_number: line_number,
68
- column: column,
69
- match: match,
70
- char_details: char_details,
71
- line: line,
72
- }
73
-
74
- @violations << violation
75
-
76
- # Register each character
77
- char_details.each do |detail|
78
- char = detail[:char]
79
- unless @characters[char]
80
- @characters[char] = NonAsciiCharacter.new(
81
- char,
82
- detail[:hex],
83
- detail[:utf8],
84
- detail[:is_math],
85
- detail[:replacement],
86
- detail[:replacement_type],
87
- )
88
- end
89
-
90
- @characters[char].add_occurrence(line_number, column, line)
91
- end
92
- end
93
-
94
- def violation_count
95
- @violations.size
96
- end
97
-
98
- def unique_characters
99
- @characters.values
100
- end
101
-
102
- def display_path
103
- "#{File.basename(@directory)}/#{@filename}"
104
- end
105
-
106
- def full_path
107
- File.expand_path(@path)
108
- end
109
-
110
- def to_h
111
- {
112
- file: display_path,
113
- count: violation_count,
114
- non_ascii_characters: unique_characters.map(&:to_h),
115
- }
116
- end
117
- end
118
-
119
- # Collection of all violations across multiple files
120
- class NonAsciiViolationCollection
121
- attr_reader :file_violations, :total_files
122
-
123
- def initialize(check_remarks: false)
124
- @file_violations = {} # Map of file paths to FileViolations objects
125
- @total_files = 0
126
- @unicode_to_asciimath = nil
127
- @check_remarks = check_remarks
128
- end
129
-
130
- def process_file(file)
131
- @total_files += 1
132
-
133
- # Initialize the mapping once
134
- @unicode_to_asciimath ||= build_unicode_to_asciimath_map
135
-
136
- file_violations = process_file_violations(file)
137
- return if file_violations.violations.empty?
138
-
139
- @file_violations[file] = file_violations
140
- end
141
-
142
- def files_with_violations
143
- @file_violations.size
144
- end
145
-
146
- def total_violations
147
- @file_violations.values.sum(&:violation_count)
148
- end
149
-
150
- def unique_character_count
151
- # Get total unique characters across all files
152
- all_chars = Set.new
153
- @file_violations.each_value do |file_violation|
154
- file_violation.unique_characters.each do |char|
155
- all_chars.add(char.char)
156
- end
157
- end
158
- all_chars.size
159
- end
160
-
161
- def total_occurrence_count
162
- # Sum all occurrences of all characters across all files
163
- @file_violations.values.sum do |file_violation|
164
- file_violation.unique_characters.sum(&:occurrence_count)
165
- end
166
- end
167
-
168
- def to_yaml_data
169
- {
170
- summary: {
171
- total_files: @total_files,
172
- files_with_violations: files_with_violations,
173
- total_violations: total_violations,
174
- total_unique_characters: unique_character_count,
175
- total_occurrences: total_occurrence_count,
176
- },
177
- violations: @file_violations.transform_keys do |k|
178
- File.expand_path(k)
179
- end.transform_values(&:to_h),
180
- }
181
- end
182
-
183
- def print_text_output
184
- # Print each file's violations if any
185
- unless @file_violations.empty?
186
- @file_violations.each_value do |file_violation|
187
- puts "\n#{Paint[file_violation.display_path, :cyan, :bold]}:"
188
-
189
- file_violation.violations.each do |v|
190
- puts " #{Paint['Line',
191
- :blue]} #{Paint[v[:line_number],
192
- :yellow]}, #{Paint['Column',
193
- :blue]} #{Paint[v[:column],
194
- :yellow]}:"
195
- puts " #{v[:line]}"
196
- puts " #{' ' * v[:column]}#{Paint['^' * v[:match].length,
197
- :red]} #{Paint['Non-ASCII sequence',
198
- :red]}"
199
-
200
- v[:char_details].each do |cd|
201
- character = file_violation.unique_characters.find do |c|
202
- c.char == cd[:char]
203
- end
204
- next unless character
205
-
206
- puts " #{Paint["\"#{cd[:char]}\"",
207
- :yellow]} - Hex: #{Paint[cd[:hex],
208
- :magenta]}, UTF-8 bytes: #{Paint[cd[:utf8],
209
- :magenta]}"
210
- puts " #{Paint['Replacement:',
211
- :green]} #{character.replacement_text}"
212
- end
213
- puts ""
214
- end
215
-
216
- puts " #{Paint['Found',
217
- :green]} #{Paint[file_violation.violation_count,
218
- :red]} #{Paint['non-ASCII sequence(s) in',
219
- :green]} #{Paint[file_violation.filename,
220
- :cyan]}\n"
221
- end
222
- end
223
-
224
- # Always print summary
225
- validation_scope = @check_remarks ? "code and remarks" : "code only (remarks excluded)"
226
- puts "\n#{Paint['Summary:', :blue, :bold]}"
227
- puts " #{Paint['Validation scope:',
228
- :green]} #{Paint[validation_scope,
229
- :cyan]}"
230
- puts " #{Paint['Scanned',
231
- :green]} #{Paint[@total_files,
232
- :yellow]} #{Paint['EXPRESS file(s)',
233
- :green]}"
234
- puts " #{Paint['Found',
235
- :green]} #{Paint[total_violations,
236
- :red]} #{Paint['non-ASCII sequence(s) in',
237
- :green]} #{Paint[files_with_violations,
238
- :red]} #{Paint['file(s)',
239
- :green]}"
240
- end
241
-
242
- def print_table_output
243
- return if @file_violations.empty?
244
-
245
- # Build rows array
246
- rows = []
247
- total_occurrences = 0
248
-
249
- @file_violations.each_value do |file_violation|
250
- file_violation.unique_characters.each do |character|
251
- occurrence_count = character.occurrence_count
252
- total_occurrences += occurrence_count
253
-
254
- rows << {
255
- file: file_violation.display_path,
256
- symbol: "\"#{character.char}\" (#{character.hex})",
257
- replacement: character.replacement_text,
258
- occurrences: occurrence_count,
259
- }
260
- end
261
- end
262
-
263
- # Add total row
264
- rows << {
265
- file: "TOTAL",
266
- symbol: "#{unique_character_count} unique",
267
- replacement: "",
268
- occurrences: total_occurrences,
269
- }
270
-
271
- # Use TableTennis to render
272
- options = {
273
- title: "Non-ASCII Characters Summary",
274
- columns: %i[file symbol replacement occurrences],
275
- headers: {
276
- file: "File",
277
- symbol: "Symbol",
278
- replacement: "Replacement",
279
- occurrences: "Occurrences",
280
- },
281
- mark: ->(row) { row[:file] == "TOTAL" },
282
- }
283
-
284
- puts "\n#{TableTennis.new(rows, options)}\n"
285
- end
286
-
287
- private
288
-
289
- def process_file_violations(file)
290
- file_violations = FileViolations.new(file)
291
-
292
- if @check_remarks
293
- # Check remarks too - validate original file content
294
- File.readlines(file,
295
- encoding: "UTF-8").each_with_index do |line, line_idx|
296
- line_number = line_idx + 1
297
-
298
- # Skip if line only contains ASCII
299
- next unless /[^\x00-\x7F]/.match?(line)
300
-
301
- # Find all non-ASCII sequences
302
- line.chomp.scan(/([^\x00-\x7F]+)/) do |match|
303
- match = match[0]
304
- column = line.index(match)
305
-
306
- # Process each character in the sequence
307
- char_details = match.chars.filter_map do |c|
308
- process_non_ascii_char(c)
309
- end
310
-
311
- # Skip if no non-ASCII characters found
312
- next if char_details.empty?
313
-
314
- file_violations.add_violation(line_number, column, match,
315
- char_details, line.chomp)
316
- end
317
- end
318
- else
319
- # Default: exclude remarks - use model-based approach
320
- # Parse the EXPRESS file to get the model
321
- repository = Expressir::Express::Parser.from_file(file)
322
-
323
- # Format each schema without remarks to get plain EXPRESS code
324
- repository.schemas.each do |schema|
325
- formatted_schema = schema.to_s(no_remarks: true)
326
-
327
- # Check the formatted schema (without remarks) for non-ASCII
328
- formatted_schema.lines.each_with_index do |line, line_idx|
329
- line_number = line_idx + 1
330
-
331
- # Skip if line only contains ASCII
332
- next unless /[^\x00-\x7F]/.match?(line)
333
-
334
- # Find all non-ASCII sequences
335
- line.chomp.scan(/([^\x00-\x7F]+)/) do |match|
336
- match = match[0]
337
- column = line.index(match)
338
-
339
- # Process each character in the sequence
340
- char_details = match.chars.filter_map do |c|
341
- process_non_ascii_char(c)
342
- end
343
-
344
- # Skip if no non-ASCII characters found
345
- next if char_details.empty?
346
-
347
- file_violations.add_violation(line_number, column, match,
348
- char_details, line.chomp)
349
- end
350
- end
351
- end
352
- end
353
-
354
- file_violations
355
- rescue Expressir::Express::Error::SchemaParseFailure
356
- # If file can't be parsed, fall back to checking original content
357
- # This ensures we still catch non-ASCII even in invalid EXPRESS
358
- File.readlines(file,
359
- encoding: "UTF-8").each_with_index do |line, line_idx|
360
- line_number = line_idx + 1
361
-
362
- # Skip if line only contains ASCII
363
- next unless /[^\x00-\x7F]/.match?(line)
364
-
365
- # Find all non-ASCII sequences
366
- line.chomp.scan(/([^\x00-\x7F]+)/) do |match|
367
- match = match[0]
368
- column = line.index(match)
369
-
370
- # Process each character in the sequence
371
- char_details = match.chars.filter_map do |c|
372
- process_non_ascii_char(c)
373
- end
374
-
375
- # Skip if no non-ASCII characters found
376
- next if char_details.empty?
377
-
378
- file_violations.add_violation(line_number, column, match,
379
- char_details, line.chomp)
380
- end
381
- end
382
-
383
- file_violations
384
- end
385
-
386
- def process_non_ascii_char(char)
387
- # Skip ASCII characters
388
- return nil if char.ord <= 0x7F
389
-
390
- code_point = char.ord
391
- hex = "0x#{code_point.to_s(16)}"
392
- utf8 = code_point.chr(Encoding::UTF_8).bytes.map do |b|
393
- "0x#{b.to_s(16)}"
394
- end.join(" ")
395
-
396
- # Check if it's a math symbol
397
- if asciimath = @unicode_to_asciimath[char]
398
- return {
399
- char: char,
400
- hex: hex,
401
- utf8: utf8,
402
- is_math: true,
403
- replacement: asciimath,
404
- replacement_type: "asciimath",
405
- }
406
- end
407
-
408
- # Not a math symbol, use ISO encoding
409
- {
410
- char: char,
411
- hex: hex,
412
- utf8: utf8,
413
- is_math: false,
414
- replacement: encode_iso_10303_11(char),
415
- replacement_type: "iso-10303-11",
416
- }
417
- end
418
-
419
- def encode_iso_10303_11(char)
420
- code_point = char.ord
421
-
422
- # Format the encoded value with double quotes
423
- if code_point < 0x10000
424
- "\"#{sprintf('%08X', code_point)}\"" # e.g., "00000041" for 'A'
425
- else
426
- # For higher code points, use all four octets
427
- group = (code_point >> 24) & 0xFF
428
- plane = (code_point >> 16) & 0xFF
429
- row = (code_point >> 8) & 0xFF
430
- cell = code_point & 0xFF
431
-
432
- "\"#{sprintf('%02X%02X%02X%02X', group, plane, row, cell)}\""
433
- end
434
- end
435
-
436
- def build_unicode_to_asciimath_map
437
- # Pre-defined mapping of common math symbols
438
- {
439
- # Greek letters
440
- "α" => "alpha",
441
- "β" => "beta",
442
- "γ" => "gamma",
443
- "Γ" => "Gamma",
444
- "δ" => "delta",
445
- "Δ" => "Delta",
446
- "ε" => "epsilon",
447
- "ζ" => "zeta",
448
- "η" => "eta",
449
- "θ" => "theta",
450
- "Θ" => "Theta",
451
- "ι" => "iota",
452
- "κ" => "kappa",
453
- "λ" => "lambda",
454
- "Λ" => "Lambda",
455
- "μ" => "mu",
456
- "ν" => "nu",
457
- "ξ" => "xi",
458
- "Ξ" => "Xi",
459
- "π" => "pi",
460
- "Π" => "Pi",
461
- "ρ" => "rho",
462
- "σ" => "sigma",
463
- "Σ" => "Sigma",
464
- "τ" => "tau",
465
- "υ" => "upsilon",
466
- "φ" => "phi",
467
- "Φ" => "Phi",
468
- "χ" => "chi",
469
- "ψ" => "psi",
470
- "Ψ" => "Psi",
471
- "ω" => "omega",
472
- "Ω" => "Omega",
473
-
474
- # Math operators
475
- "×" => "xx",
476
- "÷" => "div",
477
- "±" => "pm",
478
- "∓" => "mp",
479
- "∞" => "oo",
480
- "≤" => "le",
481
- "≥" => "ge",
482
- "≠" => "ne",
483
- "≈" => "~~",
484
- "≅" => "cong",
485
- "≡" => "equiv",
486
- "∈" => "in",
487
- "∉" => "notin",
488
- "⊂" => "subset",
489
- "⊃" => "supset",
490
- "∩" => "cap",
491
- "∪" => "cup",
492
- "∧" => "and",
493
- "∨" => "or",
494
- "¬" => "neg",
495
- "∀" => "forall",
496
- "∃" => "exists",
497
- "∄" => "nexists",
498
- "∇" => "grad",
499
- "∂" => "del",
500
- "∑" => "sum",
501
- "∏" => "prod",
502
- "∫" => "int",
503
- "∮" => "oint",
504
- "√" => "sqrt",
505
- "⊥" => "perp",
506
- "‖" => "norm",
507
- "→" => "rarr",
508
- "←" => "larr",
509
- "↔" => "harr",
510
- "⇒" => "rArr",
511
- "⇐" => "lArr",
512
- "⇔" => "hArr",
513
- }
514
- end
515
- end
516
-
517
- # ValidateAscii command for checking EXPRESS files for non-ASCII characters
518
8
  class ValidateAscii < Base
519
9
  def run(express_file_path) # rubocop:disable Metrics/AbcSize
520
10
  # Check if input is a manifest file
@@ -2,7 +2,7 @@ module Expressir
2
2
  module Commands
3
3
  class Version < Base
4
4
  def run
5
- say Expressir::VERSION
5
+ say Expressir::Version::VERSION
6
6
  end
7
7
  end
8
8
  end
@@ -10,6 +10,9 @@ module Expressir
10
10
  autoload :Validate, "#{__dir__}/commands/validate"
11
11
  autoload :ValidateLoad, "#{__dir__}/commands/validate_load"
12
12
  autoload :ValidateAscii, "#{__dir__}/commands/validate_ascii"
13
+ autoload :NonAsciiCharacter, "#{__dir__}/commands/non_ascii_character"
14
+ autoload :FileViolations, "#{__dir__}/commands/file_violations"
15
+ autoload :NonAsciiViolationCollection, "#{__dir__}/commands/non_ascii_violation_collection"
13
16
  autoload :Changes, "#{__dir__}/commands/changes"
14
17
  autoload :ChangesValidate, "#{__dir__}/commands/changes_validate"
15
18
  autoload :ChangesImportEengine, "#{__dir__}/commands/changes_import_eengine"