expressir 2.1.18 → 2.1.20

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.
data/lib/expressir/cli.rb CHANGED
@@ -1,32 +1,32 @@
1
1
  require "thor"
2
2
  require "yaml"
3
+ require "terminal-table"
4
+
5
+ require_relative "commands/base"
6
+ require_relative "commands/format"
7
+ require_relative "commands/clean"
8
+ require_relative "commands/benchmark"
9
+ require_relative "commands/benchmark_cache"
10
+ require_relative "commands/validate"
11
+ require_relative "commands/coverage"
12
+ require_relative "commands/version"
3
13
 
4
14
  module Expressir
5
15
  class Cli < Thor
16
+ # Exit with error code on command failures
17
+ def self.exit_on_failure?
18
+ true
19
+ end
20
+
6
21
  desc "format PATH", "pretty print EXPRESS schema located at PATH"
7
22
  def format(path)
8
- repository = Expressir::Express::Parser.from_file(path)
9
- repository.schemas.each do |schema|
10
- puts "\n(* Expressir formatted schema: #{schema.id} *)\n"
11
- puts schema.to_s(no_remarks: true)
12
- end
23
+ Commands::Format.new(options).run(path)
13
24
  end
14
25
 
15
26
  desc "clean PATH", "Strip remarks and prettify EXPRESS schema at PATH"
16
27
  method_option :output, type: :string, desc: "Output file path (defaults to stdout)"
17
28
  def clean(path)
18
- repository = Expressir::Express::Parser.from_file(path)
19
- formatted_schemas = repository.schemas.map do |schema|
20
- # Format schema without remarks
21
- schema.to_s(no_remarks: true)
22
- end.join("\n\n")
23
-
24
- if options[:output]
25
- File.write(options[:output], formatted_schemas)
26
- puts "Cleaned schema written to #{options[:output]}"
27
- else
28
- puts formatted_schemas
29
- end
29
+ Commands::Clean.new(options).run(path)
30
30
  end
31
31
 
32
32
  desc "benchmark FILE_OR_YAML", "Benchmark schema loading performance for a file or list of files from YAML"
@@ -35,18 +35,7 @@ module Expressir
35
35
  method_option :save, type: :boolean, desc: "Save benchmark results to file"
36
36
  method_option :format, type: :string, desc: "Output format (json, csv, default)"
37
37
  def benchmark(path)
38
- # Enable benchmarking via configuration
39
- Expressir.configuration.benchmark_enabled = true
40
- Expressir.configuration.benchmark_ips = options[:ips]
41
- Expressir.configuration.benchmark_verbose = options[:verbose]
42
- Expressir.configuration.benchmark_save = options[:save]
43
- Expressir.configuration.benchmark_format = options[:format] if options[:format]
44
-
45
- if [".yml", ".yaml"].include?(File.extname(path).downcase)
46
- benchmark_from_yaml(path)
47
- else
48
- benchmark_file(path)
49
- end
38
+ Commands::Benchmark.new(options).run(path)
50
39
  end
51
40
 
52
41
  desc "benchmark-cache FILE_OR_YAML", "Benchmark schema loading with caching"
@@ -56,178 +45,25 @@ module Expressir
56
45
  method_option :format, type: :string, desc: "Output format (json, csv, default)"
57
46
  method_option :cache_path, type: :string, desc: "Path to store the cache file"
58
47
  def benchmark_cache(path)
