dorian 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/dorian/bin.rb +163 -36
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f442cb1d0f47b1eed61e28ae03731f5c6992e61bf074dbaa3f8b54d185dad8d7
4
- data.tar.gz: 877156a017e90bdc05a57b03f072467a9ab97d4ad4880d4be4fd6ef0e6ee5948
3
+ metadata.gz: 926123b36e9d821e68bec3a83818a70f7a39f6f52c1fa5d19ac777dc98b64da0
4
+ data.tar.gz: ae5fda1a6fb16ae0ae1d3fd61a329608586329fde537e4c4430513f0d2e1eb25
5
5
  SHA512:
6
- metadata.gz: b1676c471187b363b7ed432d331d7b3ce5b20992e7f57712088bc79a182db567a140fdc2edd5af8be674031e82862b1bedd514a19434f7d81630b1b2cbb771a6
7
- data.tar.gz: c2569fa773cc0fd88871ca875a6a1fa304c06e746cecd403e591b7dbcb3e19f2e3a6e3877cd19b8071c9b0966219b03306bdd6d5f4850b57f0acffc859b40fe2
6
+ metadata.gz: 5c9bbdc2e3951bd84159719b1292dce233c4092937cdb18054301e438517030bf4bf3b2352a89ec1cb705751130f8f374b1bc40b7496951be21b7744be36cf5c
7
+ data.tar.gz: 1e9210a0bf87c799539ac9ce4c39dd774c4483facdd326718c31bb3655a895a08b1aae273e80eb87a0f32ad6aa46491bbe73a4a2ec5645102ee4c59665019f50
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.1
1
+ 2.1.0
data/lib/dorian/bin.rb CHANGED
@@ -6,8 +6,8 @@ require "dorian/eval"
6
6
  require "dorian/progress"
7
7
  require "dorian/to_struct"
8
8
  require "json"
9
- require "yaml"
10
9
  require "parallel"
10
+ require "yaml"
11
11
 
12
12
  class Dorian
13
13
  class Bin
@@ -21,10 +21,12 @@ class Dorian
21
21
  "jsonl" => :jsonl,
22
22
  "raw" => :raw,
23
23
  "yaml" => :yaml,
24
- "yml" => :yaml
24
+ "yml" => :yaml,
25
+ "yamll" => :yamll,
26
+ "ymll" => :yamll
25
27
  }.freeze
26
28
 
27
- attr_reader :parsed, :command, :arguments
29
+ attr_reader :parsed, :command, :arguments, :ruby
28
30
 
29
31
  def initialize
30
32
  @parsed =
@@ -47,6 +49,15 @@ class Dorian
47
49
  parallel: {
48
50
  alias: :p
49
51
  },
52
+ parallel_type: {
53
+ alias: :pt,
54
+ type: :string,
55
+ default: :processes
56
+ },
57
+ n: {
58
+ type: :integer,
59
+ default: 100
60
+ },
50
61
  rails: {
51
62
  alias: :r
52
63
  },
@@ -73,7 +84,8 @@ class Dorian
73
84
  progress: :boolean,
74
85
  headers: :boolean,
75
86
  progress_format: {
76
- alias: :pf
87
+ alias: :pf,
88
+ type: :string
77
89
  },
78
90
  pretty: {
79
91
  default: true
@@ -87,7 +99,9 @@ class Dorian
87
99
  }
88
100
  )
89
101
 
90
- @command, *@arguments = parsed.arguments
102
+ @arguments = parsed.arguments
103
+ @command = arguments.first
104
+ @ruby = nil
91
105
  end
92
106
 
93
107
  def self.run(...)
@@ -99,12 +113,22 @@ class Dorian
99
113
  abort VERSION if version?
100
114
 
101
115
  case command&.to_sym
102
- when :read, nil
103
- command_read
104
116
  when :each
117
+ arguments.delete("each")
118
+ @command = :each
119
+ @ruby = arguments.join(" ")
120
+ @arguments = []
105
121
  command_each
122
+ when :all
123
+ arguments.delete("all")
124
+ @command = :all
125
+ @ruby = arguments.join(" ")
126
+ @arguments = []
127
+ command_all
106
128
  else
107
- abort "#{command} not supported"
129
+ arguments.delete("read")
130
+ @command = :read
131
+ command_read
108
132
  end