59
- # Same options as benchmark + cache_path
60
- Expressir.configuration.benchmark_enabled = true
61
- Expressir.configuration.benchmark_ips = options[:ips]
62
- Expressir.configuration.benchmark_verbose = options[:verbose]
63
- Expressir.configuration.benchmark_save = options[:save]
64
- Expressir.configuration.benchmark_format = options[:format] if options[:format]
65
-
66
- # Run benchmarks with cache
67
- cache_path = options[:cache_path] || generate_temp_cache_path
68
-
69
- if [".yml", ".yaml"].include?(File.extname(path).downcase)
70
- benchmark_cache_from_yaml(path, cache_path)
71
- else
72
- benchmark_cache_file(path, cache_path)
73
- end
74
- end
75
-
76
- no_commands do
77
- def _validate_schema(path)
78
- repository = Expressir::Express::Parser.from_file(path)
79
- repository.schemas.inject([]) do |acc, schema|
80
- acc << schema.id unless schema.version&.value
81
- acc
82
- end
83
- rescue StandardError
84
- nil
85
- end
86
-
87
- def _print_validation_errors(type, array)
88
- return if array.empty?
89
-
90
- puts "#{'*' * 20} RESULTS: #{type.to_s.upcase.tr('_', ' ')} #{'*' * 20}"
91
- array.each do |msg|
92
- puts msg
93
- end
94
- end
95
-
96
- def benchmark_file(path)
97
- puts "Express Schema Loading Benchmark"
98
- puts "--------------------------------"
99
-
100
- repository = Expressir::Benchmark.measure_file(path) do
101
- Expressir::Express::Parser.from_file(path)
102
- end
103
-
104
- if repository
105
- puts "Loaded #{repository.schemas.size} schemas"
106
- else
107
- puts "Failed to load schema"
108
- end
109
- end
110
-
111
- def benchmark_from_yaml(yaml_path)
112
- puts "Express Schema Loading Benchmark from YAML"
113
- puts "--------------------------------"
114
-
115
- # Load schema list from YAML
116
- schema_list = YAML.load_file(yaml_path)
117
- if schema_list.is_a?(Hash) && schema_list["schemas"]
118
- # Handle format: { "schemas": ["path1", "path2", ...] }
119
- schema_files = schema_list["schemas"]
120
- elsif schema_list.is_a?(Array)
121
- # Handle format: ["path1", "path2", ...]
122
- schema_files = schema_list
123
- else
124
- puts "Invalid YAML format. Expected an array of schema paths or a hash with a 'schemas' key."
125
- return
126
- end
127
-
128
- puts "YAML File: #{yaml_path}"
129
- puts "Number of schemas in list: #{schema_files.size}"
130
- puts "--------------------------------"
131
-
132
- # Load the schemas
133
- Expressir::Benchmark.measure_collection(schema_files) do |file|
134
- repository = Expressir::Express::Parser.from_file(file)
135
- repository.schemas
136
- end
137
- end
138
-
139
- def benchmark_cache_file(path, cache_path)
140
- puts "Express Schema Loading Benchmark with Caching"
141
- puts "--------------------------------"
142
- puts "Schema: #{path}"
143
- puts "Cache: #{cache_path}"
144
- puts "--------------------------------"
145
-
146
- # Benchmark with caching
147
- results = Expressir::Benchmark.measure_with_cache(path, cache_path) do |file|
148
- Expressir::Express::Parser.from_file(file)
149
- end
150
-
151
- if results[:repository]
152
- schema_count = results[:repository].schemas.size
153
- puts "Loaded #{schema_count} schemas"
154
- else
155
- puts "Failed to load schema"
156
- end
157
- end
158
-
159
- def benchmark_cache_from_yaml(yaml_path, cache_path)
160
- puts "Express Schema Loading Benchmark with Caching from YAML"
161
- puts "--------------------------------"
162
-
163
- # Load schema list from YAML
164
- schema_list = YAML.load_file(yaml_path)
165
- if schema_list.is_a?(Hash) && schema_list["schemas"]
166
- # Handle format: { "schemas": ["path1", "path2", ...] }
167
- schema_files = schema_list["schemas"]
168
- elsif schema_list.is_a?(Array)
169
- # Handle format: ["path1", "path2", ...]
170
- schema_files = schema_list
171
- else
172
- puts "Invalid YAML format. Expected an array of schema paths or a hash with a 'schemas' key."
173
- return
174
- end
175
-
176
- puts "YAML File: #{yaml_path}"
177
- puts "Number of schemas in list: #{schema_files.size}"
178
- puts "Cache: #{cache_path}"
179
- puts "--------------------------------"
180
-
181
- # Process each file with caching
182
- schema_files.each_with_index do |file, index|
183
- puts "Processing file #{index + 1}/#{schema_files.size}: #{file}"
184
-
185
- # Benchmark with caching
186
- Expressir::Benchmark.measure_with_cache(file, cache_path) do |path|
187
- Expressir::Express::Parser.from_file(path)
188
- end
189
-
190
- puts "--------------------------------"
191
- end
192
- end
193
-
194
- def generate_temp_cache_path
195
- require "tempfile"
196
- Tempfile.new(["expressir_cache", ".bin"]).path
197
- end
48
+ Commands::BenchmarkCache.new(options).run(path)
198
49
  end
199
50
 
200
51
  desc "validate *PATH", "validate EXPRESS schema located at PATH"
201
- def validate(*paths) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
202
- no_version = []
203
- no_valid = []
204
-
205
- paths.each do |path|
206
- x = Pathname.new(path).realpath.relative_path_from(Dir.pwd)
207
- puts "Validating #{x}"
208
- ret = _validate_schema(path)
209
-
210
- if ret.nil?
211
- no_valid << "Failed to parse: #{x}"
212
- next
213
- end
214
-
215
- ret.each do |schema_id|
216
- no_version << "Missing version string: schema `#{schema_id}` | #{x}"
217
- end
218
- end
219
-
220
- _print_validation_errors(:failed_to_parse, no_valid)
221
- _print_validation_errors(:missing_version_string, no_version)
222
-
223
- exit 1 unless [no_valid, no_version].all?(&:empty?)
52
+ def validate(*paths)
53
+ Commands::Validate.new(options).run(paths)
54
+ end
224
55
 
225
- puts "Validation passed for all EXPRESS schemas."
56
+ desc "coverage *PATH", "List EXPRESS entities and check documentation coverage"
57
+ method_option :format, type: :string, desc: "Output format (text, json, yaml)", default: "text"
58
+ method_option :exclude, type: :string, desc: "Comma-separated list of EXPRESS entity types to skip from coverage (e.g., TYPE,CONSTANT,TYPE:SELECT)"
59
+ method_option :output, type: :string, desc: "Output file path for JSON/YAML formats (defaults to coverage_report.json/yaml)"
60
+ def coverage(*paths)
61
+ Commands::Coverage.new(options).run(paths)
226
62
  end
227
63
 
228
64
  desc "version", "Expressir Version"
229
65
  def version
230
- say(Expressir::VERSION)
66
+ Commands::Version.new(options).run
231
67
  end
232
68
  end
233
69
  end