109
133
  end
110
134
 
@@ -117,17 +141,27 @@ class Dorian
117
141
  outputs(reads(File.read(input)), file: input)
118
142
  end
119
143
 
120
- each(stdin_arguments) { |input| outputs(reads(input)) }
144
+ each(stdin_arguments + arguments) { |input| outputs(reads(input)) }
145
+ end
146
+
147
+ def everything
148
+ read_stdin_files + read_files + stdin_arguments + arguments
121
149
  end
122
150
 
123
151
  def command_each
124
- each(read_stdin_files + read_files + stdin_arguments) do |input|
125
- each(lines(reads(input))) do |line|
126
- evaluates(arguments.join(" "), it: line)
152
+ each(everything) do |input|
153
+ each(lines(reads(input)), progress: true) do |line|
154
+ evaluates(ruby, it: line)
127
155
  end
128
156
  end
129
157
  end
130
158
 
159
+ def command_all
160
+ each(everything, progress: true) do |input|
161
+ evaluates(ruby, it: reads(input))
162
+ end
163
+ end
164
+
131
165
  def outputs(content, file: nil)
132
166
  if write? && file
133
167
  File.write(file, to_output(content))
@@ -141,25 +175,22 @@ class Dorian
141
175
 
142
176
  case output
143
177
  when :csv
144
- CSV.generate(headers: headers_of(content)) do |csv|
145
- csv << headers_of(content) if headers_of(content)
146
-
147
- each(content) { |row| csv << row }
148
- end
178
+ (headers_of(content) ? headers_of(content).to_csv : "") +
179
+ map(content) do |element|
180
+ CSV.generate(headers: headers_of(content)) do |csv|
181
+ csv << wrap(element)
182
+ end
183
+ end.join
149
184
  when :json
150
185
  pretty? ? JSON.pretty_generate(content) : content.to_json
151
- when :jsonl
186
+ when :jsonl, :yamll
152
187
  map(content, &:to_json).join("\n")
153
188
  when :raw
154
189
  content
155
- when :ruby
156
- content.inspect
157
- when :rubyl
158
- map(content, &:inspect).join("\n")
159
190
  when :yaml
160
191
  content.to_yaml
161
192
  else
162
- abort "#{output} not supported"
193
+ abort "#{output.inspect} not supported"
163
194
  end
164
195
  end
165
196
 
@@ -173,15 +204,19 @@ class Dorian
173
204
  end
174
205
  when :json
175
206
  JSON.parse(content).to_deep_struct
176
- when :jsonl
207
+ when :jsonl, :yamll
177
208
  map(content.lines) { |line| JSON.parse(line) }.to_deep_struct
178
209
  when :raw
179
210
  content
180
211
  when :yaml
181
- YAML.safe_load(content)
212
+ YAML.safe_load(content).to_deep_struct
182
213
  else
183
- abort "#{input} not supported"
214
+ abort "#{input.inspect} not supported"
184
215
  end
216
+ rescue JSON::ParserError => e
217
+ abort "invalid json: #{e.message}"
218
+ rescue Psych::SyntaxError => e
219
+ abort "invalid yaml: #{e.message}"
185
220
  end
186
221
 
187
222
  def pretty?
@@ -190,13 +225,15 @@ class Dorian
190
225
 
191
226
  def read_stdin
192
227
  @read_stdin ||= $stdin.each_line.to_a
228
+ rescue Interrupt
229
+ abort "interupt in read_stdin"
193
230
  end
194
231
 
195
232
  def stdin_files
196
- return [] if files.any?
197
- return [] unless stdin == :files
233
+ return [] if files.any? || arguments.any?
234
+ return [] if stdin != :files
198
235
 
199
- read_stdin.map(&:rstrip)
236
+ map(read_stdin, &:rstrip)
200
237
  end
201
238
 
202
239
  def read_stdin_files
@@ -208,7 +245,7 @@ class Dorian
208
245
  end
209
246
 
210
247
  def stdin_arguments
211
- return [] if files.any?
248
+ return [] if files.any? || arguments.any?
212
249
  return [] if stdin == :files
213
250
 
214
251
  [read_stdin.join]
@@ -218,6 +255,10 @@ class Dorian
218
255
  options.stdin.to_sym
219
256
  end
220
257
 
258
+ def deep?
259
+ !!options.deep
260
+ end
261
+
221
262
  def options
222
263
  parsed.options
223
264
  end
@@ -294,26 +335,110 @@ class Dorian
294
335
  parsed.help
295
336
  end
296
337
 
338
+ def n
339
+ options.n
340
+ end
341
+
342
+ def parallel_type
343
+ options.parallel_type&.to_sym
344
+ end
345
+
297
346
  def headers_of(content)
298
- return unless headers?
299
347
  return unless content.respond_to?(:first)
300
348
  return unless content.first
301
349
  return unless content.first.respond_to?(:to_h)
302
350
  return unless content.first.to_h.keys.any?
303
351
 
304
352
  content.first.to_h.keys
353
+ rescue TypeError
354
+ nil
355
+ end
356
+
357
+ def parallel_options
358
+ if parallel_type == :processes
359
+ { in_processes: n }
360
+ elsif parallel_type == :threads
361
+ { in_threads: n }
362
+ else
363
+ abort "#{parallel_type.inspect} not supported"
364
+ end
305
365
  end
306
366
 
307
- def each(collection, &)
308
- parallel? ? Parallel.each(collection, &) : collection.each(&)
367
+ def each(collection, options: parallel_options, progress: false, &)
368
+ collection = wrap(collection)
369
+ progress_bar = progress ? create_progress_bar(collection.size) : nil
370
+
371
+ if parallel?
372
+ Parallel.each(
373
+ collection,
374
+ **options,
375
+ finish: ->(*) { progress_bar&.increment },
376
+ &
377
+ )
378
+ else
379
+ collection.each do |element|
380
+ yield(element).tap { progress_bar&.increment }
381
+ end
382
+ end
309
383
  end
310
384
 
311
- def map(collection, &)
312
- parallel? ? Parallel.map(collection, &) : collection.map(&)
385
+ def map(collection, options: parallel_options, progress: false, &)
386
+ collection = wrap(collection)
387
+ progress_bar = progress ? create_progress_bar(collection.size) : nil
388
+
389
+ if parallel?
390
+ Parallel.map(
391
+ collection,
392
+ **options,
393
+ finish: ->(*) { progress_bar&.increment },
394
+ &
395
+ )
396
+ else
397
+ collection.map do |element|
398
+ yield(element).tap { progress_bar&.increment }
399
+ end
400
+ end
313
401
  end
314
402
 
315
403
  def lines(input)
316
- input.is_a?(String) ? input.lines.map(&:rstrip) : Array(input)
404
+ if input.is_a?(String)
405
+ input.lines.map(&:rstrip)
406
+ elsif deep?
407
+ deep_lines(input)
408
+ else
409
+ Array(input)
410
+ end
411
+ end
412
+
413
+ def deep_lines(input)
414
+ case input
415
+ when Array
416
+ [input.to_deep_struct] +
417
+ input.flat_map { |element| deep_lines(element) }
418
+ when Hash
419
+ [input.to_deep_struct] +
420
+ input.flat_map { |key, value| deep_lines([key, value]) }
421
+ when Struct
422
+ deep_lines(input.from_deep_struct).to_deep_struct
423
+ else
424
+ [input.to_deep_struct]
425
+ end
426
+ end
427
+
428
+ def wrap(ruby)
429
+ if ruby.is_a?(Hash)
430
+ ruby
431
+ elsif ruby.respond_to?(:to_a)
432
+ ruby.to_a
433
+ else
434
+ Array(ruby)
435
+ end
436
+ end
437
+
438
+ def create_progress_bar(total)
439
+ return unless progress?
440
+
441
+ Dorian::Progress.create(total:, format: progress_format)
317
442
  end
318
443
 
319
444
  def evaluates(
@@ -324,6 +449,7 @@ class Dorian
324
449
  stderr: stderr?,
325
450
  colorize: colorize?,
326
451
  rails: rails?,
452
+ fast: fast?,
327
453
  returns: false
328
454
  )
329
455
  Dorian::Eval.eval(
@@ -334,6 +460,7 @@ class Dorian
334
460
  stderr:,
335
461
  colorize:,
336
462
  rails:,
463
+ fast:,
337
464
  returns:
338
465
  )
339
466
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dorian
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-31 00:00:00.000000000 Z
11
+ date: 2024-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: csv