@@ -0,0 +1,32 @@
1
+ module Expressir
2
+ module Commands
3
+ class Base
4
+ attr_reader :options
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+ end
9
+
10
+ # Common utilities that all commands might need
11
+ def say(message)
12
+ # Use instance variable for testability - if output is set, use it
13
+ if defined?(@output) && @output
14
+ @output.puts(message)
15
+ else
16
+ puts(message)
17
+ end
18
+ end
19
+
20
+ def exit_with_error(message, exit_code = 1)
21
+ say message
22
+ # In test mode, raise an exception instead of exiting
23
+ # This makes it easier to test error cases
24
+ if defined?(@test_mode) && @test_mode
25
+ raise message # Just raise the message as an exception
26
+ else
27
+ exit exit_code
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,68 @@
1
+ module Expressir
2
+ module Commands
3
+ class Benchmark < Base
4
+ def run(path)
5
+ configure_benchmarking
6
+
7
+ if [".yml", ".yaml"].include?(File.extname(path).downcase)
8
+ benchmark_from_yaml(path)
9
+ else
10
+ benchmark_file(path)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def configure_benchmarking
17
+ Expressir.configuration.benchmark_enabled = true
18
+ Expressir.configuration.benchmark_ips = options[:ips]
19
+ Expressir.configuration.benchmark_verbose = options[:verbose]
20
+ Expressir.configuration.benchmark_save = options[:save]
21
+ Expressir.configuration.benchmark_format = options[:format] if options[:format]
22
+ end
23
+
24
+ def benchmark_file(path)
25
+ say "Express Schema Loading Benchmark"
26
+ say "--------------------------------"
27
+
28
+ repository = Expressir::Benchmark.measure_file(path) do
29
+ Expressir::Express::Parser.from_file(path)
30
+ end
31
+
32
+ if repository
33
+ say "Loaded #{repository.schemas.size} schemas"
34
+ else
35
+ say "Failed to load schema"
36
+ end
37
+ end
38
+
39
+ def benchmark_from_yaml(yaml_path)
40
+ say "Express Schema Loading Benchmark from YAML"
41
+ say "--------------------------------"
42
+
43
+ # Load schema list from YAML
44
+ schema_list = YAML.load_file(yaml_path)
45
+ if schema_list.is_a?(Hash) && schema_list["schemas"]
46
+ # Handle format: { "schemas": ["path1", "path2", ...] }
47
+ schema_files = schema_list["schemas"]
48
+ elsif schema_list.is_a?(Array)
49
+ # Handle format: ["path1", "path2", ...]
50
+ schema_files = schema_list
51
+ else
52
+ say "Invalid YAML format. Expected an array of schema paths or a hash with a 'schemas' key."
53
+ return
54
+ end
55
+
56
+ say "YAML File: #{yaml_path}"
57
+ say "Number of schemas in list: #{schema_files.size}"
58
+ say "--------------------------------"
59
+
60
+ # Load the schemas
61
+ Expressir::Benchmark.measure_collection(schema_files) do |file|
62
+ repository = Expressir::Express::Parser.from_file(file)
63
+ repository.schemas
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,88 @@
1
+ module Expressir
2
+ module Commands
3
+ class BenchmarkCache < Base
4
+ def run(path)
5
+ configure_benchmarking
6
+
7
+ # Run benchmarks with cache
8
+ cache_path = options[:cache_path] || generate_temp_cache_path
9
+
10
+ if [".yml", ".yaml"].include?(File.extname(path).downcase)
11
+ benchmark_cache_from_yaml(path, cache_path)
12
+ else
13
+ benchmark_cache_file(path, cache_path)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def configure_benchmarking
20
+ Expressir.configuration.benchmark_enabled = true
21
+ Expressir.configuration.benchmark_ips = options[:ips]
22
+ Expressir.configuration.benchmark_verbose = options[:verbose]
23
+ Expressir.configuration.benchmark_save = options[:save]
24
+ Expressir.configuration.benchmark_format = options[:format] if options[:format]
25
+ end
26
+
27
+ def benchmark_cache_file(path, cache_path)
28
+ say "Express Schema Loading Benchmark with Caching"
29
+ say "--------------------------------"
30
+ say "Schema: #{path}"
31
+ say "Cache: #{cache_path}"
32
+ say "--------------------------------"
33
+
34
+ # Benchmark with caching
35
+ results = Expressir::Benchmark.measure_with_cache(path, cache_path) do |file|
36
+ Expressir::Express::Parser.from_file(file)
37
+ end
38
+
39
+ if results[:repository]
40
+ schema_count = results[:repository].schemas.size
41
+ say "Loaded #{schema_count} schemas"
42
+ else
43
+ say "Failed to load schema"
44
+ end
45
+ end
46
+
47
+ def benchmark_cache_from_yaml(yaml_path, cache_path)
48
+ say "Express Schema Loading Benchmark with Caching from YAML"
49
+ say "--------------------------------"
50
+
51
+ # Load schema list from YAML
52
+ schema_list = YAML.load_file(yaml_path)
53
+ if schema_list.is_a?(Hash) && schema_list["schemas"]
54
+ # Handle format: { "schemas": ["path1", "path2", ...] }
55
+ schema_files = schema_list["schemas"]
56
+ elsif schema_list.is_a?(Array)
57
+ # Handle format: ["path1", "path2", ...]
58
+ schema_files = schema_list
59
+ else
60
+ say "Invalid YAML format. Expected an array of schema paths or a hash with a 'schemas' key."
61
+ return
62
+ end
63
+
64
+ say "YAML File: #{yaml_path}"
65
+ say "Number of schemas in list: #{schema_files.size}"
66
+ say "Cache: #{cache_path}"
67
+ say "--------------------------------"
68
+
69
+ # Process each file with caching
70
+ schema_files.each_with_index do |file, index|
71
+ say "Processing file #{index + 1}/#{schema_files.size}: #{file}"
72
+
73
+ # Benchmark with caching
74
+ Expressir::Benchmark.measure_with_cache(file, cache_path) do |path|
75
+ Expressir::Express::Parser.from_file(path)
76
+ end
77
+
78
+ say "--------------------------------"
79
+ end
80
+ end
81
+
82
+ def generate_temp_cache_path
83
+ require "tempfile"
84
+ Tempfile.new(["expressir_cache", ".bin"]).path
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,20 @@
1
+ module Expressir
2
+ module Commands
3
+ class Clean < Base
4
+ def run(path)
5
+ repository = Expressir::Express::Parser.from_file(path)
6
+ formatted_schemas = repository.schemas.map do |schema|
7
+ # Format schema without remarks
8
+ schema.to_s(no_remarks: true)
9
+ end.join("\n\n")
10
+
11
+ if options[:output]
12
+ File.write(options[:output], formatted_schemas)
13
+ say "Cleaned schema written to #{options[:output]}"
14
+ else
15
+ say formatted_schemas
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